分享
 
 
 

Navigation Tree 1.1 实现源码

王朝other·作者佚名  2006-01-30
窄屏简体版  字體: |||超大  

Navigation Tree 1.1 实现详解

Navigation Tree 1.1是一个仿照http://msdn.microsoft.com/library/ 左侧目录树(如图

所示,下称MSDN Library目录树)实现的居于XML的、客户端驱动的目录树组件。

Navigation Tree 1.0 写于2002年12月,当初的目的主要是为了获得与MSDN Library目录树相同的效果。1.1的更新版本完成于2003年1月20日,更新后的Navigation Tree 1.1功能支持动态加载目录结点,也修正了1.0里面一些按键事件的响应错误。Navigation Tree 1.1的表现MSDN Library目录树更加一致。

Navigation Tree分为四个部分:结点描述文件(XML)、格式转换文件(XSL)、JavaScript文件和CSS样式表。四部分的具体实现如下:

结点描述文件(XML):

描述树结点信息和结点之间的关系。

NavigationTree.xml

<?xml version="1.0" encoding="utf-8" ?>

<?xml-stylesheet type="text/xsl" href="NavigationTree.xsl" ?>

<Tree>

<TreeNode Title="Node1" Href="http://www.china.com">

<TreeNode Title="Node11" Href="http://msdn.microsoft.com" />

<TreeNode Title="Node12" Href="about:blank" Target="_blank">

<TreeNode Title="Node121" Href="mailto:s_yzzhou@stu.edu.cn" />

<TreeNode Title="Node122" Href="javascript:alert('Hello,World');" Target="_self" />

<TreeNode Title="Node123" Href="http://ebook.stu.edu.cn" />

</TreeNode>

</TreeNode>

<TreeNode Title="Node2" Target="_blank">

<TreeNode Title="Node21" Target="_self" />

<TreeNode Title="Node22" Target="newFrame" />

</TreeNode>

<TreeNode Title="Node3" NodeSrc="NavigationTree.xml" />

<TreeNode Title="Node4" Href="http://ebook.stu.edu.cn" Target="_blank" />

<TreeNode Title="Node5" />

</Tree>

格式转换文件(XSL):

用于格式化结点描述文件。

NavigationTree.xsl

<?xml version="1.0" encoding="utf-8" ?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/Tree">

<html>

<head>

<title>NavigationTree</title>

<link rel="stylesheet" type="text/css" href="NavigationTree.css" />

<script language="javascript" src="NavigationTree.js" />

</head>

<body onselectstart="OnBodySelectStart();" onkeydown="OnBodyKeyDown();" topmargin="0" leftmargin="0" marginheight="0" marginwidth="0" bgcolor="#f1f1f1" text="#000000">

<nobr>

<div class="NavigationTree" type="root">

<div type="nodecollection">

<xsl:apply-templates select="TreeNode" />

</div>

</div>

</nobr>

</body>

</html>

</xsl:template>

<xsl:template match="TreeNode">

<div type="node">

<!--Image-->

<span class="clsSpace" type="img">

<xsl:choose>

<xsl:when test="TreeNode or @NodeSrc">

<xsl:attribute name="onclick">OnImgClick(this)</xsl:attribute>

<xsl:attribute name="style">cursor:hand</xsl:attribute>

<span class="clsCollapse">+</span>

</xsl:when>

<xsl:otherwise>

<xsl:attribute name="style">cursor:default</xsl:attribute>

<span class="clsLeaf">.</span>

</xsl:otherwise>

</xsl:choose>

</span>

<!--Label-->

<span class="clsLabel" type="label" onclick="OnItemClick(this)" onmouseover="OnItemMouseOver(this)" onmouseout="OnItemMouseOut(this)" onmousedown="OnItemMouseDown(this)" onmouseup="OnItemMouseUp(this)">

<xsl:attribute name="id">

<xsl:value-of select="@NodeId" />

</xsl:attribute>

<xsl:attribute name="title">

<xsl:value-of select="@Title" />

</xsl:attribute>

<xsl:choose>

<xsl:when test="@Href">

<xsl:attribute name="style">cursor:hand;</xsl:attribute>

<a>

<xsl:choose>

<xsl:when test="@Target">

<xsl:attribute name="target">

<xsl:value-of select="@Target" />

</xsl:attribute>

</xsl:when>

<xsl:otherwise>

<xsl:attribute name="target">fraContent</xsl:attribute> <!--Change the target frame name to appropriate value-->

</xsl:otherwise>

</xsl:choose>

<xsl:attribute name="tabindex">-1</xsl:attribute>

<xsl:attribute name="href">

<xsl:value-of select="@Href" />

</xsl:attribute>

<xsl:value-of select="@Title" />

</a>

</xsl:when>

<xsl:otherwise>

<xsl:attribute name="style">cursor:default;</xsl:attribute>

<xsl:value-of select="@Title" />

</xsl:otherwise>

</xsl:choose>

</span>

<!--Child nodes-->

<xsl:if test="TreeNode or @NodeSrc">

<div class="hidden" type="nodecollection">

<xsl:choose>

<xsl:when test="@NodeSrc">

<xsl:attribute name="nodesrc">

<xsl:value-of select="@NodeSrc" />

</xsl:attribute>

<div type="node">

<span class="clsSpace" type="img" style="cursor:default">

<span class="clsLeaf">.</span>

</span>

<span class="clsUnavailable">Loading...</span> <!--Change the suggestive string to your language-->

</div>

</xsl:when>

<xsl:otherwise>

<xsl:apply-templates select="TreeNode" />

</xsl:otherwise>

</xsl:choose>

</div>

</xsl:if>

</div>

</xsl:template>

</xsl:stylesheet>

JavaScript文件:

对文档事件进行处理。

NavigationTree.js

// Modify templatePath to the specified xsl file as you need

var templatePath="NavigationTree.xsl";

// Suggestive string for loading failure, Modify it to your language

var failureMsg="Failed to load child nodes.";

// Default window status message, Change it to your language

var defaultStatusMsg="Navigation Tree 1.1 -- [Kerry Chou]";

// Global variant for storing last clicked node item

var lastClickedNode=null;

//////////////////////////////////////////////////

/*

Beginning of event handlers

*/

// OnImgClick(obj)

// Handler of onclick event on img portion of a node

function OnImgClick(obj)

{

var node=GetNode(obj);

if(node){

if(!HasChildren(node)){

var label=GetNodeLabel(node);

if(label){

OnItemMouseDown(label);

OnItemClick(label);

OnItemMouseUp(label);

}

return;

}

if(IsExpanded(node)){

CollapseNode(node);

}else{

ExpandNode(node);

}

}

}

// OnItemClick(obj)

// Handler of onclick event on label portion of a node

function OnItemClick(obj)

{

var node=GetNode(obj);

var a=GetElement(obj,"A",null);

if(window.event.srcElement.tagName.toUpperCase()=="SPAN"){

NavigateNode(node);

}else{

document.body.focus();

}

if(node){

if(HasChildren(node)){

if(IsExpanded(node)){

CollapseNode(node);

}else{

ExpandNode(node);

}

}

}

}

// OnItemMouseDown(obj)

// Handler of onmousedown event

function OnItemMouseDown(obj)

{

if(obj){

obj.className="clsMouseDown";

}

if(lastClickedNode&&GetNodeLabel(lastClickedNode)!=obj){

GetNodeLabel(lastClickedNode).className="clsCurrentNoFocus";

}

}

// OnItemMouseUp(obj)

// Handler of onmouseup event

function OnItemMouseUp(obj)

{

if(GetNodeLabel(lastClickedNode)!=obj){

if(lastClickedNode){

GetNodeLabel(lastClickedNode).className="";

}

obj.className="clsCurrentHasFocus";

lastClickedNode=GetNode(obj);

}else{

obj.className="clsCurrentHasFocus";

}

}

// OnItemMouseOver(obj)

// Handler of onmouseover event

function OnItemMouseOver(obj)

{

if(obj&&obj!=GetNodeLabel(lastClickedNode)){

obj.className="clsMouseOver";

}

var a=GetElement(obj,"A",null);

if(a){

window.status=a.href;

}

}

// OnItemMouseOut(obj)

// Handler of onmouseout event

function OnItemMouseOut(obj)

{

if(obj&&obj!=GetNodeLabel(lastClickedNode)){

obj.className="";

}

window.status=defaultStatusMsg;

}

// OnBodyKeyDown()

// Handler of keydown event

function OnBodyKeyDown()

{

var blnRetVal = false

var objLI;

if (window.event.ctrlKey == false && window.event.altKey == false)

{

window.event.cancelBubble = true;

window.event.returnValue = false;

switch (window.event.keyCode)

{

case 9 : // tab key

if (window.event.shiftKey == true)

{

MovePrevious();

}

else

{

MoveNext();

}

break;

case 13 : // enter key

objLI = window.event.srcElement.parentElement;

if(IsExpanded(lastClickedNode)){

CollapseNode(lastClickedNode);

}else{

ExpandNode(lastClickedNode);

}

break;

case 37 : // left key

MoveLeft()

break;

case 38 : // up key

MoveUp()

break;

case 39 : // right key

MoveRight()

break;

case 40 : // down key

MoveDown()

break;

case 188 : // "<" key

MovePrevious();

break;

case 190 : // ">" key

MoveNext();

break;

default :

window.event.cancelBubble = false;

window.event.returnValue = true;

blnRetVal = true;

break;

}

}

else

{

window.event.cancelBubble = false;

window.event.returnValue = true;

blnRetVal = true;

}

return blnRetVal;

}

// Handler of onselectstart event

// Disable selection

function OnBodySelectStart()

{

window.event.cancelBubble = true;

window.event.returnValue = false;

return false;

}

/*

End of event handlers

*/

////////////////////////////////////////////////////////

// Retrieve the parent document object with specified tag name.

function GetParentObject(obj,tag)

{

if(obj){

obj=obj.parentElement;

while(obj&&obj.tagName.toUpperCase()!=tag.toUpperCase()){

obj=obj.parentElement;

}

return obj;

}

return null;

}

// Retrieve the parent document object with specified tag name and type.

function GetParentElement(obj,tag,type)

{

var parent=GetParentObject(obj,tag);

while(parent&&!CheckItemType(parent,type)){

parent=GetParentObject(parent,tag);

}

return parent;

}

// Retrieve the child document object with specified tag name and type.

function GetElement(parentObj,tag,type)

{

if(type==null){

type="";

}

if(parentObj!=null){

var children=parentObj.children;

if(children!=null){

for(var i=0;i<children.length;++i){

if(type==""){

if(CheckItemType(children(i),type)){

return children(i);

}

}else{

if(children(i).tagName.toUpperCase()==tag &&

CheckItemType(children(i),type)){

return children(i);

}

}

}

}

}

return null;

}

// Retrieve object's type if it has

function GetItemType(obj)

{

if(obj){

if(obj.type){

return obj.type;

}

}

return "";

}

// Verify object's type

function CheckItemType(obj,type)

{

if(type==null){

type="";

}

return GetItemType(obj).toUpperCase()==type.toUpperCase();

}

// Retrieve node item with a specified object within the node

function GetNode(obj)

{

if(obj){

if(CheckItemType(obj,"NODE")){

return obj;

}

if(CheckItemType(obj,"LABEL")||CheckItemType(obj,"IMG")){

while(obj&&CheckItemType(obj,"NODE")==false){

obj=GetParentObject(obj,"DIV");

}

return obj;

}

}

return null;

}

// Retrieve children container

function GetChildrenContainer(node)

{

node=GetNode(node);

if(node){

var parent=GetElement(node,"DIV","nodecollection");

return parent;

}

return null;

}

// Retrieve container in which the specified node resides in

function GetParentContainer(node)

{

node=GetNode(node);

if(node){

var container=GetParentElement(node,"DIV","nodecollection");

return container;

}

return null;

}

// Retrieve the label of the specified node

function GetNodeLabel(node)

{

var node=GetNode(node);

if(node){

return GetElement(node,"SPAN","LABEL");

}

return null;

}

// Retrieve the img of the specified node

function GetNodeImg(node)

{

var node=GetNode(node);

if(node){

return GetElement(node,"SPAN","IMG");

}

return null;

}

// Retrieve the parent node

function GetParentNode(node)

{

node=GetNode(node);

if(node){

var parent=GetParentElement(node,"DIV","nodecollection");//nodecollection

if(parent){

parent=GetParentElement(parent,"DIV","node");//parent's node

return parent;

}

}

return null;

}

// Retrieve first child node

function GetChildNode(node)

{

node=GetNode(node);

if(node){

var container=GetChildrenContainer(node);

if(container){

return GetElement(container,"DIV","node");

}

}

return null;

}

// Retrieve last child node

function GetLastChildNode(node)

{

node=GetNode(node);

if(node){

var container=GetChildrenContainer(node);

var children=container.children;

if(children.length>0){

return children(children.length-1);

}

}

return null;

}

// Retrieve next sibling node

function GetNextSibling(node)

{

node=GetNode(node);

if(node){

var container=GetParentContainer(node);

if(container){

var children=container.children;

if(children&&children.length>0){

var foundCurrent=false;

for(var i=0;i<children.length;++i){

if(foundCurrent){

return children(i);

}

if(children(i)==node){

foundCurrent=true;

}

}

}

}

}

return null;

}

// Retrieve previous sibling node

function GetPreviousSibling(node)

{

node=GetNode(node);

if(node){

var container=GetParentContainer(node);

if(container){

var children=container.children;

if(children&&children.length>0){

var previous=null;

for(var i=0;i<children.length;++i){

if(children(i)==node){

return previous;

}

previous=children(i);

}

}

}

}

return null;

}

// Expand the specified node if it has children

function ExpandNode(node)

{

node=GetNode(node);

if(node&&HasChildren(node)){

var img=GetNodeImg(node);

if(img){

img=GetElement(img,"SPAN","");

if(img&&img.className.toUpperCase()!="CLSLEAF"){

img.innerText="-";

img.className="clsExpand";

}

}

var container=GetChildrenContainer(node);

if(container){

container.className="shown";

}

if(container.nodesrc!=null){

try{

var source = new ActiveXObject("Msxml2.DOMDocument");

source.async = false;

source.resolveExternals = false;

source.load(container.nodesrc);

// Load style sheet.

var stylesheet = new ActiveXObject("Msxml2.DOMDocument");

stylesheet.async = false;

stylesheet.resolveExternals = false;

stylesheet.load(templatePath);

var nodes=stylesheet.selectNodes("//xsl:template");

for(var i=0;i<nodes.length;++i){

if(nodes(i).getAttribute("match")=="TreeNode"){

// "TreeNode" template found

}else{

// delete the other templates

stylesheet.documentElement.removeChild(nodes(i));

}

}

// Fill a div tag with the result of the transform

container.innerHTML = source.transformNode(stylesheet);

container.nodesrc=null;

}catch(err){

container.innerText=failureMsg;

return;

}

}

}

}

// Collapse the specifed node if it has children

function CollapseNode(node)

{

node=GetNode(node);

if(node&&HasChildren(node)){

var img=GetNodeImg(node);

if(img){

img=GetElement(img,"SPAN","");

if(img&&img.className.toUpperCase()!="CLSLEAF"){

img.innerText="+";

img.className="clsCollapse";

}

}

var container=GetChildrenContainer(node);

if(container){

container.className="hidden";

}

}

}

// Check whether a specified node has children nodes

function HasChildren(node)

{

node=GetNode(node);

if(node){

var container=GetChildrenContainer(node);

return container!=null;

}

return false;

}

// Check whether a specified node is expanded

function IsExpanded(node)

{

node=GetNode(node);

if(node){

var container=GetChildrenContainer(node);

if(container){

if(container.className.toUpperCase()=="HIDDEN"){

return false;

}

if(container.className.toUpperCase()=="SHOWN"){

return true;

}

}

}

return false;

}

// Check wether a specified node is collapsed

function IsCollapsed(node)

{

node=GetNode(node);

if(node){

var container=GetChildrenContainer(node);

if(container){

if(container.className.toUpperCase()=="HIDDEN"){

return true;

}

if(container.className.toUpperCase()=="SHOWN"){

return false;

}

}

}

return false;

}

// Open resource associated with a node

function NavigateNode(node)

{

if(node){

var label=GetNodeLabel(node);

if(label){

var a=GetElement(label,"A","");

if(a){

window.open(a.href,a.target);

}

}

}

}

// Select specifed node

function SelectNode(node)

{

node=GetNode(node);

if(node!=lastClickedNode&&lastClickedNode){

OnItemMouseDown(GetNodeLabel(node));

OnItemMouseUp(GetNodeLabel(node));

}

NavigateNode(node);

}

// Move to previous sibling node when '<' key is pressed or 'shift+tab' pressed

function MovePrevious()

{

if(lastClickedNode){

var previous=GetPreviousSibling(lastClickedNode);

if(previous){

SelectNode(previous);

}else{

var parent=GetParentNode(lastClickedNode)

if(parent){

SelectNode(parent);

}

}

}

}

// Move to first child node or next visible node when '>' key is pressed or 'tab' pressed

function MoveNext()

{

if(lastClickedNode){

var b=HasChildren(lastClickedNode);

if(b){

ExpandNode(lastClickedNode);

var child=GetChildNode(lastClickedNode)

SelectNode(child);

}else{

var next=GetNextSibling(lastClickedNode);

if(next){

SelectNode(next);

}else{

var parent=GetParentNode(lastClickedNode);

while(parent){

next=GetNextSibling(parent);

if(next){

SelectNode(next);

break;

}

parent=GetParentNode(parent);

}

}

}

}

}

// Move to parent node

function MoveLeft()

{

if(lastClickedNode){

if(IsExpanded(lastClickedNode)){

CollapseNode(lastClickedNode);

}else{

var parent=GetParentNode(lastClickedNode);

if(parent){

SelectNode(parent);

}

}

}

}

// Move to first child node

function MoveRight()

{

if(lastClickedNode){

if(IsCollapsed(lastClickedNode)){

ExpandNode(lastClickedNode);

}else{

var child=GetChildNode(lastClickedNode);

if(child){

SelectNode(child);

}

}

}

}

// Move to last visible node

function MoveUp()

{

if(lastClickedNode){

var previous=GetPreviousSibling(lastClickedNode);

if(previous){

while(HasChildren(previous)&&IsExpanded(previous)){

previous=GetLastChildNode(previous);

}

if(previous){

SelectNode(previous);

}

}else{

var parent=GetParentNode(lastClickedNode);

if(parent){

SelectNode(parent);

}

}

}

}

// Move to next visible node

function MoveDown()

{

if(lastClickedNode){

if(HasChildren(lastClickedNode)&&IsExpanded(lastClickedNode)){

var child=GetChildNode(lastClickedNode);

if(child){

SelectNode(child);

}

}else{

var next=GetNextSibling(lastClickedNode);

if(next){

SelectNode(next);

}else{

var parent=GetParentNode(lastClickedNode);

while(parent){

next=GetNextSibling(parent);

if(next){

SelectNode(next);

break;

}

parent=GetParentNode(parent);

}

}

}

}

}

///////////////////////////////////////////

///////////////////////////////////////////

CSS样式表:

此样式表即为MSDN Library目录树的样式表。

BODY

{

font-family: Verdana;

cursor: default;

font-size: 9pt;

}

tbody

{

font-size: 9pt;

}

.NavigationTree

{

padding: 4px 5px;

}

.Navigation IMG

{

position: relative;

cursor: hand;

top: -2px;

margin: 0px;

padding: 0px;

}

.NavigationTree A

{

color: black;

text-decoration: none;

}

span

{

padding: 2px 3px;

position: relative;

display: inline;

top: -2px;

height: 17px;

border: solid 1px #f1f1f1;

}

span.clsLabel

{

}

SPAN.clsSpace

{

font-family: verdana;

position: relative;

padding: 3px 2px;

top: 0px;

width: 17px;

margin: 0px;

cursor: hand;

overflow: hidden;

}

span.clsSpace span

{

position: relative;

width: 11px;

height: 11px;

border: solid 1px black;

background-color: #ffffff;

}

SPAN.clsCollapse

{

line-height: 6px;

font-size: 9px;

overflow: hidden;

padding: 1px;

}

SPAN.clsExpand

{

padding-left: 1px;

overflow: hidden;

line-height: 3px;

font-size: 13px;

padding-top: 3px;

}

SPAN.clsLeaf

{

overflow: visible;

font-size: 9px;

line-height: 3px;

padding: 1px 0px 0px 3px;

}

SPAN.clsMouseOver

{

background-color: #CCCCCC;

border: 1px solid #999999;

}

SPAN.clsMouseDown

{

background-color: #999999;

border: 1px solid #999999;

}

SPAN.clsCurrentHasFocus

{

background-color: #FFFFFF;

border: 1px solid #999999;

}

SPAN.clsCurrentNoFocus

{

background-color: #F1F1F1;

border: 1px solid #999999;

}

A

{

color: black;

text-decoration: none;

}

span.clsUnavailable

{

height: 0px;

border: none;

color: #888888;

}

.hidden

{

display: none;

}

.shown

{

display: block;

margin-left: 15px;

}

NavigationTree 1.1的运行结果如下图所示:

NavigationTree 1.1运行环境:

由于客户端脚本里使用到了MSXML2,所以浏览器环境必须为IE5.01或以上版本。而其他浏览器版本的兼容性问题可以使用服务器端脚本来解决。一下ASP.NET代码判断客户端浏览器版本:

<script language="C#" runat="server">

string treeurl="NavigationTree.xml";

private void Page_Load(object sender, System.EventArgs e)

{

if(Request.Browser.MajorVersion<=5&&Request.Browser.MinorVersion<0.01){

treeurl=treeurl.Replace("xml","aspx");

}

Response.Redirect(treeurl);

}

</script>

Bug Reporting:

S_yzzhou@stu.edu.cn

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有