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