Собственные классы для тегов ul в меню

Главные вкладки

Аватар пользователя g78knl6cvxf0 g78knl6cvxf0 22 января 2012 в 1:26

При выводе меню друпал добавляет к его тегам различные классы. Щедро так добавляет, и в тег li, и в тег a, а вот в "ul" - нишиша. Точнее добавляет один шиш - "menu", не зависимо от того, насколько этот ul вложен в другие.
Между тем, очень много скриптов по выводу менюшек завязаны на специальных (уникальных) метках тега ul. Особенно это касается корневого (первого, главного, начального) UL.

Как всегда нашлось уже много тем, не принесших пользу в решении этой проблемы:

http://www.drupal.ru/node/74071
http://www.drupal.ru/node/68859
http://www.drupal.ru/node/65035
http://www.drupal.ru/node/22932#comment-215099
...

В чем же сложность? А в том, что обертку пунктов меню производит вот эта функция

<?php
function ТЕМА_menu_tree($variables){
    return 
'<ul class="menu">' $variables['tree'] . '</ul>';
}
?>

Из которой даже для новичка понятно, что дело труба!( Класс прописан статически! И в переменной $variables нет ничего, что помогло бы определить уровень текущего набора пунктов. Все что можно сделать, это перекрыть ее такой же функцией, но для конкретного меню, чтобы хотя б не думать о том, то ли меню обрабатывается или нет.

<?php
function ТЕМА_menu_tree__НАЗВАНИЕ_НУЖНОГО_МЕНЮ
?>

Теперь по делу. Можно завести глобальную переменную, и увеличивать ее в функции. Благодаря этому можно добиться гарантированного уникальных id для каждого из пунктов. Вот таких

<ul class="menu_N">
.<ul class="menu_3">
..<ul class="menu_2">
...<ul class="menu_1">
</ul>

Т.е. да, нумерация будет снизу вверх, потому что именно в таком порядке будет обрабатываться меню. Таким образом, это не на много лучше добавления рандомного числа. Хотя если меню меняться не будет, то можно глянуть где какой номером, и поменять классы на осмысленные с помощью switch, но это все не то(

Что дальше? Есть бесспорно простое и эффективное решение - javascript (тем более, что jquery уже есть в друпал). Добавить с его помощью в нужный тег нужный класс - пара пустяков:

$("#block_X > ul").addClass("level_1");
$("#block_X > ul > li > ul").addClass("level_2");

и вряд ли пользователь что-нибудь успеет заметить (я, например, не успеваю). Что в этом плохого? Не знаю. Если у пользователя будут отключены скрипты, то, наверняка, меню будет далеко не единственным, что помешает ему насладиться сайтом. А раз в самом друпале так жестоко обошлись с этой оберткой, то не стыдно попросить об этом javascript.

И тем не менее, есть еще вариант, построенный на двух фактах:

1. Существует ряд модулей, позволяющих устанавливать классы для пунктов меню. Например Menu attributes , а так же хук, в котором этом можно делать самостоятельно, например так

2. В $variables['tree'] - хранятся входящие пункты меню уже собранные в html.

Поэтому если в тегах первого уровня, для текущего набора пунктов будут специальные пометки (например, "this_1_level_my_menu", "this_2_level_my_menu"), то их можно проанализировать, и понять кто есть кто.

Пример

<?php
function ТЕМА_menu_tree__МЕНЮ($variables){

   

//здесь будет результирующие название для класса ul
   
$menuClass="";

   

//пункты (под)меню, собранные в html
   
$str $variables['tree'];

   

//шаблон для получения класса интересующего тега, в данном случае первый тег "a"
   
$pattern '{^<li[^>]*><a[^>]*class="([^"]+)}';

   

   if(

preg_match($pattern$str$matches)){

       

//получить список классов
       
$aClass explode(" "$matches[1]);

       foreach(

$aClass as $class){
           switch(
$class){
        case 
"this_is_1_level_link"$menuClass="ul_1"; break;
        case 
"this_is_2_level_link"$menuClass="ul_2"; break;
        case 
"this_is_3_level_link"$menuClass="ul_3"; break;
        case 
"this_is_4_level_link"$menuClass="ul_4"; break;
        default: 
$menuClass=""; break;
           }            
       }

   if(

$menuClass!="")$menuClass=' class="'.$menuClass.'"';

   return 

"<ul $menuClass>" $variables['tree'] . "</ul>";
}
?>

Недостатки такого подхода:

1. Нужно назначать классы для отдельных пунктов меню
2. Нужно следить, чтобы среди пунктов оставались пункты с нужным идетификатором (если не делать это автоматически).
3. Слишком много телодвижений, на которые расходуются ресурсы.

ух, вот)

Комментарии

Аватар пользователя g78knl6cvxf0 g78knl6cvxf0 22 января 2012 в 11:09

Она то есть, но хочется подключать готовые менюшки настроив только их внешний вид, а не менять все правила привязанные к идентификатору ul на наследование от внешнего блока как в css, так и в js (а потом, когда выйдет обновления делать это вновь, и вновь при выборе другого меню). Тем более надо постоянно использовать > (что в css "любимые" браузеры не поддержат).

Аватар пользователя biozz biozz 28 мая 2016 в 22:17
1

Тоже обрыл все в поисках решения данной проблемы, находил разные решения, который как не крути но работали не так. И вот наткнулся на решение, которое возможно поможет не одному мне:

<?php
/**
 * Implements theme_menu_tree().
 */
function THEMENAME_menu_tree(&$variables) {
  return 
'<ul class="FIRST-LEVEL-CLASS">' $variables['tree'] . '</ul>';
}

/**
 * Implements theme_menu_link().
 */
function THEMENAME_menu_link(array $variables) {
  
$element $variables['element'];
  
$sub_menu '';

  if (

$element['#below']) {
    
// Wrap in dropdown-menu.
    
unset($element['#below']['#theme_wrappers']);
    
$sub_menu '<ul class="OTHER-LEVEL-CLASS">' drupal_render($element['#below']) . '</ul>';
  }
  
$output l($element['#title'], $element['#href'], $element['#localized_options']);
  return 
'<li' drupal_attributes($element['#attributes']) . '>' $output $sub_menu "</li>\n";
}

?>

Как видите у всех UL первого уровня будет один клас, а во всех вложенных другой. Решение очень интересное, все везде советуют ковырять menu_tree, про menu_link никто не упоминал, я то и сам ковырял menu_tree но без успешно.