DOM builder in Prototype core?

28 views
Skip to first unread message

Mislav Marohnić

unread,
Feb 3, 2007, 1:37:19 PM2/3/07
to prototy...@googlegroups.com
I just submitted a simple DOM builder enhancement [1]. The framework is currently strong on DOM manipulation, but for content updates it only relies on innerHTML. What I always use in my projects is a simple wrapper around createElement() and appendChild() DOM methods - recently I though it would make a nice addition to the core.

Other DOM builders out there are script.aculo.us' [2], which is IMO too big for core (what are those hacks for, anyway?); Vivabit DOM builder [3] (original blog post currently unavailable); and Mochikit DOM [4], which is huge and full-featured but we don't really need most of it.

Personally I think Dan's approach is most "Prototypish" and it also generated a lot of blog buzz when it came out - it was exactly what most of the people needed. Mine is similar, but without th e method creation feature: no html.DIV() or html.INPUT(), just plain ol' string arguments.

var form = $E('form',
  $E('div',
   
$E('input', {type : 'text', name : 'email'}),
   
$E('input', {type : 'text', name : 'password'}),
   
$E('input', {type : 'submit'})
  )
);

What do you think? Do you need it? Does it belong to core? If so, what approach should we take?

--
Mislav

p.s. my patch in Trac still lacks attribute fixes for IE, I'm quite aware of that... right now it's just proof of concept ;)


[1] http://dev.rubyonrails.org/tic
ket/7476
[2] http://dev.rubyonrails.org/browser/spinoffs/scriptaculous/src/builder.js
[3] http://ajaxian.com/archives/dom-builder-a-nicer-dom
[4] http://mochikit.com/doc/html/MochiKit/DOM.html

Thomas Fuchs

unread,
Feb 3, 2007, 3:33:04 PM2/3/07
to prototy...@googlegroups.com

Am 03.02.2007 um 19:37 schrieb Mislav Marohnić:

> Other DOM builders out there are script.aculo.us' [2], which is IMO
> too big for core (what are those hacks for, anyway?);

Mostly for browser bugs, many of which may have been fixed in newer
browser versions. FF and IE both had very strange (and different)
issues, iirc. See the unit tests for builder.js for more on this.

Anyway, I'm not sure if we need a DOM Builder in Prototype core, though.

I find myself using it for only a very few special occasions, as IMHO
HTML is something the server should provide (as web dev frameworks
should be good at generating HTML), and that's also one of the
central things around Rails RJS templates.

YMMV, but that approach allows for having to write less JavaScript. :)

Best,
Thomas

Colin Mollenhour

unread,
Feb 3, 2007, 5:17:03 PM2/3/07
to Prototype: Core
> What do you think? Do you need it? Does it belong to core? If so, what
> approach should we take?

I personally use Builder.node quite a bit and find it very
convenient. I like the lightweight-ness of your solution but by the
time you add in the special cases it will have grown quite a bit I
think.

$E({
div: {
table: { attributes: {id: style: className: },
tr: {
}
}
}
})

Colin Mollenhour

unread,
Feb 3, 2007, 5:29:29 PM2/3/07
to Prototype: Core
I accidentally sent that last message.. was playing around with
different API possibilities and hit tab and space and sent it... oops.

Anyway, yeah, I like the idea but would like to see something that is
syntactically prettier. I don't know what that would look like
exactly, but perhaps some data structure to replace the nested
function calls?

Could you explain your "calls functions" feature?

Thanks,
Colin

Tobie Langel

unread,
Feb 3, 2007, 5:56:50 PM2/3/07
to Prototype: Core
Sam's proposition for changing element update (see basecamp: http://
rails.updatelog.com/projects/279620/msg/cat/1905466/3314374/comments)
doubles the functionality of a DOM builder IMO.

Martin Ström

unread,
Feb 5, 2007, 7:19:44 AM2/5/07
to prototy...@googlegroups.com
I was just about to submit a patch to trac so instead I bring it up
here for discussion.
Since we already have the Builder in script.aculo.us I don't think is
necessary to bring an advanced builder into core. I've been using this
code in my recent project and it is lightweight and reads out very
well.

First we add Element.writeAttributes (or whatever it should be named
but since we already have readAttribute I thought this name should
match) to let chaining works when settings an element's attribute(s):

Element.addMethods({
// ...
writeAttributes: function(element, properties) {
element = $(element);
for (var property in properties)
element[property] = properties[property];
return element;
},
// ...
});

Then replace the current:
var Element = new Object();

with something like:

function Element(tagName, options) {
return Element.extend(document.createElement(tagName)).writeAttributes(options
|| {});
}

This way it would be really easy to create new elements when you don't
need the full functionallity from Builder with all it's fixes and
tweaks:

var myHeader = new Element('div', {id: 'header'});
$('container').appendChild(myHeader);

What do you think? I would happily provide a patch with tests if you
like this approach.

Btw, is there any way to view Sam's proposition for us without account
on the rails basecamp site?


--
burnfield.com/martin

Mislav Marohnić

unread,
Feb 5, 2007, 7:43:33 AM2/5/07
to prototy...@googlegroups.com
Wow, Martin. That is nice :D

Martin Ström

unread,
Feb 6, 2007, 8:40:59 AM2/6/07
to prototy...@googlegroups.com
Thanks
What do you other guys think, are you interested in a patch with test
or would it just be a waste of time? :)

Martin


--
burnfield.com/martin

Andrew Dupont

unread,
Feb 6, 2007, 9:18:04 AM2/6/07
to Prototype: Core
On Feb 6, 3:40 pm, "Martin Ström" <martinstromli...@gmail.com> wrote:
> What do you other guys think, are you interested in a patch with test
> or would it just be a waste of time? :)

Martin, I like your implementation a lot (especially the
Element.writeAttributes idea, which I think should be added no matter
what) but it's missing two things I like most about Dan Webb's
DOMBuilder:

* Tags as method names. Much easier to do x.DIV(foo, bar) than to do
new Element("div", foo, bar).
* Easy nesting (like "x.DIV( x.P ( x.SPAN() ) )"). DOMBuilder
responds differently based on the number and types of arguments
passed.

I think both these things are critical, or else there's little
advantage over the native DOM methods. Others may feel differently,
though.

Mislav Marohnić

unread,
Feb 6, 2007, 9:56:49 AM2/6/07
to prototy...@googlegroups.com
Andrew: that two features bring us back to Dan's or mine implementations and take out the lightweightness of Martin's elegant solution.

Martin: by all means, submit a patch with tests on the already existing ticket:
http://dev.rubyonrails.org/ticket/7476#comment:1

Doing so will enable easy reviewing and comparing.

-m

Tom Gregory

unread,
Feb 6, 2007, 11:08:24 AM2/6/07
to prototy...@googlegroups.com
While I love the simplicity of the function, there is one workaround that I think needs to be considered.  IE does not allow the 'name' attribute to be changed after createElement() is called.

To quote MSDN: "The NAME attribute cannot be set at run time on elements dynamically created with the createElement method."

Workarounds have been posted here:

May I suggest the following:

function Element(tagName, options) {
var el = null;
if (options.name) {
try {
document.createElement('<'+ tagName +' name="'+options.name+'">');
delete options.name;
} catch () {} //fails if not IE
}
el = el  || document.createElement(tagName)); //create if null


        return Element.extend(el).writeAttributes(options || {});
}


TAG

Siegfried Puchbauer

unread,
Feb 6, 2007, 11:23:21 AM2/6/07
to prototy...@googlegroups.com
I had to build a dynamic form and I liked the "new Element" approach .... so I hacked together a litte protoype.ext script which allowed it for me...

A very important thing, IMO, is to provide Insertion (bottom, top, before, after) for dom content (Insertion.* works ony for text)

The script (tested in IE7 & FF2):
----------------------------------------------
var _Element = Element;

Element =  function(tag, attributes, childs) {
        if(!!attributes &&
            (typeof attributes == 'string' || typeof attributes == 'number' ||
            attributes.nodeType == 1 || typeof attributes.length != 'undefined')){
            childs = attributes;
            attributes = {};
        }
        var el = Element.extend(document.createElement(tag)).writeAttributes(attributes || {});
        if(childs) el.insert(childs);
        return el;
    };

Object.extend(Element, _Element);

Abstract.Insertion.prototype._initialize = Abstract.Insertion.prototype.initialize;
Abstract.Insertion.prototype.initialize = function(element, content) {   
    this.element = $(element);
    if(typeof content == 'number') this._initialize(element, content.toString());
    else if(typeof content == 'string') this._initialize(element, content);
    else this.insertContent([content].flatten());
};

Element.addMethods({
    insert: function(element, child, position) {
        var pos = (position || 'bottom').capitalize();
        new Insertion[pos](element, child);
        return element;
    },
    injectInto: function(element, destination, position) {
        $(destination).insert(element, position);
        return element;
    },
    insertBefore: function(element, newSibling) {
        return $(element).insert(newSibling, 'before');
    },
    insertAfter: function(element, newSibling) {
        return $(element).insert(newSibling, 'after');
    },
    insertTop: function(element, child) {
        return $(element).insert(child, 'top');
    },
    writeAttributes: function(element, attributes) {
        element = $(element);
        for (var att in attributes)
            element[att] = attributes[att];
        return element;
    }
});

Element.TAGS = "a abbr acronym address applet area b base basefont bdo big blockquote body " +
      "br button caption center cite code col colgroup dd del dfn dir div dl dt em fieldset " +
      "font form frame frameset h1 h2 h3 h4 h5 h6 head hr html i iframe img input ins isindex "+
      "kbd label legend li link map menu meta noframes noscript object ol optgroup option p "+
      "param pre q s samp script select small span strike strong style sub sup table tbody td "+
      "textarea tfoot th thead title tr tt u ul var";

Element.create = function(tag, attributes, childs) {
    return new Element(tag, attributes, childs);
}

Element.Builder = Class.create();     
Object.extend(Element.Builder.prototype ,{
    initialize: function(tags) {
        this.tags = tags || Element.TAGS;
       
        $w(this.tags).each(function(tag) {
              this[tag] = Element.create.bind(this, tag);
          }.bind(this));
    }
});

-------------------------------------------------------

It allows you to do things  like:

var x = new Element('div').addClassName('test'); // Creates new div element and adds a classname
$('myelement').insert(x); // appends the element in "myelement"

$('myelement').insert(new Element('h1'), 'top'); // Invokes Insertion.Top

var html = new Element.Builder();

with(html) {
var node = ul({className: 'test'}, [ li('First'), li('Second'), li('third')]).hide().injectInto(document.body, 'top');
new Effect.Appear (node);
}

...

brgds, sigi

On 2/6/07, Andrew Dupont <goo...@andrewdupont.net> wrote:

Andrew Dupont

unread,
Feb 6, 2007, 11:41:07 AM2/6/07
to Prototype: Core
Actually, I withdraw my objection, since someone could write an add-on
script that wraps around Martin's approach.

Martin, keep in mind that Element.writeAttributes will need to make
the same accommodations for IE as Element.readAttribute. Tobie and I
know all too much about this, so let us know if you want help.

Cheers,
Andrew

On Feb 6, 4:56 pm, "Mislav Marohnić" <mislav.maroh...@gmail.com>
wrote:

Martin Ström

unread,
Feb 6, 2007, 12:18:43 PM2/6/07
to prototy...@googlegroups.com
Exacly my point. This shouldn't be seen as a replacement for a more
robust solution like the one earlier in this thread or the existing
Builder but more of a document.createElement-wrapper.

I'll submit a patch asap!

Ciao
martin


--
burnfield.com/martin

Justin Palmer

unread,
Feb 6, 2007, 8:06:59 PM2/6/07
to Prototype: Core
Just casting my vote for the solution Martin proposed. Simple and to
the point.

-Justin

On Feb 6, 11:18 am, "Martin Ström" <martinstromli...@gmail.com> wrote:
> Exacly my point. This shouldn't be seen as a replacement for a more
> robust solution like the one earlier in this thread or the existing
> Builder but more of a document.createElement-wrapper.
>
> I'll submit a patch asap!
>
> Ciao
> martin
>

Christophe Porteneuve

unread,
Feb 7, 2007, 2:37:23 AM2/7/07
to prototy...@googlegroups.com
Justin Palmer a écrit :

> Just casting my vote for the solution Martin proposed. Simple and to
> the point.

Yup, +1. I like the weightlessness of it. We'll have to stress that it
plays a lighter game than script.aculo.us' Builder though, so people
don't think one replaces the other entirely.

--
Christophe Porteneuve a.k.a. TDD
"[They] did not know it was impossible, so they did it." --Mark Twain
Email: t...@tddsworld.com

Dan Webb

unread,
Feb 20, 2007, 5:10:24 AM2/20/07
to Prototype: Core

>
> > Just casting my vote for the solution Martin proposed. Simple and to
> > the point.
>

Sorry for joining this discussion really late but after fielding all
the bug reports for DOMBuilder (and using it heavily myself) it has to
be said that this solution definitely isn't going to cut it. In fact
I think adding it in is going to be destructive.

The thing is is that there's loads of cross browser problems with
setting attributes (as mentioned previously) and working around at
least the common problems with a tool like this is essential otherwise
your just going to end up sending developers on huge bug hunts almost
every time they use it which is no help to anyone really. For
instance, really common attributes like class, for, style, name etc
all work unpredicable across browsers so if people try to use this
they'll very quickly realise that its problematic and end up dropping
it so the end result is that you've just given the developer the run
around. Im not saying a solution like this needs to be cover every
single little bug but it should cover the common ones.

Besides that, in terms of syntaxic sugar Martin's solution, although
very compact in implementation, doesn't buy the developer much and
since a DOM builder is all about facilitating building none trivial
DOM structures with readable code it seems a little redundant. new
Element('div', ....) then creating all the childNodes and appending
each is just not much better than document.createElement().

It's not been mentioned yet but theres a slightly updated version of
my DOM Builder in Low Pro and instead of using the apply stuff it
creates the functions with a $ prefixed which I thought was more
Prototypish. $span, $div etc. It also does fix the most common bugs
(but not as much as the scriptaculous version which is very thorough)
and is pretty small. Predictably, my vote would go for my version :)

http://svn.danwebb.net/external/lowpro/trunk/src/dom.js

On the point of whether its worth including a DOM builder at all I'm
not sure. I use it heavily as do many scripters who code
unobtrusively. The common use case is that the flat page HTML should
not include any markup that is used to scaffold javascript operations
so that if its an old/firewalled/mobile/fucked up browser then the
page isn't filled with loader graphics (which is my pet hate :) and
random elements which often render the UI unusable. If the script
runs correctly then a DOM builder can be used to add in any extra
markup needed for the script to work.

At the moment Prototype isn't strong on supporting unobtrusive code
and although, obviously, I'd like to see it do so I'm also fine with
the fact that it's coded with another opinion in mind and maybe
pulling it in both directions is just going to bloat it.

Andrew Dupont

unread,
Feb 20, 2007, 11:14:53 PM2/20/07
to Prototype: Core

On Feb 20, 4:10 am, "Dan Webb" <danwr...@gmail.com> wrote:
> The thing is is that there's loads of cross browser problems with
> setting attributes (as mentioned previously) and working around at
> least the common problems with a tool like this is essential otherwise
> your just going to end up sending developers on huge bug hunts almost
> every time they use it which is no help to anyone really. For
> instance, really common attributes like class, for, style, name etc
> all work unpredicable across browsers so if people try to use this
> they'll very quickly realise that its problematic and end up dropping
> it so the end result is that you've just given the developer the run
> around. Im not saying a solution like this needs to be cover every
> single little bug but it should cover the common ones.

The groundwork for managing these special cases has already been laid
with the work Tobie and I did on Element.readAttribute. "Class" and
"for" are easily translated into their necessary "className" and
"htmlFor" in IE. "Name" can be set in the document.createElement call
the way DOMBuilder does. And I think "style" is an edge case that
doesn't really concern me too much.

I'm sure there will be other speed bumps, but I don't think the
tyranny of the edge case is enough to hold this idea down.

> Besides that, in terms of syntaxic sugar Martin's solution, although
> very compact in implementation, doesn't buy the developer much and
> since a DOM builder is all about facilitating building none trivial
> DOM structures with readable code it seems a little redundant. new
> Element('div', ....) then creating all the childNodes and appending
> each is just not much better than document.createElement().

This is a point I raised earlier in the thread, but later withdrew.
Martin's solution is not intended to be a replacement of something
like DOMBuilder, but rather an intermediate step toward it.

> It's not been mentioned yet but theres a slightly updated version of
> my DOM Builder in Low Pro and instead of using the apply stuff it
> creates the functions with a $ prefixed which I thought was more
> Prototypish. $span, $div etc. It also does fix the most common bugs
> (but not as much as the scriptaculous version which is very thorough)
> and is pretty small. Predictably, my vote would go for my version :)
>
> http://svn.danwebb.net/external/lowpro/trunk/src/dom.js

I'm conflicted about this. I realize that DOM building convenience
methods are only convenient when the names are short, but at the same
time I worry about dropping into the $ namespace the namess of all
elements used in HTML4.

Thomas Fuchs

unread,
Feb 21, 2007, 4:44:19 AM2/21/07
to prototy...@googlegroups.com

Am 21.02.2007 um 05:14 schrieb Andrew Dupont:

>> It's not been mentioned yet but theres a slightly updated version of
>> my DOM Builder in Low Pro and instead of using the apply stuff it
>> creates the functions with a $ prefixed which I thought was more
>> Prototypish. $span, $div etc. It also does fix the most common bugs
>> (but not as much as the scriptaculous version which is very thorough)
>> and is pretty small. Predictably, my vote would go for my version :)
>>
>> http://svn.danwebb.net/external/lowpro/trunk/src/dom.js
>
> I'm conflicted about this. I realize that DOM building convenience
> methods are only convenient when the names are short, but at the same
> time I worry about dropping into the $ namespace the namess of all
> elements used in HTML4.


Note that the script.aculo.us DOM builder has this as an option, you
can choose to have the shortcuts, either globally or added to an
object of your choice.

See http://dev.rubyonrails.org/browser/spinoffs/scriptaculous/test/
unit/builder_test.html#L191 ff

The Builder.dump() call creates the TAGNAME() shortcuts.

best,
thomas

Martin Ström

unread,
Mar 14, 2007, 9:27:05 AM3/14/07
to prototy...@googlegroups.com
I finally got some time to write the code for new Element() and
Element#writeAttributes. I had some thoughts/question regarding this
and thought I bring it up here for discussion.

My patch right now will allow one to set the boolean attributes (e.g.
checked, disabled, readonly & multiple) using the 'true' keyword since
that seems to make most sense:

element.writeAttributes({readonly: true});

in opposite of setting it to the attribute name:

element.writeAttributes({readonly: 'readonly'});

which is the way you would do it in (x)html:

<input type="test" readonly="readonly">

Do you think it should work like the first one or isn't it necessary
to respect these kind of things?

The same when setting false values. #writeAttributes will not use
#setAttribute if the value is an empty string or 'false' for booleans
attributes. Instead it will use #removeAttribute and therefore make
#readAttribute return null which I believe is how you would expect it
to work:

element.writeAttributes({readonly: false}).readAttribute('readonly')
=> null // boolean attributes
element.writeAttributes({src: ''}).readAttribute('src') => '' //
normal attributes

What do you think?

Btw, great work with the 1.5.1 release, the new Selector (and the
other stuff as well of course) is really awesome. Thanks!

Martin


--
burnfield.com/martin

Mislav Marohnić

unread,
Mar 14, 2007, 10:34:41 AM3/14/07
to prototy...@googlegroups.com
On 3/14/07, Martin Ström <martinst...@gmail.com> wrote:

What do you think?

Seems nice to me. Not everything has to be strict :)

The only problem now remains IE and its read-only attributes like "name" ... If only it weren't for that :(

Martin Ström

unread,
Mar 14, 2007, 1:08:40 PM3/14/07
to prototy...@googlegroups.com
I think I have the patch ready and will submit it asap to trac.
Actually my tests to create an input element and set it's name
attribute using #writeAttributes worked fine (both IE6 and IE7) but
maybe I didn't trigger the bug correctly.


--
burnfield.com/martin

Martin Ström

unread,
Mar 14, 2007, 8:01:32 PM3/14/07
to prototy...@googlegroups.com
FYI: tests and code are now submitted to trac:
http://dev.rubyonrails.org/ticket/7476#comment:2

If i missed any of the attribute fixes for IE or any other issue, feel
free to correct me or my patch :)

On 3/14/07, Martin Ström <martinst...@gmail.com> wrote:
> I think I have the patch ready and will submit it asap to trac.
> Actually my tests to create an input element and set it's name
> attribute using #writeAttributes worked fine (both IE6 and IE7) but
> maybe I didn't trigger the bug correctly.
>
> On 3/14/07, Mislav Marohnić <mislav....@gmail.com> wrote:
> > On 3/14/07, Martin Ström <martinst...@gmail.com> wrote:
> > >
> > > What do you think?
> >
> > Seems nice to me. Not everything has to be strict :)
> >
> > The only problem now remains IE and its read-only attributes like "name" ...
> > If only it weren't for that :(
> >
> >
> > > >
> >
>
>
> --
> burnfield.com/martin
>


--
burnfield.com/martin

Kjell Bublitz

unread,
Mar 14, 2007, 8:48:52 PM3/14/07
to prototy...@googlegroups.com
Wee. This is very well done. Thanks martin and please submit this. It's lovely

On 2/5/07, Martin Ström <martinst...@gmail.com> wrote:
>


--
Regards, Kjell
www.m3nt0r.de

Mislav Marohnić

unread,
Mar 15, 2007, 8:42:44 AM3/15/07
to prototy...@googlegroups.com
On 3/15/07, Martin Ström <martinst...@gmail.com> wrote:
FYI: tests and code are now submitted to trac:
http://dev.rubyonrails.org/ticket/7476#comment:2

Nice! This is a very solid foundation for a more featured Builder (IMO). 

But, I would rename writeAttributes to setAttributes for consistency with setStyle (which also takes a hash).

Tobie Langel

unread,
Mar 15, 2007, 10:39:12 AM3/15/07
to Prototype: Core
I'd favor writeAttribute to be consistant with readAttribute... and
setStyle (which is not pluralized).

Some heated debate in perspective!

On Mar 15, 8:42 am, "Mislav Marohnić" <mislav.maroh...@gmail.com>
wrote:

Mislav Marohnić

unread,
Mar 15, 2007, 4:41:35 PM3/15/07
to prototy...@googlegroups.com
On 3/15/07, Tobie Langel <tobie....@gmail.com> wrote:

I'd favor writeAttribute to be consistant with readAttribute... and
setStyle (which is not pluralized).

Good point.

Martin Ström

unread,
Mar 15, 2007, 5:27:19 PM3/15/07
to prototy...@googlegroups.com
Yes, good point, I update the patch.

On 3/15/07, Tobie Langel <tobie....@gmail.com> wrote:
>

> I'd favor writeAttribute to be consistant with readAttribute... and
> setStyle (which is not pluralized).
>
> Some heated debate in perspective!
>

> On Mar 15, 8:42am, "Mislav Marohnić" <mislav.maroh...@gmail.com>


> wrote:
> > On 3/15/07, Martin Ström <martinstromli...@gmail.com> wrote:
> >
> >
> >
> > > FYI: tests and code are now submitted to trac:
> > >http://dev.rubyonrails.org/ticket/7476#comment:2
> >
> > Nice! This is a very solid foundation for a more featured Builder (IMO).
> >
> > But, I would rename writeAttributes to setAttributes for consistency with
> > setStyle (which also takes a hash).
>
>
> >
>


--
burnfield.com/martin

Andrew Dupont

unread,
Mar 15, 2007, 5:31:55 PM3/15/07
to Prototype: Core

On Mar 15, 9:39 am, "Tobie Langel" <tobie.lan...@gmail.com> wrote:
> I'd favor writeAttribute to be consistant with readAttribute... and
> setStyle (which is not pluralized).
>

The issue here is that each attribute is a separate unit, whereas you
could argue that each of the properties you pass to setStyle is just
part of the overall "style" of the element.

Anyway, I'm not about to get us on a semantics tangent. But if we
call it writeAttribute, people will expect it to behave like
setAttribute (the way readAttribute behaves like getAttribute). So
let's write it so that you can pass in either two string arguments or
one hash of attributes.

Cheers,
Andrew

Mislav Marohnić

unread,
Mar 15, 2007, 5:50:39 PM3/15/07
to prototy...@googlegroups.com
On 3/15/07, Andrew Dupont <goo...@andrewdupont.net> wrote:

The issue here is that each attribute is a separate unit, whereas you
could argue that each of the properties you pass to setStyle is just
part of the overall "style" of the element.

Hmm, also a very good point.

(damn, I'm so easily manipulated=

Martin Ström

unread,
Mar 15, 2007, 8:20:31 PM3/15/07
to prototy...@googlegroups.com
> let's write it so that you can pass in either two string arguments or
> one hash of attributes.
>

Done! The patch on trac is updated to support both way (parameters or hash).

Ciao
Martin

Reply all
Reply to author
Forward
0 new messages