Loading ...
Sorry, an error occurred while loading the content.

Treeview and dragdrop don't play well together, unless you use a work-around....

Expand Messages
  • plaakmann
    In YUI 2.6.0, whenever a node in a treeview is refreshed, the drag and drop objects associated with that node and its children stop functioning: both as
    Message 1 of 2 , Oct 25, 2008
    View Source
    • 0 Attachment
      In YUI 2.6.0, whenever a node in a treeview is refreshed, the drag and
      drop objects associated with that node and its children stop
      functioning: both as targets and drag-able labels. This is, of course,
      a big problem if you wish to use DND with Treeview because every time
      you add, delete, move, or even wish to relabel a node, refresh will need
      to be called to update the screen.

      I am not an expert in Javascript, but as near as I can determine this is
      a result of treeview's use of innerHTML to regenerate the child nodes.
      Even though the IDs of the labels remain the same, the element objects
      themselves get wiped out. Labels that used to be draggable won't
      because the elements are new and don't have any corresponding listeners
      to handle the mouseDown events. Similarly, due to the manner in which
      dragdrop references those labels internally (a stale reference to the
      element... which isn't checked) those refreshed labels will also not be
      droppable (targetable).

      This is my work-around:

      After I call refresh() on a node, I invoke a recursive function on that
      node that walks through all the label IDs. If that label ID is
      associated with a dragdrop object and the object is referencing an
      invalid element (presumably due to it getting wiped out), then I clobber
      the "private" variable reference to that element (the object will look
      it up by ID when it needs to). Additionally, if that object has a
      mouseDown event (exclude target-only objects), then I setup a new
      mouseDown listener for the corresponding ID and point it back to the
      object's event handler.

      I am only using this with textNodes and not dynamic trees or anything,
      however it is working well for me thus far and should be easy to modify
      to handle HTML nodes. Is there a better way? Perhaps the next version
      of YUI will make allowances for this? Any obvious bugs (I know, those
      references to internal private variables may get broken with a future
      YUI release....)? Perhaps I need to subclass the treeview and over-ride
      automatic refresh events?

      In any event, here is my code in case it can help anyone:

      // call dnd fix function recursively on specified node and its children
      function onNodeRefresh(node)
      {

      checkandfixDNDEl(node.labelElId);

      for (var i=0;i<node.children.length;i++) {
      onNodeRefresh(node.children[i]);
      }
      }

      function checkandfixDNDEl(elid)
      {

      var DDM = YAHOO.util.DragDropMgr;
      var ddi = DDM.getDDById(elid);

      // dnd instance doesnt exist for ID
      if ( ddi === null ) {
      return;
      }

      // if we can't locate the dnd instance's element by its element
      variable
      if ( !DDM.verifyEl(ddi._domRef) ) {

      // clobber the instance's element reference... it'll look it up
      by ID when it needs to
      ddi._domRef = 0;

      // only need to set a listener on draggable instances... not
      target onlys
      if ( ddi.hasEvent("mouseDownEvent") ) {
      YAHOO.util.Event.on(elid, "mousedown", ddi.handleMouseDown,
      ddi, true);
      }


      }

      }

      In case the formatting gets screwed up: http://www.pastie.org/300397
    • Satyam
      I m not good at D&D but this is what you usually do with unhooked event listeners, instead of putting a listener on each individual element you put a single
      Message 2 of 2 , Oct 25, 2008
      View Source
      • 0 Attachment
        I'm not good at D&D but this is what you usually do with unhooked event
        listeners, instead of putting a listener on each individual element you
        put a single one on a top level element, one that contains all and is
        permanent, the tree container in this case. I don't know if the D&D
        utility provides a way to do this but otherwise I would listen to
        mousedown on the tree container and use the same logic D&D uses to
        detect an actual drag: it should last more than a certain time or move
        before there is a mouseup. I would find from the event the actual
        target and with TreeView's getNodeByElement find the node that was meant
        to be moved. I know D&D supports proxies so you would actually start
        dragging the proxy with the Node information stored somewhere. You will
        not only spare yourself rehooking the listeners to the elements but also
        save yourself lots of memory storing so many listeners, one per leaf
        instead of just one.

        Now, someone with experience in D&D would probably know how to do this
        much better.

        Satyam


        plaakmann wrote:
        > In YUI 2.6.0, whenever a node in a treeview is refreshed, the drag and
        > drop objects associated with that node and its children stop
        > functioning: both as targets and drag-able labels. This is, of course,
        > a big problem if you wish to use DND with Treeview because every time
        > you add, delete, move, or even wish to relabel a node, refresh will need
        > to be called to update the screen.
        >
        > I am not an expert in Javascript, but as near as I can determine this is
        > a result of treeview's use of innerHTML to regenerate the child nodes.
        > Even though the IDs of the labels remain the same, the element objects
        > themselves get wiped out. Labels that used to be draggable won't
        > because the elements are new and don't have any corresponding listeners
        > to handle the mouseDown events. Similarly, due to the manner in which
        > dragdrop references those labels internally (a stale reference to the
        > element... which isn't checked) those refreshed labels will also not be
        > droppable (targetable).
        >
        > This is my work-around:
        >
        > After I call refresh() on a node, I invoke a recursive function on that
        > node that walks through all the label IDs. If that label ID is
        > associated with a dragdrop object and the object is referencing an
        > invalid element (presumably due to it getting wiped out), then I clobber
        > the "private" variable reference to that element (the object will look
        > it up by ID when it needs to). Additionally, if that object has a
        > mouseDown event (exclude target-only objects), then I setup a new
        > mouseDown listener for the corresponding ID and point it back to the
        > object's event handler.
        >
        > I am only using this with textNodes and not dynamic trees or anything,
        > however it is working well for me thus far and should be easy to modify
        > to handle HTML nodes. Is there a better way? Perhaps the next version
        > of YUI will make allowances for this? Any obvious bugs (I know, those
        > references to internal private variables may get broken with a future
        > YUI release....)? Perhaps I need to subclass the treeview and over-ride
        > automatic refresh events?
        >
        > In any event, here is my code in case it can help anyone:
        >
        > // call dnd fix function recursively on specified node and its children
        > function onNodeRefresh(node)
        > {
        >
        > checkandfixDNDEl(node.labelElId);
        >
        > for (var i=0;i<node.children.length;i++) {
        > onNodeRefresh(node.children[i]);
        > }
        > }
        >
        > function checkandfixDNDEl(elid)
        > {
        >
        > var DDM = YAHOO.util.DragDropMgr;
        > var ddi = DDM.getDDById(elid);
        >
        > // dnd instance doesnt exist for ID
        > if ( ddi === null ) {
        > return;
        > }
        >
        > // if we can't locate the dnd instance's element by its element
        > variable
        > if ( !DDM.verifyEl(ddi._domRef) ) {
        >
        > // clobber the instance's element reference... it'll look it up
        > by ID when it needs to
        > ddi._domRef = 0;
        >
        > // only need to set a listener on draggable instances... not
        > target onlys
        > if ( ddi.hasEvent("mouseDownEvent") ) {
        > YAHOO.util.Event.on(elid, "mousedown", ddi.handleMouseDown,
        > ddi, true);
        > }
        >
        >
        > }
        >
        > }
        >
        > In case the formatting gets screwed up: http://www.pastie.org/300397
        >
        >
        >
        >
        > ------------------------------------
        >
        > Yahoo! Groups Links
        >
        >
        >
        > ------------------------------------------------------------------------
        >
        >
        > No virus found in this incoming message.
        > Checked by AVG - http://www.avg.com
        > Version: 8.0.175 / Virus Database: 270.8.2/1743 - Release Date: 24/10/2008 8:33
        >
        >
      Your message has been successfully submitted and would be delivered to recipients shortly.