"carousel"
Bootstrap 4.1.1 Snippet by evarevirus

<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <!------ Include the above in your HEAD tag ----------> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <link rel="shortcut icon" type="image/x-icon" href="https://static.codepen.io/assets/favicon/favicon-aec34940fbc1a6e787974dcd360f2c6b63348d4b1f4e06c77743096d55480f33.ico" /> <link rel="mask-icon" type="" href="https://static.codepen.io/assets/favicon/logo-pin-8f3771b1072e3c38bd662872f6b673a722f4b3ca2421637d5596661b4e2132cc.svg" color="#111" /> <title>CodePen - Custom Carousel Generator</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css"> <style> *, *::before, *::after { margin: 0; padding: 0; box-sizing: inherit; } html { box-sizing: border-box; } body { background-color: #4e4e4e; } a { color: inherit; } .hidden { visibility: hidden !important; } .disabled { opacity: 0.4; } .removed { display: none !important; } header { position: relative; height: 65px; display: flex; align-items: flex-end; background-color: #4e4e4e; overflow: hidden; font-family: sans-serif; } header::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; border-bottom: 1px solid black; box-sizing: content-box; pointer-events: none; } .tab-nav { margin: 0 3%; } .tab-nav__list { list-style-type: none; display: flex; } .tab-nav__item { margin: 0 2px; } .tab-nav__item--active { z-index: 20; } .tab-nav__btn { color: white; border-radius: 6px 6px 0 0; padding: 10px 12px; border: 1px solid black; border-bottom: none; cursor: pointer; background-color: #404040; white-space: nowrap; } .tab-nav__btn:focus { outline: none; } .tab-nav__btn--active { border: 1px solid #191919; border-bottom: none; box-shadow: 1px -1px 2px rgba(0, 0, 0, 0.5); background-color: #4e4e4e; } main { padding: 40px 3%; min-width: 316px; } .content-panel { display: flex; } #settings-panel { justify-content: space-between; align-items: flex-start; flex-direction: row-reverse; flex-wrap: wrap; } .settings *:focus { outline: 1px solid orangered; } .settings { font-family: sans-serif; max-width: 40%; min-width: 275px; margin-right: 3%; } @media (max-width: 56.25em) { .settings { max-width: none; width: 100%; margin-right: 0; } } .settings__value-units-group { display: flex; align-items: stretch; } .settings__width-input { width: 60px; margin-right: 4px; } .settings__width-range { margin-left: 20px; width: 100%; } .settings__list { display: flex; flex-direction: column; list-style-type: none; } .settings__item { position: relative; border: 2px solid #333333; border-radius: 4px; margin-bottom: 24px; } .settings__item:last-child { margin-bottom: 0; } .settings__group { display: inherit; align-items: center; flex-wrap: wrap; margin-top: -14px; margin-left: -22px; padding: 14px 0; } @media (max-width: 37.5em) { .settings__group { margin-left: -18px; } } .settings__group--space { justify-content: space-between; } .settings__collapse-container { position: relative; display: flex; flex-direction: column; justify-content: center; padding: 12px 3% 6px; max-height: 500px; transition: max-height 0.3s ease-in, opacity 0.4s; overflow: hidden; } .settings__collapse-container--collapsed { transition: max-height 0.3s, opacity 0.2s 0.1s; max-height: 18px !important; opacity: 0 !important; } .settings__divider { border: none; border-top: 1px solid #333333; } .settings__heading { position: absolute; top: 0; left: 0; -webkit-transform: translateY(-55%); transform: translateY(-55%); background-color: #4e4e4e; font-size: 18px; font-weight: normal; margin: 0 14px; padding: 0 6px; color: #e6e6e6; } .settings__collapse-btn-wrapper { position: absolute; top: 0; right: 0; -webkit-transform: translateY(-55%); transform: translateY(-55%); margin-right: 14px; background-color: #4e4e4e; padding: 0 6px; z-index: 20; } .settings__collapse-btn { background-color: #4e4e4e; font-size: 18px; width: 24px; height: 24px; color: #e6e6e6; border-radius: 4px; border: 1px solid #333333; cursor: pointer; } .settings__label { color: #e6e6e6; margin-right: 12px; white-space: nowrap; } .settings__label--checkbox { display: flex; margin-right: 0; } .settings__unit { color: #e6e6e6; } .settings__wrap-group { display: flex; flex-wrap: wrap; } .settings__input-group { display: flex; align-items: center; margin-top: 14px; margin-left: 22px; transition: opacity 0.2s; } @media (max-width: 37.5em) { .settings__input-group { margin-left: 18px; } } .settings__input-wrapper { position: relative; width: 16px; height: 16px; } .settings__radio-label { margin-left: 3px; } .settings__number--two-digit { width: 44px; } .settings__number--three-digit { width: 52px; } .settings__text { width: 100%; padding: 0 2px; } .settings__color { width: 24px; height: 24px; } .settings__opacity-range { margin: 0 4px; width: 60px; } .settings__custom-ratio { width: 60px; margin-left: 4px; } .settings__checkbox-wrapper { position: relative; width: 16px; height: 16px; margin-right: 6px; } .settings input[type="checkbox"] { position: absolute; top: 0; left: 0; width: 100%; height: 100%; margin: 0; padding: 0; } .settings__checkbox { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: darkgray; border: solid 1px #333333; box-shadow: inset 1px 1px 2px #282828; box-sizing: border-box; padding: 0; margin: 0; } .settings__checkbox-text { font-size: 16px; } .settings__checkbox::after { content: ''; position: absolute; top: 50%; left: 50%; opacity: 0; color: black; font-weight: bold; width: 35%; height: 70%; border-right: solid 2px #333333; border-bottom: solid 2px #333333; -webkit-transform: translate(-40%, -52%) rotate(45deg); transform: translate(-40%, -52%) rotate(45deg); box-sizing: border-box; } .settings__checkbox-wrapper input:checked ~ .settings__checkbox { background-color: #e6e6e6; } .settings__checkbox-wrapper input[type="checkbox"]:checked ~ .settings__checkbox::after { opacity: 1; } .settings .disabled { opacity: 0.4; } .settings__input-description { color: #e6e6e6; font-size: 14px; font-style: italic; } .preview { position: relative; flex: 1; font-family: sans-serif; color: #e6e6e6; border: 2px solid #333333; border-radius: 4px; } @media (max-width: 56.25em) { .preview { flex: none; width: 100%; margin-bottom: 24px; } } .preview__heading { position: absolute; top: 0; left: 0; -webkit-transform: translateY(-55%); transform: translateY(-55%); background-color: #4e4e4e; font-size: 18px; font-weight: normal; margin: 0 14px; padding: 0 6px; color: #e6e6e6; transition: -webkit-transform 0.3s; transition: transform 0.3s; transition: transform 0.3s, -webkit-transform 0.3s; } .preview__wrapper { margin: 36px 0; display: flex; flex-direction: column; align-items: center; text-align: center; } @media (max-width: 56.25em) { .preview__wrapper { margin: 28px 0; } } .preview__search-form { display: flex; justify-content: center; align-items: center; min-width: 48vw; padding: 10px 3%; flex-wrap: wrap; } @media (max-width: 56.25em) { .preview__search-form { width: 100%; } } .preview__search-form *:focus { outline: 1px solid orangered; } .preview__form-heading { font-size: 16px; font-weight: normal; padding: 0 3%; } .preview__label { color: #e6e6e6; } .preview__search-input { width: 250px; padding: 2px; margin: 3% 4%; } @media (max-width: 37.5em) { .preview__search-input { width: 70%; } } .preview__search-select { margin: 0 8px 0 4px; } .preview__search-submit { padding: 2px 10px; margin: 0 20px; background-color: #404040; color: #e6e6e6; cursor: pointer; } .preview__search-submit:hover { background-color: #333333; } #source-code-panel { flex-direction: column; align-items: center; font-family: sans-serif; } .sourcecode { display: flex; flex-direction: column; max-width: 100%; } .sourcecode__block { position: relative; background-color: darkgray; border: 2px solid #333333; border-radius: 4px; margin: 0 40px 80px; padding: 20px; max-height: 500px; overflow: auto; -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; } @media (max-width: 37.5em) { .sourcecode__block { margin: 0 0 40px; } } .sourcecode__heading { background-color: #4e4e4e; font-size: 18px; font-weight: normal; margin-left: 54px; padding: 0 6px; color: #e6e6e6; } </style> <script> window.console = window.console || function(t) {}; </script> <script> if (document.location.search.match(/type=embed/gi)) { window.parent.postMessage("resize", "*"); } </script> </head> <body translate="no"> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Image Carousel</title> <style title="carousel"> #my-carousel.carousel { width: 85%; } #my-carousel.carousel .prev { transform: translate(-100%, 0); } #my-carousel.carousel .queue { transform: translate(100%, 0); } #my-carousel .carousel__viewport-wrapper { border-radius: 3%; } #my-carousel .carousel__viewport-wrapper:hover .carousel__controls-background--arrow { opacity: 0.5; } #my-carousel .carousel__viewport-wrapper:hover .carousel__controls-background--indicator { opacity: 0.5; } #my-carousel .carousel__viewport { padding-bottom: 75%; } #my-carousel .carousel__slide-container { background-color: black; transition: transform 0.3s ease-in; } #my-carousel .carousel__slide-overlay { background-color: black; opacity: 0.4; display: none; } #my-carousel .carousel__indicator-bar { visibility: visible; } #my-carousel .carousel__indicator-bar--interior:hover .carousel__controls-background--indicator { opacity: 0.5; } #my-carousel .carousel__indicator-marker { border: 1px solid #ffffff; opacity: 0.6; } #my-carousel .carousel__indicator-marker--active { background-color: #ffffff; box-shadow: 0 0 5px 0 #ffffff; pointer-events: none; opacity: 1; } #my-carousel .carousel__controls svg { opacity: 0.7; } #my-carousel .carousel__controls path { stroke: white; } #my-carousel .carousel__controls-background { background-color: black; } #my-carousel .carousel__controls-background::after { background-color: black; } #my-carousel .carousel__controls-background--arrow { box-shadow: 0 0 8px 9px black; opacity: 0; } #my-carousel .carousel__controls-background--indicator { box-shadow: 0 0 8px 9px black; opacity: 0; } .carousel, .carousel *, .carousel *::before, .carousel *::after { margin: 0; padding: 0; box-sizing: border-box; } .carousel { display: flex; flex-direction: column; align-items: center; position: relative; overflow: hidden; } .carousel__viewport-wrapper { position: relative; width: 100%; overflow: hidden; } .carousel__viewport { position: relative; width: 100%; background-color: black; pointer-events: none; } @media (max-width: 37.5em) { .carousel__viewport { max-width: 100%; max-height: 100%; } } .carousel__controls { position: absolute; top: 50%; transform: translateY(-50%); display: flex; align-items: center; border: none; background-color: transparent; z-index: 100; cursor: pointer; outline: none; width: 5%; max-width: 54px; min-width: 20px; z-index: 10; } @media (max-width: 37.5em) { .carousel__controls { display: none; } } .carousel__controls svg { width: 100%; max-width: 46px; padding: 20%; transition: opacity 0.3s; z-index: 20; } .carousel__controls--left { left: 0; border-radius: 0 10px 10px 0; } .carousel__controls--right { right: 0; border-radius: 10px 0 0 10px; } .carousel__controls:focus .carousel__focus-ring { border: 2px solid orangered; box-shadow: 0 0 6px orangered; } .carousel__controls:hover svg { opacity: 1 !important; } .carousel__controls-background { position: absolute; top: 0; right: 0; bottom: 0; left: 0; border: none; border-radius: inherit; transition: opacity 0.5s ease-in-out; z-index: -20; } .carousel__controls-background::after { content: ''; position: absolute; top: -1px; left: 0; bottom: -1px; right: 0; border-radius: inherit; border: none; } .carousel__icon-left { left: 0; } .carousel__icon-right { right: 0; } .carousel__focus-ring { position: absolute; top: 0; right: 0; bottom: 0; left: 0; border: none; border-radius: inherit; } .carousel__indicator-bar { padding: 0.12vw 0.4vw; padding-top: 0; border-radius: 10px 10px 0 0; z-index: 100; transition: background-color 0.4s; backface-visibility: hidden; } .carousel__indicator-bar--interior { position: absolute; left: 50%; bottom: 0; transform: translateX(-50%); } .carousel__indicator-bar--exterior { position: relative; } .carousel__indicator-wrapper { display: flex; } .carousel__indicator-marker { width: 10px; height: 10px; border-radius: 50%; margin: 8px 5px; cursor: pointer; } @media (max-width: 37.5em) { .carousel__indicator-marker { margin: 5px; } } .carousel__slide-container { position: absolute; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden; display: flex; align-items: center; justify-content: center; opacity: 1; } .carousel__slide-container--no-trans { transition: transform 0s !important; } .carousel__slide-container--flick-trans { transition: transform 0.2s ease-out !important; } .carousel__slide-container--jumper { transition: transform 0.075s !important; } .carousel__slide-overlay { position: absolute; top: 0; right: 0; bottom: 0; left: 0; pointer-events: none; } .carousel__slide-wrapper { flex-shrink: 0; position: relative; } .carousel__slide-wrapper--landscape { width: 100% !important; } .carousel__slide-wrapper--portrait { height: 100% !important; } .carousel__slide { display: block; width: 100%; height: 100%; } .carousel__slide--landscape-contain { width: 100%; height: auto; } .carousel__slide--portrait-contain { height: 100%; width: auto; } .carousel__slide--landscape-cover { max-width: none !important; height: 100%; } .carousel__slide--portrait-cover { max-height: none !important; width: 100%; } .carousel .hide { visibility: hidden; transition: none !important; } .carousel__image-attribution { position: absolute; left: 0; top: 0; padding: 8px 14px; color: #d2d2d2; font-size: 12px; font-family: sans-serif; border-radius: 0 0 10px 0; z-index: 100; transition: background-color 0.4s, color 0.4s; pointer-events: auto; } .carousel__image-attribution:hover { background-color: rgba(0, 0, 0, 0.6); color: #e1e1e1; } </style> </head> <body> <header> <nav class="tab-nav"> <ul role="tablist" class="tab-nav__list"> <li class="tab-nav__item tab-nav__item--active"> <button id="settings-tab" role="tab" aria-selected="true" aria-controls="settings-panel" class="tab-nav__btn tab-nav__btn--active">Settings</button> </li> <li class="tab-nav__item"> <button id="source-code-tab" role="tab" aria-selected="false" aria-controls="source-code-panel" class="tab-nav__btn">Source Code</button> </li> </ul> </nav> </header> <main> <div id="settings-panel" class="content-panel" role="tabpanel" aria-labelledby="settings-tab"> <div class="preview"> <h2 class="preview__heading">Preview</h2> <div class="preview__wrapper"> <h3 class="preview__form-heading">Test your customized Carousel with the Unsplash API</h3> <form class="preview__search-form"> <input type="text" class="preview__search-input" placeholder="Search for new images"> <div> <label class="preview__label" for="unsplash-quant">Quantity</label> <select name="unsplash-quant" class="preview__search-select" id="unsplash-quant"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5" selected>5</option> <option value="6">6</option> <option value="7">7</option> <option value="8">8</option> <option value="9">9</option> <option value="10">10</option> </select> <button type="submit" class="preview__search-submit" id="carousel-search">Submit</button> </div> </form> <div id="my-carousel" class="carousel"></div> </div> </div> <form class="settings" autocomplete="off"> <ul class="settings__list"> <li class="settings__item"> <h2 class="settings__heading">Carousel</h2> <div class="settings__collapse-btn-wrapper"> <button type="button" class="settings__collapse-btn" aria-expanded="true" aria-controls="carousel-settings">−</button> </div> <div id="carousel-settings" class="settings__collapse-container"> <div class="settings__group"> <div class="settings__input-group"> <label class="settings__label" for="carousel-namespace">Namespace ID</label> <input type="text" class="settings__text" id="carousel-namespace" placeholder="i.e. my-carousel" name="carouselNamespace"> </div> <div class="settings__input-group"> <span class="settings__input-description">A unique string used as html ID for Carousel instance</span> </div> </div> <hr class="settings__divider"> <div class="settings__group"> <div class="settings__input-group"> <label for="carousel-autoplay" class="settings__label settings__label--checkbox"> <div class="settings__checkbox-wrapper"> <input type="checkbox" id="carousel-autoplay" data-target="autoplay-properties" name="carouselAutoplay"> <span class="settings__checkbox"></span> </div> Autoplay </label> </div> <div class="settings__input-group disabled autoplay-properties"> <input id="autoplay-duration" class="settings__width-input" type="number" min="1" max="12" value="5" step="0.5" name="autoplayDuration" disabled> <span class="settings__unit">secs</span> </div> </div> </div> </li> <li class="settings__item"> <h2 class="settings__heading">Viewport</h2> <div class="settings__collapse-btn-wrapper"> <button type="button" class="settings__collapse-btn" aria-expanded="true" aria-controls="viewport-settings">−</button> </div> <div id="viewport-settings" class="settings__collapse-container"> <div class="settings__group"> <div class="settings__input-group"> <label class="settings__label" for="viewport-width">Width</label> <div class="settings__value-units-group"> <input id="viewport-width" class="settings__width-input" type="number" min="10" max="100" value="85" name="percentWidth"> <select name="widthUnits" id="width-units"> <option value="%">%</option> <option value="px">px</option> </select> </div> <input class="settings__width-range" type="range" min="10" max="100" step="1" value="85" name="percentWidth"> </div> <div class="settings__input-group"> <label class="settings__label" for="aspect-ratio">Aspect Ratio</label> <select name="aspectRatio" id="aspect-ratio"> <option value="4:3">4:3</option> <option value="3:2">3:2</option> <option value="1:1">1:1</option> <option value="16:9">16:9</option> <option value="10:3">10:3</option> <option value="3:4">3:4</option> <option value="2:3">2:3</option> </select> </div> </div> <hr class="settings__divider"> <div class="settings__group"> <div class="settings__input-group"> <label for="viewport-border" class="settings__label settings__label--checkbox"> <div class="settings__checkbox-wrapper"> <input type="checkbox" id="viewport-border" data-target="border-properties" name="viewportBorder"> <span class="settings__checkbox"></span> </div> Border </label> </div> <div class="settings__input-group disabled border-properties"> <input class="settings__color" type="color" id="viewport-border-color" value="#000000" name="viewportBorderColor" disabled> </div> <div class="settings__input-group disabled border-properties"> <label class="settings__label" for="border-thickness">Thickness</label> <input id="border-thickness" class="settings__number--two-digit" type="number" min="1" max="10" value="1" name="viewportBorderThickness" disabled> </div> </div> <hr class="settings__divider"> <div class="settings__group"> <div class="settings__input-group"> <label class="settings__label" for="viewport-rounding">Rounded Corners</label> <select name="roundingUnits" id="viewport-border-radius"> <option value="px">circular (px)</option> <option value="%">elliptical (%)</option> </select> </div> <div class="settings__input-group"> <input type="range" min="0" max="50" step="1" id="viewport-rounding" value="3" name="viewportRounding"> </div> </div> </div> </li> <li class="settings__item"> <h2 class="settings__heading">Image</h2> <div class="settings__collapse-btn-wrapper"> <button type="button" class="settings__collapse-btn" aria-expanded="true" aria-controls="image-settings">−</button> </div> <div id="image-settings" class="settings__collapse-container"> <div class="settings__group"> <div class="settings__input-group"> <label class="settings__label" for="viewport-width">Size</label> <select name="imageSize" id="image-size"> <option value="contain">contain</option> <option value="cover">cover</option> </select> </div> <div class="settings__input-group"> <label class="settings__label" for="end-cap-color">End-caps</label> <input class="settings__color" type="color" id="end-cap-color" value="#000000" name="endCapColor"> </div> </div> <hr class="settings__divider"> <div class="settings__group"> <div class="settings__input-group"> <label for="image-overlay" class="settings__label settings__label--checkbox"> <div class="settings__checkbox-wrapper"> <input type="checkbox" id="image-overlay" data-target="overlay-properties" name="imageOverlay"> <span class="settings__checkbox"></span> </div> Overlay </label> </div> <div class="settings__input-group disabled overlay-properties"> <input class="settings__color" type="color" id="image-overlay-color" value="#000000" name="imageOverlayColor" disabled> </div> <div class="settings__input-group disabled overlay-properties"> <label class="settings__label" for="overlay-opacity">Opacity</label> <input id="image-overlay-opacity" class="settings__number--three-digit" type="number" min="1" max="100" value="20" name="imageOverlayOpacity" disabled> </div> </div> <hr class="settings__divider"> <div class="settings__group"> <div class="settings__input-group"> <label class="settings__label" for="slide-animation">Slide Animation</label> <select name="transitionStyle" id="slide-animation"> <option value="horizontal">horizontal</option> <option value="viewmaster">view-master</option> <option value="vertical">vertical</option> <option value="dissolve">dissolve</option> </select> </div> </div> </div> </li> <li class="settings__item"> <h2 class="settings__heading">Controls</h2> <div class="settings__collapse-btn-wrapper"> <button type="button" class="settings__collapse-btn" aria-expanded="true" aria-controls="controls-settings">−</button> </div> <div id="controls-settings" class="settings__collapse-container"> <div class="settings__group"> <div class="settings__input-group"> <label class="settings__label" for="arrow-color">Arrows</label> <input class="settings__color" type="color" id="arrow-color" value="#ffffff" name="arrowColor"> </div> <div class="settings__input-group"> <label class="settings__label" for="arrow-opacity">Opacity</label> <input id="arrow-opacity" class="settings__number--three-digit" type="number" min="1" max="100" value="70" name="arrowOpacity"> </div> </div> <hr class="settings__divider"> <div class="settings__group"> <div class="settings__input-group"> <label for="indicator-bar" class="settings__label settings__label--checkbox"> <div class="settings__checkbox-wrapper"> <input type="checkbox" id="indicator-bar" data-target="indicator-bar-properties" name="indicatorBar" checked> <span class="settings__checkbox"></span> </div> Indicator Bar </label> </div> <div class="settings__input-group indicator-bar-properties"> <label class="settings__label" for="indicator-bar-location">Location</label> <select name="indicatorBarLocation" id="indicator-bar-location"> <option value="interior">interior</option> <option value="exterior">exterior</option> </select> </div> <div class="settings__input-group indicator-bar-properties"> <label class="settings__label" for="indicator-bar-opacity">Opacity</label> <input id="indicator-bar-opacity" class="settings__number--three-digit" type="number" min="1" max="100" value="60" name="indicatorBarOpacity"> </div> <div class="settings__wrap-group"> <div class="settings__input-group indicator-bar-properties"> <label class="settings__label" for="indicator-bar-style">Style</label> <select name="indicatorBarStyle" id="indicator-bar-style"> <option value="1">one color</option> <option value="2">two colors</option> </select> </div> <div class="settings__wrap-group"> <div class="settings__input-group indicator-bar-properties"> <label class="settings__label" for="indicator-active-color">Active</label> <input class="settings__color" type="color" id="indicator-active-color" value="#ffffff" name="indicatorActiveColor"> </div> <div class="settings__input-group indicator-bar-properties removed"> <label class="settings__label" for="indicator-inactive-color">Inactive</label> <input class="settings__color" type="color" id="indicator-inactive-color" value="#ffffff" name="indicatorInactiveColor"> </div> </div> </div> </div> <hr class="settings__divider"> <div class="settings__group settings__group--space"> <div class="settings__wrap-group"> <div class="settings__input-group"> <label for="arrow-background" class="settings__label settings__label--checkbox"> <div class="settings__checkbox-wrapper"> <input type="checkbox" id="arrow-background" data-target="arrow-background-properties" name="arrowBackground" checked> <span class="settings__checkbox"></span> </div> Arrow Background </label> </div> <div class="settings__input-group arrow-background-properties"> <label class="settings__label" for="arrow-background-visibility">Visibility</label> <select name="arrowBackgroundVisibility" id="arrow-background-visibility"> <option value="viewport">viewport hover</option> <option value="always">always</option> </select> </div> </div> <div class="settings__wrap-group"> <div class="settings__input-group"> <label for="indicator-background" class="settings__label settings__label--checkbox"> <div class="settings__checkbox-wrapper"> <input type="checkbox" id="indicator-background" data-target="indicator-background-properties" name="indicatorBackground" checked> <span class="settings__checkbox"></span> </div> Indicator Background </label> </div> <div class="settings__input-group indicator-background-properties"> <label class="settings__label" for="indicator-background-visibility">Visibility</label> <select name="indicatorBackgroundVisibility" id="indicator-background-visibility"> <option value="local">local hover</option> <option value="viewport">viewport hover</option> <option value="always">always</option> </select> </div> </div> </div> <div class="settings__group"> <div class="settings__input-group"> <label class="settings__label" for="controls-background-color">Background Style</label> <input class="settings__color" type="color" id="controls-background-color" value="#000000" name="controlsBackgroundColor"> </div> <div class="settings__input-group"> <label class="settings__label" for="controls-background-opacity">Opacity</label> <input id="controls-background-opacity" class="settings__number--three-digit" type="number" min="1" max="100" value="50" name="controlsBackgroundOpacity"> </div> <div class="settings__input-group"> <label for="controls-background-feather" class="settings__label settings__label--checkbox"> <div class="settings__checkbox-wrapper"> <input type="checkbox" id="controls-background-feather" name="controlsBackgroundFeather" checked> <span class="settings__checkbox"></span> </div> Feather </label> </div> </div> </div> </li> </ul> </form> </div> <div id="source-code-panel" class="content-panel removed" role="tabpanel" aria-labelledby="source-code-tab"> <div class="sourcecode"> <h2 class="sourcecode__heading">HTML</h2> <pre class="sourcecode__block"><code id="sourcecode-html"></code></pre> <h2 class="sourcecode__heading">JS Carousel Instance</h2> <pre class="sourcecode__block"><code id="sourcecode-instance"></code></pre> <h2 class="sourcecode__heading">Carousel Class</h2> <pre class="sourcecode__block"><code id="sourcecode-class"></code></pre> <h2 class="sourcecode__heading">Custom CSS</h2> <pre class="sourcecode__block"><code id="sourcecode-custom-css"></code></pre> <h2 class="sourcecode__heading">Static CSS</h2> <pre class="sourcecode__block"><code id="sourcecode-static-css"></code></pre> </div> </div> </main> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> </body> </html> <script src="https://static.codepen.io/assets/common/stopExecutionOnTimeout-de7e2ef6bfefd24b79a3f68b414b87b8db5b08439cac3f1012092b2290c719cd.js"></script> <script id="rendered-js"> class Carousel { constructor(id, imageArray, { autoplay, aspectRatio, imageSize, transition, indicatorBar } = {}) { this.dom = {}; this.imageArray = imageArray; this.settings = { autoplay: autoplay || null, aspectRatio: aspectRatio || '4:3', imageSize: imageSize || 'contain', transition: transition || 'horizontal', indicatorBar: indicatorBar || 'interior' }; this.state = { id, quantity: 0, slidesArr: [], isSliding: false, direction: '', currentImage: {}, currentMarker: null }; this.viewport = {}; this.touchCtrls = { slideOffset: { top: null, bottom: null, left: null, right: null }, viewmasterFactor: null, startX: null, startY: null, distX: null, distY: null, startD: null, duration: null, slides: [], scheduledAnimationFrame: false }; this.rafManager = this.rafManager.bind(this); this.init(this.imageArray); } init() { // inject carousel html into dom this.createCarouselElements(); // cache carousel elements from dom this.dom.carousel = document.querySelector(`#${this.state.id}.carousel`); this.dom.leftControl = this.dom.carousel.querySelector('.carousel__controls--left'); this.dom.rightControl = this.dom.carousel.querySelector('.carousel__controls--right'); if (this.settings.indicatorBar !== 'off') { this.dom.indicatorBar = this.settings.indicatorBar === 'interior' ? this.dom.carousel.querySelector('.carousel__indicator-bar--interior') : this.dom.carousel.querySelector('.carousel__indicator-bar--exterior'); } this.dom.viewport = this.dom.carousel.querySelector('.carousel__viewport'); this.dom.viewportWrapper = this.dom.carousel.querySelector('.carousel__viewport-wrapper'); // bind controller events this.dom.leftControl.addEventListener('mousedown', this.backward.bind(this)); this.dom.rightControl.addEventListener('mousedown', this.forward.bind(this)); this.dom.carousel.addEventListener('keydown', this.keyDownControls.bind(this)); // bind touch events this.dom.viewportWrapper.addEventListener('touchstart', this.rafManager, false); this.dom.viewportWrapper.addEventListener('touchend', this.rafManager, false); if (this.imageArray) this.buildCarousel(); } rafManager(e) { e.preventDefault(); switch (e.type) { case 'touchmove': if (this.touchCtrls.scheduledAnimationFrame) return; this.touchCtrls.scheduledAnimationFrame = true; requestAnimationFrame(() => { this.touchMoveRenders(e); }); break; case 'touchend': requestAnimationFrame(() => { this.touchEndRenders(e); }); break; default: requestAnimationFrame(() => { this.touchStartRenders(e); });} } createCarouselElements() { const carouselElements = ` <div class="carousel__viewport-wrapper"> <button class="carousel__controls carousel__controls--left"> <div class="carousel__focus-ring"></div> <div class="carousel__controls-background carousel__controls-background--arrow"></div> <svg class="carousel__icon-left" viewBox="0 0 62.826 169.29"> <g transform="translate(370.32 -123.05)"> <path d="m-312.54 287.28c-52.709-78.69-52.709-78.69-52.709-78.69m52.709-80.481c-52.747 80.11-52.747 80.11-52.747 80.11" style="fill:none;stroke-linecap:round;stroke-width:10" /> </g> </svg> </button> <button class="carousel__controls carousel__controls--right"> <div class="carousel__focus-ring"></div> <div class="carousel__controls-background carousel__controls-background--arrow"></div> <svg class="carousel__icon-right" viewBox="0 0 62.826 169.29"> <g transform="translate(370.32 -123.05)"> <path d="m-365.28 287.28c52.709-78.69 52.709-78.69 52.709-78.69m-52.709-80.481c52.747 80.11 52.747 80.11 52.747 80.11" style="fill:none;stroke-linecap:round;stroke-width:10" /> </g> </svg> </button> ${this.settings.indicatorBar === 'interior' ? ` <div class="carousel__indicator-bar carousel__indicator-bar--interior"> <div class="carousel__controls-background carousel__controls-background--indicator"></div> </div> ` : ''} <div class="carousel__viewport"></div> </div> ${this.settings.indicatorBar === 'exterior' ? '<div class="carousel__indicator-bar carousel__indicator-bar--exterior"></div>' : ''} `; document.getElementById(this.state.id).innerHTML = carouselElements; } buildCarousel() { // update quantity this.state.quantity = this.imageArray.length; // clear and build slides while (this.dom.viewport.firstChild) { this.dom.viewport.removeChild(this.dom.viewport.firstChild); } this.buildSlides(); // push img nodelist into slidesArr as objects with id and pos this.state.slidesArr = []; for (let i = 0; i < this.state.quantity; i++) { this.state.slidesArr.push({ id: i, pos: i }); } // remove controls for single image display if (this.state.quantity === 1) { this.dom.leftControl.classList.add('hidden'); this.dom.rightControl.classList.add('hidden'); if (this.dom.indicatorBar) this.dom.indicatorBar.classList.add('hidden'); return; } this.dom.leftControl.classList.remove('hidden'); this.dom.rightControl.classList.remove('hidden'); if (this.dom.indicatorBar) { this.dom.indicatorBar.classList.remove('hidden'); // clear and build indicatorBar if (this.dom.indicatorBar.contains(document.querySelector('.carousel__indicator-wrapper'))) { this.dom.indicatorBar.removeChild(document.querySelector('.carousel__indicator-wrapper')); } this.buildindicatorBar(); } // render default positioning this.initialRender(); } buildSlides() { let imageReel = ''; this.imageArray.forEach(el => { const attribution = el.auth ? `<span class="carousel__image-attribution">Photo by <a href="${el.profile}?utm_source=deluxe_image_carousel&utm_medium=referral">${el.auth}</a> on <a href="https://unsplash.com/?utm_source=deluxe_image_carousel&utm_medium=referral">Unsplash</a></span>` : ''; // FILTER_ATTRIBUTION const slideString = ` <div class="carousel__slide-container"> ${attribution} ${'' /* FILTER_ATTRIBUTION */} <div class="carousel__slide-wrapper"> <img class="carousel__slide" src="${el.url}" alt="${el.alt}"> <div class="carousel__slide-overlay"></div> </div> </div> `; imageReel += slideString; }); this.dom.viewport.insertAdjacentHTML( 'beforeend', imageReel); this.dom.slideContainers = [...this.dom.carousel.querySelectorAll('.carousel__slide-container')]; this.dom.slides = this.dom.slideContainers.map(val => ({ wrapper: val.querySelector('.carousel__slide-wrapper'), img: val.querySelector('.carousel__slide') })); this.dom.slides.forEach(val => { const poll = setInterval(() => { if (val.img.naturalWidth) { clearInterval(poll); this.addOrientationStyles(val); } }, 10); }); } addOrientationStyles(slide) { const imgAspectRatioQuotient = (slide.img.naturalWidth / slide.img.naturalHeight).toFixed(2); const viewAspectRatioQuotient = (() => { const [x, y] = this.settings.aspectRatio.split(':').map(el => parseInt(el, 10)); return (x / y).toFixed(2); })(); if (this.settings.imageSize === 'contain') { if (imgAspectRatioQuotient > viewAspectRatioQuotient) { slide.wrapper.classList.add('carousel__slide-wrapper--landscape'); const wrapperHeight = viewAspectRatioQuotient / imgAspectRatioQuotient * 100; slide.wrapper.style.height = `${wrapperHeight}%`; } else if (imgAspectRatioQuotient < viewAspectRatioQuotient) { slide.wrapper.classList.add('carousel__slide-wrapper--portrait'); const wrapperWidth = imgAspectRatioQuotient / viewAspectRatioQuotient * 100; slide.wrapper.style.width = `${wrapperWidth}%`; } else { slide.wrapper.classList.add('carousel__slide-wrapper--landscape', 'carousel__slide-wrapper--portrait'); } } else if (imgAspectRatioQuotient > viewAspectRatioQuotient) { slide.wrapper.classList.add('carousel__slide-wrapper--portrait'); const wrapperWidth = imgAspectRatioQuotient / viewAspectRatioQuotient * 100; slide.wrapper.style.width = `${wrapperWidth}%`; } else if (imgAspectRatioQuotient < viewAspectRatioQuotient) { slide.wrapper.classList.add('carousel__slide-wrapper--landscape'); const wrapperHeight = viewAspectRatioQuotient / imgAspectRatioQuotient * 100; slide.wrapper.style.height = `${wrapperHeight}%`; } else { slide.wrapper.classList.add('carousel__slide-wrapper--landscape', 'carousel__slide-wrapper--portrait'); } } buildindicatorBar() { const indicatorMarker = '<div class="carousel__indicator-marker"></div>'; let indicatorString = ''; for (let i = 0; i < this.state.quantity; i++) { indicatorString += indicatorMarker; } const indicatorWrapper = ` <div class="carousel__indicator-wrapper"> ${indicatorString} </div>`; this.dom.indicatorBar.insertAdjacentHTML( 'beforeend', indicatorWrapper); document.querySelector('.carousel__indicator-wrapper').addEventListener('click', this.jumpToMarker.bind(this)); this.dom.indicatorMarkers = [...document.querySelectorAll('.carousel__indicator-marker')]; } updateindicatorBar() { if (this.state.currentMarker) { this.state.currentMarker.classList.remove('carousel__indicator-marker--active'); } this.state.currentMarker = this.dom.indicatorMarkers[this.state.slidesArr[1].id]; this.state.currentMarker.classList.add('carousel__indicator-marker--active'); } initialRender() { this.state.slidesArr.forEach(el => { el.pos === this.state.quantity - 1 ? el.pos = 0 : el.pos += 1; }); this.sortImageArray(); this.dom.slideContainers[this.state.slidesArr[0].id].classList.add('prev'); this.dom.slideContainers[this.state.slidesArr[0].id].classList.add('hide'); if (this.state.quantity > 2) { for (let i = 2; i < this.state.quantity; i++) { this.dom.slideContainers[this.state.slidesArr[i].id].classList.add('hide'); this.dom.slideContainers[this.state.slidesArr[i].id].classList.add('queue'); } } if (this.dom.indicatorBar) this.updateindicatorBar(); if (this.settings.autoplay) { this.initializeAutoplay(); } } initializeAutoplay() { let autoplay = setInterval(() => { this.forward(); }, this.settings.autoplay); this.dom.viewportWrapper.addEventListener('mouseenter', () => { clearInterval(autoplay); }); this.dom.viewportWrapper.addEventListener('mouseleave', () => { autoplay = setInterval(() => { this.forward(); }, this.settings.autoplay); }); this.dom.viewportWrapper.addEventListener('touchstart', () => { clearInterval(autoplay); }); this.dom.viewportWrapper.addEventListener('touchend', () => { autoplay = setInterval(() => { this.forward(); }, this.settings.autoplay); }); } jumpToMarker(e) { let jumpAmount; let jumpInterval; let jumpTicker = 1; if (e.target.classList.contains('carousel__indicator-marker')) { this.dom.slideContainers.forEach(el => el.classList.add('carousel__slide-container--jumper')); jumpAmount = this.dom.indicatorMarkers.indexOf(e.target) - this.dom.indicatorMarkers.indexOf(this.state.currentMarker); if (jumpAmount > 0) { this.forward(e); jumpInterval = setInterval(function () { if (jumpTicker === jumpAmount) { clearInterval(jumpInterval); this.dom.slideContainers.forEach(el => el.classList.remove('carousel__slide-container--jumper')); return; } this.forward(e); jumpTicker++; }.bind(this), 75); } else { jumpAmount = jumpAmount * -1; this.backward(e); jumpInterval = setInterval(function () { if (jumpTicker === jumpAmount) { clearInterval(jumpInterval); this.dom.slideContainers.forEach(el => el.classList.remove('carousel__slide-container--jumper')); return; } this.backward(e); jumpTicker++; }.bind(this), 75); } } } touchStartRenders(e) { this.viewport = this.dom.viewportWrapper.getBoundingClientRect(); if (this.settings.transition === 'viewmaster' || this.settings.transition === 'horizontal') { this.touchCtrls.slideOffset.left = this.viewport.left - this.viewport.width; this.touchCtrls.slideOffset.right = this.viewport.left + this.viewport.width; } if (this.settings.transition === 'vertical') { this.touchCtrls.slideOffset.top = this.viewport.top - this.viewport.height; this.touchCtrls.slideOffset.bottom = this.viewport.top + this.viewport.height; } if (this.settings.transition === 'viewmaster') { this.touchCtrls.viewmasterFactor = this.viewport.height / 2 / this.viewport.width; } this.touchCtrls.slides = [ this.dom.slideContainers[this.state.slidesArr[0].id], this.dom.slideContainers[this.state.slidesArr[1].id], this.dom.slideContainers[this.state.slidesArr[2].id]]; const d = new Date(); this.touchCtrls.startD = d.getTime(); const touchobj = e.touches[0]; this.touchCtrls.startX = parseInt(touchobj.clientX, 10); this.touchCtrls.startY = parseInt(touchobj.clientY, 10); if (this.settings.transition !== 'dissolve') { this.touchCtrls.slides.forEach(val => { val.classList.add('carousel__slide-container--no-trans'); val.classList.remove('hide'); }); } this.dom.viewportWrapper.addEventListener('touchmove', this.rafManager, false); } touchMoveRenders(e) { let viewportWidth;let viewportHeight; const touch = this.touchCtrls; const touchobj = e.touches[0]; if (document.elementFromPoint(touchobj.clientX, touchobj.clientY) !== e.target) { touch.scheduledAnimationFrame = false; requestAnimationFrame(() => { this.touchEndRenders(e); }); return; } if (this.viewport.width) { viewportWidth = parseFloat(this.viewport.width.toFixed(1)); } if (this.viewport.height) { viewportHeight = parseFloat(this.viewport.height.toFixed(1)); } if (this.settings.transition !== 'vertical') { touch.distX = parseInt(touchobj.clientX, 10) - touch.startX; } switch (this.settings.transition) { case 'viewmaster': if (touch.distX > 0) { touch.slides[1].style.transform = `translate(${touch.distX}px, ${touch.distX * touch.viewmasterFactor}px)`; } else { touch.slides[1].style.transform = `translate(${touch.distX}px, ${touch.distX * -touch.viewmasterFactor}px)`; } if (touch.slideOffset.left + touch.distX >= touch.slideOffset.left) { touch.slides[0].style.transform = `translate(${touch.distX - viewportWidth}px, ${viewportHeight * 0.5 - touch.distX * touch.viewmasterFactor}px)`; } else { touch.slides[0].style.transform = null; } if (touch.slideOffset.right + touch.distX <= touch.slideOffset.right) { touch.slides[2].style.transform = `translate(${viewportWidth + touch.distX}px, ${viewportHeight * 0.5 + touch.distX * touch.viewmasterFactor}px)`; } else { touch.slides[2].style.transform = null; } break; case 'vertical': touch.distY = parseInt(touchobj.clientY, 10) - touch.startY; touch.slides[1].style.transform = `translate(0, ${touch.distY}px)`; if (touch.slideOffset.top + touch.distY >= touch.slideOffset.top) { touch.slides[0].style.transform = `translate(0, ${touch.distY - viewportHeight}px)`; } else { touch.slides[0].style.transform = null; } if (touch.slideOffset.bottom + touch.distY <= touch.slideOffset.bottom) { touch.slides[2].style.transform = `translate(0, ${viewportHeight + touch.distY}px)`; } else { touch.slides[2].style.transform = null; } break; case 'dissolve': break; default: touch.slides[1].style.transform = `translate(${touch.distX}px, 0)`; if (touch.slideOffset.left + touch.distX >= touch.slideOffset.left) { touch.slides[0].style.transform = `translate(${touch.distX - viewportWidth}px, 0)`; } else { touch.slides[0].style.transform = null; } if (touch.slideOffset.right + touch.distX <= touch.slideOffset.right) { touch.slides[2].style.transform = `translate(${viewportWidth + touch.distX}px, 0)`; } else { touch.slides[2].style.transform = null; }} touch.scheduledAnimationFrame = false; } touchEndRenders(e) { this.dom.viewportWrapper.removeEventListener('touchmove', this.rafManager, false); const dist = this.settings.transition === 'vertical' ? this.touchCtrls.distY : this.touchCtrls.distX; const threshold = this.settings.transition === 'vertical' ? this.viewport.height * 0.4 : this.viewport.width * 0.4; this.touchCtrls.slides.forEach(val => { val.classList.remove('carousel__slide-container--no-trans'); val.style.transform = null; }); const d = new Date(); this.touchCtrls.duration = d.getTime() - this.touchCtrls.startD; if (this.touchCtrls.duration < 200 && Math.abs(dist) > 70) { if (this.settings.transition !== 'dissolve') { this.touchCtrls.slides.forEach(val => { val.classList.add('carousel__slide-container--flick-trans'); }); } if (dist > 0) this.backward(e); if (dist < 0) this.forward(e); } else if (Math.abs(dist) > threshold) { if (dist > 0) this.backward(e); if (dist < 0) this.forward(e); } // reset all touchCtrls this.touchCtrls.distX = null; this.touchCtrls.distY = null; [...Object.keys(this.touchCtrls.slideOffset)].forEach(val => { this.touchCtrls.slideOffset[val] = null; }); } backwardRender() { if (this.state.quantity === 2) { this.dom.slideContainers[this.state.slidesArr[1].id].classList.remove('queue'); this.dom.slideContainers[this.state.slidesArr[1].id].classList.add('prev'); this.dom.slideContainers[this.state.slidesArr[0].id].classList.add('queue'); setTimeout(function () { this.dom.slideContainers[this.state.slidesArr[1].id].classList.remove('hide'); this.dom.slideContainers[this.state.slidesArr[1].id].classList.remove('prev'); }.bind(this), 1); } else { this.dom.slideContainers[this.state.slidesArr[0].id].classList.add('hide'); this.dom.slideContainers[this.state.slidesArr[0].id].classList.add('prev'); this.dom.slideContainers[this.state.slidesArr[0].id].classList.remove('queue'); this.dom.slideContainers[this.state.slidesArr[1].id].classList.remove('hide'); this.dom.slideContainers[this.state.slidesArr[1].id].classList.remove('prev'); this.dom.slideContainers[this.state.slidesArr[2].id].classList.add('queue'); } } forwardRender() { if (this.state.quantity === 2) { this.dom.slideContainers[this.state.slidesArr[0].id].classList.add('prev'); this.dom.slideContainers[this.state.slidesArr[1].id].classList.remove('prev'); this.dom.slideContainers[this.state.slidesArr[1].id].classList.add('queue'); setTimeout(function () { this.dom.slideContainers[this.state.slidesArr[1].id].classList.remove('hide'); this.dom.slideContainers[this.state.slidesArr[1].id].classList.remove('queue'); }.bind(this), 1); } else { this.dom.slideContainers[this.state.slidesArr[0].id].classList.add('prev'); this.dom.slideContainers[this.state.slidesArr[1].id].classList.remove('hide'); this.dom.slideContainers[this.state.slidesArr[1].id].classList.remove('queue'); this.dom.slideContainers[this.state.slidesArr[this.state.quantity - 1].id].classList.add('hide'); this.dom.slideContainers[this.state.slidesArr[this.state.quantity - 1].id].classList.add('queue'); this.dom.slideContainers[this.state.slidesArr[this.state.quantity - 1].id].classList.remove('prev'); } } backward(e) { if (e) { if (!e.target.classList.contains('carousel__indicator-marker')) { if (e.type === 'mousedown' && e.buttons !== 1) return; e.preventDefault(); if (this.state.isSliding) return; this.state.isSliding = true; this.state.direction = 'backward'; } } // adding handler to current slide will disable controls during animation this.state.currentImage = this.dom.slideContainers[this.state.slidesArr[1].id]; this.boundSliderTransitionend = this.sliderTransitionend.bind(this); this.state.currentImage.addEventListener('transitionend', this.boundSliderTransitionend); // update, sort, and render new positions this.state.slidesArr.forEach(el => { el.pos === this.state.quantity - 1 ? el.pos = 0 : el.pos += 1; }); this.sortImageArray(); this.backwardRender(); } forward(e) { if (e) { if (!e.target.classList.contains('carousel__indicator-marker')) { if (e.type === 'mousedown' && e.buttons !== 1) return; e.preventDefault(); if (this.state.isSliding) {return;} this.state.isSliding = true; this.state.direction = 'forward'; } } // adding handler to current slide will disable controls during animation this.state.currentImage = this.dom.slideContainers[this.state.slidesArr[1].id]; this.boundSliderTransitionend = this.sliderTransitionend.bind(this); this.state.currentImage.addEventListener('transitionend', this.boundSliderTransitionend); // update, sort, and render new positions this.state.slidesArr.forEach(el => { el.pos === 0 ? el.pos = this.state.quantity - 1 : el.pos -= 1; }); this.sortImageArray(); this.forwardRender(); } sliderTransitionend() { this.state.isSliding = false; if (this.state.quantity === 2 && this.state.direction === 'backward') { this.dom.slideContainers[this.state.slidesArr[0].id].classList.add('hide'); this.dom.slideContainers[this.state.slidesArr[0].id].classList.remove('queue'); this.dom.slideContainers[this.state.slidesArr[0].id].classList.add('prev'); } if (this.state.quantity === 2 && this.state.direction === 'forward') { this.dom.slideContainers[this.state.slidesArr[0].id].classList.add('hide'); this.dom.slideContainers[this.state.slidesArr[0].id].classList.remove('prev'); this.dom.slideContainers[this.state.slidesArr[0].id].classList.add('queue'); } this.touchCtrls.slides.forEach(val => val.classList.remove('carousel__slide-container--flick-trans')); if (this.dom.indicatorBar) this.updateindicatorBar(); this.state.currentImage.removeEventListener('transitionend', this.boundSliderTransitionend); } keyDownControls(e) { if (!e.target.classList.contains('carousel__controls')) return; if (e.key === 'Enter' || e.key === ' ' || e.key === 'Spacebar') { e.preventDefault(); if (e.target.classList.contains('carousel__controls--left')) { this.backward(e); } else { this.forward(e); } } if (e.key === 'ArrowLeft' || e.key === 'Left') { this.dom.leftControl.focus(); this.backward(e); } if (e.key === 'ArrowRight' || e.key === 'Right') { this.dom.rightControl.focus(); this.forward(e); } } sortImageArray() { function compare(a, b) { if (a.pos < b.pos) return -1; if (a.pos > b.pos) return 1; return 0; } this.state.slidesArr.sort(compare); }} const tabItems = [...document.querySelectorAll('.tab-nav__item')]; const tabBtns = [...document.querySelectorAll('.tab-nav__btn')]; const contentPanels = [...document.querySelectorAll('.content-panel')]; document.querySelector('.tab-nav__list').addEventListener('click', e => { if (e.target.classList.contains('tab-nav__btn')) { tabItems.forEach(el => el.classList.remove('tab-nav__item--active')); tabBtns.forEach(el => el.classList.remove('tab-nav__btn--active')); e.target.parentNode.classList.add('tab-nav__item--active'); e.target.classList.add('tab-nav__btn--active'); tabBtns.forEach(val => { val.setAttribute('aria-selected', 'false'); }); e.target.setAttribute('aria-selected', 'true'); contentPanels.forEach(val => { val.classList.add('removed'); }); document.querySelector(`#${e.target.getAttribute('aria-controls')}`).classList.remove('removed'); } }); const settings = { dom: [], stylesheet: [], cssRulePairs: [], cssRules: {}, instanceOptions: {}, filteredClass: Carousel.toString().split('\n').filter(val => !val.includes('FILTER_ATTRIBUTION')).join('\n'), imageSources: [], carouselNamespace: 'my-carousel', carouselAutoplay: false, autoplayDuration: 5, percentWidth: '85', pixelWidth: '', widthUnits: '%', aspectRatio: '4:3', aspectRatioX: '4', aspectRatioY: '3', viewportBorder: false, viewportBorderColor: '#000000', viewportBorderThickness: '1', viewportRounding: '3', roundingUnits: 'px', imageSize: 'contain', endCapColor: '#000000', imageOverlay: false, imageOverlayColor: '#000000', imageOverlayOpacity: '20', transitionStyle: 'horizontal', arrowColor: '#ffffff', arrowOpacity: '70', indicatorBar: true, indicatorBarLocation: 'interior', indicatorBarOpacity: '60', indicatorBarStyle: '1', indicatorActiveColor: '#ffffff', indicatorInactiveColor: '#ffffff', arrowBackground: true, arrowBackgroundVisibility: 'viewport', indicatorBackground: true, indicatorBackgroundVisibility: 'local', controlsBackgroundColor: '#000000', controlsBackgroundOpacity: '50', controlsBackgroundFeather: true, init() { this.unsplashAPICall({ query: this.randomizeQuery(), per_page: 5 }); const viewportRange = document.querySelector('.settings__width-range'); const viewportInput = document.getElementById('viewport-width'); this.dom.settingsList = document.querySelector('.settings__list'); this.dom.search = document.querySelector('.preview__search-form'); this.dom.search.addEventListener('submit', this.formSubmit.bind(this)); viewportInput.addEventListener('input', e => { if (this.widthUnits === '%') viewportRange.value = e.target.value; }); viewportRange.addEventListener('input', e => { viewportInput.value = e.target.value; }); window.addEventListener('resize', this.updateAspectRatio.bind(this)); document.getElementById('width-units').addEventListener('change', e => { switch (e.target.value) { case 'px': viewportInput.type = 'text'; viewportInput.value = this.pixelWidth; viewportInput.name = 'pixelWidth'; viewportRange.disabled = true; viewportRange.classList.add('disabled'); break; default: viewportInput.type = 'number'; viewportInput.value = this.percentWidth; viewportInput.name = 'percentWidth'; viewportRange.disabled = false; viewportRange.classList.remove('disabled');} viewportInput.focus(); }); [...document.querySelectorAll('input[type="checkbox"]')].forEach(val => { val.addEventListener('change', this.toggleDisabled); }); this.dom.settingsList.addEventListener('input', this.updateSettings.bind(this)); this.dom.settingsList.addEventListener('click', this.toggleAccordion.bind(this)); this.getStylesheet(); this.cacheAdjustableStyles(); this.dom.carousel = document.querySelector(`#${this.carouselNamespace}.carousel`); this.updateControlBackgrounds(); this.updateSourceCode(); // Adjust HTML form default values for carousel width and rounded corners on mobile if (window.innerWidth <= 600) { [viewportRange, viewportInput].forEach(val => { val.value = '100'; }); document.getElementById('viewport-rounding').value = '0'; this.percentWidth = '100'; this.viewportRounding = '0'; this.updateViewportWidth(); } }, getStylesheet() { const [stylesheet] = [...document.styleSheets].filter(val => val.title === 'carousel'); this.stylesheet = [...(stylesheet.cssRules || stylesheet.rules)]; }, cacheAdjustableStyles() { this.cssRulePairs = [ { name: 'carousel', dom: '.carousel' }, { name: 'viewportWrapper', dom: ' .carousel__viewport-wrapper' }, { name: 'viewportArrowHover', dom: ' .carousel__viewport-wrapper:hover .carousel__controls-background--arrow' }, { name: 'viewportIndicatorHover', dom: ' .carousel__viewport-wrapper:hover .carousel__controls-background--indicator' }, { name: 'viewport', dom: ' .carousel__viewport' }, { name: 'slideContainer', dom: ' .carousel__slide-container' }, { name: 'slideOverlay', dom: ' .carousel__slide-overlay' }, { name: 'slidePrev', dom: '.carousel .prev' }, { name: 'slideQueue', dom: '.carousel .queue' }, { name: 'arrowSvg', dom: ' .carousel__controls svg' }, { name: 'arrowPath', dom: ' .carousel__controls path' }, { name: 'indicatorBar', dom: ' .carousel__indicator-bar' }, { name: 'localIndicatorHover', dom: ' .carousel__indicator-bar--interior:hover .carousel__controls-background--indicator' }, { name: 'indicatorMarker', dom: ' .carousel__indicator-marker' }, { name: 'indicatorActive', dom: ' .carousel__indicator-marker--active' }, { name: 'controlsBackground1', dom: ' .carousel__controls-background' }, { name: 'controlsBackground2', dom: ' .carousel__controls-background::after' }, { name: 'arrowBackground', dom: ' .carousel__controls-background--arrow' }, { name: 'indicatorBackground', dom: ' .carousel__controls-background--indicator' }]; this.cssRulePairs.forEach(val => { [this.cssRules[val.name]] = this.stylesheet.filter(el => el.selectorText === `#${this.carouselNamespace}${val.dom}`); }); }, updateSourceCode() { document.getElementById('sourcecode-html').innerText = `<div id="${this.carouselNamespace}" class="carousel"></div>`; document.getElementById('sourcecode-instance').innerText = this.updateInstanceCode(); document.getElementById('sourcecode-custom-css').innerText = this.formatCssRules(`#${this.carouselNamespace}`); document.getElementById('sourcecode-class').innerText = this.filteredClass; document.getElementById('sourcecode-static-css').innerText = this.formatCssRules('.carousel'); }, formatCssRules(selector) { const rawCssRules = this.stylesheet.filter(val => { if (val.selectorText) { return val.selectorText.startsWith(selector); } if (val.cssRules) { return val.cssRules[0].selectorText.startsWith(selector); } }); const formattedCssRules = rawCssRules.map(val => { if (val.media) { const splitRule = val.cssText.split('\n'); splitRule[1] = `\t${splitRule[1].trim().replace(/{ /g, '{\n\t\t').replace(/; (?!})/g, ';\n\t\t').replace(/ }/g, '\n\t}')}`; return `${splitRule.slice(0, -1).join('\n')}\n${splitRule[splitRule.length - 1]}`; } return val.cssText.replace(/{ /g, '{\n\t').replace(/; (?!})/g, ';\n\t').replace(/ }/g, '\n}'); }).join('\n\n'); return formattedCssRules; }, updateStylesheetNamespace() { this.cssRulePairs.forEach(val => { this.cssRules[val.name].selectorText = `#${this.carouselNamespace}${val.dom}`; }); }, updateInstanceCode() { this.updateInstanceOptions(); if (Object.keys(this.instanceOptions).length > 0) { const stringEntries = Object.entries(this.instanceOptions).map(val => `${val[0]}: '${val[1]}'`).join(', '); return `new Carousel(\n\t${this.carouselNamespace},\n\t[yourImageArrayHere],\n\t{ ${stringEntries} }\n)`; } return `new Carousel(${this.carouselNamespace}, [yourImageArrayHere])`; }, updateInstanceOptions() { this.instanceOptions = {}; if (this.carouselAutoplay === true) this.instanceOptions.autoplay = this.autoplayDuration * 1000; if (this.aspectRatio !== '4:3') this.instanceOptions.aspectRatio = this.aspectRatio; if (this.imageSize !== 'contain') this.instanceOptions.imageSize = this.imageSize; if (this.transitionStyle !== 'horizontal') this.instanceOptions.transition = this.transitionStyle; if (this.indicatorBar === true && this.indicatorBarLocation !== 'interior') { this.instanceOptions.indicatorBar = this.indicatorBarLocation; } else if (this.indicatorBar === false) { this.instanceOptions.indicatorBar = 'off'; } }, toggleAccordion(e) { let collapseItem;let collapseTarget;let collapseBtn; if (e.target.classList.contains('settings__collapse-btn')) { collapseItem = e.target; while (!collapseItem.classList.contains('settings__item')) { collapseItem = collapseItem.parentNode; } collapseTarget = collapseItem.querySelector('.settings__collapse-container'); collapseBtn = collapseItem.querySelector('.settings__collapse-btn'); if (!collapseTarget.classList.contains('settings__collapse-container--collapsed')) { collapseTarget.setAttribute('aria-hidden', 'true'); [...collapseTarget.querySelectorAll('input, select')].forEach(val => {val.setAttribute('tabindex', '-1');}); collapseBtn.innerHTML = '+'; collapseBtn.setAttribute('aria-expanded', 'false'); } else { collapseTarget.removeAttribute('aria-hidden'); [...collapseTarget.querySelectorAll('input, select')].forEach(val => {val.setAttribute('tabindex', '0');}); collapseBtn.innerHTML = '−'; collapseBtn.setAttribute('aria-expanded', 'true'); } collapseTarget.classList.toggle('settings__collapse-container--collapsed'); } }, toggleDisabled(e) { const disableGroup = [...document.querySelectorAll(`.${e.currentTarget.getAttribute('data-target')}`)]; let disableTargets = []; disableGroup.forEach(val => { disableTargets = [...disableTargets, ...val.querySelectorAll('input, select')]; }); if (e.target.checked) { disableGroup.forEach(val => {val.classList.remove('disabled');}); disableTargets.forEach(val => {val.disabled = false;}); } else { disableGroup.forEach(val => {val.classList.add('disabled');}); disableTargets.forEach(val => {val.disabled = true;}); } }, formSubmit(e) { e.preventDefault(); const dataPost = { query: this.dom.search.querySelector('input').value, per_page: parseInt(this.dom.search.querySelector('select').value, 10) }; this.dom.search.querySelector('input').value = ''; this.unsplashAPICall(dataPost); }, unsplashAPICall(dataVals) { axios({ method: 'POST', url: 'https://feverdreamdesigns.com/api-call.php', data: dataVals }). then(function (res) { let searchResults = res.data.results; settings.imageSources = searchResults.map(el => { return { url: el.urls.regular, alt: el.description, auth: el.user.name, profile: el.user.links.html }; }); // Carousel.buildCarousel(imageSources); const carousel = new Carousel(settings.carouselNamespace, settings.imageSources); settings.awaitImageLoading(); }). catch(function (err) { console.log(err); }); }, randomizeQuery() { const queryArr = ['puppies', 'kittens', 'parrots', 'ocean', 'mountains', 'tropical', 'sailboat']; const randomize = Math.floor(Math.random() * queryArr.length); return queryArr[randomize]; }, updateSettings(e) { if (!e.target.matches('input:not([type="text"]), select, #carousel-namespace')) return; if (e.target.type === 'checkbox') { this[e.target.name] = e.target.checked; } else { this[e.target.name] = e.target.value; } switch (e.target.name) { case 'carouselNamespace': this.updateNamespace(); break; case 'carouselAutoplay': case 'autoplayDuration': this.updateAutoplay(); break; case 'percentWidth': case 'pixelWidth': case 'widthUnits': this.updateViewportWidth(e); break; case 'aspectRatio': [this.aspectRatioX, this.aspectRatioY] = this.aspectRatio.split(':').map(el => parseInt(el, 10)); this.updateAspectRatio(); break; case 'viewportBorder': case 'viewportBorderColor': case 'viewportBorderThickness': this.updateViewportBorder(); break; case 'roundingUnits': case 'viewportRounding': this.updateViewportRounding(); break; case 'imageSize': this.awaitImageLoading(); break; case 'endCapColor': this.updateEndCaps(); break; case 'imageOverlay': case 'imageOverlayColor': case 'imageOverlayOpacity': this.updateImageOverlay(); break; case 'transitionStyle': this.updateTransitionStyle(); break; case 'arrowColor': case 'arrowOpacity': this.updateArrows(); break; case 'indicatorBar': case 'indicatorBarLocation': case 'indicatorBarOpacity': case 'indicatorBarStyle': case 'indicatorActiveColor': case 'indicatorInactiveColor': if (this.indicatorBarStyle === '1') { document.getElementById('indicator-inactive-color').parentNode.classList.add('removed'); } else { document.getElementById('indicator-inactive-color').parentNode.classList.remove('removed'); } this.updateIndicatorBar(); break; case 'arrowBackground': case 'arrowBackgroundVisibility': case 'indicatorBackground': case 'indicatorBackgroundVisibility': case 'controlsBackgroundColor': case 'controlsBackgroundOpacity': case 'controlsBackgroundFeather': this.updateControlBackgrounds(); break; default:} this.updateSourceCode(); }, updateNamespace() { if (!this.carouselNamespace) { this.carouselNamespace = 'my-carousel'; } this.dom.carousel.id = this.carouselNamespace; this.updateStylesheetNamespace(); this.cacheAdjustableStyles(); }, updateAutoplay() { if (this.carouselAutoplay) { const duration = this.autoplayDuration * 1000; const carousel = new Carousel(this.carouselNamespace, this.imageSources, { ...this.instanceOptions, autoplay: duration }); } else { const carousel = new Carousel(settings.carouselNamespace, settings.imageSources, { ...this.instanceOptions, autoplay: null }); } }, updateViewportWidth() { const currentWidth = this.widthUnits === '%' ? this.percentWidth : this.pixelWidth; this.cssRules.carousel.style.width = `${currentWidth}${this.widthUnits}`; this.updateAspectRatio(); }, updateAspectRatio() { this.cssRules.viewport.style.paddingBottom = `${parseFloat((100 * this.aspectRatioY / this.aspectRatioX).toFixed(2), 10)}%`; setTimeout(() => { this.awaitImageLoading(); this.updateViewportRounding(); }, 1); }, updateViewportBorder() { if (this.viewportBorder) { this.cssRules.viewportWrapper.style.border = `${this.viewportBorderThickness}px solid ${this.viewportBorderColor}`; } else { this.cssRules.viewportWrapper.style.border = 'none'; } }, updateViewportRounding() { const [x, y] = [this.aspectRatioX, this.aspectRatioY]; if (this.widthUnits === 'px') { if (this.roundingUnits === 'px') { const shortLength = x > y ? this.pixelWidth * y / x : this.pixelWidth * x / y; const roundingValue = (shortLength * (this.viewportRounding / 100)).toFixed(2); this.cssRules.viewportWrapper.style.borderRadius = `${roundingValue}px`; } else { this.cssRules.viewportWrapper.style.borderRadius = `${this.viewportRounding}%`; } } else if (this.roundingUnits === 'px') { const shortRound = x > y ? this.viewportRounding * y / x : this.viewportRounding * x / y; const roundingValue = x > y ? `${shortRound}%/${this.viewportRounding}%` : `${this.viewportRounding}%/${shortRound}%`; this.cssRules.viewportWrapper.style.borderRadius = roundingValue; } else { this.cssRules.viewportWrapper.style.borderRadius = `${this.viewportRounding}%`; } }, awaitImageLoading() { const viewportAspectRatio = (this.aspectRatioX / this.aspectRatioY).toFixed(2); this.dom.slideWrappers = [...this.dom.carousel.querySelectorAll('.carousel__slide-wrapper')]; this.dom.slideWrappers.forEach(val => { const img = val.querySelector('.carousel__slide'); const poll = setInterval(() => { if (img.naturalWidth) { clearInterval(poll); this.updateImageSize(val, img, viewportAspectRatio); } }, 10); }); }, updateImageSize(wrapper, img, viewportAspectRatio) { this.dom.viewport = this.dom.carousel.querySelector('.carousel__viewport'); const imageAspectRatio = (img.naturalWidth / img.naturalHeight).toFixed(2); wrapper.className = 'carousel__slide-wrapper'; wrapper.style.width = null; wrapper.style.height = null; if (this.imageSize === 'contain') { if (imageAspectRatio > viewportAspectRatio) { wrapper.classList.add('carousel__slide-wrapper--landscape'); const wrapperHeight = viewportAspectRatio / imageAspectRatio * 100; wrapper.style.height = `${wrapperHeight}%`; } else if (imageAspectRatio < viewportAspectRatio) { wrapper.classList.add('carousel__slide-wrapper--portrait'); const wrapperWidth = imageAspectRatio / viewportAspectRatio * 100; wrapper.style.width = `${wrapperWidth}%`; } else { wrapper.classList.add('carousel__slide-wrapper--landscape', 'carousel__slide-wrapper--portrait'); img.classList.add('carousel__slide--landscape-contain', 'carousel__slide--portrait-contain'); } } else if (imageAspectRatio > viewportAspectRatio) { wrapper.classList.add('carousel__slide-wrapper--portrait'); const wrapperWidth = imageAspectRatio / viewportAspectRatio * 100; wrapper.style.width = `${wrapperWidth}%`; } else if (imageAspectRatio < viewportAspectRatio) { wrapper.classList.add('carousel__slide-wrapper--landscape'); const wrapperHeight = viewportAspectRatio / imageAspectRatio * 100; wrapper.style.height = `${wrapperHeight}%`; } else { wrapper.classList.add('carousel__slide-wrapper--landscape', 'carousel__slide-wrapper--portrait'); img.classList.add('carousel__slide--landscape-contain', 'carousel__slide--portrait-contain'); } }, updateEndCaps() { this.cssRules.slideContainer.style.backgroundColor = this.endCapColor; }, updateImageOverlay() { if (this.imageOverlay) { this.cssRules.slideOverlay.style.display = 'block'; this.cssRules.slideOverlay.style.backgroundColor = this.imageOverlayColor; this.cssRules.slideOverlay.style.opacity = `${this.imageOverlayOpacity / 100}`; } else { this.cssRules.slideOverlay.style.display = 'none'; } }, updateTransitionStyle() { switch (this.transitionStyle) { case 'viewmaster': this.cssRules.slideContainer.style.transition = 'transform 0.3s ease-in'; this.cssRules.slidePrev.style.transform = 'translate(-100%, 50%)'; this.cssRules.slideQueue.style.transform = 'translate(100%, 50%)'; this.cssRules.slidePrev.style.opacity = ''; this.cssRules.slideQueue.style.opacity = ''; break; case 'vertical': this.cssRules.slideContainer.style.transition = 'transform 0.3s ease-in'; this.cssRules.slidePrev.style.transform = 'translate(0, -100%)'; this.cssRules.slideQueue.style.transform = 'translate(0, 100%)'; this.cssRules.slidePrev.style.opacity = ''; this.cssRules.slideQueue.style.opacity = ''; break; case 'dissolve': this.cssRules.slideContainer.style.transition = 'opacity 0.4s ease-in-out'; this.cssRules.slidePrev.style.transform = 'translate(0, 0)'; this.cssRules.slidePrev.style.opacity = '0'; this.cssRules.slideQueue.style.transform = 'translate(0, 0)'; this.cssRules.slideQueue.style.opacity = '0'; break; default: this.cssRules.slideContainer.style.transition = 'transform 0.3s ease-in'; this.cssRules.slidePrev.style.transform = 'translate(-100%, 0)'; this.cssRules.slideQueue.style.transform = 'translate(100%, 0)'; this.cssRules.slidePrev.style.opacity = ''; this.cssRules.slideQueue.style.opacity = '';} const carousel = new Carousel( this.carouselNamespace, this.imageSources, { ...this.instanceOptions, transition: this.transitionStyle }); }, updateArrows() { this.cssRules.arrowSvg.style.opacity = `${this.arrowOpacity / 100}`; this.cssRules.arrowPath.style.stroke = this.arrowColor; }, updateIndicatorBar() { if (document.querySelector('.carousel__indicator-bar--exterior') === null) { this.dom.carousel.insertAdjacentHTML('beforeend', '<div class="carousel__indicator-bar carousel__indicator-bar--exterior"></div>'); } this.dom.indicatorBarInterior = document.querySelector('.carousel__indicator-bar--interior'); this.dom.indicatorBarExterior = document.querySelector('.carousel__indicator-bar--exterior'); this.dom.indicatorWrapper = document.querySelector('.carousel__indicator-wrapper'); if (this.indicatorBar) { this.cssRules.indicatorBar.style.visibility = 'visible'; } else { this.cssRules.indicatorBar.style.visibility = 'hidden'; } if (this.indicatorBarLocation === 'interior') { this.dom.indicatorBarInterior.appendChild(this.dom.indicatorWrapper); this.dom.indicatorBarInterior.style.visibility = ''; } else { this.dom.indicatorBarExterior.appendChild(this.dom.indicatorWrapper); this.dom.indicatorBarInterior.style.visibility = 'hidden'; } this.cssRules.indicatorActive.style.backgroundColor = this.indicatorActiveColor; this.cssRules.indicatorActive.style.boxShadow = `0 0 5px 0 ${this.indicatorActiveColor}`; this.cssRules.indicatorActive.style.border = `1px solid ${this.indicatorActiveColor}`; this.cssRules.indicatorMarker.style.opacity = `${this.indicatorBarOpacity / 100}`; if (this.indicatorBarStyle === '1') { this.cssRules.indicatorMarker.style.border = `1px solid ${this.indicatorActiveColor}`; this.cssRules.indicatorMarker.style.backgroundColor = 'transparent'; } else { this.cssRules.indicatorMarker.style.border = `1px solid ${this.indicatorInactiveColor}`; this.cssRules.indicatorMarker.style.backgroundColor = this.indicatorInactiveColor; } }, updateControlBackgrounds() { if (this.arrowBackground) { this.cssRules.arrowBackground.style.display = 'block'; } else { this.cssRules.arrowBackground.style.display = 'none'; } if (this.indicatorBackground) { this.cssRules.indicatorBackground.style.display = 'block'; } else { this.cssRules.indicatorBackground.style.display = 'none'; } if (this.arrowBackgroundVisibility === 'viewport') { this.cssRules.viewportArrowHover.style.opacity = `${this.controlsBackgroundOpacity / 100}`; this.cssRules.arrowBackground.style.opacity = '0'; } else { this.cssRules.viewportArrowHover.style.opacity = ''; this.cssRules.arrowBackground.style.opacity = `${this.controlsBackgroundOpacity / 100}`; } if (this.indicatorBackgroundVisibility === 'viewport') { this.cssRules.viewportIndicatorHover.style.opacity = `${this.controlsBackgroundOpacity / 100}`; this.cssRules.indicatorBackground.style.opacity = '0'; this.cssRules.localIndicatorHover.style.opacity = ''; } else if (this.indicatorBackgroundVisibility === 'local') { this.cssRules.indicatorBackground.style.opacity = '0'; this.cssRules.viewportIndicatorHover.style.opacity = ''; this.cssRules.localIndicatorHover.style.opacity = `${this.controlsBackgroundOpacity / 100}`; } else { this.cssRules.viewportIndicatorHover.style.opacity = ''; this.cssRules.localIndicatorHover.style.opacity = ''; this.cssRules.indicatorBackground.style.opacity = `${this.controlsBackgroundOpacity / 100}`; } this.cssRules.controlsBackground1.style.backgroundColor = this.controlsBackgroundColor; this.cssRules.controlsBackground2.style.backgroundColor = this.controlsBackgroundColor; if (this.controlsBackgroundFeather) { this.cssRules.arrowBackground.style.boxShadow = `${this.controlsBackgroundColor} 0px 0px 8px 9px`; this.cssRules.indicatorBackground.style.boxShadow = `${this.controlsBackgroundColor} 0px 0px 8px 9px`; } else { this.cssRules.arrowBackground.style.boxShadow = `${this.controlsBackgroundColor} 0px 0px 0px 6px`; this.cssRules.indicatorBackground.style.boxShadow = `${this.controlsBackgroundColor} 0px 0px 0px 3px`; } } }; settings.init(); //# sourceURL=pen.js </script> </body> </html>

Related: See More


Questions / Comments: