001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019 020package org.apache.wiki.forms; 021 022import org.apache.wiki.WikiContext; 023import org.apache.wiki.api.exceptions.PluginException; 024import org.apache.wiki.api.plugin.WikiPlugin; 025import org.apache.wiki.preferences.Preferences; 026import org.apache.wiki.util.XHTML; 027import org.apache.wiki.util.XhtmlUtil; 028import org.jdom2.Element; 029 030import java.util.HashMap; 031import java.util.Map; 032import java.util.ResourceBundle; 033 034/** 035 * Creates a Form select field. 036 */ 037public class FormSelect 038 extends FormElement 039{ 040 /** 041 * {@inheritDoc} 042 */ 043 public String execute( WikiContext ctx, Map< String, String > params ) 044 throws PluginException 045 { 046 // Don't render if no error and error-only-rendering is on. 047 FormInfo info = getFormInfo( ctx ); 048 049 ResourceBundle rb = Preferences.getBundle( ctx, WikiPlugin.CORE_PLUGINS_RESOURCEBUNDLE ); 050 Map< String, String > previousValues = null; 051 052 if ( info != null ) 053 { 054 if ( info.hide() ) 055 { 056 return "<p>" + rb.getString( "forminput.noneedtoshow" ) + "</p>"; 057 } 058 previousValues = info.getSubmission(); 059 } 060 061 if ( previousValues == null ) 062 { 063 previousValues = new HashMap< String, String >(); 064 } 065 066 Element field = buildSelect( params, previousValues, rb ); 067 068 // We should look for extra params, e.g. width, ..., here. 069 return XhtmlUtil.serialize(field); // ctx.getEngine().getContentEncoding() 070 } 071 072 073 /** 074 * Builds a Select element. 075 */ 076 private Element buildSelect( 077 Map<String,String> pluginParams, 078 Map<String,String> ctxValues, 079 ResourceBundle rb ) 080 throws PluginException 081 { 082 String inputName = pluginParams.get( PARAM_INPUTNAME ); 083 if ( inputName == null ) { 084 throw new PluginException( rb.getString( "formselect.namemissing" ) ); 085 } 086 087 String inputValue = pluginParams.get( PARAM_VALUE ); 088 String previousValue = ctxValues.get( inputName ); 089 // 090 // We provide several ways to override the separator, in case 091 // some input application the default value. 092 // 093 String optionSeparator = pluginParams.get( "separator" ); 094 if ( optionSeparator == null ) { 095 optionSeparator = ctxValues.get( "separator." + inputName); 096 } 097 if ( optionSeparator == null ) { 098 optionSeparator = ctxValues.get( "select.separator" ); 099 } 100 if ( optionSeparator == null ) { 101 optionSeparator = ";"; 102 } 103 104 String optionSelector = pluginParams.get( "selector" ); 105 if ( optionSelector == null ) { 106 optionSelector = ctxValues.get( "selector." + inputName ); 107 } 108 if ( optionSelector == null ) { 109 optionSelector = ctxValues.get( "select.selector" ); 110 } 111 if ( optionSelector == null ) { 112 optionSelector = "*"; 113 } 114 if ( optionSelector.equals( optionSeparator ) ) { 115 optionSelector = null; 116 } 117 if ( inputValue == null ) { 118 inputValue = ""; 119 } 120 121 // If values from the context contain the separator, we assume 122 // that the plugin or something else has given us a better 123 // list to display. 124 boolean contextValueOverride = false; 125 if ( previousValue != null ) { 126 if ( previousValue.indexOf( optionSeparator ) != -1 ) { 127 inputValue = previousValue; 128 previousValue = null; 129 } else { 130 // If a context value exists, but it's not a list, 131 // it'll just override any existing selector 132 // indications. 133 contextValueOverride = true; 134 } 135 } 136 137 String[] options = inputValue.split( optionSeparator ); 138 int previouslySelected = -1; 139 140 Element[] optionElements = new Element[options.length]; 141 142 // 143 // Figure out which one of the options to select: prefer the one 144 // that was previously selected, otherwise try to find the one 145 // with the "select" marker. 146 // 147 for( int i = 0; i < options.length; i++ ) { 148 int indicated = -1; 149 options[i] = options[i].trim(); 150 151 if ( optionSelector != null && options[i].startsWith( optionSelector ) ) { 152 options[i] = options[i].substring( optionSelector.length() ); 153 indicated = i; 154 } 155 if ( previouslySelected == -1 ) { 156 if ( !contextValueOverride && indicated > 0 ) { 157 previouslySelected = indicated; 158 } else if ( previousValue != null && options[i].equals( previousValue ) ) { 159 previouslySelected = i; 160 } 161 } 162 163 // huh? 164// optionElements[i] = new option( options[i] ); 165// optionElements[i].addElement( options[i] ); 166 167 optionElements[i] = XhtmlUtil.element(XHTML.option,options[i]); 168 } 169 170 if ( previouslySelected > -1 ) { 171 optionElements[previouslySelected].setAttribute(XHTML.ATTR_selected,"true"); 172 } 173 174 Element select = XhtmlUtil.element(XHTML.select); 175 select.setAttribute(XHTML.ATTR_name,HANDLERPARAM_PREFIX + inputName); 176 for ( Element option : optionElements ) { 177 select.addContent(option); 178 } 179 return select; 180 } 181}