Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #7476 (closed enhancement: fixed)

Opened 2 years ago

Last modified 2 years ago

[PATCH] Simple DOM builder

Reported by: mislav Assigned to: sam
Priority: low Milestone: 1.x
Component: Prototype Version: edge
Severity: minor Keywords: 1.5.2 discuss
Cc: haraldmartin, Tobie

Description

Intuitive API:

$E('h1', 'Giant squirrel attacks Boston', { id:'myheading' })

Lightweight implementation:

Element.create = function(el){
  if (typeof el == 'string') el = document.createElement(el);
  Element.extend(el);

  // add children (if given)
  for (var i = 1, length = arguments.length; i < length; i++)
    arguments.callee.add(el, arguments[i]);

  return el;
}
Element.create.add = function(el, child){
  if (!child) return;
  var _method = arguments.callee;

  switch (typeof child) {
  case 'object':
    if (child.nodeType) el.appendChild(child);
    else if (child.constructor == Array)
      child.flatten().each(function(subitem){ _method(el, subitem) });
    else $H(child).each(function(pair){
      el.setAttribute(pair.key, pair.value)
    });
    break;
  case 'string':
    el.appendChild(document.createTextNode(child)); break;
  case 'function':
    _method(el, child()); break;
  }
}

var $E = Element.create;

What might not be obvious:

  • flattens arrays and adds their elements
  • calls functions

Attachments

builder.diff (2.6 kB) - added by mislav on 02/03/07 17:22:20.
new_element_write_attributes.diff (6.3 kB) - added by haraldmartin on 03/14/07 23:38:12.
new Element() and Element#writeAttributes patch
new_element_write_attributes_with_ie_name_fix.diff (6.6 kB) - added by haraldmartin on 03/15/07 09:29:32.
with workaround for IEs "name" attribute
new_element_write_attribute.diff (6.6 kB) - added by haraldmartin on 03/15/07 21:35:06.
make method name singular (writeAttributes → writeAttribute) to be consistant with readAttribute and setStyle
new_element_and_write_attribute_nohash.txt (7.0 kB) - added by haraldmartin on 03/16/07 00:12:44.
writeAttribute will now either accept two parameters (name and value) or a hash with attributes. Name & value arguments were added so the method can work like the native setAttribute
new_element_and_write_attribute_nohash.diff (7.1 kB) - added by haraldmartin on 03/16/07 21:19:40.
fixed a bug in ie where calling new Element without an attribute hash
newElement.diff (13.6 kB) - added by Tobie on 04/30/07 08:30:10.
writeAttribute now handles for, style, class and checked

Change History

02/03/07 17:22:20 changed by mislav

  • attachment builder.diff added.

02/06/07 14:46:47 changed by mislav

Martin Ström has a proposition:

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

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);

03/14/07 23:38:12 changed by haraldmartin

  • attachment new_element_write_attributes.diff added.

new Element() and Element#writeAttributes patch

03/14/07 23:53:56 changed by haraldmartin

  • cc set to haraldmartin.
  • keywords changed from DOM to DOM builder.

I've added code and tests for the DOM builder I suggested on the ML. One should now be able to create elements using

var myElement = new Element('div', {id: 'another_element'});

and set any element's attribute(s)

myElement.writeAttributes({href: '/dev/null', title: 'hello'});

The booleans attributes (e.g. readonly and checked) get special treatment and let you set their value using false or true keyword. Passing a null or false value will remove the attribute completly (see the source for more details)

input.writeAttributes({readonly: true}).readAttribute('readonly');  => 'readonly'
input.writeAttributes({readonly: false}).readAttribute('readonly'); => null
input.writeAttributes({readonly: null}).readAttribute('readonly');  => null

More information in the unit tests.

The code around new Element construction is because Firefox already defined a window.Element object and we don't want to overwrite it but instead extend the new Element object with the old values.

Should we work around IE's name attribute discussed http://groups.google.com/group/prototype-core/msg/38cdf071c8431a43?hl=en& here?

Passing tests for IE6, IE7, Opera 9, Safari 2 and Firefox 1-2.

03/15/07 09:29:32 changed by haraldmartin

  • attachment new_element_write_attributes_with_ie_name_fix.diff added.

with workaround for IEs "name" attribute

(follow-up: ↓ 4 ) 03/15/07 09:33:10 changed by haraldmartin

Added a new patch with code and test for dynamically creation of elements with the "name" attribute in IE.

(in reply to: ↑ 3 ) 03/15/07 17:21:54 changed by tomg

Replying to haraldmartin:

Added a new patch with code and test for dynamically creation of elements with the "name" attribute in IE.

I like how compact this change is, but I worry that it relies on Prototype.Browser.IE--if a browser is misidentified (e.g. a compatibility script creating window.attachEvent function, which is how Prototype.Browser.IE is calculated) it could cause this function to fail. I prefer try/catch, because it works without the dependency on an external value.

03/15/07 20:47:25 changed by mislav

if some script defines window.attachEvent then Builder would be the smallest problem for the user :)

03/15/07 21:35:06 changed by haraldmartin

  • attachment new_element_write_attribute.diff added.

make method name singular (writeAttributes → writeAttribute) to be consistant with readAttribute and setStyle

03/16/07 00:12:44 changed by haraldmartin

  • attachment new_element_and_write_attribute_nohash.txt added.

writeAttribute will now either accept two parameters (name and value) or a hash with attributes. Name & value arguments were added so the method can work like the native setAttribute

03/16/07 21:19:40 changed by haraldmartin

  • attachment new_element_and_write_attribute_nohash.diff added.

fixed a bug in ie where calling new Element without an attribute hash

04/28/07 09:23:26 changed by Tobie

  • cc changed from haraldmartin to haraldmartin, Tobie.
  • keywords changed from DOM builder to 1.5.2 discuss.

(follow-up: ↓ 8 ) 04/28/07 13:44:17 changed by Tobie

Benchmarks (iterating over the whole array of XHTML elements 5 times (i.e. 1 x createElement & 4 x cloneNode):

in IE 6:

Info: Operation finished 5 iterations in 0.060s // NEW
Info: Operation finished 5 iterations in 0.621s

in Firefox 2:

info: Operation finished 5 iterations in 0.036s // NEW
info: Operation finished 5 iterations in 0.061s

(in reply to: ↑ 7 ) 04/29/07 21:42:02 changed by haraldmartin

Great work with the speed optimization Tobie

04/29/07 21:44:54 changed by Tobie

Thanks!

04/29/07 21:45:45 changed by Tobie

And thanks for your brilliant work on this. I'm loving it!

04/30/07 08:30:10 changed by Tobie

  • attachment newElement.diff added.

writeAttribute now handles for, style, class and checked

05/12/07 05:02:00 changed by sam

  • status changed from new to closed.
  • resolution set to fixed.

(In [6725]) Merge -r6634:HEAD from ../branches/dom.

* Make Element#update and Element#insert work for SELECT tags in IE and Opera. [Tobie Langel]

* Make Element#insert and Element#update better handle TABLE related elements in IE and Opera. Closes #7776, #8040, #7550, #7776, #7938. [Tobie Langel]

* Make Element#readAttribute('title') work in Opera. [Tobie Langel]

* Make Element#replace work with form elements in Firefox and Safari. Closes #8010, #7989. [dsl239, Tobie Langel]

* Add Element#wrap which wraps the element inside a new one. Closes #5732. [P. Vande, Tobie Langel]

* Make Element into a constructor: new Element(tagName, attributes). Add Element#writeAttribute which accepts a hash of attributes or a name/value pair. Closes #7476. [Mislav Marohni?\196?\135, haraldmartin, Tobie Langel]

* Insertion overhaul: Add Element.insert(content[, position = 'Bottom']). Deprecate Insertion (kept for backwards compatibility). Make Ajax.Updater option.insertion accept both Insertion.Top or the now preferred 'Top'. Closes #7907. [Tobie Langel]