diff --git a/src/implementations/twig/components/news-ticker/README.md b/src/implementations/twig/components/news-ticker/README.md index 336347a91d6..257509befe7 100644 --- a/src/implementations/twig/components/news-ticker/README.md +++ b/src/implementations/twig/components/news-ticker/README.md @@ -15,7 +15,8 @@ npm install --save @ecl/twig-component-news-ticker - **"counter_label"** (string) (default: 'of') - **"sr_previous"** (string) (default: 'Previous news') screen reader label for previous button - **"sr_next"** (string) (default: 'Next news') screen reader label for next button -- **"sr_autoplay"** (string) (default: 'News ticker auto play') screen reader label for autoplay button +- **"sr_play"** (string) (default: 'Play news ticker') screen reader label for the play button +- **"sr_pause"** (string) (default: 'Pause news ticker') screen reader label for the pause button - **"icon_path"** (string) (default: ''): path to the icons svg - **"extra_classes"** (optional) (string) (default: '') Extra classes (space separated) - **"extra_attributes"** (optional) (array) (default: []) Extra attributes diff --git a/src/implementations/twig/components/news-ticker/__snapshots__/news-ticker.test.js.snap b/src/implementations/twig/components/news-ticker/__snapshots__/news-ticker.test.js.snap index 404f91b08c6..f872947c539 100644 --- a/src/implementations/twig/components/news-ticker/__snapshots__/news-ticker.test.js.snap +++ b/src/implementations/twig/components/news-ticker/__snapshots__/news-ticker.test.js.snap @@ -10,6 +10,15 @@ exports[`News ticker Default renders correctly 1`] = `
+
@@ -23,7 +32,6 @@ exports[`News ticker Default renders correctly 1`] = ` Lorem ipsum dolor sit amet, consectetur adipiscing elit @@ -32,24 +40,23 @@ exports[`News ticker Default renders correctly 1`] = ` class="ecl-news-ticker__slide" > - - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat - + + Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat +
  • - Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit sed quia consequuntur magni dolores + + Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit sed quia consequuntur magni dolores +
  • - -
    - - 1 - - of - - 6 - -
    + +
    + + 1 + + of + + 6 + +
    @@ -218,6 +227,15 @@ exports[`News ticker Default renders correctly with extra attributes 1`] = `
    +
    @@ -231,7 +249,6 @@ exports[`News ticker Default renders correctly with extra attributes 1`] = ` Lorem ipsum dolor sit amet, consectetur adipiscing elit @@ -240,24 +257,23 @@ exports[`News ticker Default renders correctly with extra attributes 1`] = ` class="ecl-news-ticker__slide" > - - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat - + + Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat +
  • - Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit sed quia consequuntur magni dolores + + Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit sed quia consequuntur magni dolores +
  • - -
    - - 1 - - of - - 6 - -
    + +
    + + 1 + + of + + 6 + +
    @@ -424,6 +442,15 @@ exports[`News ticker Default renders correctly with extra class names 1`] = `
    +
    @@ -437,7 +464,6 @@ exports[`News ticker Default renders correctly with extra class names 1`] = ` Lorem ipsum dolor sit amet, consectetur adipiscing elit @@ -446,24 +472,23 @@ exports[`News ticker Default renders correctly with extra class names 1`] = ` class="ecl-news-ticker__slide" > - - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat - + + Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat +
  • Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur @@ -483,7 +507,6 @@ exports[`News ticker Default renders correctly with extra class names 1`] = ` Excepteur sint occaecat cupidatat officia deserunt mollit anim id est laborum @@ -494,7 +517,6 @@ exports[`News ticker Default renders correctly with extra class names 1`] = ` Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium @@ -502,119 +524,124 @@ exports[`News ticker Default renders correctly with extra class names 1`] = `
  • - Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit sed quia consequuntur magni dolores + + Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit sed quia consequuntur magni dolores +
  • - -
    - - 1 - - of - - 6 - -
    + +
    + + 1 + + of + + 6 + +
    diff --git a/src/implementations/twig/components/news-ticker/news-ticker.html.twig b/src/implementations/twig/components/news-ticker/news-ticker.html.twig index 57ff7f0811d..4aaa86adbf0 100644 --- a/src/implementations/twig/components/news-ticker/news-ticker.html.twig +++ b/src/implementations/twig/components/news-ticker/news-ticker.html.twig @@ -14,7 +14,8 @@ - "counter_label" (string) (default: 'of') - "sr_previous" (string) (default: 'Previous news') screen reader label for previous button - "sr_next" (string) (default: 'Next news') screen reader label for next button - - "sr_autoplay" (string) (default: 'News ticker auto play') screen reader label for autoplay button + - "sr_play" (string) (default: 'Play news ticker') screen reader label for play button + - "sr_pause" (string) (default: 'Pause news ticker') screen reader label for pause button - "icon_path" (string) (default: '') Path to the icons file - "extra_classes" (string) (default: '') - "extra_attributes" (array) (default: []): format: [ @@ -26,6 +27,10 @@ ], #} +{# Backward compatibility #} + +{% set _sr_autoplay = sr_autoplay|default('Play news ticker') %} + {# Internal properties #} {% set _id = id|default('') %} @@ -35,7 +40,8 @@ {% set _aria_controls = _id ~ '-content' %} {% set _sr_previous = sr_previous|default('Previous news') %} {% set _sr_next = sr_next|default('Next news') %} -{% set _sr_autoplay = sr_autoplay|default('News ticker auto play') %} +{% set _sr_play = sr_play|default(_sr_autoplay) %} +{% set _sr_pause = sr_pause|default('Pause news ticker') %} {% set _css_class = 'ecl-news-ticker' %} {% set _extra_attributes = [ 'data-ecl-news-ticker="true"', @@ -67,22 +73,31 @@
    {% if _items is not empty and _items is iterable %}
    + {% include '@ecl/icon/icon.html.twig' with { + icon: { + path: _icon_path, + name: 'information', + size: 'm', + }, + extra_classes: 'ecl-news-ticker__icon', + } only %}
      {% for _item in _items %} {% if _item.link is not empty %}
    • - {% include '@ecl/link/link.html.twig' with{ + {% include '@ecl/link/link.html.twig' with { link: { label: _item.content, path: _item.link, - external: _item.external, - icon_path: icon_path, + icon_position: 'before', + }, + icon: not _item.external ? {} : { + name: "external", + size: "xs", + path: icon_path }, extra_classes: 'ecl-news-ticker__slide-text', - extra_attributes: [ - { name: 'tabindex', value: '-1' }, - ] } only %}
    • {% else %} @@ -93,73 +108,80 @@
    {% endif %} - {% include '@ecl/icon/icon.html.twig' with { - icon: { - path: _icon_path, - name: 'information', - size: 'm', - }, - extra_classes: 'ecl-news-ticker__icon', - } only %} -
    - 1 - {{- ' ' -}}{{- _counter_label }}{{- ' ' -}} - {{_items|length}} -
    - {% include '@ecl/button/button.html.twig' with { - type: 'button', - variant: 'primary', - icon: { - path: _icon_path, - name: 'corner-arrow', - size: 'm', - transform: 'rotate-270', - }, - label: _sr_previous, - hide_label: true, - extra_classes: 'ecl-news-ticker__prev', - extra_attributes: [ - {name: 'data-ecl-news-ticker-prev'}, - {name: 'aria-controls', value: _aria_controls}, - ], - } only %} - - {% include '@ecl/button/button.html.twig' with { - type: 'button', - variant: 'primary', - icon: { - path: _icon_path, - name: 'play', - size: 'm', - }, - label: _sr_autoplay, - hide_label: true, - extra_classes: 'ecl-news-ticker__toggle', - extra_attributes: [ - {name: 'data-ecl-news-ticker-toggle'}, - {name: 'data-action', value: 'stop'}, - ], - } only %} - - {% include '@ecl/button/button.html.twig' with { - type: 'button', - variant: 'primary', - icon: { - path: _icon_path, - name: 'corner-arrow', - size: 'm', - transform: 'rotate-90', - }, - label: _sr_next, - hide_label: true, - extra_classes: 'ecl-news-ticker__next', - extra_attributes: [ - {name: 'data-ecl-news-ticker-next'}, - {name: 'aria-controls', value: _aria_controls}, - ], - } only %} - + + + + +
    + 1 + {{- ' ' -}}{{- _counter_label }}{{- ' ' -}} + {{_items|length}} +
    diff --git a/src/implementations/vanilla/components/carousel/_carousel.scss b/src/implementations/vanilla/components/carousel/_carousel.scss index 2c42d519921..73591f437a5 100644 --- a/src/implementations/vanilla/components/carousel/_carousel.scss +++ b/src/implementations/vanilla/components/carousel/_carousel.scss @@ -170,8 +170,7 @@ $_outline-width: null !default; width: 1rem; &:active, - &:hover, - &:focus { + &:hover { background-color: map.get(theme.$color, 'white-100'); } diff --git a/src/implementations/vanilla/components/carousel/carousel.js b/src/implementations/vanilla/components/carousel/carousel.js index 30ddd7cbaea..fed8c32e541 100644 --- a/src/implementations/vanilla/components/carousel/carousel.js +++ b/src/implementations/vanilla/components/carousel/carousel.js @@ -371,13 +371,11 @@ export class Carousel { this.slides.forEach((slide, index) => { const cta = queryOne('.ecl-link--cta', slide); if (this.index === index) { - slide.removeAttribute('aria-hidden', 'true'); slide.removeAttribute('inert', 'true'); if (cta) { cta.removeAttribute('tabindex', -1); } } else { - slide.setAttribute('aria-hidden', 'true'); slide.setAttribute('inert', 'true'); if (cta) { cta.setAttribute('tabindex', -1); diff --git a/src/implementations/vanilla/components/news-ticker/_news-ticker.scss b/src/implementations/vanilla/components/news-ticker/_news-ticker.scss index 6f31fe0ee6f..5fa0d5658aa 100644 --- a/src/implementations/vanilla/components/news-ticker/_news-ticker.scss +++ b/src/implementations/vanilla/components/news-ticker/_news-ticker.scss @@ -7,17 +7,17 @@ @use '@ecl/theme-dev/theme'; @use '@ecl/vanilla-layout-grid/mixins/breakpoints'; +$_controls-background: none !default; $_border-radius: none !default; $_border-width: none !default; $_counter-color: none !default; -$_btn-outline-width: none !default; -$_btn-padding-vertical: map.get(theme.$spacing, 'xs') !default; -$_btn-padding-horizontal: map.get(theme.$spacing, 's') !default; +$_outline-color: none !default; +$_outline-width: none !default; .ecl-news-ticker { align-items: center; background: map.get(theme.$color, 'white'); - border-color: map.get(theme.$color, 'blue-100'); + border-color: $_controls-background; border-radius: $_border-radius; border-style: solid; border-width: $_border-width; @@ -44,15 +44,15 @@ $_btn-padding-horizontal: map.get(theme.$spacing, 's') !default; .ecl-news-ticker__content { height: 0; - margin: map.get(theme.$spacing, 's'); - margin-inline-start: calc(#{map.get(theme.$spacing, 's')} - 5px); + margin: map.get(theme.$spacing, 'xs') 0; + padding: 0; overflow: hidden; transition-duration: 0.3s; width: 100%; } .ecl-news-ticker__slides { - color: map.get(theme.$color, 'blue-100'); + color: $_controls-background; font: map.get(theme.$font-prolonged, 'm'); list-style: none; margin: 0; @@ -64,41 +64,101 @@ $_btn-padding-horizontal: map.get(theme.$spacing, 's') !default; .ecl-news-ticker__slide { align-items: center; display: flex; - padding: 5px; + padding: 5px 0; + padding-inline-end: map.get(theme.$spacing, 's'); +} + +.ecl-news-ticker__slide, +.ecl-news-ticker__slide-text { + // stylelint-disable-next-line value-no-vendor-prefix + display: -webkit-box; + text-overflow: ellipsis; + overflow: hidden; + -webkit-line-clamp: 2; + line-clamp: 2; + -webkit-box-orient: vertical; +} + +.ecl-news-ticker__controls { + align-items: center; + align-self: stretch; + background-color: $_controls-background; + display: flex; + order: 2; + padding: calc(#{map.get(theme.$spacing, '2xs')} - 1px); + padding-top: calc(#{map.get(theme.$spacing, '2xs')} + 1px); + width: 100%; } .ecl-news-ticker__counter { - color: $_counter-color; - flex-grow: 1; + color: map.get(theme.$color, 'white'); + align-items: center; + align-self: stretch; + display: flex; font: map.get(theme.$font, 'm'); font-weight: bold; - margin-inline-start: map.get(theme.$spacing, 'l'); - margin-inline-end: map.get(theme.$spacing, 'xs'); + margin-inline-start: auto; + margin-inline-end: auto; + order: 3; text-align: end; - white-space: pre-wrap; + white-space: pre; } -.ecl-news-ticker__controls { - align-self: stretch; - background-color: map.get(theme.$color, 'blue-100'); - border-radius: $_border-radius 0 0 0; - display: flex; - flex-grow: 0; - padding: 1px 5px 0 7px; +.ecl-news-ticker__icon-default { + display: block; +} + +.ecl-news-ticker__icon-active { + display: none; +} + +.ecl-news-ticker__play, +.ecl-news-ticker__pause { + margin-inline-end: map.get(theme.$spacing, 'xs'); + order: 1; + + &:active, + &:hover, + &:focus { + .ecl-news-ticker__icon-default { + display: none; + } + + .ecl-news-ticker__icon-active { + display: block; + } + } } .ecl-news-ticker__prev, -.ecl-news-ticker__toggle, .ecl-news-ticker__next { - padding: $_btn-padding-vertical $_btn-padding-horizontal; + margin-inline-start: map.get(theme.$spacing, 'xs'); + order: 4; - &:focus { - padding: calc(#{$_btn-padding-vertical} - #{$_btn-outline-width}) - calc(#{$_btn-padding-horizontal} - #{$_btn-outline-width}); + &:active, + &:hover { + background-color: map.get(theme.$color, 'white-100'); + + .ecl-news-ticker__icon-default { + fill: $_controls-background; + } } +} - .ecl-button__icon--after { - margin: 0; +// stylelint-disable no-descending-specificity +.ecl-news-ticker__prev, +.ecl-news-ticker__next, +.ecl-news-ticker__play, +.ecl-news-ticker__pause { + align-items: center; + background: transparent; + border: 0; + cursor: pointer; + display: flex; + padding: map.get(theme.$spacing, 'xs'); + + &:focus { + outline: $_outline-width solid $_outline-color; } } @@ -109,30 +169,34 @@ $_btn-padding-horizontal: map.get(theme.$spacing, 's') !default; justify-content: initial; } - .ecl-news-ticker__icon { + .ecl-news-ticker__controls { + padding: 0; + width: auto; + } + + .ecl-news-ticker__counter { + background-color: map.get(theme.$color, 'white'); + color: $_counter-color; + flex-shrink: 0; + text-align: initial; + padding-inline-start: map.get(theme.$spacing, 's'); + padding-inline-end: map.get(theme.$spacing, 's'); order: 1; } - .ecl-news-ticker__container { + .ecl-news-ticker__prev { order: 2; } - .ecl-news-ticker__content { - margin: map.get(theme.$spacing, 'xs') 0 map.get(theme.$spacing, 'xs') -5px; - padding: 5px 5px 5px 0; + .ecl-news-ticker__play, + .ecl-news-ticker__pause { + margin-inline-start: map.get(theme.$spacing, 'xs'); + order: 3; } - .ecl-news-ticker__controls { - align-items: center; - border-radius: 0; - flex-grow: initial; + .ecl-news-ticker__next { + margin-inline-start: 0; + margin-inline-end: map.get(theme.$spacing, 'xs'); order: 4; - padding: 0 5px 0 7px; - } - - .ecl-news-ticker__counter { - flex-shrink: 0; - order: 3; - text-align: initial; } } diff --git a/src/implementations/vanilla/components/news-ticker/news-ticker-ec.scss b/src/implementations/vanilla/components/news-ticker/news-ticker-ec.scss index 2029fddba34..f54967abe8d 100644 --- a/src/implementations/vanilla/components/news-ticker/news-ticker-ec.scss +++ b/src/implementations/vanilla/components/news-ticker/news-ticker-ec.scss @@ -1,8 +1,10 @@ @use 'sass:map'; @use '@ecl/theme-dev/theme'; @use 'news-ticker' with ( + $_controls-background: map.get(theme.$color, 'blue-130'), $_border-radius: 0, $_border-width: 2px, - $_btn-outline-width: 3px, + $_outline-color: map.get(theme.$color, 'yellow-100'), + $_outline-width: 3px, $_counter-color: map.get(theme.$color, 'grey') ); diff --git a/src/implementations/vanilla/components/news-ticker/news-ticker-eu.scss b/src/implementations/vanilla/components/news-ticker/news-ticker-eu.scss index 0ca391c0b22..e8043a830b2 100644 --- a/src/implementations/vanilla/components/news-ticker/news-ticker-eu.scss +++ b/src/implementations/vanilla/components/news-ticker/news-ticker-eu.scss @@ -1,8 +1,10 @@ @use 'sass:map'; @use '@ecl/theme-dev/theme'; @use 'news-ticker' with ( + $_controls-background: map.get(theme.$color, 'blue-140'), $_border-radius: 4px, $_border-width: 2px, - $_btn-outline-width: 2px, + $_outline-color: map.get(theme.$color, 'accent-blue-100'), + $_outline-width: 2px, $_counter-color: map.get(theme.$color, 'grey-80') ); diff --git a/src/implementations/vanilla/components/news-ticker/news-ticker.js b/src/implementations/vanilla/components/news-ticker/news-ticker.js index 4631e48f8f7..74c24c36ab2 100644 --- a/src/implementations/vanilla/components/news-ticker/news-ticker.js +++ b/src/implementations/vanilla/components/news-ticker/news-ticker.js @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ import { queryOne, queryAll } from '@ecl/dom-utils'; /** @@ -31,7 +30,8 @@ export class NewsTicker { constructor( element, { - toggleSelector = '[data-ecl-news-ticker-toggle]', + playSelector = '[data-ecl-news-ticker-play]', + pauseSelector = '[data-ecl-news-ticker-pause]', prevSelector = '[data-ecl-news-ticker-prev]', nextSelector = '[data-ecl-news-ticker-next]', containerClass = '.ecl-news-ticker__container', @@ -39,6 +39,7 @@ export class NewsTicker { slidesClass = '.ecl-news-ticker__slides', slideClass = '.ecl-news-ticker__slide', currentSlideClass = '.ecl-news-ticker__counter--current', + controlsClass = '.ecl-news-ticker__controls', attachClickListener = true, attachResizeListener = true, } = {} @@ -53,7 +54,8 @@ export class NewsTicker { this.element = element; // Options - this.toggleSelector = toggleSelector; + this.playSelector = playSelector; + this.pauseSelector = pauseSelector; this.prevSelector = prevSelector; this.nextSelector = nextSelector; this.containerClass = containerClass; @@ -61,50 +63,62 @@ export class NewsTicker { this.slidesClass = slidesClass; this.slideClass = slideClass; this.currentSlideClass = currentSlideClass; + this.controlsClass = controlsClass; this.attachClickListener = attachClickListener; this.attachResizeListener = attachResizeListener; // Private variables - this.toggle = null; this.container = null; this.content = null; this.slides = null; + this.btnPlay = null; + this.btnPause = null; this.btnPrev = null; this.btnNext = null; this.index = 1; this.total = 0; this.allowShift = true; - this.autoPlay = false; + this.autoPlay = null; this.autoPlayInterval = null; + this.hoverAutoPlay = null; this.resizeTimer = null; this.cloneFirstSLide = null; this.cloneLastSLide = null; // Bind `this` for use in callbacks - this.handleClickOnToggle = this.handleClickOnToggle.bind(this); - this.handleHoverOnTicker = this.handleHoverOnTicker.bind(this); - this.handleHoverOffTicker = this.handleHoverOffTicker.bind(this); + this.handleAutoPlay = this.handleAutoPlay.bind(this); + this.handleMouseOver = this.handleMouseOver.bind(this); + this.handleMouseOut = this.handleMouseOut.bind(this); this.shiftSlide = this.shiftSlide.bind(this); this.checkIndex = this.checkIndex.bind(this); this.moveSlides = this.moveSlides.bind(this); - this.resizeTicker = this.resizeTicker.bind(this); this.handleResize = this.handleResize.bind(this); + this.handleFocus = this.handleFocus.bind(this); } /** * Initialise component. */ init() { - this.toggle = queryOne(this.toggleSelector, this.element); + this.btnPlay = queryOne(this.playSelector, this.element); + this.btnPause = queryOne(this.pauseSelector, this.element); this.btnPrev = queryOne(this.prevSelector, this.element); this.btnNext = queryOne(this.nextSelector, this.element); this.slidesContainer = queryOne(this.slidesClass, this.element); this.container = queryOne(this.containerClass, this.element); this.content = queryOne(this.contentClass, this.element); + this.controls = queryOne(this.controlsClass, this.element); this.slides = queryAll(this.slideClass, this.element); this.total = this.slides.length; + // If only one slide, don't initialize ticker and hide controls + if (this.total <= 1 && this.controls) { + this.content.style.height = 'auto'; + this.controls.style.display = 'none'; + return false; + } + const firstSlide = this.slides[0]; const lastSlide = this.slides[this.slides.length - 1]; this.cloneFirstSLide = firstSlide.cloneNode(true); @@ -117,17 +131,16 @@ export class NewsTicker { // Refresh the slides variable after adding new cloned slides this.slides = queryAll(this.slideClass, this.element); - // Initialize position of slides and size of the ticker - this.moveSlides(false); - this.resizeTicker(); + // Initialize ticker position and size + this.handleResize(); - if (this.toggle) { - this.handleClickOnToggle(); - } + // Activate autoPlay + this.handleAutoPlay(); // Bind events - if (this.attachClickListener && this.toggle) { - this.toggle.addEventListener('click', this.handleClickOnToggle); + if (this.attachClickListener && this.btnPlay && this.btnPause) { + this.btnPlay.addEventListener('click', this.handleAutoPlay); + this.btnPause.addEventListener('click', this.handleAutoPlay); } if (this.attachClickListener && this.btnNext) { this.btnNext.addEventListener( @@ -143,16 +156,19 @@ export class NewsTicker { } if (this.slidesContainer) { this.slidesContainer.addEventListener('transitionend', this.checkIndex); + this.slidesContainer.addEventListener('mouseover', this.handleMouseOver); + this.slidesContainer.addEventListener('mouseout', this.handleMouseOut); + } + if (this.container) { + this.container.addEventListener('focus', this.handleFocus, true); } if (this.attachResizeListener) { window.addEventListener('resize', this.handleResize); } - this.element.addEventListener('mouseover', this.handleHoverOnTicker); - this.element.addEventListener('mouseout', this.handleHoverOffTicker); - // Set ecl initialized attribute this.element.setAttribute('data-ecl-auto-initialized', 'true'); + return this; } /** @@ -163,8 +179,11 @@ export class NewsTicker { this.cloneFirstSLide.remove(); this.cloneLastSLide.remove(); } - if (this.toggle) { - this.toggle.replaceWith(this.toggle.cloneNode(true)); + if (this.btnPlay) { + this.btnPlay.replaceWith(this.btnPlay.cloneNode(true)); + } + if (this.btnPause) { + this.btnPause.replaceWith(this.btnPause.cloneNode(true)); } if (this.btnNext) { this.btnNext.replaceWith(this.btnNext.cloneNode(true)); @@ -177,13 +196,23 @@ export class NewsTicker { 'transitionend', this.checkIndex ); + this.slidesContainer.removeEventListener( + 'mouseover', + this.handleMouseOver + ); + this.slidesContainer.removeEventListener('mouseout', this.handleMouseOut); + } + if (this.container) { + this.container.removeEventListener('focus', this.handleFocus, true); } if (this.attachResizeListener) { window.removeEventListener('resize', this.handleResize); } + if (this.autoPlayInterval) { + clearInterval(this.autoPlayInterval); + this.autoPlay = null; + } if (this.element) { - this.element.removeEventListener('mouseover', this.handleHoverOnTicker); - this.element.removeEventListener('mouseout', this.handleHoverOffTicker); this.element.removeAttribute('data-ecl-auto-initialized'); } } @@ -199,7 +228,7 @@ export class NewsTicker { this.moveSlides(true); } if (stopAutoPlay && this.autoPlay) { - this.handleClickOnToggle(); + this.handleAutoPlay(); } this.allowShift = false; @@ -213,7 +242,7 @@ export class NewsTicker { const newOffset = this.slides[this.index].offsetTop; const newHeight = this.slides[this.index].offsetHeight; this.content.style.height = `${newHeight}px`; - this.slidesContainer.style.transitionDuration = transition ? '0.4s' : '0s'; + this.slidesContainer.style.transitionDuration = transition ? '0.4s' : '1ms'; this.slidesContainer.style.transform = `translate3d(0px, -${newOffset}px, 0px)`; } @@ -221,6 +250,7 @@ export class NewsTicker { * Action to update slides index and position. */ checkIndex() { + // Update index if (this.index === 0) { this.index = this.total; this.moveSlides(false); @@ -229,82 +259,108 @@ export class NewsTicker { this.index = 1; this.moveSlides(false); } + + // Update pagination const currentSlide = queryOne(this.currentSlideClass, this.element); currentSlide.textContent = this.index; + // Update slides + if (this.slides) { + this.slides.forEach((slide, index) => { + const cta = queryOne('.ecl-link', slide); + if (this.index === index) { + slide.removeAttribute('inert', 'true'); + if (cta) { + cta.removeAttribute('tabindex', -1); + } + } else { + slide.setAttribute('inert', 'true'); + if (cta) { + cta.setAttribute('tabindex', -1); + } + } + }); + } + this.allowShift = true; } /** * Toggles play/pause slides. */ - handleClickOnToggle() { - const useNode = queryOne( - `${this.toggleSelector} .ecl-icon use`, - this.element - ); - const originalXlinkHref = useNode.getAttribute('xlink:href'); - let newXlinkHref = ''; - + handleAutoPlay() { if (!this.autoPlay) { this.autoPlayInterval = setInterval(() => { this.shiftSlide(1); }, 5000); this.autoPlay = true; - - newXlinkHref = originalXlinkHref.replace('play', 'pause'); + const isFocus = document.activeElement === this.btnPlay; + this.btnPlay.style.display = 'none'; + this.btnPause.style.display = 'flex'; + if (isFocus) { + this.btnPause.focus(); + } } else { clearInterval(this.autoPlayInterval); this.autoPlay = false; - - newXlinkHref = originalXlinkHref.replace('pause', 'play'); + const isFocus = document.activeElement === this.btnPause; + this.btnPlay.style.display = 'flex'; + this.btnPause.style.display = 'none'; + if (isFocus) { + this.btnPlay.focus(); + } } - useNode.setAttribute('xlink:href', newXlinkHref); } /** - * Hover on ticker. + * Trigger events on mouseover. */ - handleHoverOnTicker() { - clearInterval(this.autoPlayInterval); + handleMouseOver() { + this.hoverAutoPlay = this.autoPlay; + if (this.hoverAutoPlay) { + this.handleAutoPlay(); + } return this; } /** - * Hover out ticker. + * Trigger events on mouseout. */ - handleHoverOffTicker() { - if (this.autoPlay) { - this.autoPlayInterval = setInterval(() => { - this.shiftSlide(1); - }, 5000); + handleMouseOut() { + if (this.hoverAutoPlay) { + this.handleAutoPlay(); } return this; } /** - * Resize Slides container at the height of the highest slide. + * Trigger events on resize. */ - resizeTicker() { + handleResize() { let highestSlide = 0; this.slides.forEach((slide) => { const slideHeight = slide.offsetHeight; highestSlide = highestSlide < slideHeight ? slideHeight : highestSlide; }); + highestSlide = highestSlide < 58 ? 58 : highestSlide; this.container.style.height = `${highestSlide + 10}px`; + this.moveSlides(false); } /** - * Trigger events on resize + * Trigger events on focus. + * @param {Event} e */ - handleResize() { - this.moveSlides(false); - this.resizeTicker(); - - if (this.autoPlay) { - this.handleClickOnToggle(); + handleFocus(e) { + const focusElement = e.target; + // Disable autoplay if focus is on a slide CTA + if ( + focusElement && + focusElement.contains(document.activeElement) && + this.autoPlay + ) { + this.handleAutoPlay(); } - return this; } } diff --git a/src/specs/components/news-ticker/demo/data.js b/src/specs/components/news-ticker/demo/data.js index 95c36ea6dd2..714765831d9 100644 --- a/src/specs/components/news-ticker/demo/data.js +++ b/src/specs/components/news-ticker/demo/data.js @@ -35,6 +35,7 @@ module.exports = { { content: 'Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit sed quia consequuntur magni dolores', + link: exampleLink, }, ], };