Most read posts this month



Apr 27th 2009 × microsoft internet explorer 8 finally released and some IE6 LI floating quirks

Some web dev I am–thanks to google adwords I on this very site I only just noticed an advert by microsoft for downloading IE8… Not how I should have found out about it but it beats not knowing at all, I guess.

I wonder how many issues this will introduce and how complicated my life will soon become… grab it if you have to (no follow link via google)

*update* as I went over to my Microsoft Virtual PC in order to test IE8, I accidentally loaded this site in IE6 and IT WAS HORRIBLE. In particular, it failed to inherit the width of the main content div so it spilled and defaced the site each time any code got posted (affected were code, blockquote and pre tags). Sigh… apologies, reparations have been done now, I just tend to ignore IE6 even though it still amounts to almost 15% of visitors… Even though it has been fixed in part, I should perhaps think of a gentler degradation for IE6 users, one that offers them a chance to upgrade what is now an 8 years old system…

Speaking of IE6 quirks, I had to do a semantic tab system for mootools 1.11 the other day and discovered how IE6 completely messes up the display of LI elements in an ordered list when having nested elements, spilling to the whole available space on the current line instead. The only fix for this is to float the children elements as well… For example:

<li style=”float: left”><strong>this is some text</strong></li> won’t just assume the text’s width, it will span over the whole available width and will push down a line the next LI. You need to float the strong as well in order to achieve the desired effect… Pants!


Mar 24th 2009 × mooProgress: an element javascript progress bar method

Ever needed to show something on-screen as a percentage / bar in javascript? Yes, it has been done a countless number of times before. Sometimes, even in mootools. But we like adding our own functions to the dci_core.js mini library whenever possible. So … here is a very easy and good-looking way of doing it (well, subject of what background images you can come up with, of course). The idea is simple: have a container element with a background image that is offset to outside the element’s boundaries via the background-position CSS property. As the percentage is being calculated, the background image is bring brought into view.

Our progress images look like this:

200px wide, so each percent is represented by 2px, something that is reflected in the script below. Here is the target element, styled as per our CSS:

Some more examples of various options for the progress bar, settings are contained within the actual elements:



Here’s the relevant CSS:

.progress {
    width: 200px;
    border: 1px solid #000;
    background-color: #d81e05;
    background-image: url(/gallery/img/progress.gif);
    background-repeat: no-repeat;
    background-position: -210px 0;
    height: 16px;
    line-height: 1;
    color: #F4F4F4;
    font-weight: bold;
    margin-bottom: 4px;
}
.progress2 {
    width: 202px;
    border: 1px solid #000;
    background-color: #555;
    background-image: url(/images/progressbar-orange.gif);
    background-repeat: no-repeat;
    background-position: -210px 0px;
    height: 21px;
    color: #000;
    font-weight: bold;
    margin-left: 1px;
}



The actual div and html:

<div class="progress" id="someid"></div>

Some more examples of various options for the progress bar, settings are contained within the actual elements:
<a href="#" class="barbar" data-data="{count:23,total:26,message:'loaded...',className:'progress2'}">23 of 26, "images loaded..." with cubic tween, class: progress2</a>
<a href="#" class="barbar" data-data="{count:4,total:5,message:'completed',tween:false}">4 of 5, 'completed', no tween</a>
<a href="#" class="barbar" data-data="{count:14,total:80,message:'Questions'}">14 of 80, 'Questions', cubic tween</a>
You may notice the element has a CSS dropshadow applied to it, unless you are in IE. If you are interested how this works, have a look at our mooShadow element method for absolutely positioned elements (hence the need to setStyle to absolute and back to relative afterwards, something of an issue with IE)

Here’s how we extend the element in mootools and call the methods we need:

Element.implement({
    showProgress: function(options) {
        options = $merge({
            count: 0,
            total: 10,
            message: "",
            className: "progress", // default css class
            backgroundPosition: 200, // start pos
            tween: true // animate or static
        }, options);

        // calculate % of progress
        var percent = options.total / 100, donePercent = (options.count / percent).round(), BGoffset = options.backgroundPosition - (donePercent*2).round();

        // set inline message
        this.set({
            styles: {
                "background-position": "-" + options.backgroundPosition + "px"
            },
            html: "  " + options.count + " of " + options.total + " " + options.message + " ("+donePercent+"%)",
            "class": options.className
        });

        if (options.tween)
            new Fx.Tween(this, {
                duration: 500,
                transition: Fx.Transitions.Cubic.easeIn
            }).start("background-position", "-" + BGoffset);
        else
            this.setStyle("background-position", "-" + BGoffset + "px");

        this.store("percent", donePercent); // element storage, use element.retrieve("data-percent") to get current progress.
        return this;
    }
}); // end extending elements

// apply initial state
$("someid").showProgress({count:3,total:10}); 

// bind the links to change the bar graph to real time data.
$$("a.barbar").addEvents({
    click: function(e) {
        new Event(e).stop();
        $("someid").showProgress(JSON.decode(this.get("data-data")));
    }
});

// show / read percent from element storage
$("fetchPercent").addEvent("mouseenter", function(e) {
    this.tooltip("This bar at " + $("someid").retrieve("percent") + "%");
});


That’s it, I hope it helps you. In an ideal world, this could be refactored into a mootools class but who has the time…


Nov 14th 2008 × quakelive closed beta test impressions as a developer: jquery, embedded objects and 3d

I got my hands on a login for the quakelive beta by id software and setup shop… Here is an account of my first thoughts. Please note that what I write is from the point of view of somebody that has spent many years of playing quakeworld and quake 3 arena / osp, so I will also be looking at how the game has changed.

First of all–the most noticeable thing about quakelive is that it runs within a browser. Although this was not a secret beforehand, I had some trouble imaging it – as an activex / component that sits within the browser and interfaces between the game folder (on the hard drive) and the server. Not so! Yes, there was a tiny download of a plugin, negligible at a mere 3.8mb (a typical Q3A folder with all mods weighs well over a few GB):

quakelive installer

However, there is no clientside data on your computer other than some minimal models, your local config files and things like screenshots or recorded demos. The “interface” turned out to be (to my surprise) what looks like flash! That’s right, quakelive actually runs within an embedded object in the browser and is controlled externally via javascript. The core of the site and UI is powered by jQuery (oh well, can’t all be about mootools).

<script type='text/javascript' src='/js/jquery/jquery.js?3'></script>
<script type='text/javascript' src='/js/jquery/jquery.form.js?3'></script>
...

Server browsing is all done through the “home” section of the site and AJAX. It tries to produce some results based on it’s understanding of the player’s skill level and mods of preference. It also tries to keep tag of your games played, time wasted and weapon statistics so you can follow your “progress”. However, this is the ONLY way I found that enables you to do so–there longer are any in-game means to get stats (topshots, stats wstats are not yet implemented).

From the development point of view, server browsing is via tooltip style server selections that are not the smartest but this is just a test skin… What is more worrying for the quakelive beta setup is that ID use JSON data to create the user pages to and pass variables between them and the game object. The JSON objects are generated by the main page body (presumably via PHP or whatever) and as a result, everything relating to the player’s personal account details is available in plain text within the source:

$(document).ready( function() {
    quakelive.session = "0e087cb0c37cb92568d585f1591d7df3";
    quakelive.username = "coda"; // that's me.
    quakelive.password = "dummypasshere"; // changed
    quakelive.userstatus = "ACTIVE";
    quakelive.userid = "1072nnn"; // changed
    quakelive.userinfo = {"0":"1072nnnn","PLAYER_ID":"1072nnn","1":"coda","PLAYER_NICK":"coda","2":"ACTIVE","PLAYER_STATUS":"ACTIVE","3":"coda@dci.uk.net","PLAYER_EMAIL":"coda@dci.uk.net","4":"tcpip123","PASSWORD":"tcpip123","5":null,"TIME_ZONE":null,"6":"04-NOV-08","EULA_DATE":"04-NOV-08","7":"04-NOV-08","JOIN_DATE":"04-NOV-08","8":"Dimitar","FIRSTNAME":"Dimitar","9":"2","INVITE_COUNT":"2","10":"0","EULA_OUTDATED":"0","11":"2","TIER_CTF":"2","12":"2","TIER_DM":"2","13":"2","TIER_DUEL":"2","14":"2","TIER_TDM":"2","15":"3","TIER_CA":"3","16":"0","ECODE":"0","17":null,"MSG":null};
    quakelive.cvars.Import( {"color1":1,"m_pitch":0.0174,"cg_forceModel":1,"console":1,"web_configVersion":4,"cg_enemyModel":"keel/bright","team_model":"biker/slammer","team_headmodel":"biker/slammer","headmodel":"biker/slammer","cg_drawgun":2,"r_vertexlight":1,"color2":2,"cg_drawCrosshair":9,"cg_drawFPS":1,"r_picmip":5,"cg_forceTeamModel":"sarge/red","name":"coda","cg_autoswitch":0,"cl_timeNudge":0,"com_allowConsole":1,"cg_forceEnemyModel":"keel/bright","cg_enemyColors":222222,"cg_fov":115,"cg_marks":0,"snaps":40,"cg_trueLightning":1,"r_inBrowserMode":5,"web_botskill":"medium","clan":"drink","model":"biker/slammer"} );

// etc etc.

Obviously — as this is a browser, the data will be retained in the cache and available to anyone that gains access to the computer — which kind of defeats the purpose of making a customized, portable and standalone game in order to provide exactly the same gameplay experience on any system. Have some quakelive in an internet café or LAN gaming centre and you leave your profile data and password to the next person that sits on your chair and cares to look…

I have yet to test trying to modify any of the JSON object data in order to achieve things like aliasing or trying somebody else’s account, but it hopefully serves display purposes for the UI side of things only.

As for the game itself… It have yet to make a lasting impression on me. It is totally remarkable that it runs everything on the fly – all the maps data, the game models, mods and so forth is being sent to you at map load time… All 3D is rendered based upon server-to-client data and so forth. It also looks a bit like Q3A at a glance but it is anything BUT…

Gameplay changes:
The rail gun is now reduced to a mere shadow of its former self and is only useful as a way to annoy / snipe opponents from afar (80 damage points). The game has become more about +forward and +attack with rocket spam which can — for a short while — give the impression that it plays faster than regular Q3A.

The lightning gun seems to have deteriorated as well – things like cg_truelightning are no longer functioning as they used to. The shaft itself now causes damage in proportion to the distance of the target object–further away they are, the less health it takes.

FPS is lower than it used to be – and considerably so. Tested from my laptop where I get 333 FPS on Q3A, quakelive can nail 125 but only just–there are certain maps with clipping issues that cause a drastic FPS drop and gameplay becomes very laggy.

There is also a whole new netcode as well — something of a hit and miss (pun intended) as it has rendered things like cg_smoothclients and cl_timenudge redundant. Which is great – if you are just starting to learn the ropes with quakelive. But for those that may have spent years getting used to Q3A’s physics and netcode, you will find it difficult to adjust aim and accuracy will suffer. On the upside, the hitboxes seem larger so some really hopeless rail shots tend to hit when they would not have done before… so expect some lucky frags. Of course, it also means you will get hit a lot more.

The maps have been revamped but it is essentially the same old .bsp with some changes and a couple of new DUEL and CLAN ARENA maps. Speaking of CLAN ARENA, it is now built-in but in an odd, american style – with self damage on rocket jumping. Capture the flag (CTF) has also taken a hit by the Re-introduction of “runes” , “techs” or “power ups” (whatever you want to call them) and the nail gun (not quite like the QuakeWorld nail gun but it must have come from somewhere).

Verdict:
As a whole, it is a technological marvel and will probably set a landmark in game development for years to come. Once again, ID have broken the binds of our preconceptions and created a ground-breaking event… And they have only just gotten started on Rage…

Would I play it? All things being equal, I’d much rather use Q3A with OSP than quakelive. Sorry — too old to start from scratch. Then again, who has time for games these days…


Oct 30th 2008 × slidingTips: a mootools apple-style tooltip effect

This is not working since blog upgrade, looking into it

Seems that Apple really inspire design… After having done largerBox: a mootools apple-style modal lightbox effect, I thought I’d also do some animated tooltip effects similar to the ones on their site. So, I finally got around to it and just drafted an element method for the fragged tooltips (called, slidingTips or slidingTips) into my dci_core.js collection.

Not much more to say, here it is in action:

You can interact with all form elements in this div to get a tooltip

show on focus / hide o n blur:

show on click / dispose after 5 seconds:

show on mouseover / hide on mouseout:

The code? First, the Element.implement bits, 2 functions:

Element.implement({
    slidingTip: function(what, options) {
        // apple style tooltip
        var _this = this, coords = _this.getCoordinates(), options = $merge({
            eventEnd: "mouseleave",
            eventEndTrigger: _this,     // parent element or self
            topOffset: 90,             // offset when in full view
            topStartOffset: 100,        // offset for animation start
            opacity: .8,                // target opacity in full view
            className: "tooltip",       // linked to css
            morphOptions: {
                duration: 300,
                transition: Fx.Transitions.Sine.easeOut,
            },
            delay: 0,                    // can dispose on a timer, in seconds
            id: "tid" + $random(100, 1000)
        }, options);

        // we only need one tip instance per parent element.
        if ($type(this.tip) != "element") {
            this.tip = new Element("div", {
                "class": options.className,
                id: options.id,
            });
        }

        // if it's an existing one, with an implicit id, pick it up
        if ($(options.id))
            this.tip = $(options.id);

        // set initial options and html
        this.tip.set({
            opacity: 0,
            html: "<div style='padding:20px'>" + what + "</div>",
            styles: {
                left: coords.left + coords.width / 2
            }
        }).inject(document.body).removeEvents();

        // show it. cancel any previous animation instances for tip
        if ($type(this.morph) == "object")
           this.morph.cancel();
        else
            this.morph = new Fx.Morph(this.tip, options.morphOptions);

        // show it. really.
        this.morph.start({
            opacity: options.opacity,
            top: [coords.top - _this.tip.getSize().y - options.topStartOffset, coords.top - options.topOffset]
        }).chain(function() {
            // once done, decide how to exit
            if (options.delay == 0) {
                // based on an event.
                options.eventEndTrigger.addEvent(options.eventEnd, function() {
                    _this.morph.cancel();
                    _this.slidingTipaway();
                });
            }
            else {
                // based on a timed delay
                (function() {
                    _this.slidingTipaway();
                }).delay(options.delay);
            }
        });

        // define the tooltip close animation morph object
        var closeAnimation = {
            opacity: 0,
            top: coords.top - _this.tip.getSize().y - options.topStartOffset
        }

        // ... and save it within the parent element
        this.store("closeAnimation", closeAnimation);

        return this;
    },
    slidingTipaway: function() {
        // animate an slidingTip, opposite on in method.
        if (this.tip) {
            this.morph.start(this.retrieve("closeAnimation"));
        }

        return this;
    }
});

There is some CSS to this:

<
div.tooltip {
    background:transparent url(/images/tooltip-ie.gif) no-repeat scroll 50% 50%;
    height:90px;
    left:50%;
    margin-left:-151px;
    position:absolute;
    text-align:center;
    top:0;
    width:299px;
    z-index:1010000000;
    color: #327bb2;
    font-weight: bold;
}

And finally, the demo code:

window.addEvent("domready", function() {
    $("demofocus").addEvent("focus", function() {
        this.slidingTip("Please enter your first name and your surname", {
            eventEnd: "blur", // on blur, remove tip
            topOffset: 82 // tuck in more (heigh is 90 usually)
        });
    });

    $("demosubmit").addEvent("click", function(e) {
        e.preventDefault(); // stop submit from happening
        this.slidingTip("Sorry, you are required to complete all fields before you can submit", {
            delay: 5 * 1000, // remove tooltip after 5 seconds
            topOffset: 82
        });
    });

    // find all .demo_mouse class elements and tooltip them to show data-tip values
    $$(".demo_mouse").each(function(el, i) {
        el.addEvents({
            mouseenter: function() {
                this.slidingTip(this.get("data-tip"), {
                    id: "demoid"+i, // can assign implicit ids to shadows for scripting
                    morphOptions: {
                        duration: 600
                    }
                });
            },
            click: function(e) {
                // prevent the submit from working....
                e.preventDefault();
            }
        });
    });

});

Now, the fragged apple slidingTips currently uses this image:

tooltip ie friendly

This is a .GIF so it will be IE friendly (as opposed to a .PNG with transparency). Alpha blending/anti aliasing is not perfect but will work on a light background (hence the white around the demo code).

This one:

tooltip ie friendly

... way nicer. But, on IE7 even (which allegedly supports transparency in PNG), there is a nasty bug and alpha bleeding near the pointy arrow. You can try using it by changing the .tooltip css class.


Sep 17th 2008 × largerBox: a mootools apple-style modal lightbox effect

I saw the animation apple do when viewing a trailer (non-HD) on their modal box and decided to replicate the effect for my image viewing in mootools.

Examples of largerBox v3.0 (animations / morphs / tweens don’t work too nice over iframes, mind)


UPDATE – 24/11/2009 largerBox is in the process of being refactored. largerBox v3 – beta 1 is available to look at and play with. It features a totally drag and drop solution – CSS is built into the javascript class, so are the images for next/previous and close. That’s right, there are no files to edit, updated, upload — aside from your images. Check the new source here: /js/largerBox.js

How does it work?
In the normal way, it takes a <a href=’imagename.jpg’> … </a> and attaches itself to the click event, not interfering in any way with your html. All you need to do is add ‘class=”fullimage”‘ to the anchor tag and fraggedBox will do the rest.

What do I need to get this to work?
You need to grab a copy of mootools 1.2.x – core.

You then need to grab the latest beta. Just look at the demo page anyway…


Sep 15th 2008 × thawte site seal via domready

unfortunately, we have no Thawte certificate ourselves so this demo will show the badge as ‘invalid certificate’.


The problem with the Thawte Site Seals…

After having developed a site for a client, we were asked to include the THAWTE site seals that verify the site’s authenticity. That is all fine, but the seal uses

<script src="https://siteseal.thawte.com/cgi/server/thawte_seal_generator.exe"></script>

tags and holds the DOM load, often causing a performance drop — especially so if Thawte’s server is running slow and your page waits on the DOMREADY event….

The solution for a nice clean seal: Get rid of the sealgenerator.exe

Remove the code supplied by thawte code and replace with this goodness:

window.addEvent("domready", function() {
    // written for mootools 1.2
    var doSeal = function(targetObject) {
        // show thawte seal code w/o the reference to their exe in a dom compliant way
        var loc     = window.location.href;
        var sealLoc = "https://www.thawte.com/core/process?process=public-site-seal-cert-details&public-site-seal-cert-details.referer=" + loc;
        new Asset.image("https://siteseal.thawte.com/site-seal/image?g5ff7fe3df88d8fafaa6035dc97152679ga45f4b102502fefbd20332591412323c" + (new Date()).getTimezoneOffset() + "g5d43a4e836d7d07a50759fb1da9cc900g1a0452b749ddb29083736b34ef4a14e9ga45f4b102502fefbd20332591412323c" + loc, {id: 'sealimage'})
            .inject(targetObject).addClass("cur").set("title", "click to verify").addEvent("click", function() {
                window.open(sealLoc,'ga3ef4eb41dcac740b918440eb9cd19c8','height=500,width=516,scrollbars=yes,status=1');
            });
    } // end doSeal

    // embed it...
    doSeal($("seal"));
});// domready


Sep 15th 2008 × Mootools 1.2 is slowly finishing off the community

There is simply nothing remotely as good as the mootools javascript framework out there. And version 1.2 did nothing but make it even more fun to code for. That aside, the mootools team decided to ditch the forums and move over to google groups.

I have been subscribed to the new mailing list since the start and I can see it slowly subsiding in interest and usefulness already: what precious little sense of community building i felt before is now slowly diminishing… A terrible way to alienate a loyal userbase who LOVED the old forums – People (well, I did anyway) used to browse them for the sheer fun, to get or offer help, to showcase work, to find out more about new mootools sites or plugins…

There is now a half-hearted attempt at making an unofficial forum but it is just another wrong decision that takes away even more people from the mootools google group…

Shame, really.

*update* some bloke I had not heard of (does not mean much really, I live in a box) called Tom Occhino of the mootools team posted this thread on the mootools “forum”/mail list. I am sorry to say, Tom: claiming that frameworks like jQuery don’t have forums and their users don’t bitch about it are unsubstantiated. For starters, they never had a forum to begin with so they wouldn’t feel as if something precious has been taken away from them. I believe a number of people will have chosen mootools due to the community that it had. Not the best commercial / career decision, all you have to do is look at any job site / agency: jQuery is sought after far more often than mootools (wrong as that might be). Even recruiters have heard of jQuery despite not being able to tell you what a framework is… So why disband the community and try to be another jQuery? This seat is already taken…


Aug 14th 2008 × Insane ][ Inside for WordPress is here

Welcome to my first ever wordpress theme “Insane ][ Inside" inspired by an old Quake3 clan site I did 5 years ago (work in progress) it features:

  • unique layout and graphics
  • custom and unique javascript / framework
  • sortable menus
  • WILL / MAY FEATURE: ajax login, search, comments, sharing, editing

Once it is complete, it will be made available through wordpress.org. Wee!
The old Rocket Arena clan Insane ][ Inside