Een Chrome-extensie voor Pinterest-notities bouwen

Salo Door Salo 5 min. leestijd
Een Chrome-extensie voor Pinterest-notities bouwen

In deze tutorial bouw je het kleinste nuttige prototype voor Chrome Manifest V3: een privétekstveld op de detailpagina van een Pinterest-Pin, gekoppeld aan de numerieke Pin-ID en opgeslagen in chrome.storage.local. Het is nadrukkelijk een prototype, geen productierijpe kopie van Pinterests vroegere notitiefunctie.

Pinterests DOM kan zonder aankondiging veranderen. Houd selectors op één plek, boots Pinterests beschermde merkelementen niet na en test alle paginatypen en taal- of landversies die je ondersteunt.

1. Maak de Manifest V3-extensie

Maak een map met manifest.json en content.js. Het naslagwerk van Chrome voor manifestbestanden is de officiële bron voor de beschikbare sleutels.

{
  "manifest_version": 3,
  "name": "Prototype voor Pin-context",
  "version": "0.1.0",
  "description": "Bewaar lokaal een privénotitie bij een Pinterest-Pin.",
  "permissions": ["storage"],
  "content_scripts": [{
    "matches": ["https://*.pinterest.com/*"],
    "js": ["content.js"],
    "run_at": "document_idle"
  }]
}

Het URL-patroon is ruim omdat Pinterest navigatie aan de clientzijde gebruikt. Ondersteunt je functie maar enkele routes of landdomeinen, maak het patroon dan specifieker en documenteer dat bereik.

2. Leid een stabiele sleutel af uit de Pin-URL

Gebruik niet de positie of zichtbare titel van een kaart als sleutel. Lees de numerieke ID uit een canonieke route zoals /pin/…/ en geef in alle andere gevallen null terug.

function getPinId(url = location.href) {
  try {
    const { pathname } = new URL(url);
    const match = pathname.match(/\/pin\/(\d+)\/?/);
    return match ? match[1] : null;
  } catch {
    return null;
  }
}

Test geldige detail-URL's, queryparameters, pagina's zonder Pin, ongeldige URL's en alle regionale URL-patronen die je zegt te ondersteunen. Koppel nooit ongemerkt een notitie als de ID niet zeker is.

3. Bewaar een record met een versienummer

Leg het schema expliciet vast, zodat je gegevens later kunt migreren:

async function readNote(pinId) {
  const key = 'pin-note:' + pinId;
  const result = await chrome.storage.local.get(key);
  return result[key] ?? { version: 1, pinId, text: '', updatedAt: null };
}

async function writeNote(pinId, text) {
  const key = 'pin-note:' + pinId;
  const record = {
    version: 1,
    pinId,
    text,
    updatedAt: new Date().toISOString()
  };
  await chrome.storage.local.set({ [key]: record });
  return record;
}

Chrome vermeldt een standaardlimiet van 10 MB voor storage.local, die je kunt verhogen door de machtiging unlimitedStorage te gebruiken. Chrome vermeldt ook dat de lokale extensieopslag wordt gewist zodra de extensie wordt verwijderd. Lees de actuele documentatie over de Storage API en bouw een exportfunctie voordat je gebruikers vraagt belangrijke gegevens aan de extensie toe te vertrouwen.

4. Voeg een geïsoleerde, toegankelijke editor toe

Een Shadow DOM verkleint de kans op onbedoelde stijlconflicten. Het voorbeeld voegt de editor toe aan de hoofdtekst van de pagina en is daardoor niet afhankelijk van een kwetsbare Pinterest-klassenaam:

async function mountEditor(pinId) {
  if (document.querySelector('[data-pin-context-root]')) return;

  const host = document.createElement('aside');
  host.dataset.pinContextRoot = '';
  host.setAttribute('aria-label', 'Privénotitie bij Pin');
  document.body.append(host);

  const root = host.attachShadow({ mode: 'open' });
  const label = document.createElement('label');
  label.textContent = 'Privénotitie';
  const editor = document.createElement('textarea');
  editor.id = 'pin-note-editor';
  label.htmlFor = editor.id;
  editor.setAttribute('aria-label', 'Privénotitie bij deze Pin');
  const status = document.createElement('span');
  status.setAttribute('role', 'status');

  const saved = await readNote(pinId);
  editor.value = saved.text;
  root.append(label, editor, status);
  bindAutosave(editor, status, pinId);
}

Maak interfacetekst met textContent, niet met niet-vertrouwde inhoud in innerHTML. Zorg daarnaast voor een zichtbare focusstijl, voldoende contrast, een echt label, toetsenbordbediening en een statusmelding die de focus niet overneemt.

5. Sla op zonder bij elke toetsaanslag te schrijven

function bindAutosave(editor, status, pinId) {
  let saveTimer;
  editor.addEventListener('input', () => {
    status.textContent = 'Niet opgeslagen';
    clearTimeout(saveTimer);
    saveTimer = setTimeout(async () => {
      try {
        await writeNote(pinId, editor.value);
        status.textContent = 'Lokaal opgeslagen';
      } catch (error) {
        console.error('Opslaan van Pin-notitie mislukt', error);
        status.textContent = 'Opslaan mislukt';
      }
    }, 400);
  });
}

Sla in een productieversie ook openstaande invoer op bij een paginawissel, voorkom dat twee tabbladen elkaars wijzigingen overschrijven, stel een maximale notitielengte in en toon fouten door een overschreden opslaglimiet.

6. Verwerk Pinterests navigatie aan de clientzijde

Een handler die alleen bij het laden wordt uitgevoerd, mist navigatie tussen de feed en detailpagina's. Gebruik een idempotente afstemmingsfunctie en volg wijzigingen zonder de editor bij elke DOM-mutatie opnieuw toe te voegen:

let scheduled = false;

async function reconcile() {
  scheduled = false;
  const pinId = getPinId();
  const existing = document.querySelector('[data-pin-context-root]');
  if (!pinId) {
    existing?.remove();
    return;
  }
  if (existing?.dataset.pinId === pinId) return;
  existing?.remove();
  await mountEditor(pinId);
  const mounted = document.querySelector('[data-pin-context-root]');
  if (mounted) mounted.dataset.pinId = pinId;
}

new MutationObserver(() => {
  if (scheduled) return;
  scheduled = true;
  requestAnimationFrame(reconcile);
}).observe(document.documentElement, { childList: true, subtree: true });

reconcile();

Volg in een productieversie waar mogelijk ook rechtstreeks de navigatiestatus en koppel observers los zodra ze niet meer nodig zijn. Meet de prestaties op lange feeds: een correcte functie die de pagina vertraagt, blijft een slechte extensie.

7. Houd je aan de beveiligingseisen van Manifest V3

Manifest V3 staat geen op afstand gehoste uitvoerbare code toe. Neem uitvoerbaar JavaScript op in het extensiepakket, behoud het standaardbeleid voor inhoudsbeveiliging tenzij een wijziging goed te onderbouwen is, vermijd dynamische code-uitvoering en vraag alleen de machtigingen aan die de functie nodig heeft. Het Manifest V3-overzicht van Chrome legt het platformmodel uit.

8. Voeg toe wat een echt product nodig heeft

9. Test ook wat er mis kan gaan

  1. Laad de uitgepakte extensie via chrome://extensions.
  2. Open een feed, een bord, een Pin-detailpagina en een pagina zonder Pin.
  3. Ga zonder herladen van de ene naar de andere Pin en controleer of hun notities gescheiden blijven.
  4. Open dezelfde Pin in twee tabbladen en test hoe conflicten worden afgehandeld.
  5. Schakel opslag uit of simuleer een overschreden opslaglimiet en controleer de waarschuwing.
  6. Exporteer een testrecord, verwijder het en zet het daarna terug.
  7. Test toetsenbordnavigatie, zoomen, labels voor schermlezers en de interface op lichte en donkere pagina's.

De belangrijkste technische les

Het tekstveld is het eenvoudige deel. Een betrouwbare Pinterest-extensie vereist stabiele identificatie, robuuste verwerking van de paginalevenscyclus, een toegankelijke interface, beperkte machtigingen, gedocumenteerde opslag en een geteste manier om gegevens mee te nemen. Bouw die basis voordat je meer functies toevoegt.

Blijf je Pinterest-systeem verbeteren

Ga verder met de gids die bij je volgende stap past:

Salo

Over de auteur

Salo is productontwerper en ervaren gebruiker. Hij schrijft over digitale organisatie, Pinterest-werkwijzen en hulpmiddelen om beter na te denken.

Probeer de Notestopin-extensie voor Chrome

Voeg privénotities toe aan elke pin, orden ze met tags en vind later snel terug wat je hebt opgeslagen.

Toevoegen aan Chrome