Hello all!

On the page http://keryx.se/dev/brCh/browserval.xhtml I have a DOM-scripting demo. (For reasons I'll explain below you can't use MSIE to view the page.) The page per se is not meant to be accessible or good design, but the script is supposed to be an example of best practice DOM-scripting, to be used in my teaching.

On the page you are supposed tho chose between two browsers by clicking on one of the boxes - but one box will be *hard* to catch!

The script in question can be seen at http://keryx.se/dev/brCh/browserval.js or at the end of this message.

My take on "best practice" DOM-scripting would include the following:

- Follow to the furthest reasonable extent ECMA- and W3C-standards, but allow for some de-facto Netscape 3 or MSIE 4 standards when you need to do something not yet covered by standards, such as using the Window object, XHR or maybe even innerHTML.

- All scripts should be able to run in a page sent as application/xhtml+xml with very *few* modifications. The generated (X)HTML must be well-formed and should be valid (perhaps with the exception of custom attributes). In order to prove this point my page in question is actually sent as XHTML and therefore won't render in MSIE, although the script actually works in that browser too.

- The JavaScript global variable namespace should be as unpolluted as possible. To that end I use an object literal.

- JSDoc (Why don't people use it more often?) http://jsdoc.sourceforge.net/
Subquestion: Is there a way to enforce private properties when I use an object literal?

- Unobtrusiveness
--> All JS in external files
--> No event-handling in the (X)HTML-code
--> Graceful degradation/progressive enhancement (Here my script fails, simply because it is an JS-demo.)
--> Object detection aka. capability testing instead of browser sniffing.

- Optimization
--> Not too prematurely
--> Garbage collection (fixes for bad browsers)
--> Remove all unnecessary DOM-lookups
--> Remove unnecessary strict errors http://www.wsabstract.com/javatutors/serror.shtml

- I18N
--> All messages should be kept apart from the code
--> All messages should be able to be generated by the CMS


According to my intentions - have I succeeded? What have I forgotten? What can be improved?


Lars Gunther

P.S. Here is the script

/**
 * This file contains the object brCh and sets it up
 * to be executed upon window-load
 *
 * brCh is short for "browserChoice"
 *
 * @author Lars Gunther
 * @package DOM-demo
 * @license CCSA http://creativecommons.org/licenses/sa/1.0/
 * @requires addEvent
 * @requires addLoadListener
 *
 * @todo Real private properties
 */

/**
 * This object contains all code to be executed
 *
 * It is dependant upon the addEvent method.
 * Object literals do not pollute global namespace!
 */
var brCh = {
     /**
      * This method should run on window load.
      * It sets upp all avent-handling and registers the most used elements
      */
     init: function() {
        // Do all lookups here so they won't have to be repeated
        brCh.jadiv  = document.getElementById('ja');
        brCh.nejdiv = document.getElementById('nej');
        brCh.koord  = document.getElementById("koordinater");

        if ( !brCh.jadiv || !brCh.nejdiv || !brCh.koord ) {
            throw 'Necessary XHTML-elements are not present in the code.';
        }

        addEvent(brCh.jadiv,  'mousedown', brCh.svaraBra, false);
        // OBS! inte ONmousedown, utan bara mousedown
        addEvent(brCh.nejdiv, 'mouseover', brCh.moveTo,   false);
        addEvent(brCh.nejdiv, 'mousedown', brCh.protest,  false);
        return true;
    },

    /**
     * What language should be used? Default value set here
     * @public string
     */
    lang: 'sv',

    /**
     * Messages are kept in this associative array (technically an object)
     * @public object
     */
    i18n: { },

    /**
     * X-axis starting value for the bad-choice
     * @private integer
     */
    _slumpX: 400,

    /**
     * Y-axis starting value for the bad-choice
     * @private integer
     */
    _slumpY: 150,

    /**
     * Helper math method
     *
     * @param max integer The highest possible value to be returned
     * @returns integer
     */
    _slumpad: function(max) {
        return ( Math.round(Math.random() * max) );
    },

    /**
     * This method is invoked upon mouseover the bad choice and moves it
     */
    moveTo: function() {
        // It should be hard to get a similar position once again
        do {
           brCh._slumpX = brCh._slumpad(500);
        } while ( Math.abs(brCh.oldX - brCh._slumpX) < 60 );

        do {
            brCh._slumpY = brCh._slumpad(350) + 150;
        } while ( Math.abs(brCh.oldY - brCh._slumpY) < 50 );

        brCh.nejdiv.style.left = brCh._slumpX+"px";
        brCh.nejdiv.style.top  = brCh._slumpY+"px";

        brCh.koord.childNodes.item(0).nodeValue = 'X = ' +brCh._slumpX;
        // item(1) is a br-element
        brCh.koord.childNodes.item(2).nodeValue = 'Y = ' +brCh._slumpY;
        return [ brCh._slumpX, brCh._slumpY ];
    },

    /**
     * This method is invoked when someone clicks on the good choice
     */
    svaraBra: function() {
        alert( brCh.i18n[brCh.lang].youAreWise );
document.getElementsByTagName('h1')[0].childNodes[0].nodeValue = brCh.i18n[brCh.lang].thankYou; document.getElementById('tips').childNodes[0].nodeValue = brCh.i18n[brCh.lang].goodAnswer;
        document.getElementById('tips').style.fontSize  = '200%';
        document.getElementById('ja').style.visibility  = 'hidden';
        document.getElementById('nej').style.visibility = 'hidden';
        setTimeout('window.location.reload()',3000);
        return true;
    },

    /**
     * This method is invoked, should anyone be able to click on the bad choice
     */
    protest: function() {
        alert ( brCh.i18n[brCh.lang].areYouMad );
        return true;
    }
}

// Messages in i18n-array
// This would probably be generated server-side by PHP to be more easliy synched with the
// language in the page as such (if this was not a demo...)
brCh.i18n['sv'] = { };
brCh.i18n['sv'].thankYou   = 'Tack för svaret!';
brCh.i18n['sv'].goodAnswer = 'Du valde rätt!';
brCh.i18n['sv'].youAreWise = 'Du är en klok person!';
brCh.i18n['sv'].areYouMad  = 'Är u galen eller?';

brCh.i18n['en'] = { };
brCh.i18n['en'].thankYou   = 'Thank you for the answer!';
brCh.i18n['en'].goodAnswer = 'You made the right choice!';
brCh.i18n['en'].youAreWise = 'That\'s a good choice!';
brCh.i18n['en'].areYouMad  = 'Are you crazy?';


// Set language - let's change it into English
brCh.lang = 'en';

// Start the magic!
// Basic apability testing is done by addLoadListener
addLoadListener(brCh.init);


*******************************************************************
List Guidelines: http://webstandardsgroup.org/mail/guidelines.cfm
Unsubscribe: http://webstandardsgroup.org/join/unsubscribe.cfm
Help: [EMAIL PROTECTED]
*******************************************************************

Reply via email to