2008年 01月 21日

ノード生成関数

みじかめで、よさそうなのを書こうとしているけどわりとびみょうだなぁ http://subtech.g.hatena.ne.jp/cho45/20071117/1195309573 をもとにしてj

function $N (str, childs) {
	if (str.nodeType) return str;
	var t, cur, stack = [cur = document.createDocumentFragment()];
	while (str.length) {
		if (str.indexOf("<") == 0) {
			if (t = str.match(/^\s*<(\/?[^\s>\/]+)([^>]+?)?(\/)?>/)) {
				var tag = t[1], attrs = t[2], isempty = !!t[3];
				if (tag.indexOf("/") == -1) {
					child = document.createElement(tag);
					if (attrs) attrs.replace(/([a-z]+)=(?:'([^']*)'|"([^"]*)")/gi,
						function (m, name, v1, v2) {
							child.setAttribute(name, v1 || v2);
						}
					);
					cur.appendChild(child);
					if (!isempty) {
						stack.push(cur);
						cur = child;
					}
				} else cur = stack.pop();
			} else throw("Parse Error: " + str);
		} else if (t = str.match(/^([^<]+)/)) cur.appendChild(document.createTextNode(t[0]));
		str = str.substring(t[0].length);
	}
	var ret = stack.pop();
	if (ret.childNodes.length == 1) ret = ret.firstChild;
	if (childs) for (var i = 0; i < childs.length; i++) {
		ret.appendChild(arguments.callee(childs[i]));
	}
	return ret;
}

みたいなのにしてみた (innnerHTML は table 関係の要素を扱うとき、補完とかされてかえってめんどうくさい。)

	document.body.insertBefore(
		$N("<div/>", [
			"<p>aaa<em>foobar</em></p>",
			document.createElement("br"),
			"<p><a href=''>foobar</a></p>",
		]),
		document.body.firstChild
	);

みたいにする。文字列だけあつかえてもあんまり嬉しくないので、DOM オブジェクトを混在させてもいいように

ただ、あんまり読みやすくない。jQuery みたいなのはいいんだけど、特殊なオブジェクトをつくって DOM の基本メソッドを全部実装しないといけないから長くなる……