Track Youtube player's states in YUI.add - events

My embed code to play Youtube video is:
<object height="356" width="425" type="application/x-shockwave-flash" id="myytplayer" data="http://www.youtube.com/v/MTf6qXn5Prw?enablejsapi=1&playerapiid=ytplayer&version=3"><param name="allowScriptAccess" value="always"></object>
I want to track Youtube player's events (play/pause/stop etc)
The following piece of code works independently
window.onYouTubePlayerReady = function(playerId){
ytplayer = document.getElementById("myytplayer");
ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
}
window.onytplayerStateChange = function (newState) {
alert("Player's new state: " + newState);
}
I am using YUI.
When I put the same in
YUI.add('module-name', function(Y) {
[some other code...]
window.onYouTubePlayerReady = function(playerId){
// console.log(playerId); console.log(ytplayer);
ytplayer = document.getElementById("myytplayer");
ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
}
window.onytplayerStateChange = function (newState) {
alert("Player's new state: " + newState);
}
},'3.4.0', {requires:'module-a', 'module-b'})
Function onytplayerStateChange works in Firefox and Safari but not in other browsers.
Then I tried YUI functions to make that working in all browsers so I did some changes
window.onYouTubePlayerReady = function(playerId){
var shinyPlayer = Y.one("#myytplayer");
shinyPlayer.on('onStateChange', function (e) {
e.preventDefault();
alert('here');
});
}
but it didn't work for me.
I don't want to place window.onytplayerStateChange outside of YUI.add('module-name', function(Y) {})
Please suggest what should I do to track Youtube player's states in all browsers.
Thanks in advance.

I made a jsFiddle to test this:
http://jsfiddle.net/2Mj6b/4/
For me it feels like addEventListener is a custom implementation of Google.
Normally the second parameter is a callback/function-pointer and no string.
If you attach a variable to the window object it gets global and is from every scope visible. So it's no problem if you define it in the YUI module.
The second problem is that you cant use the player as YUI object you have to stay on dom objects to get this work.
Oh this is a old question. Damn. But i will post this anyway. ;)

Related

SoundCloud embed widget, would like it to start on a random song each time

On this page I see many features for the widget: http://developers.soundcloud.com/docs/widget
But I don't see anything about random or shuffle. The way I have my widget on my website, the track listing is not displayed on purpose, so all that you can see is the play/pause button and the title. Gives it a minimalist and really clean look.
But I'd like it to start on a random song each time someone visits/refreshes the site. Is this possible?
Here is my code, just the standard embed:
<iframe width="100%" height="65" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F5346417&color=579ce6&auto_play=true&show_artwork=false"></iframe>
Well, I've managed to do this using JavaScript and the JS Widget API. This provides the use of Method .skip() which I set to a random number between zero and the number of tracks in my playlist. This also invokes autostart.
Here is my code :
$(document).ready(function(){
//Variable declaration
var player = SC.Widget($('iframe.sc-widget')[0]);
var randomVal;
//player initialisation
player.bind(SC.Widget.Events.READY, function() {
randomSong(player);
player.play();
});
//Set the random song
function randomSong(player) {
randomVal = Math.random() * 10;
for(i = 0; i < randomVal; i++)
{
player.next();
}
}
});
It works perfectly for me with the Google Chrome browser.
I used this example as the main source for my soundcloud player.
I just added the random function as you can see in this comment.

jQuery .load() wait till content is loaded

How to prevent jQuery $('body').load('something.php'); from changing any DOM till all the content from something.php (including images,js) is fully loaded
-Lets say some actual content is:
Hello world
And something.php content is:
image that loads for 10 seconds
20 js plugins
After firing .load() function nothing should happen, till images an js files are fully loaded, and THEN instantly change the content.
some preloader may appear, but its not subject of question.
[edit]----------------------------------------------------------------------
My solution for that was css code (css is loaded always before dom is build) that has cross-browser opacity 0.
.transparent{
-moz-opacity: 0.00;
opacity: 0.00;
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha"(Opacity=0);
filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0);
filter:alpha(opacity=0);
}
And it prevent from bad flickr of content usually but not always. Now its possible to detect somehow that content is loaded by jQuery ajax and apply some show timeout and so on. But in fact question is still open.
To make now a little more simple example for that question:
How to begin changing DOM after $('body').load('something.php') with 3000ms delay after clicking the link that fire .load('something.php') function? (Browser should start downloading instantly, but DOM changing has to be initiated later)
Use .get instead and assign the contents in the success callback:
$.get('something.php', function(result) {
$('body').html(result);
});
There are some implementation details you may have to solve yourself, but here's a rough solution:
Don't use .load() directly. It can't be changed to wait for all images to load.
Use $.get() to fetch the HTML into a variable, let's call it frag.
Use $(frag).find('img').each(fn) to find all images and dump each this.src inside a preloader.
var images = [],
$frag = $(frag),
loaded = 0;
function imageLoaded()
{
++loaded;
// reference images array here to keep it alive
if (images.ready && loaded >= images.length) {
// add $frag to the DOM
$frag.appendTo('#container');
}
}
$frag.find('img').each(function() {
var i = new Image();
i.onload = i.onerror = imageLoaded;
i.src = this.src;
images[images.length] = i;
});
// signal that images contains all image objects that we wish to monitor
images.ready = true;
Demo
Once all images are loaded, append the earlier frag to the DOM using $frag.appendTo('#container').
Here is a quick proof of concept that loads relevant images before inserting an HTML fragment into the DOM: http://jsfiddle.net/B8B6u/5/
You can preload the images using the onload handler to trigger iterations:
var images = $(frag).find('img'),
loader = $('<img/>');
function iterate(i, callback) {
if (i > 0) {
i--;
loader.unbind("load");
loader.load(function() {
iterate(i, callback);
});
loader.attr('src', images[i].src);
}else{
callback();
}
}
iterate(images.length,function(){
$('#container').html(frag);
});
This should work, since each image is loaded after the previous one has finished loading.
Have you tried this?
$(function(){$('body').load('something.php')});
Edit: I just realized you are actually wanting to wait for the stuff to load before it get's placed in the body.
Here are three links to similar questions.
Preloading images with jQuery
Is it possible to preload page contents with ajax/jquery technique?
Preloading images using PHP and jQuery - Comma seperated array?
You can probably adapt those to scripts too.
This might work too.
$.ajax({
'url': 'content.php',
'dataType': 'text',
'success': function(data){
var docfrag = document.createDocumentFragment();
var tmp = document.createElement('div'), child;
//get str from data here like: str data.str
tmp.innerHTML = str;
while(child = tmp.firstChild){
docfrag.appendChild(child);
}
$('body').append(docfrag);
}
});
It's a longer way of doing what Shadow Wizard suggests, but it will probably work.
Hm. Never mind. Jack's answer looks the best. I'll wait a while and if no one likes my answer I'll delete it.
Edit: It looks like appending to documentfragments can do http requests.
Any script using createDocumentFrament may benefit from preloading.
In this question they want no http requests even though that's what createDocumentFragment is doing:
Using documentFragment to parse HTML without sending HTTP requests.
I can't be sure if this is true for all browsers or just when the console.log is run, but it could be a good option for preloading if this behavior is universal.

jQuery — trigger a live event only once per element on the page?

Here's the scenario
$("p").live('customEvent', function (event, chkSomething){
//this particular custom event works with live
if(chkSomething){
doStuff();
// BUT only per element
// So almost like a .one(), but on an elemental basis, and .live()?
}
})
Here's some background
The custom event is from a plugin called inview
The actual issue is here http://syndex.me
In a nutshell, new tumblr posts are being infnitely scrolled via
javascript hack (the only one out there for tumblr fyi.)
The inview plugin listens for new posts to come into the viewport, if the top of an image is shown, it makes it visible.
It's kinda working, but if you check your console at http://.syndex.me check how often the event is being fired
Maybe i'm also being to fussy and this is ok? Please let me know your professional opinion. but ideally i'd like it to stop doing something i dont need anymore.
Some things I've tried that did not work:
stopPropagation
.die();
Some solutions via S.O. didnt work either eg In jQuery, is there any way to only bind a click once? or Using .one() with .live() jQuery
I'm pretty surprised as to why such an option isnt out there yet. Surely the .one() event is also needed for future elements too? #justsayin
Thanks.
Add a class to the element when the event happens, and only have the event happen on elements that don't have that class.
$("p:not(.nolive)").live(event,function(){
$(this).addClass("nolive");
dostuff();
});
Edit: Example from comments:
$("p").live(event,function(){
var $this = $(this);
if ($this.data("live")) {
return;
}
$this.data("live",true);
doStuff();
});
This one works (see fiddle):
jQuery(function($) {
$("p").live('customEvent', function(event, chkSomething) {
//this particular custom event works with live
if (chkSomething) {
doStuff();
// BUT only per element
// So almost like a .one(), but on an elemental basis, and .live()?
$(this).bind('customEvent', false);
}
});
function doStuff() {
window.alert('ran dostuff');
};
$('#content').append('<p>Here is a test</p>');
$('p').trigger('customEvent', {one: true});
$('p').trigger('customEvent', {one: true});
$('p').trigger('customEvent', {one: true});
});
This should also work for your needs, although it's not as pretty :)
$("p").live('customEvent', function (event, chkSomething){
//this particular custom event works with live
if(chkSomething && $(this).data('customEventRanAlready') != 1){
doStuff();
// BUT only per element
// So almost like a .one(), but on an elemental basis, and .live()?
$(this).data('customEventRanAlready', 1);
}
})
Like Kevin mentioned, you can accomplish this by manipulating the CSS selectors, but you actually don't have to use :not(). Here's an alternative method:
// Use an attribute selector like so. This will only select elements
// that have 'theImage' as their ONLY class. Adding another class to them
// will effectively disable the repeating calls from live()
$('div[class=theImage]').live('inview',function(event, visible, visiblePartX, visiblePartY) {
if (visiblePartY=="top") {
$(this).animate({ opacity: 1 });
$(this).addClass('nolive');
console.log("look just how many times this is firing")
}
});
I used the actual code from your site. Hope that was okay.

jQuery — a .live() > each() >.load.() finella

EDIT - URL to see the issue http://syndex.me
I am dynamically resizing images bigger than the browser to equal the size of the browser.
This was no easy feat as we had to wait for the images to load first in order to check first if the image was bigger than the window.
We got to this stage (which works):
var maxxxHeight = $(window).height();
$(".theImage").children('img').each(function() {
$(this).load( function() { // only if images can be loaded dynamically
handleImageLoad(this);
});
handleImageLoad(this);
});
function handleImageLoad(img)
{
var $img = $(img), // declare local and cache jQuery for the argument
myHeight = $img.height();
if ( myHeight > maxxxHeight ){
$img.height(maxxxHeight);
$img.next().text("Browser " + maxxxHeight + " image height " + myHeight);
};
}
The thing is, the page is an infinite scroll (I'm using this)
I know that you are not able to attach 'live' to 'each' as 'live' deals with events, and 'each' is not an event.
I've looked at things like the livequery plugin and using the ajaxComplete function.
With livequery i changed
$(".theImage").children('img').each(function() {
to
$(".theImage").children('img').livequery(function(){
But that didnt work.
ajaxComplete seemed to do nothing so i'm guessing the inifinte scroll i'm using is not ajax based. (surely it is though?)
Thanks
Use delegate:
$(".theImage").delegate('img', function() {
$(this).load( function() { // only if images can be loaded dynamically
handleImageLoad(this);
});
handleImageLoad(this);
});
The problem is that your infinite scroll plugin does not provide the callback functionality. Once your pictures are loaded there is no way to affect them.
I have tried to modify your plugin, so that it will serve your needs, please see http://jsfiddle.net/R8yLZ/
Scroll down the JS section till you see a bunch of comments.
This looks really complicated, and I probably don't get it at all, but I'll try anyway :-)
$("img", ".theImage").bind("load", function() {
var winH = $(window).height();
var imgH = $(this).height();
if (winH < imgH) {
$(this).height(winH);
$(this).next().text("Browser " + winH + " image height " + imgH);
}
});

Firefox logs invalid URL?

I'm writing an extension for firefox. Using dom.location to keep track of visited search results pages, i'm getting this url http://www.google.com/search?hl=en&source=hp&q=hi&aq=f&aqi=&oq=&fp=642c18fb4411ca2e . If you click it, the google search results for "hi" should come up. You'll know that from the title bar - because the rest of the page won't load. This happens with any google search. Oddly enough, if you cut part of it off, so say, http://www.google.com/search?hl=en&source=hp&q=hi - it works! But Googling "hi" myself does give me a longish URL - http://www.google.com/#hl=en&source=hp&q=hi&aq=f&aqi=&oq=&fp=db658cc5049dc510 . I know for a fact that the first time that URL was visited, the page loaded, I did it myself.
Can anyone make reason out of this?
I just tried my experiment again, this time saving the original URL in the location bar. It turns out, dom.location.href is giving a different value. How is this happening?
Original:
http://www.google.com/#hl=en&source=hp&q=hi&aq=f&aqi=&oq=&fp=642c18fb4411ca2e
dom.location.href
http://www.google.com/search?hl=en&source=hp&q=hi&aq=f&aqi=&oq=&fp=642c18fb4411ca2e
window.addEventListener("load", function() { myExtension.init(); }, false);
var myExtension = {
init: function() {
var appcontent = document.getElementById("appcontent"); // browser
if(appcontent)
appcontent.addEventListener("DOMContentLoaded", myExtension.onPageLoad, true);
var messagepane = document.getElementById("messagepane"); // mail
if(messagepane)
messagepane.addEventListener("load", function () { myExtension.onPageLoad(); }, true);
},
onPageLoad: function(aEvent) {
var doc = aEvent.originalTarget; // doc is document that triggered "onload" event
// do something with the loaded page.
// doc.location is a Location object (see below for a link).
// You can use it to make your code executed on certain pages only.
var url = doc.location.href;
if (url.match(/(?:p|q)(?:=)([^%]*)/)) {alert("MATCH" + url);resultsPages.push(url);} else {alert(url);
}
}
This snippet comes directly from Mozilla with the matching and alerts my own. I apologize for not posting the code earlier.
Well, on the "right" page http://www.google.com/#hl=en&source=hp&q=hi&aq=f&aqi=&oq=&fp=1&cad=b there seems to be a frame with the "wrong" location: frames[0].location == "http://www.google.com/search?hl=en&source=hp&q=hi&aq=f&aqi=&oq=&fp=1&cad=b". You're probably getting the inner frame's location. I have no idea why, since you didn't post any of your code and just mention some "dom.location", which I never heard of.

Resources