Prevent Firefox from moving after `.exitFullscreen()` - javascript

Firefox is exhibiting this behavior (bug?) that occurs after exiting a full screened <img> where the user ends up at the element that sits above the <img> the user had just viewed in fullscreen. In short my question is:
How can I prevent Firefox from scrolling up after exiting fullscreen mode?
The MCVE posted as a Snippet doesn't function due to SO's strict security measures so I have provided a plunker. All the details are commented in the Snippet and Plunker. In addition I have added a simple interface to not only reproduce the issue but to change the layout to test different combinations as well. Thank you for your valuable time.
SNIPPET (doesn't function--review this plunker instead)
/* Several attempts to use the .focus() method
|| and focus events did not work for me, neither
|| has tabindex and anchors. If it appears that
|| my implementation is wrong (a strong possibility)
|| please inform me.
*/
$('a').click(function(e) {
var tgt = $(this).prev();
fs(tgt[0]);
$(this).focus();
});
/* This function is for the MCVE
|| It enables the ~select~ to remove and re-insert
|| the test elements. By doing so, we can see
|| how the test elements behave in different
|| combinations. What I found out about FF is
|| that when exiting a full screened ~img~ that's
|| positioned last is that it will lose focus
|| and the viewport is scrolled up to the element
|| above it.
*/
$('#sel1').on('change', function(e) {
var V = $(this).val();
var first = $('#' + V).find(':first').attr('id');
if ($('#' + V).hasClass('media')) {
$('#' + V).fadeOut('#' + first);
} else {
$('#' + V).fadeIn('#' + first);
}
$('#' + V).toggleClass('media');
});
/* These 2 functions are responsible for
|| full screen. Please inform me if there's a
|| better way, or if anything is outdated. I
|| have researched the Fullscreen API and I
|| haven't found any updates of any use. I've
|| used these functions for the last 3 years
|| so maybe I might've missed something
|| critical.
*/ // There's no ms prefixes because I'm not concerned about IE.
var isFullScreen = function() {
return !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement);
}
function fs(target) {
if (!isFullScreen()) {
if (target.requestFullscreen) {
target.requestFullscreen();
} else if (target.webkitRequestFullscreen) {
target.webkitRequestFullscreen();
} else if (target.mozRequestFullScreen) {
target.mozRequestFullScreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
}
}
}
/* These styles are here for the demo itself
|| and are not a cause of the problem at hand
*/
* {
margin: 0;
padding: 0
}
body {
font: 400 16px/1.3 Consolas;
height: 100%;
width: 100%;
background: #333;
color: #fed
}
a {
margin: 0 auto 50px;
display: block;
width: 48px;
height: 48px;
text-align: center;
cursor: pointer;
background-size: contain;
}
.vid,
.img,
.gif,
.svg {
display: block;
margin: 20px auto;
}
.expand {
background: url(http://imgh.us/expand_2.svg)no-repeat;
}
header {
padding: 15px 10px;
margin: 15px auto;
}
fieldset {
border: 10px solid tomato;
width: 20ch
}
legend {
font-size: 1.2em;
}
dt {
text-decoration: underline;
font: 1.1em;
}
dd {
margin-left: 20px
}
.note,
dt {
color: #ffcc33
}
.demo {
width: 450px;
padding: 10px;
counter-reset: step;
}
.demo li::before {
counter-increment: step;
content: "ยป " counter(step) ". ";
text-indent: -150px;
margin-left: 30px;
color: cyan;
}
.fs:-webkit-full-screen {
max-width: 100%;
height: auto;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">
<title>Prevent Firefox from Moving After .exitFullscreen()</title>
<style>
</style>
</head>
<body>
<header>
<dl>
<dt>Objective</dt>
<dd>Prevent Firefox from Moving After .exitFullscreen()</dd>
<dt>Behavior</dt>
<dd><b class='note'>Expected: </b>When exiting fullscreen mode, we should be at the same position that we were at before</dd>
<dd><b class='note'>Experienced: </b>In FF, when exiting fullscreen mode, we are scrolled up as if the element above has a higher tab priority or more than likely is that tab index and focus are being ignored by FF.</dd>
<dt>Question</dt>
<dd><b><mark>How can I prevent Firefox from scrolling up after exiting fullscreen mode?</mark></b></dd>
</dl>
</header>
<section>
<ol class='demo'>
<li>To reproduce issue, use the <select> to remove items C, D, E, and F.</li>
<li>Next, fullscreen item B by clicking the icon below it.</li>
<li>Then exit full screen mode by hitting <kbd>ESC</kbd>.</li>
<li>Notice we have jumped up the page.</li>
</ol>
</section>
<!--This ~select~ is for the MCVE - details are
commented below in the ~script~ block-->
<section>
<fieldset>
<legend>Remove and Re-insert Elements</legend>
<select id='sel1'>
<option value="">----</option>
<option value='A'><video> src=MP4</option>
<option value='B'><img> src=PNG</option>
<option value='C'><video> poster=GIF</option>
<option value='D'><img> src=SVG</option>
<option value='E'><div> &nbsp;</option>
<option value='F'><iframe> srcdoc="<DIV><div>"</option>
</select>
</fieldset>
<!--I tried using the ~a~nchors, -id-, -name-, and -tabindex-
FF was ignoring my attempts to keep or get focus. Using named or
id ~a~nchors failed since the distance between desired spot
and the spot FF ends up at is short.-->
<div id='A' class='media'>
<video id="vid1" class="vid fs" src="http://html5demos.com/assets/dizzy.mp4" controls></video>
<a href='#/' class='expand' tab-index='1'></a>
</div>
<div id='B' class='media'>
<img id='img1' class='img fs' src='http://imgh.us/Lenna.png'>
<a href='#/' class='expand' tab-index='1'></a>
</div>
<div id='C' class='media'>
<video id='gif1' class='gif fs' poster='http://imgh.us/gir_zim.gif' width='300' height='300'></video>
<a href='#/' class='expand' tab-index='1'></a>
</div>
<div id='D' class='media'>
<img id='svg1' class='svg fs' src='http://www.clker.com/cliparts/j/g/8/S/V/O/test.svg' width='auto' height='500'>
<a href='#/' class='expand' tab-index='1'></a>
</div>
<!--Subjects E and F were added to see if a "dummy"
element were to be the last element so that FF
would exit fullscreen on the last ~img~ correctly.
I got mixed results.-->
<div id='E' class='media'>
<div id='div1' class='fs'> </div>
<a href='#/' class='expand' tab-index='1' height='1' width='1'></a>
</div>
<div id='F' class='media'>
<iframe id='ifm1' class='fs' srcdoc="<div style='color:lime'>iframe srcdoc</div><div style='color:cyan'>2 divs</div>" allowfullscreen></iframe>
<a href='#/' class='expand' tab-index='1' height='1' width='1'></a>
</div>
<footer class='bottom'> </footer>
</section>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script>
</script>
</body>
</html>

Define variables initially.
var sx,sy;
Save scrollbar position before entering Fullscreen
var d= document, r= d.documentElement, b= d.body;
sx= r.scrollLeft || b.scrollLeft || 0;
sy= r.scrollTop || b.scrollTop || 0;
When player exit full screen,
window.scrollTo(sx,sy);
Hope this helps!

This answer is fully credited to #Kaido and I'll readily replace this answer if and when Kaido posts an answer.
My attempts at using the scroll methods didn't work is because I was listening to click events when I should've been listening for the onmozfullscreenchange
Plunker
Demo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prevent Firefox from Moving After .exitFullscreen()</title>
<style>
button {
display: block;
padding: 0;
width: 32px;
height: 32px;
text-align: center;
cursor: pointer;
background-size: contain;
}
.expand {
background: url(http://imgh.us/expand_2.svg)no-repeat;
}
</style>
</head>
<body>
<div id='A' class='media'>A
<video id="vid1" class="vid fs" src="http://html5demos.com/assets/dizzy.mp4" controls></video>
</div>
<div id='B' class='media'>B
<img id='img1' class='img fs' src='http://imgh.us/Lenna.png'>
<button class='expand'></button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script>
$('button').click(function(e) {
e.preventDefault();
var tgt = $(this).prev();
fs(tgt[0]);
});
/* This function is for the MCVE
|| It enables the ~select~ to remove and re-insert
|| the test elements. By doing so, we can see
|| how the test elements behave in different
|| combinations. What I found out about FF is
|| that when exiting a full screened ~img~ that's
|| positioned last is that it will lose focus
|| and the viewport is scrolled up to the element
|| above it.
*/
$('#sel1').on('change', function(e) {
var V = $(this).val();
var first = $('#' + V).find(':first').attr('id');
if ($('#' + V).hasClass('media')) {
$('#' + V).fadeOut('#' + first);
} else {
$('#' + V).fadeIn('#' + first);
}
$('#' + V).toggleClass('media');
});
/* These 2 functions are responsible for
|| full screen.
*/ // There's no ms prefixes because I'm not concerned about IE.
var isFullScreen = function() {
return !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement);
}
// SOLUTION XXXXXXXXXX]START[XXXXXXXXXXXXXXX
var yOffset;
document.onmozfullscreenchange = function() {
if (!isFullScreen()) {
window.scrollTo(0, yOffset);
}
};
// SOLUTION XXXXXXXXXXX]END[XXXXXXXXXXXXXXXX
function fs(target) {
if (!isFullScreen()) {
yOffset = pageYOffset;
if (target.requestFullscreen) {
target.requestFullscreen();
} else if (target.webkitRequestFullscreen) {
target.webkitRequestFullscreen();
} else if (target.mozRequestFullScreen) {
target.mozRequestFullScreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
}
}
}
</script>
</body>
</html>

Related

How to Delay a Javascript Function Until it is in the middle of web page?

Hello I have a number animation on my web page and I dont want the animation to start until it is in the middle of the web page. I tried to google onscroll and other options but I could not get this to work properly.
I prefer for the animation not to start until the visitor has scrolled down to 472px. As of right now as soon as the web page loads the number animation starts automatically. Any help I would really appreciate it.
// 472 px - Starts Yellow Counter Section
const counters = document.querySelectorAll('.counter');
const speed = 200; // The lower the slower
counters.forEach(counter => {
const updateCount = () => {
const target = +counter.getAttribute('data-target');
const count = +counter.innerText;
// Lower inc to slow and higher to slow
const inc = target / speed;
// console.log(inc);
// console.log(count);
// Check if target is reached
if (count < target) {
// Add inc to count and output in counter
counter.innerText = count + inc;
// Call function every ms
setTimeout(updateCount, 1);
} else {
counter.innerText = target;
}
};
updateCount();
});
.bg-yellow-white {
background: #f7c51e;
color: white;
}
.container {
max-width: 1404px;
margin: auto;
padding: 0 2rem;
overflow: hidden;
}
.l-heading {
font-weight: bold;
font-size: 4rem;
margin-bottom: 0.75rem;
line-height: 1.1;
}
/* Padding */
.py-1 {
padding: 1.5rem 0;
}
.py-2 {
padding: 2rem 0;
}
.py-3 {
padding: 3rem 0;
}
/* All Around Padding */
.p-1 {
padding: 1.5rem;
}
.p-2 {
padding: 2rem;
}
.p-3 {
padding: 3rem;
}
/* ======================== Red Block ======================== */
.red-block {
height: 472px;
width: 100%;
background-color: red;
}
/* ======================== PROJECS COMPLETED ======================== */
#projects-completed .container .items {
display: flex;
justify-content: center;
flex-wrap: wrap;
}
#projects-completed .container .items .item .circle {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
<div class="red-block">
<p>red block</p>
</div>
<section id="projects-completed" class="counters bg-yellow-white">
<div class="container">
<div class="items">
<div class="item text-center p-3">
<div class="circle">
<div class="counter l-heading" data-target="1750">500</div>
</div>
<h2 class="py-2">Projects Completed</h2>
</div>
<div class="item text-center p-3">
<div class="circle py-2">
<div class="l-heading counter" data-target="5">500</div>
</div>
<h2 class="py-2">Staff Members</h2>
</div>
<!-- <div class="item text-center p-3">
<div class="circle">
<h3 class="l-heading ">1750</h3>
</div>
<h2 class="py-2">Projects Completed</h2>
</div>
<div class="item text-center p-3">
<div class="circle py-2">
<h3 class="l-heading">5</h3>
</div>
<h2 class="py-2">Staff Members</h2>
</div> -->
</div>
</div>
</section>
wesbos has great video on this https://www.youtube.com/watch?v=uzRsENVD3W8&list=PLu8EoSxDXHP6CGK4YVJhL_VWetA865GOH&index=14&t=0s
Basically what you need to do is listen for scroll and check where user currently is compared to desired place in px
you can check code here and adjust it to your needs https://github.com/wesbos/JavaScript30/blob/master/13%20-%20Slide%20in%20on%20Scroll/index-FINISHED.html
Try getBoundingClientRect(). document.querySelector( 'some element' ).getBoundingClientRect() will give you the properties of the specific element
for Example if you want to start an animation when an element is visible to user on his screen ( in the visible viewport ), you can use this to call the function and start the animation
let calledStatus = 0; // some flag variable to remember if function is called
window.onscroll = function(){
element = document.querySelector( '.some element' );
clientRect = element.getBoundingClientRect();
if( clientRect.top < window.innerHeight && clientRect.top > ( clientRect.height * -1) && calledStatus == 0){
//call your function or do other stuff
console.log('called' )
calledStatus = 1;
}
}
By using jquery , first add this reference script above your js code or referenece script
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></scrip>
....
</head>
if you want the code to launch specifically after 472 px:
js
$(document).ready(function () {
Let initialScroll = true;
//you can decrease or increase 472 depending on where exactly
//you want your function to be called
$(document).scroll(function () {
if (($(document).scrollTop() > 472)&& initialScroll) {
//call your function here
console.log( "reached 472")
InitialScroll=false;
}
});
});
if you want your function to start after reaching the middle
of the document
you place a div where the middle of the html code is :
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
...
<div id="middle"></div>
...
</body>
</html>
js
$(document).ready(function () {
Let initialScroll=true
$(document).scroll(function () {
if (($(document).scrollTop() >=$('#middle').position().top)&&initialScroll) {
//call your function here
console.log( "reached middle")
InitialScroll=false;
}
});
});
There is a native javascript API for "listetning" where the user currently is on the page called Intersection Observer. Basically you set a callback which should execute once the desired content scrolls into view.
It's used for all those fancy page animations where cards appear once you start scrolling to the bottom of the page since it's far more efficient than listening on the scroll event.
Kevin Powell did a great video about this topic.
Hope it helps!
Here's a code copy pasted, but it should give you a clue on how it should work:
document.addEventListener("DOMContentLoaded", function() {
let lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
let active = false;
const lazyLoad = function() {
if (active === false) {
active = true;
setTimeout(function() {
lazyImages.forEach(function(lazyImage) {
if ((lazyImage.getBoundingClientRect().top <= window.innerHeight && lazyImage.getBoundingClientRect().bottom >= 0) && getComputedStyle(lazyImage).display !== "none") {
lazyImage.src = lazyImage.dataset.src;
lazyImage.srcset = lazyImage.dataset.srcset;
lazyImage.classList.remove("lazy");
lazyImages = lazyImages.filter(function(image) {
return image !== lazyImage;
});
if (lazyImages.length === 0) {
document.removeEventListener("scroll", lazyLoad);
window.removeEventListener("resize", lazyLoad);
window.removeEventListener("orientationchange", lazyLoad);
}
}
});
active = false;
}, 200);
}
};
document.addEventListener("scroll", lazyLoad);
window.addEventListener("resize", lazyLoad);
window.addEventListener("orientationchange", lazyLoad);
});

Add a div below inline-block wrapped row - Part 2

A solution suggested by #musicnothing in an older thread displays a content div below the row of inline divs, this works good when the div.wrapblock is clicked itself.
http://jsfiddle.net/SYJaj/7/
function placeAfter($block) {
$block.after($('#content'));
}
$('.wrapblock').click(function() {
$('#content').css('display','inline-block');
var top = $(this).offset().top;
var $blocks = $(this).nextAll('.wrapblock');
if ($blocks.length == 0) {
placeAfter($(this));
return false;
}
$blocks.each(function(i, j) {
if($(this).offset().top != top) {
placeAfter($(this).prev('.wrapblock'));
return false;
} else if ((i + 1) == $blocks.length) {
placeAfter($(this));
return false;
}
});
});
The issue I'm having.
I need to trigger the same effect, but by adding the click event to a link within the wrapblock itself.
My code is nearly identical.
What I have changed is the click event handle, from $('.wrapblock').click(function() to $('.more').on('click', function() I also needed to add .closest(".wrapblock") for the content div to position itself outside of the wrapblock.
$('.more').on('click', function() {
...
if ($blocks.length == 0) {
placeAfter($(this).closest(".wrapblock"));
return false;
}
Everything can be seen and tested http://jsfiddle.net/7Lt1hnaL/
Would be great if somebody could shed some light on how I can calculate which block it needs to follow with the offset method, thanks in advance.
As you can see in the latest fiddle example, the content div is not displaying below the row of divs.
I also apologise, I wanted to post on the thread in discussion but I only have a minor posting reputation which doesn't let me, thanks.
var $chosen = null;
var $allBlocks = [];
$(function(){
$allBlocks = $('.wrapblock');
})
$(window).on('resize', function() {
if ($chosen != null) {
$('#content').css('display','none');
$('body').append($('#content'));
$chosen.trigger('click');
}
});
$('.more').on('click', function() {
$chosen = $(this);
var position = $chosen.parent('.wrapblock').position();
$('#content').css('display','inline-block');
$allBlocks.filter(function(idx, ele){
return $(ele).position().top == position.top;
})
.last()
.after($('#content'));
});
.wrapblock
{
background: #963a3a;
display: inline-block;
width: 90px;
height: 90px;
color: white;
font-size: 14px;
text-align: left;
padding: 10px;
margin: 10px;
vertical-align:top;
position:relative;
}
#content
{
display:none;
vertical-align:top;
width:100%;
background: #5582c1;
font-size: 12px;
color: white;
padding: 10px;
}
.more {
position:absolute;
bottom:15px;
right:15px;
cursor:pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<div class="wrapblock">1
<span class="more" data-ref="1">more</span>
</div>
<div class="wrapblock">2
<span class="more" data-ref="2">more</span>
</div>
<div class="wrapblock">3
<span class="more" data-ref="3">more</span>
</div>
<div class="wrapblock">4
<span class="more" data-ref="4">more</span>
</div>
<div class="wrapblock">5
<span class="more" data-ref="5">more</span>
</div>
<div class="wrapblock">6
<span class="more" data-ref="6">more</span>
</div>
<div class="wrapblock">7
<span class="more" data-ref="7">more</span>
</div>
<div class="wrapblock">8
<span class="more" data-ref="8">more</span>
</div>
<div class="wrapblock">9
<span class="more" data-ref="9">more</span>
</div>
<div id="content">Some Content</div>
Seems to do what you want. Basically, it just filters down the set of all blocks to the row of the block you clicked on using the assumption that they'll all have the same vertical offset (top), then takes the last one, because jQuery will keep them in document order, so that'll be the last one in the layout row.
Oh, and I updated the fiddle http://jsfiddle.net/7Lt1hnaL/1/

How to pause and start gif using jQuery AJAX

I am a student and I am trying to start, pause and start a gif when a user clicks the gif, however I am stuck on how to add in this click function. I know that the the gif version of the object is .images.fixed_height.url and the still image is .images.fixed_height_still.url . If I try to append like below $(this) I get that images is undefined. How would I go by doing this? Currently 10 gifs show when you click the category. Thank you for any help in advance.
Code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Giphy</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<style>
body {
background-image: url('http://www.efoza.com/postpic/2011/04/elegant-blue-wallpaper-designs_154158.jpg');
width: 100%;
}
button {
padding: 0 2%;
margin: 0 2%;
}
h4 {
font-size: 165%;
font-weight: bold;
color: white;
}
.container {
background-color: rgba(0, 0, 0, 0.2);
max-width: 1000px;
width: 100%;
}
.btn {
margin-top: 2%;
margin-bottom: 2%;
font-size: 125%;
font-weight: bold;
}
.guide {
padding: 3% 0 0 0;
}
.tag-row {
padding: 3% 0 0 0;
}
.category-row {
padding: 3% 0 ;
}
#photo {
padding-bottom: 3%;
}
</style>
</head>
<body>
<div class="container">
<div class="row text-center guide"><h4>Click a category and see the current top 10 most popular giphy's of that category!</h4></div>
<div class="row text-center tag-row" id="tags"></div>
<div class="row text-center category-row">
<input type="" name="" id="category"><button class="btn btn-secondary" id="addTag">Add Category</button>
</div>
</div>
<div class="container">
<div id="photo"></div>
</div>
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<script type="text/javascript">
var tags = ["dog", "dolphin", "whale", "cat", "elephant", "otter"];
// Function for displaying movie data
function renderButtons() {
$("#tags").empty();
for (var i = 0; i < tags.length; i++) {
$("#tags").append('<button class="tag-buttons btn btn-primary">' + tags[i] + '</button>');
}
}
// Add tags function //
$(document).on('click', '#addTag', function(event) {
event.preventDefault();
var newTag = $("#category").val().trim();
tags.push(newTag);
$("#tags").append('<button class="tag-buttons btn btn-primary">' + newTag + '</button>');
});
// Tag button function //
$(document).on('click', '.tag-buttons', function(event) {
// Keeps page from reloading //
event.preventDefault();
var type = this.innerText;
console.log(this.innerText);
var queryURL = "http://api.giphy.com/v1/gifs/search?q=" + window.encodeURI(type) + "&limit=10&api_key=dc6zaTOxFJmzC";
$.ajax({
url: queryURL,
method: "GET"
}).done(function(response) {
for (var i = 0; i < response.data.length; i++) {
$("#photo").append('<img src="' + response.data[i].images.fixed_height_still.url + '" class="animate">');
$('.animate').on('click', function() {
$(this).remove().append('<img src="' + response.data[i].images.fixed_height.url + '" class="animate">');
console.log($(this));
});
}
});
$("#photo").empty();
});
renderButtons();
</script>
</body>
</html>
The difference between fixed_height and fixed_height_still will solve the problem. if you look closely the urls differ only by name_s.gif and name.gif.
So you can simply swap the two images to create a player. This will act like a play and stop. Not play and pause. But in a small gif I don't think pause really matter, stop and pause will look similar.
adding class name to the #photo
$("#photo").append('<img class="gif" src="' + response.data[i].images.fixed_height_still.url + '">');
event handler which will control play and stop
$('body').on('click', '.gif', function() {
var src = $(this).attr("src");
if($(this).hasClass('playing')){
//stop
$(this).attr('src', src.replace(/\.gif/i, "_s.gif"))
$(this).removeClass('playing');
} else {
//play
$(this).addClass('playing');
$(this).attr('src', src.replace(/\_s.gif/i, ".gif"))
}
});
jsfiddle demo
https://jsfiddle.net/karthick6891/L9t0t1r2/
you can use this jquery plugin http://rubentd.com/gifplayer/
<img class="gifplayer" src="media/banana.png" />
<script>
$('.gifplayer').gifplayer();
</script>
you can control like this
Use these methods to play and stop the player programatically
$('#banana').gifplayer('play');
$('#banana').gifplayer('stop');
youll find more details here https://github.com/rubentd/gifplayer

On div scroll activate another div's scroll

Jsfiddle
I trying to activate my current scroll while I am outside that scroll, specifically in #DivDet
here is what I tried:
$("div#DivDet").scroll(function () {
// I don't know what i should have here
// something like $("div#scrlDiv").scroll();
});
It sounds like you want to respond to a scroll on one div by scrolling another.
You've already determined how to hook the scroll event. To set the scroll position of an element (the other div), you set the element's scrollTop and scrollLeft values (which are in pixels). If you want two divs to scroll in near-unison, for instance, you'd assign the source div's scrollTop and scrollLeft to the target div.
Example: Live Copy | Source
Relevant JavaScript:
(function() {
var target = $("#target");
$("#source").scroll(function() {
target.prop("scrollTop", this.scrollTop)
.prop("scrollLeft", this.scrollLeft);
});
})();
or alternately (source):
(function() {
var target = $("#target")[0]; // <== Getting raw element
$("#source").scroll(function() {
target.scrollTop = this.scrollTop;
target.scrollLeft = this.scrollLeft;
});
})();
Full page:
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<meta charset=utf-8 />
<title>Scroll Example</title>
<style>
.scroll-example {
display: inline-block;
width: 40%;
border: 1px solid black;
margin-right: 20px;
height: 100px;
overflow: scroll;
}
</style>
</head>
<body>
<p>Scroll the left div, watch the right one.</p>
<div id="source" class="scroll-example">
1
<br>2
<br>3
<br>4
<br>5
<br>6
<br>7
<br>8
<br>9
<br>10
<br>11
<br>12
<br>13
<br>14
<br>15
<br>16
<br>17
<br>18
<br>19
<br>20
</div>
<div id="target" class="scroll-example">
1
<br>2
<br>3
<br>4
<br>5
<br>6
<br>7
<br>8
<br>9
<br>10
<br>11
<br>12
<br>13
<br>14
<br>15
<br>16
<br>17
<br>18
<br>19
<br>20
</div>
<script>
(function() {
var target = $("#target");
$("#source").scroll(function() {
target.prop("scrollTop", this.scrollTop)
.prop("scrollLeft", this.scrollLeft);
});
})();
</script>
</body>
</html>
Solution with Vanilla JavaScript
const multiElementScroll = ( elem1, elem2 ) => {
elem1.onscroll = function() {
elem2.scrollTop = this.scrollTop;
};
}
multiElementScroll( div1, div2 )
section {
display: flex;
justify-content: space-between;
}
.scroll-box {
width: 200px;
height: 200px;
overflow-y: scroll;
border: 1px solid #d99;
}
.scroll-box h2 { margin-top: 50px; }
<section>
<div class="scroll-box" id="div1">
<h1>A</h1>
<h2>B</h2>
<h2>C</h2>
<h2>D</h2>
<h2>E</h2>
<h2>F</h2>
<h2>G</h2>
<h2>H</h2>
</div>
<div class="scroll-box" id="div2">
<h1>1</h1>
<h2>2</h2>
<h2>3</h2>
<h2>4</h2>
<h2>5</h2>
</div>
<section>

JQuery Accordion - Last Cell Flip Sides

I really didn't know how to come up with a descriptive title for this. Pretty much what I'm trying to do is make this accordion list item jump to the other side of the page when clicked. Currently the accordion is opening from left to right - but the last cell doesn't jump right it instead stays in place. How can I make that last cell jump to the right instead of staying in place.
The point of this is to put a picture in the tabs and have them come together at the beginning and end of browsing links.
JSFiddle Example - click the last cell
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Accordion</title>
<link rel="stylesheet" type="text/css" href="redo.css" />
</head>
<body>
<div id="hc1" class="haccordion">
<ul>
<li>
<div class="hpanel">
<div class="preview" id="p1"></div>
<div class="contentContainer">
<div class="content">
</div>
</div>
</div>
</li>
<li>
<div class="hpanel">
<div class="preview" id="p2"></div>
<div class="contentContainer">
</div>
</div>
</li>
<li>
<div class="hpanel">
<div class="preview" id="p3"></div>
<div class="contentContainer">
</div>
</div>
</li>
<li>
<div class="hpanel">
<div class="preview" id="p4"></div>
<div class="contentContainer">
asdf
</div>
</div>
</li>
<li>
<div class="hpanel">
<div class="preview" id="p5"></div>
<div class="contentContainer">
</div>
</div>
</li>
</ul>
</div>
<!-- Scripts -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type="text/javascript" src="accordion.js"></script>
<!-- End Scripts -->
</body>
CSS
*
{
margin:0px;
padding:0px
}
html, body
{
height:100%;
width: 100%;
}
#hc1, #hc1 ul, #hc1 li
{
height: 100%;
}
#hc1, #hc1 ul
{
width: 100%;
}
.preview
{
width: 50px;
float: left;
height: 100%;
background-color: #E48525
}
#p1{background-color: #231F20}
#p2{background-color: #4F4E4F}
#p3{background-color: #919191}
#p4{background-color: #C4C4C3}
#p5{background-color: #E8E8E8}
/*
#p1{background-color: red}
#p2{background-color: blue}
#p3{background-color: green}
#p4{background-color: black}
#p5{background-color: orange}
*/
.contentContainer
{
background-color: gray;
margin: 0 auto;
width: 100%;
height: 100%;
}
/* -- Start Accordion -- */
.haccordion{
padding: 0;
}
.haccordion ul{
margin: 0;
padding: 0;
list-style: none;
overflow: hidden; /*leave as is*/
}
.haccordion li{
margin: 0;
padding: 0;
display: block; /*leave as is*/
overflow: hidden; /*leave as is*/
float: left; /*leave as is*/
}
/* -- End Accordion -- */
Javascript
var haccordion={
//customize loading message if accordion markup is fetched via Ajax:
ajaxloadingmsg: '<div style="margin: 1em; font-weight: bold"><img src="ajaxloadr.gif" style="vertical-align: middle" /></div>',
accordioninfo: {}, //class that holds config information of each haccordion instance
expandli:function(accordionid, targetli){
var config=haccordion.accordioninfo[accordionid]
var $targetli=(typeof targetli=="number")? config.$targetlis.eq(targetli) : (typeof targetli=="string")? jQuery('#'+targetli) : jQuery(targetli)
if (typeof config.$lastexpanded!="undefined") //targetli may be an index, ID string, or DOM reference to LI
{
config.$lastexpanded.stop().animate({width:config.paneldimensions.peekw}, config.speed); //contract last opened content
config.$lastexpanded.removeClass('active');
}
$targetli.stop().animate({width:$targetli.data('hpaneloffsetw')}, config.speed) //expand current content
config.$lastexpanded=$targetli
if($targetli.attr('class') != 'active')
$targetli.addClass('active');
},
urlparamselect:function(accordionid){
var result=window.location.search.match(new RegExp(accordionid+"=(\\d+)", "i")) //check for "?accordionid=index" in URL
if (result!=null)
result=parseInt(RegExp.$1)+"" //return value as string so 0 doesn't test for false
return result //returns null or index, where index is the desired selected hcontent index
},
getCookie:function(Name){
var re=new RegExp(Name+"=[^;]+", "i") //construct RE to search for target name/value pair
if (document.cookie.match(re)) //if cookie found
return document.cookie.match(re)[0].split("=")[1] //return its value
return null
},
setCookie:function(name, value){
document.cookie = name + "=" + value + "; path=/"
},
loadexternal:function($, config){ //function to fetch external page containing the entire accordion content markup
var $hcontainer=$('#'+config.ajaxsource.container).html(this.ajaxloadingmsg)
$.ajax({
url: config.ajaxsource.path, //path to external content
async: true,
error:function(ajaxrequest){
$hcontainer.html('Error fetching content.<br />Server Response: '+ajaxrequest.responseText)
},
success:function(content){
$hcontainer.html(content)
haccordion.init($, config)
}
})
},
init:function($, config){
haccordion.accordioninfo[config.accordionid]=config //cache config info for this accordion
var $targetlis=$('#'+config.accordionid).find('ul:eq(0) > li') //find top level LIs
config.$targetlis=$targetlis
config.selectedli=config.selectedli || [] //set default selectedli option
config.speed=config.speed || "normal" //set default speed
//KEY_CHANGE_BEGIN
var maxWidth = $targetlis.parent ().width ();
$targetlis.each ( function () { maxWidth -= $(this).outerWidth (true); } );
$targetlis.each(function(i){
var $target=$(this).data('pos', i) //give each li an index #
var lclMaxWidth = maxWidth + $target.find ('.hpanel:eq(0)').outerWidth (true);
$target.css ('width', config.paneldimensions.fullw);
//get offset width of each .hpanel DIV (config.dimensions.fullw + any DIV padding)
var hpaneloffsetw = $target.find ('.hpanel:eq(0)').outerWidth (true);
if (hpaneloffsetw > lclMaxWidth)
hpaneloffsetw = lclMaxWidth;
$target.data('hpaneloffsetw', hpaneloffsetw);
$target.css ('width', '');
//KEY_CHANGE_END
$target.click(function(){
haccordion.expandli(config.accordionid, this)
config.$lastexpanded=$(this);
})
if (config.collapsecurrent){ //if previous content should be contracted when expanding current
config.$lastexpanded.removeClass('active');
$target.click(function(){
$(this).stop().animate({width:config.paneldimensions.peekw}, config.speed); //contract previous content
})
}
}) //end $targetlis.each
var selectedli=haccordion.urlparamselect(config.accordionid) || ((config.selectedli[1] && haccordion.getCookie(config.accordionid))? parseInt(haccordion.getCookie(config.accordionid)) : config.selectedli[0])
selectedli=parseInt(selectedli)
if (selectedli>=0 && selectedli<config.$targetlis.length){ //if selectedli index is within range
config.$lastexpanded=$targetlis.eq(selectedli)
config.$lastexpanded.css('width', config.$lastexpanded.data('hpaneloffsetw')) //expand selected li
}
$(window).bind('unload', function(){ //clean up and persist on page unload
haccordion.uninit($, config)
}) //end window.onunload
},
uninit:function($, config){
var $targetlis=config.$targetlis
var expandedliindex=-1 //index of expanded content to remember (-1 indicates non)
$targetlis.each(function(){
var $target=$(this)
$target.unbind()
if ($target.width()==$target.data('hpaneloffsetw'))
expandedliindex=$target.data('pos')
})
if (config.selectedli[1]==true) //enable persistence?
haccordion.setCookie(config.accordionid, expandedliindex)
},
setup:function(config){
//Use JS to write out CSS that sets up initial dimensions of each LI, for JS enabled browsers only
document.write('<style type="text/css">\n')
document.write('#'+config.accordionid+' li{width: '+config.paneldimensions.peekw+';\nheight: '+config.paneldimensions.h+';\n}\n')
document.write('#'+config.accordionid+' li .hpanel{width: '+config.paneldimensions.fullw+';\nheight: '+config.paneldimensions.h+';\n}\n')
document.write('<\/style>')
jQuery(document).ready(function($){ //on Dom load
if (config.ajaxsource) //if config.ajaxsource option defined
haccordion.loadexternal($, config)
else
haccordion.init($, config)
}) //end DOM load
}
}
haccordion.setup({
accordionid: 'hc1', //main accordion div id
paneldimensions: {peekw:'50px', fullw:'100%', h:'100%'},
selectedli: [4, false], //[selectedli_index, persiststate_bool]
collapsecurrent: false //<- No comma following very last setting!
})
Here it is: tinker.io/f7fe4/12
This is the simplest change of all of the versions, requiring only floating the first preview to the right. Can be done programatically or with css (can be buggy in IE7+):
$('#hc1 li .preview').first().css('float','right');
or
#hc1 li:first-child .preview {
float:right;
}
--
Is this the kind of effect you're looking for?
https://tinker.io/f7fe4/8
Here's the same kind of affect, with a 'smoother' animation (it keeps the outer div still on the screen however)
https://tinker.io/f7fe4/9
And this is what I thought you were talking about at first
https://tinker.io/f7fe4/4 (this pops the left most cell over to the right and opens it, kind of like an infinite slider)

Categories