Vložení vlastního makra n:confirm
- Vyki
- Člen | 388
Právě jsem si do Nette přidal v lastní makro, n:confirm
a
byl jse překvapen jak je to snadné, tak se rád podělím. Někam do
BasePresenteru, např. do metody startup přidat řádek:
<?php
[...]
LatteMacros::$defaultMacros['@confirm'] = 'data-confirm="<?php echo %:formatString% ?>"';
[...]
?>
Do stránky připojit JS (vyžaduje JQuery 1.3.x a liveQuery plugin). Inspirováno železničáři https://github.com/…src/rails.js
<script>
$(document).ready(function () {
$.fn.extend({
triggerAndReturn: function (name, data) {
var event = new $.Event(name);
this.trigger(event, data);
return event.result !== false;
}
});
$('a[data-confirm], button[data-confirm], input[data-confirm]').live('click', function (e) {
var el = $(this);
if (el.triggerAndReturn('confirm')) {
if (!confirm(el.attr('data-confirm'))) {
return false;
}
}
});
});
</script>
a v šablonách pak můžete používat jednoduše
<a n:href="this" n:confirm="Opravdu chcete smazat search index googlu?">Smazat</a>
vygeneruje
<a href="index.php" data-confirm="Opravdu chcete smazat search index googlu?">Smazat</a>
Editoval Vyki (20. 11. 2010 19:00)
- Jan Tvrdík
- Nette guru | 2595
Máš vyšší abstrakci, což ti umožňuje věci z ní plynoucí (např.
v budoucnu hromadně přejmenovat date-confirm
na
data-xyz-confirm
). Jinak je to úplně na nic (pominu-li o pár
znaků kratší zápis).
- Vyki
- Člen | 388
Ja to zatím udělal tak, že v tom klasickém handleru ignoruju to co jde z odkazu, kde class = ajax
<script>
$('a[data-confirm], button[data-confirm], input[data-confirm]').live('click', function (e) {
var el = $(this);
if(el.hasClass('ajax')){
return true;
}
if (el.triggerAndReturn('confirm')) {
if (!confirm(el.attr('data-confirm'))) {
return false;
}
}
});
</script>
a v tam kde registruju udalost pro class = ajax mám
<script>
$("a[href].ajax").livequery("click",function(e){
e.preventDefault();
var el = $(this);
if(el.attr('data-confirm')){
if (el.triggerAndReturn('confirm')) {
if (!confirm(el.attr('data-confirm'))) {
return false;
}
}
}
$.get(el.attr("href"));
});
</script>
Nic lepšího jsem zatím neměl čas bastlit.
Edit: A samozřejmě, nesmíš zapomenout v nějakém skriptu před těmito
dvěma zaregistrovat to rozšíření JQ o funkci
triggerAndReturn
.
<script>
$.fn.extend({
triggerAndReturn: function (name, data) {
var event = new $.Event(name);
this.trigger(event, data);
return event.result !== false;
}
});
</script>
Editoval Vyki (21. 11. 2010 21:07)
- Honza Marek
- Člen | 1664
Myslim, že když v té confirmovací funkci použijete e.preventDefault() a e.stopImmediatePropagation() místo return false, tak to zafunguje i na zajaxované odkazy.
- Vladimír Kocourek
- Člen | 8
Pro zajímavost se podělím s možností registrace vlastních maker (a rozšíření Latte), kterou používám já.
Podědil jsem Nette\Templates\LatteMacros
do své třídy
(Catta\LatteMacros
), kde definuju svoje makra obdobným způsobem
jako původní třída a v přepsané __construct()
přidám svoje
makra k původním.
<?php
namespace Catta;
class LatteMacros extends \Nette\Templates\LatteMacros
{
public static $cattaMacros = array(
'ifempty' => '<?php if (empty(%%)): ?>',
'/ifempty' => '<?php endif ?>',
'currentYear' => '<?php echo Date("Y") ?>',
// další makra dle své libosti
);
public function __construct()
{
parent::__construct();
$this->macros = self::$defaultMacros + self::$cattaMacros;
}
}
?>
A v BasePresenteru potom v metodě templatePrepareFilters()
říkám Latte, aby používal moji třídu namísto své.
<?php
public function templatePrepareFilters($template)
{
$template->registerFilter($latteFilter = new Nette\Templates\LatteFilter());
$latteFilter->handler = new Catta\LatteMacros;
}
?>
- Vyki
- Člen | 388
Honza Marek napsal(a):
Myslim, že když v té confirmovací funkci použijete e.preventDefault() a e.stopImmediatePropagation() místo return false, tak to zafunguje i na zajaxované odkazy.
Díky za tip – vyzkouším.
Vladimír Kocourek napsal(a):
Podědil jsem Nette\Templates\LatteMacros do své třídy (Catta\LatteMacros), kde definuju svoje makra obdobným způsobem jako původní třída a v přepsané __construct() přidám svoje makra k původním.
Není to až příliš komplikované? Rozšířit si to
výchozí pole LatteMacros::$defaultMacros
se mi zdá o poznání
snadnější.
Editoval Vyki (21. 11. 2010 22:05)
- Vladimír Kocourek
- Člen | 8
Není to až příliš komplikované? Rozšířit si to výchozí pole
LatteMacros::$defaultMacros
se mi zdá o poznání snadnější.
Mě ten můj způsob přijde čistší. :)
edit: A myslím, že třeba pro https://gist.github.com/347052 od Honzy Marka by to bylo i přehlednější. :)
Editoval Vladimír Kocourek (21. 11. 2010 22:11)
- sairon
- Člen | 32
Honza Marek napsal(a):
Myslim, že když v té confirmovací funkci použijete e.preventDefault() a e.stopImmediatePropagation() místo return false, tak to zafunguje i na zajaxované odkazy.
Ha, to je ono! e.preventDefault()
jsem tam zkoušel dát, ale
zapomněl jsem na to, že je tady potřeba ještě ta druhá metoda. Díky, po
této úpravě to už funguje tak, jak má.
- Honza Marek
- Člen | 1664
Vladimír Kocourek napsal(a):
edit: A myslím, že třeba pro https://gist.github.com/347052 od Honzy Marka by to bylo i přehlednější. :)
Jasně, ale je pak víc práce to zamontovat… musíš to mít jak v BasePresenteru, tak i v nějaké BaseControle. Když se to hodí staticky do LatteMacros, stačí zavolat jednu metodu v bootstrapu.
- David Grudl
- Nette Core | 8218
V Nette bude existovat skript nette.js
, který bude mimo jiné
řešit potvrzování a bude k tomu využívat atribut
data-nette-confirm
. Takže pokud chcete být dopředně
kompatibilní, používejte tento zápis.
- bojovyletoun
- Člen | 667
Taky jsem shodou ookolností řešil confirmy. jedna možnost je přes
$().cllick(), ale neumí ajax.
Zatímco $().live(click,) umí, ale handler je přivěšen až za odeslání
(zkoušeno přes e.stopPropagation, e. preventDefault, return false).
Ale nezkoušel jsem e.stopImmediatepropagation- funguje to?
Takže jsem to vyřešil přes jinou třídu -ne ajax ale třebaa ajaxconfirm a dopsat vlastní hanlder:
$('a.ajaxconfirm').live('click', function(event) {
event.preventDefault();
if(!window.confirm("Opravdu smazat?"))return false; // zde je řádek navíc oproti normálce
if ($.active) return;
$.post(this.href, $.nette.success);
$.nette.spinner.css({
position: 'absolute',
left: event.pageX+20,
top: event.pageY+80
});
- Vyki
- Člen | 388
sairon napsal(a):
Ha, to je ono!e.preventDefault()
jsem tam zkoušel dát, ale zapomněl jsem na to, že je tady potřeba ještě ta druhá metoda. Díky, po této úpravě to už funguje tak, jak má.
Můžu se zeptat, kam konkrétně jsi to e.preventDefault()
?
Zkoušel jsem to dávat k té confirm fci, potom na další místa, ale stejně
se to na pozadí tím ajaxem odešle, když nedám podmínku přímo do fce pro
ajax odesílání.
- srigi
- Nette Blogger | 558
Chalani, riesite v tychto svojich confirmatoroch CSRF? Myslim si, ze je
dolezite sa nad tym zamysliet. Pozor, je to nieco ine ako
$form->addProtection
, lebo na stranke nie je milion malych
formularikov, ale kopec <a n:hhref>
odkazov.
Staci ak vam niekto podstrci na utocnikovej stranke
<img src="http://mojaaplikacia/admin/pages/delete/xyz">
kym
ste prihlaseny vo svojejapp a je to v pecku.
David, bude Framework toto niekedy nejako ulahcovat?
- jasir
- Člen | 746
srigi napsal(a):
Chalani, riesite v tychto svojich confirmatoroch CSRF? Myslim si, ze je dolezite sa nad tym zamysliet. Pozor, je to nieco ine ako
$form->addProtection
, lebo na stranke nie je milion malych formularikov, ale kopec<a n:hhref>
odkazov.
- sairon
- Člen | 32
Vyki napsal(a):
sairon napsal(a):
Ha, to je ono!e.preventDefault()
jsem tam zkoušel dát, ale zapomněl jsem na to, že je tady potřeba ještě ta druhá metoda. Díky, po této úpravě to už funguje tak, jak má.Můžu se zeptat, kam konkrétně jsi to
e.preventDefault()
? Zkoušel jsem to dávat k té confirm fci, potom na další místa, ale stejně se to na pozadí tím ajaxem odešle, když nedám podmínku přímo do fce pro ajax odesílání.
U mě naprosto stačí jenom tahle lehká úprava:
$('a[data-confirm], button[data-confirm], input[data-confirm]').live('click', function (e) {
var el = $(this);
if (el.triggerAndReturn('confirm')) {
if (!confirm(el.attr('data-confirm'))) {
e.preventDefault();
e.stopImmediatePropagation();
return false;
}
}
});
Důležitá je právě i metoda stopImmediatePropagation()
.
Nemůže pak činit problémy mixování .live() a .livequery()? Nechce se mi
zkoumat, jak se od sebe liší, já si vždycky vystačil s .live(), i tady
registruju funkci pro AJAX odeslání i pro confirm dialog přes
.live(‚click‘,fce).
Edit: A teď jsem si všiml ještě jedný čertoviny – nejprve je nutné zaregistrovat event pro potvrzení, pak až funkci, která bude odesílat request. Ono je to vlastně celkem logické :)
Editoval sairon (25. 11. 2010 16:24)
- jtousek
- Člen | 951
sairon: Nevím přesně jak to funguje, ale když použiješ live tak event bubbling funguje opačným směrem než u livequery. Tedy alespoň podle toho jak se mi to divně chovalo když jsem je mixoval. Právě teď používám všude kde to jde live, aby to neblblo, ale odesílání formulářů mi přes live v 1.4.2 nešlo takže tam mám livequery (aktuální z githubu).