Отображение другой разметки в 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). Это еще один способ поймать селектор.