Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | # -*- Mode: javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | # This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | # License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 5 | |
michael@0 | 6 | // Services = object with smart getters for common XPCOM services |
michael@0 | 7 | Components.utils.import("resource://gre/modules/Services.jsm"); |
michael@0 | 8 | Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); |
michael@0 | 9 | Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); |
michael@0 | 10 | Components.utils.import("resource:///modules/RecentWindow.jsm"); |
michael@0 | 11 | |
michael@0 | 12 | XPCOMUtils.defineLazyGetter(this, "BROWSER_NEW_TAB_URL", function () { |
michael@0 | 13 | const PREF = "browser.newtab.url"; |
michael@0 | 14 | |
michael@0 | 15 | function getNewTabPageURL() { |
michael@0 | 16 | if (!Services.prefs.prefHasUserValue(PREF)) { |
michael@0 | 17 | if (PrivateBrowsingUtils.isWindowPrivate(window) && |
michael@0 | 18 | !PrivateBrowsingUtils.permanentPrivateBrowsing) |
michael@0 | 19 | return "about:privatebrowsing"; |
michael@0 | 20 | } |
michael@0 | 21 | let url = Services.prefs.getComplexValue(PREF, Ci.nsISupportsString).data; |
michael@0 | 22 | return url || "about:blank"; |
michael@0 | 23 | } |
michael@0 | 24 | |
michael@0 | 25 | function update() { |
michael@0 | 26 | BROWSER_NEW_TAB_URL = getNewTabPageURL(); |
michael@0 | 27 | } |
michael@0 | 28 | |
michael@0 | 29 | Services.prefs.addObserver(PREF, update, false); |
michael@0 | 30 | |
michael@0 | 31 | addEventListener("unload", function onUnload() { |
michael@0 | 32 | removeEventListener("unload", onUnload); |
michael@0 | 33 | Services.prefs.removeObserver(PREF, update); |
michael@0 | 34 | }); |
michael@0 | 35 | |
michael@0 | 36 | return getNewTabPageURL(); |
michael@0 | 37 | }); |
michael@0 | 38 | |
michael@0 | 39 | var TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab"; |
michael@0 | 40 | |
michael@0 | 41 | var gBidiUI = false; |
michael@0 | 42 | |
michael@0 | 43 | /** |
michael@0 | 44 | * Determines whether the given url is considered a special URL for new tabs. |
michael@0 | 45 | */ |
michael@0 | 46 | function isBlankPageURL(aURL) { |
michael@0 | 47 | return aURL == "about:blank" || aURL == BROWSER_NEW_TAB_URL; |
michael@0 | 48 | } |
michael@0 | 49 | |
michael@0 | 50 | function getBrowserURL() |
michael@0 | 51 | { |
michael@0 | 52 | return "chrome://browser/content/browser.xul"; |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | function getTopWin(skipPopups) { |
michael@0 | 56 | // If this is called in a browser window, use that window regardless of |
michael@0 | 57 | // whether it's the frontmost window, since commands can be executed in |
michael@0 | 58 | // background windows (bug 626148). |
michael@0 | 59 | if (top.document.documentElement.getAttribute("windowtype") == "navigator:browser" && |
michael@0 | 60 | (!skipPopups || top.toolbar.visible)) |
michael@0 | 61 | return top; |
michael@0 | 62 | |
michael@0 | 63 | let isPrivate = PrivateBrowsingUtils.isWindowPrivate(window); |
michael@0 | 64 | return RecentWindow.getMostRecentBrowserWindow({private: isPrivate, |
michael@0 | 65 | allowPopups: !skipPopups}); |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | function openTopWin(url) { |
michael@0 | 69 | /* deprecated */ |
michael@0 | 70 | openUILinkIn(url, "current"); |
michael@0 | 71 | } |
michael@0 | 72 | |
michael@0 | 73 | function getBoolPref(prefname, def) |
michael@0 | 74 | { |
michael@0 | 75 | try { |
michael@0 | 76 | return Services.prefs.getBoolPref(prefname); |
michael@0 | 77 | } |
michael@0 | 78 | catch(er) { |
michael@0 | 79 | return def; |
michael@0 | 80 | } |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | /* openUILink handles clicks on UI elements that cause URLs to load. |
michael@0 | 84 | * |
michael@0 | 85 | * As the third argument, you may pass an object with the same properties as |
michael@0 | 86 | * accepted by openUILinkIn, plus "ignoreButton" and "ignoreAlt". |
michael@0 | 87 | */ |
michael@0 | 88 | function openUILink(url, event, aIgnoreButton, aIgnoreAlt, aAllowThirdPartyFixup, |
michael@0 | 89 | aPostData, aReferrerURI) { |
michael@0 | 90 | let params; |
michael@0 | 91 | |
michael@0 | 92 | if (aIgnoreButton && typeof aIgnoreButton == "object") { |
michael@0 | 93 | params = aIgnoreButton; |
michael@0 | 94 | |
michael@0 | 95 | // don't forward "ignoreButton" and "ignoreAlt" to openUILinkIn |
michael@0 | 96 | aIgnoreButton = params.ignoreButton; |
michael@0 | 97 | aIgnoreAlt = params.ignoreAlt; |
michael@0 | 98 | delete params.ignoreButton; |
michael@0 | 99 | delete params.ignoreAlt; |
michael@0 | 100 | } else { |
michael@0 | 101 | params = { |
michael@0 | 102 | allowThirdPartyFixup: aAllowThirdPartyFixup, |
michael@0 | 103 | postData: aPostData, |
michael@0 | 104 | referrerURI: aReferrerURI, |
michael@0 | 105 | initiatingDoc: event ? event.target.ownerDocument : null |
michael@0 | 106 | }; |
michael@0 | 107 | } |
michael@0 | 108 | |
michael@0 | 109 | let where = whereToOpenLink(event, aIgnoreButton, aIgnoreAlt); |
michael@0 | 110 | openUILinkIn(url, where, params); |
michael@0 | 111 | } |
michael@0 | 112 | |
michael@0 | 113 | |
michael@0 | 114 | /* whereToOpenLink() looks at an event to decide where to open a link. |
michael@0 | 115 | * |
michael@0 | 116 | * The event may be a mouse event (click, double-click, middle-click) or keypress event (enter). |
michael@0 | 117 | * |
michael@0 | 118 | * On Windows, the modifiers are: |
michael@0 | 119 | * Ctrl new tab, selected |
michael@0 | 120 | * Shift new window |
michael@0 | 121 | * Ctrl+Shift new tab, in background |
michael@0 | 122 | * Alt save |
michael@0 | 123 | * |
michael@0 | 124 | * Middle-clicking is the same as Ctrl+clicking (it opens a new tab). |
michael@0 | 125 | * |
michael@0 | 126 | * Exceptions: |
michael@0 | 127 | * - Alt is ignored for menu items selected using the keyboard so you don't accidentally save stuff. |
michael@0 | 128 | * (Currently, the Alt isn't sent here at all for menu items, but that will change in bug 126189.) |
michael@0 | 129 | * - Alt is hard to use in context menus, because pressing Alt closes the menu. |
michael@0 | 130 | * - Alt can't be used on the bookmarks toolbar because Alt is used for "treat this as something draggable". |
michael@0 | 131 | * - The button is ignored for the middle-click-paste-URL feature, since it's always a middle-click. |
michael@0 | 132 | */ |
michael@0 | 133 | function whereToOpenLink( e, ignoreButton, ignoreAlt ) |
michael@0 | 134 | { |
michael@0 | 135 | // This method must treat a null event like a left click without modifier keys (i.e. |
michael@0 | 136 | // e = { shiftKey:false, ctrlKey:false, metaKey:false, altKey:false, button:0 }) |
michael@0 | 137 | // for compatibility purposes. |
michael@0 | 138 | if (!e) |
michael@0 | 139 | return "current"; |
michael@0 | 140 | |
michael@0 | 141 | var shift = e.shiftKey; |
michael@0 | 142 | var ctrl = e.ctrlKey; |
michael@0 | 143 | var meta = e.metaKey; |
michael@0 | 144 | var alt = e.altKey && !ignoreAlt; |
michael@0 | 145 | |
michael@0 | 146 | // ignoreButton allows "middle-click paste" to use function without always opening in a new window. |
michael@0 | 147 | var middle = !ignoreButton && e.button == 1; |
michael@0 | 148 | var middleUsesTabs = getBoolPref("browser.tabs.opentabfor.middleclick", true); |
michael@0 | 149 | |
michael@0 | 150 | // Don't do anything special with right-mouse clicks. They're probably clicks on context menu items. |
michael@0 | 151 | |
michael@0 | 152 | #ifdef XP_MACOSX |
michael@0 | 153 | if (meta || (middle && middleUsesTabs)) |
michael@0 | 154 | #else |
michael@0 | 155 | if (ctrl || (middle && middleUsesTabs)) |
michael@0 | 156 | #endif |
michael@0 | 157 | return shift ? "tabshifted" : "tab"; |
michael@0 | 158 | |
michael@0 | 159 | if (alt && getBoolPref("browser.altClickSave", false)) |
michael@0 | 160 | return "save"; |
michael@0 | 161 | |
michael@0 | 162 | if (shift || (middle && !middleUsesTabs)) |
michael@0 | 163 | return "window"; |
michael@0 | 164 | |
michael@0 | 165 | return "current"; |
michael@0 | 166 | } |
michael@0 | 167 | |
michael@0 | 168 | /* openUILinkIn opens a URL in a place specified by the parameter |where|. |
michael@0 | 169 | * |
michael@0 | 170 | * |where| can be: |
michael@0 | 171 | * "current" current tab (if there aren't any browser windows, then in a new window instead) |
michael@0 | 172 | * "tab" new tab (if there aren't any browser windows, then in a new window instead) |
michael@0 | 173 | * "tabshifted" same as "tab" but in background if default is to select new tabs, and vice versa |
michael@0 | 174 | * "window" new window |
michael@0 | 175 | * "save" save to disk (with no filename hint!) |
michael@0 | 176 | * |
michael@0 | 177 | * aAllowThirdPartyFixup controls whether third party services such as Google's |
michael@0 | 178 | * I Feel Lucky are allowed to interpret this URL. This parameter may be |
michael@0 | 179 | * undefined, which is treated as false. |
michael@0 | 180 | * |
michael@0 | 181 | * Instead of aAllowThirdPartyFixup, you may also pass an object with any of |
michael@0 | 182 | * these properties: |
michael@0 | 183 | * allowThirdPartyFixup (boolean) |
michael@0 | 184 | * postData (nsIInputStream) |
michael@0 | 185 | * referrerURI (nsIURI) |
michael@0 | 186 | * relatedToCurrent (boolean) |
michael@0 | 187 | * skipTabAnimation (boolean) |
michael@0 | 188 | */ |
michael@0 | 189 | function openUILinkIn(url, where, aAllowThirdPartyFixup, aPostData, aReferrerURI) { |
michael@0 | 190 | var params; |
michael@0 | 191 | |
michael@0 | 192 | if (arguments.length == 3 && typeof arguments[2] == "object") { |
michael@0 | 193 | params = aAllowThirdPartyFixup; |
michael@0 | 194 | } else { |
michael@0 | 195 | params = { |
michael@0 | 196 | allowThirdPartyFixup: aAllowThirdPartyFixup, |
michael@0 | 197 | postData: aPostData, |
michael@0 | 198 | referrerURI: aReferrerURI |
michael@0 | 199 | }; |
michael@0 | 200 | } |
michael@0 | 201 | |
michael@0 | 202 | params.fromChrome = true; |
michael@0 | 203 | |
michael@0 | 204 | openLinkIn(url, where, params); |
michael@0 | 205 | } |
michael@0 | 206 | |
michael@0 | 207 | function openLinkIn(url, where, params) { |
michael@0 | 208 | if (!where || !url) |
michael@0 | 209 | return; |
michael@0 | 210 | |
michael@0 | 211 | var aFromChrome = params.fromChrome; |
michael@0 | 212 | var aAllowThirdPartyFixup = params.allowThirdPartyFixup; |
michael@0 | 213 | var aPostData = params.postData; |
michael@0 | 214 | var aCharset = params.charset; |
michael@0 | 215 | var aReferrerURI = params.referrerURI; |
michael@0 | 216 | var aRelatedToCurrent = params.relatedToCurrent; |
michael@0 | 217 | var aDisableMCB = params.disableMCB; |
michael@0 | 218 | var aInBackground = params.inBackground; |
michael@0 | 219 | var aDisallowInheritPrincipal = params.disallowInheritPrincipal; |
michael@0 | 220 | var aInitiatingDoc = params.initiatingDoc; |
michael@0 | 221 | var aIsPrivate = params.private; |
michael@0 | 222 | var aSkipTabAnimation = params.skipTabAnimation; |
michael@0 | 223 | |
michael@0 | 224 | if (where == "save") { |
michael@0 | 225 | if (!aInitiatingDoc) { |
michael@0 | 226 | Components.utils.reportError("openUILink/openLinkIn was called with " + |
michael@0 | 227 | "where == 'save' but without initiatingDoc. See bug 814264."); |
michael@0 | 228 | return; |
michael@0 | 229 | } |
michael@0 | 230 | saveURL(url, null, null, true, null, aReferrerURI, aInitiatingDoc); |
michael@0 | 231 | return; |
michael@0 | 232 | } |
michael@0 | 233 | const Cc = Components.classes; |
michael@0 | 234 | const Ci = Components.interfaces; |
michael@0 | 235 | |
michael@0 | 236 | var w = getTopWin(); |
michael@0 | 237 | if ((where == "tab" || where == "tabshifted") && |
michael@0 | 238 | w && !w.toolbar.visible) { |
michael@0 | 239 | w = getTopWin(true); |
michael@0 | 240 | aRelatedToCurrent = false; |
michael@0 | 241 | } |
michael@0 | 242 | |
michael@0 | 243 | if (!w || where == "window") { |
michael@0 | 244 | var sa = Cc["@mozilla.org/supports-array;1"]. |
michael@0 | 245 | createInstance(Ci.nsISupportsArray); |
michael@0 | 246 | |
michael@0 | 247 | var wuri = Cc["@mozilla.org/supports-string;1"]. |
michael@0 | 248 | createInstance(Ci.nsISupportsString); |
michael@0 | 249 | wuri.data = url; |
michael@0 | 250 | |
michael@0 | 251 | let charset = null; |
michael@0 | 252 | if (aCharset) { |
michael@0 | 253 | charset = Cc["@mozilla.org/supports-string;1"] |
michael@0 | 254 | .createInstance(Ci.nsISupportsString); |
michael@0 | 255 | charset.data = "charset=" + aCharset; |
michael@0 | 256 | } |
michael@0 | 257 | |
michael@0 | 258 | var allowThirdPartyFixupSupports = Cc["@mozilla.org/supports-PRBool;1"]. |
michael@0 | 259 | createInstance(Ci.nsISupportsPRBool); |
michael@0 | 260 | allowThirdPartyFixupSupports.data = aAllowThirdPartyFixup; |
michael@0 | 261 | |
michael@0 | 262 | sa.AppendElement(wuri); |
michael@0 | 263 | sa.AppendElement(charset); |
michael@0 | 264 | sa.AppendElement(aReferrerURI); |
michael@0 | 265 | sa.AppendElement(aPostData); |
michael@0 | 266 | sa.AppendElement(allowThirdPartyFixupSupports); |
michael@0 | 267 | |
michael@0 | 268 | let features = "chrome,dialog=no,all"; |
michael@0 | 269 | if (aIsPrivate) { |
michael@0 | 270 | features += ",private"; |
michael@0 | 271 | } |
michael@0 | 272 | |
michael@0 | 273 | Services.ww.openWindow(w || window, getBrowserURL(), null, features, sa); |
michael@0 | 274 | return; |
michael@0 | 275 | } |
michael@0 | 276 | |
michael@0 | 277 | let loadInBackground = where == "current" ? false : aInBackground; |
michael@0 | 278 | if (loadInBackground == null) { |
michael@0 | 279 | loadInBackground = aFromChrome ? |
michael@0 | 280 | false : |
michael@0 | 281 | getBoolPref("browser.tabs.loadInBackground"); |
michael@0 | 282 | } |
michael@0 | 283 | |
michael@0 | 284 | if (where == "current" && w.gBrowser.selectedTab.pinned) { |
michael@0 | 285 | try { |
michael@0 | 286 | let uriObj = Services.io.newURI(url, null, null); |
michael@0 | 287 | if (!uriObj.schemeIs("javascript") && |
michael@0 | 288 | w.gBrowser.currentURI.host != uriObj.host) { |
michael@0 | 289 | where = "tab"; |
michael@0 | 290 | loadInBackground = false; |
michael@0 | 291 | } |
michael@0 | 292 | } catch (err) { |
michael@0 | 293 | where = "tab"; |
michael@0 | 294 | loadInBackground = false; |
michael@0 | 295 | } |
michael@0 | 296 | } |
michael@0 | 297 | |
michael@0 | 298 | // Raise the target window before loading the URI, since loading it may |
michael@0 | 299 | // result in a new frontmost window (e.g. "javascript:window.open('');"). |
michael@0 | 300 | w.focus(); |
michael@0 | 301 | |
michael@0 | 302 | switch (where) { |
michael@0 | 303 | case "current": |
michael@0 | 304 | let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE; |
michael@0 | 305 | if (aAllowThirdPartyFixup) { |
michael@0 | 306 | flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; |
michael@0 | 307 | flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS; |
michael@0 | 308 | } |
michael@0 | 309 | if (aDisallowInheritPrincipal) |
michael@0 | 310 | flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER; |
michael@0 | 311 | w.gBrowser.loadURIWithFlags(url, flags, aReferrerURI, null, aPostData); |
michael@0 | 312 | break; |
michael@0 | 313 | case "tabshifted": |
michael@0 | 314 | loadInBackground = !loadInBackground; |
michael@0 | 315 | // fall through |
michael@0 | 316 | case "tab": |
michael@0 | 317 | let browser = w.gBrowser; |
michael@0 | 318 | browser.loadOneTab(url, { |
michael@0 | 319 | referrerURI: aReferrerURI, |
michael@0 | 320 | charset: aCharset, |
michael@0 | 321 | postData: aPostData, |
michael@0 | 322 | inBackground: loadInBackground, |
michael@0 | 323 | allowThirdPartyFixup: aAllowThirdPartyFixup, |
michael@0 | 324 | relatedToCurrent: aRelatedToCurrent, |
michael@0 | 325 | skipAnimation: aSkipTabAnimation, |
michael@0 | 326 | disableMCB: aDisableMCB}); |
michael@0 | 327 | break; |
michael@0 | 328 | } |
michael@0 | 329 | |
michael@0 | 330 | w.gBrowser.selectedBrowser.focus(); |
michael@0 | 331 | |
michael@0 | 332 | if (!loadInBackground && w.isBlankPageURL(url)) |
michael@0 | 333 | w.focusAndSelectUrlBar(); |
michael@0 | 334 | } |
michael@0 | 335 | |
michael@0 | 336 | // Used as an onclick handler for UI elements with link-like behavior. |
michael@0 | 337 | // e.g. onclick="checkForMiddleClick(this, event);" |
michael@0 | 338 | function checkForMiddleClick(node, event) { |
michael@0 | 339 | // We should be using the disabled property here instead of the attribute, |
michael@0 | 340 | // but some elements that this function is used with don't support it (e.g. |
michael@0 | 341 | // menuitem). |
michael@0 | 342 | if (node.getAttribute("disabled") == "true") |
michael@0 | 343 | return; // Do nothing |
michael@0 | 344 | |
michael@0 | 345 | if (event.button == 1) { |
michael@0 | 346 | /* Execute the node's oncommand or command. |
michael@0 | 347 | * |
michael@0 | 348 | * XXX: we should use node.oncommand(event) once bug 246720 is fixed. |
michael@0 | 349 | */ |
michael@0 | 350 | var target = node.hasAttribute("oncommand") ? node : |
michael@0 | 351 | node.ownerDocument.getElementById(node.getAttribute("command")); |
michael@0 | 352 | var fn = new Function("event", target.getAttribute("oncommand")); |
michael@0 | 353 | fn.call(target, event); |
michael@0 | 354 | |
michael@0 | 355 | // If the middle-click was on part of a menu, close the menu. |
michael@0 | 356 | // (Menus close automatically with left-click but not with middle-click.) |
michael@0 | 357 | closeMenus(event.target); |
michael@0 | 358 | } |
michael@0 | 359 | } |
michael@0 | 360 | |
michael@0 | 361 | // Closes all popups that are ancestors of the node. |
michael@0 | 362 | function closeMenus(node) |
michael@0 | 363 | { |
michael@0 | 364 | if ("tagName" in node) { |
michael@0 | 365 | if (node.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" |
michael@0 | 366 | && (node.tagName == "menupopup" || node.tagName == "popup")) |
michael@0 | 367 | node.hidePopup(); |
michael@0 | 368 | |
michael@0 | 369 | closeMenus(node.parentNode); |
michael@0 | 370 | } |
michael@0 | 371 | } |
michael@0 | 372 | |
michael@0 | 373 | // Gather all descendent text under given document node. |
michael@0 | 374 | function gatherTextUnder ( root ) |
michael@0 | 375 | { |
michael@0 | 376 | var text = ""; |
michael@0 | 377 | var node = root.firstChild; |
michael@0 | 378 | var depth = 1; |
michael@0 | 379 | while ( node && depth > 0 ) { |
michael@0 | 380 | // See if this node is text. |
michael@0 | 381 | if ( node.nodeType == Node.TEXT_NODE ) { |
michael@0 | 382 | // Add this text to our collection. |
michael@0 | 383 | text += " " + node.data; |
michael@0 | 384 | } else if ( node instanceof HTMLImageElement) { |
michael@0 | 385 | // If it has an "alt" attribute, add that. |
michael@0 | 386 | var altText = node.getAttribute( "alt" ); |
michael@0 | 387 | if ( altText && altText != "" ) { |
michael@0 | 388 | text += " " + altText; |
michael@0 | 389 | } |
michael@0 | 390 | } |
michael@0 | 391 | // Find next node to test. |
michael@0 | 392 | // First, see if this node has children. |
michael@0 | 393 | if ( node.hasChildNodes() ) { |
michael@0 | 394 | // Go to first child. |
michael@0 | 395 | node = node.firstChild; |
michael@0 | 396 | depth++; |
michael@0 | 397 | } else { |
michael@0 | 398 | // No children, try next sibling (or parent next sibling). |
michael@0 | 399 | while ( depth > 0 && !node.nextSibling ) { |
michael@0 | 400 | node = node.parentNode; |
michael@0 | 401 | depth--; |
michael@0 | 402 | } |
michael@0 | 403 | if ( node.nextSibling ) { |
michael@0 | 404 | node = node.nextSibling; |
michael@0 | 405 | } |
michael@0 | 406 | } |
michael@0 | 407 | } |
michael@0 | 408 | // Strip leading and tailing whitespace. |
michael@0 | 409 | text = text.trim(); |
michael@0 | 410 | // Compress remaining whitespace. |
michael@0 | 411 | text = text.replace( /\s+/g, " " ); |
michael@0 | 412 | return text; |
michael@0 | 413 | } |
michael@0 | 414 | |
michael@0 | 415 | function getShellService() |
michael@0 | 416 | { |
michael@0 | 417 | var shell = null; |
michael@0 | 418 | try { |
michael@0 | 419 | shell = Components.classes["@mozilla.org/browser/shell-service;1"] |
michael@0 | 420 | .getService(Components.interfaces.nsIShellService); |
michael@0 | 421 | } catch (e) { |
michael@0 | 422 | } |
michael@0 | 423 | return shell; |
michael@0 | 424 | } |
michael@0 | 425 | |
michael@0 | 426 | function isBidiEnabled() { |
michael@0 | 427 | // first check the pref. |
michael@0 | 428 | if (getBoolPref("bidi.browser.ui", false)) |
michael@0 | 429 | return true; |
michael@0 | 430 | |
michael@0 | 431 | // then check intl.uidirection.<locale> |
michael@0 | 432 | var chromeReg = Components.classes["@mozilla.org/chrome/chrome-registry;1"]. |
michael@0 | 433 | getService(Components.interfaces.nsIXULChromeRegistry); |
michael@0 | 434 | if (chromeReg.isLocaleRTL("global")) |
michael@0 | 435 | return true; |
michael@0 | 436 | |
michael@0 | 437 | // now see if the system locale is an RTL one. |
michael@0 | 438 | var rv = false; |
michael@0 | 439 | |
michael@0 | 440 | try { |
michael@0 | 441 | var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"] |
michael@0 | 442 | .getService(Components.interfaces.nsILocaleService); |
michael@0 | 443 | var systemLocale = localeService.getSystemLocale().getCategory("NSILOCALE_CTYPE").substr(0,3); |
michael@0 | 444 | |
michael@0 | 445 | switch (systemLocale) { |
michael@0 | 446 | case "ar-": |
michael@0 | 447 | case "he-": |
michael@0 | 448 | case "fa-": |
michael@0 | 449 | case "ug-": |
michael@0 | 450 | case "ur-": |
michael@0 | 451 | case "syr": |
michael@0 | 452 | rv = true; |
michael@0 | 453 | Services.prefs.setBoolPref("bidi.browser.ui", true); |
michael@0 | 454 | } |
michael@0 | 455 | } catch (e) {} |
michael@0 | 456 | |
michael@0 | 457 | return rv; |
michael@0 | 458 | } |
michael@0 | 459 | |
michael@0 | 460 | function openAboutDialog() { |
michael@0 | 461 | var enumerator = Services.wm.getEnumerator("Browser:About"); |
michael@0 | 462 | while (enumerator.hasMoreElements()) { |
michael@0 | 463 | // Only open one about window (Bug 599573) |
michael@0 | 464 | let win = enumerator.getNext(); |
michael@0 | 465 | if (win.closed) { |
michael@0 | 466 | continue; |
michael@0 | 467 | } |
michael@0 | 468 | win.focus(); |
michael@0 | 469 | return; |
michael@0 | 470 | } |
michael@0 | 471 | |
michael@0 | 472 | #ifdef XP_WIN |
michael@0 | 473 | var features = "chrome,centerscreen,dependent"; |
michael@0 | 474 | #elifdef XP_MACOSX |
michael@0 | 475 | var features = "chrome,resizable=no,minimizable=no"; |
michael@0 | 476 | #else |
michael@0 | 477 | var features = "chrome,centerscreen,dependent,dialog=no"; |
michael@0 | 478 | #endif |
michael@0 | 479 | window.openDialog("chrome://browser/content/aboutDialog.xul", "", features); |
michael@0 | 480 | } |
michael@0 | 481 | |
michael@0 | 482 | function openPreferences(paneID, extraArgs) |
michael@0 | 483 | { |
michael@0 | 484 | function switchToAdvancedSubPane(doc) { |
michael@0 | 485 | if (extraArgs && extraArgs["advancedTab"]) { |
michael@0 | 486 | let advancedPaneTabs = doc.getElementById("advancedPrefs"); |
michael@0 | 487 | advancedPaneTabs.selectedTab = doc.getElementById(extraArgs["advancedTab"]); |
michael@0 | 488 | } |
michael@0 | 489 | } |
michael@0 | 490 | |
michael@0 | 491 | if (getBoolPref("browser.preferences.inContent")) { |
michael@0 | 492 | let win = Services.wm.getMostRecentWindow("navigator:browser"); |
michael@0 | 493 | if (!win) { |
michael@0 | 494 | return; |
michael@0 | 495 | } |
michael@0 | 496 | |
michael@0 | 497 | let newLoad = !win.switchToTabHavingURI("about:preferences", true); |
michael@0 | 498 | let browser = win.gBrowser.selectedBrowser; |
michael@0 | 499 | |
michael@0 | 500 | function switchToPane() { |
michael@0 | 501 | if (paneID) { |
michael@0 | 502 | browser.contentWindow.selectCategory(paneID); |
michael@0 | 503 | } |
michael@0 | 504 | switchToAdvancedSubPane(browser.contentDocument); |
michael@0 | 505 | } |
michael@0 | 506 | |
michael@0 | 507 | if (newLoad) { |
michael@0 | 508 | browser.addEventListener("load", function onload() { |
michael@0 | 509 | browser.removeEventListener("load", onload, true); |
michael@0 | 510 | switchToPane(); |
michael@0 | 511 | }, true); |
michael@0 | 512 | } else { |
michael@0 | 513 | switchToPane(); |
michael@0 | 514 | } |
michael@0 | 515 | } else { |
michael@0 | 516 | var instantApply = getBoolPref("browser.preferences.instantApply", false); |
michael@0 | 517 | var features = "chrome,titlebar,toolbar,centerscreen" + (instantApply ? ",dialog=no" : ",modal"); |
michael@0 | 518 | |
michael@0 | 519 | var win = Services.wm.getMostRecentWindow("Browser:Preferences"); |
michael@0 | 520 | if (win) { |
michael@0 | 521 | win.focus(); |
michael@0 | 522 | if (paneID) { |
michael@0 | 523 | var pane = win.document.getElementById(paneID); |
michael@0 | 524 | win.document.documentElement.showPane(pane); |
michael@0 | 525 | } |
michael@0 | 526 | |
michael@0 | 527 | switchToAdvancedSubPane(win.document); |
michael@0 | 528 | } else { |
michael@0 | 529 | openDialog("chrome://browser/content/preferences/preferences.xul", |
michael@0 | 530 | "Preferences", features, paneID, extraArgs); |
michael@0 | 531 | } |
michael@0 | 532 | } |
michael@0 | 533 | } |
michael@0 | 534 | |
michael@0 | 535 | function openAdvancedPreferences(tabID) |
michael@0 | 536 | { |
michael@0 | 537 | openPreferences("paneAdvanced", { "advancedTab" : tabID }); |
michael@0 | 538 | } |
michael@0 | 539 | |
michael@0 | 540 | /** |
michael@0 | 541 | * Opens the troubleshooting information (about:support) page for this version |
michael@0 | 542 | * of the application. |
michael@0 | 543 | */ |
michael@0 | 544 | function openTroubleshootingPage() |
michael@0 | 545 | { |
michael@0 | 546 | openUILinkIn("about:support", "tab"); |
michael@0 | 547 | } |
michael@0 | 548 | |
michael@0 | 549 | #ifdef MOZ_SERVICES_HEALTHREPORT |
michael@0 | 550 | /** |
michael@0 | 551 | * Opens the troubleshooting information (about:support) page for this version |
michael@0 | 552 | * of the application. |
michael@0 | 553 | */ |
michael@0 | 554 | function openHealthReport() |
michael@0 | 555 | { |
michael@0 | 556 | openUILinkIn("about:healthreport", "tab"); |
michael@0 | 557 | } |
michael@0 | 558 | #endif |
michael@0 | 559 | |
michael@0 | 560 | /** |
michael@0 | 561 | * Opens the feedback page for this version of the application. |
michael@0 | 562 | */ |
michael@0 | 563 | function openFeedbackPage() |
michael@0 | 564 | { |
michael@0 | 565 | var url = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"] |
michael@0 | 566 | .getService(Components.interfaces.nsIURLFormatter) |
michael@0 | 567 | .formatURLPref("app.feedback.baseURL"); |
michael@0 | 568 | openUILinkIn(url, "tab"); |
michael@0 | 569 | } |
michael@0 | 570 | |
michael@0 | 571 | function openTourPage() |
michael@0 | 572 | { |
michael@0 | 573 | let scope = {} |
michael@0 | 574 | Components.utils.import("resource:///modules/UITour.jsm", scope); |
michael@0 | 575 | openUILinkIn(scope.UITour.url, "tab"); |
michael@0 | 576 | } |
michael@0 | 577 | |
michael@0 | 578 | function buildHelpMenu() |
michael@0 | 579 | { |
michael@0 | 580 | // Enable/disable the "Report Web Forgery" menu item. |
michael@0 | 581 | if (typeof gSafeBrowsing != "undefined") |
michael@0 | 582 | gSafeBrowsing.setReportPhishingMenu(); |
michael@0 | 583 | } |
michael@0 | 584 | |
michael@0 | 585 | function isElementVisible(aElement) |
michael@0 | 586 | { |
michael@0 | 587 | if (!aElement) |
michael@0 | 588 | return false; |
michael@0 | 589 | |
michael@0 | 590 | // If aElement or a direct or indirect parent is hidden or collapsed, |
michael@0 | 591 | // height, width or both will be 0. |
michael@0 | 592 | var bo = aElement.boxObject; |
michael@0 | 593 | return (bo.height > 0 && bo.width > 0); |
michael@0 | 594 | } |
michael@0 | 595 | |
michael@0 | 596 | function makeURLAbsolute(aBase, aUrl) |
michael@0 | 597 | { |
michael@0 | 598 | // Note: makeURI() will throw if aUri is not a valid URI |
michael@0 | 599 | return makeURI(aUrl, null, makeURI(aBase)).spec; |
michael@0 | 600 | } |
michael@0 | 601 | |
michael@0 | 602 | /** |
michael@0 | 603 | * openNewTabWith: opens a new tab with the given URL. |
michael@0 | 604 | * |
michael@0 | 605 | * @param aURL |
michael@0 | 606 | * The URL to open (as a string). |
michael@0 | 607 | * @param aDocument |
michael@0 | 608 | * Note this parameter is now ignored. There is no security check & no |
michael@0 | 609 | * referrer header derived from aDocument (null case). |
michael@0 | 610 | * @param aPostData |
michael@0 | 611 | * Form POST data, or null. |
michael@0 | 612 | * @param aEvent |
michael@0 | 613 | * The triggering event (for the purpose of determining whether to open |
michael@0 | 614 | * in the background), or null. |
michael@0 | 615 | * @param aAllowThirdPartyFixup |
michael@0 | 616 | * If true, then we allow the URL text to be sent to third party services |
michael@0 | 617 | * (e.g., Google's I Feel Lucky) for interpretation. This parameter may |
michael@0 | 618 | * be undefined in which case it is treated as false. |
michael@0 | 619 | * @param [optional] aReferrer |
michael@0 | 620 | * This will be used as the referrer. There will be no security check. |
michael@0 | 621 | */ |
michael@0 | 622 | function openNewTabWith(aURL, aDocument, aPostData, aEvent, |
michael@0 | 623 | aAllowThirdPartyFixup, aReferrer) { |
michael@0 | 624 | |
michael@0 | 625 | // As in openNewWindowWith(), we want to pass the charset of the |
michael@0 | 626 | // current document over to a new tab. |
michael@0 | 627 | let originCharset = null; |
michael@0 | 628 | if (document.documentElement.getAttribute("windowtype") == "navigator:browser") |
michael@0 | 629 | originCharset = gBrowser.selectedBrowser.characterSet; |
michael@0 | 630 | |
michael@0 | 631 | openLinkIn(aURL, aEvent && aEvent.shiftKey ? "tabshifted" : "tab", |
michael@0 | 632 | { charset: originCharset, |
michael@0 | 633 | postData: aPostData, |
michael@0 | 634 | allowThirdPartyFixup: aAllowThirdPartyFixup, |
michael@0 | 635 | referrerURI: aReferrer }); |
michael@0 | 636 | } |
michael@0 | 637 | |
michael@0 | 638 | /** |
michael@0 | 639 | * @param aDocument |
michael@0 | 640 | * Note this parameter is ignored. See openNewTabWith() |
michael@0 | 641 | */ |
michael@0 | 642 | function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup, aReferrer) { |
michael@0 | 643 | // Extract the current charset menu setting from the current document and |
michael@0 | 644 | // use it to initialize the new browser window... |
michael@0 | 645 | let originCharset = null; |
michael@0 | 646 | if (document.documentElement.getAttribute("windowtype") == "navigator:browser") |
michael@0 | 647 | originCharset = gBrowser.selectedBrowser.characterSet; |
michael@0 | 648 | |
michael@0 | 649 | openLinkIn(aURL, "window", |
michael@0 | 650 | { charset: originCharset, |
michael@0 | 651 | postData: aPostData, |
michael@0 | 652 | allowThirdPartyFixup: aAllowThirdPartyFixup, |
michael@0 | 653 | referrerURI: aReferrer }); |
michael@0 | 654 | } |
michael@0 | 655 | |
michael@0 | 656 | // aCalledFromModal is optional |
michael@0 | 657 | function openHelpLink(aHelpTopic, aCalledFromModal, aWhere) { |
michael@0 | 658 | var url = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"] |
michael@0 | 659 | .getService(Components.interfaces.nsIURLFormatter) |
michael@0 | 660 | .formatURLPref("app.support.baseURL"); |
michael@0 | 661 | url += aHelpTopic; |
michael@0 | 662 | |
michael@0 | 663 | var where = aWhere; |
michael@0 | 664 | if (!aWhere) |
michael@0 | 665 | where = aCalledFromModal ? "window" : "tab"; |
michael@0 | 666 | |
michael@0 | 667 | openUILinkIn(url, where); |
michael@0 | 668 | } |
michael@0 | 669 | |
michael@0 | 670 | function openPrefsHelp() { |
michael@0 | 671 | // non-instant apply prefwindows are usually modal, so we can't open in the topmost window, |
michael@0 | 672 | // since its probably behind the window. |
michael@0 | 673 | var instantApply = getBoolPref("browser.preferences.instantApply"); |
michael@0 | 674 | |
michael@0 | 675 | var helpTopic = document.getElementsByTagName("prefwindow")[0].currentPane.helpTopic; |
michael@0 | 676 | openHelpLink(helpTopic, !instantApply); |
michael@0 | 677 | } |
michael@0 | 678 | |
michael@0 | 679 | function trimURL(aURL) { |
michael@0 | 680 | // This function must not modify the given URL such that calling |
michael@0 | 681 | // nsIURIFixup::createFixupURI with the result will produce a different URI. |
michael@0 | 682 | return aURL /* remove single trailing slash for http/https/ftp URLs */ |
michael@0 | 683 | .replace(/^((?:http|https|ftp):\/\/[^/]+)\/$/, "$1") |
michael@0 | 684 | /* remove http:// unless the host starts with "ftp\d*\." or contains "@" */ |
michael@0 | 685 | .replace(/^http:\/\/((?!ftp\d*\.)[^\/@]+(?:\/|$))/, "$1"); |
michael@0 | 686 | } |