Archive for the ‘DHTML’ Category

Létezik egy jQuery fgv: show(). Ennek az a szerepe, hogy a nem látható html elemet láthatóvá teszi.

Tehát végülis annyi történik, hogy egy html elemet ami el van rejtve (display: none;) megmutat, mégpedig úgy, hogy inline css-sel ad neki egy display: block tulajdonságot.

Ez így rendben is lenne, ha nem akarnánk táblázatok soraira is alkalmazni (table tr). A probléma az, hogy pl. a Firefox szétcsúszik, ha a sor elemre vonatkozó css display: block. Erre a megoldás a display: table-row css definíció. Ezzel viszont az a gond, hogy az IE nem támogatja. Az IE viszont kezeli a táblázat soraira is a display: block tulajdonságot.

Nem értem miért nem építették bele a jQuery-be a böngésző ellenőrzését a show() fgv. meghívása esetében, de akkor vegyük figyelembe magunk, hiszen nem mindegy, hogy a táblázatunk így néz ki:

FF tr elem display: block

Vagy így:

FF tr elem display: table-row

Láthatjuk, hogy az első esetben a táblázat első oszlopa sokszorosára nőtt, ezért az oldal szétcsúszott.

JS-ből lekérdezni a böngésző típusát, nem nehéz, és a jQuery-be is beépített (core).

A következő kódot aztán símán beépíthetjük egy saját fgv-be.

  1. <script type="text/javascript">
  2. function show_tr_element(object) {
  3.   if ($.browser.msie) {
  4.     object.show();
  5.   } else {
  6.     object.css("display", "table-row");
  7.   }
  8. }
  9. </script>

Ügyfelünk kérése alapján el kellett készítenünk egy DropDown menüt a nyitólapjára. Most is - mint általában - a jQuery JavaScript könyvtárban kerestem a megoldást. Rövid keresgélés után megtaláltam a Superfish jQuery plugin-t, mely tökletesen megfelelőnek tűnt a célra…legalábbis első ránézésre.

A probléma a tesztelés során jelentkezett, mégpedig a szokásos IE6/IE7/FF kompatibilitási ellentétek keretében.
Mondanom sem kell, hogy a plugin FF alatt teljesen jól teljesített (ugyanúgy mint Safari-n vagy Opera-n), a Microsoft két böngészőjénél az oldal gyakorlatilag összeomlott.

A menü FF-ban:

DropDown menü FF

Az internet Explorerben elég érdeksen mutatott:

DropDown menü IE
DropDown menü IE
DropDown menü IE

Először úgy gondoltam megkeresem a megoldást, mert biztosan lokális gond van, hiszen az oldalon található bemutatókon nincs gond Internet Explorer alatt sem, de akárhogy csürtem csavartam nem akart működni. Nem csak a kinézettel volt összeakadás, hanem a funkcionalitás sem működött. IE alatt egyszerüen eltünt a DropDown menü amikor elhagytam az egérrel a legfelső meüelemet.

Néhány órányi küszködés után úgy felidegesítettem magam, hogy eldöntöttem inkább írok egy sajátot, hiszen nem egy atomfizika a DropDown menü, főleg a jQuery-t használva.

Nézzük meg, először a HTML osztályokat, az elrendezési szabályokat!

Íme egy főmeü, és a hozzá tartozó DropDown menü:

  1. <div class="menu-sor">
  2.   <div class="ddown-menu">
  3.       <div class="fomenu-ikon">
  4.         <a href="/beteg-vagyok-gyogyulni-akarok"><img src="/themes/nyitolap/images/segiteni_img.jpg" alt="" /></a>
  5.       </div>
  6.       <ul class="submenu">
  7.         <li><?php print l("Pozitív hozzáállás", "pozitiv-hozzaallas"); ?></li>
  8.         <li><?php print l("Gyógyító nevetés", "gyogyito-nevetes"); ?></li>
  9.         <li><?php print l("Függőségek", "fuggosegek"); ?></li>
  10.         <li><?php print l("Mozgásszervi betegségek", "mozgasszervi-betegsegek"); ?></li>
  11.         <li><?php print l("Orvosok, akik agykontrollt végeztek", "orvosok-akik-agykontrollt-vegeztek"); ?></li>
  12.         <li><?php print l("Kiadványok gyógyulni vágyóknak", "kiadvanyok-gyogyulni-vagyoknak"); ?></li>
  13.       </ul>
  14.   </div>
  15.   <div class="fomenu">
  16.     <p><a href="/beteg-vagyok-gyogyulni-akarok">Beteg vagyok és gyógyulni akarok</a></p>
  17.   </div>
  18.   <div class="clear"></div>
  19. </div>

Az l() fgv. használata ne tévesszen meg senkit sem, ez egy beépített Drupal fgv., síma link generálódik belőle.
Tehát a

  1. <li><?php print l("Pozitív hozzáállás", "pozitiv-hozzaallas"); ?></li>

Sorok nyugodtan lecserélhetőek síma HTML elemekre:

  1. <li><a href="/valamilyen-tartalom">Tartalom címe</a></li>

Nézzük meg a css-t, hogy ki is nézzen valahogy, nameg azért vannak benne fontos részek:

  1. <style type="text/css">
  2. ul.submenu {
  3.   position: absolute;
  4.   display: inline;
  5.   z-index: 99;
  6.   border: 5px solid #962ab2;
  7.   display: none;
  8.   margin-left: 65px;
  9.   margin-top: 0;
  10.   width: 250px;
  11.   margin-bottom: 0;
  12. }
  13. ul.submenu li {
  14.   margin: 0;
  15.   padding: 0;
  16.   width: 250px;
  17. }
  18. ul.submenu li a {
  19.   font-size: 10pt;
  20.   display: block;
  21.   color: #409066;
  22.   background: #fdf3fd;
  23.   padding: 5px 20px;
  24.   border-bottom: 1px solid #962ab2;
  25.  
  26.   margin: 0;
  27.   width: 210px;
  28.   line-height: 14pt;
  29. }
  30. ul.submenu li a:hover {
  31.   background: white;
  32.   text-decoration: none;
  33. }
  34. div.ddown-menu {
  35.   width: 70px;
  36.   float: left;
  37. }
  38. div.ddown-menu div.fomenu-ikon {
  39.   width: 70px;
  40. }
  41. div.fomenu {
  42.   width: 250px;
  43.   float: left;
  44. }
  45. div.fomenu p {
  46.   padding-left: 10px;
  47.   padding-top: 5px;
  48. }
  49. div.menu-sor {
  50.   padding-top: 10px;
  51. }
  52. div.clear {
  53.   clear: both;
  54. }
  55. </style>

Itt volt egy-két érdekesség, amit mindenképpen szeretnék megmelíteni!

Az ul.submenu css definícióban fontos elemek:

  1.   position: absolute;
  2.   display: inline;
  3.   z-index: 99;
  4.   width: 250px;

Az első három nélkül az oldal IE-ben szétcsúszik, a szélesség megadása nélkül pedig IE6-ban csak 70px lesz a lehullómenü szélessége.

Az “ul.submenu” és az “ul.submenu li a” css definíciónál is nagyon fontos a szélesség megadása, mert különben IE6-ban eltűnik a DropDown menü ha az első elemet elhagyjuk (tehát nem tudjuk kivűlasztani mondjuk a második, vagy harmadik elemet a mnüből).
Az a (link) elemnél nyiván a paddingot kivonjuk a szélességből, ezért lesz 40px-el kevesebb.

A harmadik dolog amire figyelni kell az, hogy mindenhol megadtam a margin-bottom értékét, mégpedig 0-nak. Ez is fontos, különben IE6 alatt nagy alsó margót rak minden menüelem alá.

Végül, mint IE6 mint IE7 alatt nem volt megfelelő az “ul.submenu” bal oldali margó értéke (65px), ezért teljesen kiment a DropDown menü a jobb oldalra. Erre a Conditional comments megoldással probálkoztam, vagyis:

  1. <!–[if lte IE 7]>
  2.   margin-left: -5px;
  3. <![endif]–>

De sajnos ez nem reagált semmit, úgyhogy megoldottam ezt is JavaScript-el:

  1. <script type="text/javascript">
  2. $(function() {
  3.   if ($.browser.msie) {
  4.     $('ul.submenu').css("margin-left", "-5px");
  5.   }
  6. });
  7. </script>

Nézzük meg végül a lényeget, a HTML-hez tarotó jQuery kódot, amiben kivitelezzük a DropDown menüt:

  1. <script type="text/javascript">
  2. $(function() {
  3.   var submenu_active = false;
  4.   $(".ddown-menu").hover(
  5.   function() {
  6.     $("ul.submenu", $(this)).show();
  7.     $("ul.submenu", $(this)).hover(
  8.     function() {
  9.       submenu_active = true;
  10.     },
  11.     function() {
  12.       $(this).hide();
  13.       submenu_active = false;
  14.     });
  15.   },
  16.   function() {
  17.     if (!submenu_active) {
  18.       $("ul.submenu", $(this)).hide();
  19.     }
  20.   }
  21.   );
  22. });
  23. </script>

Mit is csinál?

Az oldal betöltődése után létrehoz egy bool tipusú változót, melyben a DropDown menü aktivitását figyeljük, majd végigmegy az összes ddown-menu osztályon, és figyeli a hover esemény.
Amikor bekövetkezik, a hozzá tartozó submenu osztályt előhozza (show), majd ennek a megjelenített menünek figyeli a hover eseményét.
Ha bekövetkezik, akkor a submenu_active változó értéke igaz lesz, hiszen éppen a menüben vagyunk, ha pedig elhagyjuk, akkor elrejtjük, és a submenu_active értékét hamisra állítjuk.
Végül megnézzük, hogy a ddown-menu osztályba tartozó elemek hover eseményének végén a submenu_active igaz-e, és ha nem akkor a DropDown listát eltávolítjuk. Erre azért van szükség, mert olyan szituáció is elképzelhető, hogy valaki nem lép be a submenu-be, csak előhozza. Ha ez a sor kimaradna, akkor ilyen esetekben a sumenu nem tunne el.

Régebben írtam egy cikket a dinamikus form ellenőrzésről, és arra gondoltam leírom az eljárás modernebb változatát, azaz a hibaüzenetek nem alert ablakban jelennek meg, hanem DHTML segítségével.

Természetesen olyan kódot kell készíteni amely akárhány form-ra dinamikusan működik, tehát nem függ az input mezők számától, és az oldalon elhelyezett form-ok mennyiségétől.

A megoldást itt is a jQuery JavaScript könyvtár adja.

De mindenek előtt érdemes átnézni hogyan is kell felépíteni egy profi form-ot. Khauth György kollegám írt már erről néhány nagyon hasznos cikket:

Miután az alapelvek tanulmányozásával végeztünk készítsük el a form-ot:

  1. <style type="text/css">
  2. .form-row {
  3.   padding-bottom: 10px;
  4.   width: 290px;
  5. }
  6.  
  7. .form-row label {
  8.   float: left;
  9.   width: 100px;
  10.   padding-right: 10px;
  11. }
  12.  
  13. .form-row input {
  14.   float: left;
  15.   padding: 3px;
  16.   width: 160px;
  17. }
  18.  
  19. .clear {
  20.   clear: both;
  21. }
  22.  
  23. .form-error {
  24.   text-align: center;
  25.   color: #C52020;
  26.   border: 1px solid #DD7777;
  27.   background: #FFCCCC;
  28.   margin: 10px 0;
  29.   display: none;
  30. }
  31. </style>
  32.  
  33. <div style="margin: 0 auto; width: 300px;">
  34.   <form action="#" method="post">
  35.     <div class="form-row">
  36.       <label for="keresztnev">Keresztnév:</label><input type="text" name="keresztnev" class="kotelezo" id="keresztnev" />
  37.       <div class="clear"></div>
  38.       <div class="form-error hianyos">A keresztnév megadása kötelező!</div>
  39.     </div>
  40.    
  41.     <div class="form-row">
  42.       <label for="vezeteknev">Vezetéknév:</label><input type="text" name="vezeteknev" class="kotelezo" id="vezeteknev" />
  43.       <div class="clear"></div>
  44.       <div class="form-error hianyos">A vezetéknév megadása kötelező!</div>
  45.     </div>
  46.    
  47.     <div class="form-row">
  48.       <label for="email">Email:</label><input type="text" name="email" class="kotelezo email" id="email" />
  49.       <div class="clear"></div>
  50.       <div class="form-error hianyos">Az email cím megadása kötelező!</div>
  51.       <div class="form-error hibas">Nem valós az email cím!</div>
  52.     </div>
  53.    
  54.     <div class="form-row" style="text-align: center;">
  55.       <input type="submit" name="submit" value="Mehet" style="float: none;" />
  56.     </div>
  57.   </form>
  58. </div>

Ha megnézzük a kód a css stílus felépítésével kezdődik, ez gyakorlatilag csak az átlátható kinézetet kezeli. A lényeg természetesen a form, és a form-on belüli osztályok elhelyezkedése!

A form-ot körülöleli egy div, a JavaScript kóddal ezen belül fogunk keresni. Ennek az a lényege, hogy akárhány form-on el tudjuk sütni az eljárást, ne kelljen minden form-nál újra és újra megírni, hozzáigazítani a form-hoz.
Három adatok kérünk be: keresztnév, vezetéknév, és email cím.
Ha megfigyeljük mindegyik alatt megtalálható a hozzá tartozó hibaüzenet is. A hibaüzenetek mindegyike a form-error osztályba van sorolva, így a kinézetük egységesen definiálható, és láthatóságuk egységesen kezelhető.
A hibaüzenetek nem csak a form-error osztályba tartoznak, hanem a hiba típusába is. Ezesetben mind a három input mezőhöz tartozik egy hianyos osztály, ami akkor jelenik meg ha üresen hagytuk, az email címhez pedig egy hibas osztály, ami akkor jelenik meg ha az email cím nem valós.

Nézzük meg a hozzá tartozó JavaScript kódot, melyben dinamikusan elleőrizzük az input mezők kitöltöttségét, és az email cím helyességét, valósságát is:

  1. <script type="text/javascript">
  2.  
  3. $(function() {
  4.   $('form').submit(function() {
  5.     var mehet       = true;
  6.     var first_error = true;
  7.     var error_obj   = null;
  8.     $('div.form-error', $(this).parent()).each(function() {
  9.       $(this).hide();
  10.     });
  11.     $('input.kotelezo', $(this).parent()).each(function() {
  12.       if ($(this).val() == '') {
  13.         mehet = false;
  14.         if (first_error) {
  15.           first_error = false;
  16.           error_obj   = $(this);
  17.         }
  18.         $('div.hianyos', $(this).parent()).show();
  19.       }
  20.     });
  21.  
  22.     var email   = $('input.email', $(this).parent()).val();
  23.     var filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
  24.     if (!filter.test(email)) {
  25.       mehet = false;
  26.       if (first_error) {
  27.         first_error = false;
  28.         error_obj   = $(this);
  29.       }
  30.       $('div.hibas', $(this).parent()).show();
  31.     }
  32.  
  33.     if (mehet) {
  34.       return true;
  35.     } else {
  36.       location = '#' + error_obj.attr('id');
  37.       return false;
  38.     }
  39.   });
  40. });
  41.  
  42. </script>

A dinamikus form ellenőrzésről írt cikkemhez képes van néhány eltérés, most ezekre térnék ki elsősorban.
Az első, hogy nem csak a mehet változót deklaráljuk, hanem a first_error bool típusút, és az error_obj html objektum típusút is. Ezek azt a célt szolgálják, hogy hibás kitöltés esetén le tudjuk tárolni melyik hiba volt az első a sorban, és automtaikusan oda ugorjunk az oldalon.
Utána láthatjuk a

  1. $('div.form-error', $(this).parent()).each(function() {
  2.       $(this).hide();
  3.     });

részt, ami arra való, ha már egyszer hibásan töltöttük ki a form-ot, akkor eltűntetjük az összes hibaüzenetet, különben ottmaradhat második hibás kitöltés esetén olyan üzenet is, ami már nem aktuális.

Ezután ellenőrizzük a kitöltöttséget, tehát végigmegyünk a kötelező input mezőkön. Ha valameny nincs kitöltve akkor a szülö objektumának hianyos osztályát megjelenítjük. Végül ellenőrizzük az email cím helyességét, tehát hogy illeszkedik-e a szabványra, és ha nem a szülő html objektumának hibas osztályát megjelenítjük.

Végül ha nem találtunk hibát tobábbengedjük a submit eseményt, ha találtunk akkor az első hibás mezőhöz ugrunk.