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/confirm-dialog/archives/master |
| Git | http://github.com/DocX/confirm-dialog |
| Demo | mimo provoz :-( |
| Forum thread | http://forum.nette.org/cs/2636-confirmationdialog |
| Autor | © 2009–2010, Lukáš Doležal |
| Licence | LGPL (knihovna) & CC-BY (Demo) |
| Nette | 0.9+ PHP 5.2+ (info k 2.0 beta na fóru od MartyIX) |
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 ConfirmationDialog.
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:
- Vytvoření komponenty,
- Vytvoření „potvrzovače“, které vytvoří na komponentě nový signál a řekne komponentě, jakou metodu volat při jeho potvrzení uživatelem,
- Při obdržení tohoto signálu se provede následující:
- Parametry poslané se signálem a název „potvrzovače“ se uloží do session,
- Session se uloží pod unikátní token do hidden prvku formuláře,
- Z potvrzovače se vytáhne znění otázky,
- Zobrazí se potvrzovací dialog,
- Uživatel klikne na Ano:
- Přečte se token z dat poslaných formulářem,
- Podle tokenu se přečtou parametry a název „potvrzovače“ ze session,
- Najde se potvrzovač s názevem ze session a podle něj se zavolá uživatelská funkce,
- 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 
h4kuna | 12. 7. 2010, 13:08 | bug
#309 radek, odkazuje se na CurlyBracketsFilter ty byli myslím odstraněny a nahrazeny LatteMacros
h4kuna | 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 ;)
Phalanx | 5. 3. 2011, 8:52 | comment
Pokud použijete verzi Nette s namespace (v5.3) je nutné:
ConfirmationDialog.php odkomentovat prvních pár řádků začínajících use
@layout.phtml změnit @{include $content} na {include #content}
config.ini vložit kódování php.default_charset = „UTF-8“ (jinak chyba s neznámým ‚encoding‘)
bootstrap.php – vytvořit si temp složku Environment::setVariable(‚tempDir‘, ‚%appDir%/temp‘); a ve složce
app vytvořit složku temp
default.default.phtml na začátek vložit {block content}
DefaultPresenter.php – odkomentovat opět řádky s use
nakopírovat si složku libs ze skeletonu do složky ConfirmationDialogDemo
doufám že to dalším lidem ušetří půl hodinu času
MartyIX | 4. 7. 2011, 9:39 | comment
https://github.com/…nfirm-dialog – verze, ktera bezi na Nette 2 beta pro PHP 5.3
(Timto byste meli usetrit pul hodiny + dalsich circa pet minut :-))

h4kuna | 12. 7. 2010, 11:17 | bug
na řádku #57 je závorka navíc