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 org.opengion.fukurou.system.OgRuntimeException; // 6.4.2.0 (2016/01/29) 019import static org.opengion.fukurou.util.StringUtil.nval; 020 021import java.io.IOException; 022import java.io.ObjectInputStream; 023 024import org.opengion.fukurou.util.Options; 025//import org.opengion.hayabusa.common.HybsSystem; // 8.5.2.0 (2023/07/14) Delete 026import org.opengion.fukurou.util.ToString; // 6.1.1.0 (2015/01/17) 027 028/** 029 * フォームの入力欄などで入力候補となるデータリストを定義するHTML拡張タグです。 030 * HTML5 から、新たに追加された要素です。 031 * 032 * データリスト内の選択肢は、optionタグ、queryOptionタグによって指定します。 033 * データリスト の id 属性は、フォームの list 属性と同じキーを指定する事で関連付けします。 034 * 035 * @og.formSample 036 * ●形式:<og:datalist id="…" /> 037 * ●body:あり(EVAL_BODY_INCLUDE:BODYをインクルードし、{@XXXX} は解析しません) 038 * 039 * ●Tag定義: 040 * <og:datalist 041 * id ○【TAG】入力候補を表示するフォームの list 属性に設定する id (必須) 042 * caseKey 【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 043 * caseVal 【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 044 * caseNN 【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない) 045 * caseNull 【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない) 046 * caseIf 【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない) 047 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 048 * > ... Body ... 049 * </og:datalist> 050 * 051 * ●使用例 052 * <og:input type="text" name="tokyo" autocomplete="on" list="tokyo.sel" /> 053 * 054 * <og:datalist id="tokyo.sel" > 055 * <og:option value="渋谷" /> 056 * <og:option value="新宿" /> 057 * <og:option value="池袋" /> 058 * </og:datalist> 059 * 060 * ただし、値なしのOptionを含めても(addNoValue="true")、HTML5の仕様上、 061 * 値なしのOptionは表示されません。 062 * 063 * @og.group 【HTML5】選択データ制御 064 * @og.rev 5.7.1.0 (2013/12/06) 新規追加 065 * 066 * @version 6.0 067 * @author Kazuhiko Hasegawa 068 * @since JDK5.0, 069 */ 070public class DatalistTag extends CommonTagSupport implements OptionAncestorIF { 071 /** このプログラムのVERSION文字列を設定します。 {@value} */ 072 private static final String VERSION = "8.5.2.0 (2023/07/14)" ; 073 private static final long serialVersionUID = 852020230714L ; 074 075 private transient Options option = new Options(); 076 /** フォームと関連付けるid */ 077 private String id; 078 079 /** 080 * デフォルトコンストラクター 081 * 082 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor. 083 */ 084 public DatalistTag() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 085 086 /** 087 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 088 * 089 * @return 後続処理の指示( EVAL_BODY_INCLUDE ) 090 */ 091 @Override 092 public int doStartTag() { 093 // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method 094 return useTag() 095 ? EVAL_BODY_INCLUDE // Body インクルード( extends TagSupport 時) 096 : SKIP_BODY ; // Body を評価しない 097 } 098 099 /** 100 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 101 * 102 * @og.rev 5.7.6.2 (2014/05/16) IEのHTML5機能が無効の場合、INDBMENU を作成します。 103 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 104 * @og.rev 8.5.2.0 (2023/07/14) 一部の機能廃止による修正(問合・トラブル 0200010980) 105 * 106 * @return 後続処理 107 */ 108 @Override 109 public int doEndTag() { 110 debugPrint(); // 4.0.0 (2005/02/28) 111 // 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応 112 if( useTag() ) { 113 // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 114 if( id == null ) { 115 final String errMsg = "idは必須です。" ; 116 throw new OgRuntimeException( errMsg ); 117 } 118 119 final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE ); 120 121// // 5.7.6.2 (2014/05/16) IEのHTML5機能が無効の場合の処理 8.5.2.0 (2023/07/14) Delete 122// final String ieHTML5 = (String)getSessionAttribute( HybsSystem.IE_HTML5_KEY ); 123// if( "FALSE".equalsIgnoreCase( ieHTML5 ) ) { 124// final String inName = id.endsWith( ".sel" ) ? id.substring( 0,id.length()-4 ) : id ; 125// 126// rtn.append("<select id='").append( id ) 127// .append( "' style='position:absolute;' onChange='selChanged(this);' >" ) 128// .append( option.getOption() ) 129// // 8.1.0.0 (2021/12/28) HTML5 準拠に見直し(<script> type属性削除) 130//// .append( "</select><script type='text/javascript'>makeInputMenu('" ) 131// .append( "</select><script>makeInputMenu('" ) 132// .append( inName ).append( "');</script>" ); 133// } 134// else { 135// // display:none は、datalist の optionのBODY部が、HTML5 以外では表示されてしまうため。 136// rtn.append("<div style='display:none;'><datalist id='") 137// .append( id ).append( "' >" ) 138// .append( option.getOption() ) 139// .append( "</datalist></div>" ); 140// } 141 rtn.append("<datalist id='") 142 .append( id ).append( "' >" ) 143 .append( option.getOption() ) 144 .append( "</datalist>" ); 145 146 jspPrint( rtn.toString() ); 147 } 148 return EVAL_PAGE ; 149 } 150 151 /** 152 * タグリブオブジェクトをリリースします。 153 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 154 * 155 */ 156 @Override 157 protected void release2() { 158 super.release2(); 159 option = new Options(); 160 id = null; 161 } 162 163 /** 164 * データリストの選択項目を追加します。 165 * 166 * datalist タグのBODY要素の OptionTag よりアクセスされます。 167 * 168 * @param opt オプションタグ文字列 169 * @see org.opengion.hayabusa.taglib.OptionAncestorIF#addOption( String ) 170 */ 171 @Override // OptionAncestorIF 172 public void addOption( final String opt ) { 173 option.add( opt ); 174 } 175 176 /** 177 * メニュー項目の最後の項目を削除します。 178 * 179 * select タグのBODY要素の OptionTag よりアクセスされます。 180 * 181 * @og.rev 6.8.0.0 (2017/06/02) メニュー項目の最後の項目を削除。 182 * 183 * @see org.opengion.hayabusa.taglib.OptionAncestorIF#removeLast() 184 */ 185 @Override // OptionAncestorIF 186 public void removeLast() { 187 option.removeLast(); 188 } 189 190 /** 191 * 【HTML】要素に対して固有の名前(id)をつける場合に設定します。 192 * 193 * @og.tag 194 * データリスト の id 属性は、フォームの list 属性と同じキーを指定する事で関連付けします。 195 * 196 * ※ 197 * 内部事情で、inputタグ(columnタグ)の list属性 に設定するキーも、id属性に設定するキーも、 198 * inputタグ(columnタグ)の name属性+".sel" を標準的に使用してください。 199 * 200 * @param id 固有の名前 201 */ 202 @Override 203 public void setId( final String id ) { 204 this.id = nval( getRequestParameter( id ), null ); 205 } 206 207 /** 208 * 値を外部から取り出します。 209 * 210 * OptionTag で、value を取り出して、内部の値と同じ場合は、選択状態にします。 211 * 212 * @og.rev 5.7.1.0 (2013/12/06) 新規追加 213 * 214 * @return null固定 215 * @see org.opengion.hayabusa.taglib.OptionAncestorIF#addOption( String ) 216 */ 217 @Override // OptionAncestorIF 218 public String getValue() { 219 // ここでは、何もしません。 220 return null; 221 } 222 223 /** 224 * 複数選択可能時に全選択を設定するかどうかを返します。 225 * 226 * これは、上位入れ子のタグの OptionTag で、multipleAll を取り出して、 227 * true であれば、全選択に設定します。 228 * 229 * @og.rev 5.7.1.0 (2013/12/06) 新規追加 230 * 231 * @return false固定 232 * @see org.opengion.hayabusa.taglib.OptionAncestorIF#addOption( String ) 233 */ 234 @Override // OptionAncestorIF 235 public boolean isMultipleAll() { 236 // ここでは、何もしません。 237 return false; 238 } 239 240 /** 241 * パラメーター変換({@XXXX}の置き換えをしない状態のパラメーターをセットします。 242 * 243 * ※ ここでは、何もしません。 244 * 245 * @og.rev 5.7.1.0 (2013/12/06) 新規追加 246 * 247 * @param param パラメーター 248 * @see org.opengion.hayabusa.taglib.OptionAncestorIF#addOption( String ) 249 */ 250 @Override // OptionAncestorIF 251 public void setRawParam( final String param ) { 252 // ここでは、何もしません。 253 } 254 255 /** 256 * セレクトメニューの場合、キー:ラベル形式で表示するかどうか[true/false/null]を返します。 257 * 258 * これは、上位入れ子のタグの OptionTag で、addKeyLabel を取り出して、 259 * true であれば、キー:ラベル形式 のオプションを、#addOption( String ) で 260 * 登録させます。 261 * 262 * @og.rev 6.0.4.0 (2014/11/28) キー:ラベル形式で表示するかどうか。新規追加 263 * 264 * @return null固定 265 * @see #addOption( String ) 266 * @see org.opengion.hayabusa.taglib.OptionAncestorIF#getAddKeyLabel() 267 */ 268 @Override // OptionAncestorIF 269 public String getAddKeyLabel() { 270 // ここでは、何もしません。 271 return null; 272 } 273 274 /** 275 * シリアライズ用のカスタムシリアライズ読み込みメソッド 276 * 277 * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。 278 * 279 * @serialData 一部のオブジェクトは、シリアライズされません。 280 * 281 * @param strm ObjectInputStreamオブジェクト 282 * @see #release2() 283 * @throws IOException シリアライズに関する入出力エラーが発生した場合 284 * @throws ClassNotFoundException クラスを見つけることができなかった場合 285 */ 286 private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException { 287 strm.defaultReadObject(); 288 option = new Options(); 289 } 290 291 /** 292 * このオブジェクトの文字列表現を返します。 293 * 基本的にデバッグ目的に使用します。 294 * 295 * @return このクラスの文字列表現 296 * @og.rtnNotNull 297 */ 298 @Override 299 public String toString() { 300 return ToString.title( this.getClass().getName() ) 301 .println( "VERSION" ,VERSION ) 302 .println( "id" ,id ) 303 .println( "Other..." ,getAttributes().getAttribute() ) 304 .fixForm().toString() ; 305 } 306}