July 2009 Archives

YUI TreeView: Drag and Drop nodes

| 4 Comments | 1 TrackBack
I recently had a need for a YUI (Yahoo! User Interface) TreeView with Drag & Drop nodes.  Here's a little background on the project.  My web application uses YUI Menu for navigation and is driven by a single database table.  Initially I threw together a quick and dirty CGI CRUD interface to manage the menu.  But, the more I had to modify the menu with this interface the more I needed something easier to use.  So I decided to scrap the CGI interface and start over with a nice 100% Ajax interface with a YUI TreeView to represent the YUI Menu.  Adding, changing, and deleting nodes is pretty easy, but to easily change the order of the Menu items, I added YUI Drag & Drop to the TreeView.  

The example I created is essentially a merge of two YUI examples with some tweaks.  The base code I used for this example is the Default TreeView example.  For my web app, the TreeView is dynamically loaded.  Either way, drag and drop will work.  The Reordering a list example was the best fit for my needs so it is used for drag and drop.

Here is the onDragOver function with tweaks to allow for dragging a nested node over it's parent without too much quirkiness:
  onDragOver: function(e, id) {
    var srcEl = this.getEl();
    var destEl = Dom.get(id);

    // We are only concerned with menu items, we ignore the dragover
    // notifications for anything else.
    if (destEl.id.match(/^ygtv[0-9]+$/)) {
      var orig_p = srcEl.parentNode;
      var p = destEl.parentNode;
      var destIdx = destEl.id.match(/[0-9]+$/);
      var destTreeNode = oTextNodeMap['ygtvlabelel' + destIdx];

      // Ignore any parent that is expanded
      // If !expanded
      if (! destTreeNode.expanded) {
        if (this.goingUp) {
          p.insertBefore(srcEl, destEl); // insert above
          lastDestId = destEl.id;
        } 
        else {
          p.insertBefore(srcEl, destEl.nextSibling); // insert below
          lastDestId = destEl.id;
        }
      }

      DDM.refreshCache();
    }
  }
The finished example of the TreeView with Drag & Drop:

Merging an entire branch back into the trunk can be a pain.  I've found that if you only want to keep the changes made to the branch then the following steps should help. Using svnmerge.py makes the whole process a bit easier by automatically tracking revision number ranges.  Information on svnmerge.py can be found here:  http://www.orcaware.com/svn/wiki/Svnmerge.py

Here are the steps:

  1. Begin by following the steps for merging the branch here (assumes you are using svnmerge.py):
    http://www.orcaware.com/svn/wiki/Svnmerge.py#Merging_development_branches_back_to_trunk

  2. Handle conflicts. If the branch is up-to-date, simply copy the latest revision file to the conflicted file. 

    Example: Let's say the latest revision is 100 and after merging a branch to the trunk, conflicts are present. The following shell one-liner will automatically resolve the conflicts, but only if the branch version is authoritative. If the trunk version has features not yet added to the branch version, you must manually resolve the conflict. 

    prompt:~# for a in *.r100; do b=`perl -e 'print split /\.merge-right.r100/, shift;' $a`; echo "copying $a $b"; cp $a $b; svn resolved $b; echo; done

    If this makes you nervous you can always consult the manual: http://svnbook.red-bean.com/en/1.5/svn.tour.cycle.html#svn.tour.cycle.resolve

  3. Commit the merge: svn ci -F svnmerge-commit-message.txt
Your branch should now be successfully merged into the trunk!
I like to use join and map in order to cut down on too much static code and to simplify building SQL statements to pass to DBI.  Ideally, some sort of database abstraction should be used, but it is not always an option.

Below is an example block of code that handles a CGI form submission with an action of "Add" or "Update".  The SQL is built according to the action and passed to a single prepare and execute.
my $sql;
my @fields = qw(field1 field2 field3 field4 field5);
my @bind_values;
if ($input->{action} eq "Add") {
  $sql =
  "INSERT INTO datatable (" .
    join(", ", @fields) .
  ") VALUES (" .
    join(", ", map {"?"} @fields) .
  ")";
  map {push @bind_values, $input->{$_} } @fields;
}
elsif ($input->{action} eq "Update") {
  $sql =
    "UPDATE datatable SET " .
      join(", ", map {"$_ = ?"} @fields) .
    " WHERE primarykey = ?";
  map { push @bind_values, $input->{$_} } @fields;
  push @bind_values, $input->{primarykey};
}

if (length $sql) {
  my $sth = $dbh->prepare($sql);
  $sth->execute(@bind_values);
}
This is a "one-liner" that I use sometimes to find files that contain carriage returns.  Some files containing carriage returns were committed to a Subversion repository that I manage. These files caused the diff to be corrupt when diffing against a file without the \r.  Not a huge issue, but annoying.

This command basically uses a for loop with find to recursively list all files starting from the current directory.  In the loop, each file is dumped into a small Perl one-liner that checks each line for a \r and increments a counter.  The grep at the end filters out all files with a zero count.  You could change \r to anything you want to find.

prompt:~# for a in `find . -type f`; do echo -n "$a: "; perl -e 'my $cr = 0; while (<STDIN>){ $cr += tr/\r//; } print $cr;' < $a; echo; done | grep -v '0$'

This produces a list of files with a count of characters found.

./someapp.cgi: 36
./anotherapp.cgi: 41
./somedir/yetanother.cgi: 199

Welcome

| No Comments | No TrackBacks
Welcome to my new blog coderfoo.com.  My intention is to publish tips and code that I've found to make my life easier as a LAMP Developer, Linux/UNIX SA, and MySQL DBA.  Hopefully these posts will help you too.

Stay tuned.

743vidxfw6

Pages

About this Archive

This page is an archive of entries from July 2009 listed from newest to oldest.

September 2009 is the next archive.

Find recent content on the main index or look in the archives to find all content.

Powered by Movable Type 4.261