001// Copyright 2008-2024 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.internal.util;
016
017import org.apache.tapestry5.*;
018
019import java.util.Map;
020
021public class SelectModelRenderer implements SelectModelVisitor
022{
023    private final MarkupWriter writer;
024
025    private final ValueEncoder encoder;
026
027    private final boolean raw;
028
029    private int optgroupIdx = -1;
030    private boolean inOptgroup = false;
031
032    public SelectModelRenderer(final MarkupWriter writer, ValueEncoder encoder, boolean raw)
033    {
034        this.writer = writer;
035        this.encoder = encoder;
036        this.raw = raw;
037    }
038
039    @Override
040    public void beginOptionGroup(OptionGroupModel groupModel)
041    {
042        this.optgroupIdx++;
043        this.inOptgroup = true;
044        this.writer.element("optgroup", "label", groupModel.getLabel());
045
046        writeDisabled(groupModel.isDisabled());
047        writeAttributes(groupModel.getAttributes());
048    }
049
050    @Override
051    public void endOptionGroup(OptionGroupModel groupModel)
052    {
053        this.inOptgroup = false;
054        this.writer.end(); // select
055    }
056
057    @Override
058    @SuppressWarnings("unchecked")
059    public void option(OptionModel optionModel)
060    {
061        Object optionValue = optionModel.getValue();
062
063        String clientValue = this.encoder.toClient(optionValue);
064
065        this.writer.element("option", "value", clientValue);
066
067        if (this.inOptgroup && this.optgroupIdx > -1)
068        {
069            this.writer.attributes("data-optgroup-idx", this.optgroupIdx);
070        }
071
072        if (isOptionSelected(optionModel, clientValue))
073        {
074            this.writer.attributes("selected", "selected");
075        }
076
077        writeDisabled(optionModel.isDisabled());
078        writeAttributes(optionModel.getAttributes());
079
080
081        if (this.raw)
082        {
083            this.writer.writeRaw(optionModel.getLabel());
084        } else
085        {
086            this.writer.write(optionModel.getLabel());
087        }
088
089        this.writer.end();
090    }
091
092    private void writeDisabled(boolean disabled)
093    {
094        if (disabled)
095        {
096            this.writer.attributes("disabled", "disabled");
097        }
098    }
099
100    private void writeAttributes(Map<String, String> attributes)
101    {
102        if (attributes == null)
103        {
104            return;
105        }
106
107        for (Map.Entry<String, String> e : attributes.entrySet())
108        {
109            this.writer.attributes(e.getKey(), e.getValue());
110        }
111    }
112
113    /**
114     * If true, then the selected attribute will be written. This implementation always returns false.
115     */
116    protected boolean isOptionSelected(OptionModel optionModel, String clientValue)
117    {
118        return false;
119    }
120
121}