Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Prototype (et al) in Greasemonkey

So, using Prototype in Greasemonkey is... awkward, at best.

You see, everything you do in GM Javascript is actually stored in this weird space called "unsafeWindow". (Clearly, I don't fully understand why.)

It also seems to be impossible to intrude on the basic elements (like Element itself) that PType wishes to.

Thus, you have to be sneaky: you cause the page to load your scripts. ...And yet, for reasons incomprehensible, you still access them in unsafeWindow. Even when events fire. ...Which, by the way, seems to be the only way to do it: events firing. You can't just natively "do stuff".

Disappointing... but work-around-able.

I think we can use this to help us Monkify some of our websites. My first target is Learnerweb, which is Usable But Obnoxious as-is.

Here's a script that causes a new <p> to appear on the cspabq page when you click pretty much anywhere under the header:

// ==UserScript==
// @name Monkeys. Greasy, greasy monkeys.
// @namespace CSP
// @description Testing Prototype and ilk in GM
// @include http://www.cspabq.org*
// ==/UserScript==

var scripts = [
'http://wiki.script.aculo.us/javascripts/prototype.js',
'http://wiki.script.aculo.us/javascripts/effects.js',
'http://wiki.script.aculo.us/javascripts/controls.js'
];
for (i in scripts) {
var script = document.createElement('script');
script.src = scripts[i];
document.getElementsByTagName('head')[0].appendChild(script);
}

window.addEventListener('load', function(event) {

$ = unsafeWindow['window'].$;
div = document.getElementById('content-main');
div.addEventListener('click', function(event) {
x = document.createElement('p');
x.innerHTML = "It is very greasy. You are likely to be eaten by a monkey.";
$('content-main').appendChild(x);
}, 'false');

}, 'false');

A Javascript Hack (using prototype)

Javascript with Prototype is the next best thing to ruby.

Okay, okay, this is a hack and it's not readable, but I was still tickled when I got this to work:

$A($('newqueuerequest').getElementsByTagName('img')).findAll( function(img) { return (img.src.indexOf("icons/red-x.gif") > -1); }).inspect();

Translation: "Give me a list of all img tags that have a red-x."

(I'm using this to ensure all fields are validated in a form, because the validation is complex.)

A Wasted Hour

I just wasted an hour looking at this HTML:






















...I couldn't figure out why the first set wasn't working (click on the second radio button and the first is still selected), and the second one was.

Then I realized I was using "ID" instead of "NAME" as an attribute.

ARGH.

Code-writing euphoria

I have a CGI that wants to validate a series of fields using Ajax.

I'm currently testing out the YUI toolkit. ...To be honest, I prefer Prototype, but I do want the breadth of knowledge to use both (and, next, I'll pick up dojo).

Anyway, back to the fields: there are three of them: client, project, and collection. I need to test if any of these fields have already been used (meaning: what the user enters must be unique), and I'm using Ajax to test this.

At first, I had a rat's nest of code, with basically a callback, handler, and response function for each one of the three. This, of course, made my teeth itch.

I tried refactoring, but I ran into the ubiquitouos scope problem in JS: I needed a closure around my "name".

After wrestling with it for two hours, this is what I ended up with, and it works beautifully:


//
// Check the existing names (client, project, collection):
//
var svrCheckExistingNames = "checkExistingNames.cgi";

nameHandler = function(o) {
checkExistingNamesSuccess(o, this.name);

}
// Stolen from Prototype:
Function.prototype.bind = function(obj) {
var method = this,
temp = function() {
return method.apply(obj, arguments);
};
return temp;
}
var clientTest = nameHandler.bind({name: 'client'});
var projectTest = nameHandler.bind({name: 'project'});
var collectionTest = nameHandler.bind({name: 'collection'});

function checkExistingNamesRequest(n, v){
$('checkExistingNames_'+n+'_container').innerHTML = "Checking existing "+n+" names... <img src="../icons/loading.gif%27" border="1" />";
var test = clientTest;
if (n == 'project') test = projectTest;
if (n == 'collection') test = collectionTest;
var request = YAHOO.util.Connect.asyncRequest('GET', svrCheckExistingNames+"?name="+n+"&value="+v, {success: test, failure: test});
}
...Why is it such a PITA to post code on Blogger? ...There must be a trick I'm not getting. (I'm using blockquote tags for nesting here!)