builder.
prototype.
機能の紹介
DOMを構築するときは、
var elt = document.createElement('button');
elt.setAttribute('id','hoge');
elt.onclick=doSomething
elt.appendChild(document.createTextNode('hello button'));
builder.
Builder.node('button',{id:'hoge',onclick:'doSomething()'},'hello button');
さらに便利なのは、
Builder.node('div',[
Builder.node('a',{href:'./foo.png'},
Builder.node('img',{src:'./foo.png'})),
Builder.node('a',{href:'./bar.png'},
Builder.node('img',{src:'./bar.png'}))]);
入れ子にした結果はこのようになります。
<div>
<a href="./foo.png">
<img src="./foo.png"/>
</a>
<a href="./bar.png">
<img src="./bar.png"/>
</a>
</div>
便利な機能 Builder.dump()
私がBuilder.
DIV([
A({href:'./foo.png'},
IMG({src:'./foo.png'})),
A({href:'./bar.png'},
IMG({src:'./bar.png'}))])
このショートカットモードともいうべき機能は、
Builder.node関数の使いかた
Builder.
- Builder.
node( 要素名 ) - Builder.
node( 要素名, 属性 ) - Builder.
node( 要素名, 入れ子 ) - Builder.
node( 要素名, 属性, 入れ子 )
要素名は、
属性は、
入れ子は、
この入れ子の中の配列は次のように扱われます。
Builder.node('p','foobar1']) ==
Builder.node('p',['foo','bar',1]) ==
Builder.node('p',['foo',['bar',1]]) ==
<p>foobar1</p>
このライブラリは、
DIV(['foo','bar','foobar'].map(function(x,i){
return BUTTON({onclick:"alert('" + x + i + "')"},x)}));
Builder
それでは、
0001: // script.aculo.us builder.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
0002:
0003: // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
0004: //
0005: // script.aculo.us is freely distributable under the terms of an MIT-style license.
0006: // For details, see the script.aculo.us web site: http://script.aculo.us/
0007:
1~7行目は著作権表示です。
0008: var Builder = {
0009: NODEMAP: {
0010: AREA: 'map',
0011: CAPTION: 'table',
0012: COL: 'table',
0013: COLGROUP: 'table',
0014: LEGEND: 'fieldset',
0015: OPTGROUP: 'select',
0016: OPTION: 'select',
0017: PARAM: 'object',
0018: TBODY: 'table',
0019: TD: 'table',
0020: TFOOT: 'table',
0021: TH: 'table',
0022: THEAD: 'table',
0023: TR: 'table'
0024: },
9~24行目のNODEMAPは、
0025: // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
0026: // due to a Firefox bug
0027: node: function(elementName) {
0028: elementName = elementName.toUpperCase();
0029:
0030: // try innerHTML approach
0031: var parentTag = this.NODEMAP[elementName] || 'div';
0032: var parentElement = document.createElement(parentTag);
0033: try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
0034: parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
0035: } catch(e) {}
0036: var element = parentElement.firstChild || null;
0037:
0038: // see if browser added wrapping tags
0039: if(element && (element.tagName.toUpperCase() != elementName))
0040: element = element.getElementsByTagName(elementName)[0];
0041:
0042: // fallback to createElement approach
0043: if(!element) element = document.createElement(elementName);
0044:
0045: // abort if nothing could be created
0046: if(!element) return;
0047:
0048: // attributes (or text)
0049: if(arguments[1])
0050: if(this._isStringOrNumber(arguments[1]) ||
0051: (arguments[1] instanceof Array) ||
0052: arguments[1].tagName) {
0053: this._children(element, arguments[1]);
0054: } else {
0055: var attrs = this._attributes(arguments[1]);
0056: if(attrs.length) {
0057: try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
0058: parentElement.innerHTML = "<" +elementName + " " +
0059: attrs + "></" + elementName + ">";
0060: } catch(e) {}
0061: element = parentElement.firstChild || null;
0062: // workaround firefox 1.0.X bug
0063: if(!element) {
0064: element = document.createElement(elementName);
0065: for(attr in arguments[1])
0066: element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
0067: }
0068: if(element.tagName.toUpperCase() != elementName)
0069: element = parentElement.getElementsByTagName(elementName)[0];
0070: }
0071: }
0072:
0073: // text, or array of children
0074: if(arguments[2])
0075: this._children(element, arguments[2]);
0076:
0077: return element;
0078: },
25~78行目のnodeは、
タグを作るには、
それで上手くいかなければ、 createElement法を使うようになっています。この方法は、
初期のライブラリでは単純なcreateElement法だけが使われていましたが、
30行目で、
31行目で、
32行目で、
33行目で、
36行目で、
39行目で、
40行目で、
43行目で、
46行目で、
50行目で、
53行目で、
55~71行目で、
先ほどと違うのは、
0057: try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
0058: parentElement.innerHTML = "<" +elementName + " " +
0059: attrs + "></" + elementName + ">";
createElement法ならば次のようにすることです。
0064: element = document.createElement(elementName);
0065: for(attr in arguments[1])
0066: element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
66行目で、
75行目で、
77行目で、
0079: _text: function(text) {
0080: return document.createTextNode(text);
0081: },
79~81行目の_textは、
0083: ATTR_MAP: {
0084: 'className': 'class',
0085: 'htmlFor': 'for'
0086: },
0087:
83~87行目のATTR_
0088: _attributes: function(attributes) {
0089: var attrs = [];
0090: for(attribute in attributes)
0091: attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
0092: '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'"') + '"');
0093: return attrs.join(" ");
0094: },
88~94行目の_attributesは、
91行目で、
92行目で、
{onclick:'alert("' + 'hello' + '")'}
93行目で、
0095: _children: function(element, children) {
0096: if(children.tagName) {
0097: element.appendChild(children);
0098: return;
0099: }
0100: if(typeof children=='object') { // array can hold nodes and text
0101: children.flatten().each( function(e) {
0102: if(typeof e=='object')
0103: element.appendChild(e)
0104: else
0105: if(Builder._isStringOrNumber(e))
0106: element.appendChild(Builder._text(e));
0107: });
0108: } else
0109: if(Builder._isStringOrNumber(children))
0110: element.appendChild(Builder._text(children));
0111: },
95~111行目の_children は、
96行目で、
100行目で、
101行目で、
102行目で、
105行目で、
109行目で、
0112: _isStringOrNumber: function(param) {
0113: return(typeof param=='string' || typeof param=='number');
0114: },
112~114行目の_isStringOrNumberは、
0115: build: function(html) {
0116: var element = this.node('div');
0117: $(element).update(html.strip());
0118: return element.down();
0119: },
115~119行目のbuildは、
0120: dump: function(scope) {
0121: if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
0122:
0123: var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
0124: "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
0125: "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
0126: "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
0127: "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
0128: "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
0129:
0130: tags.each( function(tag){
0131: scope[tag] = function() {
0132: return Builder.node.apply(Builder, [tag].concat($A(arguments)));
0133: }
0134: });
0135: }
0136: }
120~136行目のdumpは、
132行目からわかるように、