Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Commit

Permalink
Fix: #8479 - Fix long-press and video detection (#8483)
Browse files Browse the repository at this point in the history
  • Loading branch information
Brandon-T authored Nov 28, 2023
1 parent 16f651e commit 0e49c22
Showing 1 changed file with 64 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ window.__firefox__.includeOnce("Playlist", function($) {
})();
});

function isVideoNode(node) {
return node.constructor.name === 'HTMLVideoElement' || node.tagName === 'VIDEO';
}

function isAudioNode(node) {
return node.constructor.name === 'HTMLAudioElement' || node.tagName === 'AUDIO';
}

function isSourceNode(node) {
return node.constructor.name === 'HTMLSourceElement' || node.tagName === "SOURCE";
}

function notifyNode(target, type, detected, ignoreSource) {
if (target) {
var name = target.title;
Expand All @@ -105,16 +117,16 @@ window.__firefox__.includeOnce("Playlist", function($) {
}

if (!type || type == "") {
if (target.constructor.name == 'HTMLVideoElement') {
if (isVideoNode(target)) {
type = 'video';
}

if (target.constructor.name == 'HTMLAudioElement') {
if (isAudioNode(target)) {
type = 'audio';
}

if (target.constructor.name == 'HTMLSourceElement') {
if (target.parentNode.constructor.name == "HTMLVideoElement") {
if (isSourceNode(target)) {
if (isVideoNode(target.parentNode)) {
type = 'video'
} else {
type = 'audio'
Expand All @@ -128,7 +140,7 @@ window.__firefox__.includeOnce("Playlist", function($) {
}
else {
for (node of target.children) {
if (node.constructor.name == "HTMLSourceElement") {
if (isSourceNode(node)) {
if (node.src && node.src !== "") {
tagNode(target);
sendMessage(name, node, target, type, detected);
Expand All @@ -139,8 +151,17 @@ window.__firefox__.includeOnce("Playlist", function($) {
}
}

function notify(target, type, detected) {
notifyNode(target, type, detected, false);
function isElementVisible(e) {
if (!!(e.offsetWidth && e.offsetHeight && e.getClientRects().length)) {
return true;
}

var style = page.getComputedStyle(e);
return style.width != 0 &&
style.height !== 0 &&
style.opacity > 0 &&
style.display !== 'none' &&
style.visibility !== 'hidden';
}

function setupLongPress() {
Expand All @@ -155,73 +176,26 @@ window.__firefox__.includeOnce("Playlist", function($) {
}

function execute(page, offsetX, offsetY) {
var target = page.document.elementFromPoint(localX - offsetX, localY - offsetY);
var targetVideo = target ? target.closest("video") : null;
var targetAudio = target ? target.closest("audio") : null;

// Video or Audio might have some sort of overlay..
// Like player controls for pause/play, etc..
// So we search for video/audio elements relative to touch position.
if (!targetVideo && !targetAudio) {
var touchX = localX + (page.scrollX + offsetX);
var touchY = localY + (page.scrollY + offsetY);

var videoElements = page.document.querySelectorAll('video');
for (element of videoElements) {
var rect = element.getBoundingClientRect();
var x = rect.left + (page.scrollX + offsetX);
var y = rect.top + (page.scrollY + offsetY);
var w = rect.right - rect.left;
var h = rect.bottom - rect.top;

if (touchX >= x && touchX <= (x + w) && touchY >= y && touchY <= (y + h)) {
targetVideo = element;
break;
}
}

var audioElements = page.document.querySelectorAll('audio');
for (element of audioElements) {
var rect = element.getBoundingClientRect();
var x = rect.left + (page.scrollX + offsetX);
var y = rect.top + (page.scrollY + offsetY);
var w = rect.right - rect.left;
var h = rect.bottom - rect.top;

if (touchX >= x && touchX <= (x + w) && touchY >= y && touchY <= (y + h)) {
targetAudio = element;
break;
}
}

// No elements found nearby
// Select the first of each IF found because some websites can have video elements with zero size.
// In such cases, the gesture would not be on or inside the element, so this is a fallback.
if (!targetVideo && !targetAudio) {
if (videoElements.length > 0) {
targetVideo = videoElements[0];
}

if (audioElements.length > 0) {
targetAudio = audioElements[0];
}
}

// No elements found nearby so do nothing..
if (!targetVideo && !targetAudio) {
return;
var targets = page.document.elementsFromPoint(localX - offsetX, localY - offsetY).filter((e) => {
return isVideoNode(e) || isAudioNode(e);
}).filter((e) => {
return isElementVisible(e);
});


if (targets.length == 0) {
var targetAudio = page.document.querySelector('audio');
if (targetAudio) {
tagNode(targetAudio);
notifyNode(targetAudio, 'audio', false, false);
}
return;
}

// Elements found
var targetVideo = targets[0];
if (targetVideo) {
tagNode(targetVideo);
notify(targetVideo, 'video', false);
}

if (targetAudio) {
tagNode(targetAudio);
notify(targetAudio, 'audio', false);
notifyNode(targetVideo, 'video', false, false);
}
}

Expand All @@ -232,11 +206,13 @@ window.__firefox__.includeOnce("Playlist", function($) {
// Any videos in a `iframe.contentWindow.document`
// will have an offset of (0, 0) relative to its contentWindow.
// However, it will have an offset of (X, Y) relative to the current window.
for (frame of document.querySelectorAll('iframe')) {
// Get the frame's bounds relative to the current window.
var bounds = frame.getBoundingClientRect();
execute(frame.contentWindow, bounds.left, bounds.top);
}
try {
for (frame of document.querySelectorAll('iframe')) {
// Get the frame's bounds relative to the current window.
var bounds = frame.getBoundingClientRect();
execute(frame.contentWindow, bounds.left, bounds.top);
}
} catch {}
}
});
}
Expand All @@ -245,11 +221,11 @@ window.__firefox__.includeOnce("Playlist", function($) {

function setupDetector() {
function getAllVideoElements() {
return document.querySelectorAll('video');
return [...document.querySelectorAll('video')].reverse();
}

function getAllAudioElements() {
return document.querySelectorAll('audio');
return [...document.querySelectorAll('audio')].reverse();
}

function requestWhenIdleShim(fn) {
Expand Down Expand Up @@ -286,20 +262,20 @@ window.__firefox__.includeOnce("Playlist", function($) {
let observeNode = function(node) {
function processNode(node) {
// Observe video or audio elements
let isVideoElement = (node.constructor.name == "HTMLVideoElement");
let isAudioElement = (node.constructor.name == "HTMLAudioElement");
let isVideoElement = isVideoNode(node);
let isAudioElement = isAudioNode(node);
if (isVideoElement || isAudioElement) {
let type = isVideoElement ? 'video' : 'audio';
node.observer = new MutationObserver(function (mutations) {
notify(node, type, true);
notifyNode(node, type, true, false);
});

node.observer.observe(node, { attributes: true, attributeFilter: ["src"] });
node.addEventListener('loadedmetadata', function() {
notify(node, type, true);
notifyNode(node, type, true, false);
});

notify(node, type, true);
notifyNode(node, type, true, false);
}
}

Expand Down Expand Up @@ -344,15 +320,15 @@ window.__firefox__.includeOnce("Playlist", function($) {
HTMLVideoElement.prototype.setAttribute = $(function(key, value) {
setVideoAttribute.call(this, key, value);
if (key.toLowerCase() == 'src') {
notify(this, 'video', true);
notifyNode(this, 'video', true, false);
}
});

var setAudioAttribute = HTMLAudioElement.prototype.setAttribute;
HTMLAudioElement.prototype.setAttribute = $(function(key, value) {
setAudioAttribute.call(this, key, value);
if (key.toLowerCase() == 'src') {
notify(this, 'audio', true);
notifyNode(this, 'audio', true, false);
}
});
}
Expand All @@ -362,7 +338,7 @@ window.__firefox__.includeOnce("Playlist", function($) {
if (tag === 'audio' || tag === 'video') {
var node = document_createElement.call(this, tag);
observeNode(node);
notify(node, tag, true);
notifyNode(node, tag, true, false);
return node;
}
return document_createElement.call(this, tag);
Expand Down Expand Up @@ -469,13 +445,13 @@ window.__firefox__.includeOnce("Playlist", function($) {
return;
}

for (element of document.querySelectorAll('video')) {
for (const element of getAllVideoElements()) {
if (element.$<tagUUID> == tag) {
return clamp_duration(element.currentTime);
}
}

for (element of document.querySelectorAll('audio')) {
for (const element of getAllAudioElements()) {
if (element.$<tagUUID> == tag) {
return clamp_duration(element.currentTime);
}
Expand All @@ -495,11 +471,11 @@ window.__firefox__.includeOnce("Playlist", function($) {
return;
}

for (element of document.querySelectorAll('video')) {
for (element of getAllVideoElements()) {
element.pause();
}

for (element of document.querySelectorAll('audio')) {
for (element of getAllAudioElements()) {
element.pause();
}

Expand Down

0 comments on commit 0e49c22

Please sign in to comment.