Dojo中的事件处理

时间:2008-08-31 21:40:40

标签: javascript dojo

以Jeff Atwood的advice为例,我决定将JavaScript库用于我正在编写的基本待办事项列表应用程序。我选择了Dojo toolkit版本1.1.1。一开始,一切都很好:我写的拖放代码第一次工作,你可以在屏幕上拖动任务来改变他们的优先顺序,每次拖放操作调用一个发送AJAX的事件处理程序打电话给服务器让它知道订单已被更改。

然后我开始添加电子邮件跟踪功能。标准内容:新收到的电子邮件附有其主题行的唯一ID号,您可以通过在回复时将该ID号留在主题中来跟踪有关该问题的所有后续电子邮件。因此,我们有一个打开的任务列表,每个任务都有自己的ID号,每个任务都有一个按时间排序的关联电子邮件列表。我希望用户在查看任务列表时可以看到这些电子邮件的文本,因此我将每个任务框设置为Dijit“Tree”控件 - 顶级包含任务描述,分支包含电子邮件日期,以及每个分支的单个“叶子”包含电子邮件文本。

第一个问题:我希望默认情况下树视图完全折叠。在广泛搜索Google之后,我发现了许多解决方案,所有这些解决方案似乎对以前版本的Dojo都有效,但不是我使用的那个。我最终发现最好的解决方案似乎是在Tree控件加载时调用了一个事件处理程序,它只是折叠了每个分支/叶子。不幸的是,即使Tree控件已经被实例化并且其“启动”事件处理程序被调用,分支和叶子仍然没有被加载(数据仍然通过AJAX调用加载)。因此,我修改了系统,以便在服务器端添加所有电子邮件文本和树结构。这意味着当调用其启动事件处理程序时,整个完全填充的Tree控件可用。

因此,启动事件处理程序完全折叠树。接下来,我找不到一个“正确”的方式来为电子邮件留下好的格式化文本。我可以将电子邮件文本放在页面中,但任何HTML都会被转义并显示在网页中。提示更多关于Dojo文档的翻译(往往是过时的,包含1.0之前版本的代码和示例)和Google。我最终提出了获取JavaScript的解决方案,并读取每个叶节点内的SPAN元素,并在其innerHTML中解除转义的HTML代码。我想我会在Tree控件的启动事件处理程序中使用完全崩溃树代码来执行此操作。

然而......事实证明,在用户点击expando之前,实际上并未创建SPAN元素(单击树视图中的小“+”符号以展开节点)。好吧,公平 - 我将重新格式化的代码添加到onExpand()事件处理程序,或者其他任何调用。这似乎不存在。我搜索了文档,我搜索过Google ...我很可能误解了Dojo的“发布/订阅”事件处理系统,但我认为主要是因为似乎没有任何全面的文档它在任何地方(比如,我在哪里可以找到我可以订阅的事件?)。

所以,最后,我能想到的最好的解决方案是将onClick事件处理程序(不是“Dojo”事件,但Dojo一无所知的普通JavaScript事件)添加到每个树的expando节点在每个叶子的SPAN元素内重新格式化HTML的分支。除了......当调用它时,SPAN元素仍然不存在(有时 - 其他时候它被缓存,只是为了进一步混淆你)。因此,我让事件处理程序设置了一个计时器,该计时器定期调用一个函数,该函数在重新格式化之前检查相关的SPAN元素是否已经出现。

// An event handler called whenever a "email title" tree node is expanded.
function formatTreeNode(nodeID) {
    if (dijit.byId(nodeID).getChildren().length != 0) {
        clearInterval(nodeUpdateIntervalID);
        messageBody = dijit.byId(nodeID).getChildren()[0].labelNode.innerHTML
        if (messageBody.indexOf("<b>Message text:</b>") == -1) {
            messageBody = messageBody.replace(/&gt;/g, ">");
            messageBody = messageBody.replace(/&lt;/g, "<");
            messageBody = messageBody.replace(/&amp;/g, "&");
            dijit.byId(nodeID).getChildren()[0].labelNode.innerHTML = "<b>Message text:</b><div style=\"font-family:courier\">"+messageBody+"</div>";
        }
    }
}

// An event handler called when a tree node has been set up - we changed the default fully-expanded to fully-collapsed.
function setupTree(theTree) {
    dijit.byId("tree-"+theTree).rootNode.collapse();

    messageNode = dijit.byId("tree-"+theTree).rootNode.getChildren();
    for (pl = 0; pl < messageNode.length; pl++) {
        messageNode[pl].collapse();
        messageNode[pl].expandoNode.onclick = eval("nodeUpdateIntervalID = setInterval(\"formatTreeNode('"+messageNode[pl].id+"')\",200); formatTreeNode('"+messageNode[pl].id+"');");
    }
}

上面有一种真正可怕的黑客的感觉,我确信在我的思考过程中,我必须在某个地方错误地转向。有人可以告诉我:

  • 将正确格式的文本放入Dojo / Dijit Tree控件中的正确方法。
  • 处理Dojo事件的正确方法,例如我可以找出可供我订阅的事件。
  • 一个更好的JavaScript库(我可以用JQuery做我想做的事情,避免上面看到的全方位办法吗?)。
PS:如果您正在命名一个软件项目,请考虑其名称在Google中的独特性 - 我确信在没有所有武术结果阻碍的情况下,在Google中搜索“Dojo”文档会更容易。< / p>

PPS:Firefox拼写检查器知道如何拼写“Atwood”,在我放两个'T而不是一个'时纠正我。杰夫现在才出名吗?

1 个答案:

答案 0 :(得分:3)

我假设您按照dijit.Tree and dojo.data in Dojo 1.1指导您使用数据存储将数据传递到树控件的教程。那让我敲了一下砖墙一段时间。

它并不是一个很好的方法,替代方案并没有真正记录完备。您需要创建一个使用模型。我在下面列举了一个示例,我创建了一个用于显示LDAP目录结构的树模型。

您将在./dijit/_tree/model.js的dojo发行版中找到该模型的默认实现。注释应该有助于您了解模型支持的功能。

IDirectoryService类下面的代码是由Direct Web Remoting(DWR)生成的服务器端Java POJO的存根。如果您要进行大量的客户端 - 服务器交互,我强烈推荐DWR。

dojo.declare("LDAPDirectoryTreeModel", [ dijit.tree.model ], {
    getRoot : function(onItem) {
        IDirectoryService.getRoots( function(roots) {
            onItem(roots[0])
        });
    },

    mayHaveChildren : function(item) {
        return true;
    },

    getChildren : function(parentItem, onComplete) {
        IDirectoryService.getChildrenImpl(parentItem, onComplete);
    },

    getIdentity : function(item) {
        return item.dn;
    },

    getLabel : function(item) {
        return item.rdn;
    }
});

这是我的JSP页面的摘录,我在其中创建了模型并使用它来填充树控件。

<div
  dojoType="LDAPDirectoryTreeModel"
  jsid="treeModel"
  id="treeModel">
</div>
<div
  jsid="tree"
  id="tree"
  dojoType="dijit.Tree" model="treeModel"
  labelAttr="name"
  label="${directory.host}:${directory.port}">
</div>