/* * $Id: CalendarPlugin.java,v 1.2 2005/05/25 17:32:12 lchan Exp $ */ package com.ecyrd.jspwiki.plugin; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Map; import javax.servlet.http.HttpSession; import com.ecyrd.jspwiki.WikiContext; import com.ecyrd.jspwiki.WikiEngine; import com.ecyrd.jspwiki.plugin.PluginException; import com.ecyrd.jspwiki.plugin.WikiPlugin; /** * CalendarPlugin is a dual-purpose WikiPlugin. In month view mode it generates * a small HTML calendar suitable for viewing in a menu bar, providing * day/month/year browsing capabilities. In summary mode, meant for use in a * WikiPage, it displays any number of day entries, much like the WeblogPlugin. * The best use of the system is achieved by placing the calendar plugin in * something like the LeftMenu WikiPage, then creating a WikiPage with the same * name as the calendar with a summaru plugin call. This lets you browse days * and click on them to show dates and entries. * *

* The 'name' plugin parameter assigns a unique name to the calendar; this is * used both to identify per-date page names, to store a date value in the * PageContext to help determine what date to display, and to store a value in * the request to facilitate scrolling calendar months and years. Also, extra * elements in the calendar link to a WikiPage by this name; this is the logical * place e.g. to display summary views, etc. * *

* The calendar object is placed in the user's HttpSession to avoid creating and * rerendering it unnecessarily. This is a conscious design choice, and it means * that cookieless, nonauthenticated users won't be able to enjoy * CalendarPlugin. (This said, if the calendar is located e.g. in the LeftMenu, * it is rerendered every time the user changes the page. Ouch.) * *

* The small HTML calendar display contains links to the previous and next month * and the previous and next year. This information is coded as HTTP parameters * into the links, and lets the user change year/month and still stay on the * same page. * *

* The calendar title's year and month link to a WikiPage with the same name as * the calendar, with information sufficient for displaying all entries for a * year or month when using the CalendarPlugin in 'summary' mode. * *

* Parameters *

* *

* Examples of usage: *

* Display a small HTML calendar, customized for ebu: * *

 *   [{CalendarPlugin name='EbusCalendar'}]
 * 
* *

* Display a summary page of EbusCalendar, showing 10 days backward from the * selected date: * *

 *   [{CalendarPlugin view='summary' name='EbusCalendar' days='10'}]
 * 
* * *

* CSS styles used: *

* * * @author ebu */ public class CalendarPlugin implements WikiPlugin { public static final String PLUGINPARAM_VIEW = "view"; public static final String PLUGINPARAM_NAME = "name"; public static final String PLUGINPARAM_CURRENT = "current"; public static final String PLUGINPARAM_CLASS = "class"; public static final String PLUGINPARAM_LINKTO = "linkto"; public static final String PLUGINPARAM_MONTH = "month"; public static final String PLUGINPARAM_YEAR = "year"; public static final String PLUGINPARAM_DAY = "day"; public static final String PLUGINPARAM_MONTHDELTA = "dm"; public static final String PLUGINPARAM_DAYS = "days"; public static final String PLUGINPARAM_ORDER = "order"; public static final String PLUGINPARAM_DIRECTION = "direction"; public static final String EXT_MONTH = ".m"; public static final String EXT_DAY = ".d"; public static final String EXT_YEAR = ".y"; public static final String EXT_MONTHDELTA = ".dm"; public static final String VALUE_ASCENDING = "ascending"; public static final String VALUE_SUMMARY = "summary"; public static final String VALUE_MONTHVIEW = "monthview"; public static final String VALUE_UPCOMING = "upcoming"; public static final String SESSION_PREFIX = "CalPlug."; public static final String STYLE_SUMMARY = "calendarentry"; public static final String STYLE_DHEADER = "header"; public static final String STYLE_DBODY = "body"; public static final String STYLE_DFOOTER = "footer"; private SimpleDateFormat dateFormatter = new SimpleDateFormat("dd-MMM-yyyy"); /* * */ public String execute(WikiContext context, Map params) throws PluginException { String mode = (String) params.get(PLUGINPARAM_VIEW); if (mode == null) mode = VALUE_MONTHVIEW; String calName = (String) params.get(PLUGINPARAM_NAME); if (calName == null) return ("CalendarPlugin requires the 'name' parameter."); CalendarPrinter cal = null; try { cal = getCalendar(context, calName); } catch (PluginException e) { return (e.getMessage()); } String css = (String) params.get(PLUGINPARAM_CLASS); if (css != null && mode.equals(VALUE_MONTHVIEW)) cal.setCSSStyle(css); String linkMode = (String) params.get(PLUGINPARAM_LINKTO); if (linkMode != null && linkMode.equals(PLUGINPARAM_CURRENT)) { cal.setLinkingMode(CalendarPrinter.LINK_TO_CURRENT); } else { cal.setLinkingMode(CalendarPrinter.LINK_TO_DAY); } cal.setDisplayPage(context.getPage().getName()); // Does the request specify a change to the month or year? The information // is looked up first in plugin parameters (so this plugin can be used with // the WikiForms plugin), secondarily in the http request, and finally // defaults // to the current time. String dm = (String) params.get(PLUGINPARAM_MONTHDELTA); if (dm == null) dm = context.getHttpParameter(calName + EXT_MONTHDELTA); if (dm == null) dm = "0"; int deltaMonth = safeInt(dm); String month = (String) params.get(PLUGINPARAM_MONTH); if (month == null) month = context.getHttpParameter(calName + EXT_MONTH); String year = (String) params.get(PLUGINPARAM_YEAR); if (year == null) year = context.getHttpParameter(calName + EXT_YEAR); String day = (String) params.get(PLUGINPARAM_DAY); if (day == null) day = context.getHttpParameter(calName + EXT_DAY); // Protect agains multiple invocations per page. This happens easily if // you have a plugin for the same calendar e.g. in a menu bar and a summary // page. if (mode.equals(VALUE_MONTHVIEW) && !cal.requestHandled(context.getHttpRequest())) { if (year != null) cal.setYear(year); if (month != null) cal.setMonth(month); //cal.addMonths( deltaMonth ); if (day != null) cal.setDay(day); } String rval = ""; String time = (String) params.get(PLUGINPARAM_DAYS); int numberOfDays = 0; try { numberOfDays = (Integer.parseInt(time) == 0) ? 1 : Integer.parseInt(time); } catch (NumberFormatException e) { numberOfDays = 0; } if (mode.equals(VALUE_MONTHVIEW)) { rval = cal.printMonthView(); } else if (mode.equals(VALUE_SUMMARY)) { String order = (String) params.get(PLUGINPARAM_ORDER); boolean asc = (order != null && order.equals(VALUE_ASCENDING)); String direction = (String) params.get(PLUGINPARAM_DIRECTION); rval = collectPages(context.getEngine(), cal, numberOfDays, css, asc); } else if (mode.equals(VALUE_UPCOMING)) { rval = collectPages(context.getEngine(), cal, numberOfDays, css); } else { rval = "Unknown calendar view mode: " + mode; } cal.setHandledRequest(context.getHttpRequest()); return (rval); } private int safeInt(String src) { int r = 0; if (src != null) { try { r = Integer.parseInt(src); } catch (NumberFormatException ne) { } } return (r); } /** * Looks for a CalendarPrinter in the session, and creates one if it is * missing. */ private CalendarPrinter getCalendar(WikiContext context, String calName) throws PluginException { // Grab the calendar item that may exist in the context already. CalendarPrinter cal = null; WikiEngine engine = context.getEngine(); HttpSession session = null; if (context.getHttpRequest() != null && (session = context.getHttpRequest().getSession()) != null) { Object contextItem = session.getAttribute(SESSION_PREFIX + calName); if (contextItem == null || !(contextItem instanceof CalendarPrinter)) { cal = new CalendarPrinter(engine, calName); } else { cal = (CalendarPrinter) contextItem; if (!calName.equals(cal.getName())) { // Whoa, interesting. Create new? cal = new CalendarPrinter(engine, calName); } } session.setAttribute(SESSION_PREFIX + calName, cal); return (cal); } throw new PluginException( "CalendarPlugin requires session information. Are your cookies enabled?"); } /** Collect Pages starting from now (i.e. view = upcoming) * * @see #collectPages(WikiEngine, CalendarPrinter, String, String, boolean) */ private String collectPages(WikiEngine wiki, CalendarPrinter cal, int days, String style) { Calendar dayIndexer = getCalendar(cal); return collectPages(wiki, dayIndexer, cal, style, days, 1); } /** * Collects a set of pages, starting at the date of the calendar printer and * counting to the ending date, and includes them in the result string. Adds a * permalink after each entry. This is much simpler than the corresponding * functionality in the weblog plugin, since we collect everything in one-day * bites. (Hm.. need to re-think the responsibilities here; the * CalendarPrinter perhaps shouldn't be setting the date links, we should.) * *

* As an interesting exercise, consider using the WikiForms plugin to provide * a nice selector for year/month/day/time info and pushing it through to this * plugin. */ private String collectPages(WikiEngine wiki, CalendarPrinter cal, int days, String style, boolean oldestFirst) { Calendar dayIndexer = getCalendar(cal); int add = (oldestFirst) ? 1 : -1; dayIndexer.add(Calendar.DATE, (oldestFirst) ? -days : 0); return collectPages(wiki, dayIndexer, cal, style, days, add); } private String collectPages(WikiEngine wiki, Calendar from, CalendarPrinter cal, String style, int totalDays, int add) { StringBuffer sb = new StringBuffer(); if (style == null) { style = STYLE_SUMMARY; } for (int i = 0; i < totalDays; i++) { String hdrStyle = style + STYLE_DHEADER; String bodyStyle = style + STYLE_DBODY; String ftrStyle = style + STYLE_DFOOTER; String prospectPage = cal.getEntryName(from); if (wiki.pageExists(prospectPage)) { sb.append("

\n"); sb.append("
\n"); sb.append(dateFormatter.format(from.getTime())); sb.append("\n
\n"); sb.append("
\n"); sb.append(wiki.getHTML(prospectPage)); sb.append("\n
\n
"); sb.append("\npermalink\n"); sb.append("
\n"); sb.append("
\n"); } } return sb.toString(); } private static Calendar getCalendar(CalendarPrinter cal) { Calendar rc = Calendar.getInstance(); rc.set(Calendar.MONTH, cal.getMonth()); rc.set(Calendar.YEAR, cal.getYear()); rc.set(Calendar.DAY_OF_MONTH, cal.getDay()); return rc; } }