Статьи

Начало работы с Umbraco: Часть 3

В этой части серии мы создадим остальные наши узлы контента (страницы) и начнем добавлять макросы XSLT для обработки таких вещей, как создание навигации по сайту и <umbraco:Macro> элементов <umbraco:Macro> .


  1. Начало работы с Umbraco: Часть 1
  2. Начало работы с Umbraco: Часть 2
  3. Начало работы с Umbraco: Часть 3
  4. Начало работы с Umbraco: часть 4
  5. Начало работы с Umbraco: часть 5

Сначала мы добавим остальные наши узлы контента. Помните, типы документов + шаблоны + узлы содержимого = страницы. Для просмотра бэк-энда сайт должен быть открыт в Visual Web Developer Express (VWD). Щелкните правой кнопкой мыши страницу default.aspx на правой панели Solution Explorer и выберите View in Browser . Домашняя страница сайта должна загрузиться. Чтобы получить доступ к бэкенду, замените default.aspx в адресной строке на umbraco, после чего вы должны перейти на экран входа в систему, а затем в бэкэнд после того, как ваши учетные данные были введены.

Все страницы на сайте должны быть созданы как дочерние узлы домашней страницы, чтобы XSLT работал правильно. Щелкните правой кнопкой мыши узел « Home в верхней левой части панели и выберите « Create в раскрывающемся меню. Это даст нам диалог Create ; в поле Name введите About Us . Поле Choose Document Type уже должно быть заполнено первым доступным типом документа — Content — это нормально, просто нажмите кнопку « Create внизу, и новый узел будет создан как дочерний узел узла « Home :


Введите текст в текстовой области, затем Properties вкладку « Properties » и введите « All About Us в поле « Page Title , затем сохраните новый узел, используя значок диска на панели инструментов. Далее мы создадим страницу News List ; щелкните правой кнопкой мыши узел Home и снова выберите Create . Введите News в качестве имени и выберите Тип документа News List в поле выбора. Эта страница не имеет пользовательских свойств (она будет построена с использованием макроса), поэтому узел откроется на вкладке Properties . Введите Company News в поле Page Title и щелкните значок «Сохранить и опубликовать».

Далее мы можем создать несколько новостей; на этот раз щелкните правой кнопкой мыши узел News и выберите Create . Добавьте News Item 1 в поле « Name и нажмите « Create (правильный тип документа уже будет выбран). У нас есть еще несколько полей для заполнения на этот раз; идти вперед и выбрать дату, добавить Headline и Story Text . Мы также можем добавить другое изображение в библиотеку мультимедиа и выбрать его с помощью средства выбора медиафайлов (хотя это изображение не обязательно для News Items ). Также добавьте Page Title на вкладке Properties . Как только это будет сделано, создайте еще одну News Item и снова заполните поля. Убедитесь, что в текстовой области имеется достаточное количество текста для каждой новости, поскольку мы будем извлекать часть из каждого News Item чтобы создать страницу News List .

Итак, теперь мы создали Content page News List и пару News Items . Осталось только создать несколько панелей героев для отображения на главной странице. Снова щелкните правой кнопкой мыши узел Home , затем добавьте Panel 1 в качестве имени нового узла и выберите тип документа Hero Panel . Используйте текстовую область на только что созданном узле, чтобы добавить текст на панель. Кроме того, мы должны убедиться, что мы переключаемся на вкладку Properties и Umbraco Hide In Navigation флажок Umbraco Hide In Navigation . Создайте несколько панелей таким образом, возможно, используя другой текст или что-то, чтобы различать разные панели. На этом этапе наш сервер должен выглядеть следующим образом:



Теперь, когда наши страницы созданы, мы можем начать писать макросы XSLT, которые будут создавать более сложные аспекты сайта, такие как навигация, список новостей и т. Д. Если мы откроем файл BasePage.master в VWD, первый <umbraco:Macro> мы находим, является макросом pageTitle . Сначала мы создадим его, так как он довольно прост и должен дать базовое введение в XSLT.

В серверной части Umbraco перейдите в раздел « Developer », щелкните правой кнопкой мыши папку XSLT и выберите « Create . В появившемся диалоговом окне добавьте pageTitle качестве имени Filename и оставьте для поля выбора значение Clean . Обратите внимание, что флажок « Create Macro уже отмечен. Нажмите кнопку Create . Новый файл XSLT и соответствующий ему макрос будут созданы. Выберите макрос (он будет найден в папке « Macros » в дереве узлов) и измените Alias макроса с PageTitle на pageTitle (для согласованности).

Теперь переключитесь обратно на VWD и откройте файл XSLT в Solution Explorer справа. Новый файл XSLT, который мы создали в Umbraco, должен быть в списке. Конечно, мы можем добавить код XSLT напрямую через Umbraco, однако по соображениям Intellisense полезно написать его на VWD. Откройте файл XSLT, примерно в середине файла появится комментарий, который гласит <!—start writing XSLT --> , удалите этот комментарий и замените его следующим кодом:

1
2
3
4
5
6
<xsl:if test=»$currentPage/pageTitle != »»>
    <xsl:value-of select=»$currentPage/pageTitle»/>
    <xsl:text> — </xsl:text>
</xsl:if>
  
<xsl:value-of select=»$currentPage/ancestor-or-self::* /domainName»/>

Сохраните файл XSLT. По сути, XSLT используется для преобразования XML в другие типы XML или другие форматы XML, такие как XHTML. Данные, которые мы вводим в поля в серверной части Umbraco, хранятся в базе данных в виде XML, поэтому мы можем использовать XSLT для обработки этого XML и преобразования его в (X) HTML для отображения на наших страницах. Прежде чем углубляться в детали того, что делает приведенный выше код, нам просто нужно взглянуть на пару основных концепций для работы с XSLT.

Прежде всего, сразу после элемента <xsl:output> есть элемент параметра XSL ( <xsl:param> ), называемый currentPage . Это будет установлено на любую страницу, которая «вызывает» XSLT-файл, поэтому, если посетитель просматривает домашнюю страницу сайта, параметр currentPage будет установлен на Home узел в серверной части. Если страница содержимого, такая как страница « About us , просматривается, параметр currentPage будет установлен на эту страницу.

На следующей строке у нас есть элемент шаблона XSL ( <xsl:template> ), для которого установлено соответствие / что означает, что он должен соответствовать всем элементам и атрибутам XML в документе (сохраненное представление XML узла в back- конец).

Теперь давайте посмотрим на код, который мы добавили к элементу <xsl:template> . Сначала мы используем элемент <xsl:if> чтобы проверить, содержит ли значение currentPage (в параметрах XSLT должно начинаться с символа $ ) значение элемента pageTitle . Это элемент pageTitle в нашем узле страницы, а не макрос pageTitle . Если оно содержит значение, следующая строка <xsl:value-of> позволяет нам выбрать содержимое свойства pageTitle . Затем мы используем элемент <xsl:text> чтобы указать дефис для использования в качестве разделителя.

Наконец, мы снова используем элемент <xsl:value-of> чтобы выбрать свойство domainName . В этом элементе мы используем шаг XPath, который состоит из оси ancestor-or-self чтобы выбрать все узлы-предки currentPage а также currentPage , и узел ::* проверки всех атрибутов выбранных предков. Мы ограничимся этим до свойства domainName мы установили на Home узле с /domainName предиката /domainName .

Теперь просмотрите домашнюю страницу сайта, и заголовок страницы должен автоматически установить значение, которое мы ввели в свойстве domainName . Если мы просматриваем страницу о нас (просто добавляем /about-us.aspx в конец URL-адреса localhost в адресной строке), мы обнаруживаем, что заголовок установлен на All About Us – The Company . Название страницы — Название сайта является предпочтительным форматом заголовка по причинам SEO.

В этом примере страницы, у которых не установлено свойство pageTitle , просто возвращаются к свойству domainName . Некоторые авторы макросов добавляют дополнительный уровень защиты, и если pageTitle не установлен, вместо этого nodeName к nodeName . Это полезно, если клиент может забыть установить pageTitle при добавлении новых страниц на сайт, но это означает, что заголовок страницы может заканчиваться именами файлов в верблюжьей оболочке. Есть аргументы за и против этого метода. Я оставлю вам решать, нужен ли этот дополнительный запасной вариант.


Давайте добавим еще несколько макросов; Затем мы должны построить навигацию для сайта, чтобы было легче перемещаться между страницами. Этот макрос будет намного сложнее, чем макет PageTitle, который мы только что рассмотрели. Мы оставили некоторую разметку в файле BasePage.master , это структура, с которой мы закончим, как только закончим. Удалите это с главной страницы и добавьте <umbraco:Macro> элемент <umbraco:Macro> :

1
<umbraco:Macro Alias=»topNav» runat=»server»></umbraco:Macro>

Теперь создайте новый файл XSLT (и, следовательно, макрос) с именем topNav . В VWD откройте новый файл XSLT и добавьте следующий код непосредственно после параметра currentPage :

1
<xsl:variable name=»rootNode» select=»$currentPage/ancestor-or-self::* [@isDoc and @level=1]» /></div>

Затем добавьте следующий код в элемент <xsl: template>:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<nav>
    <ul class=»clear-float»>
        <li>
            <a href=»{umbraco.library:NiceUrl($rootNode/@id)}»>
                <xsl:if test=»$rootNode/@id = $currentPage/@id»>
                    <xsl:attribute name=»class»>on</xsl:attribute>
                </xsl:if>
                <xsl:value-of select=»$rootNode/@nodeName» />
            </a>
        </li>
  
        <xsl:for-each select=»$currentPage/rootNode/* [@isDoc and string(umbracoNavHide) != ‘1’]»>
            <li>
                <xsl:if test=»position() = last()»>
                    <xsl:attribute name=»class»>
                        <xsl:text>last</xsl:text>
                    </xsl:attribute>
                </xsl:if>
                <a href=»{umbraco.library:NiceUrl(@id)}»>
                    <xsl:if test=»$currentPage/@id = @id»>
                        <xsl:attribute name=»class»>on</xsl:attribute>
                    </xsl:if>
                    <xsl:attribute name=»title»>
                        <xsl:value-of select=»@nodeName»/>
                    </xsl:attribute>
                    <xsl:value-of select=»@nodeName»/>
                </a>
                <xsl:if test=»child::* [@isDoc]»>
                    <ul>
                        <xsl:for-each select=»child::* [@isDoc and string(umbracoNavHide) != ‘1’]»>
                            <xsl:choose>
                                <xsl:when test=»position() < 6 and string(child::NewsItem = ‘1’)»>
                                    <li>
                                        <a href=»{umbraco.library:NiceUrl(@id)}»>
                                            <xsl:attribute name=»title»>
                                                <xsl:value-of select=»@nodeName»/>
                                            </xsl:attribute>
                                            <xsl:value-of select=»@nodeName»/>
                                        </a>
                                    </li>
                                </xsl:when>
                                <xsl:otherwise>
                                    <li>
                                        <a href=»{umbraco.library:NiceUrl(@id)}»>
                                            <xsl:attribute name=»title»>
                                                <xsl:value-of select=»@nodeName»/>
                                            </xsl:attribute>
                                            <xsl:value-of select=»@nodeName»/>
                                        </a>
                                    </li>
                                </xsl:otherwise>
                            </xsl:choose>
                        </xsl:for-each>
                    </ul>
                </xsl:if>
            </li>
        </xsl:for-each>
    </ul>
</nav>

Сохраните файл. Прежде всего, мы устанавливаем переменную, которая соответствует корневому узлу сайта, то есть домашней странице. Чтобы выбрать только домашнюю страницу, мы перемещаемся от currentPage (используя параметр $currentPage ) через всех предков, используя ось ancestor-or-self а также ::* testtest и предикат ::* , проверяя, что узел имеет атрибут @isDoc (это добавлен на все узлы страницы Umbraco) и находится на уровне 1 (еще один атрибут, добавленный Umbraco). Это даст нам корневой узел сайта, который является домашней страницей.

Затем в <xsl:template> мы сначала создаем внешние контейнеры для нашего меню навигации, в частности элементы <nav> и <ul> . Затем мы добавляем первый элемент <li> и первый элемент привязки. Мы устанавливаем href привязки, используя библиотечную функцию Umbraco NiceUrl , которая принимает id документа в качестве аргумента. Мы предоставляем id корневого узла, используя нашу переменную $rootNode (как и параметры, переменные начинаются с символа $ . Атрибуты начинаются с @ в XSLT). Функция NiceUrl будет возвращать сохраненный URL-адрес для узла.

Затем мы проверяем, совпадает ли id $rootNode с id $currentPage используя инструкцию <xsl:if> ; если это так, мы знаем, что домашняя страница в данный момент просматривается, и добавляем класс on для привязки. Затем мы выбираем имя узла ( Name присвоенное узлу в серверной части Umbraco, которое отображается на вкладке Properties для узла), чтобы использовать его в качестве атрибута title элемента привязки, и его текст, используя элемент <xsl:value-of> для выбора значений.

Затем нам нужно перебрать каждый узел страницы под домашней страницей, то есть мы используем цикл <xsl:for-each> чтобы выбрать и обработать все узлы, которые являются $rootNode и также являются документами, но которые дополнительно не umbracoNavHide флажок umbracoNavHide . Это препятствует тому, чтобы наши панели Героя были перечислены в меню навигации по всему сайту, что явно нам не нужно!

Для каждого дочернего элемента $rootNode мы создаем новый элемент <li> . Мы делаем быструю проверку, чтобы увидеть, обрабатываем ли мы последний узел в наборе, что достигается путем проверки, равна ли position узла в наборе узлов last . Если это так, мы добавляем имя класса last в <li> .

Хотя это и не является строго необходимым в этом примере, это все же невероятно полезный метод, позволяющий использовать видение, поскольку ни IE6, ни IE7 (на которые по-прежнему приходится большой процент аудитории несчастного числа сайтов) не могут использовать last-child CSS селектор.

Затем мы создаем новый <a> внутри <li> и устанавливаем его href используя функцию NiceUrl еще раз, на этот раз передавая атрибут id текущего узла. Мы устанавливаем заголовок и текст якоря так же, как и раньше. Мы также добавляем класс on если просматриваемая страница совпадает со страницей, обрабатываемой в данный момент. Поскольку мы уже находимся в контексте узла, нам в основном не нужно использовать параметр $currentPage , используя его только тогда, когда мы @id текущего узла с @id текущей страницы.

После того как ссылка для элемента nav создана, мы проводим еще один тест (снова используя условное <xsl:if> ), чтобы определить, есть ли у текущего узла дочерние узлы, являющиеся документами. Если это так, мы создаем суб-навигацию с использованием вложенного <ul> , а затем выбираем каждый дочерний узел, который является документом и не имеет флажка umbracoNvHide .

Затем мы используем условное выражение <xsl:choose> , которое похоже на XSLT, эквивалентный if...else , чтобы ограничить число NewsItem дочернего меню NewsItem пятью, проверяя, имеет ли дочерний элемент position менее 6 когда мы обрабатываем NewsItems . Мы можем проверить, обрабатываем ли мы в настоящее время узлы NewsItem , проверив, NewsItem ли тест для этого элемента ( child::NewsItem ) child::NewsItem true .

Мы должны ограничить субнав для новостных элементов, потому что после того, как сайт какое-то время работал, потенциально могут быть сотни новостных статей, и было бы смешно перечислять их все в навигационном меню. Затем мы создаем новые <li> и <a> для каждого дочернего элемента, максимум до 5. Это в элементе <xsl:when> , который эквивалентен части if в if...else . Когда мы не обрабатываем NewsItems , мы просто создаем subnav для всех элементов (в элементе <xsl:otherwise> else <xsl:otherwise> , который эквивалентен части else if...else .)

Это по сути это; если мы сохраним это сейчас и вернемся на домашнюю страницу сайта (фактическую домашнюю страницу, которая просматривается в браузере, а не на узел «Домой» в бэкэнде) и обновим ее, мы обнаружим, что наша nav верхнего уровня создана для нас автоматически:


Далее мы можем создать навигацию для нижнего колонтитула сайта; это почти идентично верхней навигационной панели, за исключением того, что у него нет поднабра. Создайте новый XSLT-файл таким же образом, как и раньше, и назовите его footerNav . Добавьте следующий код в файл:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<nav>
    <ul>
        <li>
            <a href=»{umbraco.library:NiceUrl($rootNode/@id)}»>
                <xsl:if test=»$rootNode/@id = $currentPage/@id»>
                    <xsl:attribute name=»class»>on</xsl:attribute>
                </xsl:if>
            <xsl:attribute name=»title»>
                <xsl:value-of select=»$rootNode/@nodeName»/>
            </xsl:attribute>
            <xsl:value-of select=»$rootNode/@nodeName» />
        </a>
    </li>
  
        <xsl:for-each select=»$rootNode/* [@isDoc and string(umbracoNavHide) != ‘1’]»>
            <li>
                <xsl:if test=»position() = last()»>
                    <xsl:attribute name=»class»>
                        <xsl:text>last</xsl:text>
                    </xsl:attribute>
                </xsl:if>
                <a href=»{umbraco.library:NiceUrl(@id)}»>
                    <xsl:if test=»$currentPage/@id = @id»>
                        <xsl:attribute name=»class»>on</xsl:attribute>
                    </xsl:if>
                    <xsl:attribute name=»title»>
                        <xsl:value-of select=»@nodeName»/>
                    </xsl:attribute>
                    <xsl:value-of select=»@nodeName»/>
                </a>
            </li>
        </xsl:for-each>
    </ul>
</nav>

Этот XSLT-файл также должен определить переменную rootNode в верхней части, как и в случае с topNav , и не забудьте добавить <umbraco:Macro> в файл BasePage.master :

1
<umbraco:Macro Alias=»footerNav» runat=»server»></umbraco:Macro>

Это все макросы, которые нам нужны в файле BasePage.master . В файле Home.master есть только макрос панели Hero, который мы добавим в другой части серии, а в файле Content.master вообще нет макросов. Следующий файл, к которому нам нужно добавить макрос, это страница NewsList.master ; мы добавим это в следующей части серии.


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

XSLT и XPath являются мощными языками для работы с документами XML и элементами, содержащимися в этих документах. Если это был ваш первый опыт работы с XSLT, некоторые из них могут все еще казаться немного чуждыми, особенно если вы привыкли работать с более интуитивными языками, такими как HTML и CSS. Но не волнуйтесь, XSLT и XPath легко подобрать, если немного потренироваться, и они заслуживают изучения языков, например, jQuery использует XPath для выбора элементов из (X) HTML-страниц.

В следующей части серии мы добавим XSLT-файлы, которые будут создавать страницу списка новостей и меню навигации по новостям, а затем перейдем к рассмотрению того, как мы можем добавить .Net User Controls в Umbraco для еще большей пользовательской функциональности.