Take a look at this code. It actually loads the video perfectly, but it doesn't fire onPlayerStateChange when pausing, loading, or playing the video.
I've already implemented a function to print any new video status, but it doesn't even report events.
Why isn't the onPlayerStateChange firing?
Code from JSBin:
<body>
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
google.load("swfobject", "2.1");
</script>
<script>
function onYouTubePlayerReady(playerId) {
var myplayer = document.getElementById("myplayer");
myplayer.cueVideoById("pGBMFxN_eys",0, "default");
myplayer.addEventListener("onStateChange", onPlayerStateChange);
}
function onPlayerStateChange(newState){
log(newstate);
}
function log(text){
document.getElementById('logarea').innerHTML+=text+"<br/>";
console.log(text);
}
function setup(){
var params = { allowScriptAccess: "always",wmode:"transparent" };
var atts = { id: "myplayer" };
swfobject.embedSWF("http://www.youtube.com/apiplayer?" +
"&enablejsapi=1&playerapiid=mojplayer",
"greatvideo", "400", "300", "8", null, null, params, atts);
}
google.setOnLoadCallback(setup);
</script>
<div id="logarea">
</div>
<div id="greatvideo">
</div>
</body>
There are two bugs in your code that are preventing this from working. Once you make these changes, you'll see the following output above your YouTube video:
5
3
1
0
The bugs are as follows:
Use quotes around callback, or use an anonymous function:
// put callback in quotes or anonymous function
myplayer.addEventListener("onStateChange", "onPlayerStateChange");
Make sure parameter matches local variable passed to log function:
function onPlayerStateChange(newState){
log(newState); // variables are case sensitive
}
NOTE: addEventListener may not work in IE browsers. I'm running Ubuntu and don't have IE available, but you may need to use browser detection to use attachEvent in IE browsers. This was tested on Chrome 8.0.
I also signed up for a jsapi key. The documentation was unclear as one google page said the API Key was required to use Google Loader, while the API page itself said it was not required. You may not need to obtain a key, but if you still have trouble after making the above changes, I would suggest you obtain a key to rule out this variable in the equation.
http://code.google.com/apis/loader/signup.html
Resources:
YouTube Adding Event Listeners
YouTube EventListener Player Demo
UPDATE: This works in Chrome 8.0, Firefox 3.6, and IE8. It does not work in IE7. But instead of wasting energy on a dead browser, do the community a favor and redirect those small subset of users to an upgrade link so they can join the year 2011. :) The IE7 build I used is part of IECollections and is not the real IE7.
If you have a subset of users who, for whatever reason, are tied to older versions of IE7, and you wish to support these users, please see javascript addEventListener onStateChange not working in IE
Related
I use adobe analytics and try to track links using this:
$(document).on('click', 'a', function() {
s.tl(this, 'e', 'link', null, 'navigate');
return false;
});
or
$("a").click(function() {
s.tl(this, 'e', 'link', null, 'navigate');
return false;
});
and when I tested it and click in a link in Chrome I receive for the first the status page canceled and using the second option in chrome everything works fine but in Firefox I receive status 0 GET (NS_BINDING_ABORTED).
Is there any workaround which could run without problem in all browsers or should I fix anything to the previous?
From here is the example I use using the second box as example
I found this solution:
https://marketing.adobe.com/developer/es/forum/general-topic-forum/custom-link-tracking-capturing-issue
Which proposes this as a work around:
<script language="javascript">
function pejTracking(linkname,url) {
var s=s_gi('myprodsuite');
s.tl(this,'o',linkname,null,navigate(url));
}
function navigate(url) {
window.location=url;
}
</script>
This really works!
Is it possible to make it to work with the JQuery document or a onclick function as I have at the start of my post and there is any need to have the onclick in every link?
This is common, and (probably) isn't a problem.
This error occurs because the link tracking image request is designed to let the browser proceed to the next page before waiting for a response from the Adobe data collection servers.
Adobe Reference: NS_Binding_Aborted in Packet Monitors
Update:
You commented:
Yes I have seen this but is it possible to fix it?
You are asking to "fix" this as if it's something that is broken.. my point is that it's not broken.
But if you insist on wanting to make sure this doesn't show up, you will need to do the solution you already posted in your question.
The jQuery equivalent would be to make use of event.preventDefault() and then update window.location after the s.tl call (in navigate callback) same as the non-jQuery solution.
You also asked:
And what about chrome?
What about it? This isn't browser-specific. It has to do with timing. Try it enough times in Chrome and you should see that NS_Binding_Aborted error in Chrome, too. Maybe. Depends on connection speed, current CPU resources, internet traffic in general, how the stars are aligned, etc. - you know, all the things that make requests and response happen later rather than sooner.
I'm trying to use a facebook UI request dialog for selecting a friend. This works absolutely fine in safari and Chrome but in firefox and IE11 (Not tested lower versions yet) it continuously hangs with the loading animation.
function pickFriend(ev)
{
FB.ui(
{
method: "apprequests",
message: "Choose a friend.",
max_recipients: 1,
title:"Invite a friend"
},sendMessage);
ev.preventDefault();
}
$("#element").click(pickFriend);
I then tried calling the function directly in the console to ensure that it wasn't my implementation that was the problem, and i got the same result with it hanging with the loading animation. I then tried different display options and i can get it too work in popup mode but for me this is not very elegant and i would far prefer it to work in iframe mode the same way it does in safari and chrome.
Has anyone else been experiencing this issue? If so is there a reason for this and is ther a fix?
I'm thinking that this maybe something that is entirely down to facebook to fix which would leave no other option but to run in popup mode if i want to keep browser compatibility.
In IE11 (and node) the javascript engine can get hung up on long operations. The recommended work around is utilizing "setImmediate", so for your example:
function pickFriend(ev)
{
ev.preventDefault();
setImmediate(FB.ui
, {
method: "apprequests",
message: "Choose a friend.",
max_recipients: 1,
title:"Invite a friend"
}
, sendMessage
);
}
$("#element").click(pickFriend);
Also, make sure your "sendMessage" variable is scoped properly and not undefined or null.
Syntax
var immediateID = setImmediate(func, [param1, param2, ...]);
var immediateID = setImmediate(func);
Reference:
https://developer.mozilla.org/en-US/docs/Web/API/Window.setImmediate
I am aware of two ways of calling the "print" dialog of browser (I used the Search, of course):
document.print()
document.execCommand('print', false, null)
What is the difference between them? Support across browsers? Papers, docs or standards? Which is more correct thing to use?
Another question: what is the most straight way to print given part of a webpage? I know we can create new window or iframe to call any of two print methods above. Which one has less pitfalls?
I've tested different ways of printing part of webpage across browsers:
Chrome, Firefox, Opera (12 and new), IE11, 10, 9 and 8. I've tried to create new window, new iframe, or use existing iframe on the page. And then tried .print() and .execCommand('print').
Note: Keep in mind that .print() is called on window, and .execCommand() is called on document.
Code used for testing can be found here
Correct me if my testing code is wrong, I just wanted to find the clearest way to do the job. My conclusions:
Opera 12 can not print part of a webpage (?)
IEs don't print() iframes and windows, except current window.
Calling print() on documents inside iframes or created windows in IEs breaks the print() on current document. Be careful!
jQuery plugin printThis uses tricks for IE to do the job, and it just works. The only exception is Opera 12. By the way, this plugin uses print().
execCommand('print') works almost everywhere and with any approach (iframes, window). It's not supported by Firefox though.
execCommand() returns false if call was unsuccessful, so if you don't want to use plugins and magic tricks, create window or iframe, call execCommand('print') and if it returns false, call print().
One more thing:
Creating an iframe is tricky: you can't access its window or document directly (yes, you have ContentDocument property, which behaves differently across browsers). You should name it and then call window.frames[name] to get window object from that iframe. Do not try to call window.frames(id) - it will return the iframe.
That last method mentioned in the accepted answer, then, ends up looking like this:
iframe = document.getElementById('iframe-id');
var printed = iframe.contentWindow.document.execCommand('print', false, null);
if (!printed) window.print();
alternative:
try {
iframe = document.getElementById('iframe-id');
iframe.contentWindow.document.execCommand('print', false, null);
}
catch(e) {
window.print();
}
similar method used by printThis
if (document.queryCommandSupported("print")) {
$iframe[0].contentWindow.print();
$iframe[0].contentWindow.document.execCommand("print", false, null);
} else {
$iframe[0].contentWindow.focus();
$iframe[0].contentWindow.print();
}
You can use the combination of window.open and execComand (saveas
exemple:
<script type= "text/javascript">
function saveas() {
var oPrntWin = window.open("","_blank","width=1,height=1,left=1,top=1,menubar=yes,toolbar=yes,resizable=yes,location=no,scrollbars=yes");
oPrntWin.document.open();
oPrntWin.document.write(editeur.innerHTML);
oPrntWin .document.execCommand("SaveAs",true,"C:\\My Documents\\Saved Content.html");
oPrntWin.document.close();
}
</script>
editeur.html is a part of my document
you can do same for your frame
replace the writting in a new Window by the property "src" for the body
I'm looking for a neat way to detect whether postMessage in the browser supports the sending and receiving of objects or just strings. I figure that someone out there must have wrote something that does this but I have not managed to find a solution.
I'm using postMessage to send data to/from a WebWorker. Whilst detecting whether the browser supports workers is straight-forward, detecting whether objects can be send via postMessage has proved more difficult.
I'd like to write a simple detection function. So, if the browser supports the sending of objects to use that. If only strings are allowed I can fallback to using JSON.stringify(). I'll probably assign the function to a dojo/has test (although this is not relevant to the question/answer).
What have other people done to solve this problem? Any advice would be great, I'm new to both WebWorkers and postMessage. Thanks in advance.
I found an even easier way to detect if postMessage only supports strings or if it supports other types. Simply add a custom toString-method on the object. When trying to send an object with postMessage in IE8 and IE9 they will be converted to a string with the toString-method on the object. Since browsers that support sending objects doesn't call toString we can use this to our advantage. This test is not async, so you'll get the result instantly. Haven't tested this with web-workers, but I suppose you can use the same technique.
var onlyStrings = false;
try{window.postMessage({toString:function(){onlyStrings=true;}},"*");}catch(e){}
console.log("Browser only supports postMessage with strings? " + onlyStrings);
Tested in IE8, IE9, IE10 and latest version of Chrome, Firefox, Safari and Opera:
http://jsbin.com/igowoFaj/1/edit?js,console
Update: Did a BrowserScope test with many more tests and browsers. Conclusion is that it's safe to send clonable objects, arrays, numbers, pixel data and array buffers if onlyStrings is false. In theory all browsers that allow sending objects should use the structured clone algorithm, but the Android browser and Opera Mobile has quirks. The BrowserScope test result is a bit hard to read, because a 0 for send_xxx is only problematic if the browser actually has support for that type, so check supports_xxx too. If they are equal it's ok, but it's a bug if the browser has support but can't send (when onlyStrings is false).
You could try to perform an action BEFORE resuming your script. You could try this:
dummy_task.js
self.onmessage = function(event) {
self.postMessage(event.data);
};
javascript
workerSupportObject(callback);
function workerSupportObject(callback) {
var callbackIsCalled = false; // to make sure callback isn't run twice
var worker = new Worker('dummy_task.js'); // create a worker
// create event
worker.onmessage = function(event) {
// if the value is the same as we sent, it probably works
if(!callbackIsCalled) callback.call(null, event.data.value === 'dummy');
callbackIsCalled = true;
};
try {
// send dummy JSON data
worker.postMessage({'value': 'dummy'});
} catch(e) {
// oh... an error... clearly that's a no.
if(!callbackIsCalled) callback(null, false);
callbackIsCalled = true;
}
}
function callback(objectSupported) {
console.log('Worker supports objects: ', objectSupported);
}
I wanted to know the same thing. I created this script to detect if an object could be passed in postMessage by a simple callback to the current window. You will see IE 9 return false, IE 10 returns true.
http://jsfiddle.net/milesplit/DvqqH/
var supportsPostObject = false;
(function(){
var callback = function(e) {
supportsPostObject = (typeof(e.data)!='string');
};
(window.addEventListener) ?
window.addEventListener('message', callback) :
window.attachEvent('onmessage', callback);
('postMessage' in window) && window.postMessage({}, '*');
})();
setTimeout(function(){
alert(supportsPostObject);
}, 0);
postMessage also works between iframes; assuming that the behavior is the same between workers and frames, you should try the following or something like it:
<html>
<body>
<iframe id='if'>
</iframe>
<script>
var iframe = document.getElementById('if');
var iframeScript = iframe.contentDocument.createElement("script");
iframeScript.appendChild(
iframe.contentDocument.createTextNode(
'window.addEventListener("message", function(e) {console.log(e.data);}); console.log("listener attached");'));
iframe.contentDocument.body.appendChild(iframeScript);
iframe.contentWindow.postMessage("asdf", "*");
iframe.contentWindow.postMessage({'whatAmI': 'an object, maybe?'}, "*");
</script>
</body>
</html>
You may need to replace console or console.log to be able to see results, but on Chrome, this gets me
listener attached about:blank (1):1
asdf about:blank (1):1
Object {whatAmI: "an object, maybe?"} about:blank (1):1
when I save it to a local file and open it up.
The jsfiddle version (and the version which uses an actual worker) are left as an exercise for the reader. :)
My simple ActionScript
I am trying to use Flash's ExternalInterface to setup a callback so that JavaScript can call a method on my Flash object. Everything works fine in Safari, Firefox and in IE, but I cannot get Chrome working. When I try the code on Chrome, I get the following error:
Uncaught TypeError: Object #<an
HTMLObjectElement> has no method
'setText'
Here is the example HTML I am using (again, works fine in Safari, FF and IE)
<html><body>
<div id="mycontent"></div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<script type="text/javascript">
swfobject.embedSWF("http://invincible.dynalias.com:8080/HelloWorld.swf", "mycontent", "400", "420", "9.0.0","expressInstall.swf", {}, {allowScriptAccess:'always'},{id:'hw',name:'hw'});
function getFlash(movieName) {
return ( navigator.appName.indexOf("Microsoft") != -1) ? window[movieName] : document.getElementById(movieName);
}
</script><p>
<input type="text" id="exampleText" /> <input type="button" value="Set Text" onclick="getFlash('hw').setText(document.getElementById('exampleText')
.value)" />
</body>
</html>
and here is the ActionScript...
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.external.ExternalInterface;
import flash.system.Security;
public class HelloWorld extends Sprite {
private var textField:TextField = new TextField();
public function HelloWorld() {
Security.allowDomain("*");
ExternalInterface.addCallback("setText", this.setText);
textField.text = "Hello, world!";
addChild(textField);
}
public function setText(text:String):void {
this.textField.text = text;
}
}
}
I agree with Robson that it is a race condition, but it's not in 'writing the Flash tag' and adding a timer is not a good solution - in fact its very dangerous.
The problem is that the SWF itself isn't loaded and had a chance to initialize your external interface. For a small SWF in Chrome the timing may be more sensitive than other browers, but the underlying problem isn't specific to Chrome.
What you need to do is this :
In Actionscript
Call this function from your constructor :
public function InitializeExternalInterface():void
{
if (ExternalInterface.available) {
// register actionscript functions so they can be called by JS
ExternalInterface.addCallback("activate", activate);
Security.allowDomain("www.example.com");
// send message to parent page that SWF is loaded and interface active
trace("External Interface Initialized...");
ExternalInterface.call("flashInitialized")
}
else
{
trace("ERROR: External Interface COULD NOT BE Initialized...");
}
}
In your HTML
<script>
function flashInitialized()
{
alert("Initialized!"); // remove this obviously!
$('#Main')[0].activate(); // safe to call Flash now
}
</script>
You may find on your local machine that it works without this, but as soon as you add network delays into the equation you'll regret not doing this. An arbitrary timer is a bad idea because you will still get the error on a slow connection. This method lets the page call the flash object at the earliest possible time.
Note: Using jQuery's 'on ready' pattern is NOT a solution to the problem - although at first I mistook it for one.
$(function()
{
$('#animation')[0].SetTitle("Hello");
}
Also swfobject's callbackFn is also not a solution becasue that just tells you when the tag is inserted and not when the SWF is loaded.
I got the same problem, to fire and recieve listener events between javascript and flash.
The solution was to use AC_OETags.js file from Adobe as embedd script instead of JQuery flash. (It is found in the zip file under Client Side detection, Adobe probably have it some other places as well)
The trouble based on a race condition when the flash builds the javascript callbacks in the browser. This is not handeled correctly by a straight embed for some reason.
<div>
<script>
// Major version of Flash required
var requiredMajorVersion = 10;
// Minor version of Flash required
var requiredMinorVersion = 0;
var hasRequestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision);
AC_FL_RunContent(
"src", "tagflash",
"width", "200",
"height", "200",
"id", "myTagFlash",
"quality", "high",
"bgcolor", "#FFFFFF",
"name", "myTagFlash",
"allowScriptAccess","always",
"type", "application/x-shockwave-flash",
"pluginspage", "http://www.adobe.com/go/getflashplayer",
"flashvars", "templateData=theYear:2010&theTagNumber:123"
);
</script>
</div>
Then you can do: (works in IE, FF, Safari, Crome,++)
$("#tagFlash").gotoNewFrame();
I was having problems with ExternalInterface and Firefox and Chrome and discovered that the Adobe Script was not writing the Flash tag quickly enough, so when the browser tried to find the addCallback() function it was not there at the time.
Simply putting my Javascript function that calls the Flash created addCallback() in a window.setTimeout() calling solves the problem. Delays less than 200 ms still make the problem to occur.
I didn’t have to use the solution of trying to find if the “length” attribute exists in the document[FlashId] object. Just calling “FlashEmbed = document[FlashId]” worked just fine.
After struggling a lot, I finally decided to use the official solution from Adobe:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html
Search for ExternalInterfaceExample.as.
There is a workaround to the problem by disabling Chrome built-in flash plugin:
type the chrome://plugins in the address bar of chrome.
expand the details of plugins by clicking the details on top right corner.
in the entry of "Adobe Flash Player", disabling the first one.
This is not a solution, but shows why this happens on Chrome. Chrome accompany with a built-in flash plugins, that often cause the troubles when we use the ExternalInterface of AS3, it's annoying.