[РЕШЕНО] Как изменить HTML-код меню, возвращаемый модулем superfish? (вставка тегов span)

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

Аватар пользователя Lex-DRL Lex-DRL 14 марта 2010 в 21:02

На сайте стоит модуль Superfish, позволяющий создавать красивые выпадающие меню. Для пунктов меню он генерирует HTML-код такого вида (разбил на строки для наглядности):

<li class="sfHover" id="menu-132-1">
<a href="/foo" title="bar">Menu Item</a>
</li>

Из соображений темизации необходимо привести этот код к такому виду:

<li class="sfHover" id="menu-132-1">
<a href="/foo" title="bar">
<span class="back"><span class="bg1"></span>
Menu Item
<span class="foreground"></span></span>
</a>
</li>

Т.е. добавить несколько тегов span вокруг, до и после текста ссылки, но внутри тега < a >.
В коде модуля я нашёл такие строки:

if ((!empty($menu_item['link']['has_children'])) && (!empty($menu_item['below'])) && $depth != 0) {
        $children = theme('superfish_build', $id, $menu_item['below'], $depth, $trail);
        $parent_class = $children ? 'menuparent ' : '';
        $output .= '<li id="menu-'. $mlid .'-'. $id .'"';
        if (!empty($parent_class) || !empty($class)) {
          $output .= ' class="'. $parent_class . $class .'"';
        }
        $output .= '>'. theme('menu_item_link', $menu_item['link']);
        if ($menu_item['link']['depth'] <= $depth || $depth == -1) {
          if ($children) {
            $output .= "<ul>\n $children \n</ul>\n";
          }
        }
        $output .= "</li>\n";
      }
      else {
        $output .= '<li id="menu-'. $mlid .'-'. $id .'"';
        if (!empty($class)) {
          $output .= ' class="'. $class .'"';
        }
        $output .= '>'. theme('menu_item_link', $menu_item['link']) .'</li>'."\n";
      }

Как я понял, код самого текста ссылки получается вот здесь:

$output .= '>'. theme('menu_item_link', $menu_item['link']);

Однако, поскольку я php владею ооочень поверхностно, я не понимаю, что это за theme('menu_item_link', $menu_item['link']), и как его изменить (да, я пытался разобраться в API - но только больше запутался).
Поэтому обращаюсь с вопросом:
можно ли только средствами темизации (не модифицируя файлы самого друпала) изменить код, возвращаемый этим выражением, и как это сделать?

Насколько смог, попытался разобраться сам. Похоже, что это то ли какая-то процедура, то ли функция - но где она находится и как её изменить файлами tpl.php - простите, не знаю.

Комментарии

Аватар пользователя Lex-DRL Lex-DRL 15 марта 2010 в 23:57

Отчаянные времена требуют отчаянных мер. Даже не верится, что залез так глубоко...

Насколько я разобрался, в данном коде ссылка формируется за счёт обращения к функции theme_menu_item_link, которая может быть перекрыта аналогичной phptemplate_menu_item_link в файле template.php темы.
Однако такое решение нехорошо - т.к. искомый код будет добавлен вообще ко всем менюхам на сайте, а не только к нужной. Стал копать дальше.
Выяснил, что при обращении к функции theme_menu_item_link в качестве аргумента передаётся массив. Стало быть, мы можем перекрыть саму функцию модуля superfish, чтобы отправляемая в качестве текста ссылки переменная уже имела всю "обёртку" тегами span. В template.php вставляю изменённую функцию:

function phptemplate_superfish_build($id, $menu, $depth = -1, $trail = NULL) {
...
$menu_item['link']['title'] = '<span class="back"><span class="hover"></span></span><span class="text">' . $menu_item['link']['title'] . '</span><span class="front"></span>';
...
}

Сделал. Даже получилось. Однако все пункты меню Superfish стали в качестве текста ссылки выдавать то, что по идее должно обрабатываться как код внутри тега < a >. Посмотрел на итоговый html - все символы открывающей и закрывающей скобок в добавленной "обёртке" заменены на их HTML-коды.
Похоже на то, что это дело где-то прогоняется через фильтр ввода, потому что когда попробовал поменять в функции theme_menu_item_link - primary и secondary links, которые вызываются из темы напрямую, отобразились нормально.

Теперь загвоздка в следующем: как можно изменить фильтр ввода для не-php блоков (тех, которые предоставляются модулями)? Тут уж сам не смог найти - как ни искал.

Аватар пользователя Lex-DRL Lex-DRL 16 марта 2010 в 11:16

Ночь почти не спал... зато получилось.
Сделал по аналогии с этим (вместо вызова функции menu_item_link() обращаюсь напрямую к l() ).

Вот код, вставляемый в template.php (для Superfish 6.x-1.3)

// Override theme_superfish_build function provided by Superfish module.
function phptemplate_superfish_build($id, $menu, $depth = -1, $trail = NULL) {
  $output = '';
  foreach ($menu as $menu_item) {
    $mlid = $menu_item['link']['mlid'];
    if ($menu_item['link']['hidden'] == 0) {
      if ($trail && in_array($mlid, $trail)) {
        $class = ' active-trail';
      }
      // Wrap necessary span code around anchor text.
      $menu_item['link']['title'] = '<span class="back"><span class="hover"></span></span><span class="text">' . check_plain($menu_item['link']['title']) . '</span><span class="front"></span>';
      // Define $menu_item['link'] array as that which contains HTML code.
      $menu_item['link']['html'] = TRUE;
      if ((!empty($menu_item['link']['has_children'])) && (!empty($menu_item['below'])) && $depth != 0) {
        $children = theme('superfish_build', $id, $menu_item['below'], $depth, $trail);
        $parent_class = $children ? 'menuparent ' : '';
        $output .= '<li id="menu-'. $mlid .'-'. $id .'"';
        if (!empty($parent_class) || !empty($class)) {
          $output .= ' class="'. $parent_class . $class .'"';
        }
        /*
        Generate menu link using core l() function directly instead of
        theme('menu_item_link', $menu_item['link']) to prevent converting
        "<" and ">" characters to their HTML code.
        */

        $output .= '>'. l($menu_item['link']['title'], $menu_item['link']['href'], $menu_item['link']);
        if ($menu_item['link']['depth'] <= $depth || $depth == -1) {
          if ($children) {
            $output .= "<ul>\n $children \n</ul>\n";
          }
        }
        $output .= "</li>\n";
      }
      else {
        $output .= '<li id="menu-'. $mlid .'-'. $id .'"';
        if (!empty($class)) {
          $output .= ' class="'. $class .'"';
        }
        // The same replacing with l() function one more time.
        $output .= '>'. l($menu_item['link']['title'], $menu_item['link']['href'], $menu_item['link']) .'</li>'."\n";
      }
    }
  }
  return $output;
}

P.S.: Похоже, что за эти 2 дня я освоил столько инфы, сколько, наверное, за последние полгода не перерабатывал. Надеюсь, мой опыт пригодится.

P.P.S.: указания на кривость кода приветствуются! Попутный вопрос: в чём разница в перекрывании функции через phptemplate_функция и МояТема_функция?

Аватар пользователя lkg0dzre lkg0dzre 29 апреля 2010 в 13:52

О, спасибо, что расписал весь процесс познания, понял теперь что такое хуки и зачем они нужны. Об этом почему-то никто нигде не пишет.

Аватар пользователя Lex-DRL Lex-DRL 29 апреля 2010 в 18:13

Благодаря тому, что я не забил на полурешённую проблему, и идентичную issue [##741528]открыл к модулю на друпал.орге[/##], теперь надобность в этом хуке отпала: автор сделал интерфейс к этому хуку, я подправил кой-какой баг, и в версии 1.6 модуль уже может вставлять кастомный код "из коробки".
Можно сказать, что это какой-никакой, но мой первый contribution. Smile

P.S.: Вообще, автор молодец. После того, как я обратил его внимание на решение моей частной проблемы, он сам в новой версии не только закопипастил решение, но и добавил несколько других фич, имеющих отношение к темизации: зебра, первый/последний, id...