どうも、懲りない僕です。JavaScriptでビュー書いてるんだから、動的にビュー動かしたいよね?だから、TemplateEngineRunnerは繰り返し実行できなきゃ意味ないよね?なんてわけで、対応しました。
それにしてもアレなサンプル……
http://s-ishigami.appspot.com/files/test.html
ソース
TemplateEngine = new function() { var currentNode; this.setCurrentNode = setCurrentNode; this.propertyModelValue = function(object, propName) { return new PropertyModel(object, propName).getValue; }; this.writeText = function (value) { return new WriteText(value); }; this.writeHtml = function (value) { return new WriteHtml(value); }; this.setAttribute = function (name, value) { return new SetAttribute(name, value); }; this.loopWhile = function(condition, subController) { return new LoopFor(emptyFunction, condition, emptyFunction, subController); } this.loopFor = function(init, condition, after, subController) { return new LoopFor(init, condition, after, subController); } function emptyFunction() {} function setCurrentNode(node) { currentNode = node; } function functionOrValue(f) { if (typeof f == 'function') { return f(); } return f; } function PropertyModel(object, propName) { this.getValue = getValue; function getValue() { return object[propName]; } } function WriteText(value) { this.execute = execute; function execute() { currentNode.text(functionOrValue(value)); } } function WriteHtml(value) { this.value = value; this.execute = execute; function execute() { currentNode.html(functionOrValue(value)); } } function SetAttribute(name, value) { this.execute = execute; function execute() { currentNode.attr(name, functionOrValue(value)); } } function LoopFor(init, condition, after, subController) { this.execute = execute; function execute() { init(); while (condition()) { var clone = currentNode.clone(true); clone.attr('id', null); clone.addClass('GENERATED_NODE'); clone.addClass(currentNode.attr('id') + "_CLONE"); if (subController != null) { var thisNode = currentNode; TemplateEngineRunner.run(subController, clone); setCurrentNode(thisNode); } clone.find('*').attr('id', null); clone.insertBefore(currentNode); after(); } currentNode.addClass('ORIGINAL_NODE'); currentNode.hide(); } } } TemplateEngineRunner = new function() { this.run = run; function run(controller, parentNode) { clearGeneratedNodes(parentNode); if (typeof parentNode == 'String') { parentNode = $('#' + parentNode); } for (var key in controller) { if (parentNode == null) { TemplateEngine.setCurrentNode($('#' + key)); } else { TemplateEngine.setCurrentNode(parentNode.find('#' + key)); } controller[key].execute(); } } function clearGeneratedNodes(parentNode) { if (parentNode == null) { $('.GENERATED_NODE').remove(); $('.ORIGINAL_NODE').show(); } else { if (typeof parentNode == 'String') { parentNode = $('#' + parentNode); } parentNode.find('.GENERATED_NODE').remove(); parentNode.find('.ORIGINAL_NODE').show(); } } }
var myModel = { name: 'テスト', sex: 'male', position: 0, goNext: function() { this.position += 1; }, nameChange: function() { this.name = this.name == "テスト" ? "太郎" : "テスト"; } }; with (TemplateEngine) { var yamanote = ['大崎', '品川', '田町', '浜松町', '新橋', '有楽町', '東京', '神田', '秋葉原', '御徒町', '上野', '鶯谷', '日暮里', '西日暮里', '田端', '駒込', '巣鴨', '大塚', '池袋', '目白', '高田馬場', '新大久保', '新宿', '代々木', '原宿', '渋谷', '恵比寿', '目黒', '五反田']; var i = 0; var controller = { // オブジェクトのプロパティ出力(動的) name: writeText(propertyModelValue(myModel, 'name')), // 固定値出力 test: writeText('生麦生米生卵'), // 動的値出力 now: writeText(function() {return new Date().toString();}), // 固定HTML出力 testHtml: writeHtml('<span style="color: blue;">青</span>巻紙<span style="color: red;">赤</span>巻紙<span style="color: yellow;">黄</span>巻紙'), // 属性変更 attr: setAttribute('style', 'font-size: x-large; color: blue;'), // ループ(indexを外側の変数で定義しなければいけないことが課題) 'for': loopFor( function() {i = 0}, function() {return i < 10}, function() {i++;}, { counterFor: writeText(function() {return yamanote[(myModel.position + i) % yamanote.length];}) } ) } } TemplateEngineRunner.run(controller);
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>Template Engine Test</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <a href="javascript: myModel.goNext(); TemplateEngineRunner.run(controller)">次の駅へ</a> <p>現在日時: <span id="now"></span></p> <table border="1"> <col width="200"> <col width="200"> <tr> <th bgcolor="silver">key</th> <th bgcolor="silver">val</th> </td> <tr> <th>氏名</th> <td align="center"><a href="javascript: myModel.nameChange(); TemplateEngineRunner.run(controller)"><span id="name"></span></a></td> </td> <tr> <th>得意技</th> <td><span id="attr"><span id="test"></span></span></td> </td> <tr> <th>得意技2</th> <td><span id="testHtml"></span></td> </td> <tr id="for"> <th>次は</th> <td id="counterFor"></td> </tr> </table> <script type="text/javascript" src="http://www.google.com/jsapi"></script> <script type="text/javascript">google.load("jquery", "1.4.2");</script> <script type="text/javascript" src="templateEngine.js"></script> <script type="text/javascript" src="test.js"></script> </body> </html>
propertyModelValueとか、とてもWicket風。Mayaaを目指したらWicketに似てきた。最初からWicket風につくるべきだったか?