2. rész
Írta: János Zahratka
Nos, ahogy ígértem, íme a második rész. Ebben a szakaszban származtatni fogjuk a már elkészített jQTBaseOverlay widget-ünket, aminek ezúttal már a HTML oldalon megjelenő eredménye is lesz.
Emlékeztetőül: az előző részben elkészítettünk egy alap widget-et, a jQuery Tools overlay plugin-jéhez. Erre azért volt szükség, mert a plugin-ból több, különböző eszközt lehet csinálni. Ebben a részben két felhasználási lehetőséget fogok megmutatni. Az egyik egy olyan overlay doboz, amibe bármilyen tartalmat el lehet helyezni. A másik pedig egy üzenő/kérdező dialógus, amivel üzeneteket, illetve kérdéseket lehet megjeleníteni a felhasználóknak, és utóbbi esetében a választól függően lehet "reagálni" a felhasználó választására.
jQTOverlay
Első lépésben létrehozunk egy új php állományt a protected/components/widgets mappában jQTOverlay.php névvel. Még mielőtt nekikezdenénk awidget osztályának kiterjesztéséhez, gondoskodnunk kell róla, hogy a widget megtalálja a szülő osztályát, ezt pedig a YiiBase osztály import metódusának segítségével fogjuk megoldani. Az üres osztályunk valahogy így fog kinézni:
<?php Yii::import('application.components.widgets. jQTBaseOverlay'); class jQTOverlay extends jQTBaseOverlay { }
Ezután kicsit átírjuk a publikus init metódust, ami a widget alapértékeinek beállítását végzi el. Ebben az esetben mindőssze annyit fog csinálni ez a metódus, hogy lefuttatja a szülő osztály azonos nevű metódusát, majd meghívja a registerClientScript, és a renderBegin metódusokat. Egyik sem csinál mást, "csak" végrehajtja a szülő osztályban lévő azonos nevű eljárásokat. Ez azért lett így összerakva, mert az alap osztályban már minden szükséges metódus, és paraméter definiálva van, itt pedig csak a megfelelő sorrendben hívogatni kell őket.
... public function init() { parent::init(); $this->registerClientScript(); $this->renderBegin(); } ...
Ha ezzel megvagyunk, előkapjuk a run metódust, és meghívjuk benne a renderContent és a renderEnd metódusokat. Ezek szintén definiálva vannak a szülő osztályban.
... public function run() { $this->renderContent(); $this->renderEnd(); } ...
Már csak négy metódus van hátra, melyek egy kivételével szintén csak annyit csinálnak, hogy meghívják a szülő osztály azonos nevű metódusait. Ezek aregisterClientScript, a renderBegin, a renderContent, és a renderEnd metódusok. Az üres metódus arra való, hogy ha valaki tovább szeretné származtatni ezt a widgetet, akkorű jobb, ha megvan ez a metódus is.
... protected function registerClientScript() { parent::registerClientScript(); } protected function renderBegin() { parent::renderBegin(); } protected function renderContent() { } protected function renderEnd() { parent::renderEnd(); } ...
A widget-et tovább lehetne rövidíteni azzal, hogy azokat a metódusokat, amelyek csak a szülő osztályban lévő önmagukat hívják meg nem kell deklarálni, csak meghívni a parent segítségével, azonban gondolni kell arra is, hogy esetleg olyan osztályt fogunk csinálni, ami ezt a már kibővített osztályt fogja tovább származtatni.
Ahogy ígértem, valóban sokkal rövidebb lesz a második rész, ugyanis az a helyzet, hogy a jQTOverlay widget ezzel készen is van. Lássuk a kódot!
<?php Yii::import('application.components.widgets. jQTBaseOverlay'); class jQTOverlay extends jQTBaseOverlay { public function init() { parent::init(); $this->registerClientScript(); $this->renderBegin(); } public function run() { $this->renderEnd(); } protected function registerClientScript() { parent::registerClientScript() ; } protected function renderBegin() { parent::renderBegin(); } protected function renderContent() { } protected function renderEnd() { parent::renderEnd(); } }
Már csak annyi van hátra, hogy bármely view (nézet) állományban meghívjuk, ami valahogy így néz ki:
... <!-- Ha erre klikkel, akkor jöhet az overlay. --> <?php echo CHtml::link(CHtml::encode('Overlay'), array('#'), array( 'id' => 'showOverlay', 'name' => 'showOverlay', 'rel' => '#Overlay' ) ); ?> ... ... <!-- És ez a widget hívása. --> <?php $this->beginWidget(' application.components. widgets.jQTOverlay', array( 'htmlOptions' => array( 'id' => 'overlay', 'name' => 'overlay' ), 'trigger' => 'showOverlay', 'useMask' => true, 'title' => 'Overlay', )); ?> Bármilyen HTML, vagy php tartalom, amit meg akarunk jeleníteni. <?php //$this->endWidget(); ?> ...
jQTDialog
A második származtatott widget-ünk egy kicsit - de tényleg csak egy kicsit - bonyolultabb, de csak azért, mert arra vetemedtem, hogy egy type nevű paraméter segítségével három dialógus típust kezeljek egy widget megírásával. Mindhárom változat működése azonos. A különbség abban van, hogy milyen válaszlehetőségeket adok a felhasználónak.
Két paramétert vezettem be, amelyek a szülő osztályban nem léteznek. Az egyik a már előbb említett type, ami a dialógus típusát határozza meg. Értéke "alert" (figyelmeztetés), "question" (kérdés) vagy "decision" (döntés) lehet. A másik a message paraméter, amely a megjelenítendő üzenetet, vagy kérdést tárolja.
A szülő osztályból átvettem még az _openTag paramétert, ami pontosan ugyanazt tárolja, mint a szülő.
Az init metódus ezúttal összetettebb lesz, mint az előző esetben.
- Megvizsgálja, hogy a type paraméter a megfelelő értéket tartalmaz-e, azután azt is meg kell vizsgálni, hogy van-e üzenet, amit meg kell jeleníteni (message). Ha ez a két paraméter nem megfelelő, akkor a widget egyszerűen leáll és nem jelenít meg semmit.
- Megváltoztatja az overlay CSS osztályának nevét a dialógus típusának megfelelően. Ez nem kötelező, viszont szerintem jó megoldás arra, hogy az egyes dialógus típusok más-más megjelenési formát vehessenek fel.
- Meghívja a szülő osztály azonos nevű metódusát, aztán az előbbi overlay widget-ben leírt módon a registerClientScript és renderBegin metódusok hívásai következnek.
... public function init() { if('alert' !== $this->type && 'question' !== $this->type && 'decision' !== $this->type) { return null; } if(null === $this->message) { return null; } $this->htmlOptions['class'] = $this->type; $this->params['closeOnClick'] = false; parent::init(); $this->registerClientScript(); $this->renderBegin(); } ...
A run metódus ugyanazt csinálja, mint az előző widget.
... public function run() { $this->renderEnd(); } ...
A registerClientScript metódus állítja elő azt a javascript kódot, ami az oldal végére kerül, és a dialógus kliens oldali működéséért felelős.
Ha kérdés típusú dialógust szeretnénk megjeleníteni, akkor több válaszlehetőséget kell biztosítanunk, és egyúttal gondoskodnunk kell róla, hogy a lap tudja, hogy mit válaszolt a felhasználó. Ennek első része az, hogy egy target nevű változóba betöltjük a dialógus azonosítóját, ami vagy meg van adva az overlay plugin paraméterei között, vagy ha nincs, akkor a dialógus azonosítója lesz az.
Ha ez megvan, akkor elkérjük a szülő osztálytól a script első részét, és hozzáfűzzük a válasz gombok kezelésének szkriptjét, aztán az így elkészült kódot visszatesszük a publikus script praméterbe, majd meghívjuk a szülő osztály azonos nevű metódusát.
A script kódja csak annyira van megírva, hogy az igényeknek megfelelően simán folytatni lehessen, tehát az igazi használathoz még dolgozni kell rajta.
... protected function registerClientScript() { if('question' === $this->type || 'decision' === $this->type) { if(isset($this->params['target'])) { $target = $this->params['target']; } else { $target = $this->htmlOptions['id']; } $script = $this->script; $script = $script . "\n" . '$("#' . $target . ' .buttons button").click(function(event) {' . 'var result = $(this).attr("value");' . '});'; $this->script = $script; } parent::registerClientScript() ; } ...
És már csak annyi kell, hogy megjelenítsük a dialógusunk HTML kódját. Ennek első felét a renderBegin metódus végzi, ami kiírja a dialógus kezdő részét, címét - ha van -, aztán az üzenetet, vagy kérdést.
... protected function renderBegin() { ob_start(); ob_implicit_flush(false); echo "\n" . CHtml::openTag($this->tagName, $this->htmlOptions) . "\n"; if(null !== $this->title || '' !== $this->title) { echo CHtml::tag('h3', array('class' => 'title'), CHtml::encode($this->title), true) . "\n"; } echo CHtml::tag('p', array('class' => 'message'), CHtml::encode($this->message), true); $this->_openTag = ob_get_contents(); ob_clean(); } ...
És jön az utolsó metódus, név szerint a renderEnd, ami mindössze annyit csinál, hogy a kód végére odateszi a dialógus típusának megfelelő gombokat, aztán lezárja a widget záró kódjával az egészet.
... protected function renderEnd() { $content = ob_get_clean(); echo $this->_openTag; echo trim($content); echo "\n" . CHtml::openTag('div', array('class' => 'buttons')) . "\n"; if('alert' === $this->type) { echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonOk', 'value' => 'ok', 'class' => 'close'), 'OK', true) . "\n"; } elseif('question' === $this->type) { echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonYes', 'value' => 'yes', 'class' => 'close'), 'Igen', true) . "\n"; echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonNo', 'value' => 'no', 'class' => 'close'), 'Nem', true) . "\n"; } elseif('decision' === $this->type) { echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonYes', 'value' => 'yes', 'class' => 'close'), 'Igen', true) . "\n"; echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonNo', 'value' => 'no', 'class' => 'close'), 'Nem', true) . "\n"; echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonCancel', 'value' => 'cancel', 'class' => 'close'), 'Mégsem', true) . "\n"; } echo CHtml::closeTag('div'); echo "\n" . CHtml::closeTag($this->tagName) . '' . "\n"; } ...
Most pedig nézzük a teljes kódot!
<?php Yii::import('application.Végül pedig az elkészült widget használata a view (nézet) állományokban.components.widgets. jQTBaseOverlay'); class jQTDialog extends jQTBaseOverlay { public $type = 'alert'; public $message; private $_openTag; public function init() { if('alert' !== $this->type && 'question' !== $this->type && 'decision' !== $this->type) { return null; } if(null === $this->message) { return null; } $this->htmlOptions['class'] = $this->type; $this->params['closeOnClick'] = false; parent::init(); $this->registerClientScript(); $this->renderBegin(); } public function run() { $this->renderEnd(); } protected function registerClientScript() { if('question' === $this->type || 'decision' === $this->type) { if(isset($this->params[' target'])) { $target = $this->params['target']; } else { $target = $this->htmlOptions['id']; } $script = $this->script; $script = $script . "\n" . '$("#' . $target . ' .buttons button").click(function(event) {' . 'var result = $(this).attr("value");' . '});'; $this->script = $script; } parent::registerClientScript() ; } protected function renderBegin() { ob_start(); ob_implicit_flush(false); echo "\n" . CHtml::openTag($this->tagName, $this->htmlOptions) . "\n"; if(null !== $this->title || '' !== $this->title) { echo CHtml::tag('h3', array('class' => 'title'), CHtml::encode($this->title), true) . "\n"; } echo CHtml::tag('p', array('class' => 'message'), CHtml::encode($this->message), true); $this->_openTag = ob_get_contents(); ob_clean(); } protected function renderEnd() { $content = ob_get_clean(); echo $this->_openTag; echo trim($content); echo "\n" . CHtml::openTag('div', array('class' => 'buttons')) . "\n"; if('alert' === $this->type) { echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonOk', 'value' => 'ok', 'class' => 'close'), 'OK', true) . "\n"; } elseif('question' === $this->type) { echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonYes', 'value' => 'yes', 'class' => 'close'), 'Igen', true) . "\n"; echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonNo', 'value' => 'no', 'class' => 'close'), 'Nem', true) . "\n"; } elseif('decision' === $this->type) { echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonYes', 'value' => 'yes', 'class' => 'close'), 'Igen', true) . "\n"; echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonNo', 'value' => 'no', 'class' => 'close'), 'Nem', true) . "\n"; echo CHtml::tag('button', array('id' => $this->htmlOptions['id'] . 'ButtonCancel', 'value' => 'cancel', 'class' => 'close'), 'Mégsem', true) . "\n"; } echo CHtml::closeTag('div'); echo "\n" . CHtml::closeTag($this-> tagName) . '' . "\n"; } }
... <!-- Ha erre klikkel, akkor jöhet a dialógus. --> <?php echo CHtml::link(CHtml::encode('Remélem, lesz némi haszna a cikknek! Akinek netán kedve támadna, hogy megjegyzéssel illesse a két cikket, ne fogja vissza magát! Nem vagyok egy über okos programozó, csak szeretek ezzel foglalkozni, és szívesen tanulok én is abból, amit a nálam okosabbak mondanak/írnak.Dialog'), array('#'), array( 'id' => 'showDialog', 'name' => 'showDialog', 'rel' => '#Dialog' ) ); ?> ... ... <!-- És ez a widget hívása. --> <?php $this->widget('application. components.widgets.jQTDialog', array( 'htmlOptions' => array( 'id' => 'overlay', 'name' => 'overlay' ), 'trigger' => 'showDialog', 'useMask' => true, 'title' => 'Dialógus', 'type' => 'question', 'message' => 'Valamit kérdezni akartam, de elfelejtettem. Nem tudod, mi volt az?' )); ?> ...
No comments:
Post a Comment