Google Maps API

I started working some with the Google Maps API, and it’s pretty nice. The documentation is decent, the examples are good, etc. I realized that I’ve come to expect this from Google, so I wanted to take the time instead to point out that this is an exceptional product. For example, I began to look into making the scroll wheel zoom on my maps like they do on the Google Maps site. What does it entail? One line:

map.enableScrollWheelZoom();

However, as great of a product as it is, it seems to be lacking some things. For example, if I want an info window that gives the options to get directions to or from that location, I have to do all that myself. I have to generate the links, and make them replace the content of the info window with a form that I have to make, and I have to make that form run some JavaScript when executed to get the directions. Why? This has GOT to be a common task. Why not build it into the API? However, in the end, that pales in comparison to the real problem. There is no way to validate a Google Maps API key! Instead, you have to load JavaScript using that key, and it uses an alert to announce that the key was bad! No one wants a JavaScript alert to pop up on their page! Since I’m making a WordPress plugin out of this (teaser!), I needed to make sure that the users of my plugin wouldn’t have this issue. I ended up having to override the alert function on the options page for my plugin like this:

var KillAlerts = true;
var realAlert = alert;
var alert = new Function('a', 'if(!KillAlerts){realAlert(a)}');

Then I added a function that runs on page load, re-enables the alerts, and checks if the key was valid:

function load()
{
    // Re-anable alerts
    KillAlerts = false;

    if (GBrowserIsCompatible()) {
        // Key is valid
    } else {
        if (G_INCOMPAT) {
            // Key is NOT valid.
        } else {
            // Can't tell if the Google API Key is valid, due to the browser not being compatible with the Google Maps API.
        }
    }
}

There is no reason that it should be that complicated. They should have a web service where I can send a request to verify a key, or their script should set a global variable rather than send an ugly alert! In the end, it’s a great product, but I would have expected that these kind of rough edges would have been taken care of by now. Google, you make me sad.

WordPress Script Handling

WordPress has some great stuff for handling scripts. You can use wp_enqueue_script() or wp_register_script() to handle scripts. Since there are some scripts that I use so regularly, I decided to automate the process a little more. Basically, I create a js directory inside my template directory, and place the JavaScript files I plan to use there. Each can have certain keywords in the comments at the top of the file to set it’s handle, version, dependencies, as well as whether to enqueue it automatically. The comments may look something like:

/*
Handle: xavisys
Version: 0.1
Deps: scriptaculous-effects
Enqueue: true
*/

/*
Version: 1.5.4.1
Handle: validation
Deps: scriptaculous-effects
*/

/*
Handle: x_contact
Version: 0.1
Deps: validation
*/

Basically, if enqueue is set to true, it will automatically load the file. Otherwise, it will just register it, so that you can use the handle to enqueue it when needed. All you need to do is add the following code to your functions.php file:
Read more

Using Prototype Javascript to set the value of a radio group

Not that long ago I wrote Using Prototype Javascript to get the value of a radio group, but I keep getting asked how to set the value of a radio group using prototype JS. Here are a couple ways to do just that.

$$("input[type=radio][name='radioGroupName'][value='yourDefaultValue']")[0].writeAttribute("checked", "checked");
$("someRadioGroupMember").writeAttribute("checked", "checked");

Using Prototype Javascript to get the value of a radio group

I am constantly asked how to find the value of the selected radio button in a radio group. The way I usually told people was something like this:

var radioGrp = document['forms']['form_name_or_id']['radio_grp_name'];
for(i=0; i < radioGrp.length; i++){
    if (radioGrp[i].checked == true) {
        var radioValue = radioGrp[i].value;
    }
}

To use it you need a reference to the radio group (not just a single button), which means you need to know the form, and the radio group name. Since I use prototype for almost everything now, I decided to use it to make a simple function for this purpose. First of all, here is the function:

/**
* Returns the value of the selected radio button in the radio group, null if
* none are selected, and false if the button group doesn't exist
*
* @param {radio Object} or {radio id} el
* OR
* @param {form Object} or {form id} el
* @param {radio group name} radioGroup
*/
function $RF(el, radioGroup) {
    if($(el).type && $(el).type.toLowerCase() == 'radio') {
        var radioGroup = $(el).name;
        var el = $(el).form;
    } else if ($(el).tagName.toLowerCase() != 'form') {
        return false;
    }

    var checked = $(el).getInputs('radio', radioGroup).find(
        function(re) {return re.checked;}
    );
    return (checked) ? $F(checked) : null;
}

You can pass it either a form (object or id) and a radio group name, or a radio button (object or id).

var value = $RF('radio_btn_id');
var value = $RF('form_id', 'radio_grp_name');

Hopefully this will help simplify things for someone. Maybe they will eventually add something similar into prototype itself.

Properly degrading JavaScript Effects with Script.aculo.us

I recently decided to use Script.aculo.us in a project that I’m working on. I was actually pretty impressed with it’s cross-browser compatibility and ease of use. I didn’t even think that the 200K size (including the Prototype Framework) was that bad. However, I did run into some issues while trying to make my site function properly for users that have JavaScript disabled, while still allowing the effects for those that do.

In my particular situation, I wanted to make some objects appear with an effect. You will notice that if you apply an Appear effect to an element, it will display, then disappear, the appear with the effect. The solution is to set an inline style with display:none, except that this will cause the element to be missing from users without JavaScript. The solution? Add the display:none style with Javascript.

First, I created a CSS class called effect_appear, with no styles.

.effect_appear {
}

Then I use Javascript to modify that class, and set the display to none.

function getStyleClass (className) {
    if (document.styleSheets.length < 1) {
        return null;
    }
    if (document.styleSheets[0].cssRules) {
        var cssRules = 'cssRules';
    } else {
        var cssRules = 'rules';
    }
    for (var s = 0; s < document.styleSheets.length; s++) {
        for (var r = 0; r < document.styleSheets[s][cssRules].length; r++) {
            if (document.styleSheets[s][cssRules][r].selectorText == '.' + className) {
                return document.styleSheets[s][cssRules][r];
            }
        }
    }
    return null;
}
getStyleClass('effect_appear').style.display = 'none';

Now, any element with that class will display normal to a user without JavaScript support, but will be missing for users with JavaScript. Next I added a ‘load’ event handler to the window element, which will make the elements appear with an effect.

Event.observe(window, 'load', effects);
function effects() {
    document.getElementsByClassName('effect_appear').each(
        function (el) {
            el.visualEffect('Appear');
        }
    );
}

However, there is still one problem. Because the style we created is not inline, it seems to override any effect that we add. The solution is to first remove the classname, and hide() the element (this will remove the class, but keep the element hidden, without the user ever seeing the element). Then we apply the visual effect (in this case, Appear).

Event.observe(window, 'load', effects);
function effects() {
    document.getElementsByClassName('effect_appear').each(
        function (el) {
            el.removeClassName('effect_appear').hide().visualEffect('Appear');
        }
    );
}

Here is the whole thing. Remember, the class “effect_appear” MUST exist in one of your stylesheets, or in a style tag ABOVE this code.

function getStyleClass (className) {
    if (document.styleSheets.length < 1) {
        return null;
    }
    if (document.styleSheets[0].cssRules) {
        var cssRules = 'cssRules';
    } else {
        var cssRules = 'rules';
    }
    for (var s = 0; s < document.styleSheets.length; s++) {
        for (var r = 0; r < document.styleSheets[s][cssRules].length; r++) {
            if (document.styleSheets[s][cssRules][r].selectorText == '.' + className) {
                return document.styleSheets[s][cssRules][r];
            }
        }
    }
    return null;
}
getStyleClass('effect_appear').style.display = 'none';
Event.observe(window, 'load', effects);
function effects() {
    document.getElementsByClassName('effect_appear').each(
        function (el) {
            el.removeClassName('effect_appear').hide().visualEffect('Appear');
        }
    );
}

My Javascript Date Chooser

If you just want the code, feel free to grab the files:

Give it a try:

All it takes to actually USE this, is to add onfocus=”cal.showCal(this);” to any text input like this:
<input name=”demo” type=”text” maxlength=”10″ size=”10″ onfocus=”cal.showCal(this);” />

Stop Censorship