Webdesignérův průvodce po HTML5: Táhni a srůstej

Čtenář jistě promine kulturní narážku v nadpisu. Samosebou jde o implementaci metody drag-and-drop, tedy česky „táhni a pusť“. Podpora pro tuto metodu je totiž zahrnuta již do specifikace HTML5, takže už není potřeba k těmto účelům využívat JavaScriptových knihoven (i když se JavaScriptu nevyhneme).

Seriál: Webdesignérův průvodce po HTML5 (21 dílů)

  1. Webdesignérův průvodce po HTML5 – díl nultý 25.5.2010
  2. Webdesignérův průvodce po HTML5 – nová sémantika 1.6.2010
  3. Webdesignérův průvodce po HTML5 – nová sémantika II 8.6.2010
  4. Webdesignérův průvodce po HTML5 – pohyblivé obrázky 15.6.2010
  5. Webdesignérův průvodce po HTML5 – používáme pohyblivé obrázky 22.6.2010
  6. Webdesignérův průvodce po HTML5 – taháme data od návštěvníka 29.6.2010
  7. HTML5 Audio: rádio ve vašich stránkách 13.7.2010
  8. Webdesignérův průvodce po HTML5: Microdata 20.7.2010
  9. AppCache: webové aplikace i bez připojení 27.7.2010
  10. Webdesignérův průvodce po HTML5: WebStorage 3.8.2010
  11. Webdesignérův průvodce po HTML5: Multithreading s WebWorkers 10.8.2010
  12. Webdesignérův průvodce po HTML5: Databáze v prohlížečích 17.8.2010
  13. Webdesignérův průvodce po HTML5: Shrnutí a rozhrnutí 24.8.2010
  14. HTML5: ukládáme si data k elementům 6.12.2010
  15. Webdesignérův průvodce po HTML5: Táhni a srůstej 5.1.2011
  16. HTML5: První krůčky s FileSystem API 15.2.2011
  17. Mobilizujeme web v HTML5 4.4.2011
  18. Single Page Apps a řešení problémů s historií 1.6.2011
  19. Page Visibility API: Kouká na mě vůbec někdo? 10.8.2011
  20. Práce se soubory v prohlížeči, díl 1 15.8.2011
  21. Práce se soubory v prohlížeči, díl 2 5.9.2011

Technika drag-n-drop (Drag&Drop, táhni a pusť) je jednou ze základních metod práce s objekty v grafických UI, kdy pomocí vstupního zařízení je objekt „uchopen“, pak „přenesen“ na jiné místo a tam „položen“ či „vložen“, dle kontextu. Není divu, že webové aplikace mají potřebu tuto techniku implementovat taky, a specifikace HTML5 jim v tomto vychází vstříc.

Základy

Pokud chceme něco táhnout a pustit, musíme mít ve stránce dva elementy:

  1. ten, který se bude přesouvat (draggable)
  2. ten, nad kterým bude element puštěn (container)

Netřeba v tom hledat žádné složitosti – jak tažený objekt, tak kontejner může být obyčejný div.

Draggable

Elementy, které budou přetahovány, musí mít nastavený atribut draggable na hodnotu true. Zde poznámka: Při testech nestačilo pouhé uvedení atributu (jak umožňuje HTML) ani nastavení např. na hodnotu 1 či „on“, bylo třeba zapsat „draggable=true“. Pokud má element nastaven draggable atribut, bude možné jej uchopit a táhnout. Bez něho se bude při podobném pokusu zvýrazňovat text.

<div id=draggable1 draggable=true>Prvek 1</div>

Elementy, které lze přetahovat, budou vyvolávat i události, konkrétně dragstart a dragend.

dragstart

Událost „dragstart“ je vyvolána ve chvíli, kdy uživatel zahájí tažení objektu. V obsluze této události se nejčastěji nastavuje obsah („náklad“, dataTransfer) daného elementu, může se nastavit i „zástupce“, který bude zobrazen během přetahování a nastavují se např. i povolené operace (kopírování, přesun, vytvoření odkazu…) Obsluha události může celou operaci zrušit, pokud vrátí hodnotu false.

dragend

Pokud skončí tažení, ať už puštěním nebo zrušením, je vyvolána událost dragend. Obsluha by měla uklidit (odstranit dataTransfer).

Container

Kontejner, tedy oblast, do níž jsou přetahované objekty „vhazovány“, nemusí mít žádný speciální atribut (před krátkým časem se v návrhu spcifikace objevil atribut „dropzone“, ale je ve stádiu „first draw“). Stačí pouze řádně obsloužit příslušné události.

dragenter

Událost je vyvolána, pokud uživatel přetáhne objekt nad aktuální element. Není nutné ji implementovat.

dragover

Událost je vyvolávána, dokud se objekt pohybuje nad elementem. Pokud obsluha vrací true, prohlížeč naznačí uživateli, že zde nelze objekt upustit. Pokud obslužná rutina vrátí false, lze objekt pustit. V obsluze této metody je možné nastavit např. způsob přetažení (copy / move / link) apod.

drop

Ukončuje celou operaci přetažení. V obsluze této události je potřeba zpracovat celou operaci a udělat potřebné (přesunout objekt na nové místo, vyvolat akci apod.)

Posloupnost událostí při úspěšné operaci přetažení je následující:

  1. dragstart @ draggable
  2. dragenter @ container
  3. dragover @ container
  4. drop @ container
  5. dragend @ draggable

Ukázka

Ukažme si jednoduché demo. Začneme vytvořením tří oblastí:

<!DOCTYPE html>
<meta charset=utf-8>
<html>
  <head>
    <title>Drag'n'Drop Demo</title>
  </head>
  <body>
    <h1>Drag'n'Drop Demo</h1>
    <div id=container1 ondragover="return over(event)" ondrop="return drop(event)">
      <h2>Zásobník</h2>   
    </div>
   
    <div id=container2 ondragover="return over(event)" ondrop="return drop(event)">
      <h2>Sudá</h2>
    </div>
    <div id=container3 ondragover="return over(event)" ondrop="return drop(event)">
      <h2>Lichá</h2>
    </div>
   
    <div id=container>
      <h2>Konzole</h2>
      <textarea id=log></textarea>
    </div>
  </body>
</html>

Vytvořili jsme si tři oblasti – kontejnery (plus jednu testovací, kde se bude vypisovat log). Do první oblasti („zásobníku“) si umístíme objekty, které budeme přetahovat:

    <div id=container1 ondragover="return over(event)" ondrop="return drop(event)">
      <h2>Zásobník</h2>
   
      <div id=draggable1 draggable=true ondragstart="return start(event)" ondragend="return end(event)">Prvek 1</div>
      <div id=draggable2 draggable=true ondragstart="return start(event)" ondragend="return end(event)">Prvek 2</div>
      <div id=draggable3 draggable=true ondragstart="return start(event)" ondragend="return end(event)">Prvek 3</div>
      <div id=draggable4 draggable=true ondragstart="return start(event)" ondragend="return end(event)">Prvek 4</div>
   
    </div>

Objekty mají nastavenou obsluhu událostí dragstart i dragend  a mají atribut  draggable.

Než se dostaneme k vlastnímu oživení, tak si elementy trošku nastylujme:

    <style>
      #container1, #container2, #container3, #container {
        float:left; width:250px; height:550px;
        padding:10px; margin:10px;
        background-color: #cff;}
      #draggable1, #draggable2, #draggable3, #draggable4, #draggable {
        width:75px; height:70px; padding:5px;
        margin:5px;background-color: #ffc;}
      #log {width:230px;height:400px;}
    </style>

Obsluha událostí

Aby dávalo přetahování nějaký smysl, je třeba nastavit obsluhu patřičných událostí. My si v příkladu ukážeme i využití objektu dataTransfer, pomocí něhož můžeme dát přetahovanému elementu nějaký „vnitřní“ obsah – můžeme nastavit jeho reprezentaci v různých formátech, podobně jako např. u systémové schránky.

Ondragstart

      function start(e) {
        e.dataTransfer.effectAllowed='all';
        e.dataTransfer.setData("text/plain", e.target.getAttribute('id'));
        e.dataTransfer.setDragImage(e.target, 10, 50);
        return true;
      }

První řádek obsluhy události říká, že přetahovaný objekt lze kopírovat, přesouvat i vytvářet zástupce ( effectAllowed='all'). Druhý řádek nastavuje reprezentaci objektu pro kontejnery, které jsou schopné přijmout prostý text (text/plain). Hodnota bude rovna id příslušného elementu. Pokud si tedy objekt přetáhneme do textarea (nebo třeba do textového editoru), získáme řetězec, např. „draggable1“. Analogicky bychom mohli nastavit obsah pro „text/html“, a ten by byl použit tam, kde lze vkládat HTML (rich text editory apod.) či jakýkoli jiný typ obsahu (obrázek, soubor, URL, …)

Třetí řádek nastavuje „obrázek“, který bude symbolizovat objekt během tažení. Zde je to objekt sám. Jak vidíte, lze nastavit i bod, v němž bude kurzor (to jsou ty dvě čísla).

Vracíme true, operace přetahování je povolena.

Ondragend

      function end(e) {
        e.dataTransfer.clearData("text/plain");
        return true;
      }

Po skončení přesunu uklidíme – tedy smažeme obsah v objektu dataTransfer a vrátíme true – vše dopadlo dobře. Ve Firefoxu to bohužel nedopadne dobře – vrátí chybu, protože ve FF nelze s objektem dataTransfer manipulovat jinde než v ondragstart.

Ondragover

      function over(e) {
        var iddraggable = e.dataTransfer.getData("text/plain");
        var id = e.target.getAttribute('id');
        if (id =='container1') {e.preventDefault();return false;}
        if(id =='container2' && (iddraggable == 'draggable2' || iddraggable == 'draggable4'))
          {e.preventDefault();return false;}
          else if (id =='container3' && (iddraggable == 'draggable1' || iddraggable =='draggable3'))
            {e.preventDefault();return false;}
            else return true;
      }

Obsluha události dragover je vyvolávána, jak jsme si řekli, po dobu co se objekt pohybuje nad kontejnerem. Identifikátor taženého objektu zjistíme z textové reprezentace (viz výše, uložili jsme si jej tam v dragstart). Identifikátor kontejneru zjistíme z cíle události ( event.target).

Pomocí jednoduchých pravidel pak rozhodneme o tom, zda povolíme puštění. Nad kontejnerem 1 přijmeme vše, takže jen vrátíme false (zde false znamená, že je možno pustit, viz výše!) Nad kontejnerem 2 přijmeme jen objekty 2 a 4, nad trojkou jen 1 a 3 (čistě jako ukázku možností, nemá to žádný hlubší význam). Tam, kde je povoleno puštění objektu, vrátíme false, jinak true. Pro jistotu ještě zabráníme vyvolání výchozí obsluhy (mělo by stačit prosté return false, ale podle některých uživatelů jsou prohlížeče, v nichž to nestačí).

Ondrop

      function drop(e) {
        e.stopPropagation();
        e.preventDefault();
        var iddraggable = e.dataTransfer.getData("text/plain");
        e.target.appendChild (document.getElementById(iddraggable));
        return false;
      }

Puštění objektu nejprve zabrání vyvolání výchozí obsluze událostí. Zjistíme si ID přetaženého elementu (máme ho v dataTransfer) a daný element přesuneme do cílové oblasti.

V ukázce je v rámci obsluhy události drop ještě výpis objektu dataTransfer do logovacího okna.

Shrnutí

Drag and drop nalezne své využití v mnoha webových aplikacích a pomůže zvýšit míru jejich integrace se zbytkem systému. Díky nativní podpoře lze např. přetahovat objekty (soubory) z pracovní plochy systému do „drop kontejnerů“ na webové stránce.

K tématu:

Začal programovat v roce 1984 s programovatelnou kalkulačkou. Pokračoval k BASICu, assembleru Z80, Forthu, Pascalu, Céčku, dalším assemblerům, před časem v PHP a teď by rád neprogramoval a radši se věnoval starým počítačům.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 4

Přehled komentářů

bauglir Pár doplnění
Martin Malý Re: Pár doplnění
bauglir Re: Pár doplnění
PAPoUcH pěkná vychávka
Zdroj: https://www.zdrojak.cz/?p=3398