Add clipping/highlight planning docs and sync current extension updates
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import browser from 'webextension-polyfill'
|
||||
import { isLikelyDownloadUrl, normalizeUrl } from '../lib/downloadIntent'
|
||||
import { getSettings } from '../lib/settings'
|
||||
|
||||
const CAPTURE_TTL_MS = 8000
|
||||
const captureInFlight = new Map<string, number>()
|
||||
let extensionEnabled = false
|
||||
|
||||
function pruneCaptureInFlight(): void {
|
||||
const now = Date.now()
|
||||
@@ -12,6 +14,7 @@ function pruneCaptureInFlight(): void {
|
||||
}
|
||||
|
||||
async function sendCapture(url: string, referer: string): Promise<boolean> {
|
||||
if (!extensionEnabled) return false
|
||||
const normalized = normalizeUrl(url, window.location.href)
|
||||
if (!normalized) return false
|
||||
|
||||
@@ -46,6 +49,7 @@ function shouldIgnoreHotkey(event: MouseEvent | KeyboardEvent): boolean {
|
||||
}
|
||||
|
||||
async function interceptAnchorEvent(event: MouseEvent): Promise<void> {
|
||||
if (!extensionEnabled) return
|
||||
if (event.defaultPrevented) return
|
||||
if (shouldIgnoreHotkey(event)) return
|
||||
|
||||
@@ -61,6 +65,7 @@ async function interceptAnchorEvent(event: MouseEvent): Promise<void> {
|
||||
}
|
||||
|
||||
function interceptMouseLike(event: MouseEvent): void {
|
||||
if (!extensionEnabled) return
|
||||
const anchor = findAnchor(event.target)
|
||||
if (!anchor) return
|
||||
const href = anchor.href || ''
|
||||
@@ -89,6 +94,7 @@ document.addEventListener('click', (event: MouseEvent) => {
|
||||
}, true)
|
||||
|
||||
document.addEventListener('keydown', (event: KeyboardEvent) => {
|
||||
if (!extensionEnabled) return
|
||||
if (event.key !== 'Enter') return
|
||||
if (event.defaultPrevented) return
|
||||
if (shouldIgnoreHotkey(event)) return
|
||||
@@ -114,7 +120,7 @@ function installProgrammaticInterceptors(): void {
|
||||
const originalOpen = window.open.bind(window)
|
||||
window.open = function gomdownInterceptOpen(url?: string | URL, target?: string, features?: string): Window | null {
|
||||
const raw = String(url || '').trim()
|
||||
if (raw && isLikelyDownloadUrl(raw, window.location.href)) {
|
||||
if (extensionEnabled && raw && isLikelyDownloadUrl(raw, window.location.href)) {
|
||||
void sendCapture(raw, window.location.href)
|
||||
return null
|
||||
}
|
||||
@@ -128,7 +134,7 @@ function installProgrammaticInterceptors(): void {
|
||||
const originalAnchorClick = HTMLAnchorElement.prototype.click
|
||||
HTMLAnchorElement.prototype.click = function gomdownInterceptAnchorClick(): void {
|
||||
const href = this.href || this.getAttribute('href') || ''
|
||||
if (href && isLikelyDownloadUrl(href, window.location.href)) {
|
||||
if (extensionEnabled && href && isLikelyDownloadUrl(href, window.location.href)) {
|
||||
void sendCapture(href, document.referrer || window.location.href)
|
||||
return
|
||||
}
|
||||
@@ -196,6 +202,10 @@ function removeYoutubeOverlay(): void {
|
||||
}
|
||||
|
||||
function ensureYoutubeOverlay(): void {
|
||||
if (!extensionEnabled) {
|
||||
removeYoutubeOverlay()
|
||||
return
|
||||
}
|
||||
if (window.top !== window.self) return
|
||||
if (!isYoutubeWatchPage(window.location.href)) {
|
||||
removeYoutubeOverlay()
|
||||
@@ -283,6 +293,15 @@ watchYoutubeRouteChanges()
|
||||
let mediaToastRoot: HTMLDivElement | null = null
|
||||
let mediaToastTimer: number | null = null
|
||||
|
||||
function hideMediaCapturedToast(): void {
|
||||
if (!mediaToastRoot) return
|
||||
mediaToastRoot.style.display = 'none'
|
||||
if (mediaToastTimer !== null) {
|
||||
window.clearTimeout(mediaToastTimer)
|
||||
mediaToastTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
function ensureMediaToastRoot(): HTMLDivElement {
|
||||
if (mediaToastRoot) return mediaToastRoot
|
||||
const root = document.createElement('div')
|
||||
@@ -308,6 +327,7 @@ function ensureMediaToastRoot(): HTMLDivElement {
|
||||
}
|
||||
|
||||
function showMediaCapturedToast(payload: { kind?: string; url?: string; suggestedOut?: string }): void {
|
||||
if (!extensionEnabled) return
|
||||
const root = ensureMediaToastRoot()
|
||||
const kind = String(payload?.kind || 'media').toUpperCase()
|
||||
const out = String(payload?.suggestedOut || '').trim()
|
||||
@@ -332,3 +352,33 @@ browser.runtime.onMessage.addListener((message: any) => {
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
async function syncExtensionEnabled(): Promise<void> {
|
||||
try {
|
||||
const settings = await getSettings()
|
||||
extensionEnabled = Boolean(settings.extensionStatus)
|
||||
} catch {
|
||||
extensionEnabled = false
|
||||
}
|
||||
|
||||
if (!extensionEnabled) {
|
||||
removeYoutubeOverlay()
|
||||
hideMediaCapturedToast()
|
||||
} else {
|
||||
ensureYoutubeOverlay()
|
||||
}
|
||||
}
|
||||
|
||||
void syncExtensionEnabled()
|
||||
|
||||
browser.storage.onChanged.addListener((changes, areaName) => {
|
||||
if (areaName !== 'sync') return
|
||||
if (!changes.extensionStatus) return
|
||||
extensionEnabled = Boolean(changes.extensionStatus.newValue)
|
||||
if (!extensionEnabled) {
|
||||
removeYoutubeOverlay()
|
||||
hideMediaCapturedToast()
|
||||
return
|
||||
}
|
||||
ensureYoutubeOverlay()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user