Help making userscript work in chrome - javascript

I've written a userscript for Gmail : Pimp.my.Gmail & i'd like it to be compatible with Google Chrome too.
Now i have tried a couple of things, to the best of my Javascript knowledge (which is very weak) & have been successful up-to a certain extent, though im not sure if it's the right way.
Here's what i tried, to make it work in Chrome:
The very first thing i found is that contentWindow.document doesn't work in chrome, so i tried contentDocument, which works.
BUT i noticed one thing, checking the console messages in Firefox and Chrome, i saw that the script gets executed multiple times in Firefox whereas in Chrome it just executes once!
So i had to abandon the window.addEventListener('load', init, false); line and replace it with window.setTimeout(init, 5000); and i'm not sure if this is a good idea.
The other thing i tried is keeping the window.addEventListener('load', init, false); line and using window.setTimeout(init, 1000); inside init() in case the canvasframe is not found.
So please do lemme know what would be the best way to make this script cross-browser compatible.
Oh and im all ears for making this script better/efficient code wise (which im sure is possible)
edit: no help...? :'(
edit 28-Apr:
i re-wrote the code a little and now it looks something like this.:
if(document.location != top.location) return;
(function() {
var interval = window.setInterval(waitforiframe, 3000);
var canvas;
function waitforiframe() {
console.log("Finding canvas frame");
canvas = document.getElementById("canvas_frame");
if (canvas && canvas.contentDocument) {
console.log("Found canvas frame");
pimpmygmail();
}
}
function pimpmygmail() {
gmail = canvas.contentDocument;
if(!gmail) return;
window.clearInterval(interval);
console.log("Lets PIMP.MY.GMAIL!!!");
......rest of the code......
})();
This works perfectly fine in Firefox, but in Chrome, it gives me a top is undefined error.
Another thing i noticed is that if i remove the first line if(document.location != top.location) return; , the waitforiframe() method keeps getting called over and over again. (ie i see the "Finding canvas frame" error in the console)
can someone tell me what does the first line do? i mean what does it achieve & why does the waitforiframe() method run forever if i remove that line??

A BIG THANK YOU TO ALL WHO HELPED! -_- meh
btw, this was all i needed at the beginning of the script:
try { if(top.location.href != window.location.href) { return; } }
catch(e) { return; }

Related

Firefox returns TypeError: document.getElementById(...) is null but Chrome works fine

I've seen a lot of questions about this and I think I scanned through almost all of them but haven't found a solution for my problem yet.
As I mention in the title, Firefox (and IE) return this exception TypeError: document.getElementById(...) is null while Chrome and Safari work just fine.
I have the code online which you can check out here: http://178.62.244.224/ (the site's in Portuguese but that's not relevant for this issue).
The problem: when clicking on one of the refinements on the left side, Chrome behaves as expected and toggles the checkbox while loading new content through Ajax. When doing it in Firefox, the checkbox doesn't toggle (but the ajax call works because content changes) and the aforementioned exception shows up in the console.
The code it points to is in script.js (http://178.62.244.224/static/script.js) in this function in the getElementById line:
function toggleAllFilters(filters) {
for (i = 0; i < filters.length; i++){
var filter = filters[i];
document.getElementById(filter).checked = true;
}
};
This function is called in getFilters() in an ajax call:
$.get(url, function (response) {
document.open();
document.write(response);
document.close();
toggleAllFilters(filters);
});
As pointed in other similar questions, this seems to have to do with the fact that when doing document.getElementById the page might not be fully loaded yet and the element isn't found. For that reason I already moved script.js to the end of the page right before </body> but this had no effect.
It's clear that Firefox/IE interpret this in a different way but I really can't find out in what way. Any ideas?
Wrap the selector in quotes.
getElementById('filter')
What you have above is looking for a variable pointer, not an actual DOM element.

Youtube Javascript API: not working in IE

I have an embedded Youtube video, and I want to capture events when the user pauses the video, skips around, etc. Following the examples at Google's documentation (http://developers.google.com/youtube/js_api_reference), I do the following:
var video = (my video ID here);
var params = { allowScriptAccess: "always" };
var atts = { id: "youtubeplayer" };
var x = 854;
var y = 480;
swfobject.embedSWF("http://www.youtube.com/v/" + video + "?enablejsapi=1&playerapiid=ytplayer&version=3", "bobina", x, y, "8", null, null, params, atts);
function onYouTubePlayerReady(playerId) {
youtubeplayer = document.getElementById('youtubeplayer');
youtubeplayer.addEventListener("onStateChange", "onytplayerStateChange");
youtubeplayer.setPlaybackQuality('large');
}
function onytplayerStateChange(newState) {
//Make it autoplay on page load
if (newState == -1) {
youtubeplayer.playVideo();
}
var tiempo=youtubeplayer.getCurrentTime();
//Rounds to 2 decimals
var tiempo = Math.round(tiempo*100)/100;
alert(tiempo);
}
Now, all this works perfectly in Firefox and Safari, but there's no way to make it work in IE8 (by which I mean: the video loads, but events aren't captured: the event handler never gets called). According to javascript addEventListener onStateChange not working in IE , IE doesn't support addEventListener(), so I tried replacing that line with:
youtubeplayer.attachEvent("onStateChange", onytplayerStateChange);
But it doesn't work either. (The author of that question says that he finally solved it by putting "onComplete in my colorbox and put the swfobject in that", but I'm not using a colorbox here (I don't even know what that is), so I don't understand what he means.
Using alerts() to debug, I see that the first function (onYoutubePlayerReady()) is indeed called, but I can't even tell whether the event listener isn't being registered or whether it's the getElementById() that isn't working; I tried debugging by adding a:
alert(typeof youtubeplayer);
Right after it, but it doesn't even pop up.
Oh, and one more thing: the video starts automatically in Firefox and Safari, but in IE it doesn't either. (And yes, I'm running this on a server, not on a local page).
Anyone has any ideas? I don't really know what else to try.
Okay, found the solution. Guess what it was? Just write is as:
var youtubeplayer = document.getElementById('youtubeplayer');
And it works perfectly in IE 8. All it needed was the "var" keyword.
Just in case it's useful for someone else with the same problem...

Google Music Beta: Thumbs Up and Down Now Playing using Javascript

I am working on my first extension for Google Chrome. I want to be able to hit the "Thumbs Up" button on the Google Music Beta page using my extension. For some reason, the thumbs up button seems to be much more complicated than shuffle, repeat, play, next, and previous. For all of those, the following code works:
chrome.tabs.executeScript(tab_id,
{
code: "location.assign('javascript:SJBpost(\"" + command +
"\");void 0');",
allFrames: true
});
where command="playPause", "nextSong", "prevSong", "toggleShuffle", "togglePlay", etc.
I figured a lot of those out using the developer tools to follow the stack trace and see the arguments given to SJBpost. Trying SJBpost with "thumbsUp" returns an error.
Obviously this question is going to be restricted to a smaller crowd since not everyone is going to be able to view the source of Google Music, but if you can help me out, I would greatly appreciate it.
The div for the thumbs up on the Google Music page looks like this:
<div id="thumbsUpPlayer" class="thumbsUp" title="Thumbs up"></div>
Now, I've tried doing this using jQuery:
$("#thumbsUpPlayer").click()
But I get TypeError, undefined_method message in the javascript console.
Any help would be greatly appreciated. I am a huge beginner to javascript and plugins, and all of this stuff, and I'm really excited to get these last pieces of the extension together.
Thank you!
It seems that Google Music Beta doesn't actually listen on the click() event per se, rather, it is based on the events which usually precede the actual click event: mouseover, mousedown and mouseup.
I'm not a jQuery expert, so I can't exactly figure out why $("#thumbsUpPlayer").mouseover().mousedown().mouseup() doesn't work (neither does doing .trigger).
Anyway, here's some (tested on June 21) working javascript code (no dependencies).
function triggerMouseEvent(element, eventname){
var event = document.createEvent('MouseEvents');
event.initMouseEvent(eventname, true, true, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, element);
element.dispatchEvent(event);
}
function replicateClick(element){
triggerMouseEvent(element, 'mouseover');
triggerMouseEvent(element, 'mousedown');
triggerMouseEvent(element, 'mouseup');
}
function thumbsUp(){
replicateClick(document.getElementById('thumbsUpPlayer'));
}
function thumbsDown(){
replicateClick(document.getElementById('thumbsDownPlayer'));
}
It should be probably fairly easy to use, just call thumbsUp() if you want a thumbs up or call thumbsDown() if you want to thumbs down.
I've been looking into this today and found that you can trigger a lot of the commands using SJBpost from the console.
http://hints.macworld.com/article.php?story=20110622061755509
SJBpost('thumbsUpPlayer');
Commands I've tried and can confirm working:
playPause
thumbsUpPlayer
thumbsDownPlayer
prevSong
nextSong
I'm still looking into commands which let you retrieve current artist / track info. Let me know if you find out what those are.
The following snippet from the 'music plus for google' chrome extension might be of interest:
function playback_action(type, callback) {
var $button;
if (type == 'playPause') {
$button = $('button[data-id="play-pause"]');
}
else if (type == 'nextSong') {
$button = $('button[data-id="forward"]');
}
else if (type == 'prevSong') {
$button = $('button[data-id="rewind"]');
}
else if (type == 'currently_playing') {
$button = $('button[data-id="play-pause"]');
}
if ($('button[data-id="play-pause"]').attr('disabled')) {
$instant_mix = $('li[data-type="rd"]').click();
setTimeout(function() {
$('div[data-type="im"] .radio-icon').first().click();
}, 1000);
}
else {
$button.click();
}
callback();
}
When the above snippet stops working, check the link again and see if maybe the author updated the extension to something that works.

Javascript in Safari not always running

Am having an issue with Safari. I have a basic script using jQuery that makes some changes to a form field and adds some behaviours to it. When I run this script on using the document ready method it's fine in Firefox but in Safari it doesn't always run the initial changes. I can hit refresh and get it running fine 4/5 times, but sometimes it just doesn't initialise like it should.
This is running on a local server so the refresh is pretty quick, I'm wondering if the javascript is executing before the page has finished loading. I've tried calling the script in the foot of the page rather then the header but that hasn't helped. I remember hearing about different browsers firing document ready at different times and thought this would help remedy it but it hasn't and I can't find any further information on that topic.
Anything I'm missing that could be the issue or a workaround? The script itself doesn't seem to be at fault. Am using the jQuery colours plugin, apart from that it's only jQuery and my script.
Help is always appreciated, thanks people!
Here is the code. initSearchBox() is run using the line below in the header.
$(document).ready(function() { initSearchBox() ; });
function randomFieldValue(){
var options = new Array(
'Lorem',
'Ipsum',
'Dolor',
'Sit',
'Amet'
)
t = Math.floor(Math.random()*(options.length - 1));
return options[t] ;
}
function initSearchBox(){
instanceDefText = randomFieldValue() ;
$('#search-form-field')
.attr('value',instanceDefText)
.css('color','#fff')
.animate({color:'#999'},1500)
.focus(function(){
if($(this).attr('value') == instanceDefText){
$(this).attr('value','')
.css('color','#000')
}
})
.blur(function(){
if($(this).attr('value') == ''){
instanceDefText = randomFieldValue() ;
$(this).attr('value',instanceDefText)
.css('color','#fff')
.animate({color:'#999'},1500)
}
});
}

IE stop script warning

Only in IE I get a warning when loading my site containing javascript saying that its causing the page to run slowly (and asking if I want to stop it).
I've seen other posts about this and I've looked for any long running code or infinite loops etc. The weird thing is, when I select 'No' (to not terminate the script) the page immediately loads properly. Its almost like this warning comes up right before the page is done loading. Has anybody experienced this, or know why this might be happening?
IE has its own way of making your life impossible.
Just deactivate the warning, you can further research in the future if that's necessary.
This article might help you determine why IE is giving such a warning.
Regards,
Adapted from http://www.codeproject.com/Tips/406739/Preventing-Stop-running-this-script-in-Browsers
// Magic IE<9 workaround for irritating "Stop running this script?" dialog.
RepeatOperation = function(anonymousOperation, whenToYield){
var count = 0
return function(){
if (++count >= whenToYield){
count = 0
setTimeout(function(){anonymousOperation()}, 100)
}
else anonymousOperation()
}
}
// How to implement the workaround:
//for (var i in retailers){ // Too big for IE<9! Use magic workaround:
var i = 0; var noInArray = retailers.length
var ro = new RepeatOperation(function(){
// <<Your loop body here, using return instead of continue.>>
if (++i < noInArray) ro()
else alert("Loop finished.")
}, 200) // Run this in batches of n. 500 is too much for IE<9.
ro()

Categories

Resources