HTMLBuilder

HTMLBuilderとは

最終更新
2003-11-18T22:09:44+09:00

JavaScriptによるHTMLの省略記法、js-html で書かれたデータを、実際のHTML形式に変換する為のクラスです。当然JavaScript製。

状態

最終更新
2003-11-25T21:06:51+09:00

2003-11-17 現在:

  • document.write用のStringオブジェクトの生成
  • DOM Level 1 を利用した生成
  • DOM Level 1 とLevel 2 Event を利用した生成

以上に対応しています。

ソースコード

最終更新
2003-12-06T13:43:30+09:00
  • 2003-11-30 欠陥を修正しました(createTextNode => createComment)
  • 2003-12-06 継承しやすいよう表記法を変更しました(prototype書き換えの廃止)

if(!Array.prototype.push)
	Array.prototype.push = function(item){ this[length] = item; };
function HTMLBuilder(DOMImplementation){
	/* Class for helping to make a fragment of HTML.

	Copy left. Comment? Sophisme w650s@mcn.ne.jp

	Tipical Usage:
	ex 1) with DOM level 0:
		var tree = { h2: "Heading2", $attrs: { id: "d20031110" } }
		var builder = new HTMLBuilder();
		builder.setLevel(0);
		builder.feed(tree);
		var fragment = builder.build(); // String object (HTML source)
		document.write(fragment);
		=> <h2 id="d20031110">Heading2</h2>

	ex 2) with DOM level 1:
		var tree2 = { ul: [ {li: "item1"}, {li: "item2"} ] };
		builder.setLevel(1);
		builder.feed(tree2);
		var dfUL = builder.build(); // DocumentFragment object
		DOMElement.appendChild(dfUL);
		=> <ul><li>item1</li><li>item2</li></ul>
	
	ex 3) with light hand:
		var tree3 = { br: null };
		var br = builder.build(tree3, 0);
		document.write(br);
		=> <br />
		
	ex 4) with DOM level 2 Event
		var tree4 = {
			button: "test", $attrs: { onclick: function(){alert(0)} }
		}
		builder.setLevel(2)
		var dfButton = builder.build(tree4); // DocumentFragment object
		=> <button onclick="alert(0)">test</button>
	*/

	this._infoset = undefined;
	this._level = undefined;
	this._impl = DOMImplementation? // for forward compatibility.
		DOMImplementation : document.implementation;
	
}

(function(){
	var $ = HTMLBuilder.prototype;

	$.setInfoset = function(infoset){
		this._infoset = infoset; };

	$.getInfoset = function(){
		return this._infoset; };

	$.setLevel = function(dom_level){
		this._level = isNaN(dom_level)? this.inferLevel(): dom_level; };

	$.getLevel = function(){
		return this._level; };

	$.setImplementation = function(implementation){
		this._impl =  implementation; };

	$.getImplementation = function(){
		return this._impl; };

	$.feed = function(infoset){
		this.setInfoset(infoset); };

	$.inferLevel = function(){
		// todo : consider lying parsers (browsers).
		var impl = this.getImplementation();
		return !impl? 0:
			impl.hasFeature('HTML', '2.0')? 2:
				impl.hasFeature('HTML', '1.0')? 1: 0; };

	$.build = function(tree, level){
		if (tree)
			this.feed(tree);
		if (level !== void 0)
			this.setLevel(level);
		switch(this.getLevel()){
			case void 0:
				this.setLevel();
				arguments.callee();
				break;
			case 0:
				return this._Level_0();
				break;
			case 1:
				return this._Level_1();
				break;
			case 2:
				return this._Level_2();
				break;
			default:
				return null;
				break; } };

	$._Level_0 = function() {
		var stack = new Array();
		dispose(this.getInfoset());
		return stack.join('');

		function dispose(tree) {
			if (typeof(tree) === 'string') {
				stack.push(tree);
				return; }
			for (var name in tree) {
				if (name.charAt(0) == '$') {
					if (name == '$comment') {
						stack.push('<!--'+comment+'-->');
						break; }
					if (name == '$pi') {
						stack.push('<?'+target_content+'?>');
						break; }
					continue; }
				// start-tag
				stack.push('<'+name);
				// attributes
				var attrs = tree['$attrs'];
				for (var att in attrs) {
					var val = attrs[att];
					if (val.constructor === Function)
						val = '('+String(val).replace(/\n/g,'') + ')()';
					stack.push(' ' + att + '="' + val + '"'); }
				var value = tree[name];
				if (value === null) {
					stack.push(' />');
					continue; }
				else
					stack.push('>');
				// children
				switch (value.constructor){
					case String:
						stack.push(value);
						break;
					case Object:
						arguments.callee(value);
					case Array:
						for (var i=0,child,len=value.length;i<len;i++) {
							child = value[i];
							arguments.callee(child); }
						break;
					default:
						break; }
				// end-tag
				stack.push('</'+name+'>'); } } };

	$._Level_1 = function(event){
		var d = document;
		var dfRoot = d.createDocumentFragment();
		make(this.getInfoset(), dfRoot);
		return dfRoot;

		function make(tree, parent){
			
			if(typeof(tree) === 'string') {
				parent.appendChild(d.createTextNode(tree));
				return; }
			for (var name in tree) {
				var value = tree[name];
				/* Comment etc. */
				if (name.charAt(0) == '$') {
					if (name == '$comment')
						parent.appendChild(d.createTextNode(value));
					if (name == '$pi')
						parent.appendChild(
							d.createProcessingInstruction(value)
						);
					continue; }

				var element, attrs, children = value;
				/* Element */
				element = d.createElement(name);
				/* Attributes and Event handlers */
				for (var att in (attrs = tree['$attrs'])) {
					var val = attrs[att];
					if (!att.match(/^on(.*)/))
						element.setAttribute(att, val);
					else
						if (event)
							element.addEventListener(RegExp.$1, val, true);
						else
							element[att] = val; }
				/* Children */
				if (value === null) { // empty element
					parent.appendChild(element);
					continue; }
				switch (value.constructor) {
					case String:
						element.appendChild(d.createTextNode(value));
						break;
					case Object:
						var dfSub = d.createDocumentFragment();
						arguments.callee(value, dfSub);
						element.appendChild(dfSub);
						break;
					case Array:
						for (var i=0, dfSub=d.createDocumentFragment(),
							len=children.length; i<len; i++)
							arguments.callee(children[i], dfSub);
						element.appendChild(dfSub);
						break;
					default:
						break; }
				parent.appendChild(element); } } };

	$._Level_2 = function(){
		var impl = this.getImplementation();
		var event = impl.hasFeature('Events', '2.0');
		return this._Level_1(event); };

})();

使用例

最終更新
2003-11-18T22:12:13+09:00

シンプルなbr要素を生成してみます。

var br = { br: null }; // (1)
var builder = new HTMLBuilder(); // (2)
builder.setLevel(1); // (3)
builder.feed(br); // (4)
builder.build(); // (5)
  1. br要素を、JavaScriptのオブジェクトリテラル{ key: 値 }で抽象的に表現しています(js-html)。key が要素名、値がその内容です。空要素の場合はnullです。
  2. HTMLBuilderの具体的な実体を生成して変数builderに格納しています。
  3. DOM Level 1を利用するため、HTMLBuilderのlevelパラメータを 1 にセットします。
  4. 抽象的に表現したbr要素を、HTMLBuilderに与えます。
  5. HTMLBuilderに、具体的なbr要素を生成させています。buildメソッドの戻り値はbr要素一つだけを含んだDocumentFragmentオブジェクト(※)です。
    • levelパラメータが 0 の場合には、<br /> という文字列が返却されます。

(3)、(4)、(5)は、一つにまとめてbuilder.build(br, 1)と書くことも可能です。

(※)DocumentFragmentオブジェクトは任意のElementにappendChildすることができます。

TODO、問題点

最終更新
2003-11-18T22:07:07+09:00
2003-11-18
level 0 使用時、イベントハンドラ内でのthisキーワードの参照値が不正になる。

姉妹品(わらい)

最終更新
更新はありません