← Tutti gli articoli

Tipi di azioni

Un'azione con un clic che copia qualsiasi pagina come Markdown pulito

Leggi qualcosa che vale la pena conservare e lo vuoi nei tuoi appunti. Copiare e incollare dal browser trascina dentro il menu di navigazione, tre annunci, una barra dei cookie e un groviglio di stili inline. Cio che vuoi davvero e Markdown pulito: il titolo, i paragrafi, i link, i blocchi di codice — nient'altro. Questo articolo costruisce un pulsante azione di JustZix che fa esattamente questo, con un clic.

Perche Markdown, e perche un pulsante azione

Markdown e il formato universale per gli appunti — si incolla in modo pulito in Obsidian, Notion, le issue di GitHub, il tuo editor, un file di testo semplice. L'obiettivo qui e un pulsante nella barra delle azioni di JustZix che converte in Markdown o la selezione di testo corrente o l'intero articolo e lo deposita nei tuoi appunti. Niente DevTools, nessuna app extra, nessuna pulizia manuale.

Un'azione di tipo BUTTON e perfetta per questo: mostra un pulsante etichettato nella barra delle azioni, e cliccandolo esegue il tuo JavaScript. Scriveremo ora quel JavaScript.

La strategia di conversione

Percorriamo il DOM ricorsivamente. Per ogni nodo decidiamo: e testo (emettilo), o un elemento che sappiamo convertire (emetti Markdown per esso), o qualcosa da saltare (nav, script, annunci). Tutto cio che non riconosciamo, ci ricorsiamo dentro — cosi i wrapper sconosciuti non perdono il loro contenuto. Quel comportamento di ricorsione predefinita e il ripiego al testo semplice.

// Elements we never want in the output
const SKIP = new Set([
  'SCRIPT', 'STYLE', 'NAV', 'HEADER', 'FOOTER', 'ASIDE',
  'NOSCRIPT', 'IFRAME', 'FORM', 'BUTTON', 'SVG'
]);

function isHidden(el) {
  const s = getComputedStyle(el);
  return s.display === 'none' || s.visibility === 'hidden';
}

Convertire gli elementi inline

La conversione inline gestisce la formattazione del testo corrente: grassetto, corsivo, codice, link. Restituisce una stringa, ricorrendo nei figli cosi i tag inline annidati funzionano.

function inline(node) {
  if (node.nodeType === Node.TEXT_NODE) {
    return node.textContent.replace(/\s+/g, ' ');
  }
  if (node.nodeType !== Node.ELEMENT_NODE) return '';
  if (SKIP.has(node.tagName) || isHidden(node)) return '';

  const inner = [...node.childNodes].map(inline).join('');
  switch (node.tagName) {
    case 'STRONG': case 'B':   return '**' + inner.trim() + '**';
    case 'EM': case 'I':       return '*' + inner.trim() + '*';
    case 'CODE':               return '`' + inner.trim() + '`';
    case 'BR':                 return '  \n';
    case 'A': {
      const href = node.getAttribute('href') || '';
      const abs = href ? new URL(href, location.href).href : '';
      return abs ? '[' + inner.trim() + '](' + abs + ')' : inner;
    }
    default:                   return inner;
  }
}

Nota la gestione dei link: risolviamo gli href relativi rispetto a location.href con il costruttore URL, cosi un link copiato funziona ancora quando lo incolli altrove.

Convertire gli elementi a blocco

La conversione a blocco gestisce i pezzi strutturali — titoli, paragrafi, elenchi, blocchi di codice, citazioni — e li unisce con righe vuote.

function block(node) {
  if (node.nodeType === Node.TEXT_NODE) {
    return node.textContent.trim();
  }
  if (node.nodeType !== Node.ELEMENT_NODE) return '';
  if (SKIP.has(node.tagName) || isHidden(node)) return '';

  const t = node.tagName;

  if (/^H[1-6]$/.test(t)) {
    return '#'.repeat(+t[1]) + ' ' + inline(node).trim();
  }
  if (t === 'P') return inline(node).trim();
  if (t === 'BLOCKQUOTE') {
    return inline(node).trim()
      .split('\n').map(l => '> ' + l).join('\n');
  }
  if (t === 'PRE') {
    return '```\n' + node.textContent.replace(/\n$/, '') + '\n```';
  }
  if (t === 'UL' || t === 'OL') {
    const ordered = t === 'OL';
    return [...node.children]
      .filter(li => li.tagName === 'LI')
      .map((li, i) => (ordered ? (i + 1) + '. ' : '- ')
        + inline(li).trim())
      .join('\n');
  }
  if (t === 'HR') return '---';
  if (t === 'IMG') {
    const alt = node.getAttribute('alt') || '';
    const src = node.src || '';
    return src ? '![' + alt + '](' + src + ')' : '';
  }

  // Unknown wrapper: recurse, keep the children
  return [...node.childNodes].map(block)
    .filter(Boolean).join('\n\n');
}

L'ultima riga e il ripiego: un <div>, <section> o <article> per cui non abbiamo una regola speciale ricorre semplicemente nei suoi figli. Nel caso peggiore, un elemento esotico decade al suo testo semplice — mai a nulla.

Prima la selezione, poi l'articolo

Il pulsante dovrebbe essere intelligente: se hai del testo selezionato, converte solo quello; altrimenti converte l'articolo principale. L'API Selection ci da un range che possiamo clonare in un frammento.

function getRoot() {
  const sel = window.getSelection();
  if (sel && sel.rangeCount && !sel.isCollapsed) {
    const frag = sel.getRangeAt(0).cloneContents();
    const wrap = document.createElement('div');
    wrap.appendChild(frag);
    return wrap;
  }
  // No selection: best guess at the main content
  return document.querySelector(
    'article, main, [role="main"], .post, .content'
  ) || document.body;
}

Un frammento di selezione clonato puo iniziare a meta elemento, quindi la conversione a blocco potrebbe vedere nodi parziali — va bene, la nostra regola di ricorsione predefinita la gestisce con grazia.

Collegarlo a un'azione BUTTON e copiare

Ora assembla i pezzi, costruisci la stringa finale e scrivila negli appunti. Questo e il corpo della tua azione BUTTON.

const root = getRoot();
const md = [...root.childNodes]
  .map(block)
  .filter(Boolean)
  .join('\n\n')
  .replace(/\n{3,}/g, '\n\n')   // collapse extra blank lines
  .trim();

navigator.clipboard.writeText(md)
  .then(() => JZ.toast('Copied ' + md.length + ' chars of Markdown'))
  .catch(() => {
    // Fallback for older clipboard restrictions
    const ta = document.createElement('textarea');
    ta.value = md;
    document.body.appendChild(ta);
    ta.select();
    document.execCommand('copy');
    ta.remove();
    JZ.toast('Copied (fallback)');
  });

Per trasformare questo in un pulsante: aggiungi un'azione di tipo BUTTON alla regola, etichettala "Copia come Markdown" e incolla il codice sopra come suo gestore. JZ.toast() e l'helper di JustZix per una rapida conferma sulla pagina — utile perche le scritture negli appunti sono altrimenti silenziose.

Rifiniture che vale la pena aggiungere

Perche gli appunti, non un download

Potresti invece attivare il download di un file .md, ma gli appunti vincono per prendere note: clicchi il pulsante, passi alla tua app di appunti, incolli. Nessun file da trovare, nessuna rinomina, nessuna pulizia. La chiamata navigator.clipboard.writeText ha bisogno di un gesto dell'utente — che un clic su un pulsante e, quindi funziona e basta.

Vedi anche

Un pulsante, Markdown pulito, zero pulizia. Installa JustZix, aggiungi un'azione BUTTON con il codice sopra e inizia a collezionare il web nel modo in cui la tua app di appunti lo vuole davvero.

Valuta questo articolo

Nessuna valutazione — sii il primo.

Provalo tu stesso

Installa JustZix e incolla qualsiasi snippet di questo articolo. Due minuti da zero a una regola funzionante su tutti i tuoi dispositivi.

Ottieni JustZix

Funzionalità · Come funziona · Esempi · Casi d'uso