Skip to content

Commit

Permalink
Add carousel example (pull #958)
Browse files Browse the repository at this point in the history
Resolves issue #458 by adding a basic example of the carousel pattern that demonstrates how to make automatic rotation accessible.
  • Loading branch information
jongund authored and mcking65 committed Jan 15, 2019
1 parent a161bc6 commit 4c846e4
Show file tree
Hide file tree
Showing 13 changed files with 1,168 additions and 0 deletions.
525 changes: 525 additions & 0 deletions examples/carousel/carousel-1/carousel-1.html

Large diffs are not rendered by default.

178 changes: 178 additions & 0 deletions examples/carousel/carousel-1/css/carousel.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@

/*.carousel*/
.carousel-item {
display: none;
max-height: 400px;
max-width: 900px;
position: relative;
overflow: hidden;
width: 100%;
}

.carousel .carousel-item.active {
display: block;
}

/* More like bootstrap, less accessible*/

.carousel .carousel-inner {
max-width: 900px;
position: relative;
}

.carousel button.pause {
display: block;
font-size: 20px;
width: auto;
left: -300em;
margin-bottom: 10px;
height: auto;
position: relative;
top: 5px;
right: -20px;
border: thin solid outset;
}

.carousel button[aria-disabled=true] {
color: #666;
}

.carousel button.pause:focus{
display: block;
position: relative;
font-size: 20px;
width: auto;
left: 0px;
margin-bottom: 10px;
height: auto;
position: relative;
top: 5px;
right: -20px;
}

.carousel .carousel-items {
border: solid 2px transparent;
}

.carousel .carousel-items.focus {
border-color: white;
outline: solid 3px #005A9C;
}

.carousel .carousel-inner .carousel-image a img {
height: 100%;
width: 100%;
}

.carousel .carousel-inner .carousel-caption a {
text-decoration: underline;
border: none;
}

.carousel .carousel-inner .carousel-caption a:focus,
.carousel .carousel-inner .carousel-caption a:hover {
outline: solid 2px #FFF;
outline-offset: 1px;
}

.carousel .carousel-inner .carousel-caption h3 a {
color: #fff;
font-weight: 600;
}

.carousel .carousel-inner .carousel-caption p {
font-size: 1em;
line-height: 1.5;
margin-bottom: 0;
}

.carousel .carousel-inner .carousel-caption {
bottom: 0;
left: 0;
padding: 3% 3% 50px;
right: 0;
text-shadow: none
}

.carousel:hover .carousel-inner .carousel-caption,
.carousel .carousel-item.focus .carousel-caption {
background-color: rgba(0, 0, 0, 0.4);
}

.carousel .carousel-caption {
position: absolute;
right: 15%;
bottom: 0px;
left: 15%;
padding-top: 20px;
padding-bottom: 20px;
color: #fff;
text-align: center;
text-shadow: 0 1px 2px rgba(0,0,0,.6);
}

.carousel .carousel-inner,
.carousel .carousel-item,
.carousel .carousel-slide {
max-height: 400px;
}

.carousel .carousel-control {
position: absolute;
top: 0;
z-index: 10;
font-size: 200%;
font-weight: bold;
color: #fff;
text-align: center;
text-shadow: 0 1px 2px rgba(0,0,0,.6);
}

.carousel a.carousel-control svg {
position: relative;
display: inline-block;
top: 45%;
}

.carousel a.carousel-control svg polygon {
opacity: 0.7;
}

.carousel a.carousel-control:focus {
border: 3px solid #FFF;
outline: 1px solid #005A9C;
}

.carousel a.carousel-control:focus svg polygon,
.carousel a.carousel-control:hover svg polygon {
opacity: 1.0;
}

.carousel a.carousel-control.previous {
bottom: 0;
width: 15%;
background-image: linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);
}

.carousel a.carousel-control.previous:focus,
.carousel a.carousel-control.previous:hover {
bottom: 0;
width: 15%;
background-image: linear-gradient(to right,rgba(0,0,0,.7) 0,rgba(0,0,0,.0001) 100%);
}

.carousel a.carousel-control.next {
right: 0;
bottom: 0;
width: 15%;
background-image: linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);
}

.carousel a.carousel-control.next:focus,
.carousel a.carousel-control.next:hover {
right: 0;
bottom: 0;
width: 15%;
background-image: linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.7) 100%);
}

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
220 changes: 220 additions & 0 deletions examples/carousel/carousel-1/js/carousel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/*
* File: Carousel.js
*
* Desc: Carousel widget that implements ARIA Authoring Practices
*
*/

/*
* @constructor CarouselTablist
*
*
*/
var Carousel = function (domNode) {
this.domNode = domNode;

this.items = [];

this.firstItem = null;
this.lastItem = null;
this.currentDomNode = null;
this.liveRegionNode = null;
this.currentItem = null;
this.pauseButton = null;

this.startLabel = 'Start automatic slide show';
this.stopLabel = 'Stop automatic slide show';

this.rotate = true;
this.hasFocus = false;
this.hasHover = false;
this.isStopped = false;
this.timeInterval = 5000;
};

Carousel.prototype.init = function () {

this.liveRegionNode = this.domNode.querySelector('.carousel-items');

var items = this.domNode.querySelectorAll('.carousel-item');

for (var i = 0; i < items.length; i++) {
var item = new CarouselItem(items[i], this);

item.init();
this.items.push(item);

if (!this.firstItem) {
this.firstItem = item;
this.currentDomNode = item.domNode;
}
this.lastItem = item;

var imageLinks = items[i].querySelectorAll('.carousel-image a');

if (imageLinks && imageLinks[0]) {
imageLinks[0].addEventListener('focus', this.handleImageLinkFocus.bind(this));
imageLinks[0].addEventListener('blur', this.handleImageLinkBlur.bind(this));
}

}

// Next Slide and Previous Slide Buttons

var elems = document.querySelectorAll('.carousel a.carousel-control');

for (var i = 0; i < elems.length; i++) {
if (elems[i].tagName.toLowerCase() == 'a') {
var button = new CarouselButton(elems[i], this);

button.init();
}
}

this.currentItem = this.firstItem;

this.pauseButton = this.domNode.parentNode.parentNode.querySelector('button.pause');
if (this.pauseButton) {
var button = new PauseButton(this.pauseButton, this);
button.init();
this.pauseButton.innerHTML = this.stopLabel;
}

this.domNode.addEventListener('mouseover', this.handleMouseOver.bind(this));
this.domNode.addEventListener('mouseout', this.handleMouseOut.bind(this));

// Start rotation
setTimeout(this.rotateSlides.bind(this), this.timeInterval);
};

Carousel.prototype.setSelected = function (newItem, moveFocus) {
if (typeof moveFocus != 'boolean') {
moveFocus = false;
}

for (var i = 0; i < this.items.length; i++) {
this.items[i].hide();
}

this.currentItem = newItem;
this.currentItem.show();

if (moveFocus) {
this.currentItem.domNode.focus();
}
};

Carousel.prototype.setSelectedToPreviousItem = function (currentItem, moveFocus) {
if (typeof moveFocus != 'boolean') {
moveFocus = false;
}

var index;

if (typeof currentItem !== 'object') {
currentItem = this.currentItem;
}

if (currentItem === this.firstItem) {
this.setSelected(this.lastItem, moveFocus);
}
else {
index = this.items.indexOf(currentItem);
this.setSelected(this.items[index - 1], moveFocus);
}
};

Carousel.prototype.setSelectedToNextItem = function (currentItem, moveFocus) {
if (typeof moveFocus != 'boolean') {
moveFocus = false;
}

var index;

if (typeof currentItem !== 'object') {
currentItem = this.currentItem;
}

if (currentItem === this.lastItem) {
this.setSelected(this.firstItem, moveFocus);
}
else {
index = this.items.indexOf(currentItem);
this.setSelected(this.items[index + 1], moveFocus);
}
};

Carousel.prototype.rotateSlides = function () {
if (this.rotate) {
this.setSelectedToNextItem();
}
setTimeout(this.rotateSlides.bind(this), this.timeInterval);
};

Carousel.prototype.startRotation = function () {
if (!this.hasHover && !this.hasFocus && !this.isStopped) {
this.rotate = true;
this.liveRegionNode.setAttribute('aria-live', 'off');
this.pauseButton.innerHTML = this.stopLabel;
}
this.disablePauseButton();
};

Carousel.prototype.stopRotation = function () {
this.rotate = false;
this.liveRegionNode.setAttribute('aria-live', 'polite');
this.pauseButton.innerHTML = this.startLabel;
this.disablePauseButton();
};

Carousel.prototype.disablePauseButton = function () {
if (this.hasHover || this.hasFocus) {
this.pauseButton.setAttribute('aria-disabled', 'true');
}
else {
this.pauseButton.removeAttribute('aria-disabled');
}
};

Carousel.prototype.toggleRotation = function () {
if (this.isStopped) {
if (this.pauseButton.getAttribute('aria-disabled') !== 'true') {
this.isStopped = false;
this.startRotation();
}
}
else {
this.isStopped = true;
this.stopRotation();
}
};

Carousel.prototype.handleImageLinkFocus = function () {
this.liveRegionNode.classList.add('focus');
};

Carousel.prototype.handleImageLinkBlur = function () {
this.liveRegionNode.classList.remove('focus');
};

Carousel.prototype.handleMouseOver = function () {
this.hasHover = true;
this.stopRotation();
};

Carousel.prototype.handleMouseOut = function () {
this.hasHover = false;
this.startRotation();
};

/* Initialize Carousel Tablists */

window.addEventListener('load', function (event) {
var carousels = document.querySelectorAll('.carousel');

for (var i = 0; i < carousels.length; i++) {
var carousel = new Carousel(carousels[i]);
carousel.init();
}
}, false);

Loading

0 comments on commit 4c846e4

Please sign in to comment.