Friday, 25 September 2009

XHTML, Mozilla Firefox and ContentEditable

Can't quite get over that I'm using wifi on a bus. Job search is going well, have two companies I'm fairly sure are going to make offers and a few more leads to chase up just in case. More later if I get the jobs.

Switching from iframe/designMode to div/contentEditable and suddenly nothing was editable. Can't find this mentioned anywhere online so will blog it here: In Moz, contentEditable does nothing if the document is XHTML. In Fiinrefox 3+ and HTML this makes the element editable as per my favourite IE proprietary feature turned spec in HTML5. This isn't so surprising (contentEditable is part of HTML5, not the rather more strictly defined XHTML) but took me a long time to work out. Annoying because now I have to change a thousand .tagNames to .tagName.toLowerCase(). Double annoying because I can't use Array.pluck('tagName') to get a bunch of tagNames at once. Oh well.

So why switch? Well, having client-side applications span two documents was creating more problems than it solved. Prototype tends to make assumptions that there is only one document and sometimes gets upset when element.ownerDocument != document. Add to that, dragging and dropping breaks when the cursor wanders into another document and the overhead of loading some of the javascript twice and for a while now I've been planning on maaking this change. Hence branches/designMode-to-contentEditable/ in SVN

Monday, 21 September 2009

Chrome and DOM mutation events

I just found out the hard way: Chrome (or at least, the Linux dev builds but very likely the proper releases too) only fire DOM mutation events if the element which mutates is in the current document. Very likely Safari suffers from the same bug but until I can get it the Windows version working under WINE I can only test that theory at work.

This really quite sucks. Say you generate some XML, convert to HTML and put the HTML on the page, then start changing the XML and want to keep the HTML in sync. Well, you can't, unless you put the XML in the page too and hide it with style="display:none" or whatever. Luckily, the browsers don't seem to mind when you add weirdly named elements to the page.

The above example is essentially what I'm doing. The XML is my wikixml representation and the HTML is the same, as syntax highlighted HTML.

I'll try to work out if this is Chrome or webkit and send a bug report in as appropriate.

Sunday, 20 September 2009

Mixin factory: Really handy pattern for Classical OOP in Javascript

Prototype Classes have a sort-of multiple inheritance feature that lets you throw in Ruby-esque mixins when a Class is defined. There's a pretty good tutorial on the Prototype site.

I got a bit fed up my mixins defining not-really-hidden-but-they-start-with-an-underscore-and-have-a-slightly-obscure-name-so-lets-pretend-they-are-actually-private variables. Whenever I wanted to define state on the instance that could be shared between the mixed in functions this was the most obvious way to do this. These aren't proper private variables, they're just normal variables pretending to be

The basic form for a mixin factory is:

    var HOP_RUN_MIXIN_FACTORY = {
        make:function( likesToHop ) {

        //  vars here and arguments passed to make are per-Class that uses the mixin
            var perClassVaraible = 'one of these per class using the mixin';


        /*  return the mixin object */
            return {
                hop:function(){   
                    if( likesToHop )
                        alert( 'yay!' );
                    else
                        alert( 'meh' );
                    // ...etc ...
                }
            ,   run:function(){
                    // ...etc ...
                }
            }

        }
    };
Then, in the classes:
var Rabbit = Class.create( HOP_RUN_MIXIN_FACTORY.make( true ),
{
    initialize:function(){
    //  ...etc...
    }
,   makeMoreRabbits:function(){
    //  ...etc...
    }
}
);

var Owl = Class.create( HOP_RUN_MIXIN_FACTORY.make( false ),
{
    initialize:function(){
    //  ...etc...
    }
,   lookArround:function(){
    //  ...etc...
    }
}
);

The point is that this can be used to create slightly different versions of mixins and provides a place to keep per-class variables inside the mixin (eg, in Java, the closest analog is private static fields).

Great code, doesn't fix it!

It'll probably be a long wait until the uber awsomeness that is CSS transitions is well supported and until then I'm using the rather lovely, if somewhat breaky, Scriptaculous (aka Scripty) to fade elements in and out. CSS would be so much nicer for this, keeping the presentation (eg, that something is fading rather than just appearing) out of the Javascript. Oh well, one day.

When you want to fade something in and out, Scripty puts a surprising amount of work put on the programmer. Two conflicting effects acting at the same time on the same element are bad. Weird, flickery things happen. So before creating the Effect.appear you have to check the object isn't already appearing or fading: If appearing do nothing. If fading, cancel fade, start appear. I found I had the code to do this in several places: obvious candidate for moving into a mixin.

So, I started to implement as a Mixin Factory, storing the appear and fade effects inside the make method, ie like the var perClassVaraible in the HOP_RUN_MIXIN_FACTORY. Humph, closures are such a powerful concept but sometimes difficult to see - since the factory method is called once per class rather than once per instantiation, this was only allowing one instance of the class to do the fade in and out thing at a time. So, back to polluting my objects with this._fade_effect and this._appear_effect.

Variation - per-instance state in the mixin

Genuine per-instance mixin variables are possible but you have to ignore Class's mixin feature and mixin manually from the initialize method:

    var Rabbit = Class.create({
            initialize:function() {
                Object.extend( this, HOP_RUN_MIXIN_FACTORY.make() );
            }
        }
    );

One interesting side-effect is that the same mixin can be used to create state per-instance or per-class depending on how the mixin is applied. Maybe useful.

Fade Mixin Factory

Here is the real code I'm using now to fade in and out, in the form of a mixin factory applied from the initialize function. As usual, this is also available from Wikizzle's subversion, which is probably a more recent and/or better version than here:

var FADE_MIXIN_FACTORY = 
{
    make:function fade_mixin_factory__make( appear_options, fade_options, element ){

        var appear_effect, fade_effect;

        appear_options = appear_options || {};
        fade_options = fade_options || {};

        appear_options.afterFinish = (appear_options.afterFinish || function(){})
            .wrap( function( proceed ){
                proceed()
                fade_effect = null;
            });

        fade_options.afterFinish = (fade_options.afterFinish || function(){})
            .wrap( function( proceed ){
                proceed();
                appear_effect = null;
            });

    /*    return the mixin we made: */
        return {

            appear: function fade_mixin__appear() {

                if( appear_effect ) {    
                    return;
                }

                if( fade_effect ) {
                    fade_effect.cancel();
                    fade_effect = null;
                }

                appear_options.owner = this;
                appear_effect = new Effect.Appear( element || this.toElement(), 
                                                   appear_options );
            }

        ,    fade: function() {

                if( fade_effect ) {
                    return;
                }

                if( appear_effect ) {
                    appear_effect.cancel();
                    appear_effect = null;
                }

                fade_options.owner = this;
                fade_effect = new Effect.Fade(  element || this.toElement(), 
                                                fade_options );
            }
        };
    }
}

Wednesday, 10 June 2009

Did I read that correctly?

'crush' is a valid rel value for HTML5?

As in, you link to the pages of people you (or whoever you're making the page for) have crushes on

Bwah?

Monday, 8 June 2009

MediaWiki Syntax highlighting

I got the chance to hack a bit over the weekend so Wikizzle's trunk now has some quite pretty syntax highlighting. Iframes in designmode make DOM events look consistent. It is by far the quirkiest of all browser features I've ever coded with. Really, really, evily quirky. "A brutal odyssey to the dark side of the DOM tree" barely sums it up. At this stage the non-highlighted code works much better. In fact, the highlighted version just shows once and never updates. Gotta start somewhere.

Tuesday, 5 May 2009

Canon MP210 on 64bit Ubuntu

This wasn't so tough but a little more difficult than I'd have liked. (I'd have liked: plug in, works)

Strangely, the only place carrying the Linux drivers is Canon Australia's driver download page. Weird, I know. But easy to find thanks to Google.

Get these four files:

  • cnijfilter-common_2.80-1_i386.deb
  • cnijfilter-mp210series_2.80-1_i386.deb
  • scangearmp-common_1.10-1_i386.deb
  • scangearmp-mp210series_1.10-1_i386.deb

The files are all for 32bit, but they seem to work ok if you force apt not to notice that:

sudo dpkg -i --force-architecture *.deb

And... that's it. Set printer up as usual and scan through The Gimp.

Is is strange that Canon but all the effort into making Linux drivers and then distribute them so badly:

  • You have to go into the command line. To install a printer. On a distro targeted at the mainstream. Not good.
  • Only Canon Australia carries the files
  • They are packaged as being 32bit only when really 64bit is fine.

This is all really odd. Stuff like this is expensive to write but (should be) cheap to distribute. I don't get it.

Thursday, 26 March 2009

More vanity postings

My friend Mike is doing his finial year in my old department. He just posted on my Facebook Wall:

Hey Jim, just come back from looking at past dissertations. And Edel Sherratt walked in and just said the best one she read was a little one called 'Wikiwyg'. And started telling us stories about the person who wrote that dissertation.

What can I say? I'm touched (Wikiwyg is the old name for Wikizzle).