|
Processing...
Description & Source Code
ZK Calendar is an Ajax component readily embeddable into any Java
web application. In this demo, it's shown as a standalone, Google
Calendar like application; offering functionalities such as filtering,
detailed scheduling, multiple time zones, and daily/weekly/monthly view.
Properties such as format and style can be easily configured by setting
the calendar component's attributes. The main task for the developers is
to handle the calendar events and preparing the event data model;
similar to how other data components work in ZK.
This feature requires ZK EE. It can also be used independently under commerical or GPL license.
zk_calendar.zul
<zk> <div apply="demo.app.zk_calendar.CalendarController"> <hlayout valign="middle"> <button id="today" label="Today" /> <button id="prev" iconSclass="z-icon-arrow-left"/> <button id="next" iconSclass="z-icon-arrow-right"/> <separator width="50px" /> <button id="pageDay" label="Day" width="60px" /> <button id="pageWeek" label="Week" width="60px"/> <button id="pageMonth" label="Month" width="60px"/> <separator width="50px"/> Filter : <textbox id="filter"/> <button id="applyFilter" label="Apply"/> <button id="resetFilter" label="Reset"/> </hlayout> <separator bar="true" height="20px"/> <calendars id="calendars" firstDayOfWeek="Sunday" height="600px" timeZone="Main=GMT+0" mold="month"/> </div> <!-- Create/Update Event Popup --> <include src="/widgets/zk_calendar/zk_calendar/calendar_editor.zul" /> </zk> calendar_editor.zul
<div viewModel="@id('vm') @init('demo.app.zk_calendar.CalendarEditorViewModel')" validationMessages="@id('vmsgs')">
<window title="Create Calendar Event" border="normal" width="400px"
form="@id('fx') @load(vm.calendarItem) @save(vm.calendarItem, before='ok') @validator(vm.dateValidator)"
allDay="@ref(vm.isAllDay(fx.beginDate,fx.endDate))"
mode="popup" visible="@load(vm.visible)" position="center,center" >
<vlayout hflex="1">
<hlayout valign="middle">
Lock this item : <checkbox checked="@bind(fx.locked)" />
All Day: <checkbox checked="@load(allDay)" disabled="true" />
</hlayout>
<grid hflex='1'>
<columns>
<column width="100px" align="right" />
<column />
</columns>
<rows>
<row>
BeginDate:
<div>
<datebox hflex="1" locale="en" timeZone="GMT+0"
format="@load(allDay ? 'long' : 'long+medium')"
value="@bind(fx.beginDate)" errorMessage="@load(vmsgs.beginDate)" />
</div>
</row>
<row>
EndDate:
<div>
<datebox hflex="1" locale="en" timeZone="GMT+0"
format="@load(allDay ? 'long' : 'long+medium')"
value="@bind(fx.endDate)" errorMessage="@load(vmsgs.endDate)"/>
</div>
</row>
<row>
Color:
<cell>
Header Color <colorbox value="@bind(fx.headerColor)" />
Content Color <colorbox value="@bind(fx.contentColor)" />
</cell>
</row>
<row>
Title:
<textbox width="100%"
value="@bind(fx.title)" />
</row>
<row>
<cell colspan="2" style="text-align:center;">
<hlayout>
<button label="OK" onClick="@command('ok')" width="80px" />
<button label="Cancel" onClick="@command('cancel')" width="80px" />
<button label="Delete" onClick="@command('delete')" width="80px" />
</hlayout>
</cell>
</row>
</rows>
</grid>
</vlayout>
</window>
</div>
CalendarController.java
package demo.app.zk_calendar;
import java.util.Calendar;
import java.util.TimeZone;
import org.zkoss.calendar.CalendarWebAppInit;
import org.zkoss.calendar.Calendars;
import org.zkoss.calendar.event.CalendarsEvent;
import org.zkoss.calendar.impl.SimpleCalendarItem;
import org.zkoss.web.fn.ServletFns;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zk.ui.sys.PageCtrl;
import org.zkoss.zkmax.ui.select.annotation.Subscribe;
import org.zkoss.zul.Style;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.theme.Themes;
import javax.servlet.ServletException;
public class CalendarController extends SelectorComposer<Component> {
private static final long serialVersionUID = 1L;
@Wire
private Calendars calendars;
@Wire
private Textbox filter;
private DemoCalendarModel calendarModel;
//the in editing calendar ui event
private CalendarsEvent calendarsEvent = null;
@Override
public void doAfterCompose(Component comp) throws Exception {
overrideCalendarTheme(comp);
super.doAfterCompose(comp);
calendarModel = new DemoCalendarModel(new DemoCalendarData().getCalendarEvents());
calendars.setModel(this.calendarModel);
}
/**
* TODO: remove workaround once https://tracker.zkoss.org/browse/ZK-4771 is available and zk-calendar supports it
*/
private void overrideCalendarTheme(Component comp) throws ServletException {
String uri = CalendarWebAppInit.getCalendarThemeURI(Themes.getCurrentTheme());
new Style(uri).setPage(comp.getPage());
}
//control the calendar position
@Listen("onClick = #today")
public void gotoToday(){
TimeZone timeZone = calendars.getDefaultTimeZone();
calendars.setCurrentDate(Calendar.getInstance(timeZone).getTime());
}
@Listen("onClick = #next")
public void gotoNext(){
calendars.nextPage();
}
@Listen("onClick = #prev")
public void gotoPrev(){
calendars.previousPage();
}
//control page display
@Listen("onClick = #pageDay")
public void changeToDay(){
calendars.setMold("default");
calendars.setDays(1);
}
@Listen("onClick = #pageWeek")
public void changeToWeek(){
calendars.setMold("default");
calendars.setDays(7);
}
@Listen("onClick = #pageMonth")
public void changeToYear(){
calendars.setMold("month");
}
//control the filter
@Listen("onClick = #applyFilter")
public void applyFilter(){
calendarModel.setFilterText(filter.getValue());
calendars.setModel(calendarModel);
}
@Listen("onClick = #resetFilter")
public void resetFilter(){
filter.setText("");
calendarModel.setFilterText("");
calendars.setModel(calendarModel);
}
//listen to the calendar-create and edit of a event data
@Listen(CalendarsEvent.ON_ITEM_CREATE + " = #calendars; " +
CalendarsEvent.ON_ITEM_EDIT + " = #calendars")
public void createEvent(CalendarsEvent event) {
calendarsEvent = event;
//to display a shadow when editing
calendarsEvent.stopClearGhost();
SimpleCalendarItem data = (SimpleCalendarItem) event.getCalendarItem();
if (data == null) {
data = new SimpleCalendarItem();
data.setHeaderColor("#3366ff");
data.setContentColor("#6699ff");
data.setBeginDate(event.getBeginDate());
data.setEndDate(event.getEndDate());
} else {
data = (SimpleCalendarItem) event.getCalendarItem();
}
//notify the editor
QueueUtil.lookupQueue().publish(
new QueueMessage(QueueMessage.Type.EDIT, data));
}
//listen to the calendar-update of event data, usually send when user drag the event data
@Listen(CalendarsEvent.ON_ITEM_UPDATE + " = #calendars")
public void updateEvent(CalendarsEvent event) {
SimpleCalendarItem data = (SimpleCalendarItem) event.getCalendarItem();
data.setBeginDate(event.getBeginDate());
data.setEndDate(event.getEndDate());
calendarModel.update(data);
}
//listen to queue message from other controller
@Subscribe(value = QueueUtil.QUEUE_NAME)
public void handleQueueMessage(Event event) {
if (!(event instanceof QueueMessage)) {
return;
}
QueueMessage message = (QueueMessage) event;
switch (message.getType()) {
case DELETE:
calendarModel.remove((SimpleCalendarItem) message.getData());
//clear the shadow of the event after editing
calendarsEvent.clearGhost();
calendarsEvent = null;
break;
case OK:
if (calendarModel.indexOf((SimpleCalendarItem) message.getData()) >= 0) {
calendarModel.update((SimpleCalendarItem) message.getData());
} else {
calendarModel.add((SimpleCalendarItem) message.getData());
}
case CANCEL:
//clear the shadow of the event after editing
calendarsEvent.clearGhost();
calendarsEvent = null;
break;
}
}
}
QueueMessage.java
package demo.app.zk_calendar;
import org.zkoss.zk.ui.event.Event;
public class QueueMessage extends Event {
private static final long serialVersionUID = 1L;
static public enum Type {
EDIT, OK, DELETE, CANCEL;
}
private Type type;
private Object data;
public QueueMessage(Type type) {
super("onCalendarMessage");
this.type = type;
}
public QueueMessage(Type type, Object data) {
this(type);
this.data = data;
}
public Type getType() {
return type;
}
public Object getData() {
return data;
}
}
CalendarEditorViewModel.java
package demo.app.zk_calendar;
import org.zkoss.bind.*;
import org.zkoss.bind.annotation.*;
import org.zkoss.bind.validator.AbstractValidator;
import org.zkoss.calendar.impl.*;
import org.zkoss.zk.ui.event.EventListener;
import java.util.*;
public class CalendarEditorViewModel {
private SimpleCalendarItem calendarItem;
private boolean visible = false;
public SimpleCalendarItem getCalendarItem() {
return calendarItem;
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
@Init
public void init() {
//subscribe a queue, listen to other controller
QueueUtil.lookupQueue().subscribe(new QueueListener());
}
private void startEditing(SimpleCalendarItem calendarEventData) {
this.calendarItem = calendarEventData;
visible = true;
//reload entire view-model data when going to edit
BindUtils.postNotifyChange(null, null, this, "*");
}
public boolean isAllDay(Date beginDate, Date endDate) {
final int MINUTE_IN_DAY = 1000 * 60 * 60 * 24;
boolean allDay = false;
if (beginDate != null && endDate != null) {
long between = endDate.getTime() - beginDate.getTime();
allDay = between > MINUTE_IN_DAY;
}
return allDay;
}
public Validator getDateValidator() {
return new AbstractValidator() {
@Override
public void validate(ValidationContext ctx) {
Map<String, Property> formData = ctx.getProperties(ctx.getProperty().getValue());
Date beginDate = (Date) formData.get("beginDate").getValue();
Date endDate = (Date) formData.get("endDate").getValue();
if (beginDate == null) {
addInvalidMessage(ctx, "beginDate", "Begin date is empty");
}
if (endDate == null) {
addInvalidMessage(ctx, "endDate", "End date is empty");
}
if (beginDate != null && endDate != null && beginDate.compareTo(endDate) >= 0) {
addInvalidMessage(ctx, "endDate", "End date is before begin date");
}
}
};
}
@Command
@NotifyChange("visible")
public void cancel() {
QueueMessage message = new QueueMessage(QueueMessage.Type.CANCEL);
QueueUtil.lookupQueue().publish(message);
this.visible = false;
}
@Command
@NotifyChange("visible")
public void delete() {
QueueMessage message = new QueueMessage(QueueMessage.Type.DELETE, calendarItem);
QueueUtil.lookupQueue().publish(message);
this.visible = false;
}
@Command
@NotifyChange("visible")
public void ok() {
QueueMessage message = new QueueMessage(QueueMessage.Type.OK, calendarItem);
QueueUtil.lookupQueue().publish(message);
this.visible = false;
}
private class QueueListener implements EventListener<QueueMessage> {
@Override
public void onEvent(QueueMessage message)
throws Exception {
if (QueueMessage.Type.EDIT.equals(message.getType())) {
CalendarEditorViewModel.this.startEditing((SimpleCalendarItem) message.getData());
}
}
}
}
DemoCalendarData.java
package demo.app.zk_calendar;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.zkoss.calendar.api.CalendarItem;
import org.zkoss.calendar.impl.SimpleCalendarModel;
import org.zkoss.calendar.api.CalendarItem;
import org.zkoss.calendar.impl.SimpleCalendarItem;
import java.text.*;
import java.util.*;
public class DemoCalendarData {
private List<CalendarItem> calendarEvents = new LinkedList<>();
private final SimpleDateFormat DATA_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm");
private final Calendar cal = Calendar.getInstance();
public DemoCalendarData() {
init();
}
private void init() {
int mod = cal.get(Calendar.MONTH) + 1;
int year = cal.get(Calendar.YEAR);
String date2 = mod > 9 ? year + "/" + mod + "" : year + "/" + "0" + mod;
String date1 = --mod > 9 ? year + "/" + mod + "" : year + "/" + "0" + mod;
++mod;
String date3 = ++mod > 9 ? year + "/" + mod + "" : year + "/" + "0" + mod;
//DefaultCalendarItem doesn't have no-arg constructor, so we use SimpleCalendarItem for form binding
// Red Events
calendarEvents.add(new SimpleCalendarItem("ZK Jet Released", "", "", "background-color:#D96666", "background-color:#A32929", false, getDate(date1 + "/28 00:00"), getDate(date1 + "/29 00:00")));
calendarEvents.add(new SimpleCalendarItem("Experience ZK SpreadSheet Live Demo!", "", "", "background-color:#D96666", "background-color:#A32929", false, getDate(date1 + "/04 02:00"), getDate(date1 + "/05 03:00")));
calendarEvents.add(new SimpleCalendarItem("New Features of ZK Spreadsheet", "", "", "background-color:#D96666", "background-color:#A32929", false, getDate(date2 + "/21 05:00"), getDate(date2 + "/21 07:00")));
calendarEvents.add(new SimpleCalendarItem("ZK Spreadsheet Released", "", "", "background-color:#D96666", "background-color:#A32929", false, getDate(date2 + "/08 00:00"), getDate(date2 + "/09 00:00")));
// Blue Events
calendarEvents.add(new SimpleCalendarItem("ZK Released", "", "", "background-color:#668CD9", "background-color:#3467CE", false, getDate(date1 + "/29 03:00"), getDate(date2 + "/02 06:00")));
calendarEvents.add(new SimpleCalendarItem("New Feature of ZK ", "", "", "background-color:#668CD9", "background-color:#3467CE", false, getDate(date2 + "/02 10:00"), getDate(date2 + "/02 12:30")));
calendarEvents.add(new SimpleCalendarItem("Case Study - Mecatena", "", "", "background-color:#668CD9", "background-color:#3467CE", false, getDate(date2 + "/17 14:00"), getDate(date2 + "/18 16:00")));
calendarEvents.add(new SimpleCalendarItem("ZK Unit Testing Project - zunit", "", "", "background-color:#668CD9", "background-color:#3467CE", false, getDate(date3 + "/01 14:30"), getDate(date3 + "/01 17:30")));
// Purple Events
calendarEvents.add(new SimpleCalendarItem("ZK Studio released", "", "", "background-color:#B373B3", "background-color:#7A367A", false, getDate(date1 + "/29 08:00"), getDate(date2 + "/03 12:00")));
calendarEvents.add(new SimpleCalendarItem("Tutorial : Reading from the DB with Netbeans and ZK", "", "", "background-color:#B373B3", "background-color:#7A367A", false, getDate(date2 + "/07 08:00"), getDate(date2 + "/07 12:00")));
calendarEvents.add(new SimpleCalendarItem("Small talk - ZK Charts", "", "", "background-color:#B373B3", "background-color:#7A367A", false, getDate(date2 + "/13 11:00"), getDate(date2 + "/13 14:30")));
calendarEvents.add(new SimpleCalendarItem("Style Guide for ZK released !", "", "", "background-color:#B373B3", "background-color:#7A367A", false, getDate(date2 + "/16 14:00"), getDate(date2 + "/18 16:00")));
calendarEvents.add(new SimpleCalendarItem("Small talk -- Simple Database Access From ZK", "", "", "background-color:#B373B3", "background-color:#7A367A", false, getDate(date3 + "/02 12:00"), getDate(date3 + "/02 17:00")));
// Khaki Events
calendarEvents.add(new SimpleCalendarItem("ZK UK User Group", "", "", "background-color:#BFBF4D", "background-color:#88880E", false, getDate(date1 + "/03 00:00"), getDate(date1 + "/04 00:00")));
calendarEvents.add(new SimpleCalendarItem("How to Test ZK Application with Selenium", "", "", "background-color:#BFBF4D", "background-color:#88880E", false, getDate(date2 + "/13 05:00"), getDate(date2 + "/13 07:00")));
calendarEvents.add(new SimpleCalendarItem("ZK Alfresco Talk", "", "", "background-color:#BFBF4D", "background-color:#88880E", false, getDate(date2 + "/24 19:30"), getDate(date2 + "/24 20:00")));
calendarEvents.add(new SimpleCalendarItem("ZK selected as SourceForge.net Project of the Month", "", "", "background-color:#BFBF4D", "background-color:#88880E", false, getDate(date3 + "/03 00:00"), getDate(date3 + "/04 00:00")));
// Green Events
calendarEvents.add(new SimpleCalendarItem("ZK Mobile Released", "", "", "background-color:#4CB052", "background-color:#0D7813", false, getDate(date1 + "/28 10:00"), getDate(date1 + "/28 12:30")));
calendarEvents.add(new SimpleCalendarItem("ZK Gmaps released", "", "", "background-color:#4CB052", "background-color:#0D7813", false, getDate(date2 + "/03 00:00"), getDate(date2 + "/03 05:30")));
calendarEvents.add(new SimpleCalendarItem("Refresh with Five New ZK Themes!", "", "", "background-color:#4CB052", "background-color:#0D7813", false, getDate(date2 + "/05 20:30"), getDate(date2 + "/06 00:00")));
calendarEvents.add(new SimpleCalendarItem("ZK Roadmap Announced", "", "", "background-color:#4CB052", "background-color:#0D7813", false, getDate(date2 + "/23 00:00"), getDate(date2 + "/25 16:30")));
calendarEvents.add(new SimpleCalendarItem("Build Database CRUD Application in 6 Steps", "", "", "background-color:#4CB052", "background-color:#0D7813", false, getDate(date3 + "/01 08:30"), getDate(date3 + "/01 19:30")));
}
private Date getDate(String dateText) {
try {
return DATA_FORMAT.parse(dateText);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
public List<CalendarItem> getCalendarEvents() {
return calendarEvents;
}
}
DemoCalendarModel.java
package demo.app.zk_calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.zkoss.calendar.api.CalendarItem;
import org.zkoss.calendar.api.RenderContext;
import org.zkoss.calendar.impl.SimpleCalendarModel;
public class DemoCalendarModel extends SimpleCalendarModel {
private static final long serialVersionUID = 1L;
private String filterText = "";
public DemoCalendarModel(List<CalendarItem> calendarEvents) {
super(calendarEvents);
}
public void setFilterText(String filterText) {
this.filterText = filterText;
}
@Override
public List<CalendarItem> get(Date beginDate, Date endDate, RenderContext rc) {
List<CalendarItem> list = new LinkedList<CalendarItem>();
long begin = beginDate.getTime();
long end = endDate.getTime();
for (Object obj : _list) {
CalendarItem ce = obj instanceof CalendarItem ? (CalendarItem) obj : null;
if (ce == null) break;
long b = ce.getBeginDate().getTime();
long e = ce.getEndDate().getTime();
if (e >= begin && b < end && ce.getContent().toLowerCase().contains(filterText.toLowerCase()))
list.add(ce);
}
return list;
}
}
Copyright © 2005-2025 Potix Corporation All rights reserved.
|
|
Processing... |