Логотип

Документация по макросам и шаблонам UMI.CMS

Меню с изображениями

Это пример немного более сложного для понимания меню, поэтому для начала рекомендуется ознакомиться с топиком «Меню в виде списка». Кроме того, в этом примере будет использоваться протокол UPage (см. «Страницы: протокол UPage») и возможности сокращенного вызова по этому протоколу.

Постановка задачи

Предположим, что у нас уже есть шаблоны, описанные в предыдущем разделе — «Меню в виде списка» и мы представляем как они работают.

Наша задача, задействовать в шаблоне меню поля, содержащие путь до изображений активного и неактивного элемента меню (см. также «Общие сведения»).

Предположим, что мы хотим получить HTML-код следующего вида для списка элементов меню:

<ul>
  <li>
     <a href="/page1/">
       <img src="/images/cms/data/page1.jpg">Название страницы 1
     </a>
  </li>
  <li>
     <a href="/page2/">
       <img src="/images/cms/data/page2.jpg">Название страницы 2
     </a>
  </li>
  <li>
     <a href="/page3/" class="active">
       <img src="/images/cms/data/page3_act.jpg">Название страницы 3
     </a>
  </li>

  

</ul>

Верстка шаблонов

Итак, если посмотреть в пример предыдущего меню, мы видим, что 1 шаблон обрабатывают активный пункт меню, и 1 — все остальные.

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

После того, как изображения туда добавлены, каждая из этих страниц при запросе ее как XML данные (см. «Страницы: протокол UPage») будет содержать ссылки на эти 2 изображения в элементах:

  • property с атрибутом name="menu_pic_a" — для изображения активного раздела

  • property с атрибутом name="menu_pic_ua" — для изображения неактивного раздела

Таким образом, задача сводится к получению значений этих элементов и вставке их в атрибут src тега <img>

Сокращенный вызов по протоколу UPage

Для того, чтобы получить значение отдельного свойства для страницы, не обязательно вызывать ее полностью в виде XML-данных. Можно воспользоваться сокращенными вызовами ():

  • например, upage://94.menu_pic_a — для изображения активного раздела

  • и upage://94.menu_pic_ua — для изображения неактивного раздела

В результате мы получим XML-данные следующего содержания:

<udata generation-time="0.008246">
  <property id="28" name="menu_pic_a" type="img_file">
     <title>Изображение активного раздела</title>
     <value path="./images/cms/data/148820_pic1.jpg" folder="/images/cms/data" name="148820_pic1" ext="jpg" width="450" height="372">
       /images/cms/data/148820_pic1.jpg
     </value>
  </property>
</udata>

Включение результатов вызова UPage в обработку

Поскольку протокол UPage возвращает XML-данные, включить эти данные в обработку можно при помощи функции document(). Кроме того, на самом деле в этой задаче нас интересует только содержимое элемента value — то есть можно записать включения следующим образом (предположим, что id страницы 94):

  • document('upage://94.menu_pic_a')/udata/property/value — для изображения активного раздела

  • document('upage://94.menu_pic_ua')/udata/property/value — для изображения неактивного раздела

Теперь вернемся к шаблону, обрабатывающему отдельный пункт меню:

<xsl:template match="item" mode="menu">
  <li>
     <a href="{@link}">
       <xsl:value-of select="@name"/>
     </a>
  </li>
</xsl:template>

Вспомним теперь как выглядит ответ макроса — %content menu()% (см. в описании ответ UData). Отдельный элемент item ответа макроса уже содержит идентификатор страницы в своём атрибуте id:

<item id="95" link="/page1/" name="Название страницы 1" xlink:href="upage://95">

Передав этот параметр из шаблона в запрос UPage мы и получим ссылку на изображение для каждого пункта меню.

Построение более сложных запросов

Для того чтобы построить такой запрос необходимо воспользоваться еще одной функцией XSLT — concat().

Вставить полученное значение в атрибут src тега <img> мы можем таким же способом как мы вставляли атрибут link в href для ссылки ранее.

Таким образом получаем шаблон для неактивного пункта:

<xsl:template match="item" mode="menu">
  <li>
     <a href="{@link}">
       <img src="{document(concat('upage://', @id, '.menu_pic_ua'))/udata/property/value}"/>
       <xsl:value-of select="@name"/>
     </a>
  </li>
</xsl:template>

И шаблон для активного пункта:

<xsl:template match="item[@status = 'active']" mode="menu">
  <li>
     <a href="{@link}" class="active">
       <img src="{document(concat('upage://', @id, '.menu_pic_a'))/udata/property/value}"/>
       <xsl:value-of select="@name"/>
     </a>
  </li>
</xsl:template>

Замечание

Следует иметь в виду, что использование этих шаблонов не учитывает того, что картинки для некоторых страниц может и не быть. В таком случае в итоговом HTML-коде будут теги <img> с пустым src. Решение этой проблемы описано ниже.

Дополнение: условный вывод <img>

Для того, чтобы тег <img> вставлялся только тогда, когда есть значение в соответствующих полях у запрошенных страниц, мы опишем еще один шаблон, который будет обрабатывать результаты запроса.

Как и во всех предыдущих примерах обработку будет производить при помощи apply-templates, выбрав (select) для обработки элемент value:

<xsl:template match="item" mode="menu">
  <li>
     <a href="{@link}">
       <xsl:apply-templates select="document(concat('upage://', @id, '.menu_pic_a'))/udata/property/value" mode="menu"/>
       <xsl:value-of select="@name"/>
     </a>
  </li>
</xsl:template>

Теперь необходимо описать шаблон, который должен примениться к элементу value и вставить его значение в атрибут src тега <img>. Укажем шаблон при помощи соответствия match="value". Режим mode="menu" позволит обработать именно этот вызов и не спутать с другими возможными вызовами в шаблонах.

Сам шаблон чрезвычайно прост (однако в зависимости от реальных задач его можно дополнить всем, чем необходимо):

<xsl:template match="value" mode="menu">
  <img src="{.}" />
</xsl:template>

Запись {.} говорит шаблонизатору о том, что нужно вставить содержимое текущего обрабатываемого элемента — в нашем случае содержимое value.

В случае, если этого элемента в ответе UPage нет — инструкция apply-templates ничего не отправит на обработку, и шаблон не будет активирован. Соответственно, тег <img> в таком случае не будет выведен.

Итоговый набор шаблонов

Изображения для всех пунктов меню

Как уже было сказано выше, если мы гарантированно выводим изображения для каждого пункта меню, и все их заранее задали — достаточно будет таких шаблонов:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output encoding="UTF-8" method="html" indent="yes"/>

  
  
  <xsl:template match="/">
    <html>
      <head></head>
      <body>
      
        <div class="menu">
          <xsl:apply-templates select="document('udata://content/menu/')/udata"/>
        </div>

        <div class="content">
          
        </div>
      </body>
    </html>
  </xsl:template>

  

  <xsl:template match="udata[@module = 'content'][@method = 'menu']">
    <ul>
      <xsl:apply-templates select="items/item" mode="menu"/>
    </ul>
  </xsl:template>

  

  <xsl:template match="item" mode="menu">
    <li>
       <a href="{@link}">
         <img src="{document(concat('upage://', @id, '.menu_pic_ua'))/udata/property/value}"/>
         <xsl:value-of select="@name"/>
       </a>
    </li>
  </xsl:template>

  

  <xsl:template match="item[@status = 'active']" mode="menu">
    <li>
       <a href="{@link}" class="active">
         <img src="{document(concat('upage://', @id, '.menu_pic_a'))/udata/property/value}"/>
         <xsl:value-of select="@name"/>
       </a>
    </li>
  </xsl:template>

</xsl:stylesheet>

Изображения не для всех пунктов меню

В случае, если вывод пустого тега <img> для пунктов меню, у которых не заданы эти поля, нежелателен — предлагается следующий набор шаблонов:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output encoding="UTF-8" method="html" indent="yes"/>

  
  
  <xsl:template match="/">
    <html>
      <head></head>
      <body>
      
        <div class="menu">
          <xsl:apply-templates select="document('udata://content/menu/')/udata"/>
        </div>

        <div class="content">
          
        </div>
      </body>
    </html>
  </xsl:template>

  

  <xsl:template match="udata[@module = 'content'][@method = 'menu']" mode="menu">
    <ul>
      <xsl:apply-templates select="items/item" mode="menu"/>
    </ul>
  </xsl:template>

  

  <xsl:template match="item" mode="menu">
    <li>
       <a href="{@link}">
         <xsl:apply-templates select="document(concat('upage://', @id, '.menu_pic_a'))/udata/property/value" mode="menu"/>
         <xsl:value-of select="@name"/>
       </a>
    </li>
  </xsl:template>

  

  <xsl:template match="item[@status = 'active']" mode="menu">
    <li>
       <a href="{@link}" class="active">
         <xsl:apply-templates select="document(concat('upage://', @id, '.menu_pic_a'))/udata/property/value" mode="menu"/>
         <xsl:value-of select="@name"/>
       </a>
    </li>
  </xsl:template>

  

  <xsl:template match="value" mode="menu">
    <img src="{.}" />
  </xsl:template>

</xsl:stylesheet>