moski
moski

Reputation: 279

Greasemonkey script to replace jQuery plugin function?

I'm trying to write a Greasemonkey script for Firefox to change the behavior of some pages when they detect a window out of focus. I want the page to continue to function as if it were still in focus, even when I have another tab or window active.

I started out looking at CAPS Security Policies which seemed to work for inline Javascript (window.onfocus,window.onblur), but had no effect on external jQuery script plugin access to focus events.

This is my test page, which uses a jQuery plugin to detect focus. The plugin is inline here, but may also be an external script in some cases.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
    <title>jQuery focus test</title>
<script src="jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">

(function($) {
    $.fn.focuscheck = function() {
        function focusOn () {
            document.getElementById('console').innerHTML += '<div>Focus event handler fired.</div>';
        };
        function focusOff () {
            document.getElementById('console').innerHTML += '<div>Blur event handler fired.</div>';
        };

        $(window).bind('focus', focusOn);
        $(window).bind('blur', focusOff);
    };
})(jQuery);

</script>
</head>

<body>    
    <div id="console"></div>
    <script type="text/javascript">
    $('#func').focuscheck();
    </script>
</body>

</html>

And my Greasemonkey script. I'm trying to adapt jQuery Greasemonkey code from joanpiedra.com. In this case, I tried to completely replace the focuscheck jQuery plugin function code from my test page. All the lines are the same as the original except the function focusOff() which should display a different result. I don't know if there is a way to do this without replacing the entire function. If that's an option, I might just want to replace the single focusOff function or the line with $(window).bind('blur', focusOff);.

Right now, the Greasemonkey script doesn't work on my test page. There is no change in the output. Also, I'm not sure if I need to add jQuery to my Greasemonkey script or not, since the page already loads it.

// ==UserScript==
// @name          jQuery
// @namespace     http://www.joanpiedra.com/jquery/greasemonkey
// @description   Play nicely with jQuery and Greasemonkey
// @author        Joan Piedra
// @homepage      http://www.joanpiedra.com/jquery/greasemonkey
// @include       *
// ==/UserScript==

// Add jQuery
var GM_JQ = document.createElement('script');
GM_JQ.src = 'http://jquery.com/src/jquery-latest.js';
GM_JQ.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(GM_JQ);

// Check if jQuery's loaded
function GM_wait() {
    if(typeof unsafeWindow.jQuery == 'undefined') { window.setTimeout(GM_wait,100); }
    else { $ = unsafeWindow.jQuery; letsJQuery(); }
}
GM_wait();

// All your GM code must be inside this function
function letsJQuery() {
    var script = document.createElement('script');
    script.type = "text/javascript";
    script.innerHTML = "(function($){\
        \
        $.fn.focuscheck = function(){\
            function focusOn () {\
                document.getElementById('console').innerHTML += '<div>Focus event handler fired.</div>';\
            };\
            function focusOff () {\
                document.getElementById('console').innerHTML += '<div>CHANGED event handler.</div>';\
            };\
        \
        $(window).bind('focus', focusOn);\
        $(window).bind('blur', focusOff);\
        };\
    })(jQuery);";

    document.getElementsByTagName('head')[0].appendChild(script);   
}

Upvotes: 2

Views: 1816

Answers (1)

yodog
yodog

Reputation: 6252

I don't know if there is a way to do this without replacing the entire function

Yes, there is. See code below.

Also, I'm not sure if I need to add jQuery to my Greasemonkey script or not, since the page already loads it.

You don't have to. See code below.

The html (same as yours - i just added "fired from inline JS" to innerHTML)

<html lang="en">
.
.
function focusOn () {
   document.getElementById('console').innerHTML += '<div>Focus event handler fired from inline JS.</div>';
};
function focusOff () {
   document.getElementById('console').innerHTML += '<div>Blur event handler fired from inline JS.</div>';
};
.
.
</html>

The GM script

// ==UserScript==
// @name           TESTE 2
// @namespace      TESTE 2
// @description    TESTE 2
// @include        file:///*
// ==/UserScript==


$ = unsafeWindow.$
$(window).off('blur')

function focusOff () {
    document.getElementById('console').innerHTML += '<div>Blur event handler fired from Greasemonkey.</div>';
};

$(window).on('blur', focusOff);

The result

result image

And here, why you should not use unsafeWindow: http://wiki.greasespot.net/UnsafeWindow

EDIT

About your question in the comments

Thank you. That's exactly what I was looking for. I will look into using a safe wrapper instead of unsafeWindow. If you don't mind a follow-up question: Slide Panel demo - I tried to adapt similar code to override the click function, with $('.btn-slide').unbind('click') then adding a new function, but it doesn't quite work. The event is logged, but the button still activates. $('.btn-slide').bind('click', function(event) { event.preventDefault(); console.log('button clicked'); }); How can I prevent the slide animation?

The new code:

// ==UserScript==
// @name           TESTE 3
// @namespace      TESTE 3
// @description    TESTE 3
// @include        http://www.webdesignerwall.com/demo/jquery/*
// ==/UserScript==

$ = unsafeWindow.$

$(window).load(function(){
    $('.btn-slide')
        .unbind('click')
        .bind('click', function(event) {
            alert('my function here')
            console.log('button clicked')
        })
});

Upvotes: 2

Related Questions