Thursday, April 25, 2013

ZK Calendar as Week Picker


Introduction

This article describe how to customize the small calendar as a week picker.

Pre-request

Please check Client Side Programming and The use, apply Attribute  at References section before reading this article

The Program

calendar_as_week_picker.zul

<zk xmlns:w="client">
    <style>
        .custom-selected-node {
            background-color: #99FF99 !important;
        }
    </style>
    <vlayout>
        <label value="selected dates" />
        <textbox rows="7" id="tbx" width="300px" />
    </vlayout>
    <calendar id="cal" use="test.custom.component.WeekPicker">
        <attribute w:name="_markCal"><![CDATA[
            function (opts) {
                // clear old custom-selected-node
                jq('.custom-selected-node').each(function () {
                    jq(this).removeClass('custom-selected-node');
                });
                this.$_markCal(opts);
                if (this._view == 'day') {
                    // target: current focused date (td)
                    // parent: tr
                    var target = jq('.z-calendar-seld')[0],
                        parent = target.parentNode,
                        node = parent.firstChild,
                        beforeCnt = 0,
                        found;
                    // loop through each td
                    while (node) {
                        // add selected style
                        jq(node).addClass('custom-selected-node');
                        if (node == target) {
                            found = true;
                        } else if (!found) {
                            // count nodes before target
                            beforeCnt++;
                        }
                        node = node.nextSibling;
                    }
                    // fire event to server
                    this.fire('onCustomSelect', {bcnt: beforeCnt});
                }
            }
        ]]></attribute>
        <attribute name="onCustomSelect"><![CDATA[
            List dates = self.getSelectedDates();
            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("dd / MM / yyyy");
            String value = "";
            for (int i = 0; i < dates.size(); i++) {
                value = value + sdf.format((Date)dates.get(i)) + "\n";
            }
            tbx.setValue(value);
        ]]></attribute>
    </calendar>
</zk>


WeekPicker.java

package test.custom.component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Calendar;

public class WeekPicker extends Calendar {
    private static final long serialVersionUID = 7513083343273393743L;
    private List<Date> _selectedDates;
    static {
        addClientEvent(WeekPicker.class, "onCustomSelect", CE_IMPORTANT|CE_REPEAT_IGNORE|CE_NON_DEFERRABLE);
    }
    public List<Date> getSelectedDates () {
        return _selectedDates;
    }
    private void updateSelectedDates (int beforeCnt) {
        _selectedDates = new ArrayList<Date>();
        java.util.Calendar cal = java.util.Calendar.getInstance();
        // current selected date
        cal.setTime(getValue());
        // move to first day of the week
        cal.add(java.util.Calendar.DATE, (-1*beforeCnt));
        // add seven days to _selectedDates
        for (int i = 0; i < 7; i++) {
            _selectedDates.add(cal.getTime());
            cal.add(java.util.Calendar.DATE, 1);
        }
    }
    public void service(org.zkoss.zk.au.AuRequest request, boolean everError) {
        final String cmd = request.getCommand();
        if (cmd.equals("onCustomSelect")) {
            final Map<String, Object> data = request.getData();
            // get node count before selected date
            final Integer beforeCnt = (Integer)data.get("bcnt");
            // update selected dates
            updateSelectedDates(beforeCnt);
            // post event
            Events.postEvent("onCustomSelect", this, null);
        } else {
            super.service(request, everError);
        }
    }
}


The Result

View demo on line
http://screencast.com/t/N35NM2T98yY

References

Calendar.js
https://github.com/zkoss/zk/blob/master/zul/src/archive/web/js/zul/db/Calendar.js

Calendar.java
https://github.com/zkoss/zk/blob/master/zul/src/org/zkoss/zul/Calendar.java

Client Side Programming
http://books.zkoss.org/wiki/Small_Talks/2010/April/Client_Side_Programming

The use, apply Attribute
http://books.zkoss.org/wiki/ZK_Developer%27s_Guide/Fundamental_ZK/ZK_User_Interface_Markup_Language/ZK_Attributes#The_use.2C_apply_Attribute

Download

calendar_as_week_picker.zul
https://github.com/benbai123/ZK_Practice/blob/master/Components/projects/Components_Practice/WebContent/calendar_as_week_picker.zul

WeekPicker.java
https://github.com/benbai123/ZK_Practice/blob/master/Components/projects/Components_Practice/src/test/custom/component/WeekPicker.java

Demo Flash
https://github.com/benbai123/ZK_Practice/blob/master/Components/demos/calendar_as_week_picker.swf

4 comments:

  1. Good work.I have a question.I have a scenario let us suppose my application is open in a browser tab,and in second browser tab i have open a simple.html(right now its is inside my application) page where i have a button now i will want if i click on this button some event will fire into my application and a tab will be created inside my application which already open in browser .Can it possible with ZK?

    ReplyDelete
    Replies
    1. This is doable, you can use ajax call to load a zul page on a html button click, then set some data on a component onCreate in that zul page, and use Server push to check that data and create new tab.

      please refer to

      http://ben-bai.blogspot.tw/2013/04/notify-zul-from-html.html

      Delete
  2. One more question i was tying to create a new component in zk by extending zk image component i have to support title and alt . how can i do it

    ReplyDelete
    Replies

    1. You can refer to some similar article

      http://ben-bai.blogspot.tw/2012/08/zk-component-development-tutorial.html

      http://ben-bai.blogspot.tw/2013/01/zk-datebox-customize-datebox-as.html

      http://ben-bai.blogspot.tw/2013/01/extending-and-customizing-zk-component.html


      but if you just want to set some native dom attribute, you can use Client Attribute property,

      e.g.,

      <zk xmlns:ca="client/attribute">

      <image src="abc" ca:alt="image not found" ca:title="image title" />

      </zk>

      for more information, please refer to document

      http://books.zkoss.org/wiki/ZUML_Reference/ZUML/Namespaces/Client_Attribute

      Delete