JavaScriptによるHTMLの省略記法、js-html で書かれたデータを、実際のHTML形式に変換する為のクラスです。当然JavaScript製。
2003-11-17 現在:
以上に対応しています。
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); };
})();
シンプルなbr要素を生成してみます。
var br = { br: null }; // (1)
var builder = new HTMLBuilder(); // (2)
builder.setLevel(1); // (3)
builder.feed(br); // (4)
builder.build(); // (5)
{ key: 値 }で抽象的に表現しています(js-html)。key が要素名、値がその内容です。空要素の場合はnullです。<br /> という文字列が返却されます。(3)、(4)、(5)は、一つにまとめてbuilder.build(br, 1)と書くことも可能です。
(※)DocumentFragmentオブジェクトは任意のElementにappendChildすることができます。