среда, 26 октября 2011 г.

SharePoint и XSLT: преобразуем колонку в строку

В посте про объединение двух колонок в одну я показывал на "боевом" примере про комментарий руководителя, как можно сэкономить место на странице и сделать представление более привлекательным, объединяя несколько колонок в одну. С помощью XSLT, мы производили вот такое преобразование:


Но как видите, всё равно в строке с комментарием остается много пустого места:



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


Вперед?


Прежде всего, давайте вспомним теорию и упрощенное дерево шаблонов XsltListViewWebPart:


В предыдущем примере мы изменяли шаблон PrintTableCellEcbAllowed у заголовочной ячейки, и помещали туда дополнительный div, в который вставляли текст комментария руководителя. Легко догадаться, что в этот раз шаблон PrintTableCellEcbAllowed нам не поможет: придется подниматься по дереву шаблонов вверх, и работать уже с шаблоном Item, который, напомню, выводит элемент <tr> - то есть всю строку.

Нам нужно всего лишь научить этот шаблон в некоторых случаях (когда PM's comment не пустой) выводить два элемента <tr> вместо одного, и во второй <tr> вставлять тот же самый <div>.

Признаюсь честно, для меня это преобразование выглядит элементарным, но судя по комментариям к посту про две колонки, не для всех это настолько очевидно... :) Поэтому давайте еще раз вкратце распишем алгоритм наших действий, требуемых для желаемого преобразования:
  1. Получить код стандартного шаблона Item.
  2. Найти в этом коде завершающий тег </tr>, и после него добавить условный вывод еще одного <tr>, содержащего уже известный нам по посту про объединение двух колонок <div>.
Получить код стандартного шаблона Item можно двумя способами.

Во-первых, можно открыть в браузере на SharePoint-портале файл /_layouts/xsl/vwstyles.xsl, и найти там шаблон <xsl:template mode="Item"


Во-вторых, можно воспользоваться старым трюком с Conditional formatting, выбрав форматирование строки (а не столбца, как мы выбирали в прошлый раз):


Далее нужно выбрать любое невыполнимое условие (например ID='0'), и подключить любой стиль.

В конечном итоге, всё равно получим в нашем теге <Xsl> шаблон Item. Пролистываем до конца этого шаблона, видим закрывающий тег </tr>. Ага, он-то нам и нужен!

После него и перед </xsl:template>, нужно добавить следующий код:

    <xsl:if test="$thisNode/@PM_x0027_s_x0020_comment != ''">
      <tr>
        <td colspan="{count($Fields)+1}">
          <div style="background-color:#FFEEEE; margin: 5px; padding: 4px 10px; font-size: 9px;">
            <xsl:apply-templates select="../FieldRef[@Name='PM_x0027_s_x0020_comment']" mode="PrintFieldWithECB">
              <xsl:with-param name="thisNode" select="$thisNode"/>
            </xsl:apply-templates>
          </div>
        </td>
      </tr>
    </xsl:if>

На самом деле, я скопировал этот код из предыдущей статьи. Всё что я сделал здесь - это обернул <div> в <tr> и <td>, причем в <td> указал атрибут colspan, чтобы расширить ячейку на всю строку.

Переменная $Fields - это список всех полей (FieldRef'ов), который передается шаблону Item в качестве параметра. Плюс я использую стандартную xpath-функцию count для подсчета количества полей.

Если теперь переключиться во вкладку Design, увидим, что ура, строка с нашим div'ом действительно появилась - но она почему-то пустая, в ней нет текста!


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

Не удалось? Не страшно, ведь всегда можно подсмотреть правильный ответ :)

Дело здесь в том, что мы вызываем шаблон PrintFieldWithECB для неверной выборки данных. Ведь раньше мы вызывали его из другого шаблона, а сейчас шаблон изменился, и естественно, что нужно обновить xpath-запрос. Правильным решением здесь будет просто заменить ../FieldRef на $Fields в xpath-запросе атрибута select элемента apply-templates.

На самом деле, я надеюсь, эту загадку вы легко разгадали, и получили то, что требовалось. Да, чтобы "догнать" внешний вид до скриншота в начале статьи, понадобится конечно немножко поиграться с css :)

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

До новых встреч!

10 комментариев:

  1. Андрей, добрый день!
    Вопрос немного не по теме, но все же.
    Вы не сталкивались с ситуацией, что условное форматирование, созданное в SPD, в нём отражается, а в браузере его не видно?
    Регулярно сталкиваюсь с такой проблемой, причом раз на раз не приходится - иногда работает как часы, а иногда нивкакую.
    Буду рад любому совету (единственное - программированием не владею. Могу только слегка править код представления в SPD)

    ОтветитьУдалить
  2. Юрий, здравствуйте! Первым делом, я бы тщательно проверил разметку на вкладке [Code] - например, бывает, что иногда создается два Xsl-тэга, и потом один из них удаляется.

    ОтветитьУдалить
  3. Хм. Андрей, а вы не могли бы на примере это показать? Сам я не могу разобраться. Заранее спасибо

    ОтветитьУдалить
  4. Я вроде сумел найти нужную часть кода:

    background-color: #FF0000;




    100%
    OnChildItem(this)

    ОтветитьУдалить
  5. тьху... форма комментария сожрала весь код

    ОтветитьУдалить
  6. Андрей, приветствую!
    А возможно ли вывести этой строкой текстовое поле с расширенным форматированием? Чтобы были видны вставленные картинки, выделение текста цветом и тп.

    ОтветитьУдалить
  7. Можно. Примерно так:

    <xsl:value-of select="../FieldRef[@Name='PM_x0027_s_x0020_comment']" disable-output-escaping="false" />

    (вместо <apply-templates mode="PrintFieldWithECB">)

    ОтветитьУдалить
  8. Андрей, если не сложно объясни как сделать так как у тебя на финальной картинке (там где с скруглением и тенью), как ты это сделал? при помощи vml? я пытался пока тяжко. Да и еще здорово было бы если бы в блоке отображалось часть текста а при наведении мыши отображался весь текст. Заранее благодарен.

    ОтветитьУдалить
  9. Роман, у меня это всего-лишь CSS3, свойства rounded-border и box-shadow.

    Если вам нужна поддержка в старых браузерах, наверное придется воспользоваться какой-нибудь js-библиотекой для этого.

    ОтветитьУдалить
  10. Здравствуйте,Андрей, я создаю собственное определение списка и список. Работаю в visual studio и хотел бы узнать, как лучше подключить css в xsl для блока div?

    ОтветитьУдалить

Внимание! Реклама и прочий спам будут беспощадно удаляться.