mirror of
https://github.com/ManchildProductions/binoc-central-mirror.git
synced 2026-06-15 09:59:07 +00:00
211 lines
6.5 KiB
JavaScript
211 lines
6.5 KiB
JavaScript
/** ***** BEGIN LICENSE BLOCK *****
|
|
* 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/. */
|
|
|
|
/**
|
|
* Extract the href from the link click event.
|
|
* We look for HTMLAnchorElement, HTMLAreaElement, HTMLLinkElement,
|
|
* HTMLInputElement.form.action, and nested anchor tags.
|
|
*
|
|
* If the clicked element was a HTMLInputElement or HTMLButtonElement
|
|
* we return the form action.
|
|
* @return href for the url being clicked
|
|
*/
|
|
|
|
Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
|
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
|
|
function hRefForClickEvent(aEvent, aDontCheckInputElement)
|
|
{
|
|
var href;
|
|
var isKeyCommand = (aEvent.type == "command");
|
|
var target =
|
|
isKeyCommand ? document.commandDispatcher.focusedElement : aEvent.target;
|
|
|
|
if (target instanceof HTMLAnchorElement ||
|
|
target instanceof HTMLAreaElement ||
|
|
target instanceof HTMLLinkElement)
|
|
{
|
|
if (target.hasAttribute("href"))
|
|
href = target.href;
|
|
}
|
|
else if (target instanceof HTMLImageElement &&
|
|
target.hasAttribute("overflowing"))
|
|
{
|
|
// Return if an image is zoomed, otherwise fall through to see if it has
|
|
// a link node.
|
|
return href;
|
|
}
|
|
else if (!aDontCheckInputElement && ((target instanceof HTMLInputElement) ||
|
|
(target instanceof HTMLButtonElement)))
|
|
{
|
|
if (target.form && target.form.action)
|
|
href = target.form.action;
|
|
}
|
|
else
|
|
{
|
|
// We may be nested inside of a link node.
|
|
var linkNode = aEvent.originalTarget;
|
|
while (linkNode && !(linkNode instanceof HTMLAnchorElement))
|
|
linkNode = linkNode.parentNode;
|
|
|
|
if (linkNode)
|
|
href = linkNode.href;
|
|
}
|
|
|
|
return href;
|
|
}
|
|
|
|
function messagePaneOnResize(aEvent)
|
|
{
|
|
// Scale any overflowing images, exclude http content.
|
|
let browser = getBrowser();
|
|
let doc = browser && browser.contentDocument ? browser.contentDocument : null;
|
|
if (!doc || doc.URL.startsWith("http") || !doc.images)
|
|
return;
|
|
|
|
for (let img of doc.images)
|
|
{
|
|
if (img.clientWidth - doc.body.offsetWidth >= 0 &&
|
|
(img.clientWidth <= img.naturalWidth || !img.naturalWidth))
|
|
img.setAttribute("overflowing", true);
|
|
else
|
|
img.removeAttribute("overflowing");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check whether the click target's or its ancestor's href
|
|
* points to an anchor on the page.
|
|
*
|
|
* @param HTMLElement aTargetNode - the element node.
|
|
* @return - true if link pointing to anchor.
|
|
*/
|
|
function isLinkToAnchorOnPage(aTargetNode)
|
|
{
|
|
let url = aTargetNode.ownerDocument.URL;
|
|
if (!url.startsWith("http"))
|
|
return false;
|
|
|
|
let linkNode = aTargetNode;
|
|
while (linkNode && !(linkNode instanceof HTMLAnchorElement))
|
|
linkNode = linkNode.parentNode;
|
|
|
|
// It's not a link with an anchor.
|
|
if (!linkNode || !linkNode.href || !linkNode.hash)
|
|
return false;
|
|
|
|
// The link's href must match the document URL.
|
|
if (makeURI(linkNode.href).specIgnoringRef != makeURI(url).specIgnoringRef)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Called whenever the user clicks in the content area,
|
|
// should always return true for click to go through.
|
|
function contentAreaClick(aEvent, aPhishingDetector = true)
|
|
{
|
|
let target = aEvent.target;
|
|
|
|
// If we've loaded a web page url, and the element's or its ancestor's href
|
|
// points to an anchor on the page, let the click go through.
|
|
// Otherwise fall through and open externally.
|
|
if (isLinkToAnchorOnPage(target))
|
|
return true;
|
|
|
|
let href = hRefForClickEvent(aEvent);
|
|
|
|
if (!href && !aEvent.button) {
|
|
// Is this an image that we might want to scale?
|
|
const Ci = Components.interfaces;
|
|
|
|
if (target instanceof Ci.nsIImageLoadingContent) {
|
|
// Make sure it loaded successfully. No action if not or a broken link.
|
|
var req = target.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
|
|
if (!req || req.imageStatus & Ci.imgIRequest.STATUS_ERROR)
|
|
return false;
|
|
|
|
// Is it an image?
|
|
if (target.localName == "img" && target.hasAttribute("overflowing")) {
|
|
if (target.hasAttribute("shrinktofit"))
|
|
// Currently shrunk to fit, so unshrink it.
|
|
target.removeAttribute("shrinktofit");
|
|
else
|
|
// User wants to shrink now.
|
|
target.setAttribute("shrinktofit", true);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (!href || aEvent.button == 2)
|
|
return true;
|
|
|
|
// We want all about, http and https links in the message pane to be loaded
|
|
// externally in a browser, therefore we need to detect that here and redirect
|
|
// as necessary.
|
|
let uri = makeURI(href);
|
|
if (Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
|
|
.getService(Components.interfaces.nsIExternalProtocolService)
|
|
.isExposedProtocol(uri.scheme) &&
|
|
!uri.schemeIs("http") && !uri.schemeIs("https"))
|
|
return true;
|
|
|
|
|
|
// Now we're here, we know this should be loaded in an external browser, so
|
|
// prevent the default action so we don't try and load it here.
|
|
aEvent.preventDefault();
|
|
|
|
if (aPhishingDetector) {
|
|
// Let the phishing detector check the link.
|
|
if (!gPhishingDetector.warnOnSuspiciousLinkClick(href))
|
|
return false;
|
|
}
|
|
|
|
openLinkExternally(href);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Forces a url to open in an external application according to the protocol
|
|
* service settings.
|
|
*
|
|
* @param url A url string or an nsIURI containing the url to open.
|
|
*/
|
|
function openLinkExternally(url)
|
|
{
|
|
let uri = url;
|
|
if (!(uri instanceof Components.interfaces.nsIURI))
|
|
uri = Services.io.newURI(url, null, null);
|
|
|
|
// This can fail if there is a problem with the places database.
|
|
try {
|
|
PlacesUtils.asyncHistory.updatePlaces({
|
|
uri: uri,
|
|
visits: [{
|
|
visitDate: Date.now() * 1000,
|
|
transitionType: Components.interfaces.nsINavHistoryService.TRANSITION_LINK
|
|
}]
|
|
});
|
|
} catch (ex) {
|
|
Components.utils.reportError(ex);
|
|
}
|
|
|
|
Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
|
|
.getService(Components.interfaces.nsIExternalProtocolService)
|
|
.loadUrl(uri);
|
|
}
|
|
|
|
/**
|
|
* Compatibility to Firefox, used for example by devtools to open links. Defer
|
|
* this to the external browser for now, since in most cases this is meant to
|
|
* open an actionable tab.
|
|
*/
|
|
function openUILinkIn(url, where, options) {
|
|
openLinkExternally(url);
|
|
}
|