Alfresco Share JAR ModulesによるDashletの作成方法
前回のエントリでは、Alfresco Share JAR Modulesで作成されたSite Tags Dashletを紹介しました。今回はこのDashletの作成方法について書いていきます。
プロジェクトの作成
- コマンドプロンプトから下記のコマンドを実行します。コマンド中の、groupId、artifactId、versionは好みの値に変えてください。
mvn archetype:generate -DarchetypeGroupId=org.alfresco.maven -DarchetypeArtifactId=maven-alfresco-share-module-archetype -DarchetypeVersion=1.0.0-SNAPSHOT -DgroupId=com.mycompany -DartifactId=my-custom-share-module -Dversion=1.0-SNAPSHOT -DarchetypeRepository=http://maven.alfresco.com/nexus/content/repositories/snapshots -DinteractiveMode=false
- これでAlfresco Share JAR Modulesのプロジェクトひな形が自動生成されます。下記の構成となっていて、実は、Site Tags Dashletのソースがサンプルとして含まれている。
my-custom-share-module ├─pom.xml └─src └─main └─resources ├─alfresco │ └─site-webscripts │ └─org │ └─alfresco │ └─components │ └─dashlets │ ├─site-tags.get.config.xml │ ├─site-tags.get.desc.xml │ ├─site-tags.get.head.ftl │ ├─site-tags.get.html.ftl │ ├─site-tags.get.js │ ├─site-tags.get.properties │ └─site-tags.get_cy.properties └─META-INF └─components └─dashlets ├─images │ └─refresh.png ├─site-tags-min.js ├─site-tags.css └─site-tags.js
上記ファイルについて簡単に説明します。
src/main/resources/alfresco/site-webscripts 以下のファイル
サーバサイドで動作するコンポーネントです。
- site-tags.get.config.xml
- 設定ファイル。ここで設定した値をftlファイルから参照できる。Site Tags Dashletでは、タグの最大表示数を設定している。
- site-tags.get.desc.xml
- Dashletのエントリポイントとなるファイル。下記の内容となっていますが、重要なのは
の値です。ここをsite-dashletとすることで、サイト単位のDashletになります。もし、user-dashletとすると、ユーザごとのダッシュボードに配置可能なDashletになります。dashletとすると両方に配置可能になります。 は、この後で説明するsrc/main/resources/META-INF以下のディレクトリ構造と一致させます。
- Dashletのエントリポイントとなるファイル。下記の内容となっていますが、重要なのは
<webscript> <shortname>Tag Cloud</shortname> <description>Displays a cloud of all the tags defined in this site</description> <family>site-dashlet</family> <url>/components/dashlets/site-tags</url> </webscript>
- site-tags.get.head.ftl
- このDashletの画面をレスポンスとして出力するFreeMakerのテンプレートです。headがファイル名についていますが、HTMLので返したい内容を定義すると埋め込んでくれます。なので、CSSやJavaScriptの読み込みなどで使います。
- site-tags.get.html.ftl
- 同様にFreeMakerのテンプレートですが、こちらはHTMLの本文を定義します。つまり、Dashletで返したい内容を記述します。
- site-tags.get.js
- JavaScriptですが、ブラウザで動作する物ではありません。こちらはサーバサイドで動作する物。ここに、Dashletの画面表示の前に処理したいことを記述することになります。
- Alfresco内での一般的な書き方としては、下記のようにmain関数を定義し、そのmain関数を実行するような形になっています。
const PREFERENCES_ROOT = "org.alfresco.share.dashlet"; function main() { var s = new XML(config.script); model.maxItems = parseInt(s.maxitems, 10); …(省略)… model.preferences = preferences; } main();
-
- 重要なポイントはmodel.preferences = preferences;の部分。model変数の任意のプロパティに値を設定することで、レスポンスを生成するテンプレートファイルに値を渡すことができます。
- site-tags.get.properties、site-tags.get_cy.properties
- メッセージファイルです。多言語対応には必要。日本語リソースが必要な場合は、site-tags.get_ja.propertiesというファイルで作成すればOK。
src/main/resources/META-INF 以下のファイル
ここに配置したファイルは、クライアントからアクセスされる静的なリソースファイル(JavaScriptやCSS、画像ファイルなど)になる。
- site-tags.css
- CSSファイル。site-tags.get.head.ftlによりで読み込まれている。
- site-tags.js/site-tags-min.js
- JavaScriptのファイル。*-min.jsファイルは、YUI Compressorで圧縮したもの。
- これもsite-tags.get.head.ftlによりで読み込まれているのですが、FreeMakerのマクロ機能でデバッグモード時は*-min.jsを自動的に読むようになっています。site-tags.get.head.ftlの中身を見ると分かりますが、scriptタグを使用せずに@scriptタグを使用しています。
<#include "../component.head.inc"> <!-- Tag cloud --> <@link rel="stylesheet" type="text/css" href="${page.url.context}/res/components/dashlets/site-tags.css" /> <@script type="text/javascript" src="${page.url.context}/res/components/dashlets/site-tags.js"></@script>
-
- この@付きがFreeMakerのマクロで、実体は<#include>でインクルードしているcomponent.head.incに定義されている。これはAlfrescoの本体に格納されている共通部品なので注意。下記のように、DEBUG変数の値で-min.jsに置換している。
<#-- JavaScript minimisation via YUI Compressor --> <#macro script type src> <script type="${type}" src="${DEBUG?string(src, src?replace(".js", "-min.js"))}"></script> </#macro>
-
- 肝心のタグクラウドとしての処理、タグの一覧を取得するのはどこに実装されているかですが、実はこのsite-tags.jsで実装されている。つまり、Site Tags DashletはほぼクライアントサイドのJavaScriptで実装されています。タグの一覧はAlfrescoのREST APIを叩いて取得していて、それを画面に表示しているだけです。下記のコードでタグ一覧をJSONで取得し、画面に描画しています。
// Make an AJAX request to the Tag Service REST API Alfresco.util.Ajax.jsonGet( { url: Alfresco.constants.PROXY_URI + "api/tagscopes/site/" + $combine(this.options.siteId, this.containerId, "tags"), successCallback: { fn: this.onTagsSuccess, scope: this }, failureCallback: { fn: this.onTagsFailed, scope: this }, scope: this, noReloadOnAuthFailure: true });
日本語タグに対応してみる
前回のエントリでちょっと書いたとおり、日本語のタグを作ってしまうと、Site Tags Dashletからのリンク遷移で失敗してしまうという問題があります。これを修正してみます。
原因は何か?
日本語のタグを作ると、Site Tags Dashletからのリンク遷移を行うとタグ名が文字化けしています。タグ名はURLパラメータとして渡しているので、URLエンコードに問題がありそうです。
site-tags.js:325を見ると、タグ名はencodeURIComponentを使用してエンコードしています。
case "documentLibrary": uri += '/documentlibrary#filter=tag|' + encodeURIComponent(tag.name); break;
一方、タグに対応したドキュメント一覧の表示画面では、share.war/components/documentlibrary/documentlist.jsで処理されています。これをみると、タグ名をDL_fnDecodeBookmarkedFilter関数でデコードしているのですが、window.unescapeを使って元にもどしている。encodeURIComponentとunescapeでは文字コードが異なるので、ここで化けてしまっていました*1。
var fnDecodeBookmarkedFilter = function DL_fnDecodeBookmarkedFilter(strFilter) { var filters = strFilter.split("|"), filterObj = { filterId: window.unescape(filters[0] || ""), filterData: window.unescape(filters[1] || "") }; filterObj.filterOwner = Alfresco.util.FilterManager.getOwner(filterObj.filterId); return filterObj; };
なので、修正方法としては、site-tags.js:326のエンコード方式を変えてあげればよい。下記のように、encodeURIComponent関数をwindow.escape関数に変えてあげる。
case "documentLibrary": uri += '/documentlibrary#filter=tag|' + window.escape(tag.name); break;
作成したDashletをビルドする
作成されたプロジェクトをビルドするには、Mavenの下記コマンドを実行します。ビルドが成功すると、target/my-custom-share-module-1.0-SNAPSHOT.jarができています。
mvn install
作成したDashletをデプロイする
前回のエントリと同様に、ビルドしたJARをAlfrescoの下記に配置します。また、catalina.propertiesのshared.loaderの設定も忘れずに!
/opt/alfresco-3.4.b/tomcat/shared/lib
Alfrescoを起動している場合は、再起動します。これでDashletが使えるようになる。
まとめ
- Dashletの開発では、Mavenを使えば簡単にプロジェクトの作成→ビルドが行える環境が整います。
- Dashletの開発において、Java言語は必要ありません。HTML、CSS、JavaScript、FreeMakerによるテンプレートファイルがメインです。ShareはWeb2.0スタイルと言っているだけあって、クライアントサイドのJavaScriptでごりごり開発するのが基本的な形のようです。その時標準で使えるライブラリとしてはYUIとなります。
- また、AlfrescoではREST APIが豊富に用意されています。JSONを返してくれるので、クライアントサイド(またはサーバサイド)のJavaScriptからアクセスし、結果を加工して画面表示するようなアーキテクチャになります。
*1:documentlist.jsではwindow.unescapeをなぜ利用しているかというと、YUIのHistoryManagerをこいつは使っていて、HistoryManager自身もwindow.escape/unescapeで利用しているためと思われる。