001    package railo.runtime.tag;
002    
003    import java.io.IOException;
004    import java.util.Iterator;
005    import java.util.Map.Entry;
006    
007    import javax.servlet.jsp.tagext.Tag;
008    
009    import railo.commons.lang.HTMLEntities;
010    import railo.runtime.exp.ApplicationException;
011    import railo.runtime.exp.ExpressionException;
012    import railo.runtime.exp.PageException;
013    import railo.runtime.ext.tag.BodyTagImpl;
014    import railo.runtime.op.Caster;
015    import railo.runtime.op.Operator;
016    import railo.runtime.type.Collection.Key;
017    import railo.runtime.type.Struct;
018    import railo.runtime.type.StructImpl;
019    import railo.runtime.type.util.KeyConstants;
020    import railo.runtime.type.util.ListUtil;
021    
022    /**
023     * 
024     */
025    public final class Select extends BodyTagImpl {
026        
027        private static final int QUERY_POSITION_ABOVE = 0;
028            private static final int QUERY_POSITION_BELOW = 1;
029            private railo.runtime.type.Query query;
030        private String[] selected;
031        private String value;
032        private String display;
033        private String passthrough;
034        
035        
036        
037        private Struct attributes=new StructImpl();
038        private InputBean input=new InputBean();
039            private boolean editable=false;
040            private int height=-1;
041            private int width=-1;
042            private String label;
043            private boolean visible=true;
044            private String tooltip;
045            private String group;
046            private int queryPosition=QUERY_POSITION_ABOVE;
047            private boolean caseSensitive=false;
048        
049        
050        @Override
051        public void release() {
052            super.release();
053            query=null;
054            selected=null;
055            value=null;
056            display=null;
057            passthrough=null;
058            editable=false;
059            height=-1;
060            width=-1;
061            label=null;
062            visible=true;
063            tooltip=null;
064            group=null;
065            queryPosition=QUERY_POSITION_ABOVE;
066            caseSensitive=false;
067            attributes.clear();
068            input=new InputBean();
069        }
070        
071        /**
072         * @param cssclass The cssclass to set.
073         */
074        public void setClass(String cssclass) {
075            attributes.setEL("class",cssclass);
076        }
077        /**
078         * @param cssstyle The cssstyle to set.
079         */
080        public void setStyle(String cssstyle) {
081            attributes.setEL("style",cssstyle);
082        }
083        /**
084         * @param id The id to set.
085         */
086        public void setId(String id) {
087            attributes.setEL("id",id);
088        }
089        /**
090         * @param multiple The multiple to set.
091         */
092        public void setMultiple(String multiple) {
093            // alles ausser false ist true
094            if(Caster.toBooleanValue(multiple,true)) attributes.setEL("multiple","multiple");
095        }
096        /**
097         * @param name The name to set.
098         */
099        public void setName(String name) {
100            attributes.setEL(KeyConstants._name,name);
101            input.setName(name);
102        }
103        /**
104         * @param size The size to set.
105         */
106        public void setSize(double size) {
107            attributes.setEL(KeyConstants._size,Caster.toString(size));
108        }
109        /**
110         * @param tabindex The tabindex to set.
111         */
112        public void setTabindex(String tabindex) {
113            attributes.setEL("class",tabindex);
114        }
115        /**
116         * @param title The title to set.
117         */
118        public void setTitle(String title) {
119            attributes.setEL(KeyConstants._title,title);
120        }
121        /**
122         * @param title The title to set.
123         */
124        public void setDir(String dir) {
125            attributes.setEL("dir",dir);
126        }
127        /**
128         * @param title The title to set.
129         */
130        public void setLang(String lang) {
131            attributes.setEL("lang",lang);
132        }
133        /**
134         * @param onblur The onblur to set.
135         */
136        public void setOnblur(String onblur) {
137            attributes.setEL("onblur",onblur);
138        }
139        /**
140         * @param onchange The onchange to set.
141         */
142        public void setOnchange(String onchange) {
143            attributes.setEL("onchange",onchange);
144        }
145        /**
146         * @param onclick The onclick to set.
147         */
148        public void setOnclick(String onclick) {
149            attributes.setEL("onclick",onclick);
150        }
151        /**
152         * @param ondblclick The ondblclick to set.
153         */
154        public void setOndblclick(String ondblclick) {
155            attributes.setEL("ondblclick",ondblclick);
156        }
157        /**
158         * @param onmousedown The onmousedown to set.
159         */
160        public void setOnmousedown(String onmousedown) {
161            attributes.setEL("onmousedown",onmousedown);
162        }
163        /**
164         * @param ondblclick The ondblclick to set.
165         */
166        public void setOnmouseup(String onmouseup) {
167            attributes.setEL("onmouseup",onmouseup);
168        }
169        /**
170         * @param ondblclick The ondblclick to set.
171         */
172        public void setOnmouseover(String onmouseover) {
173            attributes.setEL("onmouseover",onmouseover);
174        }
175        /**
176         * @param ondblclick The ondblclick to set.
177         */
178        public void setOnmousemove(String onmousemove) {
179            attributes.setEL("onmousemove",onmousemove);
180        }
181        /**
182         * @param ondblclick The ondblclick to set.
183         */
184        public void setOnmouseout(String onmouseout) {
185            attributes.setEL("onmouseout",onmouseout);
186        }
187        /**
188         * @param ondblclick The ondblclick to set.
189         */
190        public void setOnkeypress(String onkeypress) {
191            attributes.setEL("onkeypress",onkeypress);
192        }
193        /**
194         * @param ondblclick The ondblclick to set.
195         */
196        public void setOnkeydown(String onkeydown) {
197            attributes.setEL("onkeydown",onkeydown);
198        }
199        /**
200         * @param ondblclick The ondblclick to set.
201         */
202        public void setOnkeyup(String onkeyup) {
203            attributes.setEL("onkeyup",onkeyup);
204        }
205        /**
206         * @param onfocus The onfocus to set.
207         */
208        public void setOnfocus(String onfocus) {
209            attributes.setEL("onfocus",onfocus);
210        }
211    
212        /**
213         * @param message The message to set.
214         */
215        public void setMessage(String message) {
216            input.setMessage(message);
217        }
218        /**
219         * @param onerror The onerror to set.
220         */
221        public void setOnerror(String onerror) {
222            input.setOnError(onerror);
223        }
224        /**
225         * @param required The required to set.
226         */
227        public void setRequired(boolean required) {
228            input.setRequired(required);
229        }
230        /**
231         * @param passthrough The passthrough to set.
232         * @throws PageException
233         */
234        public void setPassthrough(Object passthrough) throws PageException {
235            if(passthrough instanceof Struct) {
236                Struct sct = (Struct) passthrough;
237                Iterator<Entry<Key, Object>> it = sct.entryIterator();
238                Entry<Key, Object> e;
239                while(it.hasNext()) {
240                    e = it.next();
241                    attributes.setEL(e.getKey(),e.getValue());
242                }
243            }
244            else this.passthrough = Caster.toString(passthrough);
245        }
246        /**
247         * @param query The query to set.
248         * @throws PageException 
249         */
250        public void setQuery(String strQuery) throws PageException {
251            this.query = Caster.toQuery(pageContext.getVariable(strQuery));
252        }
253        /**
254         * @param display The display to set.
255         */
256        public void setDisplay(String display) {
257            this.display = display;
258        }
259        
260        public void setDataformatas(String dataformatas) throws ApplicationException {
261            dataformatas=dataformatas.trim();
262            String lcDataformatas=dataformatas.toLowerCase();
263            if( "plaintext".equals(lcDataformatas) || 
264                    "html".equals(lcDataformatas)) {
265                    attributes.setEL("dataformatas",dataformatas);
266            }
267            else 
268                    throw new ApplicationException("attribute dataformatas for tag input has an invalid value ["+dataformatas+"], valid values are [plaintext, html");
269        }
270        
271        public void setDatafld(String datafld) {
272            attributes.setEL("datafld",datafld);
273        }
274        
275        public void setDatasrc(String datasrc) {
276            attributes.setEL("datasrc",datasrc);
277        }
278    
279        public void setDisabled(String disabled) {
280            // alles ausser false ist true
281            if(Caster.toBooleanValue(disabled,true)) setDisabled(true);
282        }
283    
284        private void setDisabled(boolean disabled) {
285            if(disabled) attributes.setEL("disabled","disabled");
286        }
287        
288        /**
289         * @param selected The selected to set.
290         */
291        public void setSelected(String selected) {
292            this.selected = ListUtil.trimItems(ListUtil.listToStringArray(selected,','));
293        }
294        /**
295         * @param value The value to set.
296         */
297        public void setValue(String value) {
298            this.value = value;
299        }
300        
301        @Override
302        public int doStartTag()     {
303                    return EVAL_BODY_BUFFERED;
304            }
305        
306        @Override
307        public int doEndTag() throws PageException {
308            try {
309                _doEndTag();
310                return EVAL_PAGE;
311            } catch (IOException e) {
312                throw Caster.toPageException(e);
313            }
314        }
315        
316        
317        private void _doEndTag() throws IOException, ExpressionException, PageException {
318            
319            // check 
320            if(query!=null) {
321                    if(value==null)
322                            throw new ApplicationException("if you have defined attribute query for tag select, you must also define attribute value");
323                    else if(!query.containsKey(value))
324                            throw new ApplicationException("invalid value for attribute [value], there is no column in query with name ["+value+"]");
325                    
326                    if(display!=null && !query.containsKey(display))
327                            throw new ApplicationException("invalid value for attribute [display], there is no column in query with name ["+display+"]");
328                    
329                    if(group!=null && !query.containsKey(group))
330                            throw new ApplicationException("invalid value for attribute [group], there is no column in query with name ["+group+"]");
331            }    
332            
333            input.setType(Input.TYPE_SELECT);
334            Tag parent=getParent();
335            while(parent!=null && !(parent instanceof Form)){
336                            parent=parent.getParent();
337                    }
338                    if(parent instanceof Form) {
339                        Form form = (Form)parent;
340                        form.setInput(input);       
341                    }
342                    else { 
343                        throw new ApplicationException("Tag cfselect must be inside a cfform tag");
344                    }
345            
346            
347            pageContext.forceWrite("<select");
348            
349            Iterator<Entry<Key, Object>> it = attributes.entryIterator();
350            Entry<Key, Object> e;
351            while(it.hasNext()) {
352                    e = it.next();
353                pageContext.forceWrite(" ");
354                pageContext.forceWrite(e.getKey().getString());
355                pageContext.forceWrite("=\"");
356                pageContext.forceWrite(enc(Caster.toString(e.getValue())));
357                pageContext.forceWrite("\"");
358            }
359            
360            if(passthrough!=null) {
361                pageContext.forceWrite(" ");
362                pageContext.forceWrite(passthrough);
363            }
364            pageContext.forceWrite(">\n");
365            
366    
367            if(bodyContent!=null && queryPosition==QUERY_POSITION_BELOW)pageContext.forceWrite(bodyContent.getString());
368            
369            // write query options
370            if(query!=null) {
371                int rowCount=query.getRowCount();
372                String v,d,currentGroup=null,tmp;
373                boolean hasDisplay=display!=null;
374                boolean hasGroup=group!=null;
375                
376                for(int i=1;i<=rowCount;i++) {
377                    v = Caster.toString(query.getAt(value,i));
378                    d = hasDisplay?Caster.toString(query.getAt(display,i)):v;
379                    if(hasGroup) {
380                            tmp=Caster.toString(query.getAt(group,i));
381                            if(currentGroup==null || !Operator.equals(currentGroup,tmp,true)) {
382                                    if(currentGroup!=null)pageContext.forceWrite("</optgroup>\n");
383                                    pageContext.forceWrite("<optgroup label=\""+tmp+"\">\n");
384                                    currentGroup=tmp;
385                            }
386                    }
387                    pageContext.forceWrite("<option"+selected(v,selected)+" value=\""+v+"\">"+d+"</option>\n");
388                }
389                    if(hasGroup)pageContext.forceWrite("</optgroup>\n");
390            }
391            
392            if(bodyContent!=null && queryPosition==QUERY_POSITION_ABOVE)pageContext.forceWrite(bodyContent.getString());
393            pageContext.forceWrite("</select>");
394            
395            
396            
397            
398        }
399        
400        private String selected(String str, String[] selected) {
401            if(selected!=null) {
402                    for(int i=0;i<selected.length;i++) {
403                            if(caseSensitive) {
404                                    if(str.compareTo(selected[i])==0) return " selected";
405                            }
406                            else {
407                                    if(Operator.compare(str,selected[i])==0) return " selected";
408                            }
409                            //if(Operator.compare(str,selected[i])==0) return " selected";
410                    }
411            }
412            return "";
413        }
414    
415        
416        
417        /**
418         * html encode a string
419         * @param str string to encode
420         * @return encoded string
421         */
422        private String enc(String str) {
423            return HTMLEntities.escapeHTML(str,HTMLEntities.HTMLV20);
424        }
425    
426            /**
427             * @param editable the editable to set
428             * @throws ApplicationException 
429             */
430            public void setEditable(boolean editable)  {
431                    this.editable=editable;
432            }
433    
434            /**
435             * @param group the group to set
436             * @throws ApplicationException 
437             */
438            public void setGroup(String group) {
439                    this.group=group;
440            }
441    
442            /**
443             * @param height the height to set
444             * @throws ApplicationException 
445             */
446            public void setHeight(double height) {
447                    this.height=(int)height;
448            }
449    
450            /**
451             * @param label the label to set
452             * @throws ApplicationException 
453             */
454            public void setLabel(String label) {
455                    this.label=label;
456            }
457    
458            /**
459             * @param queryPosition the queryPosition to set
460             * @throws ApplicationException 
461             */
462            public void setQueryposition(String strQueryPosition) throws ApplicationException {
463                    strQueryPosition=strQueryPosition.trim().toLowerCase();
464                    if( "above".equals(strQueryPosition)) queryPosition=QUERY_POSITION_ABOVE;
465                    else if( "below".equals(strQueryPosition)) queryPosition=QUERY_POSITION_BELOW;
466            else 
467                    throw new ApplicationException("attribute queryPosition for tag select has an invalid value ["+strQueryPosition+"], " +
468                                    "valid values are [above, below]");
469        
470            }
471    
472            /**
473             * @param tooltip the tooltip to set
474             * @throws ApplicationException 
475             */
476            public void setTooltip(String tooltip) {
477                    this.tooltip=tooltip;
478            }
479    
480            /**
481             * @param visible the visible to set
482             * @throws ApplicationException 
483             */
484            public void setVisible(boolean visible) {
485                    this.visible=visible;
486            }
487    
488            /**
489             * @param width the width to set
490             * @throws ApplicationException 
491             */
492            public void setWidth(double width) {
493                    this.width=(int) width;
494            }
495            /**
496             * @param width the width to set
497             * @throws ApplicationException 
498             */
499            public void setEnabled(String enabled) {
500                    setDisabled(!Caster.toBooleanValue(enabled,true));
501            }
502    
503            /**
504             * @param caseSensitive the caseSensitive to set
505             */
506            public void setCasesensitive(boolean caseSensitive) {
507                    this.caseSensitive = caseSensitive;
508            }
509    }