Saturday, June 1, 2013

ZK CDT: Handling Client Side Event to Create Simple Text Note


Introduction

This is the third article of ZK CDT (ZK Component Development Tutorial) walkthrough, this article describe how to handle the client side event to create new dom elements (note block) as needed.

The goal of this walkthrough is to create a quicknote component that help you do some quick note on web page (similar to you crop some screenshot, highlight something and add some text in photo editor), and describe each part of a component through each article in this walkthrough.

This is the third part: Handle client side event in widget class

Result

View demo online:
http://screencast.com/t/QbImq9rhY

Similer to the enhancedmask component in previous article, but now you can add a note block and type some text in it by clicking on the mask element.

Pre-request

ZK CDT: Add Attributes to Create Enhanced Mask
http://ben-bai.blogspot.tw/2013/06/zk-cdt-add-attributes-to-create.html


Program

simpletextnote.zul

Contains a simpletextnote component, a slider/colorbox that control the opacity/background-color of the simpletextnote.

<zk>
    <hlayout>
        <!-- The simpletextnote component that will cover
            its children by a mask
            you can click on the mask to add a textarea
            and type text in it
        -->
        <simpletextnote width="700px" id="stn"
            opacity="20" maskColor="#00FF00">
            <button label="ZK Website" />
            <iframe width="100%"
                height="1000px"
                src="http://www.zkoss.org/"></iframe>
        </simpletextnote>
        <div>
            <!-- slider used to control opacity of simpletextnote -->
            <slider curpos="20" maxpos="100">
                <attribute name="onScroll"><![CDATA[
                    stn.setOpacity(((ScrollEvent)event).getPos());
                ]]></attribute>
                <attribute name="onScrolling"><![CDATA[
                    stn.setOpacity(((ScrollEvent)event).getPos());
                ]]></attribute>
            </slider>
            <!-- colorbox used to control mask color of simpletextnote -->
            <colorbox color="#00FF00">
                <attribute name="onChange"><![CDATA[
                    stn.setMaskColor(self.getValue());
                ]]></attribute>
            </colorbox>
        </div>
    </hlayout>
</zk>


SimpleTextNote.js

The widget class of SimpleTextNote component, extends enhancedmask and handle doClick_ event to create note block.

/**
 * Widget class of SimpleTextNote component,
 * extends custom.zk.components.quicknote.EnhancedMask, change zclass and
 * handle client side click event
 * 
 * Several new things:
 * 
 * extends another widget class:
 *             this is not that new, we have extended from
 *             zk.Widget in mask and enhancedmask components.
 *             but in this widget class we can see that we do not define the
 *             getZclass, setOpacity and setMaskColor methods again, we can
 *             use them directly since they are defined in EnhancedMask.js
 *             (The super widget class of this widget)
 * handling client side event (doClick_):
 *             the doClick_ is a predefined API
 *             that will be called automatically with an onclick event in ZK
 *             There are lots of such API in ZK, e.g., doClick_, doDoubleClick_,
 *             doRightClick_, doMouseOver_, doMouseOut_, etc, etc
 * 
 *             currently they are defined in widget.js under 'zk' project,
 *             you can override it if you want to process a click event of this widget
 * 
 * evt:
 *             the ZK wrapped event that will be passed into event-handling API automatically
 *             two major content:
 *                 evt.target: the widget that received this event
 *                 evt.domTarget: the dom element that received this event
 * 
 * override widget function:
 *             you can override a widget function that has been defined in
 *             ancestor widget class by define it again in widget class
 *             e.g., the doClick_ is defined in zk.Widget,
 *                 and we override it by define it again in this widget class
 * 
 * call ancestor's widget function:
 *             use this.$supers('functionName', arguments)
 *             to call the mathod defined in ancestor's widget class
 *             where functionName is the method to call, arguments is the parameters
 *             to pass
 * 
 */
custom.zk.components.quicknote.SimpleTextNote = zk.$extends(custom.zk.components.quicknote.EnhancedMask, {
    doClick_: function (evt) {
        // call doClick_ method in super widget class
        // (i.e., bubble up)
        // the click event will not be fired to server side
        // if this line is not added (or you need to fire it manually)
        this.$supers('doClick_', arguments);
        // add note block if click on mask element
        if (evt.domTarget == this.$n('mask'))
            this._addNoteBlock(evt);
    },
    _addNoteBlock: function (evt) {
        var n = this.$n(),
            ofs = jq(n).offset(), // offset
            x = evt.pageX - ofs.left, // left for note block
            y = evt.pageY - ofs.top, // top for note block
            noteBlock = this._createNoteBlock(x, y); // note block

        // add note block under root element of widget
        n.appendChild(noteBlock);
        // focus textarea
        jq(noteBlock.firstChild).focus();
    },
    _createNoteBlock: function (x, y) {
        var div = document.createElement('div'), // note block div
            textarea = document.createElement('textarea'), // note block textarea
            tstyle = textarea.style,
            zcls = this.getZclass();
        // add styles,
        // also add a class name to apply the style defined
        // with selector '.z-simpletextnote .z-simpletextnote-noteblock'
        // in simpleTextNote.css.dsp
        jq(div).css({'left': x+'px', // position left and top
                    'top': y+'px'})
            .addClass(zcls + '-noteblock');

        // set cols of textarea to 1 so
        // its width can be shrinked
        // also add a class name to apply the style defined
        // with selector '.z-simpletextnote .z-simpletextnote-noteblock-textarea'
        // in simpleTextNote.css.dsp
        jq(textarea).prop('cols', '1')
            .addClass(zcls + '-noteblock-textarea');

        // append textarea to div
        div.appendChild(textarea);
        return div;
    },
    // override with new css class name
    getZclass: function () {
        var zcls = this._zclass;
        return zcls? zcls : 'z-simpletextnote';
    }
});


simpleTextNote.css.dsp

<%--// ------------------------------------------- --%>
<%--//                                             --%>
<%--//            SimpleTextNote component           --%>
<%--//                                             --%>
<%--// ------------------------------------------- --%>
<%--// root element --%>
.z-simpletextnote {
    <%--// be the anchor of absolute positioned children --%>
    position: relative;
    overflow: hidden;
}
<%--// the mask that cover whole element --%>
<%--// no background-color and opacity specified --%>
<%--// since we specified them in widget class --%>
.z-simpletextnote-cover {
    <%--// absoluted positioned --%>
    position: absolute;
    <%--// align the left-top corner of parent (root) element --%>
    left: 0px;
    top: 0px;
    <%--// cover whole root element --%>
    height: 100%;
    width: 100%;
    <%--// make it the top most element under root element --%>
    z-index: 99999;
}

.z-simpletextnote .z-simpletextnote-noteblock {
    <%--// absoluted positioned --%>
    position: absolute;
    <%--// in front of mask --%>
    z-index: 999999;
}

.z-simpletextnote .z-simpletextnote-noteblock-textarea {
    <%--// h/v resizable --%>
    resize: both;
    <%--// default width and height --%>
    <%--// NOTE: the specified value of width/height will  --%>
    <%--// be the minimum value, you cannot shrink textarea --%>
    <%--// smaller than these values (at least on chrome) --%>
    width: 50px;
    height: 30px;
}


zk.wpd

Define components under "custom.zk.components.quicknote"

* only the added part, not the full code

NOTE: more components will be added with other articles later

    ...
    <widget name="SimpleTextNote" />
    ...


lang-addon.xml

Define all components in the project

* only the added part, not the full code

NOTE: more components will be added with other articles later

    ...

    <!-- 3rd, simpletextnote component
        extends enhancedmask and handle click event to
        create input field for note
        
        reuse the java class and redraw function of
        enhancedmask, create a new widget class and
        update zclass
    -->
    <component>
        <component-name>simpletextnote</component-name>
        <extends>enhancedmask</extends>
        <widget-class>custom.zk.components.quicknote.SimpleTextNote</widget-class>
        <mold>
            <mold-name>default</mold-name>
            <css-uri>css/simpleTextNote.css.dsp</css-uri>
        </mold>
    </component>

    ...


References

OOJS used in ZK
http://books.zkoss.org/wiki/ZK_Client-side_Reference/Introduction/Object_Oriented_Programming_in_JavaScript

widget.js
https://github.com/zkoss/zk/blob/master/zk/src/archive/web/js/zk/widget.js

Download

Full project at github
https://github.com/benbai123/ZK_Practice/tree/master/Components/projects/Components_Development__Series/001_walkthrough/ZKQuickNote

simpletextnote_component.swf

No comments:

Post a Comment