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
- Webdesignérův průvodce po HTML5: Shrnutí a rozhrnutí
- HTML5: ukládáme si data k elementům
- Webdesignérův průvodce po HTML5: Táhni a srůstej
- HTML5: První krůčky s FileSystem API
- Mobilizujeme web v HTML5
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:
- ten, který se bude přesouvat (draggable)
- 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í:
- dragstart @ draggable
- dragenter @ container
- dragover @ container
- drop @ container
- 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:
Školení Google Analytics pro pokročilé

- Jak využít nové funkce Google Analytics
- Vyhodnocování kampaní díky používání Multichannel funnels
- Kde návštěvníci vašeho webu utíkají z objednávacího procesu.
- Nebudete opakovat časté chyby při vyhodnocování dat o návštěvnosti.
Detailní informace o školení Google Analytics pro pokročilé »
Seriál Webdesignérův průvodce po HTML5
- Webdesignérův průvodce po HTML5: Shrnutí a rozhrnutí
- HTML5: ukládáme si data k elementům
- Webdesignérův průvodce po HTML5: Táhni a srůstej
- HTML5: První krůčky s FileSystem API
- Mobilizujeme web v HTML5
Přehled názorů
Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.

