1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.struts2.dojo.components;
23
24 import java.text.DateFormat;
25 import java.text.Format;
26 import java.text.MessageFormat;
27 import java.text.SimpleDateFormat;
28 import java.util.ArrayList;
29 import java.util.Calendar;
30 import java.util.Date;
31 import java.util.List;
32 import java.util.Random;
33
34 import javax.servlet.http.HttpServletRequest;
35 import javax.servlet.http.HttpServletResponse;
36
37 import org.apache.struts2.components.UIBean;
38 import org.apache.struts2.views.annotations.StrutsTag;
39 import org.apache.struts2.views.annotations.StrutsTagAttribute;
40 import org.apache.struts2.views.annotations.StrutsTagSkipInheritance;
41
42 import com.opensymphony.xwork2.util.ValueStack;
43 import com.opensymphony.xwork2.util.logging.Logger;
44 import com.opensymphony.xwork2.util.logging.LoggerFactory;
45
46 /***
47 * <!-- START SNIPPET: javadoc -->
48 * <p>
49 * Renders a date/time picker in a dropdown container.
50 * </p>
51 * <p>
52 * A stand-alone DateTimePicker widget that makes it easy to select a date/time, or increment by week, month,
53 * and/or year.
54 * </p>
55 *
56 * <p>
57 * It is possible to customize the user-visible formatting with either the
58 * 'formatLength' (long, short, medium or full) or 'displayFormat' attributes. By defaulty current
59 * locale will be used.</p>
60 * </p>
61 *
62 * Syntax supported by 'displayFormat' is (http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns):-
63 * <table border="1">
64 * <tr>
65 * <td>Format</td>
66 * <td>Description</td>
67 * </tr>
68 * <tr>
69 * <td>d</td>
70 * <td>Day of the month</td>
71 * </tr>
72 * <tr>
73 * <td>D</td>
74 * <td>Day of year</td>
75 * </tr>
76 * <tr>
77 * <td>M</td>
78 * <td>Month - Use one or two for the numerical month, three for the abbreviation, or four for the full name, or 5 for the narrow name.</td>
79 * </tr>
80 * <tr>
81 * <td>y</td>
82 * <td>Year</td>
83 * </tr>
84 * <tr>
85 * <td>h</td>
86 * <td>Hour [1-12].</td>
87 * </tr>
88 * <tr>
89 * <td>H</td>
90 * <td>Hour [0-23].</td>
91 * </tr>
92 * <tr>
93 * <td>m</td>
94 * <td>Minute. Use one or two for zero padding.</td>
95 * </tr>
96 * <tr>
97 * <td>s</td>
98 * <td>Second. Use one or two for zero padding.</td>
99 * </tr>
100 * </table>
101 *
102 * <p>
103 * The value sent to the server is a locale-independent value, in a hidden field as defined
104 * by the name attribute. The value will be formatted conforming to RFC3 339
105 * (yyyy-MM-dd'T'HH:mm:ss)
106 * </p>
107 * <p>
108 * The following formats(in order) will be used to parse the values of the attributes 'value',
109 * 'startDate' and 'endDate':
110 * </p>
111 * <ul>
112 * <li>SimpleDateFormat built using RFC 3339 (yyyy-MM-dd'T'HH:mm:ss)
113 * <li>SimpleDateFormat.getTimeInstance(DateFormat.SHORT)
114 * <li>SimpleDateFormat.getDateInstance(DateFormat.SHORT)
115 * <li>SimpleDateFormat.getDateInstance(DateFormat.MEDIUM)
116 * <li>SimpleDateFormat.getDateInstance(DateFormat.FULL)
117 * <li>SimpleDateFormat.getDateInstance(DateFormat.LONG)
118 * <li>SimpleDateFormat built using the value of the 'displayFormat' attribute(if any)
119 * </ul>
120 * <!-- END SNIPPET: javadoc -->
121 *
122 * <b>Examples</b>
123 *
124 * <pre>
125 * <!-- START SNIPPET: example1 -->
126 * <sx:datetimepicker name="order.date" label="Order Date" />
127 * <sx:datetimepicker name="delivery.date" label="Delivery Date" displayFormat="yyyy-MM-dd" />
128 * <sx:datetimepicker name="delivery.date" label="Delivery Date" value="%{date}" />
129 * <sx:datetimepicker name="delivery.date" label="Delivery Date" value="%{'2007-01-01'}" />
130 * <sx:datetimepicker name="order.date" label="Order Date" value="%{'today'}"/>
131 * <!-- END SNIPPET: example1 -->
132 * </pre>
133 *
134 * <!-- START SNIPPET: example2 -->
135 * <sx:datetimepicker id="picker" label="Order Date" />
136 * <script type="text/javascript">
137 * function setValue() {
138 * var picker = dojo.widget.byId("picker");
139 *
140 * //string value
141 * picker.setValue('2007-01-01');
142 *
143 * //Date value
144 * picker.setValue(new Date());
145 * }
146 *
147 * function showValue() {
148 * var picker = dojo.widget.byId("picker");
149 *
150 * //string value
151 * var stringValue = picker.getValue();
152 * alert(stringValue);
153 *
154 * //date value
155 * var dateValue = picker.getDate();
156 * alert(dateValue);
157 * }
158 * </script>
159 * <!-- END SNIPPET: example2 -->
160 *
161 * <!-- START SNIPPET: example3 -->
162 * <sx:datetimepicker id="picker" label="Order Date" valueNotifyTopics="/value"/>
163 *
164 * <script type="text/javascript">
165 * dojo.event.topic.subscribe("/value", function(textEntered, date, widget){
166 * alert('value changed');
167 * //textEntered: String enetered in the textbox
168 * //date: JavaScript Date object with the value selected
169 * //widet: widget that published the topic
170 * });
171 * </script>
172 * <!-- END SNIPPET: example3 -->
173 */
174 @StrutsTag(name="datetimepicker", tldTagClass="org.apache.struts2.dojo.views.jsp.ui.DateTimePickerTag", description="Render datetimepicker")
175 public class DateTimePicker extends UIBean {
176
177 final public static String TEMPLATE = "datetimepicker";
178
179
180
181
182 final private static String RFC3339_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
183 final private static String RFC3339_PATTERN = "{0,date," + RFC3339_FORMAT + "}";
184 final protected static Logger LOG = LoggerFactory.getLogger(DateTimePicker.class);
185 final private static transient Random RANDOM = new Random();
186
187 protected String iconPath;
188 protected String formatLength;
189 protected String displayFormat;
190 protected String toggleType;
191 protected String toggleDuration;
192 protected String type;
193
194 protected String displayWeeks;
195 protected String adjustWeeks;
196 protected String startDate;
197 protected String endDate;
198 protected String weekStartsOn;
199 protected String staticDisplay;
200 protected String dayWidth;
201 protected String language;
202 protected String templateCssPath;
203 protected String valueNotifyTopics;
204
205 public DateTimePicker(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
206 super(stack, request, response);
207 }
208
209 protected String getDefaultTemplate() {
210 return TEMPLATE;
211 }
212
213 public void evaluateParams() {
214 super.evaluateParams();
215
216 if(displayFormat != null)
217 addParameter("displayFormat", findString(displayFormat));
218 if(displayWeeks != null)
219 addParameter("displayWeeks", findString(displayWeeks));
220 if(adjustWeeks != null)
221 addParameter("adjustWeeks", findValue(adjustWeeks, Boolean.class));
222
223 if(disabled != null)
224 addParameter("disabled", findValue(disabled, Boolean.class));
225
226 if(startDate != null)
227 addParameter("startDate", format(findValue(startDate)));
228 if(endDate != null)
229 addParameter("endDate", format(findValue(endDate)));
230 if(weekStartsOn != null)
231 addParameter("weekStartsOn", findString(weekStartsOn));
232 if(staticDisplay != null)
233 addParameter("staticDisplay", findValue(staticDisplay, Boolean.class));
234 if(dayWidth != null)
235 addParameter("dayWidth", findValue(dayWidth, Integer.class));
236 if(language != null)
237 addParameter("language", findString(language));
238 if(value != null)
239 addParameter("value", format(findValue(value)));
240
241 if(iconPath != null)
242 addParameter("iconPath", findString(iconPath));
243 if(formatLength != null)
244 addParameter("formatLength", findString(formatLength));
245 if(toggleType != null)
246 addParameter("toggleType", findString(toggleType));
247 if(toggleDuration != null)
248 addParameter("toggleDuration", findValue(toggleDuration,
249 Integer.class));
250 if(type != null)
251 addParameter("type", findString(type));
252 else
253 addParameter("type", "date");
254 if(templateCssPath != null)
255 addParameter("templateCssPath", findString(templateCssPath));
256 if(valueNotifyTopics != null)
257 addParameter("valueNotifyTopics", findString(valueNotifyTopics));
258
259
260 if(parameters.containsKey("value")) {
261 addParameter("nameValue", parameters.get("value"));
262 } else {
263 if(parameters.containsKey("name")) {
264 addParameter("nameValue", format(findValue((String)parameters.get("name"))));
265 }
266 }
267
268
269 Boolean parseContent = (Boolean)stack.getContext().get(Head.PARSE_CONTENT);
270 boolean generateId = (parseContent != null ? !parseContent : true);
271
272 addParameter("pushId", generateId);
273 if ((this.id == null || this.id.length() == 0) && generateId) {
274
275
276 int nextInt = RANDOM.nextInt();
277 nextInt = nextInt == Integer.MIN_VALUE ? Integer.MAX_VALUE : Math.abs(nextInt);
278 this.id = "widget_" + String.valueOf(nextInt);
279 addParameter("id", this.id);
280 }
281 }
282
283 @Override
284 @StrutsTagSkipInheritance
285 public void setTheme(String theme) {
286 super.setTheme(theme);
287 }
288
289 @Override
290 public String getTheme() {
291 return "ajax";
292 }
293
294 @StrutsTagAttribute(description="If true, weekly size of calendar changes to acomodate the month if false," +
295 " 42 day format is used", type="Boolean", defaultValue="false")
296 public void setAdjustWeeks(String adjustWeeks) {
297 this.adjustWeeks = adjustWeeks;
298 }
299
300 @StrutsTagAttribute(description="How to render the names of the days in the header(narrow, abbr or wide)", defaultValue="narrow")
301 public void setDayWidth(String dayWidth) {
302 this.dayWidth = dayWidth;
303 }
304
305 @StrutsTagAttribute(description="Total weeks to display", type="Integer", defaultValue="6")
306 public void setDisplayWeeks(String displayWeeks) {
307 this.displayWeeks = displayWeeks;
308 }
309
310 @StrutsTagAttribute(description="Last available date in the calendar set", type="Date", defaultValue="2941-10-12")
311 public void setEndDate(String endDate) {
312 this.endDate = endDate;
313 }
314
315 @StrutsTagAttribute(description="First available date in the calendar set", type="Date", defaultValue="1492-10-12")
316 public void setStartDate(String startDate) {
317 this.startDate = startDate;
318 }
319
320 @StrutsTagAttribute(description="Disable all incremental controls, must pick a date in the current display", type="Boolean", defaultValue="false")
321 public void setStaticDisplay(String staticDisplay) {
322 this.staticDisplay = staticDisplay;
323 }
324
325 @StrutsTagAttribute(description="Adjusts the first day of the week 0==Sunday..6==Saturday", type="Integer", defaultValue="0")
326 public void setWeekStartsOn(String weekStartsOn) {
327 this.weekStartsOn = weekStartsOn;
328 }
329
330 @StrutsTagAttribute(description="Language to display this widget in", defaultValue="brower's specified preferred language")
331 public void setLanguage(String language) {
332 this.language = language;
333 }
334
335 @StrutsTagAttribute(description="A pattern used for the visual display of the formatted date, e.g. dd/MM/yyyy")
336 public void setDisplayFormat(String displayFormat) {
337 this.displayFormat = displayFormat;
338 }
339
340 @StrutsTagAttribute(description="Type of formatting used for visual display. Possible values are " +
341 "long, short, medium or full", defaultValue="short")
342 public void setFormatLength(String formatLength) {
343 this.formatLength = formatLength;
344 }
345
346 @StrutsTagAttribute(description="Path to icon used for the dropdown")
347 public void setIconPath(String iconPath) {
348 this.iconPath = iconPath;
349 }
350
351 @StrutsTagAttribute(description="Duration of toggle in milliseconds", type="Integer", defaultValue="100")
352 public void setToggleDuration(String toggleDuration) {
353 this.toggleDuration = toggleDuration;
354 }
355
356 @StrutsTagAttribute(description="Defines the type of the picker on the dropdown. Possible values are 'date'" +
357 " for a DateTimePicker, and 'time' for a timePicker", defaultValue="date")
358 public void setType(String type) {
359 this.type = type;
360 }
361
362 @StrutsTagAttribute(description="oggle type of the dropdown. Possible values are plain,wipe,explode,fade", defaultValue="plain")
363 public void setToggleType(String toggleType) {
364 this.toggleType = toggleType;
365 }
366
367 @StrutsTagAttribute(description="Template css path")
368 public void setTemplateCssPath(String templateCssPath) {
369 this.templateCssPath = templateCssPath;
370 }
371
372 @StrutsTagAttribute(description="Preset the value of input element")
373 public void setValue(String arg0) {
374 super.setValue(arg0);
375 }
376
377 @StrutsTagAttribute(description="Comma delimmited list of topics that will published when a value is selected")
378 public void setValueNotifyTopics(String valueNotifyTopics) {
379 this.valueNotifyTopics = valueNotifyTopics;
380 }
381
382 private String format(Object obj) {
383 if(obj == null)
384 return null;
385
386 if(obj instanceof Date) {
387 return MessageFormat.format(RFC3339_PATTERN, (Date) obj);
388 } else if(obj instanceof Calendar) {
389 return MessageFormat.format(RFC3339_PATTERN, ((Calendar) obj).getTime());
390 }
391 else {
392
393 String dateStr = obj.toString();
394 if(dateStr.equalsIgnoreCase("today"))
395 return MessageFormat.format(RFC3339_PATTERN, new Date());
396
397
398 Date date = null;
399
400 List<DateFormat> formats = new ArrayList<DateFormat>();
401 formats.add(new SimpleDateFormat(RFC3339_FORMAT));
402 formats.add(SimpleDateFormat.getTimeInstance(DateFormat.SHORT));
403 formats.add(SimpleDateFormat.getDateInstance(DateFormat.SHORT));
404 formats.add(SimpleDateFormat.getDateInstance(DateFormat.MEDIUM));
405 formats.add(SimpleDateFormat.getDateInstance(DateFormat.FULL));
406 formats.add(SimpleDateFormat.getDateInstance(DateFormat.LONG));
407 if (this.displayFormat != null) {
408 try {
409 SimpleDateFormat displayFormat = new SimpleDateFormat(
410 (String) getParameters().get("displayFormat"));
411 formats.add(displayFormat);
412 } catch (Exception e) {
413
414 LOG.error("Cannot use attribute", e);
415 }
416 }
417
418 for (DateFormat format : formats) {
419 try {
420 date = format.parse(dateStr);
421 if (date != null)
422 return MessageFormat.format(RFC3339_PATTERN, date);
423 } catch (Exception e) {
424
425 }
426 }
427
428
429 if (LOG.isDebugEnabled())
430 LOG.debug("Unable to parse date " + dateStr);
431 return dateStr;
432 }
433 }
434
435 }