プレゼンテーションパターンカタログ
last update: $Date: 2005-02-19 23:59:52 +0900 (Sat, 19 Feb 2005) $
はじめに
Kwartzは、「プレゼンテーションロジックとプレゼンテーションデータの分離」という概念を実現したテンプレートシステムです。 プレゼンテーションロジックとプレゼンテーションデータを分離すると、HTMLデザインをまったく崩すことなく、複雑なプレゼンテーションロジックを利用することができます。
またプレゼンテーションデータとプレゼンテーションロジックとをうまく分離するための、いくつかのパターンが存在します。 これらのパターンを「プレゼンテーションパターン」といいます。
このドキュメントでは、プレゼンテーションパターンを紹介します。
目次
置換
Replace Element by Valueパターン
エレメントを、変数や式の値で置き換えることができます。 これを「Replace Element by Valueパターン」といいます。
プレゼンテーションデータ:
Hello <span id="mark:user">World</span>!
プレゼンテーションロジック:
#user {
plogic: {
print(username); // エレメントのかわりに変数usernameを出力する
}
}
出力用スクリプト:
### for eRuby
Hello<%= username %>!
### for PHP
Hello<?php echo $username; ?>!
### for JSTL
Hello<c:out value="${username}" escapeXml="false"/>!
Replace Content by Valueパターン
タグは残したままエレメントの内容だけを式の値で置き換えることができます。 これを「Replace Content by Valueパターン」といいます。
プレゼンテーションデータ:
<h1 id="mark:title">Example</h1>
プレゼンテーションロジック:
#title {
plogic: {
@stag;
print(title); // 内容(@cont)のかわりに変数titleの値を出力する
@etag;
}
}
出力用スクリプト:
### for eRuby
<h1><%= title %></h1>
### for PHP
<h1><?php echo $title; ?></h1>
### for JSTL
<h1><c:out value="${title}" escapeXml="false"/></h1>
なお「Replace Content by Valueパターン」は、Kwartzでは次のように書くことができます。
プレゼンテーションロジック:
#title {
value: title; // 内容のかわりに変数titleの値を出力する
}
Replace Element by Elementパターン
エレメントを別のエレメントに交換することができます。 これは「Replace Element by Elementパターン」といいます。
このパターンは、ある場所で定義したエレメントを別の場所で再使用するのに便利です。
プレゼンテーションデータ:
<div id="mark:links"> <a href="/">HOME</a> | <a href="/doc">Document</a> | <a href="/faq">FAQ</a> </div> <p>Welcome to my Home Page!</p> <div id="mark:links2"> Home | Document | FAQ </div>
プレゼンテーションロジック:
#links2 {
plogic: {
@element(links); // エレメントlins2をエレメントlinksで置き換える
}
}
ここで「@element(name)」は、「id="mark:name"」や「id="name"」でマーキングされたエレメントを表しています。
出力用スクリプト:
<div> <a href="/">HOME</a> | <a href="/doc">Document</a> | <a href="/faq">FAQ</a> </div> <p>Welcome to my Home Page!</p> <div> <a href="/">HOME</a> | <a href="/doc">Document</a> | <a href="/faq">FAQ</a> </div>
Kwartzにおいて、コマンドラインオプション「-i file,file2,...」を指定すると、
他のファイルのエレメントを利用できます。
プレゼンテーションデータ(links.html):
<div id="mark:links"> <a href="/">HOME</a> | <a href="/doc">Document</a> | <a href="/faq">FAQ</a> </div>
プレゼンテーションデータ(page.html):
<div id="mark:links1"> Home | Document | FAQ </div> <p>Welcome to my Home Page!</p> <div id="mark:links2"> Home | Document | FAQ </div>
プレゼンテーションロジック(page.plogic):
#links1 {
plogic: {
@element(links);
}
}
#links2 {
plogic: {
@element(links);
}
}
コンパイル:
$ kwartz -l eruby -i links.html -p page.plogic page.html
出力用スクリプト:
<div> <a href="/">HOME</a> | <a href="/doc">Document</a> | <a href="/faq">FAQ</a> </div> <p>Welcome to my Home Page!</p> <div> <a href="/">HOME</a> | <a href="/doc">Document</a> | <a href="/faq">FAQ</a> </div>
Replace Content by Elementパターン
エレメントの内容を、別のエレメントで置き換えることができます。 これは「Replace Content by Elementパターン」といいます。
このパターンは、他のファイルでマーキングされたエレメントを取り込むときに使用されます。
プレゼンテーションデータ(contents.html):
<html>
<body>
<p>menu:</p>
<ul id="mark:menu">
<li><a href="..." id="mark:menu_item">menu1</a></li>
</ul>
<p>article:</p>
<div id="mark:article">
<h2>What is Kwartz?</h2>
<p>Kwartz is a template system, which realized the
concept <strong>`Separation of Presentation Logic
and Presentation Data'(SoPL/PD)</strong>.
</p>
</div>
</body>
</html>
プレゼンテーションロジック(contents.plogic):
#menu {
plogic: {
@stag;
foreach (item in menu_list) {
@cont;
}
@etag;
}
}
#menu_item {
value: item['name'];
attr: "href" item['url'];
}
プレゼンテーションデータ(layout.html):
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
<head>
<title id="value:title">...title...</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" type="text/css" href="design.css">
</head>
<body>
<table border="0">
<tr>
<!-- menu part -->
<td width="100" valign="top">
<div class="menu" id="mark:placeholder_menu">
<ul>
<li>menu1</li>
<li>menu2</li>
<li>menu3</li>
</ul>
</div>
</td>
<!-- article part -->
<td width="400" valign="top">
<div class="article" id="mark:placeholder_article">
aaa<br>
bbb<br>
ccc<br>
ddd<br>
</div>
</td>
</tr>
<!-- footer part -->
<tr>
<td colspan="2" class="copyright">
copyright© 2004-2005 kuwata-lab.com All Rights Reserverd
</td>
</tr>
</table>
</body>
</html>
プレゼンテーションロジック(layout.plogic):
#placeholder_menu {
plogic: {
@stag;
@element(menu); // 内容を別のエレメントで置き換える
@etag;
}
}
#placeholder_article {
plogic: {
@stag;
@element(article); // 内容を別のエレメントで置き換える
@etag;
}
}
Kwartzではコマンドオプション「-i file1,file2,...」を指定することで、
他のファイルのエレメントを読み込むことができます。
コンパイル:
$ kwartz -l eruby -i contents.html -p contens.plogic,layout.plogic layout.html
出力用スクリプト:
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
<head>
<title><%= title %></title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" type="text/css" href="design.css">
</head>
<body>
<table border="0">
<tr>
<!-- menu part -->
<td width="100" valign="top">
<div class="menu">
<ul>
<% for item in menu_list do %>
<li><a href="<%= item["url"] %>"><%= item["name"] %></a></li>
<% end %>
</ul>
</div>
</td>
<!-- article part -->
<td width="400" valign="top">
<div class="article">
<div>
<h2>What is Kwartz?</h2>
<p>Kwartz is a template system, which realized the
concept <strong>`Separation of Presentation Logic
and Presentation Data'(SoPL/PD)</strong>.
</p>
</div>
</div>
</td>
</tr>
<!-- footer part -->
<tr>
<td colspan="2" class="copyright">
copyright© 2004-2005 kuwata-lab.com All Rights Reserverd
</td>
</tr>
</table>
</body>
</html>
削除
Delete Elementパターン
プレゼンテーションロジックの定義を空欄にすると、エレメント全体を出力しないことになります。 これは「Delete Elementパターン」または「Dummy Elementパターン」といいます。
このパターンは、プレゼンテーションデータにダミーデータを含めるときに使用します。
プレゼンテーションデータ:
<ul> <li>foo</li> <li id="dummy">bar</li> </ul>
プレゼンテーションロジック:
#dummy {
plogic: {
// empty
}
}
出力用スクリプト:
### for eRuby <ul> <li>foo</li> </ul> ### for PHP <ul> <li>foo</li> </ul> ### for JSTL <ul> <li>foo</li> </ul>
Delete Tagパターン
プレゼンテーションロジックの定義において、「@cont」だけを使用し、
「@stag」と「@stag」を使わないようにすると、エレメントのタグを削除できます。
これは「Delete Tagパターン」または「Dummy Tagパターン」といいます。
このパターンは、ある条件のときだけタグを出力したい場合に使います。
プレゼンテーションデータ:
<a href="@{url}@" id="mark:next">Next</a>
プレゼンテーションロジック:
#next {
plogic: {
if (url == null) {
@cont; // タグを出力しない
} else {
@stag;
@cont;
@etag;
}
}
}
出力用スクリプト:
### for eRuby
<% if url == nil then %>
Next<% else %>
<a href="<%= url %>">Next</a>
<% end %>
### for PHP
<?php if ($url == NULL) { ?>
Next<?php } else { ?>
<a href="<?php echo $url; ?>">Next</a>
<?php } ?>
### for JSTL
<c:choose><c:when test="${url eq null}">
Next</c:when><c:otherwise>
<a href="<c:out value="${url}" escapeXml="false"/>">Next</a>
</c:otherwise></c:choose>
繰り返し
Iterate Elementパターン
繰り返しの中に「@stag」と「@cont」と「@etag」を含めると、エレメント全体を繰り返すことになります。
これを「Iterate Element」パターンといいます。
プレゼンテーションデータ:
<table>
<tr id="mark:items">
<td>@{item}@</td>
</tr>
</table>
プレゼンテーションロジック:
#items {
plogic: {
// 開始タグ、内容、終了タグを繰り返す
foreach (item in list) {
@stag;
@cont;
@etag;
}
}
}
出力用スクリプト:
### for eRuby
<ul>
<% for item in list do %>
<dt><%= item.text %></dt>
<dd><%= item.desc %></dd>
<% end %>
</ul>
### for PHP
<ul>
<?php foreach ($list as $item) { ?>
<dt><?php echo $item->text; ?></dt>
<dd><?php echo $item->desc; ?></dd>
<?php } ?>
</ul>
### for JSTL
<ul>
<c:forEach var="item" items="${list}">
<dt><c:out value="${item.text}" escapeXml="false"/></dt>
<dd><c:out value="${item.desc}" escapeXml="false"/></dd>
</c:forEach>
</ul>
Iterate Contentパターン
繰り返しの中に「@cont」を含めると、内容だけを繰り返すことになります。
これを「Iterate Content」パターンといいます。
これは<dl></dl>の内容だけを繰り返したいときに、特に有効です。
プレゼンテーションデータ:
<ul id="mark:items">
<dt>@{item.text}@</dt>
<dd>@{item.desc}@</dd>
</ul>
プレゼンテーションロジック:
#items {
plogic: {
// 内容だけを繰り返す
@stag;
foreach (item in list) {
@cont;
}
@etag;
}
}
出力用スクリプト:
### for eRuby
<ul>
<% for item in list do %>
<dt><%= item.text %></dt>
<dd><%= item.desc %></dd>
<% end %>
</ul>
### for PHP
<ul>
<?php foreach ($list as $item) { ?>
<dt><?php echo $item->text; ?></dt>
<dd><?php echo $item->desc; ?></dd>
<?php } ?>
</ul>
### for JSTL
<ul>
<c:forEach var="item" items="${list}">
<dt><c:out value="${item.text}" escapeXml="false"/></dt>
<dd><c:out value="${item.desc}" escapeXml="false"/></dd>
</c:forEach>
</ul>
選択
Select Elementパターン
複数のエレメントからひとつだけを選んで出力する場合は、次のようにします。 これは「Select Elementパターン」といいます。
プレゼンテーションデータ:
<div id="mark:message"> <font color="red" id="mark:error">ERROR!</font> <font color="blue" id="mark:warning">Warning:</font> <font color="black" id="mark:good">No error.</font> </div>
プレゼンテーションロジック:
#message {
plogic: {
if (status == 'error') {
@element(error); // ERROR!
} else if (status == 'warning') {
@element(warning); // Warning:
} else {
@element(good); // No error.
}
}
}
出力用スクリプト:
### for eRuby
<% if status == "error" then %>
<font color="red">ERROR!</font>
<% elsif status == "warning" then %>
<font color="blue">Warning:</font>
<% else %>
<font color="black">No error.</font>
<% end %>
### for PHP
<?php if ($status == "error") { ?>
<font color="red">ERROR!</font>
<?php } elseif ($status == "warning") { ?>
<font color="blue">Warning:</font>
<?php } else { ?>
<font color="black">No error.</font>
<?php } ?>
### for JSTL
<c:choose><c:when test="${status eq 'error'}">
<font color="red">ERROR!</font>
</c:when><c:when test="${status eq 'warning'}">
<font color="blue">Warning:</font>
</c:when><c:otherwise>
<font color="black">No error.</font>
</c:otherwise></c:choose>
Pick-up Elementパターン
ある特定のエレメントだけを利用するには、利用したいエレメントだけをマーキングし、 プレゼンテーションロジックでそのエレメントだけを利用します。 利用されないエレメントは無視され、出力されません。 これは「Pick-up Elementパターン」といいます。
これは「Dummy Element」パターンと逆の考え方です。 「Dummy Element」パターンでは不要なエレメントをマーキングして削除することで必要なものだけを残しますが、 「Pick-up Element」パターンでは必要なエレメントだけマーキングして取り出すことで不要なものを削除します。
プレゼンテーションデータ:
<html>
<body>
<div id="breadcrumbs">
<a href="@{item['path']}@" id="mark:crumb">@{item['name']}@</a>
<span id="mark:separator">></span>
<a href="/aaa/">AAA</a> <
<a href="/aaa/bbb/">BBB</a> &lgt;
<a href="/aaa/bbb/ccc">CCC</a> &lgt;
<b id="mark:title">@{title}@</b>
</div>
</body>
</html>
プレゼンテーションロジック:
#breadcrumbs {
plogic: {
foreach (item in list) {
@element(crumb); // print <a>...</a>
@element(separator); // print '>'
}
@element(title); // print <b>title</b>
}
}
出力用スクリプト:
### for eRuby
<html>
<body>
<% for item in list do %>
<a href="<%= item["path"] %>"><%= item["name"] %></a>
>
<% end %>
<b><%= title %></b>
</body>
</html>
### for PHP
<html>
<body>
<?php foreach ($list as $item) { ?>
<a href="<?php echo $item["path"]; ?>"><?php echo $item["name"]; ?></a>
>
<?php } ?>
<b><?php echo $title; ?></b>
</body>
</html>
### for JSTL
<html>
<body>
<c:forEach var="item" items="${list}">
<a href="<c:out value="${item['path']}" escapeXml="false"/>"><c:out value="${item['name']}" escapeXml="false"/></a>
>
</c:forEach>
<b><c:out value="${title}" escapeXml="false"/></b>
</body>
</html>
上の例は、次のように書くこともできます。
プレゼンテーションデータ:
<html>
<body>
<div id="breadcrumbs">
<a href="/" id="mark:crumb">Home</a>
<span id="mark:separator">></span>
<a href="/aaa/">AAA</a> <
<a href="/aaa/bbb/">BBB</a> &lgt;
<a href="/aaa/bbb/ccc">CCC</a> &lgt;
<b id="mark:title">Page Title</b>
</div>
</body>
</html>
プレゼンテーションロジック:
#breadcrumbs {
plogic: {
foreach (item in list) {
@element(crumb); // print <a>...</a>
@element(separator); // print '>'
}
@element(title); // print <b>title</b>
}
}
#crumb {
value: item['name'];
attr: "href" item['path'];
}
#title {
value: title;
}
Extract Elementパターン
プレゼンテーションデータ全体から、ある特定のエレメントだけを抽出し、 ほかは一切表示しないようにすることができます。 このパターンは「Extract Elementパターン」といいます。
このパターンを使うと、HTMLデータの一部だけを取り出し、部品化することができます。 例えば次の例では、HTMLファイルからタブとメニューと著作権表示を抜き出しています。
プレゼンテーションデータ(design.html):
<html id="mark:whole">
<head>
<title>Design Examples</title>
<link rel="stylesheet" href="design.css" type="text/css">
</head>
<body>
<div id="mark:tablist">
<div class="tabs" id="mark:tabs">
<a href="/" class="" id="mark:tab">Home</a>
<a href="/product/" class="selected">Product</a>
<a href="/download/" class="">Download</a>
<a href="/support/" class="">Support</a>
</div>
<div class="tabsline">
</div>
</div>
<br>
<div id="mark:menulist">
<span class="menu_title" id="value:menu_title">MenuList</span>
<div class="menus" id="mark:menus">
<a href="/cgi-bin/email.cgi" class="" id="mark:menu">E-Mail</a>
<span id="mark:menu_separator"><br></span>
<a href="/cgi-bin/board.cgi" class="selected">MesgBoard</a><br>
<a href="/cgi-bin/photo.cgi" class="">PhotoAlbum</a><br>
<a href="/cgi-bin/greeting.cgi" class="">GreetingCard</a><br>
</div>
</div>
<br>
<p> ..... </p>
<p> ..... </p>
<p> ..... </p>
<div align="center" class="copyright" id="mark:copyright">
Copyright© 2004-2005 kuwata-lab. All Rights Reserved.
</div>
</body>
</html>
プレゼンテーションロジック(copyright.plogic):
#whole {
// 全体を表すエレメントwholeを、抽出したいエレメントで置き換える
plogic: {
@element(copyright);
}
}
プレゼンテーションロジック(tablist.plogic):
#whole {
// 全体を表すエレメントwholeを、抽出したいエレメントで置き換える
plogic: {
@element(tablist);
}
}
#tabs {
plogic: {
@stag;
foreach (tab in tablist) {
klass = current_tabname == tab['name'] ? 'selected' : '';
@element(tab);
}
@etag;
}
}
#tab {
value: tab['name'];
attr: "href" tab['href'], "class" klass;
}
プレゼンテーションロジック(menulist.plogic):
#whole {
// 全体を表すエレメントwholeを、抽出したいエレメントで置き換える
plogic: {
@element(menulist);
}
}
#menus {
plogic: {
@stag;
foreach (menu in menulist) {
@element(menu);
@element(menu_separator);
}
@etag;
}
}
#menu {
value: menu['name'];
attr: "href" menu['cgipath'], "class" klass;
plogic: {
klass = current_menu == menu['name'] ? 'selected' : '';
@stag;
@cont;
@etag;
}
}
コンパイル:
### copyright $ kwartz -l eruby -p copyright.plogic design.pdata $ kwartz -l php -p copyright.plogic design.pdata ### tablist $ kwartz -l eruby -p tablist.plogic design.pdata $ kwartz -l php -p tablist.plogic design.pdata ### menulist $ kwartz -l eruby -p menulist.plogic design.pdata $ kwartz -l php -p menulist.plogic design.pdata
出力用スクリプト:
### for eRuby
<div align="center" class="copyright">
Copyright© 2004-2005 kuwata-lab. All Rights Reserved.
</div>
### for PHP
<div align="center" class="copyright">
Copyright© 2004-2005 kuwata-lab. All Rights Reserved.
</div>
出力用スクリプト:
### for eRuby
<div>
<div class="tabs">
<% for tab in tablist do %>
<% klass = current_tabname == tab["name"] ? "selected" : "" %>
<a href="<%= tab["href"] %>" class="<%= klass %>"><%= tab["name"] %></a>
<% end %>
</div>
<div class="tabsline">
</div>
</div>
### for PHP
<div>
<div class="tabs">
<?php foreach ($tablist as $tab) { ?>
<?php $klass = $current_tabname == $tab["name"] ? "selected" : ""; ?>
<a href="<?php echo $tab["href"]; ?>" class="<?php echo $klass; ?>"><?php echo $tab["name"]; ?></a>
<?php } ?>
</div>
<div class="tabsline">
</div>
</div>
出力用スクリプト:
### for eRuby
<div>
<span class="menu_title"><%= menu_title %></span>
<div class="menus">
<% for menu in menulist do %>
<% klass = current_menu == menu["name"] ? "selected" : "" %>
<a href="<%= menu["cgipath"] %>" class="<%= klass %>"><%= menu["name"] %></a>
<br>
<% end %>
</div>
</div>
### for PHP
<div>
<span class="menu_title"><?php echo $menu_title; ?></span>
<div class="menus">
<?php foreach ($menulist as $menu) { ?>
<?php $klass = $current_menu == $menu["name"] ? "selected" : ""; ?>
<a href="<?php echo $menu["cgipath"]; ?>" class="<?php echo $klass; ?>"><?php echo $menu["name"]; ?></a>
<br>
<?php } ?>
</div>
</div>
なお、コマンドラインオプション「--extract=name」でも、nameでマーキングされたエレメントを抽出できます。