]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 251656: Redesign dependency tree, part 1: fix the tree itself - Patch by André...
authorlpsolit%gmail.com <>
Thu, 23 Feb 2006 06:02:07 +0000 (06:02 +0000)
committerlpsolit%gmail.com <>
Thu, 23 Feb 2006 06:02:07 +0000 (06:02 +0000)
js/expanding-tree.js [new file with mode: 0644]
showdependencytree.cgi
skins/standard/dependency-tree.css [new file with mode: 0644]
template/en/default/bug/dependency-tree.html.tmpl
template/en/default/filterexceptions.pl

diff --git a/js/expanding-tree.js b/js/expanding-tree.js
new file mode 100644 (file)
index 0000000..d210a62
--- /dev/null
@@ -0,0 +1,157 @@
+/* The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Bugzilla Bug Tracking System.
+ * 
+ * The Initial Developer of the Original Code is Netscape Communications
+ * Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All
+ * Rights Reserved.
+ * 
+ * Contributor(s): Mike Shaver <shaver@mozilla.org>
+ *                 Christian Reis <kiko@async.com.br>
+ *                 André Batosti <batosti@async.com.br> 
+ */
+
+if (!Node) {
+    // MSIE doesn't define Node, so provide a compatibility object
+    var Node = { TEXT_NODE: 3 }
+}
+
+if (!highlighted) {
+    var highlighted = 0;
+    var highlightedclass = "";
+    var highlightedover = 0;
+}
+
+function doToggle(node, event) {
+    var deep = event.altKey || event.ctrlKey;
+
+    if (node.nodeType == Node.TEXT_NODE)
+        node = node.parentNode;
+
+    var toggle = node.nextSibling;
+    while (toggle && toggle.tagName != "UL")
+        toggle = toggle.nextSibling;
+
+    if (toggle) {
+        if (deep) {
+            var direction = toggleDisplay(toggle, node);
+            changeChildren(toggle, direction);
+        } else {
+            toggleDisplay(toggle, node);
+        }
+    }
+    /* avoid problems with default actions on links (mozilla's
+     * ctrl/shift-click defaults, for instance */
+    event.preventBubble();
+    event.preventDefault();
+    return false;
+}
+
+function changeChildren(node, direction) {
+    var item = node.firstChild;
+    while (item) {
+        /* find the LI inside the UL I got */
+        while (item && item.tagName != "LI")
+            item = item.nextSibling;
+        if (!item)
+            return;
+
+        /* got it, now find the first A */
+        var child = item.firstChild;
+        while (child && child.tagName != "A")
+            child = child.nextSibling;
+        if (!child) {
+            return
+        }
+        var bullet = child;
+
+        /* and check if it has its own sublist */
+        var sublist = item.firstChild;
+        while (sublist && sublist.tagName != "UL")
+            sublist = sublist.nextSibling;
+        if (sublist) {
+            if (direction && isClosed(sublist)) {
+                openNode(sublist, bullet);
+            } else if (!direction && !isClosed(sublist)) {
+                closeNode(sublist, bullet);
+            }
+            changeChildren(sublist, direction)
+        }
+        item = item.nextSibling;
+    }
+}
+
+function openNode(node, bullet) {
+    node.style.display = "block";
+    bullet.className = "b b_open";
+}
+
+function closeNode(node, bullet) {
+    node.style.display = "none";
+    bullet.className = "b b_closed";
+}
+
+function isClosed(node) {
+    /* XXX we should in fact check our *computed* style, not the display
+     * attribute of the current node, which may be inherited and not
+     * set. However, this really only matters when changing the default
+     * appearance of the tree through a parent style. */
+    return node.style.display == "none";
+}
+
+function toggleDisplay(node, bullet) {
+    if (isClosed(node)) {
+        openNode(node, bullet);
+        return true;
+    }
+
+    closeNode(node, bullet);
+    return false;
+}
+
+function duplicated(element) {
+    var allsumm= document.getElementsByTagName("span");
+    if (highlighted) {
+        for (i = 0;i < allsumm.length; i++) {
+            if (allsumm.item(i).id == highlighted) {
+                allsumm.item(i).className = highlightedclass;
+            }
+        }
+        if (highlighted == element) {
+            highlighted = 0;
+            return;
+        }
+    } 
+    highlighted = element;
+    var elem = document.getElementById(element);
+    highlightedclass = elem.className;
+    for (var i = 0;i < allsumm.length; i++) {
+        if (allsumm.item(i).id == element) {
+            allsumm.item(i).className = "summ_h";
+        }
+    }
+}
+
+function duplicatedover(element) {
+    if (!highlighted) {
+        highlightedover = 1;
+        duplicated(element);
+    }
+}
+
+function duplicatedout(element) {
+    if (highlighted == element && highlightedover) {
+        highlightedover = 0;
+        duplicated(element);
+    }
+}
+
index 03abb272993b3fba6401ba03719ff169d60fc04a..efc26a2b216a8218025145ca76e4c338aa60e175 100755 (executable)
@@ -65,7 +65,7 @@ if ($maxdepth !~ /^\d+$/) { $maxdepth = 0 };
 # have to embed a conditional statement into each query.
 my $milestone_column = Param('usetargetmilestone') ? "target_milestone" : "''";
 
-# The greatest depth to which either tree goes.
+# Stores the greatest depth to which either tree goes.
 my $realdepth = 0;
 
 # Generate the tree of bugs that this bug depends on and a list of IDs
@@ -148,12 +148,14 @@ sub GetBug {
     if (Bugzilla->user->can_see_bug($id)) {
         ($bug->{'exists'},
          $bug->{'status'},
+         $bug->{'resolution'},
          $bug->{'summary'},
          $bug->{'milestone'},
          $bug->{'assignee_id'},
          $bug->{'assignee_email'}) = $dbh->selectrow_array(
                 "SELECT 1,
                         bug_status, 
+                        resolution,
                         short_desc, 
                         $milestone_column, 
                         assignee.userid, 
diff --git a/skins/standard/dependency-tree.css b/skins/standard/dependency-tree.css
new file mode 100644 (file)
index 0000000..859ea19
--- /dev/null
@@ -0,0 +1,90 @@
+/* The contents of this file are subject to the Mozilla Public
+  * License Version 1.1 (the "License"); you may not use this file
+  * except in compliance with the License. You may obtain a copy of
+  * the License at http://www.mozilla.org/MPL/
+  *
+  * Software distributed under the License is distributed on an "AS
+  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  * implied. See the License for the specific language governing
+  * rights and limitations under the License.
+  *
+  * The Original Code is the Bugzilla Bug Tracking System.
+  *
+  * The Initial Developer of the Original Code is Netscape
+  * Communications
+  * Corporation. Portions created by Netscape are
+  * Copyright (C) 1998 Netscape Communications Corporation. All
+  * Rights Reserved.
+  *
+  * Contributor(s): Christian Reis <kiko@async.com.br>
+  *                 André Batosti <batosti@async.com.br>
+  */
+
+ul.tree {
+    padding-left: 0em;
+    margin-left: 1em;
+    display: block;
+}
+
+ul.tree ul {
+    padding-top: 3px;
+    display: block;
+}
+
+ul.tree li { 
+    /* see http://www.kryogenix.org/code/browser/aqlists/ for idea */
+    padding-top: 3px; 
+    text-indent: -1.2em; 
+    padding-left: 0.5em; 
+    padding-bottom: 3px;
+    list-style-type: none;
+    background: url("dependency-tree/bug-item.png") no-repeat;
+}
+
+ul.tree li a.b {
+    padding-left: 30px; 
+    margin-right: -14px; 
+    text-decoration: none;
+}
+
+ul.tree li a.b_open {
+    background: url("dependency-tree/tree-open.png") center no-repeat;
+    cursor: pointer;
+}
+
+ul.tree li a.b_closed {
+    background: url("dependency-tree/tree-closed.png") center no-repeat;
+    cursor: pointer;
+}
+
+.summ_info {
+    /* change to inline if you would like to see the full bug details
+     * displayed in the list */
+    display: none; 
+    font-size: 75%;
+}
+
+.hint {
+    font-size: 90%;
+    margin: 0.2em;
+    padding: 0.1em;
+}
+
+.hint h3, .hint ul {
+    margin-top: 0.1em;
+    margin-bottom: 0.1em;
+}
+
+.summ A, .summ_deep A {
+    text-decoration: none;
+    color: darkblue;
+}
+
+.summ_deep {
+}
+
+.summ_h A {
+    background-color: #ffffaa;
+    color: #333;
+    text-decoration: underline bold;
+}
index 8b5ecd59c31c84fe5fdbfcfca1ed69a280639bfb..8fd0c18e6fc29763b0492a63842f1c8568d1c2d0 100644 (file)
@@ -19,6 +19,7 @@
   # Contributor(s): Tobias Burnus <burnus@net-b.de>
   #                 Ville Skyttä <ville.skytta@iki.fi>
   #                 Myk Melez <myk@mozilla.org>
+  #                 André Batosti <batosti@async.com.br>
   #%]
 
 [% PROCESS global/variables.none.tmpl %]
 [% filtered_desc = blocked_tree.$bugid.summary FILTER html %]
 [% PROCESS global/header.html.tmpl
    title = "Dependency tree for $terms.Bug $bugid"
-   h1    = "Dependency tree for <a href=\"show_bug.cgi?id=$bugid\">$terms.Bug $bugid</a>"
+   h1    = "Dependency tree for 
+            <a href=\"show_bug.cgi?id=$bugid\">$terms.Bug $bugid</a>"
+   javascript_urls = ["js/expanding-tree.js"]
+   style_urls = ["skins/standard/dependency-tree.css"]
    h2    = filtered_desc
 %]
 
 [% PROCESS depthControlToolbar %]
-
-[%# Display the tree of bugs that this bug depends on. %]
-<h3>
-  [% IF hide_resolved %]
-    Open [% terms.bugs %]
-  [% ELSE %]
-    [% terms.Bugs %]
-  [% END %] 
-  that <a href="show_bug.cgi?id=[% bugid %]">[% terms.bug %] [%+ bugid %]</a> 
-  depends on</h3>
-[% IF dependson_ids.size > 0 %]
-  (
-  [% IF maxdepth -%]Up to [% maxdepth %] level[% "s" IF maxdepth > 1 %] deep | [% END %]
-  <a href="buglist.cgi?bug_id=[% dependson_ids.join(",") %]">view as [% terms.bug %] list</a>
-  [% IF canedit && dependson_ids.size > 1 %]
-    | <a href="buglist.cgi?bug_id=[% dependson_ids.join(",") %]&amp;tweak=1">change several</a>
-  [% END %])
-  [% INCLUDE display_tree tree=dependson_tree bug_id=bugid %]
-[% ELSE %]
-  </h3>
-  <p>None</p>
-[% END %]
-
-[%# Display the tree of bugs that this bug blocks. %]
-<h3>
-  [% IF hide_resolved %]
-    Open [% terms.bugs %]
-  [% ELSE %]
-    [% terms.Bugs %]
-  [% END %] 
-  that <a href="show_bug.cgi?id=[% bugid %]">[% terms.bug %] [%+ bugid %]</a> 
-  blocks</h3>
-[% IF blocked_ids.size > 0 %]
-  (
-  [% IF maxdepth -%]Up to [% maxdepth %] level[% "s" IF maxdepth > 1 %] deep | [% END %]
-  <a href="buglist.cgi?bug_id=[% blocked_ids.join(",") %]">view as [% terms.bug %] list</a>
-  [% IF canedit && blocked_ids.size > 1 %]
-    | <a href="buglist.cgi?bug_id=[% blocked_ids.join(",") %]&amp;tweak=1">change several</a>
-  [% END %])
-  [% INCLUDE display_tree tree=blocked_tree bug_id=bugid %]
-[% ELSE %]
-  </h3>
-  <p>None</p>
-[% END %]
+  
+[% INCLUDE tree_section ids=dependson_ids type=1 %]
+[% INCLUDE tree_section ids=blocked_ids type=2 %] 
 
 [% PROCESS depthControlToolbar %]
 
+[% PROCESS global/footer.html.tmpl %]
+
 [%###########################################################################%]
-[%# Block to display a tree                                                 #%]
+[%# Tree-drawing blocks                                                     #%]
 [%###########################################################################%]
 
+[% BLOCK tree_section %]
+  [%# INTERFACE
+    #   - ids: a list of bug IDs to be displayed as children
+    #   - type: the type of tree. 1 = depends on, 2 = blockeds
+    # GLOBALS
+    #   - seen: Maintains a global hash of bugs that have been displayed
+    #%]
+  [% global.seen = {} %]
+  [%# Display the tree of bugs that this bug depends on. %]
+  <h3>
+    [% ids.size %] 
+    [% IF hide_resolved %]
+      Open [% terms.bugs %]
+    [% ELSE %]
+      [% terms.Bugs %]
+    [%- END %] 
+    that <a href="show_bug.cgi?id=[% bugid %]">[% terms.bug %] [%+ bugid %]</a> 
+    [% IF type == 1 %]
+        [% tree_name = "dependson_tree" %]
+        depends on
+    [% ELSIF type == 2 %]
+        [% tree_name = "blocked_tree" %]
+        blocks
+    [% END %]
+  </h3>
+  [% IF ids.size > 0 %]
+    ([% IF maxdepth -%]Up to [% maxdepth %] level[% "s" IF maxdepth > 1 %] deep | [% END -%]
+    <a href="buglist.cgi?bug_id=[% ids.join(",") %]">view as [% terms.bug %] list</a>
+    [% IF canedit && ids.size > 1 %]
+      | <a href="buglist.cgi?bug_id=[% ids.join(",") %]&amp;tweak=1">change several</a>
+    [% END %])
+    <ul class="tree">
+      [% INCLUDE display_tree tree=$tree_name %]
+    </ul>
+    <p>
+  [% ELSE %]
+    <p>None</p>
+  [% END %]
+[% END %]
+
+
 [% BLOCK display_tree %]
-[% tree.$bug_id.seen = 1 %]
-<ul>
-  [% FOREACH dep_id = tree.$bug_id.dependencies %]
-    [% dep = tree.$dep_id %]
-    <li>
-      [% "<script>document.write('<a href=\"#\" class=\"toggle\" onclick=\"listToggle(event); return false\">[-]</a>')</script>"
-         IF dep.dependencies.size > 0 && !dep.seen %]
-      [% isclosed = !dep.open %]
-      [% FILTER closed(isclosed) %]
-      <a href="show_bug.cgi?id=[% dep_id %]">[% dep_id %]
-        [[% IF dep.milestone %][% dep.milestone FILTER html %], [% END %]
-        [% dep.assignee_email FILTER html %]] -
-        [% IF dep.seen %]
-          <i>This [% terms.bug %] appears elsewhere in this tree.</i></a>
-        [% ELSE %]
-          [%+ dep.summary FILTER html %].</a>
+  [%# INTERFACE
+    #   - bugid: the ID of the bug being displayed
+    #   - tree: a hash of bug objects
+    #%]
+  [% bug = tree.$bugid %]
+  <li>
+    [%- INCLUDE bullet bugid=bugid bug=bug -%]
+    <span class="summ[% "_deep" IF bug.dependencies.size %]" 
+          id="[% bugid FILTER html %]" 
+          [% IF global.seen.$bugid %]
+            onMouseover="duplicatedover('[% bugid FILTER html %]')"
+            onMouseout="duplicatedout('[% bugid FILTER html %]')"
+          [% END %]>
+      [%- INCLUDE buglink bug=bug bugid=bugid %]
+    </span>
+    [% IF global.seen.$bugid %]
+      <b><a title="Already displayed above; click to locate"
+            onclick="duplicated('[% bugid FILTER html %]')"
+            href="#b[% bugid %]">(*)</a></b>
+    [% ELSIF bug.dependencies.size %]
+      <ul>
+        [% FOREACH depid = bug.dependencies %]
+          [% INCLUDE display_tree bugid=depid %]
         [% END %]
-      [% END %]
-      [% INCLUDE display_tree bug_id=dep_id
-           IF dep.dependencies.size > 0 && !dep.seen %]
-    </li>
+      </ul>
+    [% END %]
+  </li>
+  [% global.seen.$bugid = 1 %]
+[% END %]
+
+[% BLOCK bullet %]
+  [% IF bug.dependencies.size > 0 && ! global.seen.$bugid %]
+    [% extra_class = " b_open" %]
+    [% extra_args = 'onclick="return doToggle(this, event)"' %] 
   [% END %]
-</ul>
+  <a name="b[% bugid %]" 
+     class="b [%+ extra_class FILTER none %]"
+     title="Click to expand or contract this portion of the tree. Hold down the Ctrl key while clicking to expand or contract all subtrees."
+     [% extra_args FILTER none %]>&nbsp;&nbsp;</a>
 [% END %]
 
-<script type="text/javascript">
-if (typeof Node == 'undefined') {
-    /* MSIE doesn't define Node, so provide a compatibility object */
-    window.Node = {
-        TEXT_NODE: 3
-    };
-}
-
-function toggleDisplay(node)
-{
-    var display = node.style.display;
-    if (display == "none") {
-        node.style.display =
-            ("oldDisplay" in node) ? node.oldDisplay : "block";
-        return true;
-    }
-
-    node.oldDisplay = display;
-    node.style.display = "none";
-    return false;
-}
-
-function listToggle(event)
-{
-    var node = event.target;
-    if (!node)
-       node = event.srcElement;
-    if (node.nodeType == Node.TEXT_NODE)
-        node = node.parentNode;
-    var toggle = node.nextSibling;
-    while (toggle && toggle.tagName != "UL")
-        toggle = toggle.nextSibling;
-    if (toggle) {
-        node.firstChild.data = toggleDisplay(toggle) ? "[-]" : "[+]";
-    }
-}
-
-</script>
+[% BLOCK buglink %]
+  [% isclosed = !bug.open %]
+  [% FILTER closed(isclosed) -%]
+    <a title="[% INCLUDE buginfo bug=bug %]"
+       href="show_bug.cgi?id=[% bugid %]">
+      <b>[%- bugid %]:</b>
+      <span class="summ_text">[%+ bug.summary FILTER html %]</span>
+      <span class="summ_info">[[% INCLUDE buginfo %]]</span>
+    </a>
+  [% END %]
+[% END %]
 
-[% PROCESS global/footer.html.tmpl %]
+[% BLOCK buginfo %]
+  [% bug.status FILTER html %]
+  [%+ bug.resolution FILTER html %]; assigned to [% bug.assignee_email FILTER html %]; 
+  [% "Target: " _ bug.milestone IF bug.milestone %]
+[% END %]
 
 [%###########################################################################%]
 [%# Block for depth control toolbar                                         #%]
 [%###########################################################################%]
 
 [% BLOCK depthControlToolbar %]
- <table cellpadding="3" border="0" cellspacing="0" bgcolor="#d0d0d0">
- <tr>
+ <table cellpadding="3" border="0" cellspacing="0" bgcolor="#e0e0e0">
  <tr>
    [%# Hide/show resolved button
        Swaps text depending on the state of hide_resolved %]
    <td align="center">
index 57a323e7ff9376f0bf6214e7e2189e73d38ddd5f..dbc618ee638e9a949a5c94232e923a6c246177f1 100644 (file)
 'bug/dependency-tree.html.tmpl' => [
   'bugid', 
   'maxdepth', 
-  'dependson_ids.join(",")', 
-  'blocked_ids.join(",")', 
-  'dep_id', 
   'hide_resolved', 
+  'ids.join(",")',
   'maxdepth + 1', 
   'maxdepth > 0 && maxdepth <= realdepth ? maxdepth : ""',
   'maxdepth == 1 ? 1