Wicket 1.5.2 で、CSS Javascritp の Link 出力のコントール方法について調べてみました。
調べた結果を記載します。
前提
動作確認している環境の情報について記載します。
-
Wicket の Version
<!-- https://mvnrepository.com/artifact/org.apache.wicket/wicket-core --> <dependency> <groupId>org.apache.wicket</groupId> <artifactId>wicket-core</artifactId> <version>1.5.2</version> </dependency>
-
OS
% sw_vers ProductName: Mac OS X ProductVersion: 10.12.6 BuildVersion: 16G1036
-
** Java の Version**
<plugin> <inherited>true</inherited> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <debug>true</debug> </configuration> </plugin>
参考
Wicket 7.6.0 での CSS Javascript の Reference 出力のコントロール方法について
過去に以下の記事を作成しましたので、Wicket 7.6.0 での方法を知りたい方はご確認ください。
Wicket scriptタグ を body 閉じタグの直前に出力する | Monotalk
Wicket 7.6.0
ですと FilteredHeaderItem
、 HeaderResponseDecorator
を使ってコントロールします。
Wicket 1.5.2 での CSS Javascript の Reference 出力のコントロール方法について
Wicket 7.6.0 と同等機能を Wicket 1.5.2 で利用するには以下の実装が必要になります。1
-
HTML と、Page クラスに Footer 部とする Container を追加する
-
HeaderResponseDecoratorHeader の設定
-
HeaderResponseContainerFilteringHeaderResponse の拡張クラスの作成
以下、各実装について説明します。
作成したもの一式は gist に UP しました。
Wicket 1.5.2 で、CSS Javascript の Reference 出力をコントロールする
1. HTML と、Page クラスに Footer 部とする Container を追加する
Footer 出力箇所とする、Page クラス、HTML にそれぞれ以下記述を追加します。
footerBucket
は ID 名称なので任意の名前で問題ありません。
HeaderResponseFilteredResponseContainer
の第二引数の footerBucket
は Footer 部に対応する Filter 名を適用します。
-
HTML
<wicket:container wicket:id="footerBucket"/>
-
Pageクラス
add(new HeaderResponseFilteredResponseContainer("footerBucket", "footerBucket"));
2. HeaderResponseDecoratorHeader の設定
WebApplication クラスで、setHeaderResponseDecorator
で、HeaderResponseDecorator
を実行します。
3.
で説明する FilteringHeaderResponse
を設定します。
filter クラスには、AbstractHeaderResponseFilter を使用し、Header 用、Footer 用で、匿名インナークラスを2つ生成しています。
-
WebApplication クラス
setHeaderResponseDecorator(new IHeaderResponseDecorator() { HeaderResponseContainerFilteringHeaderResponse.IHeaderResponseFilter[] filters = { new AbstractHeaderResponseFilter("headerBucket") {}, new AbstractHeaderResponseFilter("footerBucket") {}} ; @Override public IHeaderResponse decorate(IHeaderResponse response) { return new FilteringHeaderResponse(response, "headerBucket", filters); } });
-
CSSAcceptingHeaderResponseFilter 、JavaScriptAcceptingHeaderResponseFilter を利用しない理由
以下の理由から、CSSAcceptingHeaderResponseFilter 、JavaScriptAcceptingHeaderResponseFilter は利用しませんでした。- 文字列ベースでのReference参照だと、大きなレベルでのコントロールしかできない。
acceptReference
、acceptOtherJavaScript
、acceptOtherCss
というメソッドがありますが、文字列ベースのresponse.renderJavaScriptReference()
実行の際は、acceptOtherJavaScript
、response.renderCSSReference()
実行の際は、acceptOtherCSS
が実装され、追加する/しない の判断が行われます。
acceptOtherJavaScript
、acceptOtherCss
は、true/false のみを返すため、css ヘッダ部へ、javascript はフッタ部へ
とする大雑把なコントロールしかできず、リソース単位でのコントロールができないためです。
- 文字列ベースでのReference参照だと、大きなレベルでのコントロールしかできない。
3. HeaderResponseContainerFilteringHeaderResponse の拡張クラスの作成
リソース単位でのヘッダ出力、フッタ出力をできるようにするため、HeaderResponseContainerFilteringHeaderResponse の拡張クラス を作成しました。
- renderJavaScriptReferenceIntoFooter、renderCSSReferenceIntoFooter メソッドの追加
HeaderResponseContainerFilteringHeaderResponse
の JAVA DOC に以下の記載があります。 出力を完全にコントロールしたい場合は、runWithFilter
メソッドを使えばよいとのことなので、runWithFilter
メソッドを使用して、Footer部を指定してタグを追加するメソッドを追加しました。
If subclasses of this class have special cases where they force something into a particular bucket, regardless of the filters, they can create a Runnable that renders to the real response, and pass it to this method with the name of the filter (bucket) that they want it to appear in. Example:
public void renderJavascriptIntoHead(final String js, final String id) { runWithFilter(new Runnable() { public void run() { getRealResponse().renderJavascript(js, id); } }, "headerBucket"); }
- aync属性の出力メソッドの追加
Wicket 1.5.2 だと、defer 属性のみ出力できるのですが、Wicket 8.0 の実装を見ると、Javascript の async 属性も追加できるようになっています。
async 属性で非同期実行の順序をコントロールしたいケースがありそうですので、以下クラスの実装を参考に、async 属性をコントロールできるメソッドを追加しました。
wicket/JavaScriptUtils.java at master · apache/wicket
使い方
Page クラスの renderHead
で、IHeaderResponse
を FilteringHeaderResponse
に キャストして使用します。2
@Override
public void renderHead(IHeaderResponse response) {
FilteringHeaderResponse filteringResponse = (FilteringHeaderResponse) response;
filteringResponse.renderString("<script type=\"text/javascript\"><!-- document.write(\"Hello\"); // --></script>");
filteringResponse.renderString("<link type=\"image/x-icon\" rel=\"shortcut icon\" href=\"resources/favicon.ico\" />");
filteringResponse.renderCSSReference("https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css");
filteringResponse.renderJavaScriptReference("https://code.jquery.com/jquery-1.12.4.min.js");
filteringResponse.renderJavaScriptReference("https://code.jquery.com/jquery-1.12.4.min.js", true, false);
filteringResponse.renderJavaScriptReferenceIntoFooter("https://code.jquery.com/jquery-2.2.4.min.js", true, true);
super.renderHead(response);
}
気にしなかったこと
TOP - async/defer属性とDOM構築 に async / defer 属性についての説明があります。
async、defer 属性は論理型の属性(あれば true、なければ false)で、スクリプトがどのように実行されるべきかを表します。また src 属性がない場合は指定することができません。
論理属性なので、defer="defer" async="async"
と出る必要はないですが、HTML5 でない場合もあるかと思いましたので、この動作については変更は行いませんでした。
フレームワークは Version が上がると、痒いところに手が届くようになります。
エンタープライズだと、フレームワークの Version アップは難しかったりしますが、最新 Version の実装参考にしながら、オレオレ拡張は実施できる場合もありますね。
以上です。
コメント