/    Sign up×
Community /Pin to ProfileBookmark

Menu Script "dtree" – How can I "expand tree" AND "go to URL" with just one click?

Hi all,

I have a menu script called “dtree” written by Geir Landrö that I am attempting to alter. A demo of the original script is available here:

DEMO: [URL=”http://www.destroydrop.com/javascripts/tree/example/”]http://www.destroydrop.com/javascripts/tree/example/[/URL]

API: [URL=”http://www.destroydrop.com/javascripts/tree/api/”]http://www.destroydrop.com/javascripts/tree/api/[/URL]

MORE INFO: [URL=”http://www.destroydrop.com/javascripts/tree/”]http://www.destroydrop.com/javascripts/tree/[/URL]

What I want to do with “dtree” is the following:

With just one click, on either the node icon (which looks like a “+” or “-” symbol) OR by clicking on the category title, I would like the script to perform two functions:

  • 1. Expand that branch of the tree to the next level down (while closing any other open branches.)
  • AND

  • 2. Also go to the URL associated with the category title (next to the node icon.)
  • ( Currently, clicking on the “+/-” node only performs no. 1, and clicking on the category title only performs no. 2. I would like both to do both!

    Is this possible?

    My current configuration in dtree.js:

    target : null,
    folderLinks : true,
    useSelection : true,
    useCookies : true,
    useLines : true,
    useIcons : false,
    useStatusText : false,
    closeSameLevel : true,
    inOrder : false,

    Regards,

    Nic

    [URL=”NicMason.com”]http://www.NicMason.com[/URL]

    contact – (-at-) – nicmason – (-dot-) – com

    to post a comment
    JavaScript

    7 Comments(s)

    Copy linkTweet thisAlerts:
    @ricpApr 06.2007 — You know it's strange but the suggestion I have is to email the author of the original script and ask him (or her) how amendments should be made rather than putting the question on an open forum where it's likely nobody will have seen, let alone used, this script before.
    Copy linkTweet thisAlerts:
    @NicMason_comauthorApr 06.2007 — Hi ricp,

    That's the first thing I did. Several days ago. But, have yet to receive a response.

    If someone would care to take a look, I would be most grateful.

    For an experienced Javascript programmer, it may be a very simple thing to solve.

    Cheers!

    Nic
    Copy linkTweet thisAlerts:
    @NicMason_comauthorApr 06.2007 — Here is the code (split into two parts due to this forum's restrictions on post length):

    [CODE]/*--------------------------------------------------|

    | dTree 2.05 | www.destroydrop.com/javascript/tree/ |

    |---------------------------------------------------|

    | Copyright (c) 2002-2003 Geir Landr? |

    | |

    | This script can be used freely as long as all |

    | copyright messages are intact. |

    | |

    | Updated: 17.04.2003 |

    |--------------------------------------------------*/



    // Node object

    function Node(id, pid, name, url, title, target, icon, iconOpen, open) {

    this.id = id;

    this.pid = pid;

    this.name = name;

    this.url = url;

    this.title = title;

    this.target = target;

    this.icon = icon;

    this.iconOpen = iconOpen;

    this._io = open || false;

    this._is = false;

    this._ls = false;

    this._hc = false;

    this._ai = 0;

    this._p;

    };



    // Tree object

    function dTree(objName) {

    this.config = {

    target : null,

    folderLinks : true,

    useSelection : true,

    useCookies : true,

    useLines : true,

    useIcons : false,

    useStatusText : false,

    closeSameLevel : true,

    inOrder : false,

    domain : '',

    path : ''

    }

    this.icon = {

    root : '/components/com_sobi2/images/base.gif',

    folder : '/components/com_sobi2/images/folder.gif',

    folderOpen : '/components/com_sobi2/images/folderopen.gif',

    node : '/components/com_sobi2/images/page.gif',

    empty : '/components/com_sobi2/images/empty.gif',

    line : '/components/com_sobi2/images/line.gif',

    join : '/components/com_sobi2/images/join.gif',

    joinBottom : '/components/com_sobi2/images/joinbottom.gif',

    plus : '/components/com_sobi2/images/plus.gif',

    plusBottom : '/components/com_sobi2/images/plusbottom.gif',

    minus : '/components/com_sobi2/images/minus.gif',

    minusBottom : '/components/com_sobi2/images/minusbottom.gif',

    nlPlus : '/components/com_sobi2/images/nolines_plus.gif',

    nlMinus : '/components/com_sobi2/images/nolines_minus.gif'

    };

    this.obj = objName;

    this.aNodes = [];

    this.aIndent = [];

    this.root = new Node(-1);

    this.selectedNode = null;

    this.selectedFound = false;

    this.completed = false;

    };



    // Adds a new node to the node array

    dTree.prototype.add = function(id, pid, name, url, title, target, icon, iconOpen, open) {

    this.aNodes[this.aNodes.length] = new Node(id, pid, name, url, title, target, icon, iconOpen, open);

    };



    // Open/close all nodes

    dTree.prototype.openAll = function() {

    this.oAll(true);

    };



    dTree.prototype.closeAll = function() {

    this.oAll(false);

    };





    // Outputs the tree to the page

    dTree.prototype.toString = function() {

    var str = '<div class="dtree">n';

    if (document.getElementById) {

    if (this.config.useCookies) this.selectedNode = this.getSelected();

    str += this.addNode(this.root);

    } else str += 'Browser not supported.';

    str += '</div>';

    if (!this.selectedFound) this.selectedNode = null;

    this.completed = true;

    return str;

    };



    // Creates the tree structure

    dTree.prototype.addNode = function(pNode) {

    var str = '';

    var n=0;

    if (this.config.inOrder) n = pNode._ai;

    for (n; n<this.aNodes.length; n++) {

    if (this.aNodes[n].pid == pNode.id) {

    var cn = this.aNodes[n];

    cn._p = pNode;

    cn._ai = n;

    this.setCS(cn);

    if (!cn.target && this.config.target) cn.target = this.config.target;

    if (cn._hc && !cn._io && this.config.useCookies) cn._io = this.isOpen(cn.id);

    if (!this.config.folderLinks && cn._hc) cn.url = null;

    if (this.config.useSelection && cn.id == this.selectedNode && !this.selectedFound) {

    cn._is = true;

    this.selectedNode = n;

    this.selectedFound = true;

    }

    str += this.node(cn, n);

    if (cn._ls) break;

    }

    }

    return str;

    };



    // Creates the node icon, url and text

    dTree.prototype.node = function(node, nodeId) {

    var str = '<div class="dTreeNode">' + this.indent(node, nodeId);

    if (this.config.useIcons) {

    if (!node.icon) node.icon = (this.root.id == node.pid) ? this.icon.root : ((node._hc) ? this.icon.folder : this.icon.node);

    if (!node.iconOpen) node.iconOpen = (node._hc) ? this.icon.folderOpen : this.icon.node;

    if (this.root.id == node.pid) {

    node.icon = this.icon.root;

    node.iconOpen = this.icon.root;

    }

    str += '<img id="i' + this.obj + nodeId + '" src="' + ((node._io) ? node.iconOpen : node.icon) + '" alt="" />';

    }

    if (node.url) {

    str += '<a id="s' + this.obj + nodeId + '" class="' + ((this.config.useSelection) ? ((node._is ? 'nodeSel' : 'node')) : 'node') + '" href="' + node.url + '"';

    if (node.title) str += ' title="' + node.title + '"';

    if (node.target) str += ' target="' + node.target + '"';

    if (this.config.useStatusText) str += ' onmouseover="window.status='' + node.name + '';return true;" onmouseout="window.status='';return true;" ';

    if (this.config.useSelection && ((node._hc && this.config.folderLinks) || !node._hc))

    str += ' onclick="javascript: ' + this.obj + '.s(' + nodeId + ');"';

    str += '>';

    }

    else if ((!this.config.folderLinks || !node.url) && node._hc && node.pid != this.root.id)

    str += '<a href="javascript: ' + this.obj + '.o(' + nodeId + ');" class="node">';

    str += node.name;

    if (node.url || ((!this.config.folderLinks || !node.url) && node._hc)) str += '</a>';

    str += '</div>';

    if (node._hc) {

    str += '<div id="d' + this.obj + nodeId + '" class="clip" style="display:' + ((this.root.id == node.pid || node._io) ? 'block' : 'none') + ';">';

    str += this.addNode(node);

    str += '</div>';

    }

    this.aIndent.pop();

    return str;

    };



    // Adds the empty and line icons

    dTree.prototype.indent = function(node, nodeId) {

    var str = '';

    if (this.root.id != node.pid) {

    for (var n=0; n<this.aIndent.length; n++)

    str += '<img src="' + ( (this.aIndent[n] == 1 && this.config.useLines) ? this.icon.line : this.icon.empty ) + '" alt="" />';

    (node._ls) ? this.aIndent.push(0) : this.aIndent.push(1);

    if (node._hc) {

    str += '<a href="javascript: ' + this.obj + '.o(' + nodeId + ');"><img id="j' + this.obj + nodeId + '" border="0" src="';

    if (!this.config.useLines) str += (node._io) ? this.icon.nlMinus : this.icon.nlPlus;

    else str += ( (node._io) ? ((node._ls && this.config.useLines) ? this.icon.minusBottom : this.icon.minus) : ((node._ls && this.config.useLines) ? this.icon.plusBottom : this.icon.plus ) );

    str += '" alt="" /></a>';

    } else str += '<img src="' + ( (this.config.useLines) ? ((node._ls) ? this.icon.joinBottom : this.icon.join ) : this.icon.empty) + '" alt="" />';

    }

    return str;

    };



    // Checks if a node has any children and if it is the last sibling

    dTree.prototype.setCS = function(node) {

    var lastId;

    for (var n=0; n<this.aNodes.length; n++) {

    if (this.aNodes[n].pid == node.id) node._hc = true;

    if (this.aNodes[n].pid == node.pid) lastId = this.aNodes[n].id;

    }

    if (lastId==node.id) node._ls = true;

    };



    // Returns the selected node

    dTree.prototype.getSelected = function() {

    var sn = this.getCookie('cs' + this.obj);

    return (sn) ? sn : null;

    };



    // Highlights the selected node

    dTree.prototype.s = function(id) {

    if (!this.config.useSelection) return;

    var cn = this.aNodes[id];

    if (cn._hc && !this.config.folderLinks) return;

    if (this.selectedNode != id) {

    if (this.selectedNode || this.selectedNode==0) {

    eOld = document.getElementById("s" + this.obj + this.selectedNode);

    eOld.className = "node";

    }

    eNew = document.getElementById("s" + this.obj + id);

    eNew.className = "nodeSel";

    this.selectedNode = id;

    if (this.config.useCookies) this.setCookie('cs' + this.obj, cn.id, null, this.config.path, this.config.domain);

    }

    };


    [/CODE]
    Copy linkTweet thisAlerts:
    @NicMason_comauthorApr 06.2007 — Code PART 2:[CODE]
    // Toggle Open or close

    dTree.prototype.o = function(id) {

    var cn = this.aNodes[id];

    this.nodeStatus(!cn._io, id, cn._ls);

    cn._io = !cn._io;

    if (this.config.closeSameLevel) this.closeLevel(cn);

    if (this.config.useCookies) this.updateCookie();

    };



    // Open or close all nodes

    dTree.prototype.oAll = function(status) {

    for (var n=0; n<this.aNodes.length; n++) {

    if (this.aNodes[n]._hc && this.aNodes[n].pid != this.root.id) {

    this.nodeStatus(status, n, this.aNodes[n]._ls)

    this.aNodes[n]._io = status;

    }

    }

    if (this.config.useCookies) this.updateCookie();

    };



    // Opens the tree to a specific node

    dTree.prototype.openTo = function(nId, bSelect, bFirst) {

    if (!bFirst) {

    for (var n=0; n<this.aNodes.length; n++) {

    if (this.aNodes[n].id == nId) {

    nId=n;

    break;

    }

    }

    }

    var cn=this.aNodes[nId];

    if (cn.pid==this.root.id || !cn._p) return;

    cn._io = true;

    cn._is = bSelect;

    if (this.completed && cn._hc) this.nodeStatus(true, cn._ai, cn._ls);

    if (this.completed && bSelect) this.s(cn._ai);

    else if (bSelect) this._sn=cn._ai;

    this.openTo(cn._p._ai, false, true);

    };



    // Closes all nodes on the same level as certain node

    dTree.prototype.closeLevel = function(node) {

    for (var n=0; n<this.aNodes.length; n++) {

    if (this.aNodes[n].pid == node.pid && this.aNodes[n].id != node.id && this.aNodes[n]._hc) {

    this.nodeStatus(false, n, this.aNodes[n]._ls);

    this.aNodes[n]._io = false;

    this.closeAllChildren(this.aNodes[n]);

    }

    }

    }



    // Closes all children of a node

    dTree.prototype.closeAllChildren = function(node) {

    for (var n=0; n<this.aNodes.length; n++) {

    if (this.aNodes[n].pid == node.id && this.aNodes[n]._hc) {

    if (this.aNodes[n]._io) this.nodeStatus(false, n, this.aNodes[n]._ls);

    this.aNodes[n]._io = false;

    this.closeAllChildren(this.aNodes[n]);

    }

    }

    }



    // Change the status of a node(open or closed)

    dTree.prototype.nodeStatus = function(status, id, bottom) {

    eDiv = document.getElementById('d' + this.obj + id);

    eJoin = document.getElementById('j' + this.obj + id);

    if (this.config.useIcons) {

    eIcon = document.getElementById('i' + this.obj + id);

    eIcon.src = (status) ? this.aNodes[id].iconOpen : this.aNodes[id].icon;

    }

    eJoin.src = (this.config.useLines)?

    ((status)?((bottom)?this.icon.minusBottom:this.icon.minus):((bottom)?this.icon.plusBottom:this.icon.plus)):

    ((status)?this.icon.nlMinus:this.icon.nlPlus);

    eDiv.style.display = (status) ? 'block': 'none';

    };





    // [Cookie] Clears a cookie

    dTree.prototype.clearCookie = function() {

    var now = new Date();

    var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);

    this.setCookie('co'+this.obj, 'cookieValue', yesterday);

    this.setCookie('cs'+this.obj, 'cookieValue', yesterday);

    };



    // [Cookie] Sets value in a cookie

    dTree.prototype.setCookie = function(cookieName, cookieValue, expires, path, domain, secure) {

    document.cookie =

    escape(cookieName) + '=' + escape(cookieValue)

    + (expires ? '; expires=' + expires.toGMTString() : '')

    + (path ? '; path=' + path : '')

    + (domain ? '; domain=' + domain : '')

    + (secure ? '; secure' : '');

    };



    // [Cookie] Gets a value from a cookie

    dTree.prototype.getCookie = function(cookieName) {

    var cookieValue = '';

    var posName = document.cookie.indexOf(escape(cookieName) + '=');

    if (posName != -1) {

    var posValue = posName + (escape(cookieName) + '=').length;

    var endPos = document.cookie.indexOf(';', posValue);

    if (endPos != -1) cookieValue = unescape(document.cookie.substring(posValue, endPos));

    else cookieValue = unescape(document.cookie.substring(posValue));

    }

    return (cookieValue);

    };



    // [Cookie] Returns ids of open nodes as a string

    dTree.prototype.updateCookie = function() {

    var str = '';

    for (var n=0; n<this.aNodes.length; n++) {

    if (this.aNodes[n]._io && this.aNodes[n].pid != this.root.id) {

    if (str) str += '.';

    str += this.aNodes[n].id;

    }

    }

    this.setCookie('co' + this.obj, str, null, this.config.path, this.config.domain);

    };



    // [Cookie] Checks if a node id is in a cookie

    dTree.prototype.isOpen = function(id) {

    var aOpen = this.getCookie('co' + this.obj).split('.');

    for (var n=0; n<aOpen.length; n++)

    if (aOpen[n] == id) return true;

    return false;

    };



    // If Push and pop is not implemented by the browser

    if (!Array.prototype.push) {

    Array.prototype.push = function array_push() {

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

    this[this.length]=arguments[i];

    return this.length;

    }

    };

    if (!Array.prototype.pop) {

    Array.prototype.pop = function array_pop() {

    lastElement = this[this.length-1];

    this.length = Math.max(this.length-1,0);

    return lastElement;

    }

    };[/CODE]
    Copy linkTweet thisAlerts:
    @ricpApr 06.2007 — I've got to admit I can't be bothered trawling through reams of someone else's code. I'm sure you'll understand. I will however let you know how it can be amended.

    If you look at an example (node 8 in the example page you linked) it's generated HTML is..
    [code=html]
    <div class="dTreeNode"><img src="img/empty.gif" alt=""><img src="img/line.gif" alt=""><a href="javascript: a.o(8);"><img id="ja8" src="img/minusbottom.gif" alt=""></a><img id="ia8" src="img/folderopen.gif" alt=""><a id="sa8" class="node" href="javascript:void(0);" onclick="javascript: a.s(8);">Node 8</a></div>
    [/code]

    What you need to do is shift the onclick events from the two child <a> tags and place it onto the parent <div> when doing this pass the event object through to the function allowing you to detect if it was the text or the +/- icon that was clicked, you then perform the actions you wish.

    I would paste the amended code but the boy has used the javascript: protocol on loads of <a> tag and I can't be f*cked untwisiting his inefficient html.
    Copy linkTweet thisAlerts:
    @NicMason_comauthorApr 06.2007 — Hi ricp,

    Thank you very much for the response! ? Much appreciated! ?

    I understand what you're saying on a theoretical level.

    But being a graphic designer rather than a programmer, it would take me years to re-write the code, and even longer to debug it.

    If anyone here could take the time to re-write the code, I would be very happy to offer my design services in exchange. Perhaps even a monetary exchange, if a reasonable price is named.

    Cheers,

    NicMason.com
    Copy linkTweet thisAlerts:
    @NicMason_comauthorApr 06.2007 — The menu on the left of this page is how I would like the menu to function.
    ×

    Success!

    Help @NicMason_com spread the word by sharing this article on Twitter...

    Tweet This
    Sign in
    Forgot password?
    Sign in with TwitchSign in with GithubCreate Account
    about: ({
    version: 0.1.9 BETA 6.17,
    whats_new: community page,
    up_next: more Davinci•003 tasks,
    coming_soon: events calendar,
    social: @webDeveloperHQ
    });

    legal: ({
    terms: of use,
    privacy: policy
    });
    changelog: (
    version: 0.1.9,
    notes: added community page

    version: 0.1.8,
    notes: added Davinci•003

    version: 0.1.7,
    notes: upvote answers to bounties

    version: 0.1.6,
    notes: article editor refresh
    )...
    recent_tips: (
    tipper: @nearjob,
    tipped: article
    amount: 1000 SATS,

    tipper: @meenaratha,
    tipped: article
    amount: 1000 SATS,

    tipper: @meenaratha,
    tipped: article
    amount: 1000 SATS,
    )...