Menüpontok egyedi osztályba sorolása

oky képe

A drupal.org-on lévő egyik cikk (Enable custom bullets/icons for specific menu items) adta az alapötletet: osztálynevet adni menüpontokhoz, hogy utána egyedi stílust lehessen rájuk alkalmazni. Az eredeti cikk nagy hibájának tartottam, hogy csak modul által definiált menüponthoz lehetett használni. Én viszont azt szerettem volna elérni, hogy bármelyik menüponthoz lehessen osztályt definiálni az adminisztráción keresztül. A 4.7.4-es kiadás fájljait módosítottam ennek érdekében.

A menü modulban megoldottam, hogy az egyes menüpontokhoz tartozó űrlapon legyen egy beviteli mező az osztálynak, valamint ennek mentéséről is gondoskodni kell.

A menü tábla felkészítése:

ALTER TABLE `menu` ADD `class` VARCHAR(50)  NOT NULL AFTER `description`;

A menu.module-ban végzett módosítások diff formájában:

--- ./modules/menu.module	Wed Oct 18 22:14:42 2006
+++ menu.module	Sun Nov 19 12:07:51 2006
@@ -394,6 +394,10 @@
     '#default_value' => $item['weight'],
     '#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'),
   );
+  $form['class'] = array('#type' => 'textfield',
+    '#title' => t('Class'),
+    '#default_value' => $item['class'],
+  );
 
   // Always enable menu items (but not menus) when editing them.
   if (!($item['type'] & MENU_IS_ROOT)) {
@@ -561,7 +565,7 @@
   }
 
   if ($item['mid'] && !empty($existing_item)) {
-    db_query("UPDATE {menu} SET pid = %d, path = '%s', title = '%s', description = '%s', weight = %d, type = %d WHERE mid = %d", $item['pid'], $item['path'], $item['title'], $item['description'], $item['weight'], $item['type'], $item['mid']);
+    db_query("UPDATE {menu} SET pid = %d, path = '%s', title = '%s', description = '%s',class = '%s', weight = %d, type = %d WHERE mid = %d", $item['pid'], $item['path'], $item['title'], $item['description'], $item['class'], $item['weight'], $item['type'], $item['mid']);
     return SAVED_UPDATED;
   }
   else {
@@ -572,7 +576,7 @@
     while ($item['mid'] <= 2) {
       $item['mid'] = db_next_id('{menu}_mid');
     }
-    db_query("INSERT INTO {menu} (mid, pid, path, title, description, weight, type) VALUES (%d, %d, '%s', '%s', '%s', %d, %d)", $item['mid'], $item['pid'], $item['path'], $item['title'], $item['description'], $item['weight'], $item['type']);
+    db_query("INSERT INTO {menu} (mid, pid, path, title, description, class, weight, type) VALUES (%d, %d, '%s', '%s', '%s', '%s', %d, %d)", $item['mid'], $item['pid'], $item['path'], $item['title'], $item['description'], $item['class'], $item['weight'], $item['type']);
     return SAVED_NEW;
   }
 }

A menu.inc végzi a menüfa generálását, és megjelenítését. Itt el kell érnünk, hogy a class tulajdonság is átmenjen rajta. A menu.inc módosításai diff formában:

--- ./includes/menu.inc	Wed Sep 27 10:12:28 2006
+++ menu.inc	Sun Nov 19 12:06:52 2006
@@ -661,7 +661,8 @@
     foreach ($menu['visible'][$pid]['children'] as $mid) {
       $type = isset($menu['visible'][$mid]['type']) ? $menu['visible'][$mid]['type'] : NULL;
       $children = isset($menu['visible'][$mid]['children']) ? $menu['visible'][$mid]['children'] : NULL;
-      $output .= theme('menu_item', $mid, menu_in_active_trail($mid) || ($type & MENU_EXPANDED) ? theme('menu_tree', $mid) : '', count($children) == 0);
+        $class = isset($menu['items'][$mid]['class']) ? $menu['items'][$mid]['class'] : NULL;
+        $output .= theme('menu_item', $mid, menu_in_active_trail($mid) || ($type & MENU_EXPANDED) ? theme('menu_tree', $mid) : '', count($children) == 0, $class);
     }
   }
 
@@ -695,7 +696,10 @@
  * @ingroup themeable
  */
 function theme_menu_item_link($item, $link_item) {
-  return l($item['title'], $link_item['path'], isset($item['description']) ? array('title' => $item['description']) : array());
+ 	$leaf=array();
+	if(isset($item['description'])) $leaf['title']=$item['description'];
+	if(isset($item['class'])) $leaf['class']=$item['class'];
+  return l($item['title'], $link_item['path'], $leaf);
 }
 
 /**
@@ -711,7 +715,6 @@
   while ($link_item['type'] & MENU_LINKS_TO_PARENT) {
     $link_item = menu_get_item($link_item['pid']);
   }
-
   return theme('menu_item_link', $item, $link_item);
 }
 
@@ -1033,7 +1036,6 @@
 
   // Menu items not in the DB get temporary negative IDs.
   $temp_mid = -1;
-
   foreach ($menu_item_list as $item) {
     if (!isset($item['path'])) {
       $item['path'] = '';
@@ -1108,6 +1110,7 @@
         $_menu['items'][$item->mid]['description'] = $item->description;
         $_menu['items'][$item->mid]['pid'] = $item->pid;
         $_menu['items'][$item->mid]['weight'] = $item->weight;
+        $_menu['items'][$item->mid]['class'] = $item->class;
         $_menu['items'][$item->mid]['type'] = $item->type;
       }
     }

Hurrá! Most már a menüpontokhoz tudunk class értéket rendelni. Próbáljuk ki!

Az alap bluemarine smink style.css fájljának végére tegyük oda:

.alma {
 padding-left:50px;
 background:url(logo.png) left center no-repeat;
}

Majd mondjuk az adminisztrációs menüpontnak adjunk `alma` class értéket, és voilá!

Sok sikert, és kellemes próbálgatást kívánok.

Hozzászólások

Anonymous képe

Jó olvasgatni ilyen patch-eket :) Így olvasva a dolgot, lehet, hogy jobb lett volna a menupontra mutató link-böl készíteni egy osztályt (id-t), így nem kell hozzá adatbázis megváltoztatás, ráadásul teljesen automatikus is lenne.

Hojtsy Gábor képe

De nem lenne olyan rugalmas, mondjuk több menüponthoz ugyanolyan class értéket nehezebb lett volna megadni (bár kétségtelenül a CSS író felelőssége lett volna, nem az admin felületen kellett volna beállítani).

sajt képe

Sőt, így, ahogy én írtam nem is lehetne, de gondolom itt az volna a lényeg, hogy minden egyes menüpontnak más és más kinézete legyen. Egy-egy blokkban pedig az összes bejegyzésnek lehet a többi doboztól különböző megjelenést adni, mert minden doboznak önálló ID-ja van, illetve az aktuálisan kiválasztott pedig mindig "active".

oky képe

Mondjuk, azt is meg lehet csinálni, hogy többszörös osztályneveket adunk meg.
Pl.: 'menubehuzas cegunkrol'
A 'menubehuzas' alatt definiáljuk az általános szabályokat (padding, háttérkép elhelyezés), 'cegunkrol' alatt akkor csak a háttérkép URL-jét kell már megadni.
Majd egy másik menüponthoz lehet 'menubehuzas referenciak' osztályt adni....

Paal képe

Sziasztok!

Korábban többszür próbáltam megoldást találni a problémámra, eddig sajnos nem sikerült. Oky írása elég jól használható lenne, de még mindig nem az igazi.

A képen látható két menü. Az elsődleges (fent) 2 szintű. Megoldható, hogy a kiválasztott elsődleges menüpont addig maradjon aktív, amíg annak bármelyik almenüjében (bal oldalon) navigálok?

Köszi, Pali

--
Palócz Paal Pál, a drupal.hu admin csoportjának tagja
Ajánlott olvasmány: Eric Steven Raymond - Hogyan kérdezzünk okosan

Anonymous képe

Ezt már nézted?

bubu képe

Nagyon örülök ennek a kezdeményezésnek, régóta vágytam erre a funkcióra. Kérdésem: lehet-e ebből önnálóan telepíthető modult készíteni, vagy csak így foltként telepíthető? A foltot eléggé kacifántos karban tartani egy következő kiadás esetén... szóval nagyon jó, csak mégsem igazán használható (számomra)... lehet ezen segíteni?

Gyuris Gellért

oky képe

Csinálhatsz egy modult, ami a menüpontokhoz class-t tárol.
Ezzel a menu.module módosítását már kihagyhatod.
A másik fele (a megjelenítés, ami a menu.inc-ben van) már érdekesebb; ezt ugyanis a sminben tudod megvalósítani a 'sminkedneve_menu_item_link' függvény definiálásával.
Szóval, így sem lesz tejlesen hordozható, és csak azok alatt a sminkek alatt megy, amiket felkészítesz. Ráadásul, ez a függvény minden linkhez külön hívódna meg, ki kellene keresnie, hogy van-e az adott linkhez class (adatbázisból, v. jobb esetben a cache-ből)...
Sebesség terén biztosan nem vetekszik a patch-csel.

bubu képe

Köszönöm a választ! Körbenéztem, végül ez közelebb áll ahhoz, amit elérni szeretnék: drupal.org/node/87902

Gyuris Gellért