javascriptjqueryfocuscarouselflickity

How to set focus with javaScript?


My problem is that after I opend a modal image in the carousel, the carousel is not in focus. So I can not use the left & right keys to change images right away. Is there a solution for this? With $('.carousel').flickity().focus(); I can only set the focus to the second (last) carousel. Thanks! Kind Regards, August

//carousel and image captions
$('.carousel-container').each( function( i, container ) {
  var $container = $( container );

  var $carousel = $container.find('.carousel').flickity({
    // cellSelector: 'img',
    // fullscreen: true,
    wrapAround: true,
    imagesLoaded: true,
    percentPosition: false
  });

  var $captionTitle = $container.find('.captionTitle');
  var $caption = $container.find('.caption');
  // Flickity instance
  var flkty = $carousel.data('flickity');

  $carousel.on( 'select.flickity', function() {
    // set image caption using img's alt
    $captionTitle.text($(flkty.selectedElement).find('img').attr('title'))
    $caption.text($(flkty.selectedElement).find('img').attr('alt'))
  });
});

//modal
// create references to the modal...
var modal = document.getElementById('myModal');
// to all images -- note I'm using a class!
var images = document.getElementsByTagName('img');
// the image in the modal
var modalImg = document.getElementById("img01");
// and the caption in the modal
// var captionText = document.getElementById("caption");

// Go through all of the images with our custom class
for (var i = 0; i < images.length; i++) {
  var img = images[i];
  // and attach our click listener for this image.
  img.onclick = function(evt) {
    console.log(evt);
    modal.style.display = "block";
    modalImg.src = this.src;
    //??
    $('.carousel').flickity().focus();
  }
}
//close
var span = document.getElementsByClassName("modal")[0];

span.onclick = function() {
  modal.style.display = "none";
  modal.focus();
}
* {
  box-sizing: border-box;
  margin: 0px;
  padding: 0px;
  text-decoration: none;
}

.carousel-headline {
    text-align: center;
    width: 100%;
    margin-bottom:10px;
}

hr {
    margin-top: 50px;
    width: 0px;
}

main {
    max-width: 1080px;
    width:100%;
    margin: auto;
}

.carousel-cell {
  width: 100%;
  padding-left: 10px;
  padding-right: 10px;
  /* center images in cells with flexbox */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.carousel.is-fullscreen .carousel-cell {
  height: 100%;
}

.carousel-cell img {
  max-width: 100%;
  max-height: 500px;
}

.flickity-button {
  color: #bbb !important;
}

.flickity-button:hover {
  color: #333 !important;
}

.zoom-link {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 1;
}

.caption, .captionTitle {
  padding-left: 10px;
  padding-right: 10px;
  text-align: center;
  max-width: 800px;
  margin-left: auto;
  margin-right: auto;
  white-space:pre-wrap;
}

.captionTitle {
  margin-top: 30px;
  font-weight: bold;
}

.flickity-page-dots {
  scale: 0.75;
}

/* Modal  */

#modalImg {
  cursor: pointer;
}

.modal {
  display: none;
  /* Hidden by default */
  position: fixed;
  /* Stay in place */
  z-index: 1;
  /* Sit on top */
  /* padding-top: 100px; */
  /* Location of the box */
  left: 0;
  top: 0;
  width: 100%;
  /* Full width */
  height: 100%;
  /* Full height */
  overflow: auto;
  /* Enable scroll if needed */
  background-color: white;
  /* Fallback color */
  background-color: white;
  /* Black w/ opacity */
  cursor: pointer;
}

.modal-content {
  max-height: 1200px;
  width: auto;
  margin: 0 auto;
  display: block;
}

.close {
  text-transform: uppercase;
  color: #000;
  background-color: #fff;
  border: 0;
  padding: 4px 6px;
  line-height: 1;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9999;
}

.close:hover,
.close:focus {
  color: #bbb;
}
<link rel="stylesheet" href="https://unpkg.com/flickity@2/dist/flickity.min.css">

<div class="carousel-container">
  <p class='carousel-headline'>Carousel 1</p>
  <div class="carousel">
    <div class="carousel-cell">
      <img id="modalImg" src="https://picsum.photos/720/540/?image=517" title="Titel 1" alt="Text 1" />
    </div>
    <div class="carousel-cell">
      <img id="modalImg" src="https://picsum.photos/540/720/?image=696" title="Titel 1.1" alt="Text 1.1" />
    </div>
  </div>
  <p class="captionTitle"></p>
  <p class="caption"></p>
</div>

<hr>

<div class="carousel-container">
  <p class='carousel-headline'>Carousel 2</p>
  <div class="carousel">
    <div class="carousel-cell">
      <img id="modalImg" src="https://picsum.photos/720/540/?image=517" title="Titel 2" alt="Text 2" />
    </div>
    <div class="carousel-cell">
      <img id="modalImg" src="https://picsum.photos/540/720/?image=696" title="Titel 2.1" alt="Text 2.1" />
    </div>
  </div>
  <p class="captionTitle"></p>
  <p class="caption"></p>
</div>

<div id="myModal" class="modal">
<span class="close">close</span>
<img class="modal-content" id="img01">
<div id="caption"></div>
</div>
  
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/flickity@2/dist/flickity.pkgd.min.js"></script>


Solution

  • Prior to anything, here are the "undirectly relevant" changes:

    Then saddly, this plugin documentation would need an update... Many of the events I tried do not provide all the arguments stated.

    And the accessible properties of this, in the scope of the events handlers, are not well documented.

    I came up with those two useful ones in this case:

    So I used the on object to set the event callbacks you need.
    Only the modal "close" span needs a separate handler.

    So now, on staticClick, the modal opens and surprisingly, the focus on the slider is not lost. You can use the keyboard arrows. On change, you just need to get the "selected image" src to update the modal image.

    Now if there is a click on the modal image... The focus on the slider is lost... But have a look at the $("#myModal").on("click", ...) to keep that focus. ;)

    See comments below for more specific details of the solution.

    $(".carousel-container").each(function (i, container) {
      $(container)
        .find(".carousel")
        .flickity({
          // cellSelector: 'img',
          // fullscreen: true,
          wrapAround: true,
          imagesLoaded: true,
          percentPosition: false,
    
          // Event handlers
          on: {
            select: function (index) {
              let $container = $(this.element).parent();
    
              let $captionTitle = $container.find(".captionTitle");
              let $caption = $container.find(".caption");
              let $currentImage = $(this.selectedElement).find("img");
    
              // Set the captions
              $captionTitle.text($currentImage.attr("title"));
              $caption.text($currentImage.attr("alt"));
            },
    
            change: function (index) {
              if ($("#myModal").is(":visible")) {
                let $selectedEl = $(this.selectedElement).find("img");
                $("#modalImage").attr("src", $selectedEl.attr("src"));
              }
            },
    
            staticClick: function (event, eventAgain, selectedCell) {
              // On click on a slider image, open the modal with the right image
              // Also save the slider element to a data attribute of the modal
              // so that on modal close, the slider will be focussed
              var $activeImage = $(selectedCell).find("img");
              $("#modalImage").attr("src", $activeImage.attr("src"));
              $("#myModal").data("sliderEl", this.element).show();
            }
          }
        });
    
      // Modal close
      $("span.close").on("click", function () {
        
        // Close the modal
        $("#myModal").hide();
    
        // Focus the slider from which the modal open was triggered
        $($("#myModal").data("sliderEl")).focus();
      });
      
      // Keep the focus on the slider
      // if a click is made on the modal image
      $("#myModal").on("click", function(e){
        if($(e.target).is(".close")){return}
        $($(this).data("sliderEl")).focus();
      })
      
    });
    * {
      box-sizing: border-box;
      margin: 0px;
      padding: 0px;
      text-decoration: none;
    }
    
    .carousel-headline {
      text-align: center;
      width: 100%;
      margin-bottom: 10px;
    }
    
    hr {
      margin-top: 50px;
      width: 0px;
    }
    
    main {
      max-width: 1080px;
      width: 100%;
      margin: auto;
    }
    
    .carousel-cell {
      width: 100%;
      padding-left: 10px;
      padding-right: 10px;
      /* center images in cells with flexbox */
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    }
    
    .carousel.is-fullscreen .carousel-cell {
      height: 100%;
    }
    
    .carousel-cell img {
      max-width: 100%;
      max-height: 500px;
    }
    
    .flickity-button {
      color: #bbb !important;
    }
    
    .flickity-button:hover {
      color: #333 !important;
    }
    
    .zoom-link {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      display: block;
      z-index: 1;
    }
    
    .caption,
    .captionTitle {
      padding-left: 10px;
      padding-right: 10px;
      text-align: center;
      max-width: 800px;
      margin-left: auto;
      margin-right: auto;
      white-space: pre-wrap;
    }
    
    .captionTitle {
      margin-top: 30px;
      font-weight: bold;
    }
    
    .flickity-page-dots {
      scale: 0.75;
    }
    
    /* Modal  */
    
    .sliderImg {  /* CHANGED */
      cursor: pointer;
    }
    
    .modal {
      display: none;
      /* Hidden by default */
      position: fixed;
      /* Stay in place */
      z-index: 1;
      /* Sit on top */
      /* padding-top: 100px; */
      /* Location of the box */
      left: 0;
      top: 0;
      width: 100%;
      /* Full width */
      height: 100%;
      /* Full height */
      overflow: auto;
      /* Enable scroll if needed */
      background-color: white;
      /* Fallback color */
      background-color: white;
      /* Black w/ opacity */
      cursor: pointer;
    }
    
    .modal-content {
      max-height: 1200px;
      width: auto;
      margin: 0 auto;
      display: block;
    }
    
    .close {
      text-transform: uppercase;
      color: #000;
      background-color: #fff;
      border: 0;
      padding: 4px 6px;
      line-height: 1;
      position: fixed;
      top: 0;
      left: 0;
      z-index: 9999;
    }
    
    .close:hover,
    .close:focus {
      color: #bbb;
    }
    <link rel="stylesheet" href="https://unpkg.com/flickity@2/dist/flickity.min.css">
    
    <div class="carousel-container">
      <p class='carousel-headline'>Carousel 1</p>
      <div class="carousel">
        <div class="carousel-cell">
          <img class="sliderImg" src="https://picsum.photos/720/540/?image=517" title="Titel 1" alt="Text 1" />
        </div>
        <div class="carousel-cell">
          <img class="sliderImg" src="https://picsum.photos/540/720/?image=696" title="Titel 1.1" alt="Text 1.1" />
        </div>
      </div>
      <p class="captionTitle"></p>
      <p class="caption"></p>
    </div>
    
    <hr>
    
    <div class="carousel-container">
      <p class='carousel-headline'>Carousel 2</p>
      <div class="carousel">
        <div class="carousel-cell">
          <img class="sliderImg" src="https://picsum.photos/720/540/?image=517" title="Titel 2" alt="Text 2" />
        </div>
        <div class="carousel-cell">
          <img class="sliderImg" src="https://picsum.photos/540/720/?image=696" title="Titel 2.1" alt="Text 2.1" />
        </div>
      </div>
      <p class="captionTitle"></p>
      <p class="caption"></p>
    </div>
    
    <div id="myModal" class="modal">
      <span class="close">close</span>
      <img class="modal-content" id="modalImage">
      <div id="caption"></div>
    </div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://unpkg.com/flickity@2/dist/flickity.pkgd.min.js"></script>

    CodePen