From 3d5fd8e2b35aba2523e797a6363674f590a88d0c Mon Sep 17 00:00:00 2001 From: nagyad Date: Wed, 6 Apr 2022 13:49:52 +0200 Subject: [PATCH 01/42] EWPP-2070: Allow and in introduction fileds. --- .../src/Plugin/PageHeaderMetadata/NodeViewRoutesBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/oe_theme_helper/src/Plugin/PageHeaderMetadata/NodeViewRoutesBase.php b/modules/oe_theme_helper/src/Plugin/PageHeaderMetadata/NodeViewRoutesBase.php index aca28fea7..3cfffa5c7 100644 --- a/modules/oe_theme_helper/src/Plugin/PageHeaderMetadata/NodeViewRoutesBase.php +++ b/modules/oe_theme_helper/src/Plugin/PageHeaderMetadata/NodeViewRoutesBase.php @@ -110,7 +110,7 @@ protected function getIntroductionMetadata(string $field_name): array { // We strip the tags because the component expects only one paragraph of // text and the field is using a text format which adds paragraph tags. '#type' => 'inline_template', - '#template' => '{{ summary|render|striptags("")|raw }}', + '#template' => '{{ summary|render|striptags("")|raw }}', '#context' => [ 'summary' => [ '#type' => 'processed_text', From aa21596259d6c4d5876cd3056fe92072b29dffde Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Thu, 24 Mar 2022 18:28:36 +0200 Subject: [PATCH 02/42] EWPP-2069: Update list item default variant to render external link icon. --- .../list_item/list_item.ui_patterns.yml | 7 +++++- .../list_item/pattern-list-item.html.twig | 25 +++++++++++++++---- tests/src/Kernel/fixtures/rendering.yml | 19 +++++++++++--- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/templates/patterns/list_item/list_item.ui_patterns.yml b/templates/patterns/list_item/list_item.ui_patterns.yml index 249500309..4bc57416b 100644 --- a/templates/patterns/list_item/list_item.ui_patterns.yml +++ b/templates/patterns/list_item/list_item.ui_patterns.yml @@ -94,7 +94,7 @@ list_item: type: "text" label: "Icon" description: "An optional icon to be used with the link." - preview: "external" + preview: "list" badges: type: array label: "Badges" @@ -104,3 +104,8 @@ list_item: variant: "highlight" - label: "Status: Open" variant: "high" + external_link: + type: "boolean" + label: "External link" + description: "Whether the URL of the item is external or not." + preview: true diff --git a/templates/patterns/list_item/pattern-list-item.html.twig b/templates/patterns/list_item/pattern-list-item.html.twig index 77ee70f94..c5359bc33 100644 --- a/templates/patterns/list_item/pattern-list-item.html.twig +++ b/templates/patterns/list_item/pattern-list-item.html.twig @@ -13,6 +13,7 @@ - "length" (int) (default: 0): Max length of detail field. - "additional_information" (array): Additional information to be displayed right below the 'Detail' field. - "icon" (string) (default: ''): Icon used for the link item. + - "external_link" (bool) (default: false): Whether the link is external or not. #} {# Create macro #} @@ -76,14 +77,28 @@ } } %} {% if icon %} - {% set _link = _link|merge({ - icon: { + {% set _icon = { + 'path': ecl_icon_path, + 'name': icon, + 'size': 's', + } %} + {% endif %} + {% if external_link %} + {% if _icon %} + {% set _icon = _icon|merge({ + 'name': 'external' + }) %} + {% else %} + {% set _icon = { 'path': ecl_icon_path, - 'name': icon, + 'name': 'external', 'size': 's', - } - }) %} + } %} + {% endif %} {% endif %} + {% set _link = _link|merge({ + icon: _icon + }) %} {% include '@ecl-twig/link' with _link only %} {% else %} {{ title }} diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index e66cbc544..16aaf24f7 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -826,6 +826,7 @@ 'article.ecl-content-item div.ecl-content-item__image__after': 0 'span.ecl-label.ecl-label--highlight.ecl-u-mr-xs': 1 'span.ecl-label.ecl-label--high.ecl-u-mr-xs.ecl-u-type-color-black': 1 + 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 0 equals: 'article.ecl-content-item div.ecl-content-item__meta span.ecl-label.ecl-label--highlight.ecl-u-mr-xs': "Highlighted" 'article.ecl-content-item div.ecl-content-item__meta span.ecl-label.ecl-label--high.ecl-u-mr-xs.ecl-u-type-color-black': "Status: Open" @@ -842,16 +843,19 @@ length: 6 meta: - "Meta 1" + external_link: true assertions: count: 'article.ecl-content-item div.ecl-content-item__title a.ecl-link[href="http://example.com"]': 1 'article.ecl-content-item div[role="img"].ecl-u-d-l-block': 0 'article.ecl-content-item div.ecl-content-item__image__before': 0 'article.ecl-content-item div.ecl-content-item__image__after': 0 + 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 1 equals: 'article.ecl-content-item div.ecl-content-item__meta div.ecl-u-mt-xs': "Meta 1" - 'article.ecl-content-item div.ecl-content-item__title .ecl-link': "Item title" + 'article.ecl-content-item div.ecl-content-item__title .ecl-link span.ecl-link__label': "Item title" 'article.ecl-content-item div.ecl-content-item__description': "Item..." + 'svg.ecl-icon.ecl-icon--s.ecl-link__icon' : '' - array: '#type': pattern '#id': list_item @@ -868,6 +872,8 @@ body: "Thursday 15 November, 08:00 AM to Friday 16 November" - label: "Where" body: "The EGG, Rue Barra 175, 1070 Brussels, Belgium" + icon: "check" + external_link: true assertions: count: 'article.ecl-content-item div.ecl-content-item__title a.ecl-link[href="http://example.com"]': 1 @@ -877,13 +883,14 @@ 'div.ecl-content-item__additional_information .ecl-description-list.ecl-description-list--horizontal': 1 'div.ecl-content-item__additional_information .ecl-description-list__term': 2 'div.ecl-content-item__additional_information .ecl-description-list__definition': 2 - 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 0 + 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 1 equals: - 'article.ecl-content-item div.ecl-content-item__title .ecl-link': "Item title" + 'article.ecl-content-item div.ecl-content-item__title .ecl-link span.ecl-link__label': "Item title" 'div.ecl-content-item__additional_information .ecl-description-list .ecl-description-list__term:nth-child(1)': "When" 'div.ecl-content-item__additional_information .ecl-description-list .ecl-description-list__definition:nth-child(2)': "Thursday 15 November, 08:00 AM to Friday 16 November" 'div.ecl-content-item__additional_information .ecl-description-list .ecl-description-list__term:nth-child(3)': "Where" 'div.ecl-content-item__additional_information .ecl-description-list .ecl-description-list__definition:nth-child(4)': "The EGG, Rue Barra 175, 1070 Brussels, Belgium" + 'svg.ecl-icon.ecl-icon--s.ecl-link__icon' : '' - array: '#type': pattern '#id': list_item @@ -1017,9 +1024,13 @@ '#fields': detail: "This is a very long description. Better to trim it off." length: 32 + external_link: true assertions: + count: + 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 1 equals: 'article.ecl-content-item div.ecl-content-item__description': "This is a very long description..." + 'svg.ecl-icon.ecl-icon--s.ecl-link__icon' : '' - array: '#type': pattern '#id': list_item @@ -1028,6 +1039,8 @@ detail: "This is a very long description. Better to trim it off." length: 32 assertions: + count: + 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 0 equals: 'article.ecl-content-item div.ecl-content-item__description': "This is a very long description..." - array: From 8c67e1d8b98ee508b5e51ba85521c9818db19b41 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Thu, 24 Mar 2022 19:38:53 +0200 Subject: [PATCH 03/42] EWPP-2069: Update banner hero and page patterns to render external link icon. --- .../patterns/banners/banner_hero.ui_patterns.yml | 5 +++++ .../patterns/banners/banner_page.ui_patterns.yml | 5 +++++ .../banners/pattern-banner-hero.html.twig | 4 ++-- .../banners/pattern-banner-page.html.twig | 4 ++-- tests/src/Kernel/fixtures/rendering.yml | 16 ++++++++++------ 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/templates/patterns/banners/banner_hero.ui_patterns.yml b/templates/patterns/banners/banner_hero.ui_patterns.yml index bbc56f1dc..0f01a089c 100644 --- a/templates/patterns/banners/banner_hero.ui_patterns.yml +++ b/templates/patterns/banners/banner_hero.ui_patterns.yml @@ -63,3 +63,8 @@ banner_hero: description: "Define if the banner should be extended to full width." preview: true escape: false + external_link: + type: "boolean" + label: "External link" + description: "Whether the URL of the item is external or not." + preview: false diff --git a/templates/patterns/banners/banner_page.ui_patterns.yml b/templates/patterns/banners/banner_page.ui_patterns.yml index 358310122..b73391e6f 100644 --- a/templates/patterns/banners/banner_page.ui_patterns.yml +++ b/templates/patterns/banners/banner_page.ui_patterns.yml @@ -52,3 +52,8 @@ banner_page: description: "Define if the banner should be extended to full width." preview: true escape: false + external_link: + type: "boolean" + label: "External link" + description: "Whether the URL of the item is external or not." + preview: true diff --git a/templates/patterns/banners/pattern-banner-hero.html.twig b/templates/patterns/banners/pattern-banner-hero.html.twig index ebbb81198..4b8669238 100644 --- a/templates/patterns/banners/pattern-banner-hero.html.twig +++ b/templates/patterns/banners/pattern-banner-hero.html.twig @@ -14,8 +14,8 @@ }, 'icon': { 'path': ecl_icon_path, - 'name': "corner-arrow", - 'transform': "rotate-90", + 'name': external_link ? "external" : "corner-arrow", + 'transform': external_link ? "" : "rotate-90", 'size': "xs" } } -%} diff --git a/templates/patterns/banners/pattern-banner-page.html.twig b/templates/patterns/banners/pattern-banner-page.html.twig index 61c1e2e4d..46d1905e2 100644 --- a/templates/patterns/banners/pattern-banner-page.html.twig +++ b/templates/patterns/banners/pattern-banner-page.html.twig @@ -14,8 +14,8 @@ }, 'icon': { 'path': ecl_icon_path, - 'name': "corner-arrow", - 'transform': "rotate-90", + 'name': external_link ? "external" : "corner-arrow", + 'transform': external_link ? "" : "rotate-90", 'size': "xs" } } -%} diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index 16aaf24f7..cdb12d2d2 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -165,6 +165,7 @@ 'div.ecl-container div.ecl-hero-banner__container div.ecl-hero-banner__content div.ecl-hero-banner__title': Banner title 'div.ecl-container div.ecl-hero-banner__container div.ecl-hero-banner__content p.ecl-hero-banner__description': Banner description 'a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"] span.ecl-link__label': Subscribe + 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' - array: '#type': pattern '#id': banner_hero @@ -178,16 +179,19 @@ description: "Banner description" centered: false full_width: true + external_link: true assertions: count: 'section.ecl-hero-banner.ecl-hero-banner--primary.ecl-hero-banner--full-width': 1 'div.ecl-hero-banner__content a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"]': 1 - 'svg.ecl-icon.ecl-icon--xs.ecl-icon--rotate-90.ecl-link__icon': 1 + 'svg.ecl-icon.ecl-icon--xs.ecl-icon--rotate-90.ecl-link__icon': 0 + 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': 1 'div.ecl-hero-banner__image[style="background-image:url(http://via.placeholder.com/150x150)"]': 0 equals: 'div.ecl-container div.ecl-hero-banner__container div.ecl-hero-banner__content div.ecl-hero-banner__title': Banner title 'div.ecl-container div.ecl-hero-banner__container div.ecl-hero-banner__content p.ecl-hero-banner__description': Banner description 'a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"] span.ecl-link__label': Subscribe + 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' - array: '#type': pattern '#id': banner_hero @@ -329,6 +333,7 @@ 'div.ecl-container div.ecl-page-banner__container div.ecl-page-banner__content div.ecl-page-banner__title': Banner title 'div.ecl-container div.ecl-page-banner__container div.ecl-page-banner__content p.ecl-page-banner__description': Banner description 'a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"] span.ecl-link__label': Example + 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' - array: '#type': pattern '#id': banner_page @@ -342,17 +347,20 @@ src: "http://via.placeholder.com/150x150" alignment: "left" full_width: true + external_link: true assertions: count: 'section.ecl-page-banner.ecl-page-banner--primary.ecl-page-banner--centered': 0 'section.ecl-page-banner.ecl-page-banner--primary.ecl-page-banner--full-width': 1 'div.ecl-page-banner__content a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"]': 1 - 'svg.ecl-icon.ecl-icon--xs.ecl-icon--rotate-90.ecl-link__icon': 1 + 'svg.ecl-icon.ecl-icon--xs.ecl-icon--rotate-90.ecl-link__icon': 0 + 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': 1 'div.ecl-page-banner__image[style="background-image:url(http://via.placeholder.com/150x150)"]': 0 equals: 'div.ecl-container div.ecl-page-banner__container div.ecl-page-banner__content div.ecl-page-banner__title': Banner title 'div.ecl-container div.ecl-page-banner__container div.ecl-page-banner__content p.ecl-page-banner__description': Banner description 'a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"] span.ecl-link__label': Example + 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' - array: '#type': pattern '#id': banner_page @@ -1024,13 +1032,9 @@ '#fields': detail: "This is a very long description. Better to trim it off." length: 32 - external_link: true assertions: - count: - 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 1 equals: 'article.ecl-content-item div.ecl-content-item__description': "This is a very long description..." - 'svg.ecl-icon.ecl-icon--s.ecl-link__icon' : '' - array: '#type': pattern '#id': list_item From 45e737281c8accf967fb2b49ee96e2b888a9122a Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Fri, 25 Mar 2022 14:04:25 +0200 Subject: [PATCH 04/42] EWPP-2069: Update button pattern to render external icon. --- .../banners/banner_hero.ui_patterns.yml | 2 +- .../banners/banner_page.ui_patterns.yml | 2 +- .../patterns/button/button.ui_patterns.yml | 5 ++ .../patterns/button/pattern-button.html.twig | 23 +++++---- tests/src/Kernel/fixtures/rendering.yml | 47 ++++++++++--------- 5 files changed, 45 insertions(+), 34 deletions(-) diff --git a/templates/patterns/banners/banner_hero.ui_patterns.yml b/templates/patterns/banners/banner_hero.ui_patterns.yml index 0f01a089c..bc3414ee8 100644 --- a/templates/patterns/banners/banner_hero.ui_patterns.yml +++ b/templates/patterns/banners/banner_hero.ui_patterns.yml @@ -66,5 +66,5 @@ banner_hero: external_link: type: "boolean" label: "External link" - description: "Whether the URL of the item is external or not." + description: "Whether the banner link is external or not." preview: false diff --git a/templates/patterns/banners/banner_page.ui_patterns.yml b/templates/patterns/banners/banner_page.ui_patterns.yml index b73391e6f..2917dc8bb 100644 --- a/templates/patterns/banners/banner_page.ui_patterns.yml +++ b/templates/patterns/banners/banner_page.ui_patterns.yml @@ -55,5 +55,5 @@ banner_page: external_link: type: "boolean" label: "External link" - description: "Whether the URL of the item is external or not." + description: "Whether the banner link is external or not." preview: true diff --git a/templates/patterns/button/button.ui_patterns.yml b/templates/patterns/button/button.ui_patterns.yml index 93ead62f5..8a6d0ce49 100644 --- a/templates/patterns/button/button.ui_patterns.yml +++ b/templates/patterns/button/button.ui_patterns.yml @@ -65,3 +65,8 @@ button: label: "Disabled status" description: "Define if button should be disabled." preview: false + external_link: + type: "boolean" + label: "External link" + description: "Whether button link is external or not." + preview: false diff --git a/templates/patterns/button/pattern-button.html.twig b/templates/patterns/button/pattern-button.html.twig index 139eadc3f..a629bb138 100644 --- a/templates/patterns/button/pattern-button.html.twig +++ b/templates/patterns/button/pattern-button.html.twig @@ -4,6 +4,17 @@ * Button. */ #} +{% if icon %} + {% set _icon = { + 'path': ecl_icon_path, + 'name': external_link ? 'external' : icon, + 'size': 's' + } %} +{% endif %} +{% if external_link %} + {% set icon_position = 'after' %} +{% endif %} + {% if variant == 'default' %} {% include '@ecl-twig/link' with { 'link': { @@ -12,22 +23,14 @@ 'path': href, 'icon_position': icon_position|default('after') }, - 'icon': { - 'path': ecl_icon_path, - 'name': icon, - 'size': 's' - } + 'icon': _icon } only %} {% else %} {% include '@ecl-twig/button' with { 'label': label, 'variant': variant|replace({'_':'-'}), 'type': type_attribute, - 'icon': { - 'path': ecl_icon_path, - 'name': icon, - 'size': 's' - }, + 'icon': _icon, 'icon_position': icon_position|default('after'), 'disabled': disabled } only %} diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index cdb12d2d2..f26ed7c77 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -165,7 +165,6 @@ 'div.ecl-container div.ecl-hero-banner__container div.ecl-hero-banner__content div.ecl-hero-banner__title': Banner title 'div.ecl-container div.ecl-hero-banner__container div.ecl-hero-banner__content p.ecl-hero-banner__description': Banner description 'a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"] span.ecl-link__label': Subscribe - 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' - array: '#type': pattern '#id': banner_hero @@ -179,19 +178,16 @@ description: "Banner description" centered: false full_width: true - external_link: true assertions: count: 'section.ecl-hero-banner.ecl-hero-banner--primary.ecl-hero-banner--full-width': 1 'div.ecl-hero-banner__content a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"]': 1 - 'svg.ecl-icon.ecl-icon--xs.ecl-icon--rotate-90.ecl-link__icon': 0 - 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': 1 + 'svg.ecl-icon.ecl-icon--xs.ecl-icon--rotate-90.ecl-link__icon': 1 'div.ecl-hero-banner__image[style="background-image:url(http://via.placeholder.com/150x150)"]': 0 equals: 'div.ecl-container div.ecl-hero-banner__container div.ecl-hero-banner__content div.ecl-hero-banner__title': Banner title 'div.ecl-container div.ecl-hero-banner__container div.ecl-hero-banner__content p.ecl-hero-banner__description': Banner description 'a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"] span.ecl-link__label': Subscribe - 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' - array: '#type': pattern '#id': banner_hero @@ -333,7 +329,6 @@ 'div.ecl-container div.ecl-page-banner__container div.ecl-page-banner__content div.ecl-page-banner__title': Banner title 'div.ecl-container div.ecl-page-banner__container div.ecl-page-banner__content p.ecl-page-banner__description': Banner description 'a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"] span.ecl-link__label': Example - 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' - array: '#type': pattern '#id': banner_page @@ -347,20 +342,17 @@ src: "http://via.placeholder.com/150x150" alignment: "left" full_width: true - external_link: true assertions: count: 'section.ecl-page-banner.ecl-page-banner--primary.ecl-page-banner--centered': 0 'section.ecl-page-banner.ecl-page-banner--primary.ecl-page-banner--full-width': 1 'div.ecl-page-banner__content a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"]': 1 - 'svg.ecl-icon.ecl-icon--xs.ecl-icon--rotate-90.ecl-link__icon': 0 - 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': 1 + 'svg.ecl-icon.ecl-icon--xs.ecl-icon--rotate-90.ecl-link__icon': 1 'div.ecl-page-banner__image[style="background-image:url(http://via.placeholder.com/150x150)"]': 0 equals: 'div.ecl-container div.ecl-page-banner__container div.ecl-page-banner__content div.ecl-page-banner__title': Banner title 'div.ecl-container div.ecl-page-banner__container div.ecl-page-banner__content p.ecl-page-banner__description': Banner description 'a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after[href="http://example.com"] span.ecl-link__label': Example - 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' - array: '#type': pattern '#id': banner_page @@ -834,7 +826,6 @@ 'article.ecl-content-item div.ecl-content-item__image__after': 0 'span.ecl-label.ecl-label--highlight.ecl-u-mr-xs': 1 'span.ecl-label.ecl-label--high.ecl-u-mr-xs.ecl-u-type-color-black': 1 - 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 0 equals: 'article.ecl-content-item div.ecl-content-item__meta span.ecl-label.ecl-label--highlight.ecl-u-mr-xs': "Highlighted" 'article.ecl-content-item div.ecl-content-item__meta span.ecl-label.ecl-label--high.ecl-u-mr-xs.ecl-u-type-color-black': "Status: Open" @@ -851,19 +842,16 @@ length: 6 meta: - "Meta 1" - external_link: true assertions: count: 'article.ecl-content-item div.ecl-content-item__title a.ecl-link[href="http://example.com"]': 1 'article.ecl-content-item div[role="img"].ecl-u-d-l-block': 0 'article.ecl-content-item div.ecl-content-item__image__before': 0 'article.ecl-content-item div.ecl-content-item__image__after': 0 - 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 1 equals: 'article.ecl-content-item div.ecl-content-item__meta div.ecl-u-mt-xs': "Meta 1" - 'article.ecl-content-item div.ecl-content-item__title .ecl-link span.ecl-link__label': "Item title" + 'article.ecl-content-item div.ecl-content-item__title .ecl-link': "Item title" 'article.ecl-content-item div.ecl-content-item__description': "Item..." - 'svg.ecl-icon.ecl-icon--s.ecl-link__icon' : '' - array: '#type': pattern '#id': list_item @@ -880,8 +868,6 @@ body: "Thursday 15 November, 08:00 AM to Friday 16 November" - label: "Where" body: "The EGG, Rue Barra 175, 1070 Brussels, Belgium" - icon: "check" - external_link: true assertions: count: 'article.ecl-content-item div.ecl-content-item__title a.ecl-link[href="http://example.com"]': 1 @@ -891,14 +877,13 @@ 'div.ecl-content-item__additional_information .ecl-description-list.ecl-description-list--horizontal': 1 'div.ecl-content-item__additional_information .ecl-description-list__term': 2 'div.ecl-content-item__additional_information .ecl-description-list__definition': 2 - 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 1 + 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 0 equals: - 'article.ecl-content-item div.ecl-content-item__title .ecl-link span.ecl-link__label': "Item title" + 'article.ecl-content-item div.ecl-content-item__title .ecl-link': "Item title" 'div.ecl-content-item__additional_information .ecl-description-list .ecl-description-list__term:nth-child(1)': "When" 'div.ecl-content-item__additional_information .ecl-description-list .ecl-description-list__definition:nth-child(2)': "Thursday 15 November, 08:00 AM to Friday 16 November" 'div.ecl-content-item__additional_information .ecl-description-list .ecl-description-list__term:nth-child(3)': "Where" 'div.ecl-content-item__additional_information .ecl-description-list .ecl-description-list__definition:nth-child(4)': "The EGG, Rue Barra 175, 1070 Brussels, Belgium" - 'svg.ecl-icon.ecl-icon--s.ecl-link__icon' : '' - array: '#type': pattern '#id': list_item @@ -1043,8 +1028,6 @@ detail: "This is a very long description. Better to trim it off." length: 32 assertions: - count: - 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': 0 equals: 'article.ecl-content-item div.ecl-content-item__description': "This is a very long description..." - array: @@ -2011,6 +1994,25 @@ 'a.ecl-link--icon-before svg': 1 equals: 'a.ecl-link--standalone[href="http://example.com"] .ecl-link__label': "Button label" + 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': '' +- array: + '#type': pattern + '#id': button + '#variant': default + '#fields': + label: "Button label" + href: "http://example.com" + icon: "caret-right" + icon_position: "before" + type_attribute: "default" + external_link: true + assertions: + count: + 'a.ecl-link--icon-after svg': 1 + 'a.ecl-link--icon-before svg': 0 + equals: + 'a.ecl-link--standalone[href="http://example.com"] .ecl-link__label': "Button label" + 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': '' - array: '#type': pattern '#id': button @@ -2019,6 +2021,7 @@ label: "Button label" href: "http://example.com" type_attribute: "standalone" + external_link: true assertions: count: 'a.ecl-link--standalone': 1 From 0dc3574c665ec280b2e4758fa7ac081e1e1c0814 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Fri, 25 Mar 2022 15:15:22 +0200 Subject: [PATCH 05/42] EWPP-2069: Update featured item extended variant to render external icon. --- .../featured_item.ui_patterns.yml | 5 ++++ .../pattern-featured-item.html.twig | 4 ++-- tests/src/Kernel/fixtures/rendering.yml | 24 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/templates/patterns/featured_item/featured_item.ui_patterns.yml b/templates/patterns/featured_item/featured_item.ui_patterns.yml index a7f713cca..22ff4a57e 100644 --- a/templates/patterns/featured_item/featured_item.ui_patterns.yml +++ b/templates/patterns/featured_item/featured_item.ui_patterns.yml @@ -67,3 +67,8 @@ featured_item: variant: "highlight" - label: "Status: Open" variant: "high" + external_link: + type: "boolean" + label: "External link" + description: "Whether item's link is external or not." + preview: false diff --git a/templates/patterns/featured_item/pattern-featured-item.html.twig b/templates/patterns/featured_item/pattern-featured-item.html.twig index 8440cb981..c9f6a38c7 100644 --- a/templates/patterns/featured_item/pattern-featured-item.html.twig +++ b/templates/patterns/featured_item/pattern-featured-item.html.twig @@ -22,9 +22,9 @@ {% include '@ecl-twig/icon' with { icon: { path: ecl_icon_path, - name: "corner-arrow", + name: external_link ? "external" : "corner-arrow", size: "xs", - transform: "rotate-90" + transform: external_link ? "" : "rotate-90" }, extra_classes: "ecl-button__icon ecl-button__icon--after" } only %} diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index f26ed7c77..126b5a45e 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -2318,10 +2318,34 @@ "div.ecl-card__image": 0 'h1.ecl-card__title a.ecl-link--standalone[href="https://example.com"]': 1 'a.ecl-button[href="https://example.com"]': 1 + 'svg.ecl-icon.ecl-icon--xs.ecl-icon--rotate-90.ecl-button__icon.ecl-button__icon--after': 1 equals: 'h1.ecl-card__title a': "Example title" 'div.ecl-card__description .ecl-paragraph': "Example description" 'a.ecl-button .ecl-button__label': "Link title" + 'svg.ecl-icon.ecl-icon--xs.ecl-button__icon.ecl-button__icon--after': '' +- array: + '#type': pattern + '#id': featured_item + '#variant': "extended" + '#fields': + title: "Example title" + description: "Example description" + link: + href: "https://example.com" + label: "Link title" + external_link: true + assertions: + count: + "div.ecl-card__image": 0 + 'h1.ecl-card__title a.ecl-link--standalone[href="https://example.com"]': 1 + 'a.ecl-button[href="https://example.com"]': 1 + 'svg.ecl-icon.ecl-icon--xs.ecl-button__icon.ecl-button__icon--after': 1 + equals: + 'h1.ecl-card__title a': "Example title" + 'div.ecl-card__description .ecl-paragraph': "Example description" + 'a.ecl-button .ecl-button__label': "Link title" + 'svg.ecl-icon.ecl-icon--xs.ecl-button__icon.ecl-button__icon--after': '' - array: '#type': pattern '#id': featured_item From 4fb7604ed131749159504565d10c0b7b19bdac42 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Fri, 25 Mar 2022 15:53:21 +0200 Subject: [PATCH 06/42] EWPP-2069: Render external icon in link block pattern. --- templates/patterns/link_block/link_block.ui_patterns.yml | 2 ++ .../patterns/link_block/pattern-link-block.html.twig | 9 +++++++++ tests/src/Kernel/fixtures/rendering.yml | 9 +++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/templates/patterns/link_block/link_block.ui_patterns.yml b/templates/patterns/link_block/link_block.ui_patterns.yml index 6ace2971d..bd78ce444 100644 --- a/templates/patterns/link_block/link_block.ui_patterns.yml +++ b/templates/patterns/link_block/link_block.ui_patterns.yml @@ -14,7 +14,9 @@ link_block: preview: - label: 'European Commission' url: 'http://link-1.com' + is_external: true - label: 'Priorities' url: 'http://link-2.com' - label: 'Jobs, Growth and Investment' url: 'http://link-3.com' + is_external: true diff --git a/templates/patterns/link_block/pattern-link-block.html.twig b/templates/patterns/link_block/pattern-link-block.html.twig index e4ff6a1c2..624af293d 100644 --- a/templates/patterns/link_block/pattern-link-block.html.twig +++ b/templates/patterns/link_block/pattern-link-block.html.twig @@ -14,6 +14,15 @@ type: 'standalone' } } %} + {% if link.is_external %} + {% set _link = _link|merge({ + 'icon': { + 'path': ecl_icon_path, + 'name': "external", + 'size': "xs" + } + }) %} + {% endif %} {% set _links = _links|merge([_link]) %} {% endfor %} diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index 126b5a45e..4c4ec7489 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -1881,8 +1881,10 @@ links: - label: 'Link 1' url: 'http://link-1.com' + is_external: true - label: 'Link 2' url: 'http://link-2.com' + is_external: true - label: 'Link 3' url: 'http://link-3.com' assertions: @@ -1892,10 +1894,13 @@ 'a.ecl-link-block__link[href="http://link-1.com"]': 1 'a.ecl-link-block__link[href="http://link-2.com"]': 1 'a.ecl-link-block__link[href="http://link-3.com"]': 1 + 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': 2 equals: '.ecl-link-block__title h5': "Link block title" - '.ecl-link-block__list .ecl-link-block__item:nth-child(1) .ecl-link': "Link 1" - '.ecl-link-block__list .ecl-link-block__item:nth-child(2) .ecl-link': "Link 2" + '.ecl-link-block__list .ecl-link-block__item:nth-child(1) .ecl-link .ecl-link__label': "Link 1" + '.ecl-link-block__list .ecl-link-block__item:nth-child(1) .ecl-link svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' + '.ecl-link-block__list .ecl-link-block__item:nth-child(2) .ecl-link .ecl-link__label': "Link 2" + '.ecl-link-block__list .ecl-link-block__item:nth-child(2) .ecl-link svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' '.ecl-link-block__list .ecl-link-block__item:nth-child(3) .ecl-link': "Link 3" - array: '#type': pattern From 7d58091d7955ab98d7063028f73d525ae59fea50 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Fri, 25 Mar 2022 17:52:18 +0200 Subject: [PATCH 07/42] EWPP-2069: Adapt twig function to consider links under europa.eu domain as internal. --- .../oe_theme_helper/src/TwigExtension/TwigExtension.php | 2 +- .../fixtures/patterns/organisation_teaser_rendering.yml | 7 +++++++ tests/src/Kernel/fixtures/rendering.yml | 8 ++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php b/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php index 5f8ea0f2a..d4b51cf60 100644 --- a/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php +++ b/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php @@ -535,7 +535,7 @@ public function getLinkIcon(array $context, string $path, string $size = 's'): a 'size' => $size, 'color' => 'primary', ]; - if (UrlHelper::isExternal($path)) { + if (UrlHelper::isExternal($path) && !str_contains($path, 'europa.eu')) { $icon['name'] = 'external'; } else { diff --git a/tests/src/Kernel/fixtures/patterns/organisation_teaser_rendering.yml b/tests/src/Kernel/fixtures/patterns/organisation_teaser_rendering.yml index cfadf73c9..76b6efa3d 100644 --- a/tests/src/Kernel/fixtures/patterns/organisation_teaser_rendering.yml +++ b/tests/src/Kernel/fixtures/patterns/organisation_teaser_rendering.yml @@ -63,3 +63,10 @@ a.ecl-link[href="mailto:me@example.com"]: 1 equals: a.ecl-link svg.ecl-icon: '' +- fields: + contact_page_url: "https://european-union.europa.eu/index_en" + assertions: + count: + a.ecl-link[href="https://european-union.europa.eu/index_en"]: 1 + equals: + a.ecl-link svg.ecl-icon: '' diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index 4c4ec7489..7384cd4e4 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -2598,12 +2598,14 @@ 'div.ecl-media-container__media--ratio-16-9 iframe': 0 'figcaption.ecl-media-container__caption': 1 'a.ecl-link.ecl-link--standalone[href="http://example.com"]': 1 + 'svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon': 1 equals: 'div.ecl-featured-item__heading': "Heading" 'div.ecl-featured-item__title': "Title" 'figcaption.ecl-media-container__caption': "Some caption text for the image" 'div.ecl-featured-item__item > div.ecl': "Some more text" 'a.ecl-link span.ecl-link__label': "Call to action" + 'svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon': '' - array: '#type': pattern '#id': text_featured_media @@ -2616,7 +2618,7 @@ text: "Some more text" link: label: "Call to action" - path: "http://example.com" + path: "https://european-union.europa.eu/index_en" highlighted: true assertions: count: @@ -2630,12 +2632,14 @@ 'img.ecl-media-container__media[src="http://via.placeholder.com/150x150"]': 1 'div.ecl-media-container__media--ratio-16-9 iframe': 0 'figcaption.ecl-media-container__caption': 1 - 'a.ecl-link.ecl-link--standalone[href="http://example.com"]': 1 + 'a.ecl-link.ecl-link--standalone[href="https://european-union.europa.eu/index_en"]': 1 + 'svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon': 1 equals: 'div.ecl-featured-item__title': "Title" 'figcaption.ecl-media-container__caption': "Some caption text for the image" 'div.ecl-featured-item__item > div.ecl': "Some more text" 'a.ecl-link span.ecl-link__label': "Call to action" + 'svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon': '' - array: '#type': pattern '#id': text_featured_media From f1de13a1cc55de29b799547b38bb78b208a9000f Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Mon, 28 Mar 2022 15:24:18 +0300 Subject: [PATCH 08/42] EWPP-2069: Adapt banner paragraph preprocess and template. --- oe_theme.theme | 8 ++++++-- templates/paragraphs/paragraph--oe-banner.html.twig | 1 + tests/src/Kernel/Paragraphs/MediaParagraphsTest.php | 8 +++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/oe_theme.theme b/oe_theme.theme index 337138be6..a774e964e 100644 --- a/oe_theme.theme +++ b/oe_theme.theme @@ -213,9 +213,11 @@ function oe_theme_theme_suggestions_paragraph_alter(array &$suggestions, array $ function oe_theme_preprocess_paragraph__oe_links_block(array &$variables): void { // Massage data to be compliant with ECL links block component data structure. foreach (Element::children($variables['content']['field_oe_links']) as $index) { + $url = $variables['content']['field_oe_links'][$index]['#url']; $variables['links'][] = [ 'label' => $variables['content']['field_oe_links'][$index]['#title'], - 'url' => $variables['content']['field_oe_links'][$index]['#url'], + 'url' => $url, + 'is_external' => ($url->isExternal() && !str_contains($url->getUri(), 'europa.eu')), ]; } } @@ -1496,7 +1498,9 @@ function oe_theme_preprocess_paragraph__oe_banner(array &$variables): void { $link = $paragraph->get('field_oe_link')->first(); $variables['url'] = $link->getUrl(); $variables['label'] = $link->get('title')->getValue(); - ; + if ($link->getUrl()->isExternal() && !str_contains($link->getUrl()->getUri(), 'europa.eu')) { + $variables['external_link'] = TRUE; + } } $variables['full_width'] = (bool) $paragraph->get('field_oe_banner_full_width')->value; diff --git a/templates/paragraphs/paragraph--oe-banner.html.twig b/templates/paragraphs/paragraph--oe-banner.html.twig index a316b9f0e..d4f1b0bf7 100644 --- a/templates/paragraphs/paragraph--oe-banner.html.twig +++ b/templates/paragraphs/paragraph--oe-banner.html.twig @@ -15,4 +15,5 @@ 'image': image, 'alignment': alignment, 'full_width': full_width, + 'external_link': external_link|default(false) }) }} diff --git a/tests/src/Kernel/Paragraphs/MediaParagraphsTest.php b/tests/src/Kernel/Paragraphs/MediaParagraphsTest.php index e83bb750e..15ef6176a 100644 --- a/tests/src/Kernel/Paragraphs/MediaParagraphsTest.php +++ b/tests/src/Kernel/Paragraphs/MediaParagraphsTest.php @@ -433,7 +433,7 @@ public function testBanner(): void { 'field_oe_title' => 'Banner', 'field_oe_text' => 'Description', 'field_oe_link' => [ - 'uri' => 'http://www.example.com/', + 'uri' => 'https://european-union.europa.eu/index_en', 'title' => 'Example', ], 'field_oe_media' => [ @@ -461,6 +461,7 @@ public function testBanner(): void { $this->assertEquals('Banner', trim($crawler->filter('div.ecl-hero-banner__content div.ecl-hero-banner__title')->text())); $this->assertEquals('Description', trim($crawler->filter('div.ecl-hero-banner__content p.ecl-hero-banner__description')->text())); $this->assertCount(1, $crawler->filter('div.ecl-hero-banner__content a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after')); + $this->assertEquals('', $crawler->filter('svg.ecl-icon.ecl-icon--xs.ecl-link__icon')->html()); $this->assertStringContainsString('Example', trim($crawler->filter('div.ecl-hero-banner__content a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after span.ecl-link__label')->text())); $this->assertCount(0, $crawler->filter('.ecl-hero-banner--full-width')); @@ -476,6 +477,10 @@ public function testBanner(): void { // Variant - image / Modifier - hero_left / Full width - No. $paragraph->get('field_oe_banner_type')->setValue('hero_left'); + $paragraph->set('field_oe_link', [ + 'uri' => 'https://example.com', + 'title' => 'Example', + ]); $paragraph->save(); // Unpublish the media and assert it is not rendered anymore. @@ -489,6 +494,7 @@ public function testBanner(): void { $html = $this->renderParagraph($paragraph); $crawler = new Crawler($html); $this->assertCount(0, $crawler->filter('section.ecl-hero-banner.ecl-hero-banner--image div.ecl-hero-banner__image')); + $this->assertEquals('', $crawler->filter('svg.ecl-icon.ecl-icon--xs.ecl-link__icon')->html()); // Publish the media. $media->set('status', 1); From 2542be0abae753bccac10efd7f78bc8262047a72 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Tue, 29 Mar 2022 10:33:30 +0300 Subject: [PATCH 09/42] EWPP-2069: Make sure the europa.eu is not part of the url domain. --- .../oe_theme_helper/src/TwigExtension/TwigExtension.php | 2 +- oe_theme.theme | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php b/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php index d4b51cf60..45193a538 100644 --- a/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php +++ b/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php @@ -535,7 +535,7 @@ public function getLinkIcon(array $context, string $path, string $size = 's'): a 'size' => $size, 'color' => 'primary', ]; - if (UrlHelper::isExternal($path) && !str_contains($path, 'europa.eu')) { + if (UrlHelper::isExternal($path) && !strpos(UrlHelper::parse($path)['path'], 'europa.eu')) { $icon['name'] = 'external'; } else { diff --git a/oe_theme.theme b/oe_theme.theme index a774e964e..da83f7b04 100644 --- a/oe_theme.theme +++ b/oe_theme.theme @@ -217,7 +217,7 @@ function oe_theme_preprocess_paragraph__oe_links_block(array &$variables): void $variables['links'][] = [ 'label' => $variables['content']['field_oe_links'][$index]['#title'], 'url' => $url, - 'is_external' => ($url->isExternal() && !str_contains($url->getUri(), 'europa.eu')), + 'is_external' => ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')), ]; } } @@ -1496,9 +1496,10 @@ function oe_theme_preprocess_paragraph__oe_banner(array &$variables): void { if (!$paragraph->get('field_oe_link')->isEmpty()) { $link = $paragraph->get('field_oe_link')->first(); - $variables['url'] = $link->getUrl(); + $url = $link->getUrl(); + $variables['url'] = $url; $variables['label'] = $link->get('title')->getValue(); - if ($link->getUrl()->isExternal() && !str_contains($link->getUrl()->getUri(), 'europa.eu')) { + if ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')) { $variables['external_link'] = TRUE; } } From 4ce390fc3fc42f3009bfbf7a2deb45c9db64a956 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Tue, 29 Mar 2022 12:16:54 +0300 Subject: [PATCH 10/42] EWPP-2069: Update link patterns and their related paragraphs. --- oe_theme.theme | 26 ++++++--- .../navigation-list.html.twig | 54 +++++++++++++++++-- .../paragraph--oe-list-item-block.html.twig | 3 +- .../paragraph--oe-list-item.html.twig | 3 +- templates/patterns/link/link.ui_patterns.yml | 5 ++ .../patterns/link/pattern-link.html.twig | 22 +++++++- .../pattern-list-item--variant-date.html.twig | 16 ++++-- ...st_item_block_four_columns.ui_patterns.yml | 7 ++- ...list_item_block_one_column.ui_patterns.yml | 5 ++ ...ist_item_block_six_columns.ui_patterns.yml | 11 ++-- ...t_item_block_three_columns.ui_patterns.yml | 5 ++ ...ist_item_block_two_columns.ui_patterns.yml | 5 ++ ...ern-list-item-block-four-columns.html.twig | 4 ++ ...ttern-list-item-block-one-column.html.twig | 4 ++ ...tern-list-item-block-six-columns.html.twig | 4 ++ ...rn-list-item-block-three-columns.html.twig | 4 ++ ...tern-list-item-block-two-columns.html.twig | 4 ++ .../navigation_list.ui_patterns.yml | 8 +++ .../pattern-navigation-list.html.twig | 8 ++- .../src/Kernel/Paragraphs/ParagraphsTest.php | 7 +++ .../Patterns/LinkPatternRenderingTest.php | 27 ++++++++-- tests/src/Kernel/fixtures/rendering.yml | 27 +++++++--- 22 files changed, 227 insertions(+), 32 deletions(-) diff --git a/oe_theme.theme b/oe_theme.theme index da83f7b04..9a8773442 100644 --- a/oe_theme.theme +++ b/oe_theme.theme @@ -806,7 +806,11 @@ function oe_theme_preprocess_paragraph__oe_list_item(array &$variables): void { $list_item_variant = $paragraph->get('oe_paragraphs_variant')->first()->value; $variables['variant'] = $list_item_variant ?? 'default'; - $variables['url'] = $paragraph->get('field_oe_link')->first()->getUrl(); + $url = $paragraph->get('field_oe_link')->first()->getUrl(); + $variables['url'] = $url; + if ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')) { + $variables['external_link'] = TRUE; + } $cacheability = CacheableMetadata::createFromRenderArray($variables); @@ -869,8 +873,12 @@ function oe_theme_preprocess_paragraph__oe_list_item_block(array &$variables): v /** @var \Drupal\link\Plugin\Field\FieldType\LinkItem $link_item */ $link_item = $paragraph->get('field_oe_link')->first(); - $variables['button_url'] = $link_item->getUrl(); + $url = $link_item->getUrl(); + $variables['button_url'] = $url; $variables['button_label'] = $link_item->get('title')->getValue(); + if ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')) { + $variables['external_link'] = TRUE; + } } /** @@ -1417,11 +1425,17 @@ function oe_theme_preprocess_pattern_link(array &$variables): void { // Extract attributes from the URL object and set them as default. if ($variables['url'] instanceof Url) { $attributes = (array) $variables['url']->getOption('attributes'); + if (isset($attributes['class'])) { + $variables['classes'] = implode(' ', $attributes['class']); + unset($attributes['class']); + } + foreach ($attributes as $name => $value) { + $variables['extra_attributes'][] = [ + 'name' => $name, + 'value' => $value, + ]; + } } - - // Add ECL link classes to attributes. - $variables['attributes'] = new Attribute($attributes); - $variables['attributes']->addClass('ecl-link', 'ecl-link--' . $variables['variant']); } /** diff --git a/templates/compositions/ec-component-navigation-list/navigation-list.html.twig b/templates/compositions/ec-component-navigation-list/navigation-list.html.twig index 224b59ccc..d651eb79b 100644 --- a/templates/compositions/ec-component-navigation-list/navigation-list.html.twig +++ b/templates/compositions/ec-component-navigation-list/navigation-list.html.twig @@ -17,13 +17,23 @@

{% if title_url %} - {% include '@ecl-twig/link' with { + {% set _link = { 'link': { 'type': 'standalone', 'label': title, 'path': title_url } - } only %} + } %} + {% if external_link %} + {% set _link = _link|merge({ + icon: { + 'path': icon_path, + 'name': 'external', + 'size': 's', + } + }) %} + {% endif %} + {% include '@ecl-twig/link' with _link only %} {% else %} {{ title }} {% endif %} @@ -38,7 +48,23 @@ {% for link in links %}
  • {% if link.link.path %} - {% include '@ecl-twig/link' with { link: link.link|merge({type: 'standalone'}) } only %} + {% set _link = { + 'link': { + 'type': 'standalone', + 'label': link.link.label, + 'path': link.link.path + } + } %} + {% if link.link.is_external %} + {% set _link = _link|merge({ + icon: { + 'path': icon_path, + 'name': 'external', + 'size': 'xs', + } + }) %} + {% endif %} + {% include '@ecl-twig/link' with _link only %} {% else %} {{ link.link.label }} {% endif %} @@ -51,7 +77,27 @@
      {% for link in secondary_links %}
    • - {% include '@ecl-twig/link' with { link: link.link|merge({type: 'standalone'}) } only %} + {% if link.link.path %} + {% set _link = { + 'link': { + 'type': 'standalone', + 'label': link.link.label, + 'path': link.link.path + } + } %} + {% if link.link.is_external %} + {% set _link = _link|merge({ + icon: { + 'path': icon_path, + 'name': 'external', + 'size': 'xs', + } + }) %} + {% endif %} + {% include '@ecl-twig/link' with _link only %} + {% else %} + {{ link.link.label }} + {% endif %}
    • {% endfor %}
    diff --git a/templates/paragraphs/paragraph--oe-list-item-block.html.twig b/templates/paragraphs/paragraph--oe-list-item-block.html.twig index 9e66e994e..563015279 100644 --- a/templates/paragraphs/paragraph--oe-list-item-block.html.twig +++ b/templates/paragraphs/paragraph--oe-list-item-block.html.twig @@ -10,5 +10,6 @@ 'title': content.field_oe_title, 'items': items, 'button_url': button_url, - 'button_label': button_label + 'button_label': button_label, + 'external_link': external_link|default(false) }) }} diff --git a/templates/paragraphs/paragraph--oe-list-item.html.twig b/templates/paragraphs/paragraph--oe-list-item.html.twig index f69e161b8..b1b0670c0 100644 --- a/templates/paragraphs/paragraph--oe-list-item.html.twig +++ b/templates/paragraphs/paragraph--oe-list-item.html.twig @@ -14,5 +14,6 @@ 'meta': meta, 'date': date, 'image': image, - 'secondary_image': image + 'secondary_image': image, + 'external_link': external_link|default(false) }) }} diff --git a/templates/patterns/link/link.ui_patterns.yml b/templates/patterns/link/link.ui_patterns.yml index aac9e9ba3..f25f97040 100644 --- a/templates/patterns/link/link.ui_patterns.yml +++ b/templates/patterns/link/link.ui_patterns.yml @@ -20,3 +20,8 @@ link: description: 'A Drupal URL object. Strings will be passed to Url::fromUserInput().' preview: '#' escape: true + external_link: + type: "boolean" + label: "External link" + description: "Whether the URL is external or not." + preview: true diff --git a/templates/patterns/link/pattern-link.html.twig b/templates/patterns/link/pattern-link.html.twig index 9349888ad..b3c7cf2a9 100644 --- a/templates/patterns/link/pattern-link.html.twig +++ b/templates/patterns/link/pattern-link.html.twig @@ -4,4 +4,24 @@ * Link pattern. */ #} -{{ link(text, url, attributes) }} +{% set _link = { + link: { + type: variant|default('standalone'), + label: text, + path: url, + }, + extra_attributes: extra_attributes, + extra_classes: classes +} %} +{% if external_link %} + {% set _link = _link|merge({ + icon: { + 'path': ecl_icon_path, + 'name': 'external', + 'size': 's', + } + }) %} +{% endif %} +{% apply spaceless %} + {%- include '@ecl-twig/link' with _link only -%} +{% endapply %} diff --git a/templates/patterns/list_item/pattern-list-item--variant-date.html.twig b/templates/patterns/list_item/pattern-list-item--variant-date.html.twig index c408b657a..180d32292 100644 --- a/templates/patterns/list_item/pattern-list-item--variant-date.html.twig +++ b/templates/patterns/list_item/pattern-list-item--variant-date.html.twig @@ -54,13 +54,23 @@ {% block title %}
    {%- if url %} - {% include '@ecl-twig/link' with { + {% set _link = { link: { type: 'standalone', label: title, - path: url + path: url, } - } only %} + } %} + {% if external_link %} + {% set _link = _link|merge({ + icon: { + 'path': ecl_icon_path, + 'name': 'external', + 'size': 's', + } + }) %} + {% endif %} + {% include '@ecl-twig/link' with _link only %} {% else %} {{ title }} {%- endif -%} diff --git a/templates/patterns/list_item_blocks/list_item_block_four_columns.ui_patterns.yml b/templates/patterns/list_item_blocks/list_item_block_four_columns.ui_patterns.yml index 70ccfe7da..6cfaacf96 100644 --- a/templates/patterns/list_item_blocks/list_item_block_four_columns.ui_patterns.yml +++ b/templates/patterns/list_item_blocks/list_item_block_four_columns.ui_patterns.yml @@ -71,4 +71,9 @@ list_item_block_four_columns: type: "text" label: "Icon position" description: "The position of the icon" - preview: 'after' + preview: 'before' + external_link: + type: "boolean" + label: "External link" + description: "Whether the Button URL is external or not." + preview: false diff --git a/templates/patterns/list_item_blocks/list_item_block_one_column.ui_patterns.yml b/templates/patterns/list_item_blocks/list_item_block_one_column.ui_patterns.yml index 137365d52..9f4caa842 100644 --- a/templates/patterns/list_item_blocks/list_item_block_one_column.ui_patterns.yml +++ b/templates/patterns/list_item_blocks/list_item_block_one_column.ui_patterns.yml @@ -47,3 +47,8 @@ list_item_block_one_column: label: "Icon position" description: "The position of the icon" preview: 'after' + external_link: + type: "boolean" + label: "External link" + description: "Whether the Button URL is external or not." + preview: true diff --git a/templates/patterns/list_item_blocks/list_item_block_six_columns.ui_patterns.yml b/templates/patterns/list_item_blocks/list_item_block_six_columns.ui_patterns.yml index 0c021dd81..4db480949 100644 --- a/templates/patterns/list_item_blocks/list_item_block_six_columns.ui_patterns.yml +++ b/templates/patterns/list_item_blocks/list_item_block_six_columns.ui_patterns.yml @@ -12,16 +12,16 @@ list_item_block_six_columns: label: "Layout items" description: "Array of renderable items" preview: - - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 1' } } + - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 1', external_link: true } } - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 2' } } - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 3' } } - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 4' } } - - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 5' } } + - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 5', external_link: true } } - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 6' } } - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 7' } } - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 8' } } - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 9' } } - - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 10' } } + - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 10', external_link: true } } - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 11' } } - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 12' } } - { type: 'pattern', id: 'link', fields: { url: '#', text: 'A simple link 13' } } @@ -49,3 +49,8 @@ list_item_block_six_columns: label: "Icon position" description: "The position of the icon" preview: 'after' + external_link: + type: "boolean" + label: "External link" + description: "Whether the Button URL is external or not." + preview: true diff --git a/templates/patterns/list_item_blocks/list_item_block_three_columns.ui_patterns.yml b/templates/patterns/list_item_blocks/list_item_block_three_columns.ui_patterns.yml index ead44a296..b54db223b 100644 --- a/templates/patterns/list_item_blocks/list_item_block_three_columns.ui_patterns.yml +++ b/templates/patterns/list_item_blocks/list_item_block_three_columns.ui_patterns.yml @@ -62,3 +62,8 @@ list_item_block_three_columns: label: "Icon position" description: "The position of the icon" preview: 'after' + external_link: + type: "boolean" + label: "External link" + description: "Whether the Button URL is external or not." + preview: true diff --git a/templates/patterns/list_item_blocks/list_item_block_two_columns.ui_patterns.yml b/templates/patterns/list_item_blocks/list_item_block_two_columns.ui_patterns.yml index 2d59c4f7d..14bf458dd 100644 --- a/templates/patterns/list_item_blocks/list_item_block_two_columns.ui_patterns.yml +++ b/templates/patterns/list_item_blocks/list_item_block_two_columns.ui_patterns.yml @@ -52,3 +52,8 @@ list_item_block_two_columns: label: "Icon position" description: "The position of the icon" preview: 'after' + external_link: + type: "boolean" + label: "External link" + description: "Whether the Button URL is external or not." + preview: false diff --git a/templates/patterns/list_item_blocks/pattern-list-item-block-four-columns.html.twig b/templates/patterns/list_item_blocks/pattern-list-item-block-four-columns.html.twig index 79255dd1a..b1fcec992 100644 --- a/templates/patterns/list_item_blocks/pattern-list-item-block-four-columns.html.twig +++ b/templates/patterns/list_item_blocks/pattern-list-item-block-four-columns.html.twig @@ -5,6 +5,10 @@ */ #} {% set _button_icon_position = button_icon_position|default('after') %} +{% if external_link %} + {% set button_icon_name = 'external' %} + {% set _button_icon_position = 'after' %} +{% endif %} {% include '@oe_theme/compositions/ec-component-content-item-block/content-item-block.html.twig' with { type: 'four', title: title, diff --git a/templates/patterns/list_item_blocks/pattern-list-item-block-one-column.html.twig b/templates/patterns/list_item_blocks/pattern-list-item-block-one-column.html.twig index 0cb86d4f1..9629b648a 100644 --- a/templates/patterns/list_item_blocks/pattern-list-item-block-one-column.html.twig +++ b/templates/patterns/list_item_blocks/pattern-list-item-block-one-column.html.twig @@ -5,6 +5,10 @@ */ #} {% set _button_icon_position = button_icon_position|default('after') %} +{% if external_link %} + {% set button_icon_name = 'external' %} + {% set _button_icon_position = 'after' %} +{% endif %} {% include '@oe_theme/compositions/ec-component-content-item-block/content-item-block.html.twig' with { type: 'one', title: title, diff --git a/templates/patterns/list_item_blocks/pattern-list-item-block-six-columns.html.twig b/templates/patterns/list_item_blocks/pattern-list-item-block-six-columns.html.twig index 475a07d15..d2113890b 100644 --- a/templates/patterns/list_item_blocks/pattern-list-item-block-six-columns.html.twig +++ b/templates/patterns/list_item_blocks/pattern-list-item-block-six-columns.html.twig @@ -5,6 +5,10 @@ */ #} {% set _button_icon_position = button_icon_position|default('after') %} +{% if external_link %} + {% set button_icon_name = 'external' %} + {% set _button_icon_position = 'after' %} +{% endif %} {% include '@oe_theme/compositions/ec-component-content-item-block/content-item-block.html.twig' with { type: 'six', title: title, diff --git a/templates/patterns/list_item_blocks/pattern-list-item-block-three-columns.html.twig b/templates/patterns/list_item_blocks/pattern-list-item-block-three-columns.html.twig index e3f3809f1..00dbcffe9 100644 --- a/templates/patterns/list_item_blocks/pattern-list-item-block-three-columns.html.twig +++ b/templates/patterns/list_item_blocks/pattern-list-item-block-three-columns.html.twig @@ -5,6 +5,10 @@ */ #} {% set _button_icon_position = button_icon_position|default('after') %} +{% if external_link %} + {% set button_icon_name = 'external' %} + {% set _button_icon_position = 'after' %} +{% endif %} {% include '@oe_theme/compositions/ec-component-content-item-block/content-item-block.html.twig' with { type: 'three', title: title, diff --git a/templates/patterns/list_item_blocks/pattern-list-item-block-two-columns.html.twig b/templates/patterns/list_item_blocks/pattern-list-item-block-two-columns.html.twig index ae01a2e80..0c555b1b7 100644 --- a/templates/patterns/list_item_blocks/pattern-list-item-block-two-columns.html.twig +++ b/templates/patterns/list_item_blocks/pattern-list-item-block-two-columns.html.twig @@ -5,6 +5,10 @@ */ #} {% set _button_icon_position = button_icon_position|default('after') %} +{% if external_link %} + {% set button_icon_name = 'external' %} + {% set _button_icon_position = 'after' %} +{% endif %} {% include '@oe_theme/compositions/ec-component-content-item-block/content-item-block.html.twig' with { type: 'two', title: title, diff --git a/templates/patterns/navigation_list/navigation_list.ui_patterns.yml b/templates/patterns/navigation_list/navigation_list.ui_patterns.yml index fbd6a91f8..454a5291a 100644 --- a/templates/patterns/navigation_list/navigation_list.ui_patterns.yml +++ b/templates/patterns/navigation_list/navigation_list.ui_patterns.yml @@ -12,6 +12,11 @@ navigation_list: label: "Title URL" description: "URL to link the title of the navigation list." preview: "https://ec.europa.eu/info/education/policy-educational-issues_en" + external_link: + type: "boolean" + label: "External link" + description: "Whether the title URL is external or not." + preview: true description: type: "text" label: "Description" @@ -24,10 +29,12 @@ navigation_list: preview: - label: 'Addressing shared challenges' url: 'https://ec.europa.eu/info/education/policy-educational-issues/shared-challenges-education-and-training_en' + is_external: true - label: 'Setting objectives and measuring progress' url: 'https://ec.europa.eu/info/education/policy-educational-issues/setting-objectives-and-measuring-progress_en' - label: 'International cooperation' url: 'https://ec.europa.eu/info/education/policy-educational-issues/international-cooperation_en' + is_external: true secondary_links: type: "array" label: "Secondary Links" @@ -37,3 +44,4 @@ navigation_list: url: 'https://ec.europa.eu/info/education/policy-educational-issues/shared-challenges-education-and-training/integrating-migrants-and-refugees_en' - label: 'Early school leaving' url: 'https://ec.europa.eu/info/education/policy-educational-issues/shared-challenges-education-and-training/early-school-leaving_en' + is_external: true diff --git a/templates/patterns/navigation_list/pattern-navigation-list.html.twig b/templates/patterns/navigation_list/pattern-navigation-list.html.twig index 7b268919d..728487e19 100644 --- a/templates/patterns/navigation_list/pattern-navigation-list.html.twig +++ b/templates/patterns/navigation_list/pattern-navigation-list.html.twig @@ -10,7 +10,8 @@ {% set _link = { link: { label : link.label, - path : link.url + path : link.url, + is_external: link.is_external|default(false) } } %} {% set _links = _links|merge([_link]) %} @@ -21,7 +22,8 @@ {% set _secondary_link = { link: { label : secondary_link.label, - path : secondary_link.url + path : secondary_link.url, + is_external: secondary_link.is_external|default(false) } } %} {% set _secondary_links = _secondary_links|merge([_secondary_link]) %} @@ -30,7 +32,9 @@ {% include '@oe_theme/compositions/ec-component-navigation-list/navigation-list.html.twig' with { title: title, title_url: title_url, + external_link: external_link|default(false), description: description, links: _links, secondary_links: _secondary_links, + icon_path: ecl_icon_path } only %} diff --git a/tests/src/Kernel/Paragraphs/ParagraphsTest.php b/tests/src/Kernel/Paragraphs/ParagraphsTest.php index 47ce5e18a..c81db2264 100644 --- a/tests/src/Kernel/Paragraphs/ParagraphsTest.php +++ b/tests/src/Kernel/Paragraphs/ParagraphsTest.php @@ -404,6 +404,13 @@ public function testListItemBlock() { $crawler = new Crawler($this->renderParagraph($paragraph)); $this->assertEquals('List block title', trim($crawler->filter('h2.ecl-u-type-heading-2')->text())); + // Assert that the external icon is rendered for each list item paragraph. + $this->assertCount(3, $crawler->filter('svg.ecl-icon.ecl-icon--s.ecl-link__icon')); + $this->assertEquals('', $crawler->filter('svg.ecl-icon.ecl-icon--s.ecl-link__icon')->html()); + + // Assert the external icon is rendered for the list item block. + $this->assertCount(1, $crawler->filter('svg.ecl-icon.ecl-icon--xs.ecl-link__icon')); + $this->assertEquals('', $crawler->filter('svg.ecl-icon.ecl-icon--xs.ecl-link__icon')->html()); // Verify that the referenced paragraphs are being rendered. $this->assertCount(3, $crawler->filter('div.ecl-content-item-block__item')); diff --git a/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php b/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php index f2bea7ae5..6bf06e7bd 100644 --- a/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php +++ b/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php @@ -6,6 +6,7 @@ use Drupal\Core\Url; use Drupal\Tests\oe_theme\Kernel\AbstractKernelTestBase; +use Symfony\Component\DomCrawler\Crawler; /** * Test link pattern rendering. @@ -15,7 +16,7 @@ class LinkPatternRenderingTest extends AbstractKernelTestBase { /** - * Test that link patterns are correctly rendered when passing an URL object. + * Test that link patterns are correctly rendered when passing a URL object. * * @throws \Exception */ @@ -25,16 +26,36 @@ public function testLinkPatternRendering() { '#id' => 'link', '#fields' => [ 'text' => 'Link text', - 'url' => Url::fromUserInput('/', [ + 'url' => Url::fromUserInput('/example.com', [ 'attributes' => [ 'class' => ['foo'], + 'foo' => 'bar', ], ]), ], ]; $html = $this->renderRoot($pattern); - $this->assertEquals('Link text', trim($html)); + $crawler = new Crawler($html); + $this->assertEquals('Link text', $crawler->filter('a.ecl-link.ecl-link--standalone.foo')->text()); + $this->assertEquals('/example.com', $crawler->filter('a.ecl-link.ecl-link--standalone.foo')->attr('href')); + $this->assertEquals('bar', $crawler->filter('a.ecl-link.ecl-link--standalone.foo')->attr('foo')); + + $pattern = [ + '#type' => 'pattern', + '#id' => 'link', + '#fields' => [ + 'text' => 'Link text', + 'url' => Url::fromUserInput('/example.com'), + 'external_link' => TRUE, + ], + ]; + + $html = $this->renderRoot($pattern); + $crawler = new Crawler($html); + $this->assertEquals('Link text', $crawler->filter('a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after span.ecl-link__label')->text()); + $this->assertEquals('/example.com', $crawler->filter('a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after')->attr('href')); + $this->assertEquals('', $crawler->filter('svg.ecl-icon.ecl-icon--s.ecl-link__icon')->html()); } } diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index 7384cd4e4..93d7e1444 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -1320,6 +1320,7 @@ detail: "EU economy, the euro, and practical information for EU businesses and entrepreneurs." button_label: "View all" button_url: "http://example.com" + external_link: true assertions: count: 'div.ecl-content-item-block__title': 1 @@ -1333,13 +1334,13 @@ 'div.ecl-content-item-block__item.ecl-col-m-4 article.ecl-content-item': 0 'div.ecl-content-item-block__button': 1 'div.ecl-content-item-block__button a.ecl-link[href="http://example.com"]': 1 - 'div.ecl-content-item-block__button a.ecl-link-icon': 0 - 'div.ecl-content-item-block__button a.ecl-link--standalone svg': 0 + 'div.ecl-content-item-block__button a.ecl-link--icon.ecl-link--standalone svg': 1 equals: 'div.ecl-content-item-block__title h2.ecl-u-type-heading-2': "Block title" 'div.ecl-content-item-block__item:nth-child(1) article.ecl-content-item div.ecl-content-item__title': "Business, Economy, Euro" 'div.ecl-content-item-block__item:nth-child(1) article.ecl-content-item div.ecl-content-item__description': "EU economy, the euro, and practical information for EU businesses and entrepreneurs." - 'a.ecl-link': "View all" + 'a.ecl-link span.ecl-link__label': "View all" + 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' - array: '#type': pattern '#id': list_item_block_one_column @@ -1352,6 +1353,9 @@ detail: "EU economy, the euro, and practical information for EU businesses and entrepreneurs." button_label: "View all" button_url: "http://example.com" + button_icon_position: 'before' + button_icon_name: 'list' + external_link: true assertions: count: 'div.ecl-content-item-block__title': 0 @@ -1365,11 +1369,12 @@ 'div.ecl-content-item-block__item.ecl-col-m-4 article.ecl-content-item': 0 'div.ecl-content-item-block__button': 1 'div.ecl-content-item-block__button a.ecl-link[href="http://example.com"]': 1 - 'div.ecl-content-item-block__button a.ecl-link--standalone svg': 0 + 'div.ecl-content-item-block__button a.ecl-link--standalone.ecl-link--icon-after svg': 1 equals: 'div.ecl-content-item-block__item:nth-child(1) article.ecl-content-item div.ecl-content-item__title': "Business, Economy, Euro" 'div.ecl-content-item-block__item:nth-child(1) article.ecl-content-item div.ecl-content-item__description': "EU economy, the euro, and practical information for EU businesses and entrepreneurs." - 'a.ecl-link': "View all" + 'a.ecl-link span.ecl-link__label': "View all" + 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' - array: '#type': pattern '#id': list_item_block_one_column @@ -1381,6 +1386,11 @@ '#fields': title: "Business, Economy, Euro" detail: "EU economy, the euro, and practical information for EU businesses and entrepreneurs." + button_label: "View all" + button_url: "http://example.com" + external_link: false + button_icon_name: 'list' + button_icon_position: 'before' assertions: count: 'div.ecl-content-item-block__title': 1 @@ -1392,12 +1402,15 @@ 'div.ecl-content-item-block__item.ecl-col-12 article.ecl-content-item': 1 'div.ecl-content-item-block__item.ecl-col-m-6 article.ecl-content-item': 0 'div.ecl-content-item-block__item.ecl-col-m-4 article.ecl-content-item': 0 - 'div.ecl-content-item-block__button': 0 - 'div.ecl-content-item-block__button a.ecl-link[href="http://example.com"]': 0 + 'div.ecl-content-item-block__button': 1 + 'div.ecl-content-item-block__button a.ecl-link--standalone.ecl-link--icon-before svg': 1 + 'div.ecl-content-item-block__button a.ecl-link[href="http://example.com"]': 1 equals: 'div.ecl-content-item-block__title h2.ecl-u-type-heading-2': "Block title" 'div.ecl-content-item-block__item:nth-child(1) article.ecl-content-item div.ecl-content-item__title': "Business, Economy, Euro" 'div.ecl-content-item-block__item:nth-child(1) article.ecl-content-item div.ecl-content-item__description': "EU economy, the euro, and practical information for EU businesses and entrepreneurs." + 'a.ecl-link span.ecl-link__label': "View all" + 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' - array: '#type': pattern '#id': list_item_block_one_column From 5849ef38b9ab66f7423603df2cd95bbbac751a75 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Sat, 2 Apr 2022 18:50:18 +0300 Subject: [PATCH 11/42] EWPP-2069: Update contextual navigation pattern and paragraph. --- oe_theme.theme | 4 ++- .../contextual-navigation.html.twig | 9 ++++++ .../context_nav/context_nav.ui_patterns.yml | 5 ++++ .../context_nav/pattern-context-nav.html.twig | 3 +- .../src/Kernel/Paragraphs/ParagraphsTest.php | 28 +++++++++++++++++-- tests/src/Kernel/fixtures/rendering.yml | 13 +++++++-- 6 files changed, 55 insertions(+), 7 deletions(-) diff --git a/oe_theme.theme b/oe_theme.theme index 9a8773442..f5326ce0e 100644 --- a/oe_theme.theme +++ b/oe_theme.theme @@ -254,9 +254,11 @@ function oe_theme_preprocess_paragraph__oe_contextual_navigation(array &$variabl $variables['items'] = []; foreach (Element::children($variables['content']['field_oe_links']) as $index) { + $url = $variables['content']['field_oe_links'][$index]['#url']; $variables['items'][] = [ 'label' => $variables['content']['field_oe_links'][$index]['#title'], - 'href' => $variables['content']['field_oe_links'][$index]['#url'], + 'href' => $url, + 'is_external' => ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')), ]; } } diff --git a/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig b/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig index 763dcd3d2..44da39a25 100644 --- a/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig +++ b/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig @@ -57,12 +57,21 @@ {% set _item_classes = _item_classes ~ ' ' ~ 'ecl-contextual-navigation__item--collapsed' %} {% endif %}
  • + {% if item.is_external %} + {% set icon = { + 'path': ecl_icon_path, + 'name': 'external', + 'size': 'xs', + } %} + {% endif %} {% include '@ecl-twig/link' with item|merge({ extra_classes: 'ecl-contextual-navigation__link', link: item|merge({ type: 'standalone' }), + icon: icon ?: {}, }) only %} + {% set icon = {} %}
  • {% if _item_more is not empty and loop.last and _items|length > _items_limit %} {% set _item_classes = _item_classes|replace({ diff --git a/templates/patterns/context_nav/context_nav.ui_patterns.yml b/templates/patterns/context_nav/context_nav.ui_patterns.yml index 024648f68..bcdfa3d8d 100644 --- a/templates/patterns/context_nav/context_nav.ui_patterns.yml +++ b/templates/patterns/context_nav/context_nav.ui_patterns.yml @@ -14,14 +14,19 @@ context_nav: preview: - href: "#" label: "Item one" + is_external: true - href: "#" label: "Item two" + is_external: false - href: "#" label: "Item three" + is_external: false - href: "#" label: "Item four" + is_external: false - href: "#" label: "Item five" + is_external: true limit: type: "numeric" label: "Limit" diff --git a/templates/patterns/context_nav/pattern-context-nav.html.twig b/templates/patterns/context_nav/pattern-context-nav.html.twig index 17c233f66..52a149bfd 100644 --- a/templates/patterns/context_nav/pattern-context-nav.html.twig +++ b/templates/patterns/context_nav/pattern-context-nav.html.twig @@ -8,7 +8,8 @@ {% for _item in items %} {% set _items = _items|merge([{ label: _item.label, - path: _item.href + path: _item.href, + is_external: _item.is_external|default(false) }]) %} {% endfor %} {% include '@oe_theme/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig' with { diff --git a/tests/src/Kernel/Paragraphs/ParagraphsTest.php b/tests/src/Kernel/Paragraphs/ParagraphsTest.php index c81db2264..b86d9afcc 100644 --- a/tests/src/Kernel/Paragraphs/ParagraphsTest.php +++ b/tests/src/Kernel/Paragraphs/ParagraphsTest.php @@ -539,6 +539,14 @@ public function testContextualNavigation(): void { 'title' => 'Link 2', 'uri' => 'http://example.com/page-two', ], + [ + 'title' => 'Internal link under eu domain', + 'uri' => 'http://ec.europa.eu/info', + ], + [ + 'title' => 'Internal link', + 'uri' => 'internal:/', + ], ], 'field_oe_limit' => 1, 'field_oe_text' => 'More links', @@ -552,20 +560,36 @@ public function testContextualNavigation(): void { $this->assertEquals('Contextual navigation', trim($actual)); $link1 = $crawler->filter('nav.ecl-contextual-navigation ul.ecl-contextual-navigation__list a.ecl-contextual-navigation__link')->eq(0); - $actual = $link1->text(); + $actual = $link1->filter('span.ecl-link__label')->text(); $this->assertEquals('Link 1', trim($actual)); $actual = $link1->attr('href'); $this->assertEquals('http://example.com/page-one', trim($actual)); + $icon = $link1->filter('svg.ecl-icon.ecl-icon--xs.ecl-link__icon')->html(); + $this->assertEquals('', $icon); $link2 = $crawler->filter('nav.ecl-contextual-navigation ul.ecl-contextual-navigation__list a.ecl-contextual-navigation__link')->eq(1); - $actual = $link2->text(); + $actual = $link2->filter('span.ecl-link__label')->text(); $this->assertEquals('Link 2', trim($actual)); $actual = $link2->attr('href'); $this->assertEquals('http://example.com/page-two', trim($actual)); + $icon = $link2->filter('svg.ecl-icon.ecl-icon--xs.ecl-link__icon')->html(); + $this->assertEquals('', $icon); $actual = $crawler->filter('nav.ecl-contextual-navigation ul.ecl-contextual-navigation__list li.ecl-contextual-navigation__item--collapsed a.ecl-contextual-navigation__link')->eq(0)->text(); $this->assertEquals('Link 2', trim($actual)); + $link3 = $crawler->filter('nav.ecl-contextual-navigation ul.ecl-contextual-navigation__list a.ecl-contextual-navigation__link')->eq(2); + $actual = $link3->text(); + $this->assertEquals('Internal link under eu domain', trim($actual)); + $actual = $link3->attr('href'); + $this->assertEquals('http://ec.europa.eu/info', trim($actual)); + + $link4 = $crawler->filter('nav.ecl-contextual-navigation ul.ecl-contextual-navigation__list a.ecl-contextual-navigation__link')->eq(3); + $actual = $link4->text(); + $this->assertEquals('Internal link', trim($actual)); + $actual = $link4->attr('href'); + $this->assertEquals('/', trim($actual)); + $actual = $crawler->filter('nav.ecl-contextual-navigation ul.ecl-contextual-navigation__list button.ecl-contextual-navigation__more')->text(); $this->assertEquals('More links', trim($actual)); } diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index 93d7e1444..fc2211a18 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -1973,14 +1973,17 @@ items: - href: "http://link-1.com" label: "Item one" + is_external: true - href: "http://link-2.com" label: "Item two" - href: "http://link-3.com" label: "Item three" + is_external: true - href: "http://link-4.com" label: "Item four" - href: "http://link-5.com" label: "Item five" + is_external: true limit: 4 more_label: "More label" assertions: @@ -1988,12 +1991,16 @@ 'li.ecl-contextual-navigation__item': 6 'li.ecl-contextual-navigation__item--collapsed': 1 'li.ecl-contextual-navigation__item--more': 1 + 'span.ecl-link__label': 3 equals: - 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-1.com"]': "Item one" + 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-1.com"] span.ecl-link__label': "Item one" + 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-1.com"] svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-2.com"]': "Item two" - 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-3.com"]': "Item three" + 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-3.com"] span.ecl-link__label': "Item three" + 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-3.com"] svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-4.com"]': "Item four" - 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-5.com"]': "Item five" + 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-5.com"] span.ecl-link__label': "Item five" + 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-5.com"] svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' 'div.ecl-contextual-navigation__label': "Navigation title" 'button.ecl-contextual-navigation__more .ecl-button__label': "More label" - array: From e578c24391a8af031d67d1cd355d8f1ba24cf6b1 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Sun, 3 Apr 2022 15:47:50 +0300 Subject: [PATCH 12/42] EWPP-2069: Fix link pattern preprocess. --- oe_theme.theme | 2 ++ tests/src/Kernel/Paragraphs/ParagraphsTest.php | 2 ++ .../src/Kernel/Patterns/LinkPatternRenderingTest.php | 11 ++++++----- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/oe_theme.theme b/oe_theme.theme index f5326ce0e..a7100fc82 100644 --- a/oe_theme.theme +++ b/oe_theme.theme @@ -9,6 +9,7 @@ declare(strict_types = 1); use Drupal\block\BlockInterface; use Drupal\Component\Utility\Html; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Entity\ContentEntityInterface; @@ -1426,6 +1427,7 @@ function oe_theme_preprocess_pattern_link(array &$variables): void { // Extract attributes from the URL object and set them as default. if ($variables['url'] instanceof Url) { + $variables['external_link'] = ($variables['url']->isExternal() && !strpos(UrlHelper::parse($variables['url']->toString())['path'], 'europa.eu')); $attributes = (array) $variables['url']->getOption('attributes'); if (isset($attributes['class'])) { $variables['classes'] = implode(' ', $attributes['class']); diff --git a/tests/src/Kernel/Paragraphs/ParagraphsTest.php b/tests/src/Kernel/Paragraphs/ParagraphsTest.php index b86d9afcc..32acca301 100644 --- a/tests/src/Kernel/Paragraphs/ParagraphsTest.php +++ b/tests/src/Kernel/Paragraphs/ParagraphsTest.php @@ -583,12 +583,14 @@ public function testContextualNavigation(): void { $this->assertEquals('Internal link under eu domain', trim($actual)); $actual = $link3->attr('href'); $this->assertEquals('http://ec.europa.eu/info', trim($actual)); + $this->assertCount(0, $link3->filter('svg.ecl-icon.ecl-icon--xs.ecl-link__icon')); $link4 = $crawler->filter('nav.ecl-contextual-navigation ul.ecl-contextual-navigation__list a.ecl-contextual-navigation__link')->eq(3); $actual = $link4->text(); $this->assertEquals('Internal link', trim($actual)); $actual = $link4->attr('href'); $this->assertEquals('/', trim($actual)); + $this->assertCount(0, $link4->filter('svg.ecl-icon.ecl-icon--xs.ecl-link__icon')); $actual = $crawler->filter('nav.ecl-contextual-navigation ul.ecl-contextual-navigation__list button.ecl-contextual-navigation__more')->text(); $this->assertEquals('More links', trim($actual)); diff --git a/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php b/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php index 6bf06e7bd..c375b9985 100644 --- a/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php +++ b/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php @@ -26,7 +26,7 @@ public function testLinkPatternRendering() { '#id' => 'link', '#fields' => [ 'text' => 'Link text', - 'url' => Url::fromUserInput('/example.com', [ + 'url' => Url::fromUserInput('/node/add', [ 'attributes' => [ 'class' => ['foo'], 'foo' => 'bar', @@ -38,23 +38,24 @@ public function testLinkPatternRendering() { $html = $this->renderRoot($pattern); $crawler = new Crawler($html); $this->assertEquals('Link text', $crawler->filter('a.ecl-link.ecl-link--standalone.foo')->text()); - $this->assertEquals('/example.com', $crawler->filter('a.ecl-link.ecl-link--standalone.foo')->attr('href')); + $this->assertEquals('/node/add', $crawler->filter('a.ecl-link.ecl-link--standalone.foo')->attr('href')); $this->assertEquals('bar', $crawler->filter('a.ecl-link.ecl-link--standalone.foo')->attr('foo')); + $this->assertCount(0, $crawler->filter('span.ecl-link__label')); + $this->assertCount(0, $crawler->filter('svg.ecl-icon.ecl-icon--s.ecl-link__icon')); $pattern = [ '#type' => 'pattern', '#id' => 'link', '#fields' => [ 'text' => 'Link text', - 'url' => Url::fromUserInput('/example.com'), - 'external_link' => TRUE, + 'url' => Url::fromUri('https://example.com'), ], ]; $html = $this->renderRoot($pattern); $crawler = new Crawler($html); $this->assertEquals('Link text', $crawler->filter('a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after span.ecl-link__label')->text()); - $this->assertEquals('/example.com', $crawler->filter('a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after')->attr('href')); + $this->assertEquals('https://example.com', $crawler->filter('a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after')->attr('href')); $this->assertEquals('', $crawler->filter('svg.ecl-icon.ecl-icon--s.ecl-link__icon')->html()); } From 063bd4b0c384886bf62496434f553a6daf209bbd Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Thu, 28 Apr 2022 17:01:42 +0300 Subject: [PATCH 13/42] EWPP-2069: Update featured item pattern to render external icon for title. --- .../patterns/featured_item/pattern-featured-item.html.twig | 4 +++- tests/src/Kernel/fixtures/rendering.yml | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/templates/patterns/featured_item/pattern-featured-item.html.twig b/templates/patterns/featured_item/pattern-featured-item.html.twig index c9f6a38c7..a02c5b291 100644 --- a/templates/patterns/featured_item/pattern-featured-item.html.twig +++ b/templates/patterns/featured_item/pattern-featured-item.html.twig @@ -52,7 +52,9 @@ 'title': { 'label': title, 'path': link.href, - 'type': "standalone" + 'type': "standalone", + 'external': external_link, + 'icon_path': ecl_icon_path }, 'infos': _footer_items, 'image': image, diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index fc2211a18..4adf831ab 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -2363,14 +2363,15 @@ assertions: count: "div.ecl-card__image": 0 - 'h1.ecl-card__title a.ecl-link--standalone[href="https://example.com"]': 1 + 'h1.ecl-card__title a.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after[href="https://example.com"]': 1 'a.ecl-button[href="https://example.com"]': 1 'svg.ecl-icon.ecl-icon--xs.ecl-button__icon.ecl-button__icon--after': 1 equals: - 'h1.ecl-card__title a': "Example title" + 'h1.ecl-card__title a span.ecl-link__label': "Example title" 'div.ecl-card__description .ecl-paragraph': "Example description" 'a.ecl-button .ecl-button__label': "Link title" - 'svg.ecl-icon.ecl-icon--xs.ecl-button__icon.ecl-button__icon--after': '' + 'h1.ecl-card__title a svg.ecl-icon.ecl-icon--2xs.ecl-link__icon': '' + '.ecl-card__description svg.ecl-icon.ecl-icon--xs.ecl-button__icon.ecl-button__icon--after': '' - array: '#type': pattern '#id': featured_item From 108e88ec4cebe23cf6679a47c7e64852e67496f8 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Thu, 28 Apr 2022 17:25:35 +0300 Subject: [PATCH 14/42] EWPP-2069: Render external icon for navigation_menu pattern children items. --- .../navigation_menu/navigation_menu.ui_patterns.yml | 6 ++++++ .../pattern-navigation-menu.html.twig | 6 ++++++ tests/src/Kernel/fixtures/rendering.yml | 12 +++++++++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/templates/patterns/navigation_menu/navigation_menu.ui_patterns.yml b/templates/patterns/navigation_menu/navigation_menu.ui_patterns.yml index fb1c21ac5..a887dbd74 100644 --- a/templates/patterns/navigation_menu/navigation_menu.ui_patterns.yml +++ b/templates/patterns/navigation_menu/navigation_menu.ui_patterns.yml @@ -26,6 +26,7 @@ navigation_menu: children: - href: '#' label: 'Child 1.1' + external: true - href: '#' label: 'Child 1.2' - href: '#' @@ -34,12 +35,14 @@ navigation_menu: label: 'Child 1.4' - href: '#' label: 'Child 1.5' + external: true - href: '#' label: 'Child 1.6' - href: '#' label: 'Child 1.7' - href: '#' label: 'Child 1.8' + external: true - href: "#" label: "EU law" is_current: TRUE @@ -47,6 +50,7 @@ navigation_menu: - href: '#' label: 'Eu Treaties' is_current: TRUE + external: true - href: '#' label: 'Application of EU law' - href: '#' @@ -55,7 +59,9 @@ navigation_menu: label: 'Priorities' - href: '#' label: 'Funding' + external: true - href: '#' label: 'HORIZON2020' + external: true - href: "#" label: "Contact" diff --git a/templates/patterns/navigation_menu/pattern-navigation-menu.html.twig b/templates/patterns/navigation_menu/pattern-navigation-menu.html.twig index 427ab3c01..acd2774b4 100644 --- a/templates/patterns/navigation_menu/pattern-navigation-menu.html.twig +++ b/templates/patterns/navigation_menu/pattern-navigation-menu.html.twig @@ -20,6 +20,12 @@ is_current: child.is_current, }) %} {% endif %} + {% if child.external is defined and child.external == true %} + {% set _child = _child|merge({ + external: child.external, + icon_path: ecl_icon_path + }) %} + {% endif %} {% set _children = _children|merge([_child]) %} {% endfor %} diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index 4adf831ab..a780a669a 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -2945,10 +2945,12 @@ - href: '#' label: 'Child 1.1' is_current: true + external: true - href: '#' label: 'Child 1.2' - href: '#' label: 'Child 1.3' + external: true - href: '#' label: 'Child 1.4' - href: "#" @@ -2960,6 +2962,7 @@ label: 'Child 2.2' - href: '#' label: 'Child 2.3' + external: true - href: "#" label: "Link" assertions: @@ -2969,14 +2972,17 @@ '.ecl-menu__inner-header button.ecl-menu__back .ecl-button__label': "Back" 'li.ecl-menu__item:nth-child(1) a.ecl-menu__link': "Parent 1" 'li.ecl-menu__item:nth-child(2) a.ecl-menu__link': "Parent 2" + 'li.ecl-menu__item:nth-child(1) ul.ecl-menu__sublist li.ecl-menu__subitem--current a.ecl-menu__sublink.ecl-link--icon-after': 'Child 1.1' + 'li.ecl-menu__item:nth-child(1) ul.ecl-menu__sublist li.ecl-menu__subitem:nth-child(3) a.ecl-menu__sublink.ecl-link--icon-after': 'Child 1.3' + 'li.ecl-menu__item:nth-child(2) ul.ecl-menu__sublist li.ecl-menu__subitem:nth-child(3) a.ecl-menu__sublink.ecl-link--icon-after': 'Child 2.3' equals: - 'li.ecl-menu__item:nth-child(1) ul.ecl-menu__sublist li.ecl-menu__subitem--current a.ecl-menu__sublink': 'Child 1.1' + 'li.ecl-menu__item:nth-child(1) ul.ecl-menu__sublist li.ecl-menu__subitem--current a svg.ecl-icon.ecl-icon--2xs.ecl-menu__sublink-icon.ecl-link__icon': '' 'li.ecl-menu__item:nth-child(1) ul.ecl-menu__sublist li.ecl-menu__subitem:nth-child(2) a.ecl-menu__sublink': 'Child 1.2' - 'li.ecl-menu__item:nth-child(1) ul.ecl-menu__sublist li.ecl-menu__subitem:nth-child(3) a.ecl-menu__sublink': 'Child 1.3' + 'li.ecl-menu__item:nth-child(1) ul.ecl-menu__sublist li.ecl-menu__subitem:nth-child(3) a svg.ecl-icon.ecl-icon--2xs.ecl-menu__sublink-icon.ecl-link__icon': '' 'li.ecl-menu__item:nth-child(1) ul.ecl-menu__sublist li.ecl-menu__subitem:nth-child(4) a.ecl-menu__sublink': 'Child 1.4' 'li.ecl-menu__item:nth-child(2) ul.ecl-menu__sublist li.ecl-menu__subitem:nth-child(1) a.ecl-menu__sublink': 'Child 2.1' 'li.ecl-menu__item:nth-child(2) ul.ecl-menu__sublist li.ecl-menu__subitem:nth-child(2) a.ecl-menu__sublink': 'Child 2.2' - 'li.ecl-menu__item:nth-child(2) ul.ecl-menu__sublist li.ecl-menu__subitem:nth-child(3) a.ecl-menu__sublink': 'Child 2.3' + 'li.ecl-menu__item:nth-child(2) ul.ecl-menu__sublist li.ecl-menu__subitem:nth-child(3) a svg.ecl-icon.ecl-icon--2xs.ecl-menu__sublink-icon.ecl-link__icon': '' 'li.ecl-menu__item:nth-child(3) a.ecl-menu__link': "Link" - array: '#type': "pattern" From e1611815304e6a2d8440bc68a49407d57931df16 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Thu, 28 Apr 2022 20:11:58 +0300 Subject: [PATCH 15/42] EWPP-2069: Render external icon for facts and figures pattern.. --- .../patterns/facts_figures/facts_figures.ui_patterns.yml | 5 +++++ .../patterns/facts_figures/pattern-facts-figures.html.twig | 7 ++++++- tests/src/Kernel/fixtures/rendering.yml | 4 +++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/templates/patterns/facts_figures/facts_figures.ui_patterns.yml b/templates/patterns/facts_figures/facts_figures.ui_patterns.yml index 798904024..a244a3145 100644 --- a/templates/patterns/facts_figures/facts_figures.ui_patterns.yml +++ b/templates/patterns/facts_figures/facts_figures.ui_patterns.yml @@ -38,3 +38,8 @@ facts_figures: preview: label: "View all metrics" path: "/example" + external_link: + type: "boolean" + label: "External link" + description: "Whether the view all URL is external or not." + preview: true diff --git a/templates/patterns/facts_figures/pattern-facts-figures.html.twig b/templates/patterns/facts_figures/pattern-facts-figures.html.twig index 666fb1f1e..aff7b77be 100644 --- a/templates/patterns/facts_figures/pattern-facts-figures.html.twig +++ b/templates/patterns/facts_figures/pattern-facts-figures.html.twig @@ -5,7 +5,12 @@ */ #} {% if view_all is not empty %} - {% set _link = {'path' : view_all.path, 'label' : view_all.label} %} + {% set _link = { + 'path': view_all.path, + 'label': view_all.label, + 'external': external_link|default(false), + 'icon_path': ecl_icon_path, + } %} {% set view_all_icon = { path: ecl_icon_path, name: "corner-arrow", diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index a780a669a..508e4cf21 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -3072,6 +3072,7 @@ view_all: label: 'View all metrics' path: 'https://example.com' + external_link: true assertions: count: 'div.ecl-fact-figures.ecl-fact-figures--col-3 div.ecl-fact-figures__items': 1 @@ -3087,7 +3088,8 @@ 'div.ecl-fact-figures__item:nth-child(2) div.ecl-fact-figures__value': '10.0 millions' 'div.ecl-fact-figures__item:nth-child(2) div.ecl-fact-figures__title': 'Nam lacinia nisl eget diam mattis' 'div.ecl-fact-figures__item:nth-child(2) div.ecl-fact-figures__description': 'Sed efficitur bibendum rutrum. Nunc feugiat congue augue ac consectetur.' - 'div.ecl-fact-figures__view-all a.ecl-link.ecl-link--standalone.ecl-fact-figures__view-all-link[href="https://example.com"] span.ecl-link__label': 'View all metrics' + 'div.ecl-fact-figures__view-all a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after.ecl-fact-figures__view-all-link[href="https://example.com"] span.ecl-link__label': 'View all metrics' + 'svg.ecl-icon.ecl-icon--2xs.ecl-link__icon': '' - array: '#type': 'pattern' '#id': 'facts_figures' From 95ab8b1fcdb8e09444098a5bc9b30247654ca0f4 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Thu, 28 Apr 2022 20:33:59 +0300 Subject: [PATCH 16/42] EWPP-2069: Adapt pattern template changes to the new ecl-link external parameter. --- oe_theme.theme | 4 ++ .../contextual-navigation.html.twig | 13 +--- .../navigation-list.html.twig | 62 +++++-------------- .../paragraph--oe-facts-figures.html.twig | 3 +- .../patterns/button/pattern-button.html.twig | 27 ++++---- .../patterns/link/pattern-link.html.twig | 18 ++---- .../pattern-list-item--variant-date.html.twig | 16 ++--- ...ern-list-item--variant-highlight.html.twig | 4 +- .../list_item/pattern-list-item.html.twig | 26 +++----- 9 files changed, 55 insertions(+), 118 deletions(-) diff --git a/oe_theme.theme b/oe_theme.theme index a7100fc82..b4422f93b 100644 --- a/oe_theme.theme +++ b/oe_theme.theme @@ -1468,8 +1468,12 @@ function oe_theme_preprocess_paragraph__oe_facts_figures(array &$variables): voi $variables['title'] = $paragraph->get('field_oe_title')->value; } if (!$paragraph->get('field_oe_link')->isEmpty()) { + $url = $paragraph->get('field_oe_link')->first()->getUrl(); $variables['view_all']['path'] = $paragraph->get('field_oe_link')->first()->getUrl(); $variables['view_all']['label'] = $paragraph->get('field_oe_link')->first()->get('title')->getValue(); + if ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')) { + $variables['external_link'] = TRUE; + } } $variables['items'] = []; diff --git a/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig b/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig index 44da39a25..7b0cead7c 100644 --- a/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig +++ b/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig @@ -57,21 +57,14 @@ {% set _item_classes = _item_classes ~ ' ' ~ 'ecl-contextual-navigation__item--collapsed' %} {% endif %}
  • - {% if item.is_external %} - {% set icon = { - 'path': ecl_icon_path, - 'name': 'external', - 'size': 'xs', - } %} - {% endif %} {% include '@ecl-twig/link' with item|merge({ extra_classes: 'ecl-contextual-navigation__link', link: item|merge({ - type: 'standalone' + type: 'standalone', + external: is_external, + icon_path: ecl_icon_path, }), - icon: icon ?: {}, }) only %} - {% set icon = {} %}
  • {% if _item_more is not empty and loop.last and _items|length > _items_limit %} {% set _item_classes = _item_classes|replace({ diff --git a/templates/compositions/ec-component-navigation-list/navigation-list.html.twig b/templates/compositions/ec-component-navigation-list/navigation-list.html.twig index d651eb79b..35fc27209 100644 --- a/templates/compositions/ec-component-navigation-list/navigation-list.html.twig +++ b/templates/compositions/ec-component-navigation-list/navigation-list.html.twig @@ -17,23 +17,15 @@

    {% if title_url %} - {% set _link = { + {% include '@ecl-twig/link' with { 'link': { 'type': 'standalone', 'label': title, - 'path': title_url + 'path': title_url, + 'external': external_link, + 'icon_path': ecl_icon_path } - } %} - {% if external_link %} - {% set _link = _link|merge({ - icon: { - 'path': icon_path, - 'name': 'external', - 'size': 's', - } - }) %} - {% endif %} - {% include '@ecl-twig/link' with _link only %} + } only %} {% else %} {{ title }} {% endif %} @@ -48,23 +40,11 @@ {% for link in links %}
  • {% if link.link.path %} - {% set _link = { - 'link': { - 'type': 'standalone', - 'label': link.link.label, - 'path': link.link.path - } - } %} - {% if link.link.is_external %} - {% set _link = _link|merge({ - icon: { - 'path': icon_path, - 'name': 'external', - 'size': 'xs', - } - }) %} - {% endif %} - {% include '@ecl-twig/link' with _link only %} + {% include '@ecl-twig/link' with { link: link.link|merge({ + 'type': 'standalone', + 'external': link.link.is_external, + 'icon_path': ecl_icon_path + }) } only %} {% else %} {{ link.link.label }} {% endif %} @@ -78,23 +58,11 @@ {% for link in secondary_links %}
  • {% if link.link.path %} - {% set _link = { - 'link': { - 'type': 'standalone', - 'label': link.link.label, - 'path': link.link.path - } - } %} - {% if link.link.is_external %} - {% set _link = _link|merge({ - icon: { - 'path': icon_path, - 'name': 'external', - 'size': 'xs', - } - }) %} - {% endif %} - {% include '@ecl-twig/link' with _link only %} + {% include '@ecl-twig/link' with { link: link.link|merge({ + 'type': 'standalone', + 'external': link.link.is_external, + 'icon_path': ecl_icon_path + }) } only %} {% else %} {{ link.link.label }} {% endif %} diff --git a/templates/paragraphs/paragraph--oe-facts-figures.html.twig b/templates/paragraphs/paragraph--oe-facts-figures.html.twig index 856595578..d7e0be7e9 100644 --- a/templates/paragraphs/paragraph--oe-facts-figures.html.twig +++ b/templates/paragraphs/paragraph--oe-facts-figures.html.twig @@ -13,5 +13,6 @@ {% endif %} {{ pattern('facts_figures', { 'items': items, - 'view_all': view_all + 'view_all': view_all, + 'external_link': external_link }) }} diff --git a/templates/patterns/button/pattern-button.html.twig b/templates/patterns/button/pattern-button.html.twig index a629bb138..01bcabf17 100644 --- a/templates/patterns/button/pattern-button.html.twig +++ b/templates/patterns/button/pattern-button.html.twig @@ -4,33 +4,32 @@ * Button. */ #} -{% if icon %} - {% set _icon = { - 'path': ecl_icon_path, - 'name': external_link ? 'external' : icon, - 'size': 's' - } %} -{% endif %} -{% if external_link %} - {% set icon_position = 'after' %} -{% endif %} - {% if variant == 'default' %} {% include '@ecl-twig/link' with { 'link': { 'type': 'standalone', 'label': label, 'path': href, - 'icon_position': icon_position|default('after') + 'icon_position': icon_position|default('after'), + 'external': external_link, + 'icon_path': ecl_icon_path }, - 'icon': _icon + 'icon': { + 'path': ecl_icon_path, + 'name': icon, + 'size': 's' + } } only %} {% else %} {% include '@ecl-twig/button' with { 'label': label, 'variant': variant|replace({'_':'-'}), 'type': type_attribute, - 'icon': _icon, + 'icon': { + 'path': ecl_icon_path, + 'name': external_link ? 'external' : icon, + 'size': 's' + }, 'icon_position': icon_position|default('after'), 'disabled': disabled } only %} diff --git a/templates/patterns/link/pattern-link.html.twig b/templates/patterns/link/pattern-link.html.twig index b3c7cf2a9..fc56390c8 100644 --- a/templates/patterns/link/pattern-link.html.twig +++ b/templates/patterns/link/pattern-link.html.twig @@ -4,24 +4,14 @@ * Link pattern. */ #} -{% set _link = { +{% include '@ecl-twig/link' with { link: { type: variant|default('standalone'), label: text, path: url, + external: external_link, + icon_path: ecl_icon_path }, extra_attributes: extra_attributes, extra_classes: classes -} %} -{% if external_link %} - {% set _link = _link|merge({ - icon: { - 'path': ecl_icon_path, - 'name': 'external', - 'size': 's', - } - }) %} -{% endif %} -{% apply spaceless %} - {%- include '@ecl-twig/link' with _link only -%} -{% endapply %} +} only %} diff --git a/templates/patterns/list_item/pattern-list-item--variant-date.html.twig b/templates/patterns/list_item/pattern-list-item--variant-date.html.twig index 180d32292..9f06f3d74 100644 --- a/templates/patterns/list_item/pattern-list-item--variant-date.html.twig +++ b/templates/patterns/list_item/pattern-list-item--variant-date.html.twig @@ -54,23 +54,15 @@ {% block title %}
    {%- if url %} - {% set _link = { + {% include '@ecl-twig/link' with { link: { type: 'standalone', label: title, path: url, + external: external_link, + icon_path: ecl_icon_path } - } %} - {% if external_link %} - {% set _link = _link|merge({ - icon: { - 'path': ecl_icon_path, - 'name': 'external', - 'size': 's', - } - }) %} - {% endif %} - {% include '@ecl-twig/link' with _link only %} + } only %} {% else %} {{ title }} {%- endif -%} diff --git a/templates/patterns/list_item/pattern-list-item--variant-highlight.html.twig b/templates/patterns/list_item/pattern-list-item--variant-highlight.html.twig index 353ed236c..65cc0fded 100644 --- a/templates/patterns/list_item/pattern-list-item--variant-highlight.html.twig +++ b/templates/patterns/list_item/pattern-list-item--variant-highlight.html.twig @@ -9,7 +9,9 @@ title: { label: title, path: url, - type: "standalone" + type: "standalone", + external: external_link, + icon_path: ecl_icon_path }, image: image, description: detail|smart_trim(length), diff --git a/templates/patterns/list_item/pattern-list-item.html.twig b/templates/patterns/list_item/pattern-list-item.html.twig index c5359bc33..190941095 100644 --- a/templates/patterns/list_item/pattern-list-item.html.twig +++ b/templates/patterns/list_item/pattern-list-item.html.twig @@ -74,31 +74,19 @@ type: 'standalone', label: title, path: url, + external: external_link, + icon_path: ecl_icon_path } } %} {% if icon %} - {% set _icon = { - 'path': ecl_icon_path, - 'name': icon, - 'size': 's', - } %} - {% endif %} - {% if external_link %} - {% if _icon %} - {% set _icon = _icon|merge({ - 'name': 'external' - }) %} - {% else %} - {% set _icon = { + {% set _link = _link|merge({ + icon: { 'path': ecl_icon_path, - 'name': 'external', + 'name': icon, 'size': 's', - } %} - {% endif %} + } + }) %} {% endif %} - {% set _link = _link|merge({ - icon: _icon - }) %} {% include '@ecl-twig/link' with _link only %} {% else %} {{ title }} From 5cda45fba67e45ea5230ff49645309fbf3734d89 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Thu, 28 Apr 2022 21:06:34 +0300 Subject: [PATCH 17/42] EWPP-2069: Adapt rendering tests. --- .../contextual-navigation.html.twig | 2 +- .../src/Kernel/Paragraphs/ParagraphsTest.php | 22 ++++++++----------- .../Patterns/LinkPatternRenderingTest.php | 2 +- tests/src/Kernel/fixtures/rendering.yml | 14 ++++++------ 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig b/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig index 7b0cead7c..bedf2ce06 100644 --- a/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig +++ b/templates/compositions/ec-component-contextual-navigation/contextual-navigation.html.twig @@ -61,7 +61,7 @@ extra_classes: 'ecl-contextual-navigation__link', link: item|merge({ type: 'standalone', - external: is_external, + external: item.is_external, icon_path: ecl_icon_path, }), }) only %} diff --git a/tests/src/Kernel/Paragraphs/ParagraphsTest.php b/tests/src/Kernel/Paragraphs/ParagraphsTest.php index 32acca301..300a11108 100644 --- a/tests/src/Kernel/Paragraphs/ParagraphsTest.php +++ b/tests/src/Kernel/Paragraphs/ParagraphsTest.php @@ -405,8 +405,8 @@ public function testListItemBlock() { $crawler = new Crawler($this->renderParagraph($paragraph)); $this->assertEquals('List block title', trim($crawler->filter('h2.ecl-u-type-heading-2')->text())); // Assert that the external icon is rendered for each list item paragraph. - $this->assertCount(3, $crawler->filter('svg.ecl-icon.ecl-icon--s.ecl-link__icon')); - $this->assertEquals('', $crawler->filter('svg.ecl-icon.ecl-icon--s.ecl-link__icon')->html()); + $this->assertCount(3, $crawler->filter('svg.ecl-icon.ecl-icon--2xs.ecl-link__icon')); + $this->assertEquals('', $crawler->filter('svg.ecl-icon.ecl-icon--2xs.ecl-link__icon')->html()); // Assert the external icon is rendered for the list item block. $this->assertCount(1, $crawler->filter('svg.ecl-icon.ecl-icon--xs.ecl-link__icon')); @@ -564,7 +564,7 @@ public function testContextualNavigation(): void { $this->assertEquals('Link 1', trim($actual)); $actual = $link1->attr('href'); $this->assertEquals('http://example.com/page-one', trim($actual)); - $icon = $link1->filter('svg.ecl-icon.ecl-icon--xs.ecl-link__icon')->html(); + $icon = $link1->filter('svg.ecl-icon.ecl-icon--2xs.ecl-link__icon')->html(); $this->assertEquals('', $icon); $link2 = $crawler->filter('nav.ecl-contextual-navigation ul.ecl-contextual-navigation__list a.ecl-contextual-navigation__link')->eq(1); @@ -572,7 +572,7 @@ public function testContextualNavigation(): void { $this->assertEquals('Link 2', trim($actual)); $actual = $link2->attr('href'); $this->assertEquals('http://example.com/page-two', trim($actual)); - $icon = $link2->filter('svg.ecl-icon.ecl-icon--xs.ecl-link__icon')->html(); + $icon = $link2->filter('svg.ecl-icon.ecl-icon--2xs.ecl-link__icon')->html(); $this->assertEquals('', $icon); $actual = $crawler->filter('nav.ecl-contextual-navigation ul.ecl-contextual-navigation__list li.ecl-contextual-navigation__item--collapsed a.ecl-contextual-navigation__link')->eq(0)->text(); @@ -624,11 +624,9 @@ public function testFactsFigures(): void { $test_cases = [ 'eu' => [ 'fact_icon_size' => 'l', - 'view_all_icon_size' => 'm', ], 'ec' => [ 'fact_icon_size' => 'm', - 'view_all_icon_size' => 'xs', ], ]; foreach ($test_cases as $component_library => $icon_sizes) { @@ -651,7 +649,7 @@ public function testFactsFigures(): void { $html = $this->renderParagraph($paragraph); $crawler = new Crawler($html); - $this->assertFactsFigures($crawler, $component_library, $icon_sizes['fact_icon_size'], $icon_sizes['view_all_icon_size']); + $this->assertFactsFigures($crawler, $component_library, $icon_sizes['fact_icon_size']); // Assert paragraph with empty Title and Link fields. $paragraph = Paragraph::create([ @@ -676,22 +674,18 @@ public function testFactsFigures(): void { * Component library. * @param string $fact_icon_size * Size of the icon in facts. - * @param string $view_all_icon_size - * Size of the icon of view all link. */ - protected function assertFactsFigures(Crawler $crawler, string $component_library, string $fact_icon_size, string $view_all_icon_size): void { + protected function assertFactsFigures(Crawler $crawler, string $component_library, string $fact_icon_size): void { $this->assertCount(1, $crawler->filter('div.ecl-fact-figures.ecl-fact-figures--col-3 div.ecl-fact-figures__items')); $this->assertCount(1, $crawler->filter("div.ecl-fact-figures__item:nth-child(1) svg.ecl-icon.ecl-icon--$fact_icon_size.ecl-fact-figures__icon"), $component_library); $this->assertCount(1, $crawler->filter("div.ecl-fact-figures__item:nth-child(2) svg.ecl-icon.ecl-icon--$fact_icon_size.ecl-fact-figures__icon")); $this->assertCount(1, $crawler->filter("div.ecl-fact-figures__item:nth-child(3) svg.ecl-icon.ecl-icon--$fact_icon_size.ecl-fact-figures__icon")); - $this->assertCount(1, $crawler->filter("div.ecl-fact-figures__view-all svg.ecl-icon.ecl-icon--$view_all_icon_size.ecl-icon--rotate-90.ecl-link__icon")); $this->assertEquals('Facts and figures', trim($crawler->filter('h2.ecl-u-type-heading-2')->text())); $this->assertEquals("", $crawler->filter("div.ecl-fact-figures__item:nth-child(1) svg.ecl-icon.ecl-icon--$fact_icon_size.ecl-fact-figures__icon")->html()); $this->assertEquals("", $crawler->filter("div.ecl-fact-figures__item:nth-child(2) svg.ecl-icon.ecl-icon--$fact_icon_size.ecl-fact-figures__icon")->html()); $this->assertEquals("", $crawler->filter("div.ecl-fact-figures__item:nth-child(3) svg.ecl-icon.ecl-icon--$fact_icon_size.ecl-fact-figures__icon")->html()); - $this->assertEquals("", $crawler->filter("div.ecl-fact-figures__view-all svg.ecl-icon.ecl-icon--$view_all_icon_size.ecl-icon--rotate-90.ecl-link__icon")->html()); $this->assertEquals('10 millions', trim($crawler->filter('div.ecl-fact-figures__item:nth-child(1) div.ecl-fact-figures__value')->text())); $this->assertEquals('20 millions', trim($crawler->filter('div.ecl-fact-figures__item:nth-child(2) div.ecl-fact-figures__value')->text())); $this->assertEquals('30 millions', trim($crawler->filter('div.ecl-fact-figures__item:nth-child(3) div.ecl-fact-figures__value')->text())); @@ -702,11 +696,13 @@ protected function assertFactsFigures(Crawler $crawler, string $component_librar $this->assertEquals('Fact description 2', trim($crawler->filter('div.ecl-fact-figures__item:nth-child(2) div.ecl-fact-figures__description')->text())); $this->assertEquals('Fact description 3', trim($crawler->filter('div.ecl-fact-figures__item:nth-child(3) div.ecl-fact-figures__description')->text())); - $link = $crawler->filter('div.ecl-fact-figures__view-all a.ecl-link.ecl-link--standalone.ecl-fact-figures__view-all-link'); + $link = $crawler->filter('div.ecl-fact-figures__view-all a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after.ecl-fact-figures__view-all-link'); $actual = $link->text(); $this->assertEquals('View all metrics', trim($actual)); $actual = $link->attr('href'); $this->assertEquals('http://www.example.com/', trim($actual)); + $icon = $link->filter('svg.ecl-icon.ecl-icon--2xs.ecl-link__icon')->html(); + $this->assertEquals("", $icon); } /** diff --git a/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php b/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php index c375b9985..3435b4dab 100644 --- a/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php +++ b/tests/src/Kernel/Patterns/LinkPatternRenderingTest.php @@ -56,7 +56,7 @@ public function testLinkPatternRendering() { $crawler = new Crawler($html); $this->assertEquals('Link text', $crawler->filter('a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after span.ecl-link__label')->text()); $this->assertEquals('https://example.com', $crawler->filter('a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after')->attr('href')); - $this->assertEquals('', $crawler->filter('svg.ecl-icon.ecl-icon--s.ecl-link__icon')->html()); + $this->assertEquals('', $crawler->filter('svg.ecl-icon.ecl-icon--2xs.ecl-link__icon')->html()); } } diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index 508e4cf21..e9929ae52 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -1994,13 +1994,13 @@ 'span.ecl-link__label': 3 equals: 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-1.com"] span.ecl-link__label': "Item one" - 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-1.com"] svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' + 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-1.com"] svg.ecl-icon.ecl-icon--2xs.ecl-link__icon': '' 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-2.com"]': "Item two" 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-3.com"] span.ecl-link__label': "Item three" - 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-3.com"] svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' + 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-3.com"] svg.ecl-icon.ecl-icon--2xs.ecl-link__icon': '' 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-4.com"]': "Item four" 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-5.com"] span.ecl-link__label': "Item five" - 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-5.com"] svg.ecl-icon.ecl-icon--xs.ecl-link__icon': '' + 'li.ecl-contextual-navigation__item a.ecl-contextual-navigation__link[href="http://link-5.com"] svg.ecl-icon.ecl-icon--2xs.ecl-link__icon': '' 'div.ecl-contextual-navigation__label': "Navigation title" 'button.ecl-contextual-navigation__more .ecl-button__label': "More label" - array: @@ -2037,7 +2037,7 @@ 'a.ecl-link--icon-before svg': 0 equals: 'a.ecl-link--standalone[href="http://example.com"] .ecl-link__label': "Button label" - 'svg.ecl-icon.ecl-icon--s.ecl-link__icon': '' + 'svg.ecl-icon.ecl-icon--2xs.ecl-link__icon': '' - array: '#type': pattern '#id': button @@ -2049,10 +2049,10 @@ external_link: true assertions: count: - 'a.ecl-link--standalone': 1 - 'a.ecl-link--icon': 0 + 'a.ecl-link--icon': 1 equals: - 'a.ecl-link--standalone[href="http://example.com"]': "Button label" + 'a.ecl-link--standalone[href="http://example.com"] .ecl-link__label': "Button label" + 'svg.ecl-icon.ecl-icon--2xs.ecl-link__icon': '' - array: '#type': pattern '#id': button From 083f11706482ccc6946ba474f53c42426d6b124b Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Fri, 29 Apr 2022 10:59:48 +0300 Subject: [PATCH 18/42] EWPP-2069: Update main menu to render external icon. --- oe_theme.theme | 2 ++ .../navigation_menu/navigation_menu.ui_patterns.yml | 2 ++ .../navigation_menu/pattern-navigation-menu.html.twig | 6 ++++++ tests/src/Kernel/MainMenuTest.php | 9 ++++++++- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/oe_theme.theme b/oe_theme.theme index b4422f93b..1db0c534c 100644 --- a/oe_theme.theme +++ b/oe_theme.theme @@ -129,6 +129,7 @@ function oe_theme_preprocess_menu__main(array &$variables): void { 'label' => $item['title'], 'href' => $item['url'], 'is_current' => $item['in_active_trail'], + 'external' => ($item['url']->isExternal() && !strpos(UrlHelper::parse($item['url']->toString())['path'], 'europa.eu')), ]; }, $variables['items']); @@ -138,6 +139,7 @@ function oe_theme_preprocess_menu__main(array &$variables): void { 'label' => $item['title'], 'href' => $item['url'], 'is_current' => $item['in_active_trail'], + 'external' => ($item['url']->isExternal() && !strpos(UrlHelper::parse($item['url']->toString())['path'], 'europa.eu')), ]; }, $variables['items'][$name]['below']); } diff --git a/templates/patterns/navigation_menu/navigation_menu.ui_patterns.yml b/templates/patterns/navigation_menu/navigation_menu.ui_patterns.yml index a887dbd74..d548faf98 100644 --- a/templates/patterns/navigation_menu/navigation_menu.ui_patterns.yml +++ b/templates/patterns/navigation_menu/navigation_menu.ui_patterns.yml @@ -45,6 +45,7 @@ navigation_menu: external: true - href: "#" label: "EU law" + external: true is_current: TRUE children: - href: '#' @@ -65,3 +66,4 @@ navigation_menu: external: true - href: "#" label: "Contact" + external: true diff --git a/templates/patterns/navigation_menu/pattern-navigation-menu.html.twig b/templates/patterns/navigation_menu/pattern-navigation-menu.html.twig index acd2774b4..565586fdb 100644 --- a/templates/patterns/navigation_menu/pattern-navigation-menu.html.twig +++ b/templates/patterns/navigation_menu/pattern-navigation-menu.html.twig @@ -35,6 +35,12 @@ label: item.label, children: _children, } %} + {% if _children is empty and item.external is defined and item.external == true %} + {% set _item = _item|merge({ + external: item.external, + icon_path: ecl_icon_path + }) %} + {% endif %} {% if item.is_current is defined and item.is_current == true %} {% set _item = _item|merge({ is_current: item.is_current, diff --git a/tests/src/Kernel/MainMenuTest.php b/tests/src/Kernel/MainMenuTest.php index e8268842b..698677498 100644 --- a/tests/src/Kernel/MainMenuTest.php +++ b/tests/src/Kernel/MainMenuTest.php @@ -87,6 +87,7 @@ public function testMainMenuRendering(): void { $html = $this->renderRoot($build); $crawler = new Crawler($html); + file_put_contents('test.html', $html); // Assert wrapper contains ECL class. $actual = $crawler->filter('nav.ecl-menu'); @@ -97,6 +98,11 @@ public function testMainMenuRendering(): void { $this->assertEquals(2, $links->count()); $active_link = $crawler->filter('nav.ecl-menu li.ecl-menu__item.ecl-menu__item--current a.ecl-menu__link'); $this->assertEquals(1, $active_link->count()); + // Assert that the leaf item has the external icon rendered. + $this->assertEquals('', $links->eq(0)->filter('svg.ecl-icon.ecl-icon--xs.ecl-menu__link-icon--external.ecl-menu__link-icon')->html()); + // Assert that the parent item renders the corner arrow icon because it has + // children, although it's an external link. + $this->assertEquals('', $links->eq(1)->filter('svg.ecl-icon.ecl-icon--xs.ecl-icon--rotate-90.ecl-menu__link-icon')->html()); // Assert that parent link is correctly rendered. // Remove all non-printable characters. @@ -106,9 +112,10 @@ public function testMainMenuRendering(): void { // Assert children are rendered correctly. $position = 0; foreach ($children as $title => $url) { - $link = $crawler->filter('.ecl-menu__mega li.ecl-menu__subitem a.ecl-menu__sublink')->eq($position); + $link = $crawler->filter('.ecl-menu__mega li.ecl-menu__subitem a.ecl-menu__sublink.ecl-link--icon-after')->eq($position); $this->assertEquals($title, trim($link->text())); $this->assertEquals($url, trim($link->extract(['href'])[0])); + $this->assertEquals('', $link->filter('svg.ecl-icon.ecl-icon--2xs.ecl-menu__sublink-icon.ecl-link__icon')->html()); $position++; } From 8965551955c5f74f1d8c083e150a12bb858b47ba Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Thu, 5 May 2022 09:27:36 +0300 Subject: [PATCH 19/42] EWPP-2069: Add an external links service. --- .../oe_theme_helper.services.yml | 2 + modules/oe_theme_helper/src/ExternalLinks.php | 55 +++++++++++++++++++ .../src/ExternalLinksInterface.php | 25 +++++++++ .../src/TwigExtension/TwigExtension.php | 2 +- oe_theme.theme | 29 ++++------ .../navigation-list.html.twig | 6 +- 6 files changed, 97 insertions(+), 22 deletions(-) create mode 100644 modules/oe_theme_helper/src/ExternalLinks.php create mode 100644 modules/oe_theme_helper/src/ExternalLinksInterface.php diff --git a/modules/oe_theme_helper/oe_theme_helper.services.yml b/modules/oe_theme_helper/oe_theme_helper.services.yml index 746eb9eb7..8259407aa 100644 --- a/modules/oe_theme_helper/oe_theme_helper.services.yml +++ b/modules/oe_theme_helper/oe_theme_helper.services.yml @@ -40,3 +40,5 @@ services: class: Drupal\oe_theme_helper\MediaDataExtractorPluginManager parent: default_plugin_manager arguments: ['@entity_type.bundle.info'] + oe_theme_helper.external_links: + class: Drupal\oe_theme_helper\ExternalLinks diff --git a/modules/oe_theme_helper/src/ExternalLinks.php b/modules/oe_theme_helper/src/ExternalLinks.php new file mode 100644 index 000000000..3b8c31680 --- /dev/null +++ b/modules/oe_theme_helper/src/ExternalLinks.php @@ -0,0 +1,55 @@ +isExternal(); + $path = UrlHelper::parse($url->toString())['path']; + } + else { + $external = UrlHelper::isExternal($url); + $path = UrlHelper::parse($url)['path']; + } + if (!$external) { + return $external; + } + + // If it's external link, make sure its domain is not considered internal. + $internal_domains = $this->internalDomains(); + foreach ($internal_domains as $internal_domain) { + if (strpos($path, $internal_domain)) { + $external = FALSE; + break; + } + } + + return $external; + } + + /** + * Defines a list of domain considered internal. + * + * @return array|null + * The list of internal domains or NULL if there is none. + */ + protected function internalDomains(): ?array { + return [ + 'europa.eu', + ]; + } + +} diff --git a/modules/oe_theme_helper/src/ExternalLinksInterface.php b/modules/oe_theme_helper/src/ExternalLinksInterface.php new file mode 100644 index 000000000..ed343a756 --- /dev/null +++ b/modules/oe_theme_helper/src/ExternalLinksInterface.php @@ -0,0 +1,25 @@ + $size, 'color' => 'primary', ]; - if (UrlHelper::isExternal($path) && !strpos(UrlHelper::parse($path)['path'], 'europa.eu')) { + if (\Drupal::service('oe_theme_helper.external_links')->isExternalLink($path)) { $icon['name'] = 'external'; } else { diff --git a/oe_theme.theme b/oe_theme.theme index 1db0c534c..c7d8837e4 100644 --- a/oe_theme.theme +++ b/oe_theme.theme @@ -9,7 +9,6 @@ declare(strict_types = 1); use Drupal\block\BlockInterface; use Drupal\Component\Utility\Html; -use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Entity\ContentEntityInterface; @@ -129,7 +128,7 @@ function oe_theme_preprocess_menu__main(array &$variables): void { 'label' => $item['title'], 'href' => $item['url'], 'is_current' => $item['in_active_trail'], - 'external' => ($item['url']->isExternal() && !strpos(UrlHelper::parse($item['url']->toString())['path'], 'europa.eu')), + 'external' => \Drupal::service('oe_theme_helper.external_links')->isExternalLink($item['url']), ]; }, $variables['items']); @@ -139,7 +138,7 @@ function oe_theme_preprocess_menu__main(array &$variables): void { 'label' => $item['title'], 'href' => $item['url'], 'is_current' => $item['in_active_trail'], - 'external' => ($item['url']->isExternal() && !strpos(UrlHelper::parse($item['url']->toString())['path'], 'europa.eu')), + 'external' => \Drupal::service('oe_theme_helper.external_links')->isExternalLink($item['url']), ]; }, $variables['items'][$name]['below']); } @@ -214,13 +213,14 @@ function oe_theme_theme_suggestions_paragraph_alter(array &$suggestions, array $ * Implements hook_preprocess_paragraph(). */ function oe_theme_preprocess_paragraph__oe_links_block(array &$variables): void { + $external_links_service = \Drupal::service('oe_theme_helper.external_links'); // Massage data to be compliant with ECL links block component data structure. foreach (Element::children($variables['content']['field_oe_links']) as $index) { $url = $variables['content']['field_oe_links'][$index]['#url']; $variables['links'][] = [ 'label' => $variables['content']['field_oe_links'][$index]['#title'], 'url' => $url, - 'is_external' => ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')), + 'is_external' => $external_links_service->isExternalLink($url), ]; } } @@ -256,12 +256,13 @@ function oe_theme_preprocess_paragraph__oe_contextual_navigation(array &$variabl $variables['more_label'] = $paragraph->get('field_oe_text')->value; $variables['items'] = []; + $external_links_service = \Drupal::service('oe_theme_helper.external_links'); foreach (Element::children($variables['content']['field_oe_links']) as $index) { $url = $variables['content']['field_oe_links'][$index]['#url']; $variables['items'][] = [ 'label' => $variables['content']['field_oe_links'][$index]['#title'], 'href' => $url, - 'is_external' => ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')), + 'is_external' => $external_links_service->isExternalLink($url), ]; } } @@ -813,9 +814,7 @@ function oe_theme_preprocess_paragraph__oe_list_item(array &$variables): void { $variables['variant'] = $list_item_variant ?? 'default'; $url = $paragraph->get('field_oe_link')->first()->getUrl(); $variables['url'] = $url; - if ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')) { - $variables['external_link'] = TRUE; - } + $variables['external_link'] = \Drupal::service('oe_theme_helper.external_links')->isExternalLink($url); $cacheability = CacheableMetadata::createFromRenderArray($variables); @@ -881,9 +880,7 @@ function oe_theme_preprocess_paragraph__oe_list_item_block(array &$variables): v $url = $link_item->getUrl(); $variables['button_url'] = $url; $variables['button_label'] = $link_item->get('title')->getValue(); - if ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')) { - $variables['external_link'] = TRUE; - } + $variables['external_link'] = \Drupal::service('oe_theme_helper.external_links')->isExternalLink($url); } /** @@ -1429,7 +1426,7 @@ function oe_theme_preprocess_pattern_link(array &$variables): void { // Extract attributes from the URL object and set them as default. if ($variables['url'] instanceof Url) { - $variables['external_link'] = ($variables['url']->isExternal() && !strpos(UrlHelper::parse($variables['url']->toString())['path'], 'europa.eu')); + $variables['external_link'] = \Drupal::service('oe_theme_helper.external_links')->isExternalLink($variables['url']); $attributes = (array) $variables['url']->getOption('attributes'); if (isset($attributes['class'])) { $variables['classes'] = implode(' ', $attributes['class']); @@ -1473,9 +1470,7 @@ function oe_theme_preprocess_paragraph__oe_facts_figures(array &$variables): voi $url = $paragraph->get('field_oe_link')->first()->getUrl(); $variables['view_all']['path'] = $paragraph->get('field_oe_link')->first()->getUrl(); $variables['view_all']['label'] = $paragraph->get('field_oe_link')->first()->get('title')->getValue(); - if ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')) { - $variables['external_link'] = TRUE; - } + $variables['external_link'] = \Drupal::service('oe_theme_helper.external_links')->isExternalLink($url); } $variables['items'] = []; @@ -1523,9 +1518,7 @@ function oe_theme_preprocess_paragraph__oe_banner(array &$variables): void { $url = $link->getUrl(); $variables['url'] = $url; $variables['label'] = $link->get('title')->getValue(); - if ($url->isExternal() && !strpos(UrlHelper::parse($url->toString())['path'], 'europa.eu')) { - $variables['external_link'] = TRUE; - } + $variables['external_link'] = \Drupal::service('oe_theme_helper.external_links')->isExternalLink($url); } $variables['full_width'] = (bool) $paragraph->get('field_oe_banner_full_width')->value; diff --git a/templates/compositions/ec-component-navigation-list/navigation-list.html.twig b/templates/compositions/ec-component-navigation-list/navigation-list.html.twig index 35fc27209..7afef3fc1 100644 --- a/templates/compositions/ec-component-navigation-list/navigation-list.html.twig +++ b/templates/compositions/ec-component-navigation-list/navigation-list.html.twig @@ -23,7 +23,7 @@ 'label': title, 'path': title_url, 'external': external_link, - 'icon_path': ecl_icon_path + 'icon_path': icon_path } } only %} {% else %} @@ -43,7 +43,7 @@ {% include '@ecl-twig/link' with { link: link.link|merge({ 'type': 'standalone', 'external': link.link.is_external, - 'icon_path': ecl_icon_path + 'icon_path': icon_path }) } only %} {% else %} {{ link.link.label }} @@ -61,7 +61,7 @@ {% include '@ecl-twig/link' with { link: link.link|merge({ 'type': 'standalone', 'external': link.link.is_external, - 'icon_path': ecl_icon_path + 'icon_path': icon_path }) } only %} {% else %} {{ link.link.label }} From b5bc1d8e3fe7e529a2f3e8ebac641f56721a8111 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Mon, 9 May 2022 10:23:02 +0300 Subject: [PATCH 20/42] EWPP-2069: Add config file to set internal domain regex. --- .../oe_theme_helper.internal_domains.yml | 1 + .../config/schema/oe_theme_helper.schema.yml | 7 +++ .../oe_theme_helper.services.yml | 3 +- modules/oe_theme_helper/src/ExternalLinks.php | 44 ++++++++++--------- .../src/TwigExtension/TwigExtension.php | 15 ++++++- .../tests/src/Unit/TwigExtensionTest.php | 13 +++++- tests/src/Kernel/AbstractKernelTestBase.php | 1 + 7 files changed, 59 insertions(+), 25 deletions(-) create mode 100644 modules/oe_theme_helper/config/install/oe_theme_helper.internal_domains.yml diff --git a/modules/oe_theme_helper/config/install/oe_theme_helper.internal_domains.yml b/modules/oe_theme_helper/config/install/oe_theme_helper.internal_domains.yml new file mode 100644 index 000000000..cb0c2c473 --- /dev/null +++ b/modules/oe_theme_helper/config/install/oe_theme_helper.internal_domains.yml @@ -0,0 +1 @@ +internal_domain: '' diff --git a/modules/oe_theme_helper/config/schema/oe_theme_helper.schema.yml b/modules/oe_theme_helper/config/schema/oe_theme_helper.schema.yml index 46ea42c25..4ea6ee806 100644 --- a/modules/oe_theme_helper/config/schema/oe_theme_helper.schema.yml +++ b/modules/oe_theme_helper/config/schema/oe_theme_helper.schema.yml @@ -111,3 +111,10 @@ condition.plugin.oe_theme_helper_current_component_library: mapping: component_library: type: string + +oe_theme_helper.internal_domains: + type: config_object + mapping: + internal_domain: + type: string + label: 'Regular expression to identify internal domains.' diff --git a/modules/oe_theme_helper/oe_theme_helper.services.yml b/modules/oe_theme_helper/oe_theme_helper.services.yml index 8259407aa..9f990d6b9 100644 --- a/modules/oe_theme_helper/oe_theme_helper.services.yml +++ b/modules/oe_theme_helper/oe_theme_helper.services.yml @@ -28,7 +28,7 @@ services: parent: default_plugin_manager oe_theme_helper.twig_extension.twig_extension: class: Drupal\oe_theme_helper\TwigExtension\TwigExtension - arguments: ['@language_manager', '@renderer'] + arguments: ['@language_manager', '@renderer', '@oe_theme_helper.external_links'] tags: - { name: twig.extension } oe_theme_helper.node_metadata_event_subscriber: @@ -42,3 +42,4 @@ services: arguments: ['@entity_type.bundle.info'] oe_theme_helper.external_links: class: Drupal\oe_theme_helper\ExternalLinks + arguments: ['@config.factory'] diff --git a/modules/oe_theme_helper/src/ExternalLinks.php b/modules/oe_theme_helper/src/ExternalLinks.php index 3b8c31680..77e575248 100644 --- a/modules/oe_theme_helper/src/ExternalLinks.php +++ b/modules/oe_theme_helper/src/ExternalLinks.php @@ -5,6 +5,7 @@ namespace Drupal\oe_theme_helper; use Drupal\Component\Utility\UrlHelper; +use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Url; /** @@ -12,6 +13,23 @@ */ class ExternalLinks implements ExternalLinksInterface { + /** + * The configuration factory. + * + * @var \Drupal\Core\Config\ConfigFactoryInterface + */ + protected $configFactory; + + /** + * Constructs an ExternalLinks object. + * + * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory + * The configuration factory. + */ + public function __construct(ConfigFactoryInterface $config_factory) { + $this->configFactory = $config_factory; + } + /** * {@inheritdoc} */ @@ -28,28 +46,12 @@ public function isExternalLink($url): bool { return $external; } - // If it's external link, make sure its domain is not considered internal. - $internal_domains = $this->internalDomains(); - foreach ($internal_domains as $internal_domain) { - if (strpos($path, $internal_domain)) { - $external = FALSE; - break; - } + // If it's an external link, make sure its domain is not internal. + $internal_domain_expression = $this->configFactory->get('oe_theme_helper.internal_domains')->get('internal_domain'); + if (!$internal_domain_expression) { + return $external; } - - return $external; - } - - /** - * Defines a list of domain considered internal. - * - * @return array|null - * The list of internal domains or NULL if there is none. - */ - protected function internalDomains(): ?array { - return [ - 'europa.eu', - ]; + return !preg_match_all($internal_domain_expression, $path); } } diff --git a/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php b/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php index 698cd4cd3..da01d999a 100644 --- a/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php +++ b/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php @@ -16,6 +16,7 @@ use Drupal\Core\Render\RendererInterface; use Drupal\Core\Template\Attribute; use Drupal\oe_theme_helper\EuropeanUnionLanguages; +use Drupal\oe_theme_helper\ExternalLinksInterface; use Drupal\smart_trim\Truncate\TruncateHTML; use Drupal\Core\Template\TwigExtension as CoreTwigExtension; use Twig\Environment; @@ -45,6 +46,13 @@ class TwigExtension extends AbstractExtension { */ protected $renderer; + /** + * The external links service. + * + * @var \Drupal\oe_theme_helper\ExternalLinksInterface + */ + protected $externalLinks; + /** * Constructs a new TwigExtension object. * @@ -52,10 +60,13 @@ class TwigExtension extends AbstractExtension { * The language manager. * @param \Drupal\Core\Render\RendererInterface $renderer * The renderer service. + * @param \Drupal\oe_theme_helper\ExternalLinksInterface $external_links + * The external links service. */ - public function __construct(LanguageManagerInterface $languageManager, RendererInterface $renderer) { + public function __construct(LanguageManagerInterface $languageManager, RendererInterface $renderer, ExternalLinksInterface $external_links) { $this->languageManager = $languageManager; $this->renderer = $renderer; + $this->externalLinks = $external_links; } /** @@ -535,7 +546,7 @@ public function getLinkIcon(array $context, string $path, string $size = 's'): a 'size' => $size, 'color' => 'primary', ]; - if (\Drupal::service('oe_theme_helper.external_links')->isExternalLink($path)) { + if ($this->externalLinks->isExternalLink($path)) { $icon['name'] = 'external'; } else { diff --git a/modules/oe_theme_helper/tests/src/Unit/TwigExtensionTest.php b/modules/oe_theme_helper/tests/src/Unit/TwigExtensionTest.php index 101324d0e..62fb954f4 100644 --- a/modules/oe_theme_helper/tests/src/Unit/TwigExtensionTest.php +++ b/modules/oe_theme_helper/tests/src/Unit/TwigExtensionTest.php @@ -9,6 +9,7 @@ use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\Render\Renderer; use Drupal\Core\Template\Loader\StringLoader; +use Drupal\oe_theme_helper\ExternalLinksInterface; use Drupal\oe_theme_helper\TwigExtension\TwigExtension; use Drupal\oe_theme_helper\EuropeanUnionLanguages; use Drupal\Tests\UnitTestCase; @@ -54,6 +55,13 @@ class TwigExtensionTest extends UnitTestCase { */ protected $twig; + /** + * The external links service. + * + * @var \Drupal\oe_theme_helper\ExternalLinksInterface + */ + protected $externalLinks; + /** * {@inheritdoc} */ @@ -79,8 +87,11 @@ protected function setUp(): void { // Create Renderer service mock. $this->renderer = $this->prophesize(Renderer::class); + // Create the external link service mock. + $this->externalLinks = $this->prophesize(ExternalLinksInterface::class); + // Instantiate the system under test. - $this->extension = new TwigExtension($this->languageManager->reveal(), $this->renderer->reveal()); + $this->extension = new TwigExtension($this->languageManager->reveal(), $this->renderer->reveal(), $this->externalLinks->reveal()); // For convenience, make a version of the Twig environment available that // has the tested extension preloaded. diff --git a/tests/src/Kernel/AbstractKernelTestBase.php b/tests/src/Kernel/AbstractKernelTestBase.php index 8b7ef87e0..063dc4792 100644 --- a/tests/src/Kernel/AbstractKernelTestBase.php +++ b/tests/src/Kernel/AbstractKernelTestBase.php @@ -52,6 +52,7 @@ protected function setUp(): void { $this->container->get('theme_installer')->install(['oe_theme']); $this->config('system.theme')->set('default', 'oe_theme')->save(); $this->container->set('theme.registry', NULL); + $this->config('oe_theme_helper.internal_domains')->set('internal_domain', '/(^|^[^:]+:\/\/|[^\.]+\.)europa\.eu/m')->save(); // @todo Drupal 9 ignores settings in settings.testing.php in kernel tests. // See https://www.drupal.org/project/drupal/issues/3190974. Need to From 4ee45b71cca029a74a130621fcff3767589f36ec Mon Sep 17 00:00:00 2001 From: Sergii Pavlenko Date: Tue, 10 May 2022 12:12:27 +0300 Subject: [PATCH 21/42] EWPP-2205: Allow description to be nullable in ListItemAssert. --- tests/src/PatternAssertions/ListItemAssert.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/src/PatternAssertions/ListItemAssert.php b/tests/src/PatternAssertions/ListItemAssert.php index 726343fc8..731ee760e 100644 --- a/tests/src/PatternAssertions/ListItemAssert.php +++ b/tests/src/PatternAssertions/ListItemAssert.php @@ -229,6 +229,10 @@ protected function assertHighlightImage($expected_image, string $variant, Crawle protected function assertDescription($expected, string $variant, Crawler $crawler): void { $base_selector = $this->getBaseItemClass($variant); $description_selector = 'div' . $base_selector . '__description'; + if (is_null($expected)) { + $this->assertElementNotExists($description_selector, $crawler); + return; + } $this->assertElementExists($description_selector, $crawler); $description_element = $crawler->filter($description_selector); if ($expected instanceof PatternAssertStateInterface) { From 78585b5b7834a5717c8dadfd62ab661f3233ce07 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Sun, 3 Apr 2022 15:46:03 +0300 Subject: [PATCH 22/42] EWPP-2072: Update node and custom entities link fields to render external icon. --- .../oe-theme-content-event-media.html.twig | 10 +++++++++- ...se-button--oe-consultation--full.html.twig | 4 +++- ...node--oe-event-website--oe-event.html.twig | 19 ++++++++++++++++++ ...nsparency-links--oe-person--full.html.twig | 14 ++++++++++++- ...de--oe-project-calls--oe-project.html.twig | 4 +++- ...--oe-project-website--oe-project.html.twig | 20 +++++++++++++++++++ .../field--oe-contact--oe-website.html.twig | 20 +++++++++++++++++++ ...tion--oe-website--oe-stakeholder.html.twig | 20 +++++++++++++++++++ .../Functional/ContentProjectRenderTest.php | 4 ++-- 9 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 templates/field/field--node--oe-event-website--oe-event.html.twig create mode 100644 templates/field/field--node--oe-project-website--oe-project.html.twig create mode 100644 templates/field/field--oe-contact--oe-website.html.twig create mode 100644 templates/field/field--oe-organisation--oe-website--oe-stakeholder.html.twig diff --git a/modules/oe_theme_content_event/templates/oe-theme-content-event-media.html.twig b/modules/oe_theme_content_event/templates/oe-theme-content-event-media.html.twig index fc089c32c..af7727b92 100644 --- a/modules/oe_theme_content_event/templates/oe-theme-content-event-media.html.twig +++ b/modules/oe_theme_content_event/templates/oe-theme-content-event-media.html.twig @@ -22,7 +22,15 @@ 'size': 's', } } %} - {% include '@ecl-twig/link' with _link only %} + {% include '@ecl-twig/link' with { + link: { + type: 'standalone', + label: items.media_more_link.title, + path: items.media_more_link.url, + icon_position: 'after' + }, + icon: get_link_icon(items.media_more_link.url.toString()) + } %} {% endif %} {% if items.media_more_description %}
    diff --git a/templates/field/field--node--oe-consultation-response-button--oe-consultation--full.html.twig b/templates/field/field--node--oe-consultation-response-button--oe-consultation--full.html.twig index caedbfb02..5c03e7ba7 100644 --- a/templates/field/field--node--oe-consultation-response-button--oe-consultation--full.html.twig +++ b/templates/field/field--node--oe-consultation-response-button--oe-consultation--full.html.twig @@ -13,7 +13,9 @@ type: 'cta', label: item.content['#title']|default('Respond to the questionnaire'|t), path: item.content['#url'], - } + icon_position: 'after' + }, + icon: get_link_icon(item.content['#url'].toString()) } %}
    {% endfor %} diff --git a/templates/field/field--node--oe-event-website--oe-event.html.twig b/templates/field/field--node--oe-event-website--oe-event.html.twig new file mode 100644 index 000000000..d86f74784 --- /dev/null +++ b/templates/field/field--node--oe-event-website--oe-event.html.twig @@ -0,0 +1,19 @@ +{# +/** + * @file + * Theme override for the Event website link field of Event CT. + * + * @see ./core/themes/stable/templates/field/field.html.twig + */ +#} +{% for item in items %} + {% include '@ecl-twig/link' with { + link: { + type: 'standalone', + label: item.content['#title'], + path: item.content['#url'], + icon_position: 'after' + }, + icon: get_link_icon(item.content['#url'].toString()) + } %} +{% endfor %} diff --git a/templates/field/field--node--oe-person-transparency-links--oe-person--full.html.twig b/templates/field/field--node--oe-person-transparency-links--oe-person--full.html.twig index 254d87cce..866c5fae6 100644 --- a/templates/field/field--node--oe-person-transparency-links--oe-person--full.html.twig +++ b/templates/field/field--node--oe-person-transparency-links--oe-person--full.html.twig @@ -6,4 +6,16 @@ * @see ./core/themes/stable/templates/field/field.html.twig */ #} -{% for item in items %}
    {{ item.content }}
    {% endfor %} +{% for item in items %} +
    + {% include '@ecl-twig/link' with { + link: { + type: 'standalone', + label: item.content['#title'], + path: item.content['#url'], + icon_position: 'after' + }, + icon: get_link_icon(item.content['#url'].toString()) + } %} +
    +{% endfor %} diff --git a/templates/field/field--node--oe-project-calls--oe-project.html.twig b/templates/field/field--node--oe-project-calls--oe-project.html.twig index d412f2def..7727c11a6 100644 --- a/templates/field/field--node--oe-project-calls--oe-project.html.twig +++ b/templates/field/field--node--oe-project-calls--oe-project.html.twig @@ -12,10 +12,12 @@
      {% for item in items %}
    • + {% set _external = (item.content['#url'].external and 'europa.eu' not in item.content['#url'].toString()) %} {{ pattern('list_item', { meta: [ uppercase_label ], url: item.content['#url'], - title: item.content['#title'] + title: item.content['#title'], + external_link: _external }) }}
    • {% endfor %} diff --git a/templates/field/field--node--oe-project-website--oe-project.html.twig b/templates/field/field--node--oe-project-website--oe-project.html.twig new file mode 100644 index 000000000..db231c97b --- /dev/null +++ b/templates/field/field--node--oe-project-website--oe-project.html.twig @@ -0,0 +1,20 @@ +{# +/** + * @file + * Theme override for the Project website field of the Project CT. + * + * @see ./core/themes/stable/templates/field/field.html.twig + */ +#} +{% for item in items %} + {% set bubble_cache = item.content|render %} + {% include '@ecl-twig/link' with { + link: { + type: 'standalone', + label: item.content['#title'], + path: item.content['#url'], + icon_position: 'after' + }, + icon: get_link_icon(item.content['#url'].toString()) + } %} +{% endfor %} diff --git a/templates/field/field--oe-contact--oe-website.html.twig b/templates/field/field--oe-contact--oe-website.html.twig new file mode 100644 index 000000000..122383951 --- /dev/null +++ b/templates/field/field--oe-contact--oe-website.html.twig @@ -0,0 +1,20 @@ +{# +/** + * @file + * Theme override for the Website field of the Contact entity. + * + * @see ./core/themes/stable/templates/field/field.html.twig + */ +#} +{% for item in items %} + {% set bubble_cache = item.content|render %} + {% include '@ecl-twig/link' with { + link: { + type: 'standalone', + label: item.content['#title'], + path: item.content['#url'], + icon_position: 'after' + }, + icon: get_link_icon(item.content['#url'].toString()) + } %} +{% endfor %} diff --git a/templates/field/field--oe-organisation--oe-website--oe-stakeholder.html.twig b/templates/field/field--oe-organisation--oe-website--oe-stakeholder.html.twig new file mode 100644 index 000000000..8e97256b4 --- /dev/null +++ b/templates/field/field--oe-organisation--oe-website--oe-stakeholder.html.twig @@ -0,0 +1,20 @@ +{# +/** + * @file + * Theme override for the Website field of the Organisation entity. + * + * @see ./core/themes/stable/templates/field/field.html.twig + */ +#} +{% for item in items %} + {% set bubble_cache = item.content|render %} + {% include '@ecl-twig/link' with { + link: { + type: 'standalone', + label: item.content['#url'].toString(), + path: item.content['#url'], + icon_position: 'after' + }, + icon: get_link_icon(item.content['#url'].toString()) + } %} +{% endfor %} diff --git a/tests/src/Functional/ContentProjectRenderTest.php b/tests/src/Functional/ContentProjectRenderTest.php index 96e967eb1..de30d85c4 100644 --- a/tests/src/Functional/ContentProjectRenderTest.php +++ b/tests/src/Functional/ContentProjectRenderTest.php @@ -377,10 +377,10 @@ protected function assertStakeholderOrganisationRendering(NodeElement $rendered_ $field_list_assert->assertVariant('horizontal', $field_list_html); // Assert contact link. - $contact_links = $rendered_stakeholder_element->findAll('css', '.ecl-link'); + $contact_links = $rendered_stakeholder_element->findAll('css', 'div.ecl-u-mt-l.ecl-u-type-bold a.ecl-link'); $this->assertCount(1, $contact_links); $this->assertStringContainsString("http://example.com/contact_$name", $contact_links[0]->getAttribute('href')); - $contact_link_labels = $rendered_stakeholder_element->findAll('css', '.ecl-link__label'); + $contact_link_labels = $rendered_stakeholder_element->findAll('css', 'div.ecl-u-mt-l.ecl-u-type-bold span.ecl-link__label'); $this->assertCount(1, $contact_link_labels); $this->assertEquals('Contact organisation', $contact_link_labels[0]->getText()); } From f3de7ccc9c105be4b0d1afdbc0b7757138d2fc65 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Mon, 4 Apr 2022 12:02:47 +0300 Subject: [PATCH 23/42] EWPP-2072: Update event extra fields to render external icon. --- ...me-content-event-online-description.html.twig | 8 +++++++- ...e-content-event-registration-button.html.twig | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/modules/oe_theme_content_event/templates/oe-theme-content-event-online-description.html.twig b/modules/oe_theme_content_event/templates/oe-theme-content-event-online-description.html.twig index 7376f7938..8c69ec0da 100644 --- a/modules/oe_theme_content_event/templates/oe-theme-content-event-online-description.html.twig +++ b/modules/oe_theme_content_event/templates/oe-theme-content-event-online-description.html.twig @@ -8,6 +8,12 @@ {% endif %} diff --git a/modules/oe_theme_content_event/templates/oe-theme-content-event-registration-button.html.twig b/modules/oe_theme_content_event/templates/oe-theme-content-event-registration-button.html.twig index 519ca01fd..62877c5a0 100644 --- a/modules/oe_theme_content_event/templates/oe-theme-content-event-registration-button.html.twig +++ b/modules/oe_theme_content_event/templates/oe-theme-content-event-registration-button.html.twig @@ -7,11 +7,23 @@
      {% if show_button %} {% if registration_day %} - {{ label }} + + {{ pattern('link', { + variant: 'cta', + text: label, + url: url + }) }} + {% else %} {% if enabled %} - {{ label }} + + {{ pattern('link', { + variant: 'cta', + text: label, + url: url + }) }} + {% else %} {% endif %} From fdb09df8a06e508e10fb98be86859aa0cad8a377 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Mon, 4 Apr 2022 17:47:32 +0300 Subject: [PATCH 24/42] EWPP-2072: Update test coverage. --- .../ContentConsultationRenderTest.php | 7 +++- .../src/Functional/ContentEventRenderTest.php | 34 ++++++++++++++----- .../Functional/ContentPersonRenderTest.php | 4 +++ .../Functional/ContentProjectRenderTest.php | 33 ++++++++++++++---- 4 files changed, 63 insertions(+), 15 deletions(-) diff --git a/tests/src/Functional/ContentConsultationRenderTest.php b/tests/src/Functional/ContentConsultationRenderTest.php index f09a66969..93cd1007c 100644 --- a/tests/src/Functional/ContentConsultationRenderTest.php +++ b/tests/src/Functional/ContentConsultationRenderTest.php @@ -554,8 +554,11 @@ public function testConsultationRendering(): void { ])->save(); $this->drupalGet($node->toUrl()); $respond_button = $content_items[3]->find('css', '.ecl-link.ecl-link--cta'); + $icon = $respond_button->find('css', 'svg.ecl-icon.ecl-icon--s.ecl-icon--rotate-90.ecl-icon--primary.ecl-link__icon'); + $this->assertEquals('', $icon->getHtml()); $this->assertEquals('Respond to the questionnaire', $respond_button->getText()); - // Add a link to respond button and assert default label. + // Add a link with title to respond button and assert the label is updated + // and the external icon is rendered. $node->set('oe_consultation_response_button', [ 'uri' => 'https://example.com', 'title' => 'Link text', @@ -563,6 +566,8 @@ public function testConsultationRendering(): void { $this->drupalGet($node->toUrl()); $respond_button = $content_items[3]->find('css', '.ecl-link.ecl-link--cta'); $this->assertEquals('Link text', $respond_button->getText()); + $icon = $respond_button->find('css', 'svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $this->assertEquals('', $icon->getHtml()); // Assert status "Closed". $static_time = new DrupalDateTime('2020-04-20 14:00:00', DateTimeItemInterface::STORAGE_TIMEZONE); diff --git a/tests/src/Functional/ContentEventRenderTest.php b/tests/src/Functional/ContentEventRenderTest.php index 813921c70..30bbf153d 100644 --- a/tests/src/Functional/ContentEventRenderTest.php +++ b/tests/src/Functional/ContentEventRenderTest.php @@ -449,6 +449,8 @@ public function testEventRendering(): void { 'body' => 'Event website', ]; $field_list_assert->assertPattern($field_list_expected_values, $practical_list_content->getOuterHtml()); + $event_website_link_icon = $this->assertSession()->elementExists('css', 'dl.ecl-description-list dd a.ecl-link svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $this->assertEquals('', $event_website_link_icon->getHtml()); // Assert "Registration capacity" field. $node->set('oe_event_registration_capacity', 'event registration capacity')->save(); @@ -476,7 +478,7 @@ public function testEventRendering(): void { $this->drupalGet($node->toUrl()); $registration_content = $this->assertSession()->elementExists('css', '#event-registration-block'); - $this->assertRegistrationButtonEnabled($registration_content, 'Register here', 'http://www.example.com/registation'); + $this->assertRegistrationButtonEnabled($registration_content, 'Register here', 'http://www.example.com/registation', TRUE); // Report or media content are not shown when event is still ongoing. $node->set('oe_event_report_summary', 'Event report summary'); @@ -556,17 +558,20 @@ public function testEventRendering(): void { $this->cronRun(); $this->drupalGet($node->toUrl()); - $this->assertRegistrationButtonEnabled($registration_content, 'Register here', 'http://www.example.com/registation'); + $this->assertRegistrationButtonEnabled($registration_content, 'Register here', 'http://www.example.com/registation', TRUE); $this->assertEquals('Book your seat, 1 day left to register, registration will end on 21 February 2020, 15:00 CET', $registration_info_content->getText()); // Assert "Registration date" field when registration will finish today in // one hour. + // Set the Registration URL to an internal path. + $node->set('oe_event_registration_url', 'https://www.europa.eu.com/registation'); + $node->save(); $static_time = new DrupalDateTime('2020-02-21 13:00:00', DateTimeItemInterface::STORAGE_TIMEZONE); $this->freezeTime($static_time); $this->cronRun(); $this->drupalGet($node->toUrl()); - $this->assertRegistrationButtonEnabled($registration_content, 'Register here', 'http://www.example.com/registation'); + $this->assertRegistrationButtonEnabled($registration_content, 'Register here', 'https://www.europa.eu.com/registation', FALSE); $this->assertEquals('Book your seat, the registration will end today, 21 February 2020, 15:00 CET', $registration_info_content->getText()); // Assert "Registration date" field in the past. @@ -590,9 +595,10 @@ public function testEventRendering(): void { $this->assertEquals('Livestream', $online_heading->getText()); $online_description = $this->assertSession()->elementExists('css', 'div > div:nth-of-type(1) > .ecl', $details_content); $this->assertEquals('Online event description', $online_description->getText()); - $online_button = $this->assertSession()->elementExists('css', 'a.ecl-u-mt-l.ecl-u-mb-l.ecl-link.ecl-link--cta.ecl-u-d-inline-block', $details_content); - $this->assertEquals('Link to online event', $online_button->getText()); + $online_button = $this->assertSession()->elementExists('css', 'span.ecl-u-mt-l.ecl-u-mb-l.ecl-u-d-inline-block a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after', $details_content); + $this->assertEquals('Link to online event', $online_button->find('css', 'span.ecl-link__label')->getText()); $this->assertEquals('http://www.example.com/online_link', $online_button->getAttribute('href')); + $this->assertEquals('', $online_button->find('css', 'svg.ecl-icon.ecl-icon--2xs.ecl-link__icon')->getHtml()); $description_summary = $this->assertSession()->elementExists('css', 'div > div:nth-of-type(2) .ecl', $details_content); $this->assertEquals('Event report summary', $description_summary->getText()); @@ -615,6 +621,8 @@ public function testEventRendering(): void { $this->assertEmpty($caption->find('css', '.ecl-gallery__meta')->getText()); // Assert media links. $this->assertSession()->linkExistsExact('Main link for media items'); + $more_media_link_icon = $this->assertSession()->elementExists('css', 'div#event-media a.ecl-link svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $this->assertEquals('', $more_media_link_icon->getHtml()); $this->assertSession()->pageTextContainsOnce('More media links'); // Assert that summary and description fields are not displayed anymore. @@ -1078,10 +1086,20 @@ public function testEventRendering(): void { * Button text. * @param string $link * Button link. + * @param bool $external + * Whether the registration link is external or not. */ - protected function assertRegistrationButtonEnabled(NodeElement $parent_element, string $text, string $link): void { - $rendered_button = $this->assertSession()->elementExists('css', 'a.ecl-u-mt-2xl.ecl-link.ecl-link--cta', $parent_element); - $this->assertEquals($text, $rendered_button->getText()); + protected function assertRegistrationButtonEnabled(NodeElement $parent_element, string $text, string $link, bool $external): void { + if ($external) { + $rendered_button = $this->assertSession()->elementExists('css', 'span.ecl-u-mt-2xl.ecl-u-d-inline-block a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after', $parent_element); + $this->assertEquals($text, $rendered_button->find('css', 'span.ecl-link__label')->getText()); + $this->assertEquals('', $rendered_button->find('css', 'svg.ecl-icon.ecl-icon--2xs.ecl-link__icon')->getHtml()); + } + else { + $this->assertSession()->elementNotExists('css', 'span.ecl-u-mt-2xl.ecl-u-d-inline-block a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after', $parent_element); + $rendered_button = $this->assertSession()->elementExists('css', 'a.ecl-link.ecl-link--cta', $parent_element); + $this->assertEquals($text, $rendered_button->getText()); + } $this->assertEquals($link, $rendered_button->getAttribute('href')); } diff --git a/tests/src/Functional/ContentPersonRenderTest.php b/tests/src/Functional/ContentPersonRenderTest.php index 38f948196..67a7cf061 100644 --- a/tests/src/Functional/ContentPersonRenderTest.php +++ b/tests/src/Functional/ContentPersonRenderTest.php @@ -347,8 +347,12 @@ public function testPersonRendering(): void { $this->assertCount(2, $transparency_links_items); $this->assertEquals('http://example.com/link_1', $transparency_links_items[0]->getAttribute('href')); $this->assertEquals('Person link 1', $transparency_links_items[0]->getText()); + $first_link_icon = $transparency_links_items[0]->find('css', 'a.ecl-link svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $this->assertEquals('', $first_link_icon->getHtml()); $this->assertEquals('http://example.com/link_2', $transparency_links_items[1]->getAttribute('href')); $this->assertEquals('http://example.com/link_2', $transparency_links_items[1]->getText()); + $second_link_icon = $transparency_links_items[1]->find('css', 'a.ecl-link svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $this->assertEquals('', $second_link_icon->getHtml()); // Assert Biography introduction field. $node->set('oe_person_biography_intro', 'Biography introduction text')->save(); diff --git a/tests/src/Functional/ContentProjectRenderTest.php b/tests/src/Functional/ContentProjectRenderTest.php index de30d85c4..13f56245b 100644 --- a/tests/src/Functional/ContentProjectRenderTest.php +++ b/tests/src/Functional/ContentProjectRenderTest.php @@ -85,6 +85,10 @@ public function testProjectRendering(): void { [ 'uri' => 'http://proposal-call-no-title.com', ], + [ + 'uri' => 'http://ec.europa.eu/info', + 'title' => 'Internal Call for proposal', + ], ], 'oe_project_results' => 'Project results...', 'oe_project_result_files' => [ @@ -223,6 +227,8 @@ public function testProjectRendering(): void { $field_list_html = $description_lists[2]->getHtml(); $field_list_assert->assertPattern($third_field_list_expected_values, $field_list_html); $field_list_assert->assertVariant('featured_horizontal', $field_list_html); + $project_website_icon = $this->assertSession()->elementExists('css', 'dl.ecl-description-list dd a.ecl-link svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $this->assertEquals('', $project_website_icon->getHtml()); // Assert documents file. $file_wrapper = $this->assertSession()->elementExists('css', 'div#project-documents'); @@ -249,9 +255,10 @@ public function testProjectRendering(): void { $this->assertListItem($funding_items[0], 'Anti Fraud Information System (AFIS)', 'Funding programme'); $proposal_items = $unordered_list_items[1]->findAll('css', '.ecl-unordered-list__item'); - $this->assertCount(2, $proposal_items); - $this->assertListItem($proposal_items[0], 'Test call for proposal', 'Call for proposals', 'http://proposal-call.com'); - $this->assertListItem($proposal_items[1], 'http://proposal-call-no-title.com', 'Call for proposals', 'http://proposal-call-no-title.com'); + $this->assertCount(3, $proposal_items); + $this->assertListItem($proposal_items[0], 'Test call for proposal', 'Call for proposals', 'http://proposal-call.com', TRUE); + $this->assertListItem($proposal_items[1], 'http://proposal-call-no-title.com', 'Call for proposals', 'http://proposal-call-no-title.com', TRUE); + $this->assertListItem($proposal_items[2], 'Internal Call for proposal', 'Call for proposals', 'http://ec.europa.eu/info'); // Assert bottom region - Stakeholders. $project_stakeholders = $this->assertSession()->elementExists('css', 'div#project-stakeholders'); @@ -375,11 +382,16 @@ protected function assertStakeholderOrganisationRendering(NodeElement $rendered_ $field_list_html = $field_list_wrapper->getHtml(); $field_list_assert->assertPattern($first_field_list_expected_values, $field_list_html); $field_list_assert->assertVariant('horizontal', $field_list_html); + // Assert contact website's icon. + $website_icon = $field_list_wrapper->find('css', 'dl.ecl-description-list dd a.ecl-link'); + $this->assertEquals('', $website_icon->find('css', 'svg.ecl-icon.ecl-icon--s.ecl-link__icon')->getHtml()); // Assert contact link. - $contact_links = $rendered_stakeholder_element->findAll('css', 'div.ecl-u-mt-l.ecl-u-type-bold a.ecl-link'); + $contact_links = $rendered_stakeholder_element->findAll('css', 'div.ecl-u-mt-l.ecl-u-type-bold a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after'); $this->assertCount(1, $contact_links); $this->assertStringContainsString("http://example.com/contact_$name", $contact_links[0]->getAttribute('href')); + // Assert contact link's icon. + $this->assertEquals('', $contact_links[0]->find('css', 'svg.ecl-icon.ecl-icon--s.ecl-link__icon')->getHtml()); $contact_link_labels = $rendered_stakeholder_element->findAll('css', 'div.ecl-u-mt-l.ecl-u-type-bold span.ecl-link__label'); $this->assertCount(1, $contact_link_labels); $this->assertEquals('Contact organisation', $contact_link_labels[0]->getText()); @@ -396,10 +408,12 @@ protected function assertStakeholderOrganisationRendering(NodeElement $rendered_ * Meta value of the list item. * @param string $link * Link that is used. + * @param bool $external_link + * Whether the link is external or not. * * @throws \Behat\Mink\Exception\ElementNotFoundException */ - protected function assertListItem(NodeElement $rendered_element, string $title, string $meta, $link = ''): void { + protected function assertListItem(NodeElement $rendered_element, string $title, string $meta, $link = '', bool $external_link = FALSE): void { $list_item_assert = new ListItemAssert(); $expected_values = [ 'meta' => $meta, @@ -414,7 +428,14 @@ protected function assertListItem(NodeElement $rendered_element, string $title, $this->assertEquals($meta, $field_meta->getText()); if (!empty($link)) { - $link_tag = $rendered_element->find('css', '.ecl-link'); + if ($external_link) { + $link_tag = $rendered_element->find('css', 'a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after'); + $this->assertEquals('', $link_tag->find('css', 'svg.ecl-icon.ecl-icon--2xs.ecl-link__icon')->getHtml()); + } + else { + $this->assertSession()->elementNotExists('css', 'svg.ecl-icon.ecl-icon--s.ecl-link__icon', $rendered_element); + $link_tag = $rendered_element->find('css', '.ecl-link'); + } $this->assertEquals($link, $link_tag->getAttribute('href')); } } From 179fa85b26e21ae57ddb0e7549314485af3789d4 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Tue, 10 May 2022 13:33:18 +0300 Subject: [PATCH 25/42] EWPP-2072: Adapt field templates to use the ecl external parameter. --- .../Display/OnlineDescriptionExtraField.php | 12 +++++++++++- .../oe-theme-content-event-media.html.twig | 17 +++-------------- ...e-content-event-online-description.html.twig | 14 +++++++------- ...-content-event-registration-button.html.twig | 8 ++++++-- .../src/TwigExtension/TwigExtension.php | 16 ++++++++++++++-- ...onse-button--oe-consultation--full.html.twig | 6 +++--- ...--node--oe-event-website--oe-event.html.twig | 6 +++--- ...ransparency-links--oe-person--full.html.twig | 6 +++--- ...node--oe-project-calls--oe-project.html.twig | 3 +-- ...de--oe-project-website--oe-project.html.twig | 6 +++--- .../field--oe-contact--oe-website.html.twig | 6 +++--- ...sation--oe-website--oe-stakeholder.html.twig | 6 +++--- .../ContentConsultationRenderTest.php | 11 +---------- tests/src/Functional/ContentEventRenderTest.php | 15 ++++----------- .../src/Functional/ContentPersonRenderTest.php | 10 ++-------- .../src/Functional/ContentProjectRenderTest.php | 9 ++------- tests/src/Functional/ContentRenderTestBase.php | 16 ++++++++++++++++ 17 files changed, 85 insertions(+), 82 deletions(-) diff --git a/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/OnlineDescriptionExtraField.php b/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/OnlineDescriptionExtraField.php index 160dba47c..75c0ae297 100644 --- a/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/OnlineDescriptionExtraField.php +++ b/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/OnlineDescriptionExtraField.php @@ -66,7 +66,17 @@ public function viewElements(ContentEntityInterface $entity) { /** @var \Drupal\link\Plugin\Field\FieldType\LinkItem $link */ $link = $entity->get('oe_event_online_link')->first(); $value = $link->getValue(); - $build['#url'] = $link->getUrl(); + $url = $link->getUrl(); + $url->setOptions([ + 'attributes' => [ + 'class' => [ + 'ecl-u-mt-l', + 'ecl-u-mb-l', + 'ecl-u-d-inline-block', + ], + ], + ]); + $build['#url'] = $url; $build['#label'] = $value['title']; return $build; diff --git a/modules/oe_theme_content_event/templates/oe-theme-content-event-media.html.twig b/modules/oe_theme_content_event/templates/oe-theme-content-event-media.html.twig index af7727b92..4b76b35b2 100644 --- a/modules/oe_theme_content_event/templates/oe-theme-content-event-media.html.twig +++ b/modules/oe_theme_content_event/templates/oe-theme-content-event-media.html.twig @@ -15,22 +15,11 @@ type: 'standalone', label: items.media_more_link.title, path: items.media_more_link.url, - }, - icon: { - 'path': ecl_icon_path, - 'name': 'external', - 'size': 's', + external: items.media_more_link.url.toString()|is_external_url, + icon_path: ecl_icon_path } } %} - {% include '@ecl-twig/link' with { - link: { - type: 'standalone', - label: items.media_more_link.title, - path: items.media_more_link.url, - icon_position: 'after' - }, - icon: get_link_icon(items.media_more_link.url.toString()) - } %} + {% include '@ecl-twig/link' with _link only %} {% endif %} {% if items.media_more_description %}
      diff --git a/modules/oe_theme_content_event/templates/oe-theme-content-event-online-description.html.twig b/modules/oe_theme_content_event/templates/oe-theme-content-event-online-description.html.twig index 8c69ec0da..8f1f76e3c 100644 --- a/modules/oe_theme_content_event/templates/oe-theme-content-event-online-description.html.twig +++ b/modules/oe_theme_content_event/templates/oe-theme-content-event-online-description.html.twig @@ -8,12 +8,12 @@ {% endif %} diff --git a/modules/oe_theme_content_event/templates/oe-theme-content-event-registration-button.html.twig b/modules/oe_theme_content_event/templates/oe-theme-content-event-registration-button.html.twig index 62877c5a0..e8c1b71c4 100644 --- a/modules/oe_theme_content_event/templates/oe-theme-content-event-registration-button.html.twig +++ b/modules/oe_theme_content_event/templates/oe-theme-content-event-registration-button.html.twig @@ -11,7 +11,9 @@ {{ pattern('link', { variant: 'cta', text: label, - url: url + url: url, + external_link: url.toString()|is_external_url, + icon_path: ecl_icon_path }) }} @@ -21,7 +23,9 @@ {{ pattern('link', { variant: 'cta', text: label, - url: url + url: url, + external_link: url.toString()|is_external_url, + icon_path: ecl_icon_path }) }} {% else %} diff --git a/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php b/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php index da01d999a..fd3470a5d 100644 --- a/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php +++ b/modules/oe_theme_helper/src/TwigExtension/TwigExtension.php @@ -5,7 +5,6 @@ namespace Drupal\oe_theme_helper\TwigExtension; use Drupal\Component\Render\MarkupInterface; -use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Language\LanguageManager; use Drupal\Core\Language\LanguageManagerInterface; @@ -82,7 +81,7 @@ public function getFilters(): array { new TwigFilter('to_date_status', [$this, 'toDateStatus']), new TwigFilter('to_ecl_attributes', [$this, 'toEclAttributes']), new TwigFilter('smart_trim', [$this, 'smartTrim'], ['needs_environment' => TRUE]), - new TwigFilter('is_external_url', [UrlHelper::class, 'isExternal']), + new TwigFilter('is_external_url', [$this, 'isExternal']), new TwigFilter('filter_empty', [$this, 'filterEmpty']), new TwigFilter('create_markup', [$this, 'createMarkup']), ]; @@ -606,6 +605,19 @@ public function eclFooterLinks(array $context, array $links): array { return $ecl_links; } + /** + * Checks if a given path is external or not. + * + * @param string $path + * The path to be checked. + * + * @return bool + * Whether the path is external. + */ + public function isExternal(string $path): bool { + return $this->externalLinks->isExternalLink($path); + } + /** * Creates a Markup object. * diff --git a/templates/field/field--node--oe-consultation-response-button--oe-consultation--full.html.twig b/templates/field/field--node--oe-consultation-response-button--oe-consultation--full.html.twig index 5c03e7ba7..147af62a8 100644 --- a/templates/field/field--node--oe-consultation-response-button--oe-consultation--full.html.twig +++ b/templates/field/field--node--oe-consultation-response-button--oe-consultation--full.html.twig @@ -13,9 +13,9 @@ type: 'cta', label: item.content['#title']|default('Respond to the questionnaire'|t), path: item.content['#url'], - icon_position: 'after' - }, - icon: get_link_icon(item.content['#url'].toString()) + external: item.content['#url'].toString()|is_external_url, + icon_path: ecl_icon_path + } } %}
      {% endfor %} diff --git a/templates/field/field--node--oe-event-website--oe-event.html.twig b/templates/field/field--node--oe-event-website--oe-event.html.twig index d86f74784..9518365f7 100644 --- a/templates/field/field--node--oe-event-website--oe-event.html.twig +++ b/templates/field/field--node--oe-event-website--oe-event.html.twig @@ -12,8 +12,8 @@ type: 'standalone', label: item.content['#title'], path: item.content['#url'], - icon_position: 'after' - }, - icon: get_link_icon(item.content['#url'].toString()) + external: item.content['#url'].toString()|is_external_url, + icon_path: ecl_icon_path + } } %} {% endfor %} diff --git a/templates/field/field--node--oe-person-transparency-links--oe-person--full.html.twig b/templates/field/field--node--oe-person-transparency-links--oe-person--full.html.twig index 866c5fae6..e63ab8ddf 100644 --- a/templates/field/field--node--oe-person-transparency-links--oe-person--full.html.twig +++ b/templates/field/field--node--oe-person-transparency-links--oe-person--full.html.twig @@ -13,9 +13,9 @@ type: 'standalone', label: item.content['#title'], path: item.content['#url'], - icon_position: 'after' - }, - icon: get_link_icon(item.content['#url'].toString()) + external: item.content['#url'].toString()|is_external_url, + icon_path: ecl_icon_path + } } %}
      {% endfor %} diff --git a/templates/field/field--node--oe-project-calls--oe-project.html.twig b/templates/field/field--node--oe-project-calls--oe-project.html.twig index 7727c11a6..2c5310ed2 100644 --- a/templates/field/field--node--oe-project-calls--oe-project.html.twig +++ b/templates/field/field--node--oe-project-calls--oe-project.html.twig @@ -12,12 +12,11 @@
        {% for item in items %}
      • - {% set _external = (item.content['#url'].external and 'europa.eu' not in item.content['#url'].toString()) %} {{ pattern('list_item', { meta: [ uppercase_label ], url: item.content['#url'], title: item.content['#title'], - external_link: _external + external_link: item.content['#url'].toString()|is_external_url }) }}
      • {% endfor %} diff --git a/templates/field/field--node--oe-project-website--oe-project.html.twig b/templates/field/field--node--oe-project-website--oe-project.html.twig index db231c97b..146162658 100644 --- a/templates/field/field--node--oe-project-website--oe-project.html.twig +++ b/templates/field/field--node--oe-project-website--oe-project.html.twig @@ -13,8 +13,8 @@ type: 'standalone', label: item.content['#title'], path: item.content['#url'], - icon_position: 'after' - }, - icon: get_link_icon(item.content['#url'].toString()) + external: item.content['#url'].toString()|is_external_url, + icon_path: ecl_icon_path + } } %} {% endfor %} diff --git a/templates/field/field--oe-contact--oe-website.html.twig b/templates/field/field--oe-contact--oe-website.html.twig index 122383951..e136e7d8b 100644 --- a/templates/field/field--oe-contact--oe-website.html.twig +++ b/templates/field/field--oe-contact--oe-website.html.twig @@ -13,8 +13,8 @@ type: 'standalone', label: item.content['#title'], path: item.content['#url'], - icon_position: 'after' - }, - icon: get_link_icon(item.content['#url'].toString()) + external: item.content['#url'].toString()|is_external_url, + icon_path: ecl_icon_path + } } %} {% endfor %} diff --git a/templates/field/field--oe-organisation--oe-website--oe-stakeholder.html.twig b/templates/field/field--oe-organisation--oe-website--oe-stakeholder.html.twig index 8e97256b4..7a678d7f1 100644 --- a/templates/field/field--oe-organisation--oe-website--oe-stakeholder.html.twig +++ b/templates/field/field--oe-organisation--oe-website--oe-stakeholder.html.twig @@ -13,8 +13,8 @@ type: 'standalone', label: item.content['#url'].toString(), path: item.content['#url'], - icon_position: 'after' - }, - icon: get_link_icon(item.content['#url'].toString()) + external: item.content['#url'].toString()|is_external_url, + icon_path: ecl_icon_path + } } %} {% endfor %} diff --git a/tests/src/Functional/ContentConsultationRenderTest.php b/tests/src/Functional/ContentConsultationRenderTest.php index 93cd1007c..cc70538e1 100644 --- a/tests/src/Functional/ContentConsultationRenderTest.php +++ b/tests/src/Functional/ContentConsultationRenderTest.php @@ -29,13 +29,6 @@ class ContentConsultationRenderTest extends ContentRenderTestBase { * {@inheritdoc} */ protected static $modules = [ - 'config', - 'datetime_testing', - 'block', - 'system', - 'path', - 'field_group', - 'oe_theme_helper', 'oe_theme_content_consultation', ]; @@ -554,8 +547,6 @@ public function testConsultationRendering(): void { ])->save(); $this->drupalGet($node->toUrl()); $respond_button = $content_items[3]->find('css', '.ecl-link.ecl-link--cta'); - $icon = $respond_button->find('css', 'svg.ecl-icon.ecl-icon--s.ecl-icon--rotate-90.ecl-icon--primary.ecl-link__icon'); - $this->assertEquals('', $icon->getHtml()); $this->assertEquals('Respond to the questionnaire', $respond_button->getText()); // Add a link with title to respond button and assert the label is updated // and the external icon is rendered. @@ -566,7 +557,7 @@ public function testConsultationRendering(): void { $this->drupalGet($node->toUrl()); $respond_button = $content_items[3]->find('css', '.ecl-link.ecl-link--cta'); $this->assertEquals('Link text', $respond_button->getText()); - $icon = $respond_button->find('css', 'svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $icon = $respond_button->find('css', 'svg.ecl-icon.ecl-icon--2xs.ecl-link__icon'); $this->assertEquals('', $icon->getHtml()); // Assert status "Closed". diff --git a/tests/src/Functional/ContentEventRenderTest.php b/tests/src/Functional/ContentEventRenderTest.php index 30bbf153d..322064566 100644 --- a/tests/src/Functional/ContentEventRenderTest.php +++ b/tests/src/Functional/ContentEventRenderTest.php @@ -35,16 +35,9 @@ class ContentEventRenderTest extends ContentRenderTestBase { * {@inheritdoc} */ public static $modules = [ - 'config', - 'content_translation', - 'datetime_testing', - 'block', - 'system', - 'oe_theme_helper', 'oe_theme_content_event', 'oe_content_event_person_reference', 'oe_multilingual', - 'path', ]; /** @@ -449,7 +442,7 @@ public function testEventRendering(): void { 'body' => 'Event website', ]; $field_list_assert->assertPattern($field_list_expected_values, $practical_list_content->getOuterHtml()); - $event_website_link_icon = $this->assertSession()->elementExists('css', 'dl.ecl-description-list dd a.ecl-link svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $event_website_link_icon = $this->assertSession()->elementExists('css', 'dl.ecl-description-list dd a.ecl-link svg.ecl-icon.ecl-icon--2xs.ecl-link__icon'); $this->assertEquals('', $event_website_link_icon->getHtml()); // Assert "Registration capacity" field. @@ -595,7 +588,7 @@ public function testEventRendering(): void { $this->assertEquals('Livestream', $online_heading->getText()); $online_description = $this->assertSession()->elementExists('css', 'div > div:nth-of-type(1) > .ecl', $details_content); $this->assertEquals('Online event description', $online_description->getText()); - $online_button = $this->assertSession()->elementExists('css', 'span.ecl-u-mt-l.ecl-u-mb-l.ecl-u-d-inline-block a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after', $details_content); + $online_button = $this->assertSession()->elementExists('css', 'a.ecl-link.ecl-link--cta.ecl-link--icon.ecl-link--icon-after.ecl-u-mt-l.ecl-u-mb-l.ecl-u-d-inline-block', $details_content); $this->assertEquals('Link to online event', $online_button->find('css', 'span.ecl-link__label')->getText()); $this->assertEquals('http://www.example.com/online_link', $online_button->getAttribute('href')); $this->assertEquals('', $online_button->find('css', 'svg.ecl-icon.ecl-icon--2xs.ecl-link__icon')->getHtml()); @@ -621,7 +614,7 @@ public function testEventRendering(): void { $this->assertEmpty($caption->find('css', '.ecl-gallery__meta')->getText()); // Assert media links. $this->assertSession()->linkExistsExact('Main link for media items'); - $more_media_link_icon = $this->assertSession()->elementExists('css', 'div#event-media a.ecl-link svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $more_media_link_icon = $this->assertSession()->elementExists('css', 'div#event-media a.ecl-link svg.ecl-icon.ecl-icon--2xs.ecl-link__icon'); $this->assertEquals('', $more_media_link_icon->getHtml()); $this->assertSession()->pageTextContainsOnce('More media links'); @@ -1087,7 +1080,7 @@ public function testEventRendering(): void { * @param string $link * Button link. * @param bool $external - * Whether the registration link is external or not. + * Whether the registration link is external. */ protected function assertRegistrationButtonEnabled(NodeElement $parent_element, string $text, string $link, bool $external): void { if ($external) { diff --git a/tests/src/Functional/ContentPersonRenderTest.php b/tests/src/Functional/ContentPersonRenderTest.php index 67a7cf061..f55487692 100644 --- a/tests/src/Functional/ContentPersonRenderTest.php +++ b/tests/src/Functional/ContentPersonRenderTest.php @@ -31,12 +31,6 @@ class ContentPersonRenderTest extends ContentRenderTestBase { * {@inheritdoc} */ protected static $modules = [ - 'config', - 'block', - 'system', - 'path', - 'field_group', - 'oe_theme_helper', 'oe_theme_content_person', ]; @@ -347,11 +341,11 @@ public function testPersonRendering(): void { $this->assertCount(2, $transparency_links_items); $this->assertEquals('http://example.com/link_1', $transparency_links_items[0]->getAttribute('href')); $this->assertEquals('Person link 1', $transparency_links_items[0]->getText()); - $first_link_icon = $transparency_links_items[0]->find('css', 'a.ecl-link svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $first_link_icon = $transparency_links_items[0]->find('css', 'a.ecl-link svg.ecl-icon.ecl-icon--2xs.ecl-link__icon'); $this->assertEquals('', $first_link_icon->getHtml()); $this->assertEquals('http://example.com/link_2', $transparency_links_items[1]->getAttribute('href')); $this->assertEquals('http://example.com/link_2', $transparency_links_items[1]->getText()); - $second_link_icon = $transparency_links_items[1]->find('css', 'a.ecl-link svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $second_link_icon = $transparency_links_items[1]->find('css', 'a.ecl-link svg.ecl-icon.ecl-icon--2xs.ecl-link__icon'); $this->assertEquals('', $second_link_icon->getHtml()); // Assert Biography introduction field. diff --git a/tests/src/Functional/ContentProjectRenderTest.php b/tests/src/Functional/ContentProjectRenderTest.php index 13f56245b..671018bfd 100644 --- a/tests/src/Functional/ContentProjectRenderTest.php +++ b/tests/src/Functional/ContentProjectRenderTest.php @@ -24,13 +24,8 @@ class ContentProjectRenderTest extends ContentRenderTestBase { * {@inheritdoc} */ public static $modules = [ - 'config', - 'system', - 'oe_theme_helper', - 'path', 'oe_theme_content_entity_contact', 'oe_theme_content_project', - 'block', 'options', ]; @@ -227,7 +222,7 @@ public function testProjectRendering(): void { $field_list_html = $description_lists[2]->getHtml(); $field_list_assert->assertPattern($third_field_list_expected_values, $field_list_html); $field_list_assert->assertVariant('featured_horizontal', $field_list_html); - $project_website_icon = $this->assertSession()->elementExists('css', 'dl.ecl-description-list dd a.ecl-link svg.ecl-icon.ecl-icon--s.ecl-icon--primary.ecl-link__icon'); + $project_website_icon = $this->assertSession()->elementExists('css', 'dl.ecl-description-list dd a.ecl-link svg.ecl-icon.ecl-icon--2xs.ecl-link__icon'); $this->assertEquals('', $project_website_icon->getHtml()); // Assert documents file. @@ -384,7 +379,7 @@ protected function assertStakeholderOrganisationRendering(NodeElement $rendered_ $field_list_assert->assertVariant('horizontal', $field_list_html); // Assert contact website's icon. $website_icon = $field_list_wrapper->find('css', 'dl.ecl-description-list dd a.ecl-link'); - $this->assertEquals('', $website_icon->find('css', 'svg.ecl-icon.ecl-icon--s.ecl-link__icon')->getHtml()); + $this->assertEquals('', $website_icon->find('css', 'svg.ecl-icon.ecl-icon--2xs.ecl-link__icon')->getHtml()); // Assert contact link. $contact_links = $rendered_stakeholder_element->findAll('css', 'div.ecl-u-mt-l.ecl-u-type-bold a.ecl-link.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after'); diff --git a/tests/src/Functional/ContentRenderTestBase.php b/tests/src/Functional/ContentRenderTestBase.php index 9b79421e3..0a018d5c5 100644 --- a/tests/src/Functional/ContentRenderTestBase.php +++ b/tests/src/Functional/ContentRenderTestBase.php @@ -25,6 +25,20 @@ */ abstract class ContentRenderTestBase extends BrowserTestBase { + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'content_translation', + 'config', + 'datetime_testing', + 'block', + 'system', + 'path', + 'field_group', + 'oe_theme_helper', + ]; + /** * {@inheritdoc} */ @@ -51,6 +65,8 @@ protected function setUp(): void { Role::load(RoleInterface::ANONYMOUS_ID) ->grantPermission('view published skos concept entities') ->save(); + + $this->config('oe_theme_helper.internal_domains')->set('internal_domain', '/(^|^[^:]+:\/\/|[^\.]+\.)europa\.eu/m')->save(); } /** From 430179a9db1a86d3e17ca1509a39340a6f973042 Mon Sep 17 00:00:00 2001 From: nagyad Date: Wed, 18 May 2022 10:40:36 +0200 Subject: [PATCH 26/42] EWPP-2071: Add external icon to external custom footer links. This reverts commit 3355d04cb9e91c6673e2c7bac6cf4d480515f2ad. --- oe_theme.theme | 43 +++++ .../Functional/CorporateFooterRenderTest.php | 148 +++++++++++++++--- 2 files changed, 167 insertions(+), 24 deletions(-) diff --git a/oe_theme.theme b/oe_theme.theme index c7d8837e4..01c92e254 100644 --- a/oe_theme.theme +++ b/oe_theme.theme @@ -9,6 +9,7 @@ declare(strict_types = 1); use Drupal\block\BlockInterface; use Drupal\Component\Utility\Html; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Entity\ContentEntityInterface; @@ -1710,6 +1711,13 @@ function oe_theme_theme_suggestions_oe_corporate_blocks_eu_footer_alter(array &$ $suggestions[] = 'oe_corporate_blocks_eu_footer__' . $branding; } +/** + * Implements hook_preprocess_HOOK(). + */ +function oe_theme_preprocess_oe_corporate_blocks_ec_footer(array &$variables) { + _oe_theme_preprocess_site_specific_footer_links($variables); +} + /** * Implements hook_preprocess_HOOK(). */ @@ -1728,6 +1736,41 @@ function oe_theme_preprocess_oe_corporate_blocks_eu_footer(array &$variables) { $site_logo_href .= '/index_' . EuropeanUnionLanguages::getInternalLanguageCode($variables['current_language_id']); } $variables['path'] = $site_logo_href; + + _oe_theme_preprocess_site_specific_footer_links($variables); +} + +/** + * Helper function to preprocess footer links and set external flag to them. + * + * @param array $variables + * The variables array from the preprocess hook. + */ +function _oe_theme_preprocess_site_specific_footer_links(array &$variables): void { + if (empty($variables['site_specific_footer']['other_links'])) { + return; + } + + foreach ($variables['site_specific_footer']['other_links'] as $section => $links) { + if (empty($links['links'])) { + continue; + } + + foreach ($links['links'] as $index => $link) { + if (!$link['href'] instanceof Url) { + continue; + } + + if ($link['href']->isExternal()) { + $parts = UrlHelper::parse($link['href']->toString()); + if (strpos($parts['path'], 'europa.eu')) { + // We consider links with europa.eu domains as internal. + continue; + } + $variables['site_specific_footer']['other_links'][$section]['links'][$index]['external'] = TRUE; + } + } + } } /** diff --git a/tests/src/Functional/CorporateFooterRenderTest.php b/tests/src/Functional/CorporateFooterRenderTest.php index 3dcb565e7..67c694c33 100644 --- a/tests/src/Functional/CorporateFooterRenderTest.php +++ b/tests/src/Functional/CorporateFooterRenderTest.php @@ -339,7 +339,7 @@ public function testCorporateFooterRendering(): void { $this->assertListLink($actual, 'standardised', $expected); } - // Add a few custom footer links, one by one to assert section distripution. + // Add a few custom footer links, one by one to assert section distribution. $this->createGeneralLink('Custom contact 1', 'contact_us'); $this->drupalGet(''); @@ -356,7 +356,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom contact 1', 'href' => 'http://example.com/custom-contact-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external svg icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); $assert->elementNotExists('css', 'footer.ecl-footer-standardised div.ecl-footer-standardised__row:nth-child(1) div.ecl-footer-standardised__column:nth-child(3) div.ecl-footer-standardised__section:nth-child(1)'); @@ -375,7 +378,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom contact 1', 'href' => 'http://example.com/custom-contact-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); $column = $assert->elementExists('css', 'footer.ecl-footer-standardised div.ecl-footer-standardised__row:nth-child(1) div.ecl-footer-standardised__column:nth-child(3)'); $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(1)', $column); @@ -388,7 +394,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom about 1', 'href' => 'http://example.com/custom-about-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); // Add one more, assert odd goes into column 2, even goes into column 3. $this->createGeneralLink('Custom related 1', 'related_sites'); @@ -405,7 +414,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom contact 1', 'href' => 'http://example.com/custom-contact-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(2)', $column); @@ -417,7 +429,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom related 1', 'href' => 'http://example.com/custom-related-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); $column = $assert->elementExists('css', 'footer.ecl-footer-standardised div.ecl-footer-standardised__row:nth-child(1) div.ecl-footer-standardised__column:nth-child(3)'); $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(1)', $column); @@ -430,7 +445,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom about 1', 'href' => 'http://example.com/custom-about-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); // Add the follow us, assert it goes last, into the centre column. // We have 3 sub-sections plus follow, distribution should be 2 and 2. @@ -449,7 +467,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom contact 1', 'href' => 'http://example.com/custom-contact-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(2)', $column); @@ -485,7 +506,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom about 1', 'href' => 'http://example.com/custom-about-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); // Assert previous last in section 2 moved to the right into section 3. $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(2)', $column); @@ -498,7 +522,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom related 1', 'href' => 'http://example.com/custom-related-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); // Assert adding a custom section in backend appears, // and is placed in the footer on the right column. @@ -517,7 +544,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom contact 1', 'href' => 'http://example.com/custom-contact-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); // Since we have an even number there is no switch, // assert Related is back in section 2. @@ -531,7 +561,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom related 1', 'href' => 'http://example.com/custom-related-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); // Here we assert Follow us is still on the left in section 2. $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(3)', $column); @@ -568,7 +601,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom about 1', 'href' => 'http://example.com/custom-about-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(2)', $column); @@ -580,7 +616,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom link 1', 'href' => 'http://example.com/custom-link-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); // Assert updating a general link also changes the footer content. $this->updateGeneralLink('custom-link-1', [ @@ -600,7 +639,32 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom link altered', 'href' => 'http://example.com/custom-link-altered', ]; + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); + + // Update the link with local path, so the external icon won't be present. + $this->updateGeneralLink('custom-link-1', [ + 'label' => 'Custom link altered', + 'url' => '', + ]); + $this->drupalGet(''); + + $column = $assert->elementExists('css', 'footer.ecl-footer-standardised div.ecl-footer-standardised__row:nth-child(1) div.ecl-footer-standardised__column:nth-child(3)'); + $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(2)', $column); + + $actual = $assert->elementExists('css', '.ecl-footer-standardised__title', $subsection); + $this->assertEquals('Section 1', $actual->getText()); + + $actual = $subsection->find('css', 'ul li:nth-child(1) > a'); + $expected = [ + 'label' => 'Custom link altered', + 'href' => '/build/', + ]; $this->assertListLink($actual, 'standardised', $expected); + // We should not have any icon present. + $assert->elementNotExists('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon', $actual); // Assert updating a section also changes the footer content. $this->updateSection('section_1', [ @@ -635,7 +699,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom contact 1', 'href' => 'http://example.com/custom-contact-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(2)', $column); @@ -647,7 +714,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom about 1', 'href' => 'http://example.com/custom-about-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(3)', $column); @@ -681,9 +751,11 @@ public function testCorporateFooterRendering(): void { $actual = $subsection->find('css', 'ul li:nth-child(1) > a'); $expected = [ 'label' => 'Custom link altered', - 'href' => 'http://example.com/custom-link-altered', + 'href' => '/build/', ]; $this->assertListLink($actual, 'standardised', $expected); + // We should not have any icon present. + $assert->elementNotExists('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon', $actual); $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(2)', $column); @@ -695,7 +767,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom related 1', 'href' => 'http://example.com/custom-related-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); // Assert deleting links removes the section. $this->deleteEntity('footer_link_general', 'custom-about-1'); @@ -712,7 +787,10 @@ public function testCorporateFooterRendering(): void { 'label' => 'Custom contact 1', 'href' => 'http://example.com/custom-contact-1', ]; - $this->assertListLink($actual, 'standardised', $expected); + $this->assertListLink($actual, 'standardised', $expected, TRUE); + // We should have the external icon present. + $icon = $actual->find('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon use'); + $this->assertStringContainsString('external', $icon->getAttribute('xlink:href')); $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(2)', $column); @@ -739,6 +817,25 @@ public function testCorporateFooterRendering(): void { ]; $this->assertSocialLink($social_label, $social_link, $expected); + // Update the link with europa.eu path, so the external icon won't be + // present. + $this->updateGeneralLink('custom-link-1', [ + 'label' => 'Custom link altered', + 'url' => 'http://ec.europa.eu/info', + ]); + $this->drupalGet(''); + + $column = $assert->elementExists('css', 'footer.ecl-footer-standardised div.ecl-footer-standardised__row:nth-child(1) div.ecl-footer-standardised__column:nth-child(3)'); + $subsection = $assert->elementExists('css', '.ecl-footer-standardised__section:nth-child(1)', $column); + $actual = $subsection->find('css', 'ul li:nth-child(1) > a'); + $expected = [ + 'label' => 'Custom link altered', + 'href' => 'http://ec.europa.eu/info', + ]; + $this->assertListLink($actual, 'standardised', $expected); + // We should not have any icon present. + $assert->elementNotExists('css', 'svg.ecl-icon.ecl-icon--xs.ecl-link__icon', $actual); + // Assert deleting sections in backend is reflected in the footer. $this->deleteEntity('footer_link_section', 'about_us'); $this->deleteEntity('footer_link_section', 'contact_us'); @@ -802,11 +899,14 @@ protected function assertFooterPresence(string $branding, int $expected_section_ * Ecl branding, core/standardised. * @param array $expected * The expected data. + * @param bool $icon + * If the link should have an icon, defaults to FALSE. */ - protected function assertListLink(NodeElement $actual, string $branding, array $expected): void { + protected function assertListLink(NodeElement $actual, string $branding, array $expected, bool $icon = FALSE): void { $this->assertEquals($expected['label'], $actual->getText()); $this->assertEquals($expected['href'], $actual->getAttribute('href')); - $this->assertEquals("ecl-link ecl-link--standalone ecl-footer-{$branding}__link", $actual->getAttribute('class')); + $icon_class = $icon ? 'ecl-link--icon ecl-link--icon-after ' : ''; + $this->assertEquals("ecl-link ecl-link--standalone {$icon_class}ecl-footer-{$branding}__link", $actual->getAttribute('class')); } /** @@ -868,7 +968,7 @@ protected function updateSiteSettings(string $site_owner, string $site_name): vo */ protected function createGeneralLink(string $label, string $section = ''): void { $id = Html::getId($label); - $link = \Drupal::entityTypeManager()->getStorage('footer_link_general')->create([ + \Drupal::entityTypeManager()->getStorage('footer_link_general')->create([ 'id' => $id, 'label' => $label, 'url' => 'http://example.com/' . $id, @@ -905,7 +1005,7 @@ protected function updateGeneralLink(string $id, array $data): void { */ protected function createSocialLink(string $label, string $network): void { $id = Html::getId($label); - $link = \Drupal::entityTypeManager()->getStorage('footer_link_social')->create([ + \Drupal::entityTypeManager()->getStorage('footer_link_social')->create([ 'id' => $id, 'label' => $label, 'url' => 'http://example.com/' . $id, @@ -923,7 +1023,7 @@ protected function createSocialLink(string $label, string $network): void { * The section label. */ protected function createSection(string $id, string $label): void { - $section = \Drupal::entityTypeManager()->getStorage('footer_link_section')->create([ + \Drupal::entityTypeManager()->getStorage('footer_link_section')->create([ 'id' => $id, 'label' => $label, 'weight' => 0, From a2cbf517071ae95f7750d2933716c5e0b833fa7b Mon Sep 17 00:00:00 2001 From: nagyad Date: Wed, 18 May 2022 12:02:47 +0200 Subject: [PATCH 27/42] EWPP-2274: Use external link service. --- oe_theme.theme | 10 +++------- tests/src/Functional/CorporateFooterRenderTest.php | 3 +++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/oe_theme.theme b/oe_theme.theme index 01c92e254..897e2cb03 100644 --- a/oe_theme.theme +++ b/oe_theme.theme @@ -9,7 +9,6 @@ declare(strict_types = 1); use Drupal\block\BlockInterface; use Drupal\Component\Utility\Html; -use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Entity\ContentEntityInterface; @@ -1751,6 +1750,8 @@ function _oe_theme_preprocess_site_specific_footer_links(array &$variables): voi return; } + $external_link_service = \Drupal::service('oe_theme_helper.external_links'); + foreach ($variables['site_specific_footer']['other_links'] as $section => $links) { if (empty($links['links'])) { continue; @@ -1761,12 +1762,7 @@ function _oe_theme_preprocess_site_specific_footer_links(array &$variables): voi continue; } - if ($link['href']->isExternal()) { - $parts = UrlHelper::parse($link['href']->toString()); - if (strpos($parts['path'], 'europa.eu')) { - // We consider links with europa.eu domains as internal. - continue; - } + if ($external_link_service->isExternalLink($link['href'])) { $variables['site_specific_footer']['other_links'][$section]['links'][$index]['external'] = TRUE; } } diff --git a/tests/src/Functional/CorporateFooterRenderTest.php b/tests/src/Functional/CorporateFooterRenderTest.php index 67c694c33..3ec6c5501 100644 --- a/tests/src/Functional/CorporateFooterRenderTest.php +++ b/tests/src/Functional/CorporateFooterRenderTest.php @@ -60,6 +60,9 @@ protected function setUp(): void { $this->container->get('plugin.manager.ui_patterns')->clearCachedDefinitions(); $this->configFactory = $this->container->get('config.factory'); $this->linkManager = $this->container->get('oe_corporate_blocks.footer_link_manager'); + + // Set the internal domain config to detect external links properly. + $this->config('oe_theme_helper.internal_domains')->set('internal_domain', '/(^|^[^:]+:\/\/|[^\.]+\.)europa\.eu/m')->save(); } /** From 5cbe19904199046288db49ddea8462341e3e22a7 Mon Sep 17 00:00:00 2001 From: Francesco Sardara Date: Sat, 7 May 2022 11:31:40 +0200 Subject: [PATCH 28/42] EWPP-2149: Refactor inpage navigation so that it works on specific containers. --- js/inpage_navigation.js | 130 ++++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 51 deletions(-) diff --git a/js/inpage_navigation.js b/js/inpage_navigation.js index d5f5ae958..873eee79e 100644 --- a/js/inpage_navigation.js +++ b/js/inpage_navigation.js @@ -19,63 +19,24 @@ */ Drupal.behaviors.eclInPageNavigation = { attach: function attach(context, settings) { - // Loop through all the elements marked as source areas. - Array.prototype.forEach.call(document.querySelectorAll('[data-inpage-navigation-source-area]'), function (area) { - var selectors = area.getAttribute('data-inpage-navigation-source-area'); - - // Loop through all the elements that are referenced by the specified selector(s), and mark them as source - // elements. We cannot collect the elements at this stage, as multiple nested areas can be present in the page. - // This could lead to scenarios where elements are collected multiple times, or not collected following the - // order of appearance in the page. - // The :scope pseudo-class is needed to make sure that the selectors are applied inside the parent. - // @see https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll#user_notes - Array.prototype.forEach.call(area.querySelectorAll(':scope ' + selectors), function (element) { - element.setAttribute('data-inpage-navigation-source-element', ''); + Array.prototype.forEach.call(document.querySelectorAll('.inpage-navigation-container'), function (container) { + let items_markup = Drupal.eclInPageNavigation.generateItems(container, function (id, text) { + return Drupal.theme('oe_theme_inpage_navigation_item', id, text); }); - }); - var items_markup = ''; - // Collect all the elements marked as source. Now the elements will be unique and ordered correctly. - Array.prototype.forEach.call(document.querySelectorAll('[data-inpage-navigation-source-element]'), function (element) { - var title = element.textContent.trim(); - - // Skip elements with empty content. - if (title.length === 0) { - return; - } - - // Generate an unique ID if not present. - if (!element.hasAttribute('id')) { - var id = Drupal.eclInPageNavigation.slug(title); - // If an empty ID is generated, skip this element. - if (id === false) { - return; - } - - element.setAttribute('id', id); - } - - // Cleanup the markup from the helper attribute added above. - element.removeAttribute('data-inpage-navigation-source-element'); - - items_markup += Drupal.theme('oe_theme_inpage_navigation_item', element.getAttribute('id'), title); - }); - - // Loop through all the inpage navigation marked with our special class. The auto-initialisation is disabled on - // them, as initialisation should be run only after the items are added. Otherwise JS callbacks won't be applied - // correctly. - Array.prototype.forEach.call(document.querySelectorAll('.oe-theme-ecl-inpage-navigation'), function (block) { + const nav = container.querySelector(':scope .oe-theme-ecl-inpage-navigation'); if (items_markup.length === 0) { // When there are no items, execute the callback to handle the block. - Drupal.eclInPageNavigation.handleEmptyInpageNavigation(block); + Drupal.eclInPageNavigation.handleEmptyInpageNavigation(nav); return; } - block.querySelector('ul').innerHTML = items_markup; - var instance = new ECL.InpageNavigation(block); + nav.querySelector('ul').innerHTML = items_markup; + + let instance = new ECL.InpageNavigation(nav); instance.init(); Drupal.eclInPageNavigation.instances.push(instance); - }) + }); }, detach: function detach(context, settings, trigger) { Drupal.eclInPageNavigation.instances.forEach(function (instance){ @@ -105,6 +66,73 @@ */ instances: [], + /** + * @callback ItemRenderCallback + * @param {string} id + * The ID of the element this item points to. + * @param {string} text + * The text of the link. + * + * @return {string} + * The HTML of the item. + */ + + /** + * Generates the inpage navigation items. + * + * @param {HTMLElement} container + * The element where to search for elements composing the inpage navigation. + * @param {ItemRenderCallback} item_cb + * The single item render callback. + * + * @returns {string} + * The HTML of the generated items. + */ + generateItems: function(container, item_cb) { + Array.prototype.forEach.call(container.querySelectorAll(':scope [data-inpage-navigation-source-area]'), function (area) { + let selectors = area.getAttribute('data-inpage-navigation-source-area'); + + // Loop through all the elements that are referenced by the specified selector(s), and mark them as source + // elements. We cannot collect the elements at this stage, as multiple nested areas can be present in the page. + // This could lead to scenarios where elements are collected multiple times, or not collected following the + // order of appearance in the page. + // The :scope pseudo-class is needed to make sure that the selectors are applied inside the parent. + // @see https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll#user_notes + Array.prototype.forEach.call(area.querySelectorAll(':scope ' + selectors), function (element) { + element.setAttribute('data-inpage-navigation-source-element', ''); + }); + }); + + let items_markup = ''; + // Collect all the elements marked as source. Now the elements will be unique and ordered correctly. + Array.prototype.forEach.call(container.querySelectorAll(':scope [data-inpage-navigation-source-element]'), function (element) { + let title = element.textContent.trim(); + + // Skip elements with empty content. + if (title.length === 0) { + return; + } + + // Generate an unique ID if not present. + if (!element.hasAttribute('id')) { + let id = Drupal.eclInPageNavigation.slug(title); + // If an empty ID is generated, skip this element. + if (id === false) { + return; + } + + element.setAttribute('id', id); + } + + // Cleanup the markup from the helper attribute added above. + element.removeAttribute('data-inpage-navigation-source-element'); + + items_markup += item_cb(element.getAttribute('id'), title); + }); + + return items_markup; + }, + /** * Generates a unique slug from a text string. * @@ -119,7 +147,7 @@ * A unique slug, safe to use as ID for an element. False when the generated slug is empty. */ slug: function(value) { - var originalSlug = value + let originalSlug = value .toLowerCase() .trim() // Remove html tags. @@ -128,8 +156,8 @@ .replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '') .replace(/\s/g, '-'); - var slug = originalSlug; - var occurrenceAccumulator = 0; + let slug = originalSlug; + let occurrenceAccumulator = 0; // If the slug string is empty, quit. if (slug.length === 0) { From 7d33ccd94bb512de9c3c39392cf18e02b81d3d58 Mon Sep 17 00:00:00 2001 From: Francesco Sardara Date: Sat, 7 May 2022 11:38:09 +0200 Subject: [PATCH 29/42] EWPP-2149: Bail out if a container has no inpage navigation block. --- js/inpage_navigation.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/js/inpage_navigation.js b/js/inpage_navigation.js index 873eee79e..1c6a3d0c8 100644 --- a/js/inpage_navigation.js +++ b/js/inpage_navigation.js @@ -20,11 +20,17 @@ Drupal.behaviors.eclInPageNavigation = { attach: function attach(context, settings) { Array.prototype.forEach.call(document.querySelectorAll('.inpage-navigation-container'), function (container) { + const nav = container.querySelector(':scope .oe-theme-ecl-inpage-navigation'); + + // Bail out if no inpage navigation element is present. + if (nav === null) { + return; + } + let items_markup = Drupal.eclInPageNavigation.generateItems(container, function (id, text) { return Drupal.theme('oe_theme_inpage_navigation_item', id, text); }); - const nav = container.querySelector(':scope .oe-theme-ecl-inpage-navigation'); if (items_markup.length === 0) { // When there are no items, execute the callback to handle the block. Drupal.eclInPageNavigation.handleEmptyInpageNavigation(nav); From e9c7159b4b888f7814641242ed94374007a2a309 Mon Sep 17 00:00:00 2001 From: Francesco Sardara Date: Sat, 7 May 2022 11:39:31 +0200 Subject: [PATCH 30/42] EWPP-2149: Refactor test module to simplify declarations of new test scenarios. --- .../oe_theme_inpage_navigation_test.module | 5 +---- ...e_theme_inpage_navigation_test.routing.yml | 6 ++++-- .../InpageNavigationTestController.php | 19 +++++-------------- ...inpage-navigation-test--content.html.twig} | 0 ...ge-navigation-test--no-elements.html.twig} | 0 5 files changed, 10 insertions(+), 20 deletions(-) rename modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/{oe-theme-inpage-navigation-test-content.html.twig => oe-theme-inpage-navigation-test--content.html.twig} (100%) rename modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/{oe-theme-inpage-navigation-test-no-elements.html.twig => oe-theme-inpage-navigation-test--no-elements.html.twig} (100%) diff --git a/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.module b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.module index 0a6e85425..7b11f4c9b 100644 --- a/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.module +++ b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.module @@ -12,10 +12,7 @@ declare(strict_types = 1); */ function oe_theme_inpage_navigation_test_theme($existing, $type, $theme, $path) { return [ - 'oe_theme_inpage_navigation_test_content' => [ - 'render element' => 'element', - ], - 'oe_theme_inpage_navigation_test_no_elements' => [ + 'oe_theme_inpage_navigation_test' => [ 'render element' => 'element', ], ]; diff --git a/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.routing.yml b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.routing.yml index 79410deea..765790a54 100644 --- a/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.routing.yml +++ b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.routing.yml @@ -2,7 +2,8 @@ oe_theme_inpage_navigation_test.content: path: '/oe-theme-inpage-navigation-test/content' defaults: _title: 'In-page navigation content page' - _controller: '\Drupal\oe_theme_inpage_navigation_test\Controller\InpageNavigationTestController::contentPage' + _controller: '\Drupal\oe_theme_inpage_navigation_test\Controller\InpageNavigationTestController::renderTemplate' + variation: 'content' requirements: _access: 'TRUE' @@ -10,6 +11,7 @@ oe_theme_inpage_navigation_test.no_entries: path: '/oe-theme-inpage-navigation-test/no-entries' defaults: _title: 'In-page navigation no entries page' - _controller: '\Drupal\oe_theme_inpage_navigation_test\Controller\InpageNavigationTestController::noEntriesPage' + _controller: '\Drupal\oe_theme_inpage_navigation_test\Controller\InpageNavigationTestController::renderTemplate' + variation: 'no_elements' requirements: _access: 'TRUE' diff --git a/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/src/Controller/InpageNavigationTestController.php b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/src/Controller/InpageNavigationTestController.php index e17502715..6ddf11013 100644 --- a/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/src/Controller/InpageNavigationTestController.php +++ b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/src/Controller/InpageNavigationTestController.php @@ -12,26 +12,17 @@ class InpageNavigationTestController extends ControllerBase { /** - * Generates a page with test content for the inpage navigation. + * Renders a test page using a specific variation of the test template. * - * @return array - * The response render array. - */ - public function contentPage(): array { - return [ - '#theme' => 'oe_theme_inpage_navigation_test_content', - ]; - } - - /** - * Returns content that doesn't generate any entries for inpage navigation. + * @param string $variation + * The template variation to render. * * @return array * The response render array. */ - public function noEntriesPage(): array { + public function renderTemplate(string $variation): array { return [ - '#theme' => 'oe_theme_inpage_navigation_test_no_elements', + '#theme' => 'oe_theme_inpage_navigation_test__' . $variation, ]; } diff --git a/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test-content.html.twig b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test--content.html.twig similarity index 100% rename from modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test-content.html.twig rename to modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test--content.html.twig diff --git a/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test-no-elements.html.twig b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test--no-elements.html.twig similarity index 100% rename from modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test-no-elements.html.twig rename to modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test--no-elements.html.twig From 859aed5c333715f2be24374095f6e2254c568882 Mon Sep 17 00:00:00 2001 From: Francesco Sardara Date: Sat, 7 May 2022 12:08:18 +0200 Subject: [PATCH 31/42] EWPP-2149: Define the main content as inpage navigation container if none are present. --- js/inpage_navigation.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/js/inpage_navigation.js b/js/inpage_navigation.js index 1c6a3d0c8..23a03a93f 100644 --- a/js/inpage_navigation.js +++ b/js/inpage_navigation.js @@ -19,7 +19,18 @@ */ Drupal.behaviors.eclInPageNavigation = { attach: function attach(context, settings) { - Array.prototype.forEach.call(document.querySelectorAll('.inpage-navigation-container'), function (container) { + const inpage_navigations = document.querySelectorAll('.oe-theme-ecl-inpage-navigation'); + if (inpage_navigations.length === 0) { + return; + } + + let containers = [].slice.call(document.querySelectorAll('.inpage-navigation-container')); + // If no specifically defined containers are present, we use the main content as one. + if (containers.length === 0) { + containers.push(document.querySelector('#main-content')); + } + + containers.forEach(function (container) { const nav = container.querySelector(':scope .oe-theme-ecl-inpage-navigation'); // Bail out if no inpage navigation element is present. From d0f19c4d07c549c78e296a273afa92d6871a4a6e Mon Sep 17 00:00:00 2001 From: Francesco Sardara Date: Sat, 7 May 2022 12:09:41 +0200 Subject: [PATCH 32/42] EWPP-2149: Instance is never rewritten. --- js/inpage_navigation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/inpage_navigation.js b/js/inpage_navigation.js index 23a03a93f..020823556 100644 --- a/js/inpage_navigation.js +++ b/js/inpage_navigation.js @@ -50,7 +50,7 @@ nav.querySelector('ul').innerHTML = items_markup; - let instance = new ECL.InpageNavigation(nav); + const instance = new ECL.InpageNavigation(nav); instance.init(); Drupal.eclInPageNavigation.instances.push(instance); }); From a4a58ac8d01520e87cb5a3e9d3cdf13bc7724736 Mon Sep 17 00:00:00 2001 From: Francesco Sardara Date: Sat, 7 May 2022 12:54:11 +0200 Subject: [PATCH 33/42] EWPP-2149: Add test coverage for multiple inpage navigation containers. --- ...e_theme_inpage_navigation_test.routing.yml | 9 +++ ...inpage-navigation-test--multiple.html.twig | 69 +++++++++++++++++++ .../InPageNavigationLibraryTest.php | 66 ++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test--multiple.html.twig diff --git a/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.routing.yml b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.routing.yml index 765790a54..9652ae285 100644 --- a/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.routing.yml +++ b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/oe_theme_inpage_navigation_test.routing.yml @@ -15,3 +15,12 @@ oe_theme_inpage_navigation_test.no_entries: variation: 'no_elements' requirements: _access: 'TRUE' + +oe_theme_inpage_navigation_test.multiple: + path: '/oe-theme-inpage-navigation-test/multiple' + defaults: + _title: 'In-page navigation multiple containers page' + _controller: '\Drupal\oe_theme_inpage_navigation_test\Controller\InpageNavigationTestController::renderTemplate' + variation: 'multiple' + requirements: + _access: 'TRUE' diff --git a/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test--multiple.html.twig b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test--multiple.html.twig new file mode 100644 index 000000000..5bb900277 --- /dev/null +++ b/modules/oe_theme_helper/tests/modules/oe_theme_inpage_navigation_test/templates/oe-theme-inpage-navigation-test--multiple.html.twig @@ -0,0 +1,69 @@ +{# +/** + * @file + * Test template with multiple in-page navigation sections. + */ +#} +{% macro inpage_navigation(title) %} + {% set build = { + '#theme': 'oe_theme_helper_inpage_navigation_block', + '#title': title|default('Page contents'), + '#attached': { + 'library': [ + 'oe_theme/inpage_navigation' + ] + } + } %} + {{ build }} +{% endmacro %} + +
        +
        + {{ _self.inpage_navigation('First nav') }} + +
        +

        Area 1 title 1

        +

        Lorem ipsum dolor sit.

        +

        Area 1 title 2

        +

        Cum eveniet itaque veniam?

        + {# First occurrence of an heading with "Details" as text. #} +

        Details

        +

        Beatae ducimus laborum sapiente?

        + {# A title that should be ignored in this container. #} +

        Area 1 unused title

        +
        +
        + + {# A div that contains elements that should be ignored. #} +
        +

        Lorem ipsum dolor.

        +

        Adipisci, alias, expedita.

        +

        Lorem ipsum dolor.

        +

        Ab alias, iusto.

        +
        + +
        + {{ _self.inpage_navigation('Second nav') }} + +
        +

        Area 2 title 1

        +

        Beatae ducimus laborum sapiente?

        +

        Area 2 title 2

        +

        Perspiciatis quo repellendus voluptate!

        + {# Second occurrence of an heading with "Details" as text. #} +

        Details

        +

        Ab dolor earum placeat!

        +

        Area 2 title 4

        +

        Nulla pariatur quaerat reprehenderit.

        + + {# + A "deeply" nested area, to simulate a standalone component with his own source area selectors. + For example, we are rendering a paragraphs entity reference field. + #} +
        + Special title element +

        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nostrum, tempora?

        +
        +
        +
        +
        diff --git a/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationLibraryTest.php b/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationLibraryTest.php index 74037db88..4924cfe36 100644 --- a/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationLibraryTest.php +++ b/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationLibraryTest.php @@ -154,4 +154,70 @@ public function testLibrary(): void { $assert_session->elementExists('css', 'h1.ecl-page-header__title.empty-inpage-nav-test'); } + /** + * Tests when multiple inpage navigation containers are present in the page. + */ + public function testMultipleContainers(): void { + $this->drupalGet('/oe-theme-inpage-navigation-test/multiple'); + $assert_session = $this->assertSession(); + + $main_content = $assert_session->elementExists('css', '#inpage-navigation-test-container'); + // Each inpage navigation adds two extra IDs, one for a button and one for + // the ul itself. This means that we actually are expecting 8 IDs generated + // in total by the library. + $this->assertCount(12, $main_content->findAll('xpath', '//*[@id]')); + + $first_container = $main_content->find('css', '.first-container'); + $navigation = $assert_session->elementExists('css', '.oe-theme-ecl-inpage-navigation', $first_container); + $assert = new InPageNavigationAssert(); + $expected = [ + 'title' => 'First nav', + 'list' => [ + [ + 'label' => 'Area 1 title 1', + 'href' => '#area-1-title-1', + ], + [ + 'label' => 'Area 1 title 2', + 'href' => '#area-1-title-2', + ], + [ + 'label' => 'Details', + 'href' => '#details', + ], + ], + ]; + $assert->assertPattern($expected, $navigation->getOuterHtml()); + + $second_container = $main_content->find('css', '.second-container'); + $navigation = $assert_session->elementExists('css', '.oe-theme-ecl-inpage-navigation', $second_container); + $assert = new InPageNavigationAssert(); + $expected = [ + 'title' => 'Second nav', + 'list' => [ + [ + 'label' => 'Area 2 title 1', + 'href' => '#area-2-title-1', + ], + [ + 'label' => 'Area 2 title 2', + 'href' => '#area-2-title-2', + ], + [ + 'label' => 'Details', + 'href' => '#details-1', + ], + [ + 'label' => 'Area 2 title 4', + 'href' => '#area-2-title-4', + ], + [ + 'label' => 'Special title element', + 'href' => '#special-title-element', + ], + ], + ]; + $assert->assertPattern($expected, $navigation->getOuterHtml()); + } + } From 41b58bbbe23359f6915ccc7df3811429fd7cffae Mon Sep 17 00:00:00 2001 From: Francesco Sardara Date: Mon, 9 May 2022 14:17:24 +0200 Subject: [PATCH 34/42] EWPP-2149: Test that titles outside content rows are not included in its inpage navigation. --- .../InPageNavigationParagraphTest.php | 14 +++++++++++++- ...ontent-row--variant-inpage_navigation.html.twig | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationParagraphTest.php b/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationParagraphTest.php index 77477f56f..81e9b7a75 100644 --- a/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationParagraphTest.php +++ b/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationParagraphTest.php @@ -77,11 +77,23 @@ public function testInpageNavigationInParagraphContentRow(): void { ]); $content_row->save(); + // Create standalone a rich text paragraph with headings not used + // by inpage navigation block. + $paragraph2 = Paragraph::create([ + 'type' => 'oe_rich_text', + 'field_oe_title' => 'Rich text title', + 'field_oe_text_long' => [ + 'value' => 'The rich text body.

        Here is a heading

        ', + 'format' => 'full_html', + ], + ]); + $paragraph2->save(); + // Create a landing page that uses this paragraph. $node = $this->drupalCreateNode([ 'title' => 'The node title', 'type' => 'oe_demo_landing_page', - 'field_oe_demo_body' => [$content_row], + 'field_oe_demo_body' => [$content_row, $paragraph2], ]); $this->drupalGet($node->toUrl()); diff --git a/templates/paragraphs/paragraph--oe-content-row--variant-inpage_navigation.html.twig b/templates/paragraphs/paragraph--oe-content-row--variant-inpage_navigation.html.twig index 6c96a6028..21faa29d6 100644 --- a/templates/paragraphs/paragraph--oe-content-row--variant-inpage_navigation.html.twig +++ b/templates/paragraphs/paragraph--oe-content-row--variant-inpage_navigation.html.twig @@ -6,11 +6,11 @@ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig */ #} -
        +
        {{ inpage }}
        -
        +
        {{ content.field_oe_paragraphs }}
        From 0ab880a952bc44e6efac9aa7bb6a1841d8fa0271 Mon Sep 17 00:00:00 2001 From: Francesco Sardara Date: Mon, 9 May 2022 14:55:30 +0200 Subject: [PATCH 35/42] EWPP-2149: Add test coverage for multiple inpage navigation content rows. --- .../InPageNavigationParagraphTest.php | 67 +++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationParagraphTest.php b/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationParagraphTest.php index 81e9b7a75..145d2e72d 100644 --- a/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationParagraphTest.php +++ b/modules/oe_theme_helper/tests/src/FunctionalJavascript/InPageNavigationParagraphTest.php @@ -4,6 +4,7 @@ namespace Drupal\Tests\oe_theme_helper\FunctionalJavascript; +use Behat\Mink\Element\NodeElement; use Drupal\filter\Entity\FilterFormat; use Drupal\FunctionalJavascriptTests\WebDriverTestBase; use Drupal\paragraphs\Entity\Paragraph; @@ -68,7 +69,7 @@ public function testInpageNavigationInParagraphContentRow(): void { ]); $paragraph->save(); - // Create the main content row paragraph with a default variant. + // Create the main content row paragraph with the inpage navigation variant. $content_row = Paragraph::create([ 'type' => 'oe_content_row', 'oe_paragraphs_variant' => 'inpage_navigation', @@ -97,8 +98,8 @@ public function testInpageNavigationInParagraphContentRow(): void { ]); $this->drupalGet($node->toUrl()); - $navigation = $this->assertSession()->elementExists('css', '.ecl-col-l-3.ecl-u-z-navigation .ecl-inpage-navigation'); - $inpage_nav_assert = new InPageNavigationAssert(); + $containers = $this->getSession()->getPage()->findAll('css', '.inpage-navigation-container'); + $this->assertCount(1, $containers); $inpage_nav_expected_values = [ 'title' => 'Page navigation', 'list' => [ @@ -106,8 +107,66 @@ public function testInpageNavigationInParagraphContentRow(): void { ['label' => 'Here is a heading', 'href' => '#here-is-a-heading'], ], ]; - $inpage_nav_assert->assertPattern($inpage_nav_expected_values, $navigation->getOuterHtml()); + $this->assertInPageNavigation($inpage_nav_expected_values, $containers[0]); + + // Create another content row with a rich text paragraph. + $paragraph3 = Paragraph::create([ + 'type' => 'oe_rich_text', + 'field_oe_title' => 'Second rich text paragraph', + 'field_oe_text_long' => [ + 'value' => 'Some other text.

        Another heading

        ', + 'format' => 'full_html', + ], + ]); + $paragraph3->save(); + $content_row2 = Paragraph::create([ + 'type' => 'oe_content_row', + 'oe_paragraphs_variant' => 'inpage_navigation', + 'field_oe_title' => 'Second page navigation', + 'field_oe_paragraphs' => [$paragraph3], + ]); + $content_row->save(); + // Reference the two content rows and the extra rich text paragraphs. + $node->set('field_oe_demo_body', [ + $content_row, + $paragraph2, + $content_row2, + ]); + $node->save(); + + $this->drupalGet($node->toUrl()); + $containers = $this->getSession()->getPage()->findAll('css', '.inpage-navigation-container'); + $this->assertCount(2, $containers); + // The first inpage navigation didn't change. + $this->assertInPageNavigation($inpage_nav_expected_values, $containers[0]); + $this->assertInPageNavigation([ + 'title' => 'Second page navigation', + 'list' => [ + [ + 'label' => 'Second rich text paragraph', + 'href' => '#second-rich-text-paragraph', + ], + [ + 'label' => 'Another heading', + 'href' => '#another-heading', + ], + ], + ], $containers[1]); + } + + /** + * Asserts the inpage navigation inside a container. + * + * @param array $expected + * The expected values. + * @param \Behat\Mink\Element\NodeElement $container + * The inpage navigation container. + */ + protected function assertInPageNavigation(array $expected, NodeElement $container): void { + $navigation = $this->assertSession()->elementExists('css', '.ecl-col-l-3.ecl-u-z-navigation .ecl-inpage-navigation', $container); + $inpage_nav_assert = new InPageNavigationAssert(); + $inpage_nav_assert->assertPattern($expected, $navigation->getOuterHtml()); } } From ab735250e899951bb01aa1509c856cd4326d0d92 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Thu, 9 Jun 2022 16:44:06 +0300 Subject: [PATCH 36/42] EWPP-2022: Fix featured_item selectors for extended variant test case. --- tests/src/Kernel/fixtures/rendering.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/src/Kernel/fixtures/rendering.yml b/tests/src/Kernel/fixtures/rendering.yml index 3a06391f3..821084cdf 100644 --- a/tests/src/Kernel/fixtures/rendering.yml +++ b/tests/src/Kernel/fixtures/rendering.yml @@ -2386,15 +2386,15 @@ assertions: count: "div.ecl-card__image": 0 - 'h1.ecl-card__title a.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after[href="https://example.com"]': 1 + 'h1.ecl-content-block__title a.ecl-link--standalone.ecl-link--icon.ecl-link--icon-after[href="https://example.com"]': 1 'a.ecl-button[href="https://example.com"]': 1 'svg.ecl-icon.ecl-icon--xs.ecl-button__icon.ecl-button__icon--after': 1 equals: - 'h1.ecl-card__title a span.ecl-link__label': "Example title" - 'div.ecl-card__description .ecl-paragraph': "Example description" + 'h1.ecl-content-block__title a span.ecl-link__label': "Example title" + 'div.ecl-content-block__description .ecl-paragraph': "Example description" 'a.ecl-button .ecl-button__label': "Link title" - 'h1.ecl-card__title a svg.ecl-icon.ecl-icon--2xs.ecl-link__icon': '' - '.ecl-card__description svg.ecl-icon.ecl-icon--xs.ecl-button__icon.ecl-button__icon--after': '' + 'h1.ecl-content-block__title a svg.ecl-icon.ecl-icon--2xs.ecl-link__icon': '' + '.ecl-content-block__description svg.ecl-icon.ecl-icon--xs.ecl-button__icon.ecl-button__icon--after': '' - array: '#type': pattern '#id': featured_item From d7f6ba12c8d83b761ebec676c926aada75a252b8 Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Tue, 7 Jun 2022 11:08:47 +0300 Subject: [PATCH 37/42] EWPP-2307: Add external_link parameter to node teaser templates. --- templates/content/node--oe-call-proposals--teaser.html.twig | 1 + templates/content/node--oe-call-tenders--teaser.html.twig | 1 + templates/content/node--oe-consultation--teaser.html.twig | 1 + templates/content/node--oe-event--teaser.html.twig | 1 + templates/content/node--oe-news--teaser.html.twig | 1 + templates/content/node--oe-organisation--teaser.html.twig | 1 + templates/content/node--oe-page--teaser.html.twig | 1 + templates/content/node--oe-person--teaser.html.twig | 1 + templates/content/node--oe-policy--teaser.html.twig | 1 + templates/content/node--oe-project--teaser.html.twig | 1 + templates/content/node--oe-publication--teaser.html.twig | 1 + 11 files changed, 11 insertions(+) diff --git a/templates/content/node--oe-call-proposals--teaser.html.twig b/templates/content/node--oe-call-proposals--teaser.html.twig index 9c4d49def..67c25abd3 100644 --- a/templates/content/node--oe-call-proposals--teaser.html.twig +++ b/templates/content/node--oe-call-proposals--teaser.html.twig @@ -16,5 +16,6 @@ 'title': content.extra_field_oe_theme_helper_short_title_with_fallback|field_value, 'additional_information': additional_information, 'badges': badges, + 'external_link': external_link }) }} {% endblock %} diff --git a/templates/content/node--oe-call-tenders--teaser.html.twig b/templates/content/node--oe-call-tenders--teaser.html.twig index 86ed5fe30..ba51433cb 100644 --- a/templates/content/node--oe-call-tenders--teaser.html.twig +++ b/templates/content/node--oe-call-tenders--teaser.html.twig @@ -16,5 +16,6 @@ 'title': content.extra_field_oe_theme_helper_short_title_with_fallback|field_value, 'additional_information': additional_information, 'badges': badges, + 'external_link': external_link }) }} {% endblock %} diff --git a/templates/content/node--oe-consultation--teaser.html.twig b/templates/content/node--oe-consultation--teaser.html.twig index e745f26ad..7a1d402a2 100644 --- a/templates/content/node--oe-consultation--teaser.html.twig +++ b/templates/content/node--oe-consultation--teaser.html.twig @@ -16,5 +16,6 @@ 'title': content.extra_field_oe_theme_helper_short_title_with_fallback|field_value, 'additional_information': additional_information, 'badges': badges, + 'external_link': external_link }) }} {% endblock %} diff --git a/templates/content/node--oe-event--teaser.html.twig b/templates/content/node--oe-event--teaser.html.twig index 1308aa825..e6444b03b 100644 --- a/templates/content/node--oe-event--teaser.html.twig +++ b/templates/content/node--oe-event--teaser.html.twig @@ -21,5 +21,6 @@ 'detail': detail, 'additional_information': additional_information, 'badges': badges, + 'external_link': external_link }) }} {% endblock %} diff --git a/templates/content/node--oe-news--teaser.html.twig b/templates/content/node--oe-news--teaser.html.twig index c0225d427..c0a334ca9 100644 --- a/templates/content/node--oe-news--teaser.html.twig +++ b/templates/content/node--oe-news--teaser.html.twig @@ -25,6 +25,7 @@ 'image': image_url ? { 'src': image_url }, 'additional_information': additional_information, 'badges': badges, + 'external_link': external_link }) }} {% endblock %} {% endspaceless %} diff --git a/templates/content/node--oe-organisation--teaser.html.twig b/templates/content/node--oe-organisation--teaser.html.twig index a259c8dc0..a2416095c 100644 --- a/templates/content/node--oe-organisation--teaser.html.twig +++ b/templates/content/node--oe-organisation--teaser.html.twig @@ -21,5 +21,6 @@ 'additional_information': additional_information, 'image': image_url ? { 'src': image_url }, 'badges': badges, + 'external_link': external_link }) }} {% endblock %} diff --git a/templates/content/node--oe-page--teaser.html.twig b/templates/content/node--oe-page--teaser.html.twig index 9f11e6809..fd0a6446a 100644 --- a/templates/content/node--oe-page--teaser.html.twig +++ b/templates/content/node--oe-page--teaser.html.twig @@ -12,5 +12,6 @@ 'detail': content.oe_teaser|field_value, 'additional_information': additional_information|default([]), 'badges': badges, + 'external_link': external_link }) }} {% endblock %} diff --git a/templates/content/node--oe-person--teaser.html.twig b/templates/content/node--oe-person--teaser.html.twig index 236dcdb54..124a2c6ce 100644 --- a/templates/content/node--oe-person--teaser.html.twig +++ b/templates/content/node--oe-person--teaser.html.twig @@ -24,5 +24,6 @@ 'additional_information': additional_information, 'image': content.portrait_image ? { 'src': content.portrait_image|render }, 'badges': badges, + 'external_link': external_link }) }} {% endblock %} diff --git a/templates/content/node--oe-policy--teaser.html.twig b/templates/content/node--oe-policy--teaser.html.twig index fef08e6e5..fdba2680d 100644 --- a/templates/content/node--oe-policy--teaser.html.twig +++ b/templates/content/node--oe-policy--teaser.html.twig @@ -12,5 +12,6 @@ 'detail': content.oe_teaser|field_value, 'additional_information': additional_information|default([]), 'badges': badges, + 'external_link': external_link }) }} {% endblock %} diff --git a/templates/content/node--oe-project--teaser.html.twig b/templates/content/node--oe-project--teaser.html.twig index f10bfab05..730052bbd 100644 --- a/templates/content/node--oe-project--teaser.html.twig +++ b/templates/content/node--oe-project--teaser.html.twig @@ -17,5 +17,6 @@ 'additional_information': additional_information, 'image': image_url ? { 'src': image_url }, 'badges': badges, + 'external_link': external_link }) }} {% endblock %} diff --git a/templates/content/node--oe-publication--teaser.html.twig b/templates/content/node--oe-publication--teaser.html.twig index 1d48f4647..3510fdda1 100644 --- a/templates/content/node--oe-publication--teaser.html.twig +++ b/templates/content/node--oe-publication--teaser.html.twig @@ -19,5 +19,6 @@ 'image': image_url ? { 'src': image_url }, 'additional_information': additional_information, 'badges': badges, + 'external_link': external_link }) }} {% endblock %} From c7645b0620096c578db0dca97d7054434b3b33fa Mon Sep 17 00:00:00 2001 From: nagyad Date: Wed, 11 May 2022 17:52:33 +0200 Subject: [PATCH 38/42] EWPP-2166: Check access for programme before render. --- .../src/Plugin/ExtraField/Display/ProgrammeExtraField.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/ProgrammeExtraField.php b/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/ProgrammeExtraField.php index f710354bd..7932f53c2 100755 --- a/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/ProgrammeExtraField.php +++ b/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/ProgrammeExtraField.php @@ -150,6 +150,12 @@ public function viewElements(ContentEntityInterface $entity) { continue; } + $access = $programme->access('view', NULL, TRUE); + $cache->addCacheableDependency($access); + if (!$access->isAllowed()) { + continue; + } + $programme = $this->entityRepository->getTranslationFromContext($programme); $cache->addCacheableDependency($programme); From 8c08c9eb31d0546d8fd4b25fe85b11e43a34e049 Mon Sep 17 00:00:00 2001 From: nagyad Date: Wed, 11 May 2022 18:04:41 +0200 Subject: [PATCH 39/42] EWPP-2166: Fix test. --- .../src/Plugin/ExtraField/Display/ProgrammeExtraField.php | 3 +++ tests/src/Functional/ContentEventRenderTest.php | 1 + 2 files changed, 4 insertions(+) diff --git a/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/ProgrammeExtraField.php b/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/ProgrammeExtraField.php index 7932f53c2..811bbd3dc 100755 --- a/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/ProgrammeExtraField.php +++ b/modules/oe_theme_content_event/src/Plugin/ExtraField/Display/ProgrammeExtraField.php @@ -113,6 +113,9 @@ public function getLabel() { /** * {@inheritdoc} + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) */ public function viewElements(ContentEntityInterface $entity) { if ($entity->get('oe_event_programme')->isEmpty()) { diff --git a/tests/src/Functional/ContentEventRenderTest.php b/tests/src/Functional/ContentEventRenderTest.php index 68b3fc53c..552403657 100644 --- a/tests/src/Functional/ContentEventRenderTest.php +++ b/tests/src/Functional/ContentEventRenderTest.php @@ -57,6 +57,7 @@ protected function setUp(): void { Role::load(RoleInterface::ANONYMOUS_ID) ->grantPermission('view published oe_venue') ->grantPermission('view published oe_contact') + ->grantPermission('view published oe_event_programme') ->save(); $field = FieldConfig::create([ From 6fe3b2f0f0f6ba2d2fd87a17263120f22384c2ec Mon Sep 17 00:00:00 2001 From: 22Alexandra Date: Fri, 17 Jun 2022 12:51:18 +0300 Subject: [PATCH 40/42] EWPP-2022: Provide test coverage for the external links service. --- modules/oe_theme_helper/src/ExternalLinks.php | 20 ++++++---- .../tests/src/Kernel/ExternalLinksTest.php | 37 +++++++++++++++++++ 2 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 modules/oe_theme_helper/tests/src/Kernel/ExternalLinksTest.php diff --git a/modules/oe_theme_helper/src/ExternalLinks.php b/modules/oe_theme_helper/src/ExternalLinks.php index 77e575248..3b38dacbc 100644 --- a/modules/oe_theme_helper/src/ExternalLinks.php +++ b/modules/oe_theme_helper/src/ExternalLinks.php @@ -14,11 +14,11 @@ class ExternalLinks implements ExternalLinksInterface { /** - * The configuration factory. + * The internal domain regex. * - * @var \Drupal\Core\Config\ConfigFactoryInterface + * @var string */ - protected $configFactory; + protected string $internalDomainExpression; /** * Constructs an ExternalLinks object. @@ -27,13 +27,18 @@ class ExternalLinks implements ExternalLinksInterface { * The configuration factory. */ public function __construct(ConfigFactoryInterface $config_factory) { - $this->configFactory = $config_factory; + $this->internalDomainExpression = $config_factory->get('oe_theme_helper.internal_domains')->get('internal_domain') ?? ''; } /** * {@inheritdoc} */ - public function isExternalLink($url): bool { + public function isExternalLink($url = NULL): bool { + // If no value is provided or the value si not a proper link, we'll + // return FALSE as it can't be evaluated. + if (!$url) { + return FALSE; + } if ($url instanceof Url) { $external = $url->isExternal(); $path = UrlHelper::parse($url->toString())['path']; @@ -47,11 +52,10 @@ public function isExternalLink($url): bool { } // If it's an external link, make sure its domain is not internal. - $internal_domain_expression = $this->configFactory->get('oe_theme_helper.internal_domains')->get('internal_domain'); - if (!$internal_domain_expression) { + if (!$this->internalDomainExpression) { return $external; } - return !preg_match_all($internal_domain_expression, $path); + return !preg_match_all($this->internalDomainExpression, $path); } } diff --git a/modules/oe_theme_helper/tests/src/Kernel/ExternalLinksTest.php b/modules/oe_theme_helper/tests/src/Kernel/ExternalLinksTest.php new file mode 100644 index 000000000..fcdcf10a9 --- /dev/null +++ b/modules/oe_theme_helper/tests/src/Kernel/ExternalLinksTest.php @@ -0,0 +1,37 @@ +container->get('oe_theme_helper.external_links'); + // Assert internal URL. + $this->assertFalse($external_links->isExternalLink(Url::fromUserInput('/user'))); + // Assert external string path. + $this->assertTrue($external_links->isExternalLink('https://example.com')); + // Assert external string path under EU domain. + $this->assertFalse($external_links->isExternalLink('https://example.europa.eu')); + $this->assertFalse($external_links->isExternalLink('www.ec.europa.eu/info')); + // Assert null and empty value. + $this->assertFalse($external_links->isExternalLink()); + $this->assertFalse($external_links->isExternalLink('')); + // Assert incorrect paths. + $this->assertFalse($external_links->isExternalLink('www. incorrect . com')); + $this->assertFalse($external_links->isExternalLink('www. ec . europa . eu')); + } + +} From 1ac3ec5a1af9b6e1cc73ab859e1ffb740ec5e2df Mon Sep 17 00:00:00 2001 From: Evgenii Nikitin Date: Fri, 3 Jun 2022 12:43:45 +0200 Subject: [PATCH 41/42] EWPP-2296: Rename .ecl-navigation-list to .ecl-navigation to avoid conflict with ECL. --- .../ec-component-navigation/local-tasks.html.twig | 8 ++++---- tests/src/Kernel/MenuLocalTasksTest.php | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/templates/compositions/ec-component-navigation/local-tasks.html.twig b/templates/compositions/ec-component-navigation/local-tasks.html.twig index 28c9633cf..9b7d42bee 100644 --- a/templates/compositions/ec-component-navigation/local-tasks.html.twig +++ b/templates/compositions/ec-component-navigation/local-tasks.html.twig @@ -18,7 +18,7 @@ {% set _title = title|default('Navigation') %} {% set _links = links|default([]) %} {% set _variant = variant|default('primary') %} -{% set _css_class = 'ecl-navigation-list' %} +{% set _css_class = 'ecl-navigation' %} {% set _extra_attributes = '' %} {# Internal logic - Process properties #} @@ -46,10 +46,10 @@ {% if _links is not empty %}