• ExtAspNet应用技巧(二十二) Ext4JSLint之JSON文件创建树控件



    引子

    Ext4JSLint是使用ExtAspNet来展示JSLint-Toolkit检查结果的开源项目。
    JSLint-Toolkit是一个使用Rhino和JSLint的开源项目,可以对一个文件夹中的所有JavaScript进行语法检查,并显示友好的检查结果。

    下面是JSLint-Toolkit生成的检查结果:

        [{
            "name": "source", 
            "type": "folder", 
            "kids": [
             {
              "name": "config.js", 
              "type": "file", 
              "errors": [0, 0, 0]
             }, 
             {
              "name": "lint.js", 
              "type": "file", 
              "errors": [3, 0, 3]
             }, 
             {
              "name": "main.js", 
              "type": "file", 
              "errors": [0, 0, 0]
             }, 
             {
              "name": "util.js", 
              "type": "file", 
              "errors": [0, 0, 0]
             }
            ], 
            "basePath": "scripts/source", 
            "fileCount": 4, 
            "errors": [3, 0, 3]
        }, 
        {
            "name": "jquery-1.3.2.js", 
            "type": "file", 
            "basePath": "scripts/jquery-1.3.2.js", 
            "errors": [51, 43, 8]
        }]
        


    这样一个JSON字符串其实描述了一个如下的文件结构:
        +scripts/source
         -config.js
         -lint.js
         -main.js
         -util.js
        -scripts/jquery-1.3.2.js
        

    特别注意的是,根节点多了一个属性basePath用来表示根路径。
    errors表示此JavaScript文件中的错误数(这是一个数组,第一个表示总数,第二个表示严重错误的个数)。

    页面效果:



    ASPX标签定义

        <ext:Tree runat="server" ID="Tree1" ShowBorder="false" ShowHeader="false" AutoScroll="true"
            EnableArrows="true" OnNodeCommand="Tree1_NodeCommand">
        </ext:Tree>
        


    标签定义非常简单,因为所有的逻辑都在后台实现了。
    同时定义了点击树节点的事件处理OnNodeCommand="Tree1_NodeCommand",因为我们要在点击树节点时更新中间的Grid,也即是当前JavaScript的错误列表。


    树与递归

    只要有树的地方就少不了递归函数,因此这段代码对于我们理解递归也很有帮助。

    首先看看页面初始化代码:
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                LoadData(true);
            }
        }
        #region LoadData
        private void LoadData(bool showAllErrors)
        {
            btnExpandAll.OnClientClick = Tree1.GetExpandAllNodesReference();
            btnCollapseAll.OnClientClick = Tree1.GetCollapseAllNodesReference();
    
            string treestr = GetFileContent("~/data/json/tree.json");
            List<string> treePathList = new List<string>();
            ResolveMenuTree(new JSONArray(treestr), treePathList, showAllErrors, Tree1.Nodes);
        }
        private string GetFileContent(string path)
        {
            string treestr = String.Empty;
            using (StreamReader sr = new StreamReader(Server.MapPath(path)))
            {
                treestr = sr.ReadToEnd();
            }
            return treestr;
        }
        private void ResolveMenuTree(JSONArray ja, List<string> treePathList, bool showAllErrors, ExtAspNet.TreeNodeCollection nodes)
        {
            // TODO 递归生成树
        }
        private string GetTreePath(List<string> treePath)
        {
            string path = String.Empty;
            foreach (string node in treePath)
            {
                path += node + "/";
            }
            return path.TrimEnd('/');
        }
        


    我们通过Nii.JSON这个开源类库(已经包含在ExtAspNet中),来将JSON字符串转换为JSONArray对象,以便在递归中使用:
        JSONArray ja = new JSONArray(treestr);
        



    递归生成树

    为了让大家看清问题的本质,我首先放出一个简单的递归,只完成基本功能:
        private void ResolveMenuTree2(JSONArray ja, List<string> treePathList, bool showAllErrors, ExtAspNet.TreeNodeCollection nodes)
        {
            for (int i = 0; i < ja.Count; i++)
            {
                JSONObject kid = ja[i] as JSONObject;
                string name = kid.getString("name");
                // 当前路径,如果basePath存在说明是根目录
                if (kid.has("basePath"))
                {
                    treePathList.Add(kid.getString("basePath"));
                }
                else
                {
                    treePathList.Add(name);
                }
                string currentPath = GetTreePath(treePathList);
    
                string type = kid.getString("type");
                // 如果文件夹中没有文件,则不添加此文件夹
                if (type == "folder" && kid.getInt("fileCount") == 0)
                {
                    treePathList.RemoveAt(treePathList.Count - 1);
                    continue;
                }
                ExtAspNet.TreeNode node = new ExtAspNet.TreeNode();
                nodes.Add(node);
                node.Text = name;
                node.Text = String.Format("<span qtip=\"{0}\">{1}</span>", currentPath, node.Text);
                if (type == "folder")
                {
                    node.SingleClickExpand = true;
                    ResolveMenuTree2(kid.getJSONArray("kids"), treePathList, showAllErrors, node.Nodes);
                }
                else
                {
                    node.Leaf = true;
                }
                treePathList.RemoveAt(treePathList.Count - 1);
            }
        }
        


    在这段代码中,我们通过treePathList来记录当前节点的路径,这也是一个关键点。

    此时生成的页面截图:



    完整的代码(根据错误设置节点颜色,同时为有错误的节点可回发):
        private void ResolveMenuTree(JSONArray ja, List<string> treePathList, bool showAllErrors, ExtAspNet.TreeNodeCollection nodes)
        {
            for (int i = 0; i < ja.Count; i++)
            {
                JSONObject kid = ja[i] as JSONObject;
                string name = kid.getString("name");
                // 当前路径,如果basePath存在说明是根目录
                if (kid.has("basePath"))
                {
                    treePathList.Add(kid.getString("basePath"));
                }
                else
                {
                    treePathList.Add(name);
                }
                string currentPath = GetTreePath(treePathList);
                // 获取JSLint错误数
                JSONArray errors = kid.getJSONArray("errors");
                int errorCount = errors.getInt(0);
                int criticalErrorCount = errors.getInt(1);
                if (showAllErrors)
                {
                    if (errorCount > 0)
                    {
                        name += String.Format(" ({0})", errorCount);
                    }
                }
                else
                {
                    if (criticalErrorCount > 0)
                    {
                        name += String.Format(" ({0})", criticalErrorCount);
                    }
                }
                string type = kid.getString("type");
                // 如果文件夹中没有文件,则不添加此文件夹
                if (type == "folder" && kid.getInt("fileCount") == 0)
                {
                    treePathList.RemoveAt(treePathList.Count - 1);
                    continue;
                }
                ExtAspNet.TreeNode node = new ExtAspNet.TreeNode();
                nodes.Add(node);
                node.Text = name;
                //node.ToolTip = currentPath;
                // 节点的显示颜色
                string style = "";
                if (showAllErrors)
                {
                    if (errorCount == 0)
                    {
                        style = "color:green;";
                    }
                    else
                    {
                        if (criticalErrorCount == 0)
                        {
                            style = "color:#FF9900;";
                        }
                        else
                        {
                            style = "color:#FF0000;";
                        }
                    }
                }
                else
                {
                    if (criticalErrorCount != 0)
                    {
                        style = "color:#FF0000;";
                    }
                    else
                    {
                        style = "color:green;";
                    }
                }
                node.Text = String.Format("<span qtip=\"{2}\" style=\"{0}\">{1}</span>", style, node.Text, currentPath);
    
                if (type == "folder")
                {
                    node.SingleClickExpand = true;
                    ResolveMenuTree(kid.getJSONArray("kids"), treePathList, showAllErrors, node.Nodes);
                }
                else
                {
                    node.Leaf = true;
                    if (showAllErrors)
                    {
                        if (errorCount != 0)
                        {
                            node.EnablePostBack = true;
                            node.CommandName = currentPath;
                        }
                    }
                    else
                    {
                        if (criticalErrorCount != 0)
                        {
                            node.EnablePostBack = true;
                            node.CommandName = currentPath;
                        }
                    }
                }
                treePathList.RemoveAt(treePathList.Count - 1);
            }
        }
        



    下一章将讲述如何点击左侧树节点时更新中间的Grid控件,并加载右侧的IFrame(即JavaScript文件的内容)。


    下载全部源代码

  • 相关阅读:
    spark
    mongdb
    redis
    mysql
    kylin
    kafka
    hadoop+hive+hbase+kylin
    git
    elasticsearch
    clickhouse
  • 原文地址:https://www.cnblogs.com/sanshi/p/1570173.html
Copyright © 2020-2023  润新知