I added the ability to display a youtube video within a Lightbox on my website. However, the code I found to help with this doesn't have a close (X) on the Lightbox. Whilst it does close by just clicking anywhere on the mask, I think not all web users are going to realise this, so I added a simple
x
onto the Lightbox div. Whilst this does actually give a functional closing (X) on the lightbox, it has the undesirable effect of the page being back at the top when the Lightbox has closed.
What I ideally want is for the Lightbox to simply close, and the page remains in the same place as it was when it opens, which is what happens if I just click on the mask.
I can see there is a section commented '// Hide lightbox when clicked on', but I have no clue how I can make an (X) also trigger this same action.
Here is the complete script used.
<div id="youtubelightbox" class="parent">x
<div class="centeredchild">
<div class="videowrapper">
<div id="playerdiv"></div>
</div>
</div>
</div>
<script>
// load Youtube API code asynchronously
var tag = document.createElement('script')
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0]
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag)
var isiOS = navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)/i) != null //boolean check for iOS devices
var youtubelightbox = document.getElementById('youtubelightbox')
var player // variable to hold new YT.Player() instance
// Hide lightbox when clicked on
youtubelightbox.addEventListener('click', function(){
this.style.display = 'none'
player.stopVideo()
}, false)
// Exclude youtube iframe from above action
youtubelightbox.querySelector('.centeredchild').addEventListener('click', function(e){
e.stopPropagation()
}, false)
// define onYouTubeIframeAPIReady() function and initialize lightbox when API is ready
function onYouTubeIframeAPIReady() {
createlightbox()
}
// Extracts the Youtube video ID from a well formed Youtube URL
function getyoutubeid(link){
// Assumed Youtube URL formats
// https://www.youtube.com/watch?v=Pe0jFDPHkzo
// https://youtu.be/Pe0jFDPHkzo
// https://www.youtube.com/v/Pe0jFDPHkzo
// and more
//See http://stackoverflow.com/a/6904504/4360074
var youtubeidreg = /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/i;
return youtubeidreg.exec(link)[1] // return Youtube video ID portion of link
}
// Creates a new YT.Player() instance
function createyoutubeplayer(videourl){
player = new YT.Player('playerdiv', {
videoId: videourl,
playerVars: {autoplay:1,
rel:0,
showinfo:0,
fs:0
}
})
}
// Main Youtube lightbox function
function createlightbox(){
var targetlinks = document.querySelectorAll('.lightbox')
for (var i=0; i<targetlinks.length; i++){
var link = targetlinks[i]
link._videoid = getyoutubeid(link) // store youtube video ID portion of link inside _videoid property
targetlinks[i].addEventListener('click', function(e){
youtubelightbox.style.display = 'block'
if (typeof player == 'undefined'){ // if video player hasn't been created yet
createyoutubeplayer(this._videoid)
}
else{
if (isiOS){ // iOS devices can only use the "cue" related methods
player.cueVideoById(this._videoid)
}
else{
player.loadVideoById(this._videoid)
}
}
e.preventDefault()
}, false)
}
}
if (isiOS){ // iOS devices can only use the "cue" related methods
player.cueVideoById(this._videoid)
}
else{
player.loadVideoById(this._videoid)
}
After some trial and error I figured this out.
I changed the html to
<div id="youtubelightbox" class="parent">
<div class="centeredchild"><div id="x">x</div>
<div class="videowrapper">
<div id="playerdiv"></div>
</div>
</div>
</div>
And added the following to the script
x.addEventListener('click', function(){
youtubelightbox.style.display = 'none'
player.stopVideo()
}, false)
Related
EDIT #1 with connexo’s solution
Within the following HTML, I want to click in the parent 'li' to play the child 'audio'
The problem is noted in the alert calls within the JS; i.e., trying to compare a HTMLLIElement with a HTMLAudioElement.
How can I successfully do that?
HTML:
I have several:
<li>
text here<br>
<audio controls preload="auto">
<source src="aSong.mp3">
</audio>
</li>
JS:
$('li:has(audio)').on("click", function(evt) {
var m, theSongInArray,
// thisSong = $(this)[0]; // HTMLLIElement
// now a HTMLAudioElement thanks to connexo
$thisLI = $(this);
thisSong = $thisLI.find('audio')[0];
// itsAllSongs defined elsewhere
for (m=0; m < itsAllSongs.length; m++)
{
// HTMLAudioElement
theSongInArray = itsAllSongs[m];
if (thisSong == theSongInArray)
{
if ( thisSong.paused )
thisSong.play();
else
{
thisSong.pause();
thisSong.currentTime = 0;
}
}
}
});
Note: connexo's solution is perfect - but now I have a new problem =
My intent above, which connexo has solved, was to be able to click anywhere within 'li:has(audio)' and have the toggling effect between .play() and .pause() .. and it now does that.
BUT, now the anywhere within 'li:has(audio)' seems to not include the play icon of:
If I click on the slider, the progress bar, the time-stamp, or anywhere else on the long <audio> control it works great, but not on the play icon on the far left of the above control.
SUPER wierd - this 2nd challenge goes away (I can then click just on the play icon) if I remove:
$('li:has(audio)').on("click", function(evt) {
})
Hopefully, connexo has another brilliant solution.
EDIT #2 = solution of the current problem:
Now, I can click on either the li area surrounding the <audio> element, or on just the <audio> element itself. As a matter of interest, when I click on just the play icon of <audio>, the song will play and, if I click on the position slider, the slider will move without playing/pausing the song itself:
/*
alert(evt.target); // = HTMLLIElement, or HTMLAudioElement
*/
if (evt.target.id.length == 0)
thisSong = $(this).find('audio')[0]; // HTMLLIElement -> HTMLAudioElement
else // >= 3, e.g., = "SSB" or "AIRFORCE"
thisSong = $(this)[0]; // [object HTMLAudioElement]
I am a beginner JS user, and I am trying to get a video to play on fullscreen and replace an invisible div further down on the page. I started with a guide from Chris Ferdinandi.
In his guide, the video replaces the image that is clicked. I would like to have the div later down on the page to be replaced on the click.
Any guidance would be great!
HTML
<a data-video="480459339" class="stylsheetref" href="#" target="">Watch the Tour</a>
<div id="video-replace"></div>
Javascript (modified from this guide)
<script>
if (!Element.prototype.requestFullscreen) {
Element.prototype.requestFullscreen = Element.prototype.mozRequestFullscreen || Element.prototype.webkitRequestFullscreen || Element.prototype.msRequestFullscreen;
}
// Listen for clicks
document.addEventListener('click', function (event) {
//Set invisible Div (new code added by me)
var videonew = '#video-replace');
// Check if clicked element is a video link
var videoId = event.target.getAttribute('data-video');
if (!videoId) return;
// Create iframe
var iframe = document.createElement('div');
iframe.innerHTML = '<p>x</p><iframe width="560" height="960" src="https://player.vimeo.com/video/' + videoId + '?rel=0&autoplay=1" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>';
var video = iframe.childNodes[1];
// Replace the image with the video
event.target.parentNode.replaceChild(video, videonew);
// Enter fullscreen mode
video.requestFullscreen();
}, false);
</script>
There are problems in your code.
var videonew = '#video-replace'); there's an orphan ), since you are using this in the `replaceChild``method I assume you want the variable to reference to an element.
So change it to
var videonew = document.querySelector('#video-replace');
Pro tip: Using the Developer console during development can help you figure out such errors in your code.
I have designed an i-phone-like screen on a web browser where I am testing this application I am in the process of building. It works great up until the point where I want to call out another set of videos.
What works
The application is structured so that when the user sees the screen she is directed to a channel that has a vertical video.
The buttons on the top left and top right advance to the next and the previous video.
<div id="topVid" class="videoContainer">
<div class="topHorizontalButtonRow">
</div>
<video class="topVid" loop onclick="this.paused? this.play() : this.pause()" >
<source src="videos/ParisisBurning_660x370_I_went_to_a_ball.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
There is a "channel" button that shows the user a smaller window if pressed, where the user can view other channels by clicking on a second set of buttons next and previous buttons.
<div id="bottomVid" class="videoContainerTwo hiddenElement">
<div class="topHorizontalButtonRow">
<div class="buttonLeftTriangleBlue"></div>
<div class="buttonRightTriangleBlue"></div>
</div>
<video loop onclick="this.paused? this.play() : this.pause()" >
<source src="videos/Politics_Refugee_Sign.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
jquery show/hide smaller window:
$(".buttonTeardropChannelBlue").click( function (){
if( $("#bottomVid").is(':visible') ) {
$("#bottomVid").hide();
} else {
$("#bottomVid").show();
}
});
If the user wants to watch this specific channel, she can click on the smaller window, which hides the current window and advances to the other channel. The video can be clicked on, and once that happens, the user will be directed to the next channel.
Below is the code that works perfectly to advance the video of the current selection, and it contains the videos in arranged in an array.
var Vids = (function() {
var _currentId = -1;
var _urls =
["videos/ParisisBurning_370x660_Get_Into_The_Suits_Vert.mp4","videos/ParisisBurning_370x660_School_Vert.mp4","videos/ParisisBurning_660x370_I_came_I_saw_Vert.mp4", "videos/ParisisBurning_660x370_I_went_to_a_ball.mp4"]; // literal array
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
})();
What does not work
The issue: showing and hiding multiple video lists
However, the problem starts when I want to select a different class of videos, which has the exact same code except for different videos. I have changed the name of the function to say, VidsTwo but the problem remains.
var VidsTwo = (function() {
var _currentId = -1;
var _urls = ["videos/Politics_Atl_We_are_the_people.mp4","videos/Politics_Atlanta_Whose_Streets.mp4", "videos/Politics_Womens_March_Washington_CBS_VERT.mp4",
"videos/Politics_No_bans_no_walls_America_is_home_to_all_VERT.mp4",
"videos/Politics_Let_them_in_VERT.mp4",
"videos/Politics_Tear it Down_JFK_VERT.mp4",
"videos/Politics_This_is_What_America_Looks_Like_embrace.mp4",
"videos/Politics_This_land_was_made_VERT.mp4", "videos/Politics_We_need_an_independent_investigation_town_hall.mp4",
"videos/Politics_Just say no_town_hall_VERT.mp4", ]; // literal array
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
})();
The issue remains: the buttons will continue to play the videos of the current channel in addition to the ones of the new channel, and it will not hide the current video. I understand it happens because in the javascript code, it uses the select element by tag which is "video". and all the array lists have "video" so it is playing all of them.
What is the best solution to this problem, given that I want to be able to separate the videos into categories "channels" that will have similar thematic content, and that this categories will be called by users as they look at a second smaller window of videos?
Core questions
Is there a way to have it NOT play a selection of arrays? What can I change in the Javascript code that will indicate that these separate video arrays do not belong to the same class? How can I make it clear in the code that these videos, although they are all videos, belong to different categories and therefore can only be played if their specific category is called?
Brainstorming solutions:
I am thinking I would probably need a second div that will have a
second row of buttons that call out the second function, since the
prev and next indicate a separate variable that was declared for each
class of videos...but this is getting a bit complicated for my newbie
skills:)
Or perhaps each video on a parent class should be saved on the
html itself as a hidden div and should be called by using "show
next child of parent div", as opposed to being saved as an array on
the javascript code?
The next step is adding marquee text to each video so maybe having
separate hidden divs on the html itself is a better solution than
having the videos stored as javascript arrays?
This is basically a prototype/beta for something that will become an
app so there is no database yet, (which will make it easier to
store this info eventually once I begin more in-depth user tests).
This complication is for testing only:)
UPDATE: I am still curious as to what the best solution would be, however I have decided, in this case, to add divs directly to the html and use jquery's next sibling selectors. Because I will have some text specific to some videos, they won't be properly connected to the javascript arrays anyway. I find the javascript array solution "cooler" but it is perhaps not the best in the end.
make Vids like this:
var Vids = function(vidArray=[]) {
var _currentId = -1;
var _urls = vidArray;
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
};
then prepare your url array and call Vids:
var urls =["videos/ParisisBurning_370x660_Get_Into_The_Suits_Vert.mp4","videos/ParisisBurning_370x660_School_Vert.mp4","videos/ParisisBurning_660x370_I_came_I_saw_Vert.mp4", "videos/ParisisBurning_660x370_I_went_to_a_ball.mp4"];
Vids(urlf).play(3); //Replace 3 with any id
I am using easytabs.js to display some content. On one of the tabs is a youtube video with a custom image. The youtube video plays when the custom image is clicked. However I would like the youtube video to pause when one of the other tabs are clicked.
The test page is here: http://toddyhotpants.com/test/
If anyone has any ideas I would love to hear them!
Thanks!
The YouTube video player has a JavaScript APi you can use to work with videos loaded on your page.
You can find the docs here: https://developers.google.com/youtube/js_api_reference
As you can see there, add this to the video URL when you load it: &enablejsapi
Then when it is loaded it will call the onYoutubePlayerReady call back after which player will be available for you to call player.playVideo() and player.pauseVideo().
Let me know how it goes.
UPDATE:
Here is the example, this should pause a video after a tab is switched with easytabs.
I got the easytabs code from their site and it has jQuery so I assume that is a requirement and you already have it.
Remember to change the container ID for your tab div in the code, and set any easytab options you need to set.
<script type="text/javascript">
var yPlayer = false;
function onYouTubePlayerReady(playerId) {
yPlayer = document.getElementById(playerId);
}
$('#YOUR-TAB-CONTAINER-ID-HERE')
.easytabs({
//put your options here
})
.bind('easytabs:after', function(e, tab){
if ( ! tab.hasClass('active') && ! tab.hasClass('collapsed') ) {
yPlayer.pauseVideo();
}
});
</script>
UPDATE 2:
Based on your comment I've come up with this:
<script>
$(function(){
var player = false;
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onYouTubePlayerAPIReady() {
player = new YT.Player('ytplayer', {
height: '670',
width: '470',
videoId: 'nsjPrsmsll0 '
});
$('#YOUR-TAB-CONTAINER-ID-HERE')
.easytabs({
//put your options here
})
.bind('easytabs:after', function(e, tab){
if ( ! tab.hasClass('active') && ! tab.hasClass('collapsed') ) {
player.pauseVideo();
}
});
}
});
</script>
Replace your youtube video iframe with the this: and use the JS code I provided.
I'm pretty new to javascript and programming and have run into a brick wall with my project. I have a div which contains the javascript to embed a quicktime player, when the page is first loaded no .mov file is pointed at by the page so a placeholder div is 'unhidden' and the player div is set to style.display = 'none'.
So far so good, the user then enters the name of the new movie, the placeholder div is hidden and the player div is unhidden. My problem is that the javascript in the player div didn't run when the div was made visible, if I make the script for the player into a seperate function then call it when the player div is unhidden then the player runs full screen and not in the div.
I've tried using jquery to add the javascript into the div after the div is made visible but can't seem to get $("#player").load(somescript) or $("#player").html(htmlwithjavain) to add the script.
I know the player div contenst can be changed as I can use $("#player").empty(); and $("#player").html(); to manipulate it.
Thanks for reading, hope you can help
Here's the relevant code:-
<html>
<head>
<title>Browse Media Player</title>
<link rel="stylesheet" type="text/css" href="CSS/browser.css" />
<script type="text/javascript">
<!--
var userinterrupt=false;
var runonce=false;
var currentfile;
var basemediapath = "http://10.255.10.71/IsilonBrowse/movfiles/";
var playerheight = 750;
var playerwidth = 900;
var currenttc;
var basetime;
var baseduration;
var currentduration = "no tc available";
var tcoffset = 35990;
var playspeed = 1;
var boolisplaying=true;
var boolonslide=false;
//function to fire off other methods when the DOM is loaded
//Use in place of body onload, using jquery library
//
$(document).ready(function()
{
//showEvents('jquery running');
showhideplayer(null);
});
//-->
</script>
</head>
<body onload="forceslider(); timecode()">
<div class="container">
<div id="timecode_container">
<div class="tc_overlay"></div>
<div id="timecode" class="timecode"></div>
</div>
<div id="player" class="playerdiv" style="display:none;">
**javascript for player goes here...**
</div>
<div id="noclipoverlay" class="playerdiv" style="display:none;">
<p>No media loaded...
</div>
<div id="noclipoverlay2" class="playerdiv" style="display:none;">
<p>loading media....
</div>
</div>
<div id="loadstatus"></div>
<div id="alerts"></div>
</body>
</html>
Now the mainstuff.js file which should add the javascript code:-
//function to switch the player div and mask div is no media file is
//defined in the 'currentfile' variable
//
function showhideplayer(state)
{
if (!currentfile)
{
showEvents('wtf no media');
document.getElementById("player").style.display = 'none';
document.getElementById("noclipoverlay").style.display = 'block';
}
else if (currentfile)
{
document.getElementById("player").style.display = 'block';
document.getElementById("noclipoverlay").style.display = 'none';
showEvents('valid media file');
}
}
//end of showhideplayer
//function to change movie files, note SetResetPropertiesOnReload must be set to false
//otherwise the B'stard player will default all attributes when setURL runs
//
function changemovie(newmovie)
{
oldfile = currentfile;
if (newmovie == currentfile)
{
showEvents('same file requested so no action taken');
return;
}
if (newmovie != currentfile)
{
showEvents('changing movie');
//switch the divs around to hide the 'no media slide'
document.getElementById("player").style.display = 'block';
document.getElementById("noclipoverlay").style.display = 'none';
}
showEvents('movie changed to: '+newmovie);
currentfile=newmovie;
if (!oldfile)
{
$("#player").empty();
showEvents('the old media file was blank');
$("#player").load("/path/loadplayer.js");
}
document.movie1.Stop();
document.movie1.SetResetPropertiesOnReload(false);
document.movie1.SetURL(currentfile);
//showEvents('movie changed to: '+newmovie);
if (boolisplaying)
{
document.movie1.Play();
}
}
[EDIT] and here's the contents of loadplayer.js:-
var movie1 = QT_WriteOBJECT(
currentfile, playerwidth, playerheight, "",
"controller","false",
"obj#id", "movie1",
"emb#id","qt_movie1",
"postdomevents","True",
"emb#NAME","movie1",
"enablejavascript","true",
"autoplay","true",
"scale","aspect",
"pluginspage","http://www.apple.com/quicktime/download/"
);
Without knowing the content of your loadplayer.js file, it will be difficult to give you a solution.
For example, if the script attempts to do a document.write() after the page has loaded, it will create a new page, overwriting the current page. Is that what you mean when you say the quicktime movie is running full screen?
Also it is generally not a good idea to load a SCRIPT element and insert it as HTML. When you add HTML to the page, jQuery finds all the SCRIPT elements and evaluates them in a global context, which might give you unexpected results.
Use QT_GenerateOBJECTText_XHTML or QT_GenerateOBJECTText from AC_QuickTime.js if you'd like to return a string.