Denny's profileJava DreamsBlogLists Tools Help

Blog


    November 15

    Dojo TreeV3使用详解

    Dojo TreeV3使用详解

                                                  作者:邓胤(deng.yin@gmail.com)

        工作中使用了TreeV3这个dojo的组件,感觉基本上已经是把dojo的treeV3使用到了极点(自定义树的外观,树节点的拖拉,把其他Drag Source拖拉到树中),公司也要求我作个treeV3演说。所以特意把这篇文章写下来。

        首先先对treeV3做一个简单的介绍。TreeV3.js, TreeNodeV3.js, .TreeBasicControllerV3.js, TreeContextMenuV3.js,TreeDndControllerV3.js,TreeEditor.js, 主要的就是这些js一起协作。有兴趣的可以看看源码, 其实dojo的代码看起来还算是瞒简单的。下面我就用几个例子来说明怎样扩展或自定义TreeV3。本篇文章是增对有一定dojo知识的读者,如果你现在还不了解dojo,请看
    http://dojotoolkit.org/.

        1.  为叶子节点增加图标。
           IconTree.html
          
    <div dojoType="TreeV3" listeners="controller">
        <div dojoType="TreeNodeV3" title="Item 1" widgetId="1">
            <div dojoType="TreeNodeV3" childIconSrc="images/page.gif" title="Item 1.1" widgetId="Item 1.1"></div>
            <div dojoType="TreeNodeV3" childIconSrc="images/page.gif" title="Item 1.2" widgetId="Item 1.2"></div>
        </div>

        <div dojoType="TreeNodeV3" title="Item 2" widgetId="Item 2">
            <div dojoType="TreeNodeV3" childIconSrc="images/page.gif" title="Item 2.1" widgetId="Item 2.1"></div>
        </div>

        <div dojoType="TreeNodeV3" title="Empty Folder" isFolder="true" widgetId="Item 3"></div>
        <div dojoType="TreeNodeV3" childIconSrc="images/page.gif" title="Item 4" widgetId="Item 4"></div>
    </div>
        我们在每个TreeNode上加上childIconSrc属性。请看icontree.js怎样让这个属性生效的。
        icontree.js
    dojo.lang.extend(dojo.widget.TreeNodeV3, {
        childIconsrc: "",
        childIcon: null,
        iconNode:null,
        titleNode:null,
        postCreate: function(args) {
        //build icon
            if (args["childIconsrc"]) {
                this.childIconsrc = args["childIconsrc"];
            }
            this.childIcon = document.createElement("img");
            if (this.childIconsrc != "") {
                this.childIcon.src = this.childIconsrc;
                this.childIcon.setAttribute("width", "16");
                this.childIcon.setAttribute("height", "16");
            }
            this.iconNode = this.tree.labelNodeTemplate.cloneNode(true);
            this.titleNode = this.tree.labelNodeTemplate.cloneNode(true);
            if (!this.isFolder){
                //clear treenode, if it is not folder node
                this.labelNode.innerHTML="";
            }
            this.titleNode.innerHTML=this.title;
            this.iconNode.appendChild(this.childIcon);
            // add icon first, then add title
            this.labelNode.appendChild(this.iconNode);
            this.labelNode.appendChild(this.titleNode);       
        }
    });
    我们扩展了TreeNodeV3这个组件的postCreate方法(dojo组件都有这个方法,他相当于构造方法吧,我们可以在这里做必要的初始化),这里做的事应该比较清楚,我们通过childIconsrc这个属性创建了iconNode, 然后清空TreeNodeV3的labelNode。再增加iconNode和titleNode

    2. 拖动物体到tree中
    dragother.html
    <div dojoType="TreeV3" DndMode="between;onto" DndAcceptTypes="firstTree;feed" widgetId="firstTree" listeners="basicController;dndcontroller;selector;disableWrap" toggle="fade" showGrid="false" showRootGrid="true">
        <div dojoType="TreeNodeV3" title="Item 1" widgetId="1">
            <div dojoType="TreeNodeV3"  title="Item 1.1" widgetId="Item 1.1"></div>
            <div dojoType="TreeNodeV3" title="Item 1.2" widgetId="Item 1.2"></div>
        </div>

        <div dojoType="TreeNodeV3" title="Item 2" widgetId="Item 2">
            <div dojoType="TreeNodeV3" title="Item 2.1" widgetId="Item 2.1"></div>
        </div>

        <div dojoType="TreeNodeV3" title="Empty Folder" isFolder="true" widgetId="Item 3"></div>
        <div dojoType="TreeNodeV3" title="Item 4" widgetId="Item 4"></div>
    </div>

    <br/>

    <span id="feed_0">Drag me0 to tree.</span><br/>
    <span id="feed_1">Drag me1 to tree.</span><br/>
    <span id="feed_2">Drag me2 to tree.</span><br/>
    <span>You can't drag me.</span>
    注意黑体的DndAcceptTypes属性。说明这个树接受dragSource type为firstTree或者feed的(也就是自己,还有就是下面的span, 我们需要把span变成可以拖动的物体 dragSource)。再看dragother.js。
        dojo.addOnLoad(function(){
               var num = 0;
               while(dojo.byId("feed_" + num) != null){
                   var dropSource = new dojo.dnd.HtmlDragSource(dojo.byId("feed_" + num), "feed");
                   num++;
            }   
        });

    dojo.dnd.TreeDropTargetV3.prototype.oldGetDropHandler = dojo.dnd.TreeDropTargetV3.prototype.getDropHandler;
    dojo.lang.extend(dojo.dnd.TreeDropTargetV3, {
       
        getDropHandler: function(e, source, targetParent, targetIndex) {
            if (source.type == "feed"){
                var sourceNode = source.domNode;
                if (dojo.widget.byId(sourceNode.id) != null){
                    alert("this widget has already been here.");
                    return function(){
                        return false;
                    }
                }            
                var node = createTreeNode(sourceNode.id, sourceNode.innerHTML);
                targetParent.addChild(node, targetIndex);
                return function(){
                    return true;
                }
            }
            return this.oldGetDropHandler(e, source, targetParent, targetIndex);
        }   
    });   

    function createTreeNode(widgetId, title) {
        return dojo.widget.createWidget("TreeNodeV3",
        {
            widgetId: widgetId,                                                   
            title: title,
            isFolder: false,
            tree: 'firstTree'
        });
    }

    第一段是让那些span成为dragsource。第二段我们hack了dojo.dnd.TreeDropTargetV3的 getDropHandler方法(具体可以看看TreeDndControllerV3.js)。当我们接收到dragSources时我们获取那些 span中的一些信息,然后create 一个treeNode,在把这个treeNode加到树中。

    3.   ...................................................
    4.   ...................................................
    5.   ...................................................

    还有一些hack treeV3的东西实在不愿写。 dojo的treeV3真的是蛮强大的(仔细看看那几个**Controller和TreeV3 TreeNodeV3的源码), 而且dojo的widget源码还是蛮容易理解的。有兴趣的朋友可以看看dojo的源码。还有就是dojo包里面tests目录下面的例子。大多数应用的话看看里面的例子也就行了。

    例 子的源码可以在http://deng.yin.googlepages.com/TreeV3Sample.zip下载。本例子中没有包括 dojo0.4源码,用户可以到http://download.dojotoolkit.org/release-0.4.0/dojo-0.4.0- ajax.zip下载源码, 然后解压到例子中的dojo目录。

    格式不好的话可以看http://docs.google.com/View?docid=ajgd3tgv958v_3gz374h
    October 20

    巧妙使用javascript让你的页面程序处于index frame中。

    假如我们有这个一个页面,  index.html
    <frameset framespacing="0" border="false" cols="180,*" frameborder="1">
    <frame name="left"  scrolling="auto" marginwidth="0" marginheight="0" src="Toc.html">
    <frame name="main" scrolling="auto" src="Content.html">
      </frameset>
      <noframes>
      <body>
      <p>This page uses frames, but your browser doesn't support them.</p>
      </body>
      </noframes>

    Toc.html是目录页面, Content.html是内容页面。     

    场景1:假如一个用户登入后, 进入index.html,然后用户过了很长一段时间没有操作session timeout了。这时候用户再去点页面的操作的话,这时候Content.html会转到登入页面, 但是因为在一个frame里面, 所以登入页面会在index.html中。我们希望他不出现在index.html中, 清在登入页面加上下面这段javascript
    <script type="text/javascript">
        if (window.top != self){
            window.top.location = self.location;
        }
    </script>

    场景2:我们希望右边的内容页面不能独立的出现(即一定要出现在index.html中),我们也需要在每个在“main” frame的页面加上下面这段javascript
    if (window.top == self){
        // ensure sub page would contain in index page
        window.location="index.html";
    }
    October 09

    How can I move text cursor in a text input field?

    Thanks the following codes. while in Firefox, you just need to invoke textElement.focus() method.

    So here is how to position the caret end the end of a text field/text
    area with IE4/5:

    <SCRIPT>
    function setCaretToEnd (el) {
    if (el.createTextRange) {
    var v = el.value;
    var r = el.createTextRange();
    r.moveStart('character', v.length);
    r.select();
    }
    }
    function insertAtEnd (el, txt) {
    el.value += txt;
    setCaretToEnd (el);
    }
    </SCRIPT>
    </HEAD>
    <BODY>
    <FORM>
    <INPUT TYPE="text" NAME="aText" SIZE="40">
    <BR>
    <INPUT TYPE="text" NAME="a2ndText" VALUE="Kibology for all.">
    <INPUT TYPE="button" VALUE="insert and move to end"
    ONCLICK="insertAtEnd (this.form.aText,
    this.form.a2ndText.value);"
    >
    <BR>
    <INPUT TYPE="text" NAME="a3rdText" VALUE="All for Kibology.">
    <INPUT TYPE="button" VALUE="insert and move to end"
    ONCLICK="insertAtEnd (this.form.aTextArea,
    this.form.a3rdText.value);"
    >
    <BR>
    <TEXTAREA NAME="aTextArea" ROWS="5" COLS="20" WRAP="soft"></TEXTAREA>
    </FORM>


    http://www.faqts.com/knowledge_base/view.phtml/aid/17749/fid/53
    September 12

    Hack dojo codes with dojo's util

    dojo.lang.extend(dojo.widget.PopupMenu2, {
        onOpen: function(e){
            this.openEvent = e;
            var x = e.pageX, y = e.pageY;

            var win = dojo.html.getElementWindow(e.target);
            var iframe = win._frameElement || win.frameElement;
            if(iframe){
                var cood = dojo.html.abs(iframe, true);
                x += cood.x - dojo.withGlobal(win, dojo.html.getScroll).left;
                //override the onOpen to reslove the problem the context popup menu open under the selected TreeNode.
                if (!(e.type == "contextmenu" && dojo.render.html.ie))
                    y += cood.y - dojo.withGlobal(win, dojo.html.getScroll).top;
            }
            this.open(x, y, null, [x, y]);

            e.preventDefault();
            e.stopPropagation();
        }
    });

    这样我们就是复写了dojo.widget.PopupMenu2类的onOpen方法。如果我们想调用覆盖以前的方法。
    //backup the old function
    dojo.widget.TreeBasicControllerV3.prototype.oldOnKey =dojo.widget.TreeBasicControllerV3.prototype.onKey;
    dojo.lang.extend(dojo.widget.TreeBasicControllerV3, {
        onClick: function(e) {
            if (e.target.tagName == "INPUT")
                return ;
            // default click handler just sets the focus
            var treeWidget = this.getWidgetByNode(e.currentTarget);
            if (!treeWidget || !treeWidget.isTree) { return; }
            var nodeWidget = this.getWidgetByNode(e.target);
            if (!nodeWidget || !nodeWidget.isTreeNode) { return; }
            this._focusLabel(treeWidget, nodeWidget);
        },
        onKey: function (e){
            if (e.target.tagName == "INPUT")
                return ;
            this.oldOnKey(e);
        }
    });

    dojo.lang.extend这个方式是多么的方便。我们可以用这个方法方便的扩展或修改以有的代码。

    看看dojo的dojo.lang.common  里面包括了对象间的一些操作。如dojo.lang.inherits, dojo.lang.mixin etc
    September 05

    javascript中的继承。

    本来打算写篇关于javascript继承的文章, 但是觉得这篇文章已经写得够好了。

    http://forum.javaeye.com/viewtopic.php?t=19748