changing audio track when a certain dom element enters viewport - javascript

Here is a codepen that illustrates changing music depending on what is showing in the viewport:
http://codepen.io/littleredbowtie/pen/epONpM
One song is triggered by an element at the top and a different song is triggered when you scroll to the bottom. However, If you scroll from top to the middle and then back up to the top, the first song starts over. Since it is the SAME DOM element coming into the viewport, I do not want to reset the music. I have tried using a variable to track the most recently viewed trigger , for example:
var oldInview = "";
and only to change the music if it's different. But as you can see from the codepen, it doesn't work. What is a recommended solution?

Rather than wrap your $('p.inview1').bind(...) in an if, add && oldInview !== 'view1' to your if (visible). This makes sure nothing is called again if oldInvew === 'view1' despite the event being fired and detected.
$('p.inview1').on('inview', function (event, visible) {
if (visible && oldInview !== "view1"){
$(this).text('Yay! You can see me1!');
myFunctionT1();
oldInview = "view1";
} else {
$(this).text('Hidden again. Muhahah!');
myFunctionP1();
}
});

Related

Getting a href source within the iframe [duplicate]

I got a warning by my ad system provider about click fraud. No further info, all they are recommending is "hide the ads for users who click on ads too quickly'". I wrote a piece of JS script that hides all DIVs with ads for N seconds (using cookie) when clicked on, but this solution does not work as the "inner" content (with ads) is generated by an JS script that calls and renders the content from external server (as you would expect from an ad system). So, when one takes the cross-domain security into account it is kinda Catch 22. How can I detect a click inside a DIV (locally defined) of which content is rendered by an external JS and in iframe?
Example:
<div class="ad-class"> <!-- locally defined div -->
<div id="my-id"> </div> <!-- identifies my ad in the provider's system -->
<script>
var foo = blah // declares the ad dimensions and stuff
// and renders the contextual ad in #my-id DIV
</script>
</div>
Were it all local, solution would be easy as the internal div would inherit the parent class ("ad-class"). In case of cross-domain, this is not valid. Any tips, dudes?
You cannot detect click events in cross-domain iframe.
That put, you might have one bad option:
One of the nearest things you can do is detect that the focus moved from your window to the iframe:
window.focus(); //force focus on the currenct window;
window.addEventListener('blur', function(e){
if(document.activeElement == document.querySelector('iframe'))
{
alert('Focus Left Current Window and Moved to Iframe / Possible click!');
}
});
http://jsfiddle.net/wk1yv6q3/
However it's not reliable, loose focus does not mean a click, it could be user moving across the website using TAB.
Another problem is that, you only detect the first time focus is moved to the iframe, you do not know what user does in there, he can click a million times and you will never know.
Luizgrs inspired me this solution :
var clickIframe = window.setInterval(checkFocus, 100);
var i = 0;
function checkFocus() {
if(document.activeElement == document.getElementById("ifr")) {
console.log("clicked "+(i++));
window.focus();
}
}
<!DOCTYPE html>
<h2>Onclick event on iframe</h2>
<iframe src="https://www.brokenbrowser.com/" id="ifr"></iframe>
The function detect if the iframe has the focus, if yes, the user clicked into the iframe. We then give back the focus to our main windows, which allow us to find if the user click another time.
This trick has been usefull to me for a POC on a 2 step iframe click-jacking. Getting to know when the user clicked for the first time on the iframe allowed me to reorganize my different layers to keep the illusion perfect.
The approach #Luizgrs pointed out is very accurate, however I managed to indeed detect the click event using a variation of the method:
var iframeMouseOver = false;
$("YOUR_CONTAINER_ID")
.off("mouseover.iframe").on("mouseover.iframe", function() {
iframeMouseOver = true;
})
.off("mouseout.iframe").on("mouseout.iframe", function() {
iframeMouseOver = false;
});
$(window).off("blur.iframe").on("blur.iframe", function() {
if(iframeMouseOver){
$j("#os_top").click();
}
});
The above code works like a charm on desktop if you want to add mobile support you just need to use touch events touchstartand touchendevents to simulate the mouseover on mobile.
Source
Well, a while ago I found this plugin for WordPress. Obviously it does what I need -- just wondering how this guy made it to work, it does count clicks on Adsense iframe. I must have a closer look though I am not a PHP programmer. I program mainly in Python and need some solution of this kind for Django. If anyone can read the code easily, I would appreciate any help.
The plugin is searching first for any iframe wrapped by a previous specified class name.
The iframe id´s will be collected in a array and for everyone of these id´s an mouseover event will be created which fires the script which hides the class 'cfmonitor'. As a result the iframe containing ad is not visible anymore.
// IFRAME ACTION
function iframeAction () {
jq.each(jq.cfmonitor.iframes, function(index,element) {
frameID = jq(element).attr('id') || false;
if (frameID) initiateIframe(frameID);
//alert (frameID);
});
}
// INIT IFRAME
function initiateIframe(elementID) {
var element = document.getElementById(elementID);
// MOUSE IN && OUT
if (element) {
element.onmouseover = processMouseOver;
element.onmouseout = processMouseOut;
//console.log("mouse on out");
}
// CLICKS
if (typeof window.attachEvent !== 'undefined') {
top.attachEvent('onblur', processIFrameClick);
}
else if (typeof window.addEventListener !== 'undefined') {
top.addEventListener('blur', processIFrameClick, false);
}
}
// IFRAME CLICKS
function processIFrameClick() {
// ADD A CLICK
if(isOverIFrame) {
//addClick();
// Some logic here to hide the class 'cfmonitor'
//console.log("Go");
top.focus();
}
}
Check this it might help. You can not detect the click event when its cross browser.
window.focus();
window.addEventListener('blur', function(e){
if(document.activeElement == document.getElementById('Your iframe id'))
{
console.log('iframe click!');
}
});

Media play/pause toggling without using too many if statements?

I am creating a playlist of songs for a website that looks like this:
However, I am struggling to figure out the proper way to implement all of the possible case statements that a user may go through while toggling the buttons such as:
toggling one play button on and off
toggling one play button on, and then clicking another play button so that the previous has to toggle off
and so on.
Right now my code (below) works for every case EXCEPT for when a user toggles a play button on and off, and then clicks a different play button. This specific case causes both of the icons to toggle to the pause button instead of just the most recently clicked. I know why this happens, it is because an ID of lastPlayed is left on the old play button, thus triggering the toggle if statment.
My question is, is there an easier way to set up play button toggling that covers all of these cases without having to make a specific if statement for every possible outcome?
Either finding a better solution or fixing my one bug works, but cleaner code is always preferred, thanks for any help!
var playCounter = 0;
function clickSongPlay(artist, title, url, imageURL, element) {
//debugger;
player.playlist.push(
{
title: title,
artist: artist,
file: url,
imageURL: imageURL,
howl: null
}
);
//check to see if we need to resume the song
if ($(element).hasClass("resumeSong") && $(".music-control").hasClass("ion-ios-play")) {
console.log("resuming");
/////////LINE BELOW RESUMES THE TRACK FROM CURRENT POSITION////////
player.play();
$(element).toggleClass("ion-ios-play ion-ios-pause");
$(".resumeSong").removeClass("resumeSong");
return;
}
//if a song is playing and the pause button is clicked, pause the track
if ($(element).hasClass("ion-ios-pause")) {
console.log("pausing");
player.pause();
$(element).toggleClass("ion-ios-pause ion-ios-play");
$(element).addClass("resumeSong");
return;
}
//start playing a new song
if ($(element).hasClass("ion-ios-play") && !$(element).hasClass("resumeSong")) {
if ($("#lastPlayed") && !playCounter == 0) {
console.log("here is a new song");
$("#lastPlayed").toggleClass("ion-ios-pause ion-ios-play")
$(".music-control").removeAttr("id", "lastPlayed");
}
console.log("new song");
///////LINE BELOW LOADS THE NEW SONG//////////////
player.skipTo(player.playlist.length - 1);
$(element).toggleClass("ion-ios-play ion-ios-pause");
$(element).attr("id", "lastPlayed");
playCounter += 1;
return;
}
}
Here is the HTML for a specific song div:
<div><i class="icon ion-ios-play music-control" onclick="clickSongPlay('#song.Artist','#song.Title','#song.URL','#song.Album.ImageURL', this);"></i></div>
Well, as I can see it, there are two problems here.
One, you need to pause any song that is currently playing, whenever an element is clicked. The step that is missing from your code is the position at which we the playing song is advanced so far. I'd record this into a data-offset property of the element itself. So later, we can continue playback from where it left...
Two, find out if the clicked element is on pause or not. If it is - resume, else play from the beginning.
So here is UNTESTED code sample, which might set you on the right track:
function clickSongPlay(artist, title, url, imageURL, element) {
var nowPlaying = $(element).siblings(".ion-ios-pause")
if (nowPlaying) {
player.pause();
nowPlaying.data("offset") = player.seek();
nowPlaying.toggleClass("ion-ios-pause ion-ios-play");
nowPlaying.addClass("resumeSong");
}
player.src(url);
player.seek($(element).data("offset"));
if ($(element).hasClass("resumeSong")) {
console.log("resuming");
$(element).removeData("offset");
$(element).toggleClass("ion-ios-play ion-ios-pause");
$(element).removeClass("resumeSong");
}
player.play();
}

How to properly scroll IFrame to bottom in javascript

For a mockup-webpage used for research on interaction on websites, I created a mockup message-stream using JavaScript. This message stream is loaded in an IFrame and should show images at pre-set intervals and scroll to the bottom of the page after placing a new image at the bottom of the page. Getting the images to appear is working quite well with the provided script. However, both Chrome and IE seem to have trouble scrolling the page to the bottom. I would like to scroll to the bottom of the page as soon as the image is attached, but have for now added a 5 ms delay because that seemed to work sometimes. My questions are:
Is it okay to use document.body.scrollHeight for this purpose?
Can I make the scroll occur directly, or do I need a small interval before scrolling?
How to make the code scroll to the bottom of the IFrame directly after adding an image?
The following functions are used and trypost() is started onLoad:
function scrollToBottom(){
window.scrollBy(0,document.body.scrollHeight);
}
function trypost(){
point = point + 1;
if(point < interval.length){
//create and append a new image
var newImg = document.createElement("IMG");
newImg.src = "images/"+images[point]+".png";
document.getElementById('holder').appendChild(newImg);
//create and append a return
var br = document.createElement("br");
document.getElementById('holder').appendChild(br);
//time scroll to bottom (after an arbitrary 5 seconds)
var stb = window.setTimeout(scrollToBottom, 5);
//time next post
var nextupdate = interval[point]*400;
var tp = window.setTimeout(trypost, nextupdate);
}
}
My script section contains at least the following variables:
var point = -1;
var interval = [10, 10, 15];
var images = ["r1", "a1", "r2"];
This questions is a continuation of the project described in How to proper use setTimeout with IE?
To answer one of your questions, document.body.scrollHeight is appropriate for this purpose, but not if you're actually calling for document. That'll give you the scroll height of the document the iFrame is in, not the iFrame's document. The iFrame's document can be called upon by [insert variable for iFrame here].contentDocument.
Here's how I did it (and by that, I mean I tested it out with my own stuff to make sure it worked):
let i = document.querySelector('iframe')
i.contentWindow.scrollTo(0, i.contentDocument.body.scrollHeight);
That being said, the other answer by Thomas Urban will also work most of the time. The difference is only if your page has a really long scroll height. Most pages won't be longer than 999999 (for all I know that's impossible and that's why they chose that number), but if you have a page longer than that, the method I showed here would scroll to the bottom and the 999999 would scroll to somewhere not yet at the bottom.
Also note, if you have more than one iFrame, you're gonna want to query it in a different way than I did, like by ID.
Scrolling to bottom is always like scrolling to some ridiculously large top offset, e.g. 999999.
iframe.contentWindow.scrollTo( 0, 999999 );
In addition see this post: Scrolling an iframe with javascript?
If scrolling occurs too early it's probably due to images not being loaded yet. Thus, you will have to scroll as soon as added image has been loaded rather than on having placed it. Add
newImg.onload = function() { triggerScrolling(); };
after creating newImg, but before assigning property src.
If several events are required to trigger scrolling you might need to use some "event collector".
function getEventCollector( start, trigger ) {
return function() {
if ( --start == 0 ) { trigger(); )
};
}
You can then use it like this:
var collector = getEventCollector( 2, function() { triggerScrolling(); } );
newImg.onload = collector;
window.setTimeout( collector, 100 );
This way triggerScrolling() is invoked after 100ms at least and after image has been loaded for collector has to be invoked twice for triggerScrolling() being invoked eventually.

Calling a function or focusing a programmatically generated Iframe from an HTML5 canvas

I have an HTML5 canvas controlled and generated by a library of JavaScript files (Craftyjs library mostly).
The canvas generates 2 regular html iframes (same domain) which are stacked on top of each other.
The canvas switches between the two iframes based on calls from the iframes to the parent so I know the code controlling the canvas is easily accessed by their common parent.
I want the parent canvas to either call a function in the iframes to have them focus on a specific element in them or to somehow just have the iframes get focus in general.
I would also prefer to not have to constantly reload/recreate the iframes to get focus.
---- In the Iframe ----
//The head has a function "focusThis()" to focus on an element in the iframe
//body also has onfocus="focusThis();"
//Call the parent to change to the other iframe
parent.changeIframe();
---- In the parent's canvas JS code ----
// I know the function and will hide/show the iframe, but it won't focus
function changeIframe(){
//For now, just switch randomly
MODE = Math.floor(Math.random()*2);
//I am hiding the iframes here, then showing the one that should be seen
Crafty("Game1").each(function () {this.visible = false});
Crafty("Game2").each(function () {this.visible = false});
//Switch the iframes
if(MODE){
//Show this iframe
Crafty("iframe1").each(function () {this.visible = true});
These are things I have tried to get to work
When it doesn't throw an error it doesn't do anything in chrome or FireFox.
(Object [object global] has no method 'focusThis') is a common error
//document.getElementById('iframe1').focus();
//document.getElementById("iframe1").contentWindow.focusThis();
//document.getElementById('iframe1').contentWindow.focusThis();
//var iframe_window = window.frames["iframe1"];
//iframe_window.focus();
//iframe_window.contentDocument.body.focus();
//window.parent.document.getElementById('iframe1').contentWindow.focusThis;
//window.parent.document.getElementById('iframe1').contentWindow.focusThis();
//window.frames["iframe1"].focus();
//window.frames["iframe1"].contentWindow.focus();
//window.frames["iframe1"].contentDocument.focus();
var frame = document.getElementById("iframe1");
if(frame){
alert("yep");
frame.contentWindow.focusThis();
}
}
else{
//....Same thing but for iframe2
}
}
Any help would be greatly appreciated.
I solved my problem after some more fiddling.
This also solved my problem without having to reload the iframe.
I set a timer in the onload function of each iframe that tries to focus itself onto an element in itself based on a parent flag variable (MODE) that tells the iframe if it is supposed to have focus and an internal variable (focused) that tells it to stop trying to focus once it finally has focus again.
Somewhere in the head...
var focused = false;
function focusThis(){
if(parent.MODE && !focused){
document.getElementById("SOME_ELEMENT_I_WANT_FOCUSED").focus();
focused = true;
}
}
Somewhere in onLoad...
var autoFocus =
setInterval(function(){if(parent.MODE && !focused) focusThis()},500);
Somewhere in script below the body...
parent.changeIframe();
changeImage();
if(!parent.MODE){
//This element is just to have a place for focus to go when out of focus
document.getElementById("NA").focus();
focused = false;
}
else
focused = true;

HTML5 + Javascript audio trigger events at certain times in audio playback

I am researching setting up a script that will show certain notes along with accompanying music tracks. Basically I need certain times in the audio track to trigger events. I have seen I could use the currentTime similar to the following, but I am getting hung up on a good way to make a concise function to move between frames and move back and firth if there is a rewind etc. Help's appreciated greatly!
$("#ogg_player_1_obj").bind('timeupdate', notePosition);
function notePosition(){
myVid=document.getElementById("ogg_player_1_obj");
mct=myVid.currentTime;
//SET Frame based on time???
}
function notePosition(){
//your code.
if(frame1start <= mct && frame1end >= mct) {
$(".frame").fadeOut(100);
$("#frame1").fadeIn(100);
}
//and again for every frame.
}
This works if you put every frame in a seperate element with class frame and the id frame + number.

Categories

Resources