Mixin

Mixin、説明として適切な例がなかなか浮かばないのですが、とりあえず私が最近書いたMixinを晒してみます。

import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.annotations.MixinAfter;
import org.apache.tapestry.annotations.Parameter;

@MixinAfter
public class TableRow {

	@Parameter(required = true)
	private int _columns;

	private int _index;

	void setupRender() {
		_index = -1;
	}

	void beginRender(MarkupWriter writer) {
		++_index;

		if ((_index % _columns) == 0) {
			writer.element("tr");
		}
	}

	void afterRender(MarkupWriter writer) {
		if ((_index % _columns) == _columns - 1) {
			writer.end();	// tr
		}
	}

	void cleanupRender(MarkupWriter writer) {
		int n = _columns - 1 - (_index % _columns);
		if (n > 0) {
			writer.element("td", "colspan", n);
			writer.end();
			writer.end();	// tr
		}
	}
}

使用例:

<table>
	<t:loop source="dataList" value="data" t:mixins="tablerow" tablerow.columns="5">
		<td>${data.name}</td>
	</t:loop>
</table>


Loopコンポーネントに対して使用することを想定しています。
tablerow.columnsパラメータで指定した回数分ループが回る毎に <tr>...</tr> で囲むという単純なものです。
最後の行で不足分がある時は <td colspan="不足分"></td> で埋めます。

@MixinAfter
public class TableRow {

と、@MixinAfterアノテーションしているのは、Loopコンポーネントの各処理フェーズの「後」にMixinするためです(この場合、afterRender, cleanupRenderフェーズでは、Loopコンポーネントの「前」に処理されるので、MixinAfterという名前よりもMixinInnerとかの方が良い気がしますが)。このアノテーションが無い場合は各フェーズの前(というか外側)にMixinされます。