/*
* $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
*
* - view - Determines the major rendering mode. Values are
* 'monthview' (optional, default) and 'summary'. The former renders a small
* HTML calendar suitable for menus, sidebars, etc, with day/month/year
* selection and links to a page with the same name as the calendar and to
* today's date. The latter is similar to the WeblogPlugin: it collects several
* daily entries into one page, and is meant for use in a WikiPage body.
*
- name - A (unique) name for the calendar. All links in the
* calendar take to a page by the same name; by placing a summary view on that
* page, you get full functionality.
*
- class - the CSS class to render the calendar as. If the value is
* foo , styles foo and footitle are used to render the
* monthview calendar; foo , fooheader , foobody ,
* and foofooter are used to render each daily entry in summary view.
* The default values are 'calendar' for monthview and 'calendarentry' for
* summary.
*
- linkto - in monthview mode, a value of 'current' will cause all
* day-links to only change the selected date; the browser will stay on the same
* day. To view a calendar page, first click e.g. on the month name, then select
* a day; to edit that date's entry, click on the little "E" link at the bottom
* right. The default behavior is for the day links to direct the browser to
* that day's entry.
*
- month , year , day - a date to set the calendar to.
* These are NOT for regular plugin use, but can prove useful with the
* WikiForms plugin: you can create a form-controlled calendar page.
*
- days - in summary mode, the number of days to display. Use this
* to summarize the last 7 days, or 31, or whatever you please. (The calendar
* title month and year utilise this parameter to provide a month's and year's
* view.) The default value is one day ('today').
*
- order - in summary mode, the value 'ascending' switches the
* default newest-entry-first order to oldes-entry-first.
*
*
*
* 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:
*
* - calendar - (div) surrounding calendar entry (monthview mode)
*
- calendartitle - (div) surrounding calendar title bar (monthview mode)
*
- today - (a) today's day (monthview mode)
*
- selected - (a) selected day (monthview mode)
*
- dayentry - (div) surrounding a summary day entry (summary mode)
*
- dayentryheading - (div) surrounding day entry header (summary mode)
*
- dayentrybody - (div) ... (summary mode)
*
- dayentryfooter - (div) ... (summary mode)
*
*
*
* @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
\n");
sb.append("
\n");
}
//by IK
from.add(Calendar.DATE, add);
}
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;
}
}