001/*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.hayabusa.taglib;
017
018import static org.opengion.fukurou.util.StringUtil.nval;
019
020import java.io.IOException;
021import java.io.ObjectInputStream;
022import java.io.ObjectOutputStream;
023
024import org.opengion.fukurou.util.Options;
025import org.opengion.hayabusa.common.HybsSystem;
026
027/**
028 * フォームの入力欄などで入力候補となるデータリストを定義するHTML拡張タグです。
029 * HTML5 から、新たに追加された要素です。
030 *
031 * データリスト内の選択肢は、optionタグ、queryOptionタグによって指定します。
032 * データリスト の id 属性は、フォームの list 属性と同じキーを指定する事で関連付けします。
033 *
034 * @og.formSample
035 * ●形式:<og:datalist id="…" />
036 * ●body:あり(EVAL_BODY_INCLUDE:BODYをインクルードし、{@XXXX} は解析しません)
037 *
038 * ●Tag定義:
039 *   <og:datalist
040 *       id               ○【TAG】入力候補を表示するフォームの list 属性に設定する id (必須)
041 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
042 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
043 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:true)
044 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:true)
045 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
046 *   >   ... Body ...
047 *   </og:datalist>
048 *
049 * ●使用例
050 * <og:input type="text" name="tokyo" autocomplete="on" list="tokyo.sel" />
051 *
052 *  <og:datalist id="tokyo.sel" >
053 *      <og:option value="渋谷" />
054 *      <og:option value="新宿" />
055 *      <og:option value="池袋" />
056 *  </og:datalist><
057 *
058 * @og.group 【HTML5】選択データ制御
059 * @og.rev 5.7.1.0 (2013/12/06) 新規追加
060 *
061 * @version  6.0
062 * @author       Kazuhiko Hasegawa
063 * @since    JDK5.0,
064 */
065public class DatalistTag extends CommonTagSupport implements OptionAncestorIF {
066        //* このプログラムのVERSION文字列を設定します。   {@value} */
067        private static final String VERSION = "5.7.6.2 (2014/05/16)" ;
068
069        private static final long serialVersionUID = 576220140516L ;
070
071        private transient Options option        = new Options();
072
073        private String id       = null;         // フォームと関連付けるid
074
075        /**
076         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
077         *
078         * @return      後続処理の指示( EVAL_BODY_INCLUDE )
079         */
080        @Override
081        public int doStartTag() {
082                if( useTag() ) {
083                        return EVAL_BODY_INCLUDE ;      // Body インクルード( extends TagSupport 時)
084                }
085                return SKIP_BODY ;                              // Body を評価しない
086        }
087
088        /**
089         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
090         *
091         * @og.rev 5.7.6.2 (2014/05/16) IEのHTML5機能が無効の場合、INDBMENU を作成します。
092         *
093         * @return      後続処理
094         */
095        @Override
096        public int doEndTag() {
097                debugPrint();           // 4.0.0 (2005/02/28)
098                // 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
099                if( useTag() ) {
100                        StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
101
102                        // 5.7.6.2 (2014/05/16) IEのHTML5機能が無効の場合の処理
103                        String ieHTML5 = (String)getSessionAttribute( HybsSystem.IE_HTML5_KEY );
104                        if( "FALSE".equalsIgnoreCase( ieHTML5 ) ) {
105                                String inName = id.endsWith( ".sel" ) ? id.substring( 0,id.length()-4 ) : id ;
106
107                                rtn.append("<select id='").append( id )
108                                        .append( "' style='position:absolute;' onChange='selChanged(this);' >" )
109                                        .append( option.getOption() )
110                                        .append( "</select>" )
111                                        .append( "<script type='text/javascript'>makeInputMenu('" )
112                                        .append( inName ).append( "');</script>" );
113                        }
114                        else {
115                                // display:none は、datalist の optionのBODY部が、HTML5 以外では表示されてしまうため。
116                                rtn.append("<div style='display:none;'>" )
117                                        .append("<datalist id='").append( id ).append( "' >" )
118                                        .append( option.getOption() )
119                                        .append( "</datalist>" )
120                                        .append( "</div>" );
121                        }
122
123                        jspPrint( rtn.toString() );
124                }
125                return EVAL_PAGE ;
126        }
127
128        /**
129         * タグリブオブジェクトをリリースします。
130         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
131         *
132         */
133        @Override
134        protected void release2() {
135                super.release2();
136                option  = new Options();
137                id              = null;
138        }
139
140        /**
141         * データリストの選択項目を追加します。
142         *
143         * datalist タグのBODY要素の OptionTag よりアクセスされます。
144         *
145         * @param       opt      オプションタグ文字列
146         */
147        public void addOption( final String opt ) {
148                option.add( opt );
149        }
150
151        /**
152         * 【HTML】要素に対して固有の名前(id)をつける場合に設定します。
153         *
154         * @og.tag
155         * データリスト の id 属性は、フォームの list 属性と同じキーを指定する事で関連付けします。
156         *
157         * ※
158         * 内部事情で、inputタグ(columnタグ)の list属性 に設定するキーも、id属性に設定するキーも、
159         * inputタグ(columnタグ)の name属性+".sel" を標準的に使用してください。
160         *
161         * @param   id 固有の名前
162         */
163        @Override
164        public void setId( final String id ) {
165                this.id = nval( getRequestParameter( id ), null );
166        }
167
168        /**
169         * 値を外部から取り出します。
170         *
171         * OptionTag で、value を取り出して、内部の値と同じ場合は、選択状態にします。
172         *
173         * @og.rev 3.5.4.0 (2003/11/25) 新規作成
174         *
175         * @return      内部に設定された値
176         */
177        public String getValue() {
178                // ここでは、何もしません。
179                return null;
180        }
181
182        /**
183         * 複数選択可能時に全選択を設定するかどうかを返します。
184         *
185         * これは、上位入れ子のタグの OptionTag で、multipleAll を取り出して、
186         * true であれば、全選択に設定します。
187         *
188         * @og.rev 3.8.0.9 (2005/10/17) 新規作成
189         *
190         * @return      全選択:true / 通常:false
191         */
192        public boolean isMultipleAll() {
193                // ここでは、何もしません。
194                return false;
195        }
196
197        /**
198         * パラメーター変換({&#064;XXXX}の置き換えをしない状態のパラメーターをセットします。
199         *
200         * @og.rev 5.1.7.0 (2010/06/01) 新規作成(動的プルダウン実装見直し)
201         * @og.rev 5.5.4.0 (2012/07/02) 予約語対応
202         *
203         * @param   param パラメーター
204         */
205        public void setRawParam( final String param ) {
206                // ここでは、何もしません。
207        }
208
209        /**
210         * シリアライズ用のカスタムシリアライズ書き込みメソッド
211         *
212         * @serialData 一部のオブジェクトは、シリアライズされません。
213         *
214         * @param       strm    ObjectOutputStreamオブジェクト
215         * @throws IOException  シリアライズに関する入出力エラーが発生した場合
216         */
217        private void writeObject( final ObjectOutputStream strm ) throws IOException {
218                strm.defaultWriteObject();
219        }
220
221        /**
222         * シリアライズ用のカスタムシリアライズ読み込みメソッド
223         *
224         * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
225         *
226         * @serialData 一部のオブジェクトは、シリアライズされません。
227         *
228         * @param       strm    ObjectInputStreamオブジェクト
229         * @see #release2()
230         * @throws IOException  シリアライズに関する入出力エラーが発生した場合
231         * @throws ClassNotFoundException       クラスを見つけることができなかった場合
232         */
233        private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
234                strm.defaultReadObject();
235                option = new Options();
236        }
237
238        /**
239         * このオブジェクトの文字列表現を返します。
240         * 基本的にデバッグ目的に使用します。
241         *
242         * @return このクラスの文字列表現
243         */
244        @Override
245        public String toString() {
246                return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
247                                .println( "VERSION"             ,VERSION                )
248                                .println( "id"                  ,id                             )
249                                .println( "Other..."    ,getAttributes().getAttribute() )
250                                .fixForm().toString() ;
251        }
252}