Отображение другой разметки в Sightly на основе селектора Sling

Контекст

Я работаю над проектом AEM 6, который использует Sightly в качестве языка шаблонов. Я сталкиваюсь со случаем использования, в котором я хочу показать или скрыть определенные части разметки в зависимости от наличия селектора Sling.

Например, запрос к /content/my-project/my-page.html должен дать базовый вид страницы и когда запрос сделан /content/my-project/my-page.ubermode.html, Sling должен возвращать тот же контент, представленный немного другим HTML-документом.

Согласно Шпаргалке, должно быть возможно использовать другой скрипт.

Мне удалось реализовать это в компоненте, поместив два скрипта Sightly, mycomponent.html а также ubermode.html (назван в честь селектора)

/apps/(...)/mycomponent
            |- .content.xml
            |- _cq_editConfig.xml
            |- dialog.xml
            |- mycomponent.html
            |- ubermode.html

Это требует некоторого дублирования кода, когда дело доходит до структуры HTML, но работает нормально.

Тем не менее, в этом конкретном случае мне нужно сделать то же самое на уровне рендерера (давайте назовем это myapp/core/renderers/fancyPageRenderer). Более того, у рендерера есть другой рендер, так как sling:resourceSuperType (давайте назовем этот родительский рендер myapp/core/renderers/genericPageRenderer) и опирается на умеренно сложную серию включений (data-sly-include).

В fancyPageRendererЯ переопределяю один из сценариев, изначально определенных и включенных в genericPageRenderer, Это та часть, которую я хотел бы отличать, когда ubermode селектор используется. Давайте назовем этот скрипт mainColumn.html

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

Это была начальная структура

/apps/(...)/renderers/fancyPageRenderer
                      |- .content.xml
                      |- mainColumn.html //this overrides a script included by a parent renderer

Вот что я попробовал:

/apps/(...)/renderers/fancyPageRenderer
                      |- .content.xml
                      |- mainColumn.uber.html
                      |- mainColumn.html

Это просто не сработало и mainColumn.html будет включен каждый раз.


/apps/(...)/renderers/fancyPageRenderer
                      |- .content.xml
                      |- uber.html
                      |- mainColumn.html

Это вызвало uber.html сценария, который будет использоваться, но полученная страница не содержала разметки, определенной в других сценариях, включенных в genericPageRenderer


Я думаю, что я мог бы просто скопировать все соответствующие сценарии и включает в себя fancyPageRenderer но это приведет к массовому и совершенно недопустимому дублированию кода.

Я также знаю, что можно вручную добавлять, удалять или заменять селекторы, используяdata-sly-resource или просто использовать оригинальные селекторы, но в моем случае это data-sly-include и не data-sly-resource это широко используется.

Есть ли элегантный способ обойти эту проблему?

2 ответа

Решение

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

Вот текущая структура fancyPageRenderer (который не изменился с оригинала):

/apps/(...)/renderers/fancyPageRenderer
                      |- .content.xml
                      |- mainColumn.html //this overrides a script included by the parent renderer

Вот что я использовал в mainColumn.html Достоверно сценарий:

 <div class="fancy main-column" data-sly-use.uberMode="com.foo.bar.myapp.fancy.UberMode">
     <div data-sly-test="uberMode.enabled" >Uber-mode-only-content</div>
     <!-- Lots of markup here -->
     <div data-sly-test="!uberMode.enabled" >Explicitly non-uber-mode content</div>
     <div>Common content (but some uber-mode-dependend, nested divs as well, rendered the same way as above)</div>
 </div>

и базовая модель слинга, UberMode

@Model(adaptables = SlingHttpServletRequest.class)
public class UberMode {

    @Inject
    SlingHttpServletRequest request;

    private boolean enabled = false;

    @PostConstruct
    public void postConstruct() {
        if (request != null) {
            List<String> selectors = Arrays.asList(request.getRequestPathInfo().getSelectors());
            enabled = selectors.contains("ubermode");
        }
    }

    public boolean isEnabled() {
        return enabled;
    }
}

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

Это также оставляет мне много вариантов рефакторинга. Я мог бы перейти от использования селектора к параметру запроса или заголовку и написать только пару строк кода, даже не касаясь сценария Sigthly, который фактически является клиентским кодом моего класса.

Добавьте файл ubermode.html, который будет вызываться при наличии убермода Sling Selector. Чтобы избежать дублирования кода, извлеките общие части (header.html, footer.html и т. д.) и включите их там, где это необходимо.

В случае с mainColumn.html вы можете попробовать поместить его в подкаталог с именем ubermode (/ubermode/mainColumn.html). Это еще один способ поймать селектор.

Другие вопросы по тегам