I am trying to create two sets of play/pause controls for a video using jquery and css. The first set is on the first screen in a large size, and the second set is in a fixed location in the viewport as the user scrolls down, this is so the user can listen to the audio and operate the controls as they view the website without having to scroll to the top. When the users clicks pause, the video pauses and fades, the pause button fades, and the play button becomes full opacity, and the opposite happens when the user clicks play. I have this working for the first set in the jsfiddle and code below, however I have been trying for the past few hours to find a way to make these changes happen with both sets of controls so both sets stay in sync (ie: when one pause button fades, the one in the second set does as well) and have not been able to make much progress.
Here is a jsfiddle (edited, was missing some css) of the first set working, and the jquery:
Object.defineProperty(HTMLMediaElement.prototype, 'playing', {
get: function() {
return !!(this.currentTime > 0 && !this.paused && !this.ended && this.readyState > 2);
}
})
var vid = document.getElementById("myVideo"),
pauseButton = document.getElementById("vidpause"),
playButton = document.getElementById("vidplay");
var vid = document.getElementById("myVideo");
function vidFade() {
vid.classList.add("stopfade");
}
pauseButton.addEventListener("click", function() {
vid.classList.toggle("stopfade");
if (vid.paused) {
vid.play();
vidpause.classList.add("full-button");
vidpause.classList.remove("fade-button");
vidplay.classList.add("fade-button");
vidplay.classList.remove("full-button");
} else {
vid.pause();
vidpause.classList.add("fade-button");
vidpause.classList.remove("full-button")
vidplay.classList.add("full-button");
vidplay.classList.remove("fade-button")
}
})
playButton.addEventListener("click", function() {
vid.classList.toggle("stopfade");
if (vid.playing) {
vid.pause();
vidplay.classList.add("full-button");
vidplay.classList.remove("fade-button");
vidpause.classList.add("fade-button");
vidpause.classList.remove("full-button");
} else {
vid.play();
vidplay.classList.add("fade-button");
vidplay.classList.remove("full-button")
vidpause.classList.add("full-button");
vidpause.classList.remove("fade-button")
}
})
I know that getElementById will only work with one element, to get the second set working with the first, I have tried using getElementByClassName (not shown) or querySelectorAll (below).
Object.defineProperty(HTMLMediaElement.prototype, 'playing', {
get: function() {
return !!(this.currentTime > 0 && !this.paused && !this.ended && this.readyState > 2);
}
})
var vid = document.getElementById("myVideo");
function vidFade() {
vid.classList.add("stopfade");
}
var pauseButton = document.querySelectorAll(".vidpause");
var i;
for (i = 0; i < pauseButton.length; i++) {
pauseButton[i].addEventListener("click", function() {
vid.classList.toggle("stopfade");
if (vid.paused) {
vid.play();
vidpause.classList.toggleClass("full-button");
vidpause.classList.remove("fade-button");
vidplay.classList.add("fade-button");
vidplay.classList.remove("full-button");
}
else {
vid.pause();
vidpause.classList.add("fade-button");
vidpause.classList.remove("full-button")
vidplay.classList.add("full-button");
vidplay.classList.remove("fade-button")
}
})
}
var playButton = document.querySelectorAll(".vidplay");
var i;
for (i = 0; i < pauseButton.length; i++) {
playButton[i].addEventListener("click", function() {
vid.classList.toggle("stopfade");
if (vid.playing) {
vid.pause();
vidplay.classList.add("full-button");
vidplay.classList.remove("fade-button");
vidpause.classList.add("fade-button");
vidpause.classList.remove("full-button");
} else {
vid.play();
vidplay.classList.add("fade-button");
vidplay.classList.remove("full-button")
vidpause.classList.add("full-button");
vidpause.classList.remove("fade-button")
}
})
}
When I try the above and variations of it, the chrome console gives me an error of "vidpause is undefined". I have been thinking maybe there is an issue with the order I am calling my elements in, or trying to loop the array (?) or trying to change classes while calling classes but ... I am stumped.
Any advice on this would be very helpful, I am pretty new to jquery.
First querySelectorAll returns a NodeList, so it does not have the classList property thus the error.
You need to iterate over the list and set the property. You can also simplify the code set by adding a common class video-play and video-pause to all the play and pause buttons
Object.defineProperty(HTMLMediaElement.prototype, 'playing', {
get: function() {
return !!(this.currentTime > 0 && !this.paused && !this.ended && this.readyState > 2);
}
})
var vid = document.getElementById("myVideo");
function vidFade() {
vid.classList.add("stopfade");
}
function fadeInOut(fadeIn, fadeOut) {
[].forEach.call(fadeIn, function(el) {
el.classList.add('full-button');
el.classList.remove('fade-button');
});
[].forEach.call(fadeOut, function(el) {
el.classList.remove('full-button');
el.classList.add('fade-button');
});
};
var pauseButtons = document.querySelectorAll(".video-pause");
var playButtons = document.querySelectorAll(".video-play");
[].forEach.call(document.querySelectorAll(".video-play, .video-pause"), function(pauseButton) {
pauseButton.addEventListener("click", function(e) {
e.preventDefault();
vid.classList.toggle("stopfade");
if (vid.paused) {
vid.play();
fadeInOut(pauseButtons, playButtons);
} else {
vid.pause();
fadeInOut(playButtons, pauseButtons);
}
})
});
video#myVideo {
transition: 1s opacity;
}
.stopfade {
opacity: .5;
}
.vidplay {
opacity: 0.50;
}
.vidpause {
opacity: 1;
}
/* Play/Pause Main */
.icon-play-main {
position: absolute;
top: 165px;
left: 50px;
width: 0;
height: 0;
border-width: 23px 35px;
border-style: solid;
border-color: transparent transparent transparent #ff0;
/* #666 */
}
.icon-pause-main,
.icon-pause-main:after {
position: absolute;
width: 14px;
height: 45px;
background-color: #ff0;
/* #666 */
}
.icon-pause-main {
top: 165px;
left: 3.5px;
}
.icon-pause-main:after {
content: "";
top: 0;
left: 20px;
}
/* Play/Pause bottom left */
.playpause {
top: 230px;
left: 0px;
position: fixed;
x-index: 510;
}
.icon-play {
position: absolute;
top: 10px;
left: 30px;
width: 0;
height: 0;
border-width: 10px 15px;
border-style: solid;
border-color: transparent transparent transparent #0cf;
/* #666 */
}
.icon-pause,
.icon-pause:after {
position: absolute;
width: 6px;
height: 20px;
background-color: #0cf;
/* #666 */
}
.icon-pause {
top: 10px;
left: 6px;
}
.icon-pause:after {
content: "";
top: 0;
left: 10px;
}
.fade-button {
opacity: 0.50;
}
.full-button {
opacity: 1;
}
<video autoplay loop muted id="myVideo">
<source src="http://hushhushandsecret.com/hhs/jquery/fullpagejs/imgs/flowers.mp4" type="video/mp4">Your browser does not support the video element.
</video>
<a class="video-pause vidpause full-button" href="#"><span class="icon-pause-main"></span></a>
<a class="video-play vidplay fade-button" href="#"><span class="icon-play-main"></span></a>
<div class="playpause">
<a class="full-button" href="#"><span class="video-pause icon-pause"></span></a>
<a class="fade-button" href="#"><span class="video-play icon-play"></span></a>
</div>
in order to convert it to a cleaner jQuery method you will need to do the following:
Add an extra generic class to each of the video controls such as play and pause:
<a id="vidpause" class="full-button" href="#"><span class="icon-pause-main pause"></span></a>
<a id="vidplay" class="fade-button" href="#"><span class="icon-play-main play"></span></a>
<div class="playpause">
<a class="full-button" href="#"><span class="icon-pause pause"></span></a>
<a class="fade-button" href="#"><span class="icon-play play"></span></a>
</div>
Then use jQuery generic class selectors with $(this) to manipulate the video and clicked controls as necessary:
// create a variable for the video element
var vid = $('#myVideo');
// Function to re-uyse repeated code
// Takes a bool playing - is the video playing
// takes element clicked - the video control element clicked
function vidControls(playing, clicked){
// if the video is playing pause it
if(!playing){
vid.get(0).pause();
clicked.parent('a').removeClass('fade-button').addClass('full-button'); // toggle the classes
clicked.parent('a').prev().removeClass('full-button').addClass('fade-button'); // assume pause always before play
}else{ // otherwise play it
vid.get(0).play();
clicked.parent('a').removeClass('full-button').addClass('fade-button'); // toggle the classes
clicked.parent('a').prev().removeClass('fade-button').addClass('full-button'); // assume pause always before play
}
}
// Play button click event
$('.play').click(function(){
// fade the video in/out as necessary
vid.toggleClass('stopfade');
// Re-use repeating code
vidControls(vid.get(0).paused, $(this));
});
// Pause button click event
$('.pause').click(function(){
// fade the video in/out as necessary
vid.toggleClass('stopfade');
// Re-use repeating code:
vidControls(vid.get(0).paused, $(this));
});
Working JSFiddle
Related
I want to make two functions, "functionattoppage" and "functionat1000pxpage". I want to make the function "functionattoppage" activate when the user is at the top of a webpage and "functionat1000pxpage" activate when the user is down about 1000px from the top of the page, is this possible?
Here is the only thing I could come up with:
window.onscroll = function () {
scrollFunction()
};
function scrollFunction() {
if (document.body.scrollTop > 1000 || document.documentElement.scrollTop > 1000) {
document.body.classList.add("body.changed");
}
if (document.body.scrollTop > 0 || document.documentElement.scrollTop > 0) {
document.body.classList.remove("body.changed");
}
}
<h1>Please look at the JavaScript section, it is what my best guess would be on how to make this work</h1>
Sorry if I didn't explain this very well, I don't have much time right now. If you need more information please ask me.
After console logging document.body.scrollTopin the fiddle came out to be zero. Plus your conditions are bound to fail because when scrollTop > 1000 then it is > 0 too.
you should either make it a else or move the >0 condition to the first
window.onscroll = function() {
scrollFunction()
};
function scrollFunction() {
console.log(document.documentElement.scrollTop);
if (document.documentElement.scrollTop > 200) {
document.getElementsByTagName('h1')[1].classList.add("changed");
}
else{
document.getElementsByTagName('h1')[1].classList.remove("changed");
}
}
.changed {
color: red
}
<h1>Please look at the JavaScript section, it is what my best guess would be on how to make this work</h1>
<div style="height: 400px;background: grey;"></div>
<h1>Please look at the JavaScript section, it is what my best guess would be on how to make this work</h1>
<div style="height: 400px;background: grey;"></div>
Looks like you are trying to hide a class when the scroll position for the window is within 0 and 1000 pixels yes? The a conditional that will check if the scrollY position of the window, window.scrollY is greater than 0, but less than 1000, add the class else remove the class.
window.onscroll = () => {
scrollFunction()
}
const scrollFunction = () => {
window.scrollY > 0 && window.scrollY < 1000 ?
document.body.classList.add("changed") :
document.body.classList.remove("changed")
document.getElementById("scroll_position").textContent = window.scrollY;
}
#scroll_position {
position: fixed;
top: 0;
right: 0;
background: red;
color: #fff;
padding: 8px;
width: 100px;
}
#cont {
height: 3000px;
}
#cont h1 {
position: sticky;
top: 50px;
}
.changed {
background: black;
color: white;
}
<p id="scroll_position"></p>
<div id="cont">
<h1>Please look at the JavaScript section, it is what my best guess would be on how to make this work</h1>
</div>
You can use a div as your marker. And when it is >= 0 execute one function and when it gets to -1000px execute another. Use getBoundingClientRect() to get an elements coordinates.
HTML
<div id=“marker1”></div>
JS
window.addEventListener( "scroll", function(){
let marker1 = document.getElementById("marker1").getBoundingClientRect();
if (marker1.top >= 0) atTop();
if (marker1.top <= -1000) at1000px();
})
function atTop() {
document.body.style.backgroundColor = "blue";
}
function at1000px() {
document.body.style.backgroundColor = "red";
}
Be aware the atTop won’t execute until you start scrolling because of the type of event listener. If you want it executed on load also then you’ll need to add that.
You can do it through sensing the scroll event as you are doing, but it's quite overheady.
Instead you could use an IntersectionObserver on a couple of elements, This will tell you when they come into and go out of the viewport and you don't have to worry about any intermediate scrolling.
If you already have elements that you want to sense in those positions you could sense those going into and out of the viewport. If not you can 'plant' a couple of 1px divs at the top and at 1000px and sense them coming in and out.
This snippet just logs the comings and goings to the console but of course you put whatever code you want in their place.
function callback (entries) {
for (let i = 0; i < entries.length; i++) {
if (entries[i].isIntersecting) {console.log(entries[i].target.classList + ' is in the viewport'); }
else {console.log(entries[i].target.classList + ' is not in the viewport'); }
}
}
const observer = new IntersectionObserver(callback);
const sensors = document.querySelectorAll('.sensor');
for (let i = 0; i < sensors.length; i++) {
observer.observe(sensors[i]);
}
.talldiv {
width: 100vw;
height: 2000px;
background-image: linear-gradient(to bottom, red, blue, orange, green, purple, cyan); /*just so we notice scrolling */
}
.sensor {
position: absolute;
left: 50%;
top: var(--top);
width: 1px;
height: 1px;
background: transparent;
}
.sensetop {
--top: 0px;
}
.sense1000px {
--top: 999px;
}
<div class="sensor sensetop"></div>
<div class="sensor sense1000px"></div>
<div class="talldiv"></div>
var terminal = document.getElementById('terminal');
var vncScreen = document.getElementById('screen');
var video = document.getElementById('video');
var vncToggle = document.getElementById('vncToggle');
var termToggle = document.getElementById('terminalToggle');
termToggle.onclick = function toggleTerminal() {
if (terminal.classList.contains('hide')) {
terminal.classList.remove('hide');
if (vncScreen.classList.contains('hide')) {} else {vncScreen.classList.add('hide')}
if (video.classList.contains('hide')) {} else {video.classList.add('hide')}
} else {
terminal.classList.add('hide');
if (video.classList.contains('hide')) {video.classList.remove('hide')} else {}
}
}
vncToggle.onclick = function toggleVNC() {
if (vncScreen.classList.contains('hide')) {
vncScreen.classList.remove('hide');
if (terminal.classList.contains('hide')) {} else {terminal.classList.add('hide')}
if (video.classList.contains('hide')) {} else {video.classList.add('hide')}
} else {
vncScreen.classList.add('hide');
if (video.classList.contains('hide')) {video.classList.remove('hide')} else {}
}
}
.black-box {
background: black;
height: 500px;
width: 500px;
position: absolute;
}
.green-box {
background: green;
height: 500px;
width: 500px;
position: absolute;
}
.blue-box {
background: blue;
height: 500px;
width: 500px;
position: absolute;
}
.hide {
display: none;
}
<button class="button" id="terminalToggle" title="Toggle Terminal">Toggle terminal</button>
<button class="button" id="vncToggle" title="Toggle Terminal">Toggle vnc</button>
<div id='video' class="black-box"></div>
<div id='screen' class="green-box hide"></div>
<div id='terminal' class="blue-box hide"></div>
basically when you click "Toggle terminal" it should show blue and then if you click again go back to black; when you click "Toggle vnc" it should show green and then if you click again go back to black. If you click "Toggle vnc" and it is already blue, it should turn green and vice versa (but clicking "Toggle terminal")
I currently have the following Js:
var terminal = document.getElementById('terminal'); //video-like element
var vncScreen = document.getElementById('screen'); //video-like element
var video = document.getElementById('video'); //video-like element
var vncToggle = document.getElementById('vncToggle'); //button
var termToggle = document.getElementById('terminalToggle'); //button
termToggle.onclick = function toggleTerminal() {
terminal.classList.toggle('hide');
vncScreen.classList.toggle('hide');
video.classList.toggle('hide');
}
vncToggle.onclick = function toggleVNC() {
vncScreen.classList.toggle('hide');
terminal.classList.toggle('hide');
video.classList.toggle('hide');
}
and css:
.hide {
display: none;
}
When I had just two different HTML elements, this class toggling methodology worked. Now that there are 3, I'm not sure it will work as desired.
video is initially visible i.e. hide is not in its classList
terminal is initially hidden i.e. hide is in its classList
vncScreen is initially hidden i.e. hide is in its classList
When toggleTerminal() is called:
video becomes hidden
terminal becomes visible
vncScreen becomes visible (but it should not)
If toggleVNC() is called (after toggleTerminal()):
video becomes visible again (but it should not)
terminal becomes hidden
vncScreen becomes hidden
Note how if the either of the function calls were toggled only by themselves, this method would work (provided I removed vncScreen.classList.toggle('hide'); in toggleTerminal() and terminal.classList.toggle('hide'); in toggleVNC()).
The problem is I need to account for any order of button-presses of termToggle and vncToggle. Essentially my goal is to "cycle" these elements such that:
1) Toggling of the "selected" element (i.e. termToggle corresponds to visibility of terminal element && vncToggle corresponds to visibility of vncScreen element) hides the remaining two elements (video && vncScreen || terminal && video respectively)
2) The order of toggling of "selected" elements does not affect 1)
3) A second toggle of the "selected" element will hide itself and the other element that is not video
Any ideas on how to best accomplish this?
At one point I thought about doing some logic that evaluated whether hide was contained in the appropriate classList's and just manually add or remove the hide class accordingly but this seemed kind of sloppy to me (idk, maybe its not?).
See code snippet in question for functionality, Js redundantly posted here:
var terminal = document.getElementById('terminal');
var vncScreen = document.getElementById('screen');
var video = document.getElementById('video');
var vncToggle = document.getElementById('vncToggle');
var termToggle = document.getElementById('terminalToggle');
termToggle.onclick = function toggleTerminal() {
if (terminal.classList.contains('hide')) {
terminal.classList.remove('hide');
if (vncScreen.classList.contains('hide')) {} else {vncScreen.classList.add('hide')}
if (video.classList.contains('hide')) {} else {video.classList.add('hide')}
} else {
terminal.classList.add('hide');
if (video.classList.contains('hide')) {video.classList.remove('hide')} else {}
}
}
vncToggle.onclick = function toggleVNC() {
if (vncScreen.classList.contains('hide')) {
vncScreen.classList.remove('hide');
if (terminal.classList.contains('hide')) {} else {terminal.classList.add('hide')}
if (video.classList.contains('hide')) {} else {video.classList.add('hide')}
} else {
vncScreen.classList.add('hide');
if (video.classList.contains('hide')) {video.classList.remove('hide')} else {}
}
}
I would like to display some element (div for example) when the user scrolling.
I seeing that a scrollTop, but isn't work. Because for sure I use badly.
I can't find some help without JQuery. I don't want to use JQuery.
I try this :
var scroll = document.body.scrollTop;
var divLis = document.querySelectorAll("div");
for(let i = 0; i < divLis.length; i++) {
if(scroll === divLis[i]) {
divLis[i].style.transform = "translateX(0)";
divLis[i].style.transition = "2s";
}
}
I honestly can't really tell what you're trying to do, but given your response to #uom-pgregorio's answer, I'm guessing you might just want a pure JS scroll listener:
window.addEventListener('scroll', function() {});
Edit: Sorry I just noticed that you didn't want jQuery but I'll just leave this here in case you change your mind.
$(window).scroll(function() {
// show the div(s)
});
That's an event handler where the function runs or fires up whenever the window or viewport scrolls.
Ok... I understand.
I wanted to try this :
* {
margin: 0;
padding: 0;
border: 0;
}
body {
height: 200vh;
}
.left {
width: 300px;
height: 300px;
background-color: red;
position: absolute;
top: 150%;
transform: translateX(-300px);
transition: 5s;
}
// HTML :
<div class="left"></div>
// JS
var divLis = document.querySelector(".left");
window.addEventListener("scroll", function (e) {
if(window.pageYOffset > 500) {
console.log(window.pageYOffset)
divLis.style.transform = "translateX(0)";
}
})
So, it's very simple and I took my head for nothing.
So thanks so much for answering me !
Enjoy your Weekend
I am trying to create a slideshow where the current photo is listed below in a circle and the circle changes color based on the current photo shown. The user should then be able to click on on each "bubble" and go to the appropriate photo while the show continues from that point.
The problem I am having is that I cannot remove the class, and then gather the index of the bubble. I cannot figure out how to use two separate loops with $bubbles.onclick. I tried with alerts for testing and it only displayed the second alert.
On a separate note, I also cannot get the the last bubble to remove class. The clipIndex skips the last value of the array and resets without displaying an alert and the last bubble stays pink.
Any suggestions? Sorry if the post isn't clear or the code doesn't read well, this is my first post.
<div id="slideShow">
<img class="clip currentClip" src="img/index01.jpg">
<img class="clip" src="img/index02.jpg">
<img class="clip" src="img/index03.jpg">
<img class="clip" src="img/index04.jpg">
<div id="sliderBubble">
<img class = "bubbles currentBubble" src="img/sBubblePink.png">
<img class = "bubbles" src="img/sBubble.png">
<img class = "bubbles" src="img/sBubble.png">
<img class = "bubbles" src="img/sBubble.png">
</div>
</div>
.clip {
max-height: 100%;
max-width: 100%;
position: absolute;
display: none;
margin-left: 50px;
border-radius: 10px;
}
.currentClip {
display: block;
}
#sliderBubble {
display: block;
height: 10px;
margin-top: 580px;
text-align:center;
}
var $clips = $(".clip"),
clipIndex = 0,
numClips = $clips.length,
sliderSpeed = 4000,
sliderEffect = 1000,
$bubbles = $(".bubbles");
fadeOutCurrent = function() {
$($clips[clipIndex++ % numClips]).fadeOut(sliderEffect, function() {
$(this).removeClass("currentClip");
});
},
fadeInNext = function () {
$($clips[clipIndex % numClips]).fadeIn(sliderEffect, function () {
$(this).addClass("currentClip");
});
},
setBubble = function() {
$bubbles[clipIndex % numClips].src = "img/sBubblePink.png";
$bubbles[(clipIndex % numClips) -1].src = "img/sBubble.png";
},
initSlider = function () {
setInterval(function() {
fadeOutCurrent();
fadeInNext();
setBubble();
}, sliderSpeed);
};
newClipIndex = function () {
for (var i = 0; i < numClips; i++) {
// Insert Function here for removeclass current bubble onclick
(function(clipIndex) {
$bubbles[i].onclick = function() {
alert(clipIndex);
$($clips[clipIndex]).addClass("currentClip");
}
})(i);
}
};
I am currently using a combination of fancybox thumbnails and buttons (only the toggle size button). By default, the buttons appear in the centre of the viewport, I would like to move this to the bottom right hand corner of the image, essentially appearing attached in the same way the close button is or just below the right corner would also be fine.
I have tried space it relative to the viewport width but it doesn't work. Is there a way to position it relative to the image?
I apologise for the abundance of code - I have no idea what to include and what to disregard, so I've put it all in.
If you look at my website (unfinished but I've uploaded it to help) you can see the issue on gallery one.
Shereewalker.com
Any help would be very much appreciated.
Here is my css
#fancybox-buttons {
position: fixed;
left: 0;
width: 100%;
z-index: 8050;}
#fancybox-buttons.top {top: 10px;}
#fancybox-buttons.bottom {bottom: 10px;}
.fancybox-close {
position: absolute;
top: -18px;
right: -18px;
width: 36px;
height: 36px;
cursor: pointer;
z-index: 8040; }
#fancybox-buttons ul {
width: 36px;
height: 36px;
cursor: pointer;
margin: 0 auto;
list-style: none;}
#fancybox-buttons ul li {
float: left;
margin: 0;
padding: 0;}
And my javascript
jQuery(document).ready(function ($) {
$(".fancybox").fancybox({
prevEffect : 'none',
nextEffect : 'none',
// API options
helpers : {
title : {
type: 'outside'
},
buttons: {},
thumbs: {
width : 10,
height : 10
}
}
}); // fancybox
}); // ready
And even more javascript
(function ($) {
//Shortcut for fancyBox object
var F = $.fancybox;
//Add helper object
F.helpers.buttons = {
defaults : {
skipSingle : false, // disables if gallery contains single image
position : 'top', // 'top' or 'bottom'
tpl : '<div id="fancybox-buttons"><ul><li><a class="btnToggle" title="Toggle size" href="javascript:;"></a></li></ul></div>'
},
list : null,
buttons: null,
beforeLoad: function (opts, obj) {
//Remove self if gallery do not have at least two items
if (opts.skipSingle && obj.group.length < 2) {
obj.helpers.buttons = false;
obj.closeBtn = true;
return;
}
//Increase top margin to give space for buttons
obj.margin[ opts.position === 'bottom' ? 2 : 0 ] += 30;
},
onPlayStart: function () {
if (this.buttons) {
this.buttons.play.attr('title', 'Pause slideshow').addClass('btnPlayOn');
}
},
onPlayEnd: function () {
if (this.buttons) {
this.buttons.play.attr('title', 'Start slideshow').removeClass('btnPlayOn');
}
},
afterShow: function (opts, obj) {
var buttons = this.buttons;
if (!buttons) {
this.list = $(opts.tpl).addClass(opts.position).appendTo('body');
buttons = {
prev : this.list.find('.btnPrev').click( F.prev ),
next : this.list.find('.btnNext').click( F.next ),
play : this.list.find('.btnPlay').click( F.play ),
toggle : this.list.find('.btnToggle').click( F.toggle ),
close : this.list.find('.btnClose').click( F.close )
}
}
//Prev
if (obj.index > 0 || obj.loop) {
buttons.prev.removeClass('btnDisabled');
} else {
buttons.prev.addClass('btnDisabled');
}
//Next / Play
if (obj.loop || obj.index < obj.group.length - 1) {
buttons.next.removeClass('btnDisabled');
buttons.play.removeClass('btnDisabled');
} else {
buttons.next.addClass('btnDisabled');
buttons.play.addClass('btnDisabled');
}
this.buttons = buttons;
this.onUpdate(opts, obj);
},
onUpdate: function (opts, obj) {
var toggle;
if (!this.buttons) {
return;
}
toggle = this.buttons.toggle.removeClass('btnDisabled btnToggleOn');
//Size toggle button
if (obj.canShrink) {
toggle.addClass('btnToggleOn');
} else if (!obj.canExpand) {
toggle.addClass('btnDisabled');
}
},
beforeClose: function () {
if (this.list) {
this.list.remove();
}
this.list = null;
this.buttons = null;
}
};
}(jQuery));
If you want to move the toggle button only, you actually need to clone it rather than moving it.
Based on this answer https://stackoverflow.com/a/17888534/1055987, we could tweak it into this :
CSS
/* hide the actual buttons helper */
#fancybox-buttons {
display: none;
}
/* position the clone : notice the class "clone" */
.clone {
position: absolute;
top: 5px;
right: 0;
}
.btnToggle.clone {
background-position: 3px -60px;
border-left: 1px solid #111;
border-right: 1px solid #3e3e3e;
width: 35px;
height: 35px;
background-image: url("{your path}/helpers/fancybox_buttons.png");
background-color: #333;
}
.clone.btnToggleOn {
background-position: -27px -60px;
}
Then the jQuery code :
jQuery(document).ready(function ($) {
$(".fancybox").fancybox({
helpers: {
title: {
type: 'inside'
},
buttons: {} // we need this to clone
},
afterLoad: function () {
// make sure we have a title
this.title = this.title ? this.title : " ";
},
afterShow: function () {
// wait for the buttons helper
setTimeout(function () {
$("#fancybox-buttons")
.find(".btnToggle")
.clone(true, true) // clone with data and events
.addClass("clone") // add class "clone"
.appendTo(".fancybox-title") // append it to the title
.fadeIn(); // show it nicely
}, 100); //setTimeout
}, // afterShow
onUpdate: function () {
var toggle = $(".btnToggle.clone").removeClass('btnDisabled btnToggleOn');
if (this.canShrink) {
toggle.addClass('btnToggleOn');
} else if (!this.canExpand) {
toggle.addClass('btnDisabled');
}
}
}); // fancybox
}); // ready
See JSFIDDLE
The toggle size button (and thumbnails) and hard to align because they are in separate full-width containers. This markup is generated by FancyBox for the gallery slideshow.
It looks like this:
<body>
<div class="fancybox-wrap">
<div class="fancybox-overlay">
<div id="fancybox-buttons">
<div id="fancybox-thumbs">
The .fancybox-wrap contains the gallery image and #fancybox-buttons contains the toggle size button.
Luckily, the OP was creating a template (tpl) for the toggle size button... but was injecting it into the <body> so it was unaware of the content of the .fancybox-wrap.
To fix this just change this line:
this.list = $(opts.tpl).addClass(opts.position).appendTo('body');
To this:
this.list = $(opts.tpl).addClass(opts.position).appendTo('.fancybox-wrap');
This just puts the buttons inside the same container as the gallery image (which is what we want to align too).