Zum Inhalt springen

Wie TabTTL einen Live-Countdown auf das Tab-Icon jeder Website malt und das Original spurlos zurücklegt.

JP 2 Min. Lesezeit

Die sichtbarste Funktion von TabTTL ist gleichzeitig die kleinste: ein Countdown direkt auf dem Icon jedes Tabs. Der abgelaufene Teil wird grau, als würde ein Uhrzeiger darüberstreichen. Das sieht einfach aus, aber damit es auf jeder Website funktioniert, brauchte es ein paar Tricks.

Der Browser lässt dich nicht auf Tabs zeichnen

Es gibt keine Extension-API für „zeichne auf das Icon dieses Tabs“. Ein Favicon ändert man nur so, wie die Seite selbst es tut: über ein <link rel="icon"> im <head>. Also läuft in jedem Tab ein kleines Content-Script, das kurzzeitig die Favicon-Verwaltung der Seite übernimmt.

Deaktivieren statt löschen

Der naive Ansatz entfernt die Icon-Links der Seite und fügt einen neuen hinzu. Das geht schief, sobald man aufhören will: Das Original-Markup ist weg. TabTTL benennt sie deshalb nur um:

ts
for (const link of document.querySelectorAll<HTMLLinkElement>('link[rel~="icon" i]')) {
	if (link.id === OWN_ID) continue;
	link.dataset.tabttlRel = link.rel; // Original merken
	link.rel = 'tabttl-disabled-icon'; // Browser ignorieren unbekannte rels
}

Endet der Countdown, bekommt jeder Link sein ursprüngliches rel zurück. Ein Detail: Browser zeigen das letzte Icon weiter an, bis ein neuer Icon-Link eingefügt wird. Wiederherstellen heißt also, das Element zu klonen und auszutauschen, nicht nur das Attribut zurückzusetzen.

Den Frame zeichnen

Das Original-Icon wird über das Hintergrundskript geladen (so bleibt das Canvas frei von CORS-Problemen), in voller Größe auf ein 32 × 32-Canvas gezeichnet, und darüber kommt das Overlay:

ts
ctx.clearRect(0, 0, SIZE, SIZE);
if (this.icon) ctx.drawImage(this.icon, 0, 0, SIZE, SIZE);
overlay(ctx, SIZE);
link.href = this.canvas.toDataURL('image/png');

Das Icon behält immer seine volle Größe. Eine frühere Version hat es verkleinert, um einen Ring darum zu legen, und damit sah jeder Tab kaputt aus. Overlays nutzen einen weichen Schatten statt harter Konturen, so sind sie auf hellen und dunklen Icons lesbar.

Seiten wehren sich

Gmail, Slack und viele andere tauschen ihr Favicon, um Ungelesenes anzuzeigen. Ein MutationObserver auf dem <head> bemerkt neue oder geänderte Icon-Links, deaktiviert sie wieder und markiert das Icon als geändert, damit der nächste Frame von der neuen Quelle zeichnet.

Nicht kodieren, was schon gezeichnet ist

toDataURL kostet eine PNG-Kodierung, und ein Countdown tickt. Jeder Render-Aufruf übergibt einen Schlüssel, der beschreibt, was er zeichnen würde (Stil, Restanteil auf den sichtbaren Schritt gerundet, Farbe). Haben sich weder Schlüssel noch Quell-Icon geändert, wird der Frame übersprungen, und so kosten die meisten Ticks nichts.

Die Seite so verlassen, wie man sie vorgefunden hat

Eine Erweiterung, die auf jeder Seite läuft, arbeitet in fremdem DOM. TabTTL ändert so wenig wie möglich, merkt sich genau, was es geändert hat, und kann alles davon zurücknehmen. So würde ich jede Erweiterung bauen, die fremde Seiten anfasst.

#browser-extensions#canvas#typescript

Über das Projekt

Expired 3
J by-jp.de
D D Docs: Alarms API
G G Pull request #42
F F Flight deals
R R Recipe: ramen
Live

TabTTL

Ungenutzte Tabs automatisch schließen, in Firefox und Edge.

Eine Erweiterung für Firefox und Edge, die ungenutzte Tabs gruppiert, schließt oder entlädt. Jeder Tab zählt auf seinem Icon herunter; oft besuchte Seiten bekommen mehr Zeit.

Projekt ansehen →

Weiterlesen