Revision control

Copy as Markdown

Other Tools

// /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* - [ Dependencies ] ---------------------------------------------------------
* utilityOverlay.js:
* - gatherTextUnder
*/
function hrefAndLinkNodeForClickEvent(event)
{
var href = "";
var isKeyCommand = (event.type == "command");
var linkNode = isKeyCommand ? document.commandDispatcher.focusedElement
: event.originalTarget;
while (linkNode instanceof Element) {
if (linkNode instanceof HTMLAnchorElement ||
linkNode instanceof HTMLAreaElement ||
linkNode instanceof HTMLLinkElement) {
href = linkNode.href;
if (href)
break;
}
// Try MathML href
else if (linkNode.namespaceURI == "http://www.w3.org/1998/Math/MathML" &&
linkNode.hasAttribute("href")) {
href = linkNode.getAttribute("href");
href = makeURLAbsolute(linkNode.baseURI, href);
break;
}
// Try simple XLink
else if (linkNode.hasAttributeNS("http://www.w3.org/1999/xlink", "href")) {
href = linkNode.getAttributeNS("http://www.w3.org/1999/xlink", "href");
href = makeURLAbsolute(linkNode.baseURI, href);
break;
}
linkNode = linkNode.parentNode;
}
return href ? {href: href, linkNode: linkNode} : null;
}
// Called whenever the user clicks in the content area,
// except when left-clicking on links (special case)
// should always return true for click to go through
function contentAreaClick(event)
{
if (!event.isTrusted || event.defaultPrevented) {
return true;
}
var isKeyCommand = (event.type == "command");
var ceParams = hrefAndLinkNodeForClickEvent(event);
if (ceParams) {
var href = ceParams.href;
if (isKeyCommand) {
var doc = event.target.ownerDocument;
urlSecurityCheck(href, doc.nodePrincipal);
openLinkIn(href, event && event.altKey ? "tabshifted" : "tab",
{ charset: doc.characterSet,
referrerURI: doc.documentURIObject });
event.stopPropagation();
}
else {
// if in mailnews block the link left click if we determine
// that this URL is phishy (i.e. a potential email scam)
if ("gMessengerBundle" in this && event.button < 2 &&
isPhishingURL(ceParams.linkNode, false, href))
return false;
handleLinkClick(event, href, ceParams.linkNode);
// Mark the page as a user followed link. This is done so that history can
// distinguish automatic embed visits from user activated ones. For example
// pages loaded in frames are embed visits and lost with the session, while
// visits across frames should be preserved.
try {
PlacesUIUtils.markPageAsFollowedLink(href);
} catch (ex) { /* Skip invalid URIs. */ }
}
return true;
}
if (!isKeyCommand && event.button == 1 &&
Services.prefs.getBoolPref("middlemouse.contentLoadURL") &&
!Services.prefs.getBoolPref("general.autoScroll")) {
middleMousePaste(event);
}
return true;
}
function handleLinkClick(event, href, linkNode) {
if (event.button == 2) // right click
return false;
var where = whereToOpenLink(event);
if (where == "current")
return false;
var doc = event.target.ownerDocument;
if (where == "save") {
saveURL(href, linkNode ? gatherTextUnder(linkNode) : "", null, false,
true, doc.documentURIObject, doc);
event.preventDefault();
return true;
}
var referrerURI = doc.documentURIObject;
// if the mixedContentChannel is present and the referring URI passes
// a same origin check with the target URI, we can preserve the users
// decision of disabling MCB on a page for it's child tabs.
var persistAllowMixedContentInChildTab = false;
if (where == "tab" && getBrowser().docShell.mixedContentChannel) {
const sm = Services.scriptSecurityManager;
try {
var targetURI = makeURI(href);
sm.checkSameOriginURI(referrerURI, targetURI, false);
persistAllowMixedContentInChildTab = true;
}
catch (e) { }
}
urlSecurityCheck(href, doc.nodePrincipal);
let params = {
charset: doc.characterSet,
private: gPrivate ? true : false,
allowMixedContent: persistAllowMixedContentInChildTab,
referrerURI: referrerURI,
noReferrer: BrowserUtils.linkHasNoReferrer(linkNode),
originPrincipal: doc.nodePrincipal,
triggeringPrincipal: doc.nodePrincipal,
};
// The new tab/window must use the same userContextId
if (doc.nodePrincipal.originAttributes.userContextId) {
params.userContextId = doc.nodePrincipal.originAttributes.userContextId;
}
openLinkIn(href, where, params);
event.preventDefault();
return true;
}
function middleMousePaste(event) {
let clipboard = readFromClipboard();
if (!clipboard)
return;
// Strip embedded newlines and surrounding whitespace, to match the URL
// bar's behavior (stripsurroundingwhitespace).
clipboard = clipboard.replace(/\s*\n\s*/g, "");
clipboard = stripUnsafeProtocolOnPaste(clipboard);
// If its not the current tab, we don't need to do anything because the
// browser doesn't exist.
let where = whereToOpenLink(event, true, false);
let lastLocationChange;
if (where == "current") {
lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
}
getShortcutOrURIAndPostData(clipboard).then(data => {
try {
makeURI(data.url);
} catch (ex) {
// Not a valid URI.
return;
}
try {
addToUrlbarHistory(data.url);
} catch (ex) {
// Things may go wrong when adding url to session history,
// but don't let that interfere with the loading of the url.
Cu.reportError(ex);
}
if (where != "current" ||
lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) {
openUILink(data.url, event,
{ ignoreButton: true,
disallowInheritPrincipal: !data.mayInheritPrincipal });
}
});
event.stopPropagation();
}
function stripUnsafeProtocolOnPaste(pasteData) {
// Don't allow pasting javascript URIs since we don't support
// LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL for those.
let changed = false;
let pasteDataNoJS = pasteData.replace(/\r?\n/g, "")
.replace(/^(?:\s*javascript:)+/i,
() => { changed = true;
return ""; });
return changed ? pasteDataNoJS : pasteData;
}
function addToUrlbarHistory(aUrlToAdd)
{
if (gPrivate)
return;
if (!Services.prefs.getBoolPref("browser.urlbar.historyEnabled"))
return;
// Remove leading and trailing spaces first.
aUrlToAdd = aUrlToAdd.trim();
if (!aUrlToAdd)
return;
// Don't store bad URLs.
if (aUrlToAdd.search(/[\x00-\x1F]/) != -1)
return;
getShortcutOrURIAndPostData(aUrlToAdd).then(data => {
var fixedUpURI = Services.uriFixup.createFixupURI(data.url, 0);
if (!fixedUpURI.schemeIs("data"))
PlacesUtils.history.markPageAsTyped(fixedUpURI);
}).catch(() => {});
// Open or create the urlbar history database.
var file = GetUrlbarHistoryFile();
var connection = Services.storage.openDatabase(file);
connection.beginTransaction();
if (!connection.tableExists("urlbarhistory"))
connection.createTable("urlbarhistory", "url TEXT");
// If the URL is already present in the database then remove it from
// its current position. It is then reinserted at the top of the list.
var statement = connection.createStatement(
"DELETE FROM urlbarhistory WHERE LOWER(url) = LOWER(?1)");
statement.bindByIndex(0, aUrlToAdd);
statement.execute();
statement.finalize();
// Put the value as it was typed by the user in to urlbar history.
statement = connection.createStatement(
"INSERT INTO urlbarhistory (url) VALUES (?1)");
statement.bindByIndex(0, aUrlToAdd);
statement.execute();
statement.finalize();
// Remove any expired history items so that we don't let
// this grow without bound.
connection.executeSimpleSQL(
"DELETE FROM urlbarhistory WHERE ROWID NOT IN " +
"(SELECT ROWID FROM urlbarhistory ORDER BY ROWID DESC LIMIT 30)");
connection.commitTransaction();
connection.close();
}