13.自定义菜单

“自定义菜单”是指向鼠标右键弹出菜单增加菜单项，通过"MenuBeforePopup"事件、调用AddMenu( )函数、以及"MenuClicked"事件，实现了菜单的自定义，整个过程是动态的。
详细的过程是：当鼠标右键菜单即将要弹出时，Treelist会触发页面的OnEvent(id, "MenuBeforePopup", ...)事件，在这个事件的js中，你可以通过调用AddMenu( )函数向Treelist动态增加菜单项；如果用户选中了你定义的菜单项，Treelist会触发OnEvent(id, "MenuClicked", ...)事件，从而达到了自定义菜单功能的目的.
在demo中有详细的演示页，相信您一看就明白。
AddMenu( 参数 )函数中的参数可以是XML串、非XML的文字串，或URL，其规则举例如下：

    <items>
    <item id="3103" text="热销" icon="buttons.zip#303.ico">
    <item id="3104" text="滞销产品" icon="buttons.zip#304.ico">
     <item id="31041" text="库存1" icon="buttons.zip#304.ico" detail="浮动的详细说明，可选"/>
     <item id="31042" text="库存2" enable="false" detail="浮动的详细说明，可选"/>
    </item>
    </items>

如果采用非XML的普通串，其举例如下：

    //多个菜单项之间以回车符分隔
    var s = "id=4001; text=男帽; icon=buttons.zip#301.ico; detail=夏季时装\r\n";
    s += "id=4002; text=时髦头巾; icon=buttons.zip#302.ico; detail=优惠直销"

规则1：如果是XML串，元素名须为item;
规则2：如果是XML串，item允许有下级item，表示菜单项的子菜单：
规则3：属性有id、text、icon、enable、checked、detail，其中 id 必须 >=3000 .
14.事件

Supcan Treelist的OnEvent( id, Event, p1, p2, p3, p4 )事件含义及参数分别如下：
事件的js用法可参见Demo。
备注1：如果当前列为 Button型 或 editWithButton型, 鼠标点在 button上则为"button"；如果列中有多个button，那么分别为"button1"、"button2"...类推.
备注2：EditKeydown和EditChar均为在输入框中的键盘事件，EditKeydown能捕获几乎所有键盘动作，包括非字符的回车、Tab等；而EditChar则以输入的字符为主，包括中文.
您可以执行全局函数 CancelEvent( ) 去阻止继续执行，就如事件没有发生过那样，但不同的ASCII码，您需要在这二个事件中挑选一个执行CancelEvent( )，具体请在演示页“12.事件”中去测试;
备注3：1-Ctrl键也按下了； 2-Shift键也按下了； 3-二者一起按下了.
备注4：格式为handle=[?];asChild=true，例如串"handle=82922093;asChild=true"，其中handle的含义为源Treelist的句柄(可通过GetHandle函数获得)，如果是自我拖拽，则不出现该项；asChild=true表示作为子孙拖入，如果非子孙、或者当前非树，则不出现该项.
15.XML提交格式规范

通过调用函数GetChangedXML( )，能取得输入内容的XML包，使得应用服务器能作相应处理，函数中参数level为提交级别，分如下4种：
级别0：生成当前全部、最新内容(不包括修改前的原始内容);
级别1：仅生成被修改过的单元格的内容(包括原始内容);
级别2：在级别1的基础上，增加被修改过单元的整行内容;
级别3，内容包含所有行、所有列、修改前后的内容.
级别0最常用，并且XML规范最简单，如下所示：

    <?xml version="1.0" encoding="UTF-8"?">
    <!-- id在XML描述文件中定义 -->
    <table id="?" level="0" 自定义属性="?" >
    　<row>
    　　　<!-- 列名处为真实的列名 -->
    　　　<列名>Text</列名>
    　　　...
    　</row>
    　<row ...>
    　　　...
    　</row>
    　...
    </table>

级别1、2、3的内容规定如下：

    <?xml version="1.0" encoding="UTF-8"?">
    <!-- id、key在XML描述文件中定义 -->
    <table id="?" key="?" level="?" 自定义属性="?" >

    　<!-- 区域1: 被修改的行 -->
    　<modifiedRow>
    　　<!-- key为该行key列的原始值(被修改前), rowNumber为行号 -->
    　　<row key="?" rowNumber="?">
    　　　<!-- 列名处为真实的列名, origin为原始值(被修改前)，isModified仅用于级别2和级别3, Text处为修改后的值 -->
    　　　<列名 origin="?" isModified="false">Text</列名>
    　　　...
    　　</row>
    　　...
    　</modifiedRow>

    　<!-- 区域2: 新增行 -->
    　<newRow>
    　　<!-- key为该行key列处输入的值, rowNumber为行号 -->
    　　<row key="?" rowNumber="?">
    　　　<!-- 列名处为真实的列名, Text处为输入的内容 -->
    　　　<列名>Text</列名>
    　　　...
    　　</row>
    　　...
    　</newRow>

    　<!-- 区域3: 被删除的行 -->
    　<deletedRow>
    　　<!-- key为该行key列的原始值(被修改前) -->
    　　<row key="?"></row>
    　　...
    　</deletedRow>

    　<!-- 区域4: 未修改过的行(仅用于级别3 时) -->
    　<notModifiedRow>
    　　<!-- 略，和区域1相比只是少了"Origin"属性 -->
    　</notModifiedRow>

    </table>

警告：应用服务器端开发的程序不应过于依赖级别1/2/3中的origin的内容(被修改前)，因为需要考虑并发.