9. března 2026

Výběr textu: třídy Selection a Range

V této kapitole probereme výběr textu v dokumentu i ve formulářových polích, jako je <input>.

JavaScript umí přistupovat k existujícímu výběru, vybírat nebo rušit výběr celých DOM uzlů i jejich částí, odstranit vybraný obsah z dokumentu, zabalit jej do značky a podobně.

Návody na nejčastější úlohy najdete na konci kapitoly v části „Shrnutí“. Vaše aktuální potřeby to možná pokryje, ale pokud si přečtete celý text, dozvíte se mnohem víc.

Základní objekty Range a Selection se snadno používají a nebudete pak potřebovat žádný návod, jak je přinutit udělat to, co chcete.

Range

Základním konceptem výběru je třída Range (rozsah), což je v zásadě dvojice „hraničních bodů“: začátek a konec rozsahu.

Objekt třídy Range se vytváří bez parametrů:

let rozsah = new Range();

Pak můžeme nastavit hranice výběru voláním rozsah.setStart(uzel, pozice) a rozsah.setEnd(uzel, pozice).

Jak možná tušíte, později použijeme objekty třídy Range k výběru textu, ale napřed jich několik vytvořme.

Částečný výběr textu

Zajímavé je, že první argument uzel v obou metodách může být buď textový, nebo elementový uzel, a na tom pak závisí význam druhého argumentu.

Pokud je uzel textový uzel, pak pozice musí být pozice v jeho textu.

Máme-li například element <p>Hello</p>, můžeme vytvořit rozsah obsahující písmena „ll“ následovně:

<p id="p">Hello</p>
<script>
  let rozsah = new Range();
  rozsah.setStart(p.firstChild, 2);
  rozsah.setEnd(p.firstChild, 4);

  // toString na rozsahu vrátí jeho obsah jako text
  console.log(rozsah); // ll
</script>

Zde vezmeme první dítě uzlu <p> (což je textový uzel) a specifikujeme pozice textu uvnitř něho:

Výběr elementových uzlů

Jestliže uzel je elementový uzel, pak pozice musí být pořadí jeho dítěte.

To se hodí pro vytváření rozsahů, které obsahují celé uzly a nezastaví se někde uprostřed jejich textu.

Mějme například složitější fragment dokumentu:

<p id="p">Example: <i>italic</i> and <b>bold</b></p>

Zde je jeho DOM struktura s elementovými i textovými uzly:

Vytvořme rozsah pro "Example: <i>italic</i>".

Jak vidíme, tato věta se skládá z právě dvou dětí uzlu <p>, jejichž indexy jsou 0 a 1:

  • Počáteční bod má <p> jako rodičovský uzel a jeho pozice je 0.

    Můžeme jej tedy nastavit voláním rozsah.setStart(p, 0).

  • Koncový bod má také <p> jako rodičovský uzel, ale jeho pozice je 2 (specifikuje, kde má rozsah skončit, ale pozice není zahrnuta).

    Můžeme jej tedy nastavit voláním rozsah.setStart(p, 2).

Když si spustíte následující demo, uvidíte, že se text vybral:

<p id="p">Example: <i>italic</i> and <b>bold</b></p>

<script>
  let rozsah = new Range();

  rozsah.setStart(p, 0);
  rozsah.setEnd(p, 2);

  // toString na rozsahu vrací jeho obsah jako text bez značek
  console.log(rozsah); // Example: italic

  // tento rozsah aplikujeme na výběr v dokumentu (bude později vysvětleno)
  document.getSelection().addRange(rozsah);
</script>

Zde je flexibilnější zkušební příklad, v němž si můžete nastavit počáteční a koncové pořadí a prozkoumat jiné varianty:

<p id="p">Example: <i>italic</i> and <b>bold</b></p>

Od <input id="počátek" type="number" value=1> – Do <input id="konec" type="number" value=4>
<button id="tlačítko">Kliknutím vyberete</button>
<script>
  tlačítko.onclick = () => {
    let rozsah = new Range();

    rozsah.setStart(p, počátek.value);
    rozsah.setEnd(p, konec.value);

    // aplikujeme výběr, bude později vysvětleno
    document.getSelection().removeAllRanges();
    document.getSelection().addRange(rozsah);
  };
</script>

Například výběr ve stejném <p> od pozice 1 do 4 nám vydá rozsah <i>italic</i> and <b>bold</b>:

Počáteční a koncový uzel se mohou lišit

V setStart a setEnd nemusíme používat tentýž uzel. Rozsah se může táhnout přes mnoho navzájem nesouvisejících uzlů. Důležité je jen to, aby konec byl v dokumentu až za začátkem.

Výběr většího fragmentu

Učiňme v našem příkladu větší výběr, například:

Už víme, jak na to. Musíme jen nastavit začátek a konec jako relativní pozice v textových uzlech.

Potřebujeme vytvořit rozsah, který:

  • začíná na pozici 2 v prvním dítÄ›ti <p> (vezme vÅ¡echna písmena „Example: “ kromÄ› prvních dvou),
  • končí na pozici 3 v prvním dítÄ›ti <b> (vezme první tÅ™i písmena „bold“ , ale žádné další):
<p id="p">Example: <i>italic</i> and <b>bold</b></p>

<script>
  let rozsah = new Range();

  rozsah.setStart(p.firstChild, 2);
  rozsah.setEnd(p.querySelector('b').firstChild, 3);

  console.log(rozsah); // ample: italic and bol

  // použijeme tento rozsah pro výběr (vysvětlíme později)
  window.getSelection().addRange(rozsah);
</script>

Jak vidíte, je docela jednoduché vytvořit rozsah, jaký chceme.

Kdybychom chtěli vybírat celé uzly, můžeme do setStart/setEnd předávat elementy. Jinak můžeme pracovat na úrovni textu.

Vlastnosti objektu rozsahu

Objekt rozsahu, který jsme v našem příkladu vytvořili, má následující vlastnosti:

  • startContainer, startOffset – uzel a pozice začátku,
    • v uvedeném příkladu: první textový uzel uvnitÅ™ <p> a 2.
  • endContainer, endOffset – uzel a pozice konce,
    • v uvedeném příkladu: první textový uzel uvnitÅ™ <b> a 3.
  • collapsed – booleovská vlastnost, true, jestliže rozsah začíná a končí ve stejném bodÄ› (uvnitÅ™ rozsahu tedy není žádný obsah),
    • v uvedeném příkladu: false.
  • commonAncestorContainer – nejbližší společný pÅ™edek vÅ¡ech uzlů v rozsahu,
    • v uvedeném příkladu: <p>.

Metody pro nastavení rozsahu

K manipulaci s rozsahy slouží množství vhodných metod.

Už jsme viděli setStart a setEnd, nyní uvedeme jiné podobné metody.

Nastavení začátku:

  • setStart(uzel, pozice) nastaví začátek na pozici pozice v uzel
  • setStartBefore(uzel) nastaví začátek právÄ› pÅ™ed uzel
  • setStartAfter(uzel) nastaví začátek právÄ› za uzel

Nastavení konce (obdobné metody):

  • setEnd(uzel, pozice) nastaví konec na pozici pozice v uzel
  • setEndBefore(uzel) nastaví konec právÄ› pÅ™ed uzel
  • setEndAfter(uzel) nastaví konec právÄ› za uzel

Technicky mohou cokoli z toho udělat i setStart/setEnd, ale jiné metody jsou pohodlnější.

Ve všech těchto metodách může uzel být jak textový, tak elementový uzel: u textových uzlů pozice přeskočí uvedený počet znaků, zatímco u elementových uzlů uvedený počet dětských uzlů.

Existují i další metody pro vytvoření rozsahu:

  • selectNode(uzel) nastaví rozsah tak, aby byl vybrán celý uzel
  • selectNodeContents(uzel) nastaví rozsah tak, aby byl vybrán celý obsah uzlu uzel
  • collapse(naZačátek): pokud je naZačátek=true, nastaví konec=začátek, jinak nastaví začátek=konec, čímž se rozsah smrskne
  • cloneRange() vytvoří nový rozsah se stejným začátkem a koncem

Metody pro editaci rozsahu

Když je rozsah vytvořen, můžeme s jeho obsahem manipulovat pomocí následujících metod:

  • deleteContents() – odstraní obsah rozsahu z dokumentu
  • extractContents() – odstraní obsah rozsahu z dokumentu a vrátí jej jako DocumentFragment
  • cloneContents() – naklonuje obsah rozsahu a vrátí jej jako DocumentFragment
  • insertNode(uzel) – vloží uzel do dokumentu na začátek rozsahu
  • surroundContents(uzel) – zapouzdří obsah rozsahu do uzlu uzel. Aby to fungovalo, musí rozsah obsahovat otevírací i uzavírací značku pro vÅ¡echny elementy uvnitÅ™: nesmí to být částečný rozsah, napÅ™. <i>abc.

Pomocí těchto metod můžeme s vybranými uzly provádět v zásadě cokoli.

Zde je zkušební příklad, abyste je viděli v akci:

Klikáním na tlačítka spouštějte metody na výběru, „resetPříkladu“ jej resetuje.

<p id="p">Example: <i>italic</i> and <b>bold</b></p>

<p id="výsledek"></p>
<script>
  let rozsah = new Range();

  // Zde je uvedena každá předváděná metoda:
  let metody = {
    deleteContents() {
      rozsah.deleteContents()
    },
    extractContents() {
      let obsah = rozsah.extractContents();
      výsledek.innerHTML = "";
      výsledek.append("extrahováno: ", obsah);
    },
    cloneContents() {
      let obsah = rozsah.cloneContents();
      výsledek.innerHTML = "";
      výsledek.append("klonováno: ", obsah);
    },
    insertNode() {
      let novýUzel = document.createElement('u');
      novýUzel.innerHTML = "NOVÝ UZEL";
      rozsah.insertNode(novýUzel);
    },
    surroundContents() {
      let novýUzel = document.createElement('u');
      try {
        rozsah.surroundContents(novýUzel);
      } catch(e) { console.log(e) }
    },
    resetPříkladu() {
      p.innerHTML = `Example: <i>italic</i> and <b>bold</b>`;
      výsledek.innerHTML = "";

      rozsah.setStart(p.firstChild, 2);
      rozsah.setEnd(p.querySelector('b').firstChild, 3);

      window.getSelection().removeAllRanges();
      window.getSelection().addRange(rozsah);
    }
  };

  for(let metoda in metody) {
    document.write(`<div><button onclick="metody.${metoda}()">${metoda}</button></div>`);
  }

  metody.resetPříkladu();
</script>

Existují i metody pro porovnávání rozsahů, ale ty se používají jen zřídka. Kdybyste je potřebovali, prosíme obraťte se na specifikaci nebo manuál MDN.

Výběr

Range je obecný objekt pro správu rozsahů výběru, ale vytvoření Range neznamená, že uvidíme výběr na obrazovce.

Můžeme objekty Range vytvářet, předávat – samy o sobě vizuálně nic nevybírají.

Výběr v dokumentu představuje objekt třídy Selection, který můžeme získat pomocí window.getSelection() nebo document.getSelection(). Výběr může obsahovat nula nebo více rozsahů. Alespoň to tvrdí specifikace API Selection. V praxi však umožňuje výběr více rozsahů v dokumentu jedině Firefox, a to pomocí Ctrl+kliknutí (na Macu Cmd+kliknutí).

Zde je screenshot výběru se třemi rozsahy, vytvořený ve Firefoxu:

Ostatní prohlížeče podporují maximálně jeden rozsah. Jak uvidíme, některé metody třídy Selection předpokládají, že rozsahů může být víc, ale opakujeme, že ve všech prohlížečích s výjimkou Firefoxu je maximálně jeden.

Následuje malé demo, které zobrazí aktuální výběr (něco označte a klikněte) jako text:

Vlastnosti třídy Selection

Jak bylo řečeno, výběr může teoreticky obsahovat více rozsahů. Objekty těchto rozsahů můžeme získat metodou:

  • getRangeAt(i) – vrátí i-tý rozsah, počínaje 0. Ve vÅ¡ech prohlížečích kromÄ› Firefoxu se používá pouze 0.

Třída má i vlastnosti, jejichž používání je často pohodlnější.

Podobně jako rozsah, i objekt výběru má začátek, nazývaný „kotva“ („anchor“), a konec, nazývaný „fokus“ („focus“).

Hlavní vlastnosti výběru jsou:

  • anchorNode – uzel, kde výbÄ›r začíná,
  • anchorOffset – pozice v anchorNode, kde výbÄ›r začíná,
  • focusNode – uzel, kde výbÄ›r končí,
  • focusOffset – pozice ve focusNode, kde výbÄ›r končí,
  • isCollapsed – true, jestliže výbÄ›r nic neobsahuje (prázdný rozsah) nebo neexistuje,
  • rangeCount – počet rozsahů ve výbÄ›ru, ve vÅ¡ech prohlížečích kromÄ› Firefoxu maximálnÄ› 1.
Začátek/konec objektu Selection oproti Range

Mezi kotvou/fokusem výběru a začátkem/koncem objektu Range je důležitý rozdíl.

Jak víme, objekty Range mají vždy začátek před koncem.

U výběrů tomu tak vždy není.

Vybrat něco myší je možné oběma směry: „zleva doprava“ nebo „zprava doleva“.

Jinými slovy, když stisknete tlačítko myši a pak jí posunujete v dokumentu směrem dopředu, pak konec výběru (fokus) bude za začátkem (kotvou).

Například když uživatel začne vybírat myší a postupuje od „Example“ k „italic“:

…Ale stejný výběr lze provést i obráceně: začít od „italic“ a postupovat k „Example“ (směrem zpět), pak jeho konec (fokus) bude před začátkem (kotvou):

Události výběru

Následující události umožňují sledovat výběr:

  • elem.onselectstart – když je výbÄ›r zahájen specificky na elementu elem (nebo uvnitÅ™ nÄ›j). Například když na nÄ›m uživatel stiskne tlačítko myÅ¡i a začne pohybovat ukazatelem.
    • Zákaz standardní akce zruší zahájení výbÄ›ru. Začít výbÄ›r tímto elementem tedy pÅ™estane být možné, ale element bude stále možné vybrat. NávÅ¡tÄ›vník bude jen muset zahájit výbÄ›r jinde.
  • document.onselectionchange – když je výbÄ›r zahájen nebo zmÄ›nÄ›n.
    • Prosíme vÅ¡imnÄ›te si: tento handler lze nastavit jen na document, sleduje vÅ¡echny výbÄ›ry na nÄ›m.

Demo sledování výběru

Následuje malé demo, které sleduje aktuální výběr na document a zobrazí jeho hranice:

<p id="p">Vyberte mÄ›: <i>italic</i> and <b>bold</b></p>

Od <input id="výběrOd" disabled> – Do <input id="výběrDo" disabled>
<script>
  document.onselectionchange = function() {
    let výběr = document.getSelection();

    let {anchorNode, anchorOffset, focusNode, focusOffset} = výběr;

    // anchorNode a focusNode jsou obvykle textové uzly
    výběrOd.value = `${anchorNode?.data}, index ${anchorOffset}`;
    výběrDo.value = `${focusNode?.data}, index ${focusOffset}`;
  };
</script>

Demo kopírování výběru

Kopírovat vybraný obsah je možné dvěma způsoby:

  1. Můžeme jej pomocí document.getSelection().toString() získat jako text.
  2. Chceme-li zkopírovat úplný DOM, tj. chceme zachovat formátování, můžeme získat příslušné rozsahy pomocí getRangeAt(...). Objekt Range obsahuje metodu cloneContents(), která naklonuje jeho obsah a vrátí jej jako objekt třídy DocumentFragment, který můžeme vložit jinam.

Následuje demo kopírování vybraného obsahu jako text i jako DOM uzly:

<p id="p">Vyberte mÄ›: <i>italic</i> and <b>bold</b></p>

Klonováno: <span id="klonováno"></span>
<br>
Jako text: <span id="jakoText"></span>

<script>
  document.onselectionchange = function() {
    let výběr = document.getSelection();

    klonováno.innerHTML = jakoText.innerHTML = "";

    // Naklonujeme DOM uzly z rozsahů (zde podporujeme vícenásobný výběr)
    for (let i = 0; i < výběr.rangeCount; i++) {
      klonováno.append(výběr.getRangeAt(i).cloneContents());
    }

    // Získáme výběr jako text
    jakoText.innerHTML += výběr;
  };
</script>

Metody výběru

S výběrem můžeme pracovat pomocí přidávání a odstraňování rozsahů:

  • getRangeAt(i) – vrátí i-tý rozsah, počínaje 0. Ve vÅ¡ech prohlížečích kromÄ› Firefoxu se používá pouze 0.
  • addRange(rozsah) – pÅ™idá rozsah do výbÄ›ru. Jestliže už výbÄ›r má pÅ™idÄ›lený rozsah, vÅ¡echny prohlížeče kromÄ› Firefoxu toto volání ignorují.
  • removeRange(rozsah) – odstraní rozsah z výbÄ›ru.
  • removeAllRanges() – odstraní vÅ¡echny rozsahy.
  • empty() – totéž jako removeAllRanges.

Existují i pohodlnější metody, které umožňují manipulovat s rozsahem výběru přímo, bez mezilehlého objektu Range:

  • collapse(uzel, pozice) – nahradí vybraný rozsah novým, který začíná a končí v zadaném uzlu uzel na pozici pozice,
  • setPosition(uzel, pozice) – totéž jako collapse,
  • collapseToStart() – smrskne výbÄ›r (nahradí jej prázdným rozsahem) na jeho začátek,
  • collapseToEnd() – smrskne výbÄ›r na jeho konec,
  • extend(uzel, pozice) – pÅ™esune fokus výbÄ›ru na zadaný uzel na pozici pozice,
  • setBaseAndExtent(kotvaUzel, kotvaPozice, fokusUzel, fokusPozice) – nahradí vybraný rozsah zadaným začátkem kotvaUzel/kotvaPozice a koncem fokusUzel/fokusPozice. VeÅ¡kerý obsah mezi nimi bude vybrán,
  • selectAllChildren(uzel) – vybere vÅ¡echny dÄ›ti uzlu uzel,
  • deleteFromDocument() – odstraní vybraný obsah z dokumentu,
  • containsNode(uzel, umožnitČástečnýVýbÄ›r = false) – ověří, zda výbÄ›r obsahuje uzel (je-li druhý argument true, stačí, když obsahuje jen jeho část).

Pro většinu úloh tyto metody vyhovují a není třeba přistupovat k podkladovému objektu Range.

Například vybereme celý obsah odstavce <p>:

<p id="p">Vyberte mÄ›: <i>italic</i> and <b>bold</b></p>

<script>
  // výběr od 0. dítěte značky <p> do posledního dítěte
  document.getSelection().setBaseAndExtent(p, 0, p, p.childNodes.length);
</script>

Totéž za použití rozsahů:

<p id="p">Vyberte mÄ›: <i>italic</i> a <b>bold</b></p>

<script>
  let rozsah = new Range();
  rozsah.selectNodeContents(p); // nebo selectNode(p), chceme-li vybrat i značku <p>

  document.getSelection().removeAllRanges(); // zrušíme existující výběr, je-li nějaký
  document.getSelection().addRange(rozsah);
</script>
Když něco vybíráte, napřed odstraňte již existující výběr

Jestliže v dokumentu již nějaký výběr existuje, napřed jej vyprázdněte voláním removeAllRanges() a teprve pak přidávejte rozsahy. Jinak budou všechny prohlížeče kromě Firefoxu nové rozsahy ignorovat.

Výjimkou jsou některé metody výběru, které nahrazují existující výběr, například setBaseAndExtent.

Výběr v ovládacích prvcích formulářů

Elementy formulářů, např. input a textarea, poskytují speciální API pro výběr, které neobsahuje objekty Selection nebo Range. Protože vstupní hodnota je čistý text a nikoli HTML kód, nejsou takové objekty zapotřebí a všechno je pak mnohem snazší.

Vlastnosti:

  • input.selectionStart – pozice začátku výbÄ›ru (zapisovatelná),
  • input.selectionEnd – pozice konce výbÄ›ru (zapisovatelná),
  • input.selectionDirection – smÄ›r výbÄ›ru, jeden z "forward" (dopÅ™edu), "backward" (dozadu) nebo "none" (žádný, napÅ™. pokud byl výbÄ›r proveden dvojitým kliknutím myÅ¡i).

Události:

  • input.onselect – spustí se, když je nÄ›co vybráno.

Metody:

  • input.select() – vybere vÅ¡echen obsah textového ovládacího prvku (místo input může být textarea),

  • input.setSelectionRange(začátek, konec, [smÄ›r]) – zmÄ›ní výbÄ›r tak, aby se táhl od pozice začátek do pozice konec v zadaném smÄ›ru (nepovinný),

  • input.setRangeText(náhrada, [začátek], [konec], [režimVýbÄ›ru]) – nahradí text v zadaném rozsahu novým textem.

    Pokud jsou uvedeny nepovinné argumenty začátek a konec, nastavují začátek a konec rozsahu, jinak se použije uživatelský výběr.

    Poslední argument, režimVýběru, stanovuje, jak bude výběr nastaven po nahrazení textu. Možné hodnoty jsou:

    • "select" – bude vybrán novÄ› vložený text.
    • "start" – rozsah výbÄ›ru se smrskne právÄ› pÅ™ed vložený text (kurzor bude hned pÅ™ed ním).
    • "end" – rozsah výbÄ›ru se smrskne právÄ› za vložený text (kurzor bude hned za ním).
    • "preserve" – pokusí se zachovat výbÄ›r. Tato hodnota je standardní.

Podívejme se nyní na tyto metody v akci.

Příklad: sledování výběru

Například následující kód sleduje výběr pomocí události onselect:

<textarea id="area" style="width:80%;height:60px">
Výběr v tomto textu aktualizuje hodnoty pod ním.
</textarea>
<br>
Od <input id="výběrOd" disabled> – Do <input id="výběrDo" disabled>

<script>
  area.onselect = function() {
    výběrOd.value = area.selectionStart;
    výběrDo.value = area.selectionEnd;
  };
</script>

Prosíme všimněte si:

  • Událost onselect se spustí, když je nÄ›co vybráno, ale ne tehdy, když je výbÄ›r odstranÄ›n.
  • Událost document.onselectionchange by se podle specifikace nemÄ›la spouÅ¡tÄ›t pÅ™i výbÄ›rech uvnitÅ™ formulářového ovládacího prvku, protože ty se nevztahují k výbÄ›ru a rozsahům v document. NÄ›které prohlížeče ji generují, ale nemÄ›li bychom se na to spoléhat.

Příklad: pohyb kurzoru

Vlastnosti selectionStart a selectionEnd můžeme měnit a tím nastavovat výběr.

Důležitý krajní případ je, když se selectionStart a selectionEnd navzájem rovnají. Pak specifikují právě pozici kurzoru. Nebo, jinak řečeno, když není nic zvoleno, výběr je smrsknut na pozici kurzoru.

Nastavením selectionStart a selectionEnd na stejnou hodnotu tedy pohybujeme kurzorem.

Příklad:

<textarea id="area" style="width:80%;height:60px">
Když na mě vstoupíte, kurzor bude na pozici 10.
</textarea>

<script>
  area.onfocus = () => {
    // setTimeout s nulovou prodlevou se spustí poté, co skončí akce prohlížeče "focus"
    setTimeout(() => {
      // můžeme nastavit jakýkoli výběr
      // bude-li start=end, kurzor se přesune právě na toto místo
      area.selectionStart = area.selectionEnd = 10;
    });
  };
</script>

Příklad: modifikace výběru

K modifikaci výběru můžeme použít metodu input.setRangeText(). Můžeme samozřejmě načíst selectionStart/End a při znalosti výběru změnit odpovídající podřetězec hodnoty value, ale setRangeText je silnější a často i vhodnější.

Tato metoda je trochu složitější. V nejjednodušší formě s jedním argumentem nahradí uživatelem vybraný řetězec a odstraní výběr.

Například zde bude uživatelův výběr obklopen *...*:

<input id="vstup" style="width:200px" value="Vyberte zde text a stiskněte tlačítko">
<button id="tlačítko">Obklopit výběr hvězdičkami *...*</button>

<script>
tlačítko.onclick = () => {
  if (vstup.selectionStart == vstup.selectionEnd) {
    return; // nebylo nic vybráno
  }

  let výběr = vstup.value.slice(vstup.selectionStart, vstup.selectionEnd);
  vstup.setRangeText(`*${výběr}*`);
};
</script>

Dalšími argumenty můžeme nastavit začátek a konec rozsahu.

V tomto příkladu najdeme ve vstupním textu "TOTO", nahradíme je a ponecháme nahrazující text vybraný:

<input id="vstup" style="width:200px" value="Nahradit TOTO v textu">
<button id="tlačítko">Nahradit TOTO</button>

<script>
tlačítko.onclick = () => {
  let pozice = vstup.value.indexOf("TOTO");
  if (pozice >= 0) {
    vstup.setRangeText("*TOTO*", pozice, pozice + 4, "select");
    vstup.focus(); // nastavením fokusu zviditelníme výběr
  }
};
</script>

Příklad: vložení textu na pozici kurzoru

Jestliže není nic vybráno nebo jestliže v setRangeText použijeme stejný začátek a konec, pak bude pouze vložen nový text a nic se neodstraní.

Pomocí setRangeText můžeme také něco vložit „na pozici kurzoru“.

Následující tlačítko vloží "AHOJ" na pozici kurzoru a umístí kurzor hned za něj. Pokud výběr není prázdný, bude nahrazen (porovnáním selectionStart!=selectionEnd to můžeme zjistit a pak místo toho udělat něco jiného):

<input id="vstup" style="width:200px" value="Text Text Text Text Text">
<button id="tlačítko">Vložit "AHOJ" na pozici kurzoru</button>

<script>
  tlačítko.onclick = () => {
    vstup.setRangeText("AHOJ", vstup.selectionStart, vstup.selectionEnd, "end");
    vstup.focus();
  };
</script>

Zákaz výběru

K tomu, abychom zakázali něco vybrat, máme tři možnosti:

  1. Použít CSS vlastnost user-select: none.

    <style>
    #elem {
      user-select: none;
    }
    </style>
    <div>Lze vybrat <div id="elem">Nelze vybrat</div> Lze vybrat</div>

    Tím se zabrání tomu, aby výběr začínal na elem, ale uživatel může zahájit výběr jinde a elem do něj zahrnout.

    Pak se elem stane součástí document.getSelection(), takže k výběru ve skutečnosti dojde, ale jeho obsah bude při operaci kopírování a vložení obvykle ignorován.

  2. Zakázat standardní akci v událostech onselectstart nebo mousedown.

    <div>Lze vybrat <div id="elem">Nelze vybrat</div> Lze vybrat</div>
    
    <script>
      elem.onselectstart = () => false;
    </script>

    Tím se zakáže zahájit výběr na elem, ale návštěvník jej může zahájit na jiném elementu a pak rozšířit na elem.

    To se hodí, když je na stejné akci, která spouští výběr (např. mousedown), jiný handler události. Tím tedy zakážeme výběr, abychom se vyhnuli konfliktu, ale stále umožníme kopírovat obsah elem.

  3. Můžeme také pomocí document.getSelection().empty() odstranit výběr poté, co k němu dojde. To se však používá zřídka, neboť to způsobuje nechtěné blikání, když se výběr objeví a zmizí.

Odkazy

Shrnutí

Probrali jsme dvě různá API pro výběr:

  1. Pro dokument: objekty Selection a Range.
  2. Pro input, textarea: další metody a vlastnosti.

Druhé uvedené API je velmi jednoduché, neboť pracuje s textem.

Pravděpodobně nejčastěji používané návody jsou:

  1. Získání výběru:
    let výběr = document.getSelection();
    
    let klonovaný = /* element, do kterého chceme naklonovat vybrané uzly */;
    
    // pak aplikujeme metody Range na výběr.getRangeAt(0)
    // nebo jako zde na všechny rozsahy, chceme-li podporovat vícenásobný výběr
    for (let i = 0; i < výběr.rangeCount; i++) {
      klonovaný.append(výběr.getRangeAt(i).cloneContents());
    }
  2. Nastavení výběru:
    let výběr = document.getSelection();
    
    // přímo:
    výběr.setBaseAndExtent(...od...do...);
    
    // nebo můžeme vytvořit rozsah a:
    výběr.removeAllRanges();
    výběr.addRange(rozsah);

A nakonec ke kurzoru. Pozice kurzoru v editovatelných prvcích, např. <textarea>, je vždy na začátku nebo na konci výběru. Pomocí výběru můžeme zjistit pozici kurzoru nebo přemístit kurzor nastavením elem.selectionStart a elem.selectionEnd.

Mapa tutoriálu

Komentáře

přečtěte si před komentováním…
  • Máte-li návrhy na zlepÅ¡ení, vytvoÅ™te prosím issue na GitHubu nebo pull request místo komentáře.
  • Pokud v článku něčemu nerozumíte, napiÅ¡te prosím, čemu pÅ™esnÄ› a na kterém místÄ›.
  • Pro vložení nÄ›kolika slov kódu použijte značku <code>, pro nÄ›kolik řádků je obalte značkou <pre>, pro více než 10 řádků vložte odkaz na pískoviÅ¡tÄ› (plnkr, jsbin, codepen…)