Friday, January 20, 2012

ZK Flow Control - Prevent Opening Multiple Tabs

Sometimes we want limit that one user can only active one page, how to achieve this?
There are several parts described as follows:

1. The entry page

test.zul

<zk>
    <button label="go to page 1">
        <attribute name="onClick">
            // get the user active time
            Long time = test.Maps.keyMap.get("userName");
            // If no active time or expired, set active time and redirect,
            // Stay at this page otherwise.
            if (time == null || (System.currentTimeMillis()-time) > 10000) {
                test.Maps.keyMap.put("userName", System.currentTimeMillis());
                test.Maps.tmpKeyMap.put("userName", test.Maps.keyMap.get("userName"));
                Executions.getCurrent().sendRedirect("page1.zul");
            }
            else // redirect to another error page as need here
                Executions.getCurrent().sendRedirect("");
        </attribute>
    </button>
</zk>

The entry page is the only page that a user can open multiple times, we check whether the user is already work at other page while 'go to page 1' button clicked, redirect to 'page1.zul' or stay at this page as need.

Note we put the active time into another tmpKeyMap before redirect to page1, we will check it at page1 later, we can not check the keyMap directly because the result will the same at different page/session.

2. Page 1

page1.zul

<zk>
    <div visible="false">
        <attribute name="onCreate">
            // get active time from tmpKeyMap and check it
            Long time = test.Maps.tmpKeyMap.get("userName");
            if (time == null || (System.currentTimeMillis()-time) > 10000)
                Executions.getCurrent().sendRedirect("test.zul");
            else
                self.setVisible(true);
        </attribute>
        page1<div></div>
        <button label="go to page 2">
            <attribute name="onClick">
                test.Maps.tmpKeyMap.put("userName", test.Maps.keyMap.get("userName"));
                Executions.getCurrent().sendRedirect("page2.zul");
            </attribute>
        </button>
    </div>
    <timer repeats="true" running="true" delay="1000">
        <attribute name="onTimer">
            // keep update the active time and clear the data in tmpKeyMap
            test.Maps.keyMap.put("userName", System.currentTimeMillis());
            if (test.Maps.tmpKeyMap.get("userName") != null)
                test.Maps.tmpKeyMap.remove("userName");
        </attribute>
    </timer>
</zk>

In this page, the content is initial invisible, we get the active time from tmpKeyMap and show the content if it is valid, redirect to test.zul otherwise.

Then we start a timer, keep update the active time, the delay is 1000ms and remember we consider that time as expired if (current time - active time) > 10000ms (10 seconds). You can adjust the delay time and expire condition as need, the larger the delay and expire condition, the longer the user have to wait to enter the page again after he/she left.

Conclusions:
The effect:

1. The user can not link to page1.zul directly
2. Only one page can redirect to page1.zul from test.zul
3. Click the browser's 'previous page' or refresh page will return to test.zul.
4. Can enter page1 again after return to test.zul and wait about 10 seconds.

Download
You can download the full project from github:
https://github.com/benbai123/ZK_Practice/tree/master/Flow/LimitOnePage

3 comments:

  1. Hi did you write something for ZK+JasperReport

    ReplyDelete
    Replies
    1. yes, just haven't made an article of it, I'll do it later

      Delete
    2. done, http://ben-bai.blogspot.tw/2012/10/generate-report-by-zk-jasperreport.html

      Delete