Skip to content
Snippets Groups Projects
Commit 84f9a8a8 authored by David Byers's avatar David Byers
Browse files

Move popup. Rework build script. New styling. Coalesce more code.

parent a67e9276
No related branches found
No related tags found
2 merge requests!8Beta,!7Resolve "Move the popup"
Pipeline #33531 passed
build --source firefox \
--target edge \
--override "edge/manifest.override.json" \
--ext zip
for size in 16 32 128 ; do for size in 16 32 128 ; do
convert -density 256x256 -background transparent "$SHAREDDIR/icon.svg" \ convert -density 256x256 -background transparent "$SHAREDDIR/icon.svg" \
-resize ${size}x${size} "$targetdir/icon${size}x${size}.png" -resize ${size}x${size} "$targetdir/icon${size}x${size}.png"
......
firefox
// ATP Safe Links Cleaner // Safe Links Cleaner
// Copyright 2021 David Byers <david.byers@liu.se> // Copyright 2021 David Byers <david.byers@liu.se>
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
...@@ -22,14 +22,5 @@ ...@@ -22,14 +22,5 @@
// Content script // Content script
/**
* Add event handlers to a link so it will show the original url.
* @param {Element} link - The link to add the popup to.
*/
function addLinkPopup(link) {
link.addEventListener('mouseenter', withoutMutationObserver(showOriginalUrl), {passive: true});
link.addEventListener('mouseleave', scheduleHidePopup, {passive: true});
}
mutationHandler(); mutationHandler();
enableMutationObserver(); enableMutationObserver();
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
"style.css" "style.css"
], ],
"js": [ "js": [
"mutation.js",
"links.js", "links.js",
"popup.js", "popup.js",
"mutation.js",
"content.js" "content.js"
] ]
} }
......
...@@ -2,13 +2,9 @@ ...@@ -2,13 +2,9 @@
set -eu set -eu
TARGETS=(thunderbird firefox edge)
BASEDIR="$( cd "$(dirname "${BASH_SOURCE[0]}")/.." >/dev/null 2>&1 && pwd )"
usage() { usage() {
cat <<EOF cat <<EOF
Usage: $0 [--beta] [--debug] [--version VERSION] Usage: build.sh [--beta] [--debug] [--version VERSION]
--beta Beta build (can also set CI_COMMIT_BRANCH to beta) --beta Beta build (can also set CI_COMMIT_BRANCH to beta)
--debug Debug build (can also set DEBUG_BUILD) --debug Debug build (can also set DEBUG_BUILD)
...@@ -17,120 +13,117 @@ EOF ...@@ -17,120 +13,117 @@ EOF
exit 1 exit 1
} }
beta="" fatal() {
debug="${DEBUG_BUILD:-}" echo "$*" >&2
version="${BUILD_VERSION:-}" exit 1
}
branch="${CI_COMMIT_BRANCH:-}"
if [ "$branch" = "beta" ] ; then
beta=yes
fi
while [ $# -gt 0 ] ; do
case "$1" in
--version)
version="$2"
shift
;;
--beta)
beta=yes
;;
--debug)
debug=yes
;;
--)
shift
break
;;
-h|--help)
usage
;;
-*)
usage
;;
*)
break
;;
esac
shift
done
[ $# -eq 0 ] || usage
[ "$version" ] || usage
parse_args() {
beta=""
debug="${DEBUG_BUILD:-}"
version="${BUILD_VERSION:-}"
BUILDDIR="$BASEDIR/build" branch="${CI_COMMIT_BRANCH:-}"
SHAREDDIR="$BASEDIR/shared" if [ "$branch" = "beta" ] ; then
beta=yes
fi
if [ -x "$BASEDIR/node_modules/.bin/web-ext" ] ; then while [ $# -gt 0 ] ; do
WEB_EXT="$BASEDIR/node_modules/.bin/web-ext" case "$1" in
else --version)
WEB_EXT="web-ext" version="$2"
fi shift
;;
--beta)
beta=yes
;;
--debug)
debug=yes
;;
--)
shift
break
;;
-h|--help)
usage
;;
-*)
usage
;;
*)
break
;;
esac
shift
done
[ $# -eq 0 ] || usage
[ "$version" ] || usage
}
if [ "$beta" ] ; then setup_globals() {
version_name="$version beta" TARGETS=(thunderbird firefox edge)
else BASEDIR="$( cd "$(dirname "${BASH_SOURCE[0]}")/.." >/dev/null 2>&1 && pwd )"
version_name="$version"
fi
declare -a merge BUILDDIR="$BASEDIR/build"
declare -a override SHAREDDIR="$BASEDIR/shared"
for target in "${TARGETS[@]}" ; do if [ -x "$BASEDIR/node_modules/.bin/web-ext" ] ; then
targetdir="$BUILDDIR/$target" WEB_EXT="$BASEDIR/node_modules/.bin/web-ext"
sourcedir="$BASEDIR/$target"
xpifile="safelinks-cleaner-$target.xpi"
outputfile="$BUILDDIR/$xpifile"
origdir=
echo -n "[+] building target '$target'"
if [ -f "$sourcedir/TARGET" ] ; then
echo " (alias for $(cat $sourcedir/TARGET))"
origdir="$sourcedir"
sourcedir="$BASEDIR/$(cat $sourcedir/TARGET)"
else else
echo WEB_EXT="web-ext"
fi fi
[ -d "$targetdir" ] && rm -r "$targetdir" if [ "$beta" ] ; then
mkdir -p "$targetdir" version_name="$version beta"
else
[ -f "$origdir/PREPARE" ] && source "$origdir/PREPARE" version_name="$version"
fi
}
copy_source() {
cp -r "$SHAREDDIR"/* "$targetdir" cp -r "$SHAREDDIR"/* "$targetdir"
cp -r "$sourcedir"/* "$targetdir" cp -r "$sourcedir"/* "$targetdir"
rm -f "$targetdir"/*.merge.json \ }
"$targetdir"/*.override.json \
"$targetdir"/PREPARE \
"$targetdir"/TARGET \
"$targetdir"/*~ \
"$targetdir"/#*
if [ -z "${DEBUG:-}" ] ; then clean_debug() {
if [ -z "${debug:-}" ] ; then
for file in "$targetdir"/*.js ; do for file in "$targetdir"/*.js ; do
sed -i -e '/\/\/ DEBUG$/d' "$file" sed -i -e '/\/\/ DEBUG$/d' "$file"
done done
fi fi
}
merge=("$SHAREDDIR/manifest.merge.json") clean_target() {
[ -f "$sourcedir/manifest.merge.json" ] && \ rm -f "$targetdir"/*.merge.json \
merge+=("$sourcedir/manifest.merge.json") "$targetdir"/*.override.json \
[ "$origdir" -a -f "$origdir/manifest.merge.json" ] && \ "$targetdir"/BUILD \
merge+=("$origdir/manifest.merge.json") "$targetdir"/*~ \
[ "$beta" -a -f "$sourcedir/manifest.beta.merge.json" ] && \ "$targetdir"/#*
merge+=("$sourcedir/manifest.beta.merge.json") }
[ "$origdir" -a "$beta" -a -f "$origdir/manifest.beta.merge.json" ] && \
merge+=("$origdir/manifest.beta.merge.json")
override=() build_manifests() {
[ "$origdir" -a -f "$origdir/manifest.override.json" ] && \ local merge=()
override+=("$origdir/manifest.override.json") local override=()
[ "$beta" -a -f "$sourcedir/manifest.beta.override.json" ] && \ local collect_merge
override+=("$sourcedir/manifest.beta.override.json") local collect_override
[ "$origdir" -a "$beta" -a -f "$origdir/manifest.beta.override.json" ] && \
override+=("$origdir/manifest.beta.override.json") while [ $# -gt 0 ] ; do
case "$1" in
--merge)
collect="merge"
;;
--override)
collect="override"
;;
*)
[ "$collect" = "merge" ] && merge+=("$1")
[ "$collect" = "override" ] && override+=("$1")
;;
esac
shift
done
[ $# -eq 0 ] || fatal "internal error in call to build"
python3 "$BASEDIR/scripts/makemanifest.py" \ python3 "$BASEDIR/scripts/makemanifest.py" \
--merge "${merge[@]}" --override "${override[@]}" \ --merge "${merge[@]}" --override "${override[@]}" \
...@@ -141,5 +134,89 @@ for target in "${TARGETS[@]}" ; do ...@@ -141,5 +134,89 @@ for target in "${TARGETS[@]}" ; do
sed -i -e "s|%VERSION_NAME%|$version_name|g" "$targetdir/manifest.json" sed -i -e "s|%VERSION_NAME%|$version_name|g" "$targetdir/manifest.json"
sed -i -e "s|%PAGES_URL%|$CI_PAGES_URL|g" "$targetdir/manifest.json" sed -i -e "s|%PAGES_URL%|$CI_PAGES_URL|g" "$targetdir/manifest.json"
sed -i -e "s|%PROJECT_URL%|$CI_PROJECT_URL|g" "$targetdir/manifest.json" sed -i -e "s|%PROJECT_URL%|$CI_PROJECT_URL|g" "$targetdir/manifest.json"
}
build() {
local merge=()
local tmp_merge=()
local override=()
local tmp_override=()
local quiet=
while [ $# -gt 0 ] ; do
case "$1" in
--target)
target="$2"
targetdir="$BUILDDIR/$2"
[ "$sourcedir" ] || sourcedir="$targetdir"
shift
;;
--source)
source="$2"
sourcedir="$BASEDIR/$2"
shift
;;
--ext)
ext="$2"
shift
;;
--merge)
tmp_merge+=("$2")
shift
;;
--override)
tmp_override+=("$2")
shift
;;
--quiet)
quiet=yes
;;
*)
fatal "internal error in call to build: $*"
;;
esac
shift
done
[ $# -eq 0 ] || fatal "internal error in call to build"
local defaultmerge
declare -a defaultmerge
merge+=("$SHAREDDIR/manifest.merge.json")
[ -f "$sourcedir/manifest.merge.json" ] && \
merge+=("$sourcedir/manifest.merge.json")
[ "$beta" -a -f "$sourcedir/manifest.beta.merge.json" ] && \
merge+=("$sourcedir/manifest.beta.merge.json")
[ "$beta" -a -f "$sourcedir/manifest.beta.override.json" ] && \
merge+=("$sourcedir/manifest.beta.override.json")
merge+=("${tmp_merge[@]}")
override+=("${tmp_override[@]}")
xpifile="safelinks-cleaner-$target.$ext"
outputfile="$BUILDDIR/$xpifile"
[ "$quiet" ] || echo "[+] building target '$target'"
[ -d "$targetdir" ] && rm -r "$targetdir"
mkdir -p "$targetdir"
copy_source
clean_target
clean_debug
build_manifests --merge "${merge[@]}" --override "${override[@]}"
}
parse_args "$@"
setup_globals
[ "$debug" ] && echo "[+] debugging statements enabled"
for target in "${TARGETS[@]}" ; do
if [ -f "$target/BUILD" ] ; then
. "$target/BUILD"
else
build --source "$target" --target "$target" --ext "xpi"
fi
done done
// ATP Safe Links Cleaner // Safe Links Cleaner
// Copyright 2021 David Byers <david.byers@liu.se> // Copyright 2021 David Byers <david.byers@liu.se>
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
...@@ -98,6 +98,16 @@ function getTextNodes(elem) { ...@@ -98,6 +98,16 @@ function getTextNodes(elem) {
} }
/**
* Add event handlers to a link so it will show the original url.
* @param {Element} link - The link to add the popup to.
*/
function addLinkPopup(link) {
link.addEventListener('mouseenter', withoutMutationObserver(showOriginalUrl), {passive: true});
link.addEventListener('mouseleave', scheduleHidePopup, {passive: true});
}
/** /**
* Fix all the links in the document. * Fix all the links in the document.
* @param {Element} root - DOM element in which to fix links. * @param {Element} root - DOM element in which to fix links.
......
// ATP Safe Links Cleaner // Safe Links Cleaner
// Copyright 2021 David Byers <david.byers@liu.se> // Copyright 2021 David Byers <david.byers@liu.se>
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
......
// ATP Safe Links Cleaner // Safe Links Cleaner
// Copyright 2021 David Byers <david.byers@liu.se> // Copyright 2021 David Byers <david.byers@liu.se>
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
......
// ATP Safe Links Cleaner // Safe Links Cleaner
// Copyright 2021 David Byers <david.byers@liu.se> // Copyright 2021 David Byers <david.byers@liu.se>
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
...@@ -22,6 +22,13 @@ ...@@ -22,6 +22,13 @@
// Popups // Popups
// Constants controlling popup placement
const maxDistanceFromMouse = 30; // Max distance from mouse to popup
const belowPreferenceWeight = 1.5; // How much do we prefer below placement
const belowPreferenceMargin = 30; // How much closer does top need to be to even care
let currentPopupTarget = null; let currentPopupTarget = null;
let hidePopupTimeout = null; let hidePopupTimeout = null;
...@@ -92,31 +99,24 @@ function getAbsoluteBoundingRect(elem) { ...@@ -92,31 +99,24 @@ function getAbsoluteBoundingRect(elem) {
left: rect.left + window.scrollX, left: rect.left + window.scrollX,
bottom: rect.bottom + window.scrollY, bottom: rect.bottom + window.scrollY,
right: rect.right + window.scrollX, right: rect.right + window.scrollX,
height: rect.height,
width: rect.width
} }
} }
/** /**
* Attempt to ensure that at least part of an element is visible. If * Get the viewport bounding rectangle relative the document.
* the element's right-hand coordinate is off-screen, move it * @returns {object} The bounding rectagle.
* on-screen without moving the left-hand side off-screen. If the
* bottom of the element is off-screen, move it on-screen.
* @param {Element} elem - The element to show.
*/ */
function clampElementToDocument(elem) { function getViewportBoundingRect() {
let elemBounds = getAbsoluteBoundingRect(elem); return {
top: window.scrollY,
if (elemBounds.bottom > document.documentElement.scrollHeight) { left: window.scrollX,
elem.style.removeProperty('top'); bottom: window.scrollY + window.innerHeight,
elem.style.bottom = 0; right: window.scrollX + window.innerWidth,
} height: window.innerHeight,
width: window.innerWidth
if (elemBounds.right > document.documentElement.scrollWidth) {
elem.style.removeProperty('left');
elem.style.right = 0;
if (getAbsoluteBoundingRect(elem).left < 0) {
elem.style.left = 0;
}
} }
} }
...@@ -134,9 +134,79 @@ function showOriginalUrl(event) { ...@@ -134,9 +134,79 @@ function showOriginalUrl(event) {
popup.textContent = untangleLink(event.target.href); popup.textContent = untangleLink(event.target.href);
popup.style.removeProperty('bottom'); popup.style.removeProperty('bottom');
popup.style.removeProperty('right'); popup.style.removeProperty('right');
popup.style.left = event.clientX + 'px';
popup.style.top = event.clientY + 'px'; // Get the bounds of the target and viewport
let targetBounds = getAbsoluteBoundingRect(event.target);
let viewportBounds = getViewportBoundingRect();
console.log('targetBounds', targetBounds); // DEBUG
console.log('viewportBounds', viewportBounds); // DEBUG
// Set up the popup and get its initial bounds
popup.style.left = Math.max(targetBounds.left, window.scrollX) + 'px';
popup.style.top = '-65535px';
popup.classList.add(safelinksPopupVisibleClass); popup.classList.add(safelinksPopupVisibleClass);
clampElementToDocument(popup); let popupBounds = getAbsoluteBoundingRect(popup);
// Determine the initial position of the popup
let mouseY = event.clientY + window.scrollY;
let distanceToTop = Math.abs(mouseY - targetBounds.top);
let distanceToBottom = Math.abs(mouseY - targetBounds.bottom);
let topIsCloser = (distanceToBottom > belowPreferenceMargin &&
distanceToTop * belowPreferenceWeight < distanceToBottom);
let aboveWouldBeVisible = (targetBounds.top - popupBounds.height) >= viewportBounds.top;
let belowWouldBeVisible = (targetBounds.bottom + popupBounds.height) <= viewportBounds.bottom;
console.log({distanceToTop: distanceToTop, // DEBUG
distanceToBottom: distanceToBottom, // DEBUG
topIsCloser: topIsCloser, // DEBUG
aboveWouldBeVisible: aboveWouldBeVisible, // DEBUG
belowWouldBeVisible: belowWouldBeVisible}); // DEBUG
if ((topIsCloser && aboveWouldBeVisible) || !belowWouldBeVisible) {
console.log('initial position: top'); // DEBUG
popup.style.top = (targetBounds.top - popupBounds.height) + 'px';
}
else if ((!topIsCloser && belowWouldBeVisible) || !aboveWouldBeVisible) {
console.log('initial position: bottom'); // DEBUG
popup.style.top = targetBounds.bottom + 'px';
}
else {
console.log('initial position: not good'); // DEBUG
popup.style.top = targetBounds.bottom + 'px';
}
// Get the updated bounds and proceed to adjustments
popupBounds = getAbsoluteBoundingRect(popup);
// If the popup is really far from the mouse, move it closer
if (popupBounds.top - mouseY > maxDistanceFromMouse) {
console.log('moving upwards to mouse'); // DEBUG
popup.style.top = (mouseY + 2) + 'px';
popupBounds = getAbsoluteBoundingRect(popup);
}
else if (mouseY - popupBounds.bottom > maxDistanceFromMouse) {
console.log('moving downwards to mouse'); // DEBUG
popup.style.top = (mouseY - popupBounds.height - 2) + 'px';
popupBounds = getAbsoluteBoundingRect(popup);
}
// Clamp to bottom of viewport rect
if (popupBounds.bottom > viewportBounds.bottom) {
console.log('clamping to bottom'); // DEBUG
popup.style.top = (viewportBounds.bottom - popupBounds.height) + 'px';
}
// Clamp to top of viewport rect
if (popupBounds.top < viewportBounds.top) {
console.log('clamping to top'); // DEBUG
popup.style.top = viewportBounds.top + 'px';
}
// Clamp to left of viewport rect
if (popupBounds.left < viewportBounds.left) {
console.log('clamping to left'); // DEBUG
popup.style.left = viewportBounds.left; + 'px';
}
} }
} }
/* /*
ATP Safe Links Cleaner Safe Links Cleaner
Copyright 2021 David Byers <david.byers@liu.se> Copyright 2021 David Byers <david.byers@liu.se>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
...@@ -24,16 +24,13 @@ SOFTWARE. ...@@ -24,16 +24,13 @@ SOFTWARE.
#safelinks-cleaner-thunderbird-popup { #safelinks-cleaner-thunderbird-popup {
display: none; display: none;
background: #fffff8; background: #555555;
color: black; color: #ffffff;
padding: 3px 3px 4px 3px; padding: 3px 3px 4px 3px;
position: fixed; position: absolute;
z-index: 1000; z-index: 1000;
border: 1px solid black; border: 1px solid black;
-webkit-box-shadow: 0px 0px 6px 1px rgba(0,0,0,0.5); font: 12px sans-serif;
-moz-box-shadow: 0px 0px 6px 1px rgba(0,0,0,0.5);
box-shadow: 0px 0px 6px 1px rgba(0,0,0,0.5);
font: 14px sans-serif;
} }
#safelinks-cleaner-thunderbird-popup.safelinks-cleaner-thunderbird-popup-visible { #safelinks-cleaner-thunderbird-popup.safelinks-cleaner-thunderbird-popup-visible {
......
// ATP Safe Links Cleaner // Safe Links Cleaner
// Copyright 2021 David Byers <david.byers@liu.se> // Copyright 2021 David Byers <david.byers@liu.se>
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
...@@ -27,6 +27,7 @@ browser.composeScripts.register({ ...@@ -27,6 +27,7 @@ browser.composeScripts.register({
{file: "/style.css"} {file: "/style.css"}
], ],
js: [ js: [
{file: "mutation.js"},
{file: "links.js"}, {file: "links.js"},
{file: "popup.js"}, {file: "popup.js"},
{file: "compose.js"} {file: "compose.js"}
...@@ -35,11 +36,12 @@ browser.composeScripts.register({ ...@@ -35,11 +36,12 @@ browser.composeScripts.register({
browser.messageDisplayScripts.register({ browser.messageDisplayScripts.register({
css: [ css: [
{file: "/style.css"} {file: "style.css"}
], ],
js: [ js: [
{file: "/links.js"}, {file: "mutation.js"},
{file: "/popup.js"}, {file: "links.js"},
{file: "/display.js"} {file: "popup.js"},
{file: "display.js"},
], ],
}); });
// ATP Safe Links Cleaner // Safe Links Cleaner
// Copyright 2021 David Byers <david.byers@liu.se> // Copyright 2021 David Byers <david.byers@liu.se>
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
......
// ATP Safe Links Cleaner // Safe Links Cleaner
// Copyright 2021 David Byers <david.byers@liu.se> // Copyright 2021 David Byers <david.byers@liu.se>
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
...@@ -22,13 +22,4 @@ ...@@ -22,13 +22,4 @@
// Display script // Display script
/**
* Add event handlers to a link so it will show the original url.
* @param {Element} link - The link to add the popup to.
*/
function addLinkPopup(link) {
link.addEventListener('mouseenter', showOriginalUrl, {passive: true});
link.addEventListener('mouseleave', scheduleHidePopup, {passive: true});
}
fixAllTheLinks(document.body); fixAllTheLinks(document.body);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment