EN | CS | Přihlásit | Registrovat

ConfirmationDialog

ConfirmationDialog je komponenta umožňující pohodlné ošetření akcí, vyžadujících zvýšenou pozornost a potvrzení uživatele. Díky revoluční schoponosti dynamických událostí ji lze snadno použít i v jiných komponentách jako je DataGrid. Jako samozřejmost je kompletní podpora AJAXu.

Download http://github­.com/DocX/con­firm-dialog/archives/mas­ter
Git http://github­.com/DocX/con­firm-dialog
Demo http://gdmt.cz/net­te-components/confirm-dialog-demo/
Forum thread http://forum.net­te.org/cs/2636-confirmationdialog
Autor © 2009–2010, Lukáš Doležal
Licence GPL
Nette 0.9+ PHP 5.2+

Co to umí

  • Zobrazení dialogu s otázkou a tlačítky „Ano“ a „Ne“ snadno jako volání signálů
  • Snadné „zajaxování“ celého dialogu.
  • Snadné propojení s komponentou DataGrid od Romana Sklenáře
  • Potvrzení akce je zabezpečeno proti CSRF útoku a neumožnuje změnit parametry akce.
  • Podporuje zobrazování doplňujících se otázek.
  • Funkční nezávisle na JS.

Confirmation Dialog je sám o sobě chápán jako zabezpečovací prvek a proto je u něj kladen velký důraz na bezpečnost. Je více než jen obdoba javascriptového onclick='return confirm(..)'. Nejen že je imunní vůči CSRF útoku, ale zamezuje i jakékoliv změně parametrů akce (například ID mazaného příspěvku) na straně klienta. Navíc je funkční i s vypnutým JS.

Instalace

Stáhněte si archív s komponentou ConfirmationDi­alog. Ve složce ConfirmationDialog se nachází vlastní komponenta, ve složce Example naleznete ukázkový presenter a soubor se stylem.

Složku ConfirmationDialog je vhodné umístit buď do app/components složky každého projektu nebo do složky libs, kterou může sdílet více aplikací najednou. Důležité ale je aby se načítal soubor ConfirmationDialog.php

Namespaces

Pokud používáte PHP 5.3 a Nette variantu se jmennými prostory, stačí v souboru ConfirmationDialog.php odkomentovat prvních pár řádků začínajících use.

Začínáme

Životní cyklus

Pro lepší pochopení „dynamických signálů“ si pro začátek ukážeme cestu, kterou komponenta projde od vytvoření po spuštění potvrzené akce:

  1. Vytvoření komponenty,
  2. Vytvoření „potvrzovače“, které vytvoří na komponentě nový signál a řekne komponentě, jakou metodu volat při jeho potvrzení uživatelem,
  3. Při obdržení tohoto signálu se provede následující:
    1. Parametry poslané se signálem a název „potvrzovače“ se uloží do session,
    2. Session se uloží pod unikátní token do hidden prvku formuláře,
    3. Z potvrzovače se vytáhne znění otázky,
    4. Zobrazí se potvrzovací dialog,
  4. Uživatel klikne na Ano:
    1. Přečte se token z dat poslaných formulářem,
    2. Podle tokenu se přečtou parametry a název „potvrzovače“ ze session,
    3. Najde se potvrzovač s názevem ze session a podle něj se zavolá uživatelská funkce,
  5. Session se smaže a komponenta se skryje.

Vytvoření komponenty

Aby komponenta správně fungovala, je potřeba ji vytvořit v továrničce presenteru.

function createComponentConfirmForm()
{
$form = new ConfirmationDialog();

dále komponentě vytvoříme „potvrzovače“

$form
->addConfirmer(
'delete', // název signálu bude 'confirmDelete!'
array($this, 'deleteItem'), // callback na funkci při kliku na YES
'Opravdu smazat?' // otázka (může být i callback vracející string)
)
->addConfirmer( // všimněte si Fluent rozhraní
'enable', // 'confirmEnable!'
array($this, 'enableItem'),
array($this, 'questionEnable')
);

//...

return $form;
}

Takto jsme dialog naučili přijímat dva signály confirmDelete! a confirmEnable!, při nichž se zobrazí potvrzovací formulář. Text otázky se v prvním případě zadal staticky, v druhém případě se při zobrazení formuláře zavolá metoda podobná následující:

function questionEnable($dialog, $params)
{
// $dialog je odkaz na ConfirmationDialog, může se tím například
// změnit element P s otázkou a nastavit třída pro DIV obklopující dialog
$dialog->getQuestionPrototype()->addClass('green');
$dialog->dialogClass = 'green';

// $params obsahují parametry, s nimiž byl zavolán zobrazovací signál
return "Opravdu aktivovat položku ID $params[id]?";
}

Metody, které jsou volány při potvrzení, mohou vypadat následnovně:

function deleteItem($id)
{
// smazani
}

Všimněte si, že metoda má parametry podobně jako jiné handlery signálů. To podporuje jednodný návrh aplikace v Nette. Metoda by se klidně mohla jmenovat handleDelete($id), tím by se ale otevřela bezpečnostní díra – taková metoda by šla zavolat stejně jako standartní signál z URL.

Ukázka šablony

V šabloně lze potvrzovací dialog vyvolat standartně zavoláním signálu. Widget dialogu umístěte kam chete aby se zobrazoval. Pomocí CSS s ním lze pohybovat (viz css v example).

@{control confirmForm}

{foreach $items as $item}
<a href="{link confirmForm:confirmDelete! id => $item->id}">Smazat položku {$item->name}</a>
<a href="{link confirmForm:confirmEnable! id => $item->id}">Aktivovat položku {$item->name}</a>
{/foreach}

zAJAXování

Komponentu lze velmi snadno zobrazovat AJAXově.

Pro správnou funkčnost AJAXu je potřeba, aby se JavaScript postaral o „zajaxování“ ajaxově vytvořených formulářů :) To lze udělat pomocí jQuery livequery pluginu nebo v novějších verzích jQuery pomocí delegate

Jediné co se k tomu potřebuje je skript od Honzy Marka na Ajaxové formuláře doplněný o schopnost AJAXovat za živa – livequery.

CSS třídu, kterou se dialog bude hlásat o zAJAXování lze změnit následovně:

$form->getFormElementPrototype()->addClass('ajax');

Symbióza s DataGridem

Nyní se dostáváme k tomu nejzajímavějšímu a tím je použití ConfirmationDialogu spolu s akcemi v DataGridu. Nejzajímavější na tom je, že na tom nic není :)

V presenteru si vytvoříme ConfirmationForm a jeho obslužné „potvrzovače“, jak už umíme. V továrničce DataGridu pak vytoříme jednoduše akci:

$grid->addAction('Delete item', 'confirmForm:confirmDelete!', null, true);

Nyní už víme proč ty „dynamické signály“. DataGrid totiž neumí přidat parametry k akci (mimo ID), jediné rozlišení je tedy pomocí jména signálu.

Zřetězená potvrzení

Představte si, že máte akci „smazat uživatele“. Ten má ale ke svému účtu přidružené své příspěvky, články, fotografie atd. Jako správní návrháři databáze máme nastaveny cizí klíče tak, aby nešlo takového uživatele jen tak smazat. Ale přesto chceme, aby měl admin moc takového uživatele pohodlně odstranit.

Mohli by jsme do tabulky dát 2 tlačítka, jedno normální a druhé mazající uživatele „silou“. To by ale bylo ve výsledku k ničemu, protože by byl admin (ne)obtěžován pouze jednou výzvou a nemusel by si uvědomit závažnost svého činu. Navíc by to nevypadalo hezky. ConfirmationDialog proto umožňuje řetězit potvrzení.

V továrně na dialog si vytoříme 2 potvrzovače:

function createComponentDialog()
{
...
->addConfirmer(
'delete',
array($this, 'deleteItem'),
'Opravdu smazat?'
)
->addConfirmer(
'absolutelyDelete', // 'confirmEnable!'
array($this, 'DeleteItemWOCheck'),
'Smazat se vším všudy?'
);
...
}

Metoda zpracovávající delete potom může vypadat takto:

function deleteItem($id)
{
if (!$db->getUser($id)->delete())
{
$this->flashMessage(
'Smazání selhalo, nějaké položky jsou připojeny na uživatele.',
'error'
);
$this->invalidateControl();

// zavolání další otázky

// POZOR - 2. parametr je POLE parametrů - položky tohoto pole se předají
// jako jednotlivé parametry obslužné funkci
$this['confirmForm']->showConfirm('absolutelyDelete', array('id' => $id));
}
}

function deleteItemWOCheck($id)
{
...
}

Tímto se zobrazí dialog s potvrzovačem absolutelyDelete a parametry, jaké jsou v poli. Po jeho potvrzení se spustí funkce deleteItemWOCheck s parametrem $id, který se uložil při zobrazování dialogu.


Komentáře Comments feed

matata | 12. 7. 2010, 11:17 | bug

na řádku #57 je závorka navíc

matata | 12. 7. 2010, 13:08 | bug

#309 radek, odkazuje se na CurlyBracketsFilter ty byli myslím odstraněny a nahrazeny LatteMacros

matata | 12. 7. 2010, 14:12 | comment

doporučuji doplňek zrevidovat

  • šablony jak v doplňku tak v ukázce jsou psány pro staré CurlyBrakets…
  • obsah tady na stránkách (php 5.2) neodpovídá kódu v balíku, respektivě směrováno na php 5.3
  • @ už se taky myslím neudávají?
DocX | 12. 7. 2010, 14:58 | comment

Diky za info. Aktualizoval jsem GIT repozitář a dal jsem odkaz na stažení přímo na něj.

Momentálně nepracuji s a nestihl jsem si porjít „nové“ Nette s LatteFiltry, takže nevím přesně co je potřeba. Budu rád, když to třeba na GITu forknete a upravíte nebo mi pošlete patch.

Jinak prosím příště mi dotazy posílejte raději na email nebo do fóra (mam tam upozornění), tady si toho nemusím všimnout a myslím, že k tomu tu komentáře ani nejsou ;)

Login to submit a comment