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
020 package org.apache.wiki.forms;
021
022 import org.apache.wiki.WikiContext;
023 import org.apache.wiki.api.exceptions.PluginException;
024 import org.apache.wiki.api.plugin.WikiPlugin;
025 import org.apache.wiki.preferences.Preferences;
026 import org.apache.wiki.util.XHTML;
027 import org.apache.wiki.util.XhtmlUtil;
028 import org.jdom2.Element;
029
030 import java.util.HashMap;
031 import java.util.Map;
032 import java.util.ResourceBundle;
033
034 /**
035 * Creates a Form select field.
036 */
037 public 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 }