l'essentiel est invisible pour les yeux

Saturday, May 20, 2006

[JavaScript]MarkUpBuilder - DOMの生成

JavascriptでのDOM生成について、調べていたところ、マークアップビルダ、存在しないメソッドの記事を見つけて、SpiderMonkey以外のJavascript実装のブラウザでも汎用的に使えるように、実装してみました。

Prototype.jsに依存しています。


var MarkupBuilder = Class.create();
MarkupBuilder.DOM = ["ul", "ol", "li", "td", "tr", "thead", "tbody", "tfoot", "table", "th",
"tbody", "input", "span", "p", "a", "div", "img", "textarea", "label", "script", "iframe"]
MarkupBuilder.cache = null;
MarkupBuilder.UA = navigator.userAgent.toLowerCase();
MarkupBuilder.prototype = {
__noSuchMethod__ : function(name, args) {
var element = document.createElement(name);
var attrs = args[0] || {};
var bMSIE = MarkupBuilder.UA.indexOf("msie") != -1;
for(var name in attrs) {
if(bMSIE && name.indexOf('on') != -1) // IE setAttribute bug
attrs[name] = new Function(attrs[name]);
else if(!bMSIE && name == "className"){
var _class = attrs[name], name = "class";
attrs[name] = _class;
}
try {
if(attrs.hasOwnProperty(name)) element.setAttribute(name, attrs[name]);
} catch(e) {throw e;}
}
for(var i=1, len=args.length;i<len;++i) {
if(args[i] instanceof Array)
for(var j=0, len2=args[i].length;j<len2;++j) element.appendChild(args[i][j]);
else
if(typeof args[i] == "string" || args[i] instanceof String) element.innerHTML += args[i];
else element.appendChild(args[i]);
}
return element;
},
initialize : function() {
if(MarkupBuilder.cache) return MarkupBuilder.cache;
if(!navigator.userAgent.match(/Gecko/)) {
var proto = $A(MarkupBuilder.DOM).inject({}, function(methods, tagName, idx) {
methods[tagName] = function() {return this.__noSuchMethod__(tagName, arguments)};
return methods;});
if(this.__proto__) this.__proto__ = proto;
else Object.extend(MarkupBuilder.prototype, proto);
}
MarkupBuilder.cache = this;
}
}

追記(2006/05/20):
・IEではsetAttributeメソッドでイベントリスナが登録できないバグに対応
・効率化のためにシングルトンにした。
・IE以外では、classNammをclassに変換。
・DOMの一次元配列を渡せるようにした
・HTMLを挿入できるようにした


使用例

var b = new MarkupBuilder();
var dom = b.div({id: "id1", className: "class1"},"divInnerText",
b.span({id: "id2", className: "class2"}, "spanInnerText"),
b.a({id: "id3", onclick: "return false;", href: ""}, "link"));

生成されるHTML

<div class="class1" id="id1">
divInnerText
<span class="class2" id="id2"> spanInnerText </span>
<a href="" onclick="return false;" id="id3"> link
</div>

SpiderMonkey系のブラウザでは、__noSuchMethod__を使用し、それ以外のブラウザではMarkupBuilderを拡張しています。
IEではobj.__proto__が使用できないので、Object.extend()を使って拡張しています。

Firefox1.5とIE6では動作確認していますが、バグがあるかもです。


追記
随分久しぶりの投稿になってしまいました。。
現在、「UIE Japan、今度は「組み込みエンジニア」募集」で紹介されているサービスを実装中です。今までに無い面白いサービスを6月末あたりにリリースしますのでお楽しみに。

JavaScriptを本格的にやり始めてから2ヶ月がたちました。
面白いですね。と言うことで、リリース予定の新しいサービスはJavaScriptゴリゴリです。