I have a reveal presentation in an iframe. Each slide has a div with an audio player in in and the divs id is "narration".
I have a button outside the frame that is used to hide/show this div. The problem is that it only does this for the first slide and not the rest.
EDIT : This seems to hide the divs :
function checkAudio() {
if (document.getElementById('cb1').checked) {
var y = document.getElementById('ppt').contentWindow.document.getElementsByClassName('narration');
var i;
for (i = 0; i < y.length; i++) {
y[i].style.display = 'none';
}
} else {
var y = document.getElementById('ppt').contentWindow.document.getElementsByClassName('narration');
var i;
for (i = 0; i < y.length; i++) {
y[i].style.display = 'block';
}
}
}
HTML in iframe (There is one for each slide) :
<div id="narration"><p align="middle">
<audio controls="" preload="none">
<source src="mp3/2.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio></p>
</div>
JS (outside of iframe):
function checkAudio() {
if (document.getElementById('cb1').checked) {
document.getElementById('ppt').contentWindow.document.getElementById('narration').style.display = 'none';
} else {
document.getElementById('ppt').contentWindow.document.getElementById('narration').style.display = 'block';
}
}
After changing your IDs to classes (read here why), you need to update your javascript code to handle the multiple divs via a foreach loop.
function checkAudio() {
var narrationDivs = document.getElementById('ppt').contentWindow.document.getElementsByClassName('narration');
var newDisplay = "block";
if (document.getElementById('cb1').checked) {
newDisplay = "none";
}
narrationDivs.forEach(function(div) {
div.style.display = newDisplay;
});
}
In order to have the code run again when your iframe changes, you need to update your iframe changing function:
function setURL(url){
document.getElementById('ppt').src = url;
checkAudio(); // Just run the function again!
}
If you want to show a specific element using a button, you should use a specific ID. If you want to show all items using a single button you should use classes. You could also use classes to show a specific element e.g.: The 5th button will show the 5th element but this is not a good style.
When the site in the iframe loads the next frame, your code doesn't know to hide the div it presents again. You need an event to process on.
You need to poll the id so that if it shows up again, you can hide it. See: iframe contents change event?
function checkAudio() {
if (document.getElementById('cb1').checked) {
var y = document.getElementById('ppt').contentWindow.document.getElementsByClassName('narration');
var i;
for (i = 0; i < y.length; i++) {
y[i].style.display = 'none';
}
} else {
var y = document.getElementById('ppt').contentWindow.document.getElementsByClassName('narration');
var i;
for (i = 0; i < y.length; i++) {
y[i].style.display = 'block';
}
}
}
You might also want to check out the audio-slideshow plugin that allows to play separate audio files for each slide and fragment. If your main need is this, the plugin should do the job for you.
You can find a demo here and the plugin here. There is also the slideshow-recorder plugin that allows you to record your narration.
Asvin
Related
I've created a loader for my website (the whole front end is custom,so as of right now i can edit about 95% of everything I have except for woocommerce plugin).
Super simple one, it follows this logic, if the anchor is an # or the page itself it wont do anything (which is what I wanted) but the woocommerce plugin to generate my image gallery is a link that isn't the page itself or a #. Which means I need to collect the path-name of the extension that if it ends on jpg png or any image file to continue; and skip over the rest of the animation and allow the plugin to run its course.
Ive use Barba JS, SWUP and other animations with woocommerce and this is the only one that doesnt interrupt or have so many conditions with woocommerce.
function fadeInPage() {
if (!window.AnimationEvent) { return; }
var fader = document.getElementById('fader');
fader.classList.add('fade-out');
}
document.addEventListener('DOMContentLoaded', function() {
if (!window.AnimationEvent) { return }
var anchors = document.getElementsByTagName('a');
******* for (var idx = 0; idx < anchors.length; idx += 1) {
if (anchors[idx].hostname !== window.location.hostname || anchors[idx].pathname === window.location.pathname) *******
{
continue;
}
anchors[idx].addEventListener('click', function(event) {
var fader = document.getElementById('fader'),
anchor = event.currentTarget;
var listener = function() {
window.location = anchor.href;
fader.removeEventListener('animationend', listener);
};
fader.addEventListener('animationend', listener);
event.preventDefault();
fader.classList.add('fade-in');
});
}
});
window.addEventListener('pageshow', function (event) {
if (!event.persisted) {
return;
}
var fader = document.getElementById('fader');
fader.classList.remove('fade-in');
});
I starred what i need changed. the animation works, the page transition works. I need the animation to recognize if the a tag ends with an jpg or png to skip and not do the animation and treat the link as if the animation wasn't there.
Never used woocommerce so I don't totally understand the use case, but you can get the file extension of a link like so:
for (var idx = 0; idx < anchors.length; idx += 1) {
let fileType = anchors[idx].href.split('.').pop();
//Do whatever
}
Or if you want to compare it to a preset list of extensions you can use a regex:
for (var idx = 0; idx < anchors.length; idx += 1) {
if (anchors[idx].href.match(/\.(jpg|png)$/)) {
//Do whatever
}
}
I would like to hide an image on my site using this code:
$(document).ready(function(){ $('body').find('img[src$="myimage.png"]').remove(); });
Is there any way to convert this to javascript and still make it work in internet explorer??
i assume you mean convert to vanilla js (without needing jquery lib).. this should work
window.addEventListener("load", function(){
const els = document.getElementsByTagName("IMG");
for (let i = 0; i < els.length; i++){
let src = els[i].getAttribute("src");
if (src == "myimage.png") {
els[i].style.display = "none";
break;
}
}
});
My code is running well...
but there is one thing I can't solve:
when I mouseover the image the loop starts well, but on subsequent mouseovers it starts changing faster and faster...
var Image = new Array("//placehold.it/400x180/?text=Welcome",
"//placehold.it/400x180/?text=To",
"//placehold.it/400x180/?text=My",
"//placehold.it/400x180/?text=Web+page",
"//placehold.it/400x180/?text=INPHP");
var Image_Number=0;
var Image_Length= Image.length;
function change_image(num){
Image_Number = Image_Number + num;
if(Image_Number > Image_Length)
Image_Number = 0;
if(Image_Number < Image_Length)
document.slideshow.src = Image[Image_Number];
return false;
Image_Number = Image_Length;
}
function auto () {
setInterval("change_image(1)", 1000);
}
<img src="//placehold.it/400x180/?text=Welcome" name="slideshow" onmouseover="auto()" />
On every mouseover you're reassigning a brand-new-intervalâ„¢ resulting in multiple functions running at the same time.
name on IMG tag is an obsolete HTML5 attribute - See also img tag # W3.org
"change_image(1)" ...strings inside setInterval or setTimeout tigger eval. Which is bad. The real function name should be used instead: setInterval(functionName, ms)
You're not managing well the argument num
You cannot have code after a return statement
Use the mouseenter event (instead of mouseover)
and many more errors....
Here's a remake:
var images = [
"//placehold.it/400x180/?text=Welcome",
"//placehold.it/400x180/?text=To",
"//placehold.it/400x180/?text=My",
"//placehold.it/400x180/?text=Web+page",
"//placehold.it/400x180/?text=INPHP"
];
var c = 0; // c as Counter ya?
var tot = images.length;
var angryCat = false;
// Preload! Make sure all images are in tha house
for(var i=0; i<tot; i++) {
var im = new Image();
im.src= images[i];
}
function changeImage() {
document.slideshow.src = images[++c%tot];
}
function auto() {
if(angryCat) return; // No more mouse enter
angryCat = true;
setInterval(changeImage, 1000);
}
<img src="//placehold.it/400x180/?text=Welcome" name="slideshow" onmouseenter="auto()" />
The increment and loop is achieved using ++c % tot
The angryCat boolean flag helps to know it the auto() already started (mouse was there!), in that case it will return; (exit) the function preventing the creation of additional overlapping intervals on subsequent mouseenter (which was your main issue).
Additionally, I'd suggest to keep your JS away from HTML, so instead of the JS attribute event
onmouseenter="auto()"
assign an ID to your image id="myimage" and use JS:
document.getElementById("myimage").addEventListener("mouseenter", auto, false);
I have a html like:
<div class="clicked-div" onclick="divClicked(this);">
<img src="src1"/>
<img src="src2"/>
......
</div>
if I set the img onclick event using the following method:
var imgs = document.getElementsByTagName("img");
for (var i = 0; i < imgs.length; i++) {
imgs[i].onClick=imageClicked(imgs[i]);
}
function divClicked(div){
alert(div.getAttribute("id"));
}
function imageClicked(image){
alert(image.getAttribute("src"));
}
when the uiwebview load one image, it will call imageClicked a time though I haven't click it.
And when I click a image ,how do I determing which method will be called divClicked or imageClicked? THank you.
Your code is calling imageClicked at the point you're trying to just set it up as a handler.
It's actually easier than you think it is:
var imgs = document.getElementsByTagName("img");
for (var i = 0; i < imgs.length; i++) {
imgs[i].onclick = imageClicked; // <=== Not *calling*, just referring to it
}
function imageClicked() {
alert(this.getAttribute("src")); // <== `this` rather than `image`
}
When imageClicked is called in response to the click event, it's called with this set to the image element that was clicked.
How to prevent the div to handle the click event when the image was clicked
Instead of onclick, you use modern event handling and stop propagation. As you're using a uiWebView, you don't have to worry about old IE, which makes things simpler:
var imgs = document.getElementsByTagName("img");
for (var i = 0; i < imgs.length; i++) {
imgs[i].addEventListener("click", imageClicked, false);
}
function imageClicked(e) {
alert(this.getAttribute("src"));
e.stopPropagation(); // <=== Prevents the click reaching the div
}
Live example:
// Hook up the divs so we handle clicks on them
var divs = document.getElementsByTagName("div");
for (var i = 0; i < divs.length; i++) {
divs[i].onclick = divClicked; // <=== Not *calling*, just referring to it
}
function divClicked() {
alert("div clicked");
}
// The images code
var imgs = document.getElementsByTagName("img");
for (var i = 0; i < imgs.length; i++) {
imgs[i].addEventListener("click", imageClicked, false);
}
function imageClicked(e) {
alert(this.getAttribute("src"));
e.stopPropagation();
}
<div>
<img src="https://www.gravatar.com/avatar/2cd48a51689add31036ce202cc020255?s=32&d=identicon&r=PG&f=1">
</div>
<div>
<img src="https://www.gravatar.com/avatar/760b4da77fd54d37c104029ff1f56749?s=32&d=identicon&r=PG">
</div>
<div>
<img src="https://www.gravatar.com/avatar/ca3e484c121268e4c8302616b2395eb9?s=32&d=identicon&r=PG">
</div>
<div>
No image in this one, so you can see it handle clicks
</div>
Side note: Although you can use onClick in your HTML, when you're using it in JavaScript, it has to be onclick (all lower case). I've made that change above in the version that still used it.
I'd like to do this with javascript. I'm building a presentation using Hakim El Hattab's Reveal.js as a foundation.
The way Reveal.js works is the current slide you are viewing has a class of .present, any previous slides have a class of .past, and any slides yet to come into view have a class of .future.
I would like it to automatically pause any video that is inside a slide set to .past or .future.
How should I go about this?
Thanks in advance!
************UPDATE**************
so thanks to some direction i got over on the css-tricks forums i was able to get it working on a single video using getElementById.
below is the javascript i'm using to add the .past and .future classes and simultaneously pause a video.
if( i < index ) {
// Any element previous to index is given the 'past' class
slide.setAttribute('class', 'past');
document.getElementById('vid').pause();
}
else if( i > index ) {
// Any element subsequent to index is given the 'future' class
slide.setAttribute('class', 'future');
document.getElementById('vid').pause();
}
the issue that i'm having now is how would i apply it to a tag name (ie: video) or possibly a class.
Now that you posted your code, it makes it easier to fix:
if( i < index ) {
// Any element previous to index is given the 'past' class
slide.setAttribute('class', 'past');
var vids = document.getElementsByClassName("past");
for (var i = 0; i < vids.length; i++) {
vids[i].pause();
}
}
else if( i > index ) {
// Any element subsequent to index is given the 'future' class
slide.setAttribute('class', 'future');
var vids = document.getElementsByClassName("future");
for (var i = 0; i < vids.length; i++) {
vids[i].pause();
}
}
See if that helps. If it doesn't, are you using a modern and standards-compliant browser? getElementsByClassName() is a relatively new feature. It works in the latest version of Chrome for me.
I don't know if setTimeout would work here but you could try the following:
function PauseVids() {
var vids = document.getElementsByClassName("past");
var vids2 = document.getElementsByClassName("future");
for (var i = 0; i < vids.length; i++) {
vids[i].pause();
}
for (var i = 0; i < vids2.length; i++) {
vids2[i].pause();
}
}
// Within onLoad or $(document).ready()
setTimeout("PauseVids()", 1000);
Tell me if that works.
#petschekr :guess this won't work, because classname past future is not only set to videoelements?!
i have no idea how reveals work and what kind of player you are using! but my way would be sth like:
there is only one file with the present class, right (current Slide)
a) define sth like a onChange function (for example on every button which changes pages + keypresses)
b) trigger that function before you switch pages
function onChange(){
var currentSlice = document.getElementByClassName('present') //get current html elemen
var videoObjects = currentSlice.getElementsByTag('video') //get videoelements here html5 video
for each videoObj
videoObj.pause()
edit: pseudocode to get you an idea!