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    }