Skip to content

Commit ea5b5fc

Browse files
shakyShaneShane Osbourne
and
Shane Osbourne
authored
fix(duck-player): capture the correct url before a click occurs (#579)
Co-authored-by: Shane Osbourne <[email protected]>
1 parent f41a73c commit ea5b5fc

File tree

4 files changed

+66
-22
lines changed

4 files changed

+66
-22
lines changed

.eslintignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@ integration-test/extension/contentScope.js
66
integration-test/pages/build
77
packages/special-pages/pages/**/public
88
script-overload-snapshots/
9+
packages/special-pages/playwright-report/
10+
packages/special-pages/test-results/
11+
/playwright-report
12+
/test-results

src/features/duckplayer/overlays.js

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ export async function initOverlays (environment, comms) {
252252
const OpenInDuckPlayer = {
253253
clickBoundElements: new Map(),
254254
enabled: false,
255-
255+
/** @type {string|null} */
256+
lastMouseOver: null,
256257
bindEventsToAll: () => {
257258
if (!OpenInDuckPlayer.enabled) {
258259
return
@@ -263,38 +264,69 @@ export async function initOverlays (environment, comms) {
263264
return VideoThumbnail.isSingleVideoURL(element?.getAttribute('href')) ||
264265
element.getAttribute('id') === 'media-container-link'
265266
}
266-
const excludeAlreadyBound = (element) => !OpenInDuckPlayer.clickBoundElements.has(element)
267-
268267
videoLinksAndPreview
269-
.filter(excludeAlreadyBound)
270-
.forEach(element => {
271-
if (isValidVideoLinkOrPreview(element)) {
272-
const onClickOpenDuckPlayer = (event) => {
273-
event.preventDefault()
274-
event.stopPropagation()
275-
276-
const link = event.target.closest('a')
277-
278-
if (link) {
279-
const href = VideoParams.fromHref(link.href)?.toPrivatePlayerUrl()
268+
.forEach((/** @type {HTMLElement|HTMLAnchorElement} */element) => {
269+
// bail when this element was already seen
270+
if (OpenInDuckPlayer.clickBoundElements.has(element)) return
271+
272+
// bail if it's not a valid element
273+
if (!isValidVideoLinkOrPreview(element)) return
274+
275+
// handle mouseover + click events
276+
const handler = {
277+
handleEvent (event) {
278+
switch (event.type) {
279+
case 'mouseover': {
280+
/**
281+
* Store the element's link value on hover - this occurs just in time
282+
* before the youtube overlay take sover the event space
283+
*/
284+
const href = element instanceof HTMLAnchorElement
285+
? VideoParams.fromHref(element.href)?.toPrivatePlayerUrl()
286+
: null
280287
if (href) {
281-
comms.openDuckPlayer({ href })
288+
OpenInDuckPlayer.lastMouseOver = href
282289
}
290+
break
283291
}
292+
case 'click': {
293+
/**
294+
* On click, the receiver might be the preview element - if
295+
* it is, we want to use the last hovered `a` tag instead
296+
*/
297+
event.preventDefault()
298+
event.stopPropagation()
299+
300+
const link = event.target.closest('a')
301+
const fromClosest = VideoParams.fromHref(link?.href)?.toPrivatePlayerUrl()
302+
303+
if (fromClosest) {
304+
comms.openDuckPlayer({ href: fromClosest })
305+
} else if (OpenInDuckPlayer.lastMouseOver) {
306+
comms.openDuckPlayer({ href: OpenInDuckPlayer.lastMouseOver })
307+
} else {
308+
// could not navigate, doing nothing
309+
}
284310

285-
return false
311+
break
312+
}
313+
}
286314
}
315+
}
287316

288-
element.addEventListener('click', onClickOpenDuckPlayer, true)
317+
// register both handlers
318+
element.addEventListener('mouseover', handler, true)
319+
element.addEventListener('click', handler, true)
289320

290-
OpenInDuckPlayer.clickBoundElements.set(element, onClickOpenDuckPlayer)
291-
}
321+
// store the handler for removal later (eg: if settings change)
322+
OpenInDuckPlayer.clickBoundElements.set(element, handler)
292323
})
293324
},
294325

295326
disable: () => {
296-
OpenInDuckPlayer.clickBoundElements.forEach((functionToRemove, element) => {
297-
element.removeEventListener('click', functionToRemove, true)
327+
OpenInDuckPlayer.clickBoundElements.forEach((handler, element) => {
328+
element.removeEventListener('mouseover', handler, true)
329+
element.removeEventListener('click', handler, true)
298330
OpenInDuckPlayer.clickBoundElements.delete(element)
299331
})
300332

src/features/duckplayer/util.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,13 @@ export class VideoParams {
200200
* @returns {VideoParams|null}
201201
*/
202202
static fromHref (href) {
203-
const url = new URL(href)
203+
let url
204+
try {
205+
url = new URL(href)
206+
} catch (e) {
207+
return null
208+
}
209+
204210
const vParam = url.searchParams.get('v')
205211
const tParam = url.searchParams.get('t')
206212

tsconfig.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"integration-test/pages",
2727
"integration-test/extension",
2828
"packages/special-pages/pages/**/public",
29+
"packages/special-pages/playwright-report",
30+
"packages/special-pages/test-results",
2931
"docs"
3032
]
3133
}

0 commit comments

Comments
 (0)