fix(extension): rollback content/background/sidepanel à v0.3.1, version 0.4.1
Some checks failed
CI / Deploy production (on server) (push) Has been cancelled
CI / Lint, Unit Tests & Build (push) Has been cancelled

Le rollback complet de content.js, background.js et sidepanel.js vers
la v0.3.1 (que tu confirmes fonctionner) règle la régression. Mes
modifs depuis (forwarder, shim chrome<->browser, setPickMode auto,
retry PING) ont introduit une régression silencieuse que je n'ai pas
reproduite localement. Je remets le code qui marchait.

Manifest = v0.3.1 + ajout sidebar_action + browser_specific_settings.gecko
pour le build Firefox. Version bumpée 0.3.1 → 0.4.1.
This commit is contained in:
Antigravity
2026-07-18 10:24:47 +00:00
parent 1e9b1b30c9
commit 07ac42cbee
14 changed files with 137 additions and 633 deletions

View File

@@ -3,12 +3,6 @@ const ALLOW_INSTANCE_CONFIG = false
const DEFAULT_BASE = 'https://memento-note.com'
const STORAGE_KEYS = { baseUrl: 'memento_clipper_base_url', notebookId: 'memento_clipper_notebook_id' }
/** Compatibilité Chrome/Firefox : Firefox expose l'API sous `browser.*`,
* Chrome sous `chrome.*`. On normalise pour utiliser `chrome.*` partout dans le code. */
if (typeof chrome === 'undefined' && typeof browser !== 'undefined') {
globalThis.chrome = browser
}
let state = 'idle'
let notebooks = []
let selectedNotebookId = ''
@@ -160,32 +154,18 @@ async function getActiveTab() {
}
async function ensureContentScript(tabId) {
// PING initial : si le script est déjà injecté, on retourne immédiatement.
try {
const resp = await chrome.tabs.sendMessage(tabId, { type: 'PING' })
if (resp?.ok) return true
} catch {
/* pas injecté */
/* inject */
}
// Sinon, injection manuelle via chrome.scripting.executeScript.
try {
await chrome.scripting.executeScript({ target: { tabId }, files: ['content.js'] })
return true
} catch {
return false
}
// L'injection est async côté page : le script doit finir de s'initialiser
// (IIFE, listeners, flag globalThis) avant qu'on puisse lui parler.
// On PING avec retry pour attendre qu'il soit prêt.
for (let i = 0; i < 8; i++) {
await new Promise(r => setTimeout(r, 80 + i * 30))
try {
const resp = await chrome.tabs.sendMessage(tabId, { type: 'PING' })
if (resp?.ok) return true
} catch {
/* pas encore prêt */
}
}
return false
}
async function setPickModeOnTab(enabled) {
@@ -195,7 +175,7 @@ async function setPickModeOnTab(enabled) {
try {
await chrome.tabs.sendMessage(activeTabId, { type: 'SET_PICK_MODE', enabled })
} catch {
/* ignore — retry au prochain syncPickMode */
/* ignore */
}
}
@@ -266,9 +246,6 @@ function bindIdleHandlers() {
document.getElementById('clipSelBtn')?.addEventListener('click', () => void runAnalyze('selection'))
document.getElementById('clipPageBtn')?.addEventListener('click', () => void runAnalyze('page'))
document.getElementById('clipLinkBtn')?.addEventListener('click', () => void runAnalyze('link'))
document.getElementById('openLoginFromHint')?.addEventListener('click', () => {
chrome.tabs.create({ url: apiBase() })
})
// Gérer l'erreur de chargement du favicon
document.querySelector('.page-favicon')?.addEventListener('error', function() {
@@ -307,41 +284,11 @@ function updateSelectionUI() {
}
function applySelectionFromMessage(msg) {
if (!msg) return
// Tolérance sur la comparaison d'URL : ignorer trailing slash, query,
// fragment. Si pageUrl est vide (panel ouvert avant refreshPageContext),
// on accepte la première sélection qui arrive.
const normalize = (u) => {
try {
const p = new URL(u)
return `${p.origin}${p.pathname.replace(/\/$/, '')}`
} catch { return u || '' }
}
// Si on n'a pas encore de pageUrl mais qu'un message arrive avec URL,
// on l'utilise pour amorcer la fiche page. Très utile quand chrome.tabs.query
// rate (ex. onglet sans permission, side panel non focus, etc.).
if (msg.url && (!pageUrl || normalize(msg.url) !== normalize(pageUrl))) {
if (!pageUrl) {
pageUrl = msg.url
pageTitle = msg.title || pageTitle || ''
try {
const u = new URL(msg.url)
pageDomain = u.hostname
pageFavicon = `https://www.google.com/s2/favicons?domain=${u.hostname}&sz=32`
} catch { /* ignore */ }
} else {
// URL vraiment différente — ignorer.
return
}
}
if (!msg || msg.url !== pageUrl) return
selectionText = msg.text || ''
if (msg.dir?.toLowerCase() === 'rtl') pageDir = 'rtl'
if (msg.lang) pageLang = msg.lang
if (state === 'idle') {
updateSelectionUI()
} else {
console.debug('[memento] selection updated while busy, deferring UI')
}
if (state === 'idle') updateSelectionUI()
}
async function refreshPageContext() {
@@ -410,15 +357,12 @@ async function loadSettings() {
async function loadNotebooks(preferredId) {
try {
await ensureApiPermission()
const url = `${apiBase()}/api/clip/notebooks`
const res = await fetch(url, { credentials: 'include' })
const res = await fetch(`${apiBase()}/api/clip/notebooks`, { credentials: 'include' })
if (!res.ok) {
connected = false
updateConnBadge()
if (res.status === 401) {
// Diagnostic : préciser l'URL configurée pour aider l'utilisateur à
// diagnostiquer un mismatch (localhost vs 127.0.0.1 vs LAN IP).
throw new Error(`${t('errLoginRequired')}\n${t('errLoginHintUrl', apiBase())}`)
throw new Error(t('errLoginRequired'))
}
throw new Error(t('errLoadNotebooks'))
}
@@ -459,11 +403,7 @@ function renderIdle() {
const authHint =
!connected && errorMessage
? `<div class="auth-hint">${escapeHtml(errorMessage).replace(/\n/g, '<br/>')}
<div style="margin-top:8px">
<button type="button" class="btn btn-secondary btn-sm" id="openLoginFromHint">${escapeHtml(t('openMomento'))}</button>
</div>
</div>`
? `<div class="auth-hint">${escapeHtml(errorMessage)}</div>`
: ''
els.screen.innerHTML = `