2010年10月28日木曜日

jQuery ThickBoxを使ってみた

画像をクリックすると画像を拡大して表示するサイトをよく見かけ、
かっこいいなぁと思っていたので自分もやってみました。

調べたところjQueryとThickboxというものを使用すると簡単に実現出来そうです。


手順
配布ページより以下のファイルをダウンロード。
http://jquery.com/demo/thickbox/
  • jquery.js
  • loadingAnimation.gif
  • thickbox.css
  • thickbox.js

※jquery.jsの名前はjquery-latest.jsだったりするかも


thickbox.jsの8行目でloadingAnimation.gifのパスが設定されているので
loadingAnimation.gifのパスを自分に環境に合わせます。
var tb_pathToImage = "images/loadingAnimation.gif";


ThickBoxを利用したいhtmlのhead要素などでファイルを読み込みます。
<link rel="stylesheet" href="thickbox.css" type="text/css" media="all">
<script type="text/javascript" src="jquery-latest.js" ></script>
<script type="text/javascript" src="thickbox.js"></script>



あとは実際に使用するHTMLに設置するだけです。

▼画像拡大の場合
サムネイル画像と拡大画像へのリンクを張ります。一番見かけますね。
<a href="拡大画像1.jpg" class="thickbox" title="サンプル" rel="test"><img src="サムネイル画像1.jpg" width="160" height="120" alt="サンプル" border="0" /></a>
<a href="拡大画像2.jpg" class="thickbox" title="サンプル" rel="test"><img src="サムネイル画像2.jpg" width="160" height="120" alt="サンプル" border="0" /></a>



▼HTML拡大表示
HTMLを表示することもできます。
<a href="test.html?width=400&height=200" class="thickbox">testhtml</a>


▼iframe拡大表示
iframeを表示することもできるんですね。
<a href="test.html?TB_iframe=true&width=400&height=300" class="thickbox">testhtmlInIframe</a>


▼ページ内HTML拡大表示
ページ内のHTMLを拡大表示することもできます。ページ内のdiv要素をdisplay:noneにしておいて、リンククリックで表示みたいな。
<a href="#TB_inline?width=400&height=300&inlineId=thickboxdivtest" class="thickbox">ページ内HTMLテスト</a>
<div id="thickboxdivtest" style="display:none"><span style="font-weight:bold">テスト文字表示だよ<br/>テスト文字表示だよ<br/></span></div>



注意点
ちなみに、最初グループ化属性のrel属性をつけると画像が表示されませんでした。
jqueryとthickboxのversionに相性があるようで、rel属性をつけると画像が表示されない
場合は以下の修正をすると動作するようになります。

thickbox.js(ver3.1、unCompressed)の79行目を以下のように修正
TB_TempArray = $(“a[@rel="+imageGroup+"]“).get();
                 ↓
TB_TempArray = $(“a[rel="+imageGroup+"]“).get();




ThickBox、簡単に設置できるのでお勧めです。
とりあえず使い方は押さえたので、thickbox.js、thickbox.cssをカスタマイズすればまた色々できそうですね。

2010年10月22日金曜日

seasar2のdicon設定 namespace指定はメモリを喰う?

seasar2のdiconファイル定義では、components要素に
namespace属性を指定できます。
http://s2container.seasar.org/2.4/ja/reference/html/config-dicon.html#d0e1484

名前空間を指定できるわけですが、これを指定すると
メモリ使用量(heapsize)がけっこう増えます
(もちろん登録コンポーネント数にもよりますが)。
heapdumpして確認するとS2ContainerのHashMapの
容量がだいぶ変わることがわかりました。

S2Container内で管理しているコンポーネント名が
長くなると思うので単純に増えそうではありますが。。

今回はAutoRegisterで大量にコンポーネントを登録し、
namespaceを全てのdiconにつけていました。
必要のないnamespace指定を取り除いたところ、
以下のような結果となりました。
namespaceをつける        S2ContainerのHashMap 約1GB
namespaceをつけない(※1) S2ContainerのHashMap 約400MB 

(※1)もともとseasar2のjarに含まれているdiconを拡張したものは
     namespaces指定そのまま。
     データソースの切替等でJDBC関連の必要な部分はnamespaceを指定。

使用しているS2のversionはseasar2.4.25で、だいたい2.4系はSmartDeployを
使用すると思うのであまり注意は必要ないかもしれませんが、
とりあえずnamespaceを無駄に指定するのはよくなさそうですね。

2010年10月19日火曜日

webページの横幅は何pxにすべきか

ふとサイト製作におけるWEBページの横幅の妥当性を知りたくなったので調べてみた。軽くぐぐっただけで大量に情報がありますね。

1000px弱時代のWebデザイン
web屋が主張する「リキッドレイアウト」に騙されないために
webページ作成の際に、横幅を何ピクセルにすべきでしょうか。
横幅を固定するな!後悔しないためのWebデザイン
固定か可変かそれが問題だ
mixiのデザイン変更から学ぶ、ウェブサイトの最小横幅を800px以下にすべき理由
気持ちのいいサイトとは(3)~リキッドデザイン~
リキッドデザイン問題はmax-widthとIE6用expressionで解決



まずは対象となるターゲットユーザは誰か。
一般ユーザなのか、イントラネット内の企業ユーザなのかで
大きく分かれると思います。

企業ユーザであれば、ブラウザの種類や端末の解像度もおおよそ見当が付くこと
多いと思いますのでそれに合わせて作成するのがよいかと。

一般ユーザの場合はブラウザや端末の種類が多岐に渡るのでなかなか難しいですが、
横幅800~1000px弱で作成するのが無難なのではないでしょうか。


リキッドデザインはよいとは思うのですが、「ブラウザを最大化すると逆に見にくい」という問題もあります。
max-widthを利用して広がり過ぎを解決するという方法もあるようです。
リキッドデザイン問題はmax-widthとIE6用expressionで解決

で、自分なりの結論ですが、1000px弱時代のWebデザインにあるように
ほとんどのユーザーが横幅1024px以上表示できることと、デザインのし易さから固定幅横幅800~1000px弱でサイトをデザインすることがよいのではないかと思いました。
もちろん、ケースバイケースではあるのですが。。



あとIE6の場合は、印刷対策をしとかないと見切れたりするので注意が必要ですね。
ブラウザ印刷とスクリーン解像度の不思議な関係
印刷できるページを作るには
印刷用CSS:webページの横幅について

2010年10月15日金曜日

アップロードファイルのローカル最終更新日時を取得できるか

WEBアプリにてアップロードファイルのローカル最終更新日時を
取得できるか調べてみましたが、結論から言うとできません。
言語はJavaですが多言語も同様です。

[調査1]
・リクエストをパケットモニタしましたが、
   飛んでいる情報は以下3つになります。
    フィールド名
    ファイルパス
    ファイル内容


[調査2]
 ・RFC 1867 ファイルアップロードについての規定にも
   タイムスタンプの記載はなし
  RFC原文
  studyinghttp日本語訳
 
上記調査からタイムスタンプのようなファイル属性はhttp通信時に
欠落する(リクエストに付加されない)ためサーバ側で取得
することは不可能。


最終更新日時の取得などはファイルの一意性を確認したい
場合が多いと思うので、別の方法として
java.security.DigestInputStream等を使用してファイル内容の
ハッシュ値を保存しておく方法が考えられる
(よくダウンロードファイルの改変チェックに使用されているもの)。

 ファイル名
 ファイルサイズ
 ハッシュ値
の比較で全て同じであればファイルの一意性としても
よいかな。

2010年10月8日金曜日

Teeda sendRedirectでIllegalStateException

Teedaでrendererの拡張を行っているのですが、sendRedirectでIllegalStateExceptionが発生。
java.lang.IllegalStateException
    at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:435)
    at org.seasar.teeda.core.util.ServletExternalContextUtil.redirect(ServletExternalContextUtil.java:188)
    at org.seasar.teeda.extension.context.TmsServletExternalContextImpl.redirect(TmsServletExternalContextImpl.java:298)
    at org.seasar.teeda.core.util.NavigationHandlerUtil.redirect(NavigationHandlerUtil.java:55)
    at org.seasar.teeda.extension.util.TeedaExtensionErrorPageManagerImpl.handleException(TeedaExtensionErrorPageManagerImpl.java:84)
    at org.seasar.teeda.core.lifecycle.LifecycleImpl.handleException(LifecycleImpl.java:116)
    at org.seasar.teeda.core.lifecycle.LifecycleImpl.render(LifecycleImpl.java:135)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:101)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at jp.co.isid.fine.io.file.UploadFilter.doFilter(UploadFilter.java:60)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.seasar.teeda.core.filter.RequestDumpFilter.doFilter(RequestDumpFilter.java:125)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.seasar.framework.container.hotdeploy.HotdeployFilter.doFilter(HotdeployFilter.java:70)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.seasar.framework.container.filter.S2ContainerFilter.doFilter(S2ContainerFilter.java:77)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.seasar.extension.filter.EncodingFilter.doFilter(EncodingFilter.java:69)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at jp.mufg.tms.base.web.filter.SessionInvalidateFilter.doFilter(SessionInvalidateFilter.java:47)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at jp.mufg.tms.base.web.filter.ThreadLocalFilter.doFilter(ThreadLocalFilter.java:72)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at jp.mufg.tms.base.web.filter.NocacheFilter.doFilter(NocacheFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    at java.lang.Thread.run(Thread.java:619)


スタックトレース見ればわかりますが、レンダリングでエラーが発生した場合は
org.seasar.teeda.core.lifecycle.LifecycleImpl#handleExceptionにデバッグいれると
エラーの内容がわかりますね。

jspで開発していた時に、jsp:includeを使用してflush="ture"にしている場合に、
カスタムタグ内でsendRedirectすると似たような例外が発生した記憶があったので、
(レスポンスをコミットした状態[表示結果を一部でも返している状態]でリダイレクトしていたため)
一瞬全然見当違いな調査をしてしまったのですが、Pageクラスのgetterの名前が正しくないだけでした。。(おつ

2010年10月7日木曜日

javascript Window間オブジェクト操作の注意点

window.openして子ウィンドウ側から親ウィンドウのselectboxの値を変更するコードを実行したところ
「サーバによって例外が返されました」というわけわからないエラーが発生(サーバにアクセスしてないし)。。
※テストブラウザはIE6

var option = new Option('xxxxx','xxxxx');
parentSelectObj.options[parentSelectObj.options.length] = option;
 //↑ここで上記エラー


ふーむ、ネット調べたりオライリー本読み直してみたところ、
・フレーム間、ウィンドウ間ではスコープチェーンが違う
・関数が実行されるスコープは、関数を呼び出したフレームではなく関数が定義されたフレーム(ウィンドウもしかり)
・コンストラクタも関数
・コンストラクタとそのコンストラクタのプロトタイプオブジェクトは、ウィンドウごとに独立

言われてみれば確かに。


というわけで、コードを以下に修正したところ無事動作しました。

var option = window.opener.document.createElement('Option');
option.text  = 'xxxxx';
option.value = 'xxxxx';
parentSelectObj.options[parentSelectObj.options.length] = option;