File:  [LON-CAPA] / loncom / interface / lonwishlist.pm
Revision 1.2: download - view: text, annotated - select for diffs
Mon Aug 16 08:58:39 2010 UTC (13 years, 9 months ago) by wenzelju
Branches: MAIN
CVS tags: HEAD
londocs, lonmenu, lonwishlist:
- Added import-functionality for wishlist.

lonwishlist:
- Replaced getkeys() and get() by dump().
- Preview of links in wishlist now in Popup.
- Some little style changes (inserted <p> etc.).

    1: # The LearningOnline Network with CAPA
    2: # Routines to control the wishlist
    3: #
    4: # $Id: lonwishlist.pm,v 1.2 2010/08/16 08:58:39 wenzelju Exp $
    5: #
    6: # Copyright Michigan State University Board of Trustees
    7: #
    8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    9: #
   10: # LON-CAPA is free software; you can redistribute it and/or modify
   11: # it under the terms of the GNU General Public License as published by
   12: # the Free Software Foundation; either version 2 of the License, or
   13: # (at your option) any later version.
   14: #
   15: # LON-CAPA is distributed in the hope that it will be useful,
   16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18: # GNU General Public License for more details.
   19: #
   20: # You should have received a copy of the GNU General Public License
   21: # along with LON-CAPA; if not, write to the Free Software
   22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   23: #
   24: # /home/httpd/html/adm/gpl.txt
   25: #
   26: # http://www.lon-capa.org/
   27: #
   28: 
   29: 
   30: 
   31: package Apache::lonwishlist;
   32: 
   33: use strict;
   34: use Apache::Constants qw(:common);
   35: use Apache::lonnet;
   36: use Apache::loncommon();
   37: use Apache::lonhtmlcommon;
   38: use Apache::lonlocal;
   39: use LONCAPA;
   40: use Tree;
   41: 
   42: 
   43: # Global variables
   44: my $root;
   45: my @childrenRt;
   46: my %TreeHash;
   47: my %TreeToHash;
   48: my @allFolders;
   49: my @allNodes;
   50: my $indentConst = 20;
   51: 
   52: 
   53: # Read wishlist from user-data
   54: sub getWishlist {
   55:     my %wishlist = &Apache::lonnet::dump('wishlist');
   56:     foreach my $i ( keys %wishlist) {
   57:         #File not found. This appears at the first time using the wishlist
   58:         #Create file and put 'root' into it
   59:        if ($i =~m/^error:No such file/) {
   60:            &Apache::lonnet::logthis($i.'! Create file by putting in the "root" of the directory tree.');
   61:            &Apache::lonnet::put('wishlist', {'root' => ''});
   62:            %wishlist = &Apache::lonnet::dump('wishlist');
   63:        }
   64:        elsif ($i =~ /^(con_lost|error|no_such_host)/i) {
   65:            &Apache::lonnet::logthis('ERROR while attempting to get wishlist: '.$i);
   66:            return 'error';
   67:        }
   68:     }
   69: 
   70:     # if we got no keys in hash returned by dump(), return error.
   71:     # wishlist will not be loaded, instead the user will be asked to try again later
   72:     if ((keys %wishlist) == 0) {
   73:         &Apache::lonnet::logthis('ERROR while attempting to get wishlist: no keys retrieved!');
   74:         return 'error';
   75:     }
   76:     
   77:     return %wishlist;
   78: }
   79: 
   80: 
   81: # Write wishlist to user-data
   82: sub putWishlist {
   83:     my $wishlist = shift;
   84:     &Apache::lonnet::put('wishlist',$wishlist);
   85: }
   86: 
   87: 
   88: # Removes all existing entrys for wishlist in user-data
   89: sub deleteWishlist {
   90:     my @wishlistkeys = &Apache::lonnet::getkeys('wishlist');
   91:     my %wishlist = &Apache::lonnet::del('wishlist',\@wishlistkeys);
   92: }
   93: 
   94: 
   95: # Create a new entry
   96: sub newEntry() {
   97:     my ($title, $path, $note) = @_;
   98:     my $date = gmtime();
   99:     # Create Entry-Object
  100:     my $entry = Entry->new(title => $title, path => $path, note => $note, date => $date);
  101:     # Create Tree-Object, this correspones a node in the wishlist-tree
  102:     my $tree = Tree->new($entry);
  103:     # Add this node to wishlist-tree
  104:     my $folderIndex = $env{'form.folders'};
  105:     if ($folderIndex ne '') {
  106:         @allFolders = ();
  107:         &getFoldersToArray(\@childrenRt);
  108:         my $folderToInsertOn = &Tree::getNodeByIndex($folderIndex,\@allFolders);
  109:         $folderToInsertOn->add_child($tree);
  110:     }
  111:     else {
  112:         $root->add_child($tree);
  113:     }
  114:     &saveChanges();
  115: }
  116: 
  117: 
  118: # Delete entries
  119: sub deleteEntries {
  120:     my $marked = shift;
  121:     &getNodesToArray(\@childrenRt);
  122: 
  123:     foreach my $m (@$marked) {
  124:         my $found = &Tree::getNodeByIndex($m, \@allNodes);
  125:         &Tree::removeNode($found);
  126:     }
  127:     @allNodes = ();
  128:     &saveChanges();
  129: }
  130: 
  131: 
  132: # Sort entries
  133: sub sortEntries {
  134:     my $indexNode = shift;
  135:     my $at = shift;
  136:     
  137:     &getNodesToArray(\@childrenRt);
  138:     my $foundNode = &Tree::getNodeByIndex($indexNode, \@allNodes);
  139: 
  140:     &Tree::moveNode($foundNode,$at,undef);
  141:     @allNodes = ();
  142: }
  143: 
  144: 
  145: # Move entries
  146: sub moveEntries {
  147:     my $indexNodesToMove = shift;
  148:     my $indexParent = shift;
  149:     my @nodesToMove = ();
  150: 
  151:     # get all nodes that should be moved
  152:     &getNodesToArray(\@childrenRt);
  153:     foreach my $index (@$indexNodesToMove) {
  154:         my $foundNode = &Tree::getNodeByIndex($index, \@allNodes);
  155:         push(@nodesToMove, $foundNode);
  156:     }
  157: 
  158:     foreach my $node (@nodesToMove) {
  159:         my $foundParent;
  160:         my $parentIsIn = 0;
  161:         foreach my $n (@nodesToMove) {
  162:             if ($node->parent()->value() ne "root") {
  163:                if ($node->parent()->value()->nindex() == $n->value()->nindex()) {
  164:                     $parentIsIn = 1;
  165:                 }
  166:             }
  167:         }
  168:         if (!$parentIsIn) {
  169:             if ($indexParent ne "root") {
  170:                 $foundParent = &Tree::getNodeByIndex($indexParent, \@allNodes);
  171:                 &Tree::moveNode($node,undef,$foundParent);
  172:             }
  173:             else {
  174:                 &Tree::moveNode($node,undef,$root);
  175:             }
  176:         }
  177:     }
  178:     @allNodes = ();
  179: }
  180: 
  181: 
  182: # Set a new title for an entry
  183: sub setNewTitle {
  184:     my ($nodeindex, $newTitle) = @_;
  185:     &getNodesToArray(\@childrenRt);
  186:     my $found = &Tree::getNodeByIndex($nodeindex, \@allNodes);
  187:     $found->value()->title($newTitle); 
  188:     @allNodes = ();
  189: }
  190: 
  191: 
  192: # Set a new note for an entry
  193: sub setNewNote {
  194:     my ($nodeindex, $newNote) = @_;
  195:     &getNodesToArray(\@childrenRt);
  196:     my $found = &Tree::getNodeByIndex($nodeindex, \@allNodes);
  197:     $found->value()->note($newNote); 
  198:     @allNodes = ();
  199: }
  200: 
  201: 
  202: # Save all changes
  203: sub saveChanges {
  204:     @childrenRt = $root->children();
  205:     &Tree::TreeIndex(\@childrenRt);
  206:     &Tree::setCountZero();
  207:     &Tree::RootToHash(\@childrenRt);
  208:     &Tree::TreeToHash(\@childrenRt);
  209:     &deleteWishlist();
  210:     &putWishlist(\%TreeToHash);
  211: 
  212: }
  213: 
  214: 
  215: # Return the names for all exiting folders in option-tags, so
  216: # a new link or a new folder can be created in an existing folder
  217: my $indent = 0;
  218: my $foldersOption;
  219: sub getFoldersForOption {
  220:     my $nodes = shift;
  221: 
  222:     foreach my $n (@$nodes) {
  223:         if ($n->value()->path() eq '') {
  224:             $foldersOption .= '<option value="'.$n->value()->nindex().'" style="margin-left:'.$indent.'px">'.
  225:                                    $n->value()->title().
  226:                                '</option>';
  227: 
  228:         my @children = $n->children();
  229:         if ($#children >=0) {
  230:             $indent += 10;
  231:             &getFoldersForOption(\@children);
  232:             $indent -= 10;
  233:             }
  234:         }
  235:     }
  236: }
  237: 
  238: 
  239: sub getfoldersOption {
  240:    if (&getWishlist ne 'error') {
  241:        %TreeHash = &getWishlist();
  242:        $root = &Tree::HashToTree();
  243:        @childrenRt = $root->children();
  244:        &getFoldersForOption(\@childrenRt);
  245:        my $options = '<option value="" selected="selected">('.&mt('Top level').')</option>'.$foldersOption;
  246:        $foldersOption = '';
  247:        return $options;
  248:    }
  249:    else {
  250:        return '';
  251:    }
  252: }
  253: 
  254: 
  255: # Put all folder-nodes to an array
  256: sub getFoldersToArray {
  257:     my $children = shift;
  258:     foreach my $c (@$children) {
  259:         if ($c->value()->path() eq '') {
  260:             push(@allFolders,$c);
  261:         }
  262:         my @newchildren = $c->children();
  263:         if ($#newchildren >= 0) {
  264:             &getFoldersToArray(\@newchildren);
  265:         }
  266:     }
  267: }
  268: 
  269: 
  270: # Put all nodes to an array
  271: sub getNodesToArray {
  272:     my $children = shift;
  273:     foreach my $c (@$children) {
  274:         push(@allNodes,$c);
  275:         my @newchildren = $c->children();
  276:         if ($#newchildren >= 0) {
  277:             &getNodesToArray(\@newchildren);
  278:         }
  279:     }
  280: }
  281: 
  282: 
  283: # Return a script-tag containing Javascript-function
  284: # needed for wishlist actions like 'new link' ect.
  285: sub JSforWishlist {
  286:     my $startPagePopup = &Apache::loncommon::start_page('Wishlist',undef,
  287:                                                             {'only_body' => 1,
  288:                                                              'js_ready'  => 1,
  289:                                                              'bgcolor'   => '#FFFFFF',});
  290:     my $endPagePopup = &Apache::loncommon::end_page({'js_ready' => 1});
  291: 
  292:     @allFolders = ();
  293:     &getFoldersToArray(\@childrenRt);
  294:     &getFoldersForOption(\@childrenRt);
  295: 
  296:     # texthash
  297:     my %lt = &Apache::lonlocal::texthash(
  298:                  'nl' => 'New Link',
  299:                  'nf' => 'New Folder',
  300:                  'lt' => 'Link Title',
  301:                  'ft' => 'Folder Title',
  302:                  'pa' => 'Path',
  303:                  'nt' => 'Note',
  304:                  'si' => 'Save in',
  305:                  'cl' => 'Cancel');
  306: 
  307: 
  308:     my $inPageNewLink = '<h1>'.$lt{'nl'}.'</h1>'.
  309:                         '<form method="post" name="newlink" action="/adm/wishlist" target="wishlist" '.
  310:                         'onsubmit="return newlinksubmit();" >'.
  311:                         &Apache::lonhtmlcommon::start_pick_box().
  312:                         &Apache::lonhtmlcommon::row_title($lt{'lt'}).
  313:                         '<input type="text" name="title" size="45" value="" />'.
  314:                         &Apache::lonhtmlcommon::row_closure().
  315:                         &Apache::lonhtmlcommon::row_title($lt{'pa'}).
  316:                         '<input type="text" name="path" size="45" value="" />'.
  317:                         &Apache::lonhtmlcommon::row_closure().
  318:                         &Apache::lonhtmlcommon::row_title($lt{'nt'}).
  319:                         '<textarea name="note" rows="3" cols="35" style="width:100%"></textarea>'.
  320:                         &Apache::lonhtmlcommon::row_closure(1).
  321:                         &Apache::lonhtmlcommon::end_pick_box().
  322:                         '<br/><br/>'.
  323:                         '<input type="submit" value="'.$lt{'si'}.'" />'.
  324:                         '<select name="folders">'.
  325:                         '<option value="" selected="selected">('.&mt('Top level').')</option>'.
  326:                         $foldersOption.
  327:                         '</select>'.
  328:                         '<input type="button" value="'.$lt{'cl'}.'" onclick="javascript:window.close();" />'.
  329:                         '</form>';
  330:     
  331:     my $inPageNewFolder = '<h1>'.$lt{'nf'}.'</h1>'.
  332:                           '<form method="post" name="newfolder" action="/adm/wishlist" target="wishlist" '.
  333:                           'onsubmit="return newfoldersubmit();" >'.
  334:                           &Apache::lonhtmlcommon::start_pick_box().
  335:                           &Apache::lonhtmlcommon::row_title($lt{'ft'}).
  336:                           '<input type="text" name="title" size="45" value="" /><br />'.
  337:                           &Apache::lonhtmlcommon::row_closure().
  338:                           &Apache::lonhtmlcommon::row_title($lt{'nt'}).
  339:                           '<textarea name="note" rows="3" cols="35" style="width:100%"></textarea><br />'.
  340:                           &Apache::lonhtmlcommon::row_closure(1).
  341:                           &Apache::lonhtmlcommon::end_pick_box().
  342:                           '<br/><br/>'.
  343:                           '<input type="submit" value="'.$lt{'si'}.'" />'.
  344:                           '<select name="folders">'.
  345:                           '<option value="" selected="selected">('.&mt('Top level').')</option>'.
  346:                           $foldersOption.
  347:                           '</select>'.
  348:                           '<input type="button" value="'.$lt{'cl'}.'" onclick="javascript:window.close();" />'.
  349:                           '</form>';
  350: 
  351:     # Remove all \n for inserting on javascript document.write
  352:     $inPageNewLink =~ s/\n//g;
  353:     $inPageNewFolder =~ s/\n//g;
  354: 
  355:     my $warningLink = &mt('You must insert a title and a path!');
  356:     my $warningFolder = &mt('You must insert a title!');
  357:     my $warningDelete = &mt('Are you sure you want to delete the selected entries? Deleting a folder also deletes all entries within this folder!');
  358:     my $warningSave = &mt('You have unsaved changes. You can either save these changes now by clicking "ok" or click "cancel" if you do not want to save your changes.');
  359:     my $warningMove = &mt('You must select a destination folder!');
  360:     $foldersOption = '';
  361: 
  362:     my $js = &Apache::lonhtmlcommon::scripttag(<<JAVASCRIPT);
  363:     function newLink() {
  364:         newlinkWin=window.open('','newlinkWin','width=580,height=320,scrollbars=yes');
  365:         newlinkWin.document.write('$startPagePopup' 
  366:                               +'<script type="text\/javascript">'
  367:                               +'function newlinksubmit(){'
  368:                               +'var path = document.getElementsByName("path")[0].value;'
  369:                               +'var title = document.getElementsByName("title")[0].value;'
  370:                               +'if (!path || !title) {'
  371:                               +'alert("$warningLink");'
  372:                               +'return false;}'
  373:                               +'else {'
  374:                               +'window.close();'
  375:                               +'return true;}}'
  376:                               +'<\/scr'+'ipt>'
  377:                               +'$inPageNewLink'
  378:                               +'$endPagePopup');
  379:         newlinkWin.document.close();
  380:     }
  381: 
  382:     function newFolder() {
  383:         newfolderWin=window.open('','newfolderWin','width=580,height=270, scrollbars=yes');
  384:         newfolderWin.document.write('$startPagePopup' 
  385:                               +'<script type="text\/javascript">'
  386:                               +'function newfoldersubmit(){'
  387:                               +'var title = document.getElementsByName("title")[0].value;'
  388:                               +'if (!title) {'
  389:                               +'alert("$warningFolder");'
  390:                               +'return false;}'
  391:                               +'else {'
  392:                               +'window.close();'
  393:                               +'return true;}}'
  394:                               +'<\/scr'+'ipt>'
  395:                               +'$inPageNewFolder'
  396:                               +'$endPagePopup');
  397:         newfolderWin.document.close();
  398:     }
  399: 
  400:     function setFormAction(action,mode) {
  401:         var r = true;
  402:         setAction('');
  403:         if (action == 'delete') {
  404:             r = confirm("$warningDelete");
  405:             setAction('delete');
  406:         }
  407:         else if (action == 'save') {
  408:             var d = getDifferences();
  409:             if (d) {
  410:                 if (!confirm('$warningSave')) {
  411:                     setAction('noSave');
  412:                 }
  413:             }
  414:             r = true;
  415:         }
  416:         document.getElementsByName('list')[0].setAttribute("action", "/adm/wishlist?mode="+mode); 
  417:         if (r) {
  418:             document.getElementsByName('list')[0].submit(); 
  419:         }
  420:     }
  421: 
  422:     function setAction(action) {
  423:         document.getElementById('action').value = action; 
  424:     }
  425: 
  426:     function getDifferences() {
  427:         var newtitles = document.getElementsByName('newtitle');
  428:         var i = 0;
  429:         for (i=0;i<newtitles.length;i++) {
  430:             var newt = newtitles[i].value;
  431:             var oldt = newtitles[i].alt;
  432:             if (newt != oldt) {
  433:                 return true;
  434:             }
  435:         }
  436:         var newnote = document.getElementsByName('newnote');
  437:         var i = 0;
  438:         for (i=0;i<newnote.length;i++) {
  439:             var newn = newnote[i].value;
  440:             var oldn = newnote[i].innerHTML;
  441:             if (newn != oldn) {
  442:                 return true;
  443:             }
  444:         }
  445:         return false;
  446:     }
  447: 
  448:     function onLoadAction(mode) {
  449:         window.name = 'wishlist';
  450:         if (mode == "edit") {
  451:             var deepestRows = getDeepestRows();
  452:             setDisplaySelect(deepestRows, '');
  453:         }
  454:     }
  455: 
  456:     function folderAction(rowid) {
  457:         var row = document.getElementById(rowid);
  458:         var indent = getIndent(row);
  459:         var displ;
  460:         var status;
  461:         if (getImage(row) == 'closed') {
  462:             displ = '';
  463:             status = 'open';
  464:         }
  465:         else {
  466:             displ = 'LC_hidden';
  467:             status = 'closed';
  468:         }
  469:         setImage(row,status);
  470:         if (getNextRow(row) != null) {
  471:             var nextIndent = getIndent(getNextRow(row));
  472:             row = getNextRow(row);
  473:             while (nextIndent > indent) {
  474:                 if (displ == '') {
  475:                     row.className = (row.className).replace('LC_hidden','');
  476:                 }
  477:                 else if (displ != '' && !((row.className).match('LC_hidden'))) {
  478:                     var oldClass = row.className;
  479:                     row.className = oldClass+' LC_hidden';
  480:                     setDisplayNote(row.id.replace('row','note'),'LC_hidden');
  481:                 }
  482:                 if (status == 'open' && getImage(row).match('closed')) {
  483:                     row = getNextRowWithIndent(row, getIndent(row));
  484:                 }
  485:                 else {
  486:                     row = getNextRow(row);
  487:                 } 
  488:                 if (row != null) {
  489:                     nextIndent = getIndent(row);
  490:                 } 
  491:                 else {
  492:                     nextIndent = indent;
  493:                 }
  494:             }
  495:         }
  496:         setClasses();
  497:         var newtitles = document.getElementsByName('newtitle');
  498:         if (newtitles.length>0) {
  499:             var deepestRows = getDeepestRows();
  500:             var otherRows = getOtherRows(deepestRows);
  501:             setDisplaySelect(deepestRows,'');
  502:             setDisplaySelect(otherRows,'LC_hidden');
  503:         }
  504:     }
  505: 
  506:     function selectAction(rowid) {
  507:         var row = document.getElementById(rowid);
  508:         var indent = getIndent(row);
  509:         var checked = getChecked(row);
  510:         var previousFolderRows = new Array();
  511:         if (indent != 0) {
  512:             previousFolderRows = getPreviousFolderRows(row);
  513:         }
  514:         if (getNextRow(row) != null) {
  515:             var nextIndent = getIndent(getNextRow(row));
  516:             row = getNextRow(row);
  517:                 while (nextIndent > indent) {
  518:                     setChecked(row,checked);
  519:                     if (status == 'open' && getImage(row).match('closed')) {
  520:                         row = getNextRowWithIndent(row, getIndent(row));
  521:                     }
  522:                     else {
  523:                         row = getNextRow(row);
  524:                     }
  525:                     if (row != null) {
  526:                         nextIndent = getIndent(row);
  527:                     }
  528:                     else {
  529:                         nextIndent = indent;
  530:                     }
  531:                 }
  532:         }
  533:         if (!checked) {
  534:             var i = 0;
  535:             for (i=0;i<previousFolderRows.length;i++) {
  536:                 setChecked(previousFolderRows[i], false);
  537:             }
  538:         }
  539:     }
  540: 
  541:     function getNextNote(row) {
  542:         var rowId = row.id;
  543:         var nextRowId = parseInt(rowId.substr(3,rowId.length))+1;
  544:         nextRowId = "note"+nextRowId;
  545:         var nextRow = document.getElementById(nextRowId);
  546:         return nextRow;
  547:     }
  548: 
  549:     function getNextRow(row) {
  550:         var rowId = row.id;
  551:         var nextRowId = parseInt(rowId.substr(3,rowId.length))+1;
  552:         nextRowId = "row"+nextRowId;
  553:         var nextRow = document.getElementById(nextRowId);
  554:         return nextRow;
  555:     }
  556: 
  557:     function getPreviousRow(row) {
  558:         var rowId = row.id;
  559:         var previousRowId =  parseInt(rowId.substr(3,rowId.length))-1;
  560:         previousRowId = "row"+previousRowId;
  561:         var previousRow =document.getElementById(previousRowId);
  562:         return previousRow;
  563:     }
  564: 
  565:     function getIndent(row) {
  566:         var childPADD = document.getElementById(row.id.replace('row','padd'));
  567:         indent = childPADD.style.paddingLeft;
  568:         indent = parseInt(indent.substr(0,(indent.length-2)));
  569:  
  570:         if (getImage(row).match('link')) {
  571:             indent -= $indentConst;
  572:         }
  573:         return indent;
  574:     }
  575: 
  576:     function getNextRowWithIndent(row, indent) {
  577:         var nextRow = getNextRow(row);
  578:         if (nextRow != null) {
  579:         var nextIndent = getIndent(nextRow);
  580:         while (nextIndent >= indent) {
  581:             if (nextIndent == indent) {
  582:                 return nextRow;
  583:             }
  584:             nextRow = getNextRow(nextRow);
  585:             if (nextRow == null) {
  586:                 return null;
  587:             }
  588:             nextIndent = getIndent(nextRow);
  589:         }
  590:         }
  591:         return nextRow;
  592:     }
  593: 
  594:     function getImage(row) {
  595:         var childIMG = document.getElementById(row.id.replace('row','img'));
  596:         if ((childIMG.src).match('closed')) {
  597:             return 'closed';
  598:         }
  599:         else if ((childIMG.src).match('open')) {
  600:             return 'open;'
  601:         }
  602:         else {
  603:             return 'link';
  604:         }
  605:     } 
  606: 
  607:     function setImage(row, status) {
  608:         var childIMG = document.getElementById(row.id.replace('row','img'));
  609:         var childIMGFolder = document.getElementById(row.id.replace('row','imgFolder'));
  610:         childIMG.src = "/adm/lonIcons/arrow."+status+".gif";
  611:         childIMGFolder.src="/adm/lonIcons/navmap.folder."+status+".gif"; 
  612:     }
  613: 
  614:     function getChecked(row) {
  615:         var childCHECK = document.getElementById(row.id.replace('row','check'));
  616:         var checked = childCHECK.checked;
  617:         return checked;
  618:     }
  619: 
  620:     function setChecked(row,checked) {
  621:         var childCHECK = document.getElementById(row.id.replace('row','check'));
  622:         childCHECK.checked = checked;
  623:     }
  624: 
  625:     function getPreviousFolderRows(row) {
  626:         var previousRow = getPreviousRow(row);
  627:         var indent = getIndent(previousRow);
  628:         var kindOfEntry = getImage(previousRow);
  629:         var rows = new Array();
  630:         if (kindOfEntry != 'link') {
  631:             rows.push(previousRow);
  632:         }
  633: 
  634:         while (indent >0) {
  635:             previousRow = getPreviousRow(previousRow);
  636:             if (previousRow != null) {
  637:                 indent = getIndent(previousRow);
  638:                 kindOfEntry = getImage(previousRow);
  639:                 if (kindOfEntry != 'link') {
  640:                     rows.push(previousRow);
  641:                 }
  642:             }
  643:             else {
  644:                 indent = 0; 
  645:             }
  646:         }
  647:         return rows;
  648:     }
  649: 
  650:     function getDeepestRows() {
  651:         var row = document.getElementById('row0');
  652:         var firstRow = row;
  653:         var indent = getIndent(row);
  654:         var maxIndent = indent;
  655:         while (getNextRow(row) != null) {
  656:             row = getNextRow(row);
  657:             indent = getIndent(row);
  658:             if (indent>maxIndent && !((row.className).match('LC_hidden'))) {
  659:                 maxIndent = indent;
  660:             }
  661:         }
  662:         var deepestRows = new Array();
  663:         row = firstRow;
  664:         var rowIndent;
  665:         while (getNextRow(row) != null) {
  666:             rowIndent = getIndent(row);
  667:             if (rowIndent == maxIndent) {
  668:                 deepestRows.push(row);
  669:             }
  670:             row = getNextRow(row);
  671:         }
  672:         rowIndent = getIndent(row);
  673:         if (rowIndent == maxIndent) {
  674:             deepestRows.push(row);
  675:         }
  676:         return deepestRows;
  677:     }
  678: 
  679:     function getOtherRows(deepestRows) {
  680:         var row = document.getElementById('row0');
  681:         var otherRows = new Array();
  682:         var isIn = false;
  683:         while (getNextRow(row) != null) {
  684:             var i = 0;
  685:             for (i=0; i < deepestRows.length; i++) {
  686:                 if (row.id == deepestRows[i].id) {
  687:                     isIn = true;
  688:                 }
  689:             }
  690:             if (!isIn) {
  691:                 otherRows.push(row);
  692:             }
  693:             row = getNextRow(row);
  694:             isIn = false;
  695:         }
  696:         for (i=0; i < deepestRows.length; i++) {
  697:             if (row.id == deepestRows[i].id) {
  698:                 isIn = true;
  699:             }
  700:         }
  701:         if (!isIn) {
  702:             otherRows.push(row);
  703:         }
  704:         return otherRows;
  705:     }
  706: 
  707:     function setDisplaySelect(deepestRows, displ) {
  708:         var i = 0;
  709:         for (i = 0; i < deepestRows.length; i++) {
  710:             var row = deepestRows[i];
  711:             var childSEL = document.getElementById(row.id.replace('row','sel'));
  712:             childSEL.className = displ;
  713:         } 
  714:     }
  715: 
  716:     function submitSelect() {
  717:        var list = document.getElementsByName('list')[0];
  718:        list.setAttribute("action","/adm/wishlist?mode=edit");
  719:        list.submit();
  720:     }
  721: 
  722:     function setDisplayNote(rowid, displ) {
  723:         var row = document.getElementById(rowid);
  724:         if (!displ) {
  725:             if ((row.className).match('LC_hidden')) {
  726:                 row.className = (row.className).replace('LC_hidden','');
  727:             }
  728:             else {
  729:                 var oldClass = row.className;
  730:                 row.className = oldClass+' LC_hidden';
  731:             }
  732:         }
  733:         else {
  734:             if (displ == '') {
  735:                 row.className = (row.className).replace('LC_hidden','');
  736:             }
  737:             else if (displ != '' && !((row.className).match('LC_hidden'))) {
  738:                 var oldClass = row.className;
  739:                 row.className = oldClass+' LC_hidden';
  740:             }
  741:         }
  742:         var noteText = document.getElementById(rowid.replace('note','noteText'));
  743:         var noteImg = document.getElementById(rowid.replace('note','noteImg'));
  744:         if (noteText.value) {
  745:             noteImg.src = "/res/adm/pages/anot2.png";
  746:         }
  747:         else {
  748:             noteImg.src = "/res/adm/pages/anot.png";
  749:         }
  750: 
  751:     }
  752: 
  753:     function setClasses() {
  754:         var row = document.getElementById("row0");
  755:         var note = document.getElementById("note0");
  756:         var LC_class = 0;
  757:         if (getNextRow(row) != null) {
  758:             while (getNextRow(row) != null) {
  759:                 if (!(row.className).match('LC_hidden')) {
  760:                     note.className = (note.className).replace('LC_even_row','');
  761:                     note.className = (note.className).replace('LC_odd_row','');
  762:                     if (LC_class) {
  763:                         row.className = 'LC_even_row';
  764:                         note.className = 'LC_even_row'+note.className;
  765:                     }
  766:                     else {
  767:                         row.className = 'LC_odd_row';
  768:                         note.className = 'LC_odd_row'+note.className;;
  769:                     }
  770:                     LC_class = !LC_class;
  771:                 }
  772:                 note = getNextNote(row);
  773:                 row = getNextRow(row);
  774:             }
  775:         }
  776:         if (!(row.className).match('LC_hidden')) {
  777:             note.className = (note.className).replace('LC_even_row','');
  778:             note.className = (note.className).replace('LC_odd_row','');
  779:             if (LC_class) {
  780:                 row.className = 'LC_even_row';
  781:                 note.className = 'LC_even_row'+note.className;
  782:             }
  783:             else {
  784:                 row.className = 'LC_odd_row';
  785:                 note.className = 'LC_odd_row'+note.className;
  786:             }
  787:         }
  788:     }
  789: 
  790:     function selectDestinationFolder() {
  791:         var mark = document.getElementsByName('mark');
  792:         var i = 0;
  793:         for (i = 0; i < mark.length; i++) {
  794:             if (mark[i].checked) {
  795:                 document.getElementsByName('list')[0].submit();
  796:                 return true;
  797:             }
  798:         }
  799:         alert('$warningMove');
  800:         return false;
  801:     }
  802: 
  803:     function preview(url) {
  804:        var newWin = window.open(url+'?inhibitmenu=yes','preview','width=560,height=350,scrollbars=yes');
  805:        newWin.focus();
  806:     }
  807: 
  808:     function finish_import() {
  809:         opener.document.forms.simpleedit.importdetail.value='';
  810:         for (var num = 0; num < document.forms.groupsort.fnum.value; num++) {
  811:             if (eval("document.forms.groupsort.check"+num+".checked") && eval("document.forms.groupsort.filelink"+num+".value") != '') {
  812:                 opener.document.forms.simpleedit.importdetail.value+='&'+
  813:                 eval("document.forms.groupsort.title"+num+".value")+'='+
  814:                 eval("document.forms.groupsort.filelink"+num+".value")+'='+
  815:                 eval("document.forms.groupsort.id"+num+".value");
  816:             }
  817:         }
  818:         opener.document.forms.simpleedit.submit();
  819:         self.close();
  820:     }
  821: 
  822:     function checkAll() {
  823:         var checkboxes = document.getElementsByName('check');
  824:         for (var i = 0; i < checkboxes.length; i++) {
  825:             checkboxes[i].checked = "checked";
  826:         }
  827:     }
  828: 
  829:     function uncheckAll() {
  830:         var checkboxes = document.getElementsByName('check');
  831:         for (var i = 0; i < checkboxes.length; i++) {
  832:             checkboxes[i].checked = "";
  833:         }
  834:     }
  835: 
  836: JAVASCRIPT
  837:    return $js;
  838: }
  839: 
  840: 
  841: # HTML-Markup for table if in view-mode
  842: my $wishlistHTMLview;
  843: my $indent = $indentConst;
  844: sub wishlistView {
  845:     my $nodes = shift;
  846: 
  847:     foreach my $n (@$nodes) {
  848:         my $index = $n->value()->nindex();
  849: 
  850:         # start row, use data_table routines to set class to LC_even or LC_odd automatically. this row contains a checkbox, the title and the note-icon.
  851:         # only display the top level entries on load
  852:         $wishlistHTMLview .= ($n->parent()->value() eq 'root')?&Apache::loncommon::start_data_table_row('','row'.$index)
  853:                                                               :&Apache::loncommon::continue_data_table_row('LC_hidden','row'.$index);
  854: 
  855:  
  856:         # checkboxes
  857:         $wishlistHTMLview .= '<td><input type="checkbox" name="mark" id="check'.$index.'" value="'.$index.'" '.
  858:                              'onclick="selectAction('."'row".$index."'".')"/></td>';
  859: 
  860:         # entry is a folder
  861:         if ($n->value()->path() eq '') {
  862:             $wishlistHTMLview .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;">'.
  863:                                  '<a href="javascript:;" onclick="folderAction('."'row".$index."'".')" style="vertical-align:top">'.
  864:                                  '<img src="/adm/lonIcons/arrow.closed.gif" id="img'.$index.'" alt = "" class="LC_icon"/>'.
  865:                                  '<img src="/adm/lonIcons/navmap.folder.closed.gif" id="imgFolder'.$index.'" alt="folder"/>'.
  866:                                  $n->value()->title().'</a></td>';
  867:         }
  868:         # entry is a link
  869:         else {
  870:             $wishlistHTMLview .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px; min-width: 220px;">'.
  871:                                  '<a href="javascript:preview('."'".$n->value()->path()."'".');">'.
  872:                                  '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link" />'.
  873:                                  $n->value()->title().'</a></td>';
  874:         }
  875: 
  876:         # note-icon, different icons for an entries with note and those without
  877:         my $noteIMG = 'anot.png';
  878: 
  879:         if ($n->value()->note() ne '') {
  880:             $noteIMG = 'anot2.png';
  881:         }
  882: 
  883:         $wishlistHTMLview .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
  884:                              '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
  885:                              ' class="LC_icon"/></a></td>';
  886: 
  887:         $wishlistHTMLview .= &Apache::loncommon::end_data_table_row();
  888: 
  889:         # start row containing the textarea for the note, do not display note on default
  890:         $wishlistHTMLview .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
  891:                              '<td></td><td>'.
  892:                              '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
  893:                              'name="newnote" >'.
  894:                              $n->value()->note().'</textarea></td><td></td>';
  895:         $wishlistHTMLview .= &Apache::loncommon::end_data_table_row();
  896: 
  897:         # if the entry is a folder, it could have other entries as content. if it has, call wishlistView for those entries 
  898:         my @children = $n->children();
  899:         if ($#children >=0) {
  900:             $indent += 20;
  901:             &wishlistView(\@children);
  902:             $indent -= 20;
  903:         }
  904:     }
  905: }
  906: 
  907: 
  908: # HTML-Markup for table if in edit-mode
  909: my $wishlistHTMLedit;
  910: my $indent = $indentConst;
  911: sub wishlistEdit {
  912:     my $nodes = shift;
  913:     my $curNode = 1;
  914: 
  915:     foreach my $n (@$nodes) {
  916:         my $index = $n->value()->nindex();
  917: 
  918:         # start row, use data_table routines to set class to LC_even or LC_odd automatically.
  919:         # this rows contains a checkbox, a select-field for sorting entries, the title in an input-field and the note-icon.
  920:         # only display the top level entries on load
  921:         $wishlistHTMLedit .= ($n->parent()->value() eq 'root')?&Apache::loncommon::start_data_table_row('','row'.$index)
  922:                                                               :&Apache::loncommon::continue_data_table_row('LC_hidden','row'.$index);
  923: 
  924:         # checkboxes
  925:         $wishlistHTMLedit .= '<td><input type="checkbox" name="mark" id="check'.$index.'" value="'.$index.'" '.
  926:                              'onclick="selectAction('."'row".$index."'".')"/></td>';
  927: 
  928:         # option-tags for sorting entries. we need the numbers from 1 to n with n being the number of entries on the same level as the current entry.
  929:         # set the number for the current entry into brackets 
  930:         my $options;
  931:         for (my $i = 1; $i < ((scalar @{$nodes})+1); $i++) {
  932:            if ($i == $curNode) {
  933:                $options .= '<option selected="selected" value="">('.$i.')</option>';
  934:            }
  935:            else {
  936:                $options .= '<option value="'.$i.'">'.$i.'</option>';
  937:            }
  938:         }
  939:         $curNode++;
  940: 
  941:         # entry is a folder
  942:         if ($n->value()->path() eq '') {
  943:             $wishlistHTMLedit .= '<td><select class="LC_hidden" name="sel" id="sel'.$index.'" onchange="submitSelect();">'.
  944:                                  $options.'</select></td>'.
  945:                                  '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px;">'.
  946:                                  '<a href="javascript:;" onclick="folderAction('."'row".$index."'".')" style="vertical-align:top" >'.
  947:                                  '<img src="/adm/lonIcons/arrow.closed.gif" id="img'.$index.'" alt = ""  class="LC_icon"/>'.
  948:                                  '<img src="/adm/lonIcons/navmap.folder.closed.gif" id="imgFolder'.$index.'" alt="folder"/></a>';
  949: 
  950:         }
  951:         # entry is a link
  952:         else {
  953:             $wishlistHTMLedit .= '<td><select class="LC_hidden" name="sel" id="sel'.$index.'" onchange="submitSelect();">'.
  954:                                  $options.'</select></td>'.
  955:                                  '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px;">'.
  956:                                  '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link"/>';
  957:         }
  958: 
  959:         # input-field for title
  960:         $wishlistHTMLedit .= '<input type="text" name="newtitle" value="'.$n->value()->title().'" alt = "'.$n->value()->title().'"/></td>';
  961: 
  962:         # note-icon, different icons for an entries with note and those without
  963:         my $noteIMG = 'anot.png';
  964: 
  965:         if ($n->value()->note() ne '') {
  966:             $noteIMG = 'anot2.png';
  967:         }
  968: 
  969:         $wishlistHTMLedit .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
  970:                              '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
  971:                              ' class="LC_icon"/></a></td>';
  972: 
  973:         $wishlistHTMLedit .= &Apache::loncommon::end_data_table_row();
  974: 
  975:         # start row containing the textarea for the note
  976:         $wishlistHTMLedit .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
  977:                              '<td></td><td></td><td>'.
  978:                              '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
  979:                              'name="newnote">'.
  980:                              $n->value()->note().'</textarea></td><td></td>';
  981:         $wishlistHTMLedit .= &Apache::loncommon::end_data_table_row();
  982: 
  983:         # if the entry is a folder, it could have other entries as content. if it has, call wishlistEdit for those entries 
  984:         my @children = $n->children();
  985:         if ($#children >=0) {
  986:             $indent += 20;
  987:             &wishlistEdit(\@children);
  988:             $indent -= 20;
  989:         }
  990:     }
  991: }
  992: 
  993: 
  994: 
  995: # HTML-Markup for table if in move-mode
  996: my $wishlistHTMLmove ='<tr id="root" class="LC_odd_row"><td><input type="radio" name="mark" id="radioRoot" value="root" /></td>'.
  997:                       '<td>'.&mt('Top level').'</td><td></td></tr>';
  998: my $indent = $indentConst;
  999: sub wishlistMove {
 1000:     my $nodes = shift;
 1001:     my $marked = shift;
 1002: 
 1003:     foreach my $n (@$nodes) {
 1004:         my $index = $n->value()->nindex();
 1005: 
 1006:         #find out wether the current entry was marked to be moved.
 1007:         my $isIn = 0;
 1008:         foreach my $m (@$marked) {
 1009:             if ($index == $m) {
 1010:                $isIn = 1;
 1011:             }
 1012:         }
 1013:         # start row and set class for even or odd row. this rows contains the title and the note-icon and can contain a radio-button
 1014:         $wishlistHTMLmove .= &Apache::loncommon::start_data_table_row('','row'.$index);
 1015: 
 1016: 
 1017:         # entry is a folder
 1018:         if ($n->value()->path() eq '') {
 1019:             # display a radio-button, if the folder was not selected to be moved
 1020:             if (!$isIn) {
 1021:                 $wishlistHTMLmove .= '<td><input type="radio" name="mark" id="radio'.$index.'" value="'.$index.'" /></td>'.
 1022:                                      '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;">';
 1023:             }
 1024:             # higlight the title, if the folder was selected to be moved
 1025:             else {
 1026:                 $wishlistHTMLmove .= '<td></td>'.
 1027:                                      '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;'.
 1028:                                      'color:red;">';
 1029:             }
 1030:             #arrow- and folder-image, all folders are open, and title
 1031:             $wishlistHTMLmove .= '<img src="/adm/lonIcons/arrow.open.gif" id="img'.$index.'" alt = "" />'.
 1032:                                  '<img src="/adm/lonIcons/navmap.folder.open.gif" id="imgFolder'.$index.'" alt="folder"/>'.
 1033:                                  $n->value()->title().'</td>';
 1034:         }
 1035:         # entry is a link
 1036:         else {
 1037:             # higlight the title, if the link was selected to be moved
 1038:             my $highlight = '';
 1039:             if ($isIn) {
 1040:                $highlight = 'style="color:red;"';
 1041:             }
 1042:             # link-image and title
 1043:             $wishlistHTMLmove .= '<td></td>'.
 1044:                                  '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px; min-width: 220px;">'.
 1045:                                  '<a href="javascript:preview('."'".$n->value()->path()."'".');" '.$highlight.'>'.
 1046:                                  '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link"/>'.
 1047:                                  $n->value()->title().'</a></td>';
 1048:         }
 1049: 
 1050:         # note-icon, different icons for an entries with note and those without
 1051:         my $noteIMG = 'anot.png';
 1052: 
 1053:         if ($n->value()->note() ne '') {
 1054:             $noteIMG = 'anot2.png';
 1055:         }
 1056: 
 1057:         $wishlistHTMLmove .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
 1058:                              '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
 1059:                              ' class="LC_icon"/></a></td>';
 1060: 
 1061:         $wishlistHTMLmove .= &Apache::loncommon::end_data_table_row();
 1062: 
 1063:         # start row containing the textarea for the note, readonly in move-mode
 1064:         $wishlistHTMLmove .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
 1065:                              '<td></td><td>'.
 1066:                              '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
 1067:                              'name="newnote" readonly="readonly">'.
 1068:                              $n->value()->note().'</textarea></td><td></td>'.
 1069:                              &Apache::loncommon::end_data_table_row();
 1070: 
 1071:         # if the entry is a folder, it could have other entries as content. if it has, call wishlistMove for those entries 
 1072:         my @children = $n->children();
 1073:         if ($#children >=0) {
 1074:             $indent += 20;
 1075:             &wishlistMove(\@children, $marked);
 1076:             $indent -= 20;
 1077:         }
 1078:     }
 1079: }
 1080: 
 1081: 
 1082: 
 1083: # HTML-Markup for table if in import-mode
 1084: my $wishlistHTMLimport;
 1085: my $indent = $indentConst;
 1086: my $form = 1;
 1087: sub wishlistImport {
 1088:     my $nodes = shift;
 1089: 
 1090:     foreach my $n (@$nodes) {
 1091:         my $index = $n->value()->nindex();
 1092: 
 1093:         # start row, use data_table routines to set class to LC_even or LC_odd automatically. this row contains a checkbox, the title and the note-icon.
 1094:         # only display the top level entries on load
 1095:         $wishlistHTMLimport .= ($n->parent()->value() eq 'root')?&Apache::loncommon::start_data_table_row('','row'.$index)
 1096:                                                                 :&Apache::loncommon::continue_data_table_row('LC_hidden','row'.$index);
 1097: 
 1098:  
 1099:         # checkboxes
 1100:         $wishlistHTMLimport .= '<td>'.
 1101:                                '<input type="checkbox" name="check" id="check'.$index.'" value="'.$index.'" '.
 1102:                                'onclick="selectAction('."'row".$index."'".')"/>'.
 1103:                                '<input type="hidden" name="title'.$index.'" value="'.&escape($n->value()->title()).'">'.
 1104:                                '<input type="hidden" name="filelink'.$index.'" value="'.&escape($n->value()->path()).'">'.
 1105:                                '<input type="hidden" name="id'.$index.'">'.
 1106:                                '</td>';
 1107: 
 1108:         # entry is a folder
 1109:         if ($n->value()->path() eq '') {
 1110:             $wishlistHTMLimport .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;">'.
 1111:                                    '<a href="javascript:;" onclick="folderAction('."'row".$index."'".')" style="vertical-align:top">'.
 1112:                                    '<img src="/adm/lonIcons/arrow.closed.gif" id="img'.$index.'" alt = "" class="LC_icon"/>'.
 1113:                                    '<img src="/adm/lonIcons/navmap.folder.closed.gif" id="imgFolder'.$index.'" alt="folder"/>'.
 1114:                                    $n->value()->title().'</a></td>';
 1115:         }
 1116:         # entry is a link
 1117:         else {
 1118:             $wishlistHTMLimport .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px; min-width: 220px;">'.
 1119:                                    '<a href="javascript:preview('."'".$n->value()->path()."'".');">'.
 1120:                                    '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link" />'.
 1121:                                    $n->value()->title().'</a></td>';
 1122:                                    $form++;
 1123:         }
 1124: 
 1125:         # note-icon, different icons for an entries with note and those without
 1126:         my $noteIMG = 'anot.png';
 1127: 
 1128:         if ($n->value()->note() ne '') {
 1129:             $noteIMG = 'anot2.png';
 1130:         }
 1131: 
 1132:         $wishlistHTMLimport .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
 1133:                              '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
 1134:                              ' class="LC_icon"/></a></td>';
 1135: 
 1136:         $wishlistHTMLimport .= &Apache::loncommon::end_data_table_row();
 1137: 
 1138:         # start row containing the textarea for the note, do not display note on default, readonly in import-mode
 1139:         $wishlistHTMLimport .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
 1140:                              '<td></td><td>'.
 1141:                              '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
 1142:                              'name="newnote" readonly="readonly">'.
 1143:                              $n->value()->note().'</textarea></td><td></td>';
 1144:         $wishlistHTMLimport .= &Apache::loncommon::end_data_table_row();
 1145: 
 1146:         # if the entry is a folder, it could have other entries as content. if it has, call wishlistImport for those entries 
 1147:         my @children = $n->children();
 1148:         if ($#children >=0) {
 1149:             $indent += 20;
 1150:             &wishlistImport(\@children);
 1151:             $indent -= 20;
 1152:         }
 1153:     }
 1154: }
 1155: 
 1156: # Returns the HTML-Markup for wishlist
 1157: sub makePage {
 1158:     my $mode = shift;
 1159:     my $marked = shift;
 1160: 
 1161:     # breadcrumbs and start_page
 1162:     &Apache::lonhtmlcommon::clear_breadcrumbs();
 1163:     &Apache::lonhtmlcommon::add_breadcrumb(
 1164:               { href => '/adm/wishlist?mode='.$mode,
 1165:                 text => 'Wishlist'});
 1166:     my $startPage = &Apache::loncommon::start_page('Wishlist',undef,
 1167:                                                      {'add_entries' => {
 1168:                                                         'onload' => 'javascript:onLoadAction('."'".$mode."'".');',
 1169:                                                         'onunload' => 'javascript:window.name = '."'loncapaclient'"}});
 1170: 
 1171:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Wishlist '.
 1172:                            '<a title="Online-Hilfe" href="/adm/help/Wishlist.hlp" target="_top">'.
 1173:                            '<img src="/adm/help/help.png" alt="'.&mt('Help').'" '.
 1174:                            'title="'.&mt('Help').'" class="LC_icon" /></a>');
 1175: 
 1176:     # get javascript-code for wishlist-interactions
 1177:     my $js = &JSforWishlist();
 1178: 
 1179:     # texthash for items in funtionlist
 1180:     my %lt = &Apache::lonlocal::texthash(
 1181:                  'ed' => 'Edit',
 1182:                  'vw' => 'View',
 1183:                  'al' => 'Add Link',
 1184:                  'af' => 'Add Folder',
 1185:                  'mv' => 'Move Selected',
 1186:                  'dl' => 'Delete Selected',
 1187:                  'sv' => 'Save');
 1188: 
 1189:     # start functionlist
 1190:     my $functions = &Apache::lonhtmlcommon::start_funclist();
 1191: 
 1192:     # icon for edit-mode, display when in view-mode
 1193:     if ($mode eq 'view') {
 1194:         $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
 1195:                           'onclick="setFormAction('."'save','edit'".'); list.submit();" class="LC_menubuttons_link">'.
 1196:                           '<img src="/res/adm/pages/edit-mode-22x22.png" alt="'.$lt{'ed'}.'" '.
 1197:                           'title="'.$lt{'ed'}.'" class="LC_icon"/> '.
 1198:                           '<span class="LC_menubuttons_inline_text">'.$lt{'ed'}.'</span></a>');
 1199:     }
 1200:     # icon for view-mode, display when in edit-mode
 1201:     else {
 1202:         $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
 1203:                           'onclick="setFormAction('."'save','view'".'); list.submit();" class="LC_menubuttons_link">'.
 1204:                           '<img src="/res/adm/pages/view-mode-22x22.png" alt="'.$lt{'vw'}.'" '.
 1205:                           'title="'.$lt{'vw'}.'" class="LC_icon"/> '.
 1206:                           '<span class="LC_menubuttons_inline_text">'.$lt{'vw'}.'</span></a>');
 1207:     }
 1208:     
 1209:     # icon for adding a new link
 1210:     $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
 1211:                       'onclick="newLink();" class="LC_menubuttons_link">'.
 1212:                       '<img src="/res/adm/pages/link-new-22x22.png" alt="'.$lt{'al'}.'" '.
 1213:                       'title="'.$lt{'al'}.'" class="LC_icon"/>'.
 1214:                       '<span class="LC_menubuttons_inline_text">'.$lt{'al'}.'</span></a>');
 1215: 
 1216:     # icon for adding a new folder
 1217:     $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
 1218:                       'onclick="newFolder();" class="LC_menubuttons_link">'.
 1219:                       '<img src="/res/adm/pages/folder-new-22x22.png" alt="'.$lt{'af'}.'" '.
 1220:                       'title="'.$lt{'af'}.'" class="LC_icon"/>'.
 1221:                       '<span class="LC_menubuttons_inline_text">'.$lt{'af'}.'</span></a>');
 1222: 
 1223:     # icon for moving entries
 1224:     $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
 1225:                       'onclick="setFormAction('."'move','move'".'); " class="LC_menubuttons_link">'.
 1226:                       '<img src="/res/adm/pages/move-22x22.png" alt="'.$lt{'mv'}.'" '.
 1227:                       'title="'.$lt{'mv'}.'" class="LC_icon" />'.
 1228:                       '<span class="LC_menubuttons_inline_text">'.$lt{'mv'}.'</span></a>');
 1229: 
 1230:     # icon for deleting entries
 1231:     $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
 1232:                       'onclick="setFormAction('."'delete','".$mode."'".'); " class="LC_menubuttons_link">'.
 1233:                       '<img src="/res/adm/pages/del.png" alt="'.$lt{'dl'}.'" '.
 1234:                       'title="'.$lt{'dl'}.'" class="LC_icon" />'.
 1235:                       '<span class="LC_menubuttons_inline_text">'.$lt{'dl'}.'</span></a>');
 1236: 
 1237:     # icon for saving changes
 1238:     $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
 1239:                       'onclick="setFormAction('."'','".$mode."'".'); " class="LC_menubuttons_link">'.
 1240:                       '<img src="/res/adm/pages/save-22x22.png" alt="'.$lt{'sv'}.'" '.
 1241:                       'title="'.$lt{'sv'}.'" class="LC_icon" />'.
 1242:                       '<span class="LC_menubuttons_inline_text">'.$lt{'sv'}.'</span></a>');
 1243: 
 1244:     # end funtionlist and generate subbox 
 1245:     $functions.= &Apache::lonhtmlcommon::end_funclist();
 1246:     my $subbox = &Apache::loncommon::head_subbox($functions);
 1247: 
 1248:     # start form 
 1249:     my $inner .= '<form name="list" action ="/adm/wishlist" method="post">'.
 1250:                  '<input type="hidden" id="action" name="action" value=""/>';
 1251:  
 1252:     # only display subbox in view- or edit-mode
 1253:     if ($mode eq 'view' || $mode eq 'edit') {
 1254:         $inner .= $subbox;
 1255:     }
 1256: 
 1257:     # generate table-content depending on mode
 1258:     if ($mode eq 'edit') {
 1259:         &wishlistEdit(\@childrenRt);
 1260:         if ($wishlistHTMLedit ne '') {
 1261:             $inner .= &Apache::loncommon::start_data_table("LC_tableOfContent");
 1262:             $inner .= $wishlistHTMLedit;
 1263:             $inner .= &Apache::loncommon::end_data_table();
 1264:         }
 1265:         else {
 1266:             $inner .= '<span class="LC_info">'.&mt("Your wishlist ist currently empty.").'</span>';
 1267:         }
 1268:         $wishlistHTMLedit = '';
 1269:     }
 1270:     elsif ($mode eq 'view') {
 1271:         &wishlistView(\@childrenRt);
 1272:         if ($wishlistHTMLview ne '') {
 1273:             $inner .= '<table class="LC_data_table LC_tableOfContent">'.$wishlistHTMLview.'</table>';
 1274:         }
 1275:         else {
 1276:             $inner .= '<span class="LC_info">'.&mt("Your wishlist ist currently empty.").'</span>';
 1277:         }
 1278:         $wishlistHTMLview = '';
 1279:     }
 1280:     else {
 1281:         my $markStr = '';
 1282:         foreach my $m (@$marked) {
 1283:             $markStr .= $m.',';
 1284:         }
 1285:         if ($markStr) {
 1286:             $markStr = substr($markStr, 0, length($markStr)-1);
 1287:             $inner .= '<input type="hidden" value="'.$markStr.'" name="markedToMove"/>';
 1288:             $inner .= '<p><span class="LC_info">'.&mt('You have selected the red marked entries to be moved to another folder. '.
 1289:                                                    'Now choose the new destination folder.').'</span></p>';
 1290:             &wishlistMove(\@childrenRt, $marked);
 1291:             $inner .= '<table class="LC_data_table LC_tableOfContent">'.$wishlistHTMLmove.'</table><br/><br/>';
 1292:             $inner .= '<input type="button" value="'.&mt('Move').'" onclick="setFormAction('."'','view'".'); selectDestinationFolder()"/>'.
 1293:                       '<input type="button" value="'.&mt('Cancel').'" onclick="go('."'/adm/wishlist'".')"/>';
 1294: 
 1295:             $wishlistHTMLmove ='<tr id="root" class="LC_odd_row"><td><input type="radio" name="mark" id="radioRoot" value="root" /></td>'.
 1296:                                '<td>'.&mt('Top level').'</td><td></td></tr>';
 1297:         }
 1298:         else {
 1299:             $inner .= '<p><span class="LC_info">'.&mt("You haven't marked any entry to move.").'</span></p>'.
 1300:                       '<input type="button" value="'.&mt('Back').'" onclick="go('."'/adm/wishlist'".')"/>';
 1301:         }
 1302:     }
 1303:     
 1304:     # end form 
 1305:     $inner .= '</form>';
 1306: 
 1307:     # end_page 
 1308:     my $endPage =  &Apache::loncommon::end_page();
 1309: 
 1310:     # put all page-elements together
 1311:     my $page = $startPage.$breadcrumbs.$js.$inner.$endPage;
 1312: 
 1313:     return $page;
 1314: }
 1315: 
 1316: 
 1317: # Returns the HTML-Markup for the page, shown when a link was set
 1318: sub makePageSet {
 1319:     # start_page 
 1320:     my $startPage = &Apache::loncommon::start_page('Wishlist',undef,
 1321:                                                    {'only_body' => 1});
 1322:     
 1323:     # confirm success and offer link to wishlist
 1324:     my $message = &Apache::lonhtmlcommon::confirm_success(&mt('Link successfully set!'));
 1325:     $message = &Apache::loncommon::confirmwrapper($message);
 1326: 
 1327:     my $inner .= '<br>'.$message.'<br/><br/>'.
 1328:                  '<a href="javascript:;" onclick="opener.open('."'/adm/wishlist'".');window.close();">'.&mt('Go to wishlist').'</a>'.
 1329:                  '&nbsp;<a href="javascript:;" onclick="window.close();">'.&mt('Close this window').'</a>';
 1330: 
 1331:     # end_page 
 1332:     my $endPage =  &Apache::loncommon::end_page();
 1333: 
 1334:     # put all page-elements together
 1335:     my $page = $startPage.$inner.$endPage;
 1336: 
 1337:     return $page;
 1338: }
 1339: 
 1340: 
 1341: # Returns the HTML-Markup for the page, shown when links should be imported into a course
 1342: sub makePageImport {
 1343:     # start_page 
 1344:     my $startPage = &Apache::loncommon::start_page('Wishlist',undef,
 1345:                                                    {'only_body' => 1});
 1346:     
 1347:     # get javascript-code for wishlist-interactions
 1348:     my $js = &JSforWishlist();
 1349: 
 1350:     my $inner = '<h1>'.&mt('Import Resources from Wishlist').'</h1>';
 1351:     $inner .= '<p><span class="LC_info">'.&mt("Please note that you  can use the checkboxes corresponding to a folder to ".
 1352:                                               "easily check all links within this folder. The folder structure itself can't be imported. ".
 1353:                                               "All checked links will be imported into the current folder of your course.").'</span></p>';
 1354: 
 1355:     my %wishlist = &getWishlist();
 1356:     my $fnum = (keys %wishlist)-1;
 1357: 
 1358:     $inner .= '<form method="post" name="groupsort">'.
 1359:               '<input type="hidden" value="'.$fnum.'" name="fnum">'.
 1360:               '<input type="button" onclick="javascript:checkAll()" id="checkallbutton" value="'.&mt('Check All').'">'.
 1361:               '<input type="button" onclick="javascript:uncheckAll()" id="uncheckallbutton" value="'.&mt('Uncheck All').'">'.
 1362:               '<input type="button" value="'.&mt('Import Checked').'" onclick="finish_import();">'.    
 1363:               '<input type="button" value="'.&mt('Cancel').'" onclick="window.close();"><br/><br/>'; 
 1364: 
 1365:     
 1366:     # wishlist-table
 1367:     &wishlistImport(\@childrenRt);
 1368:     if ($wishlistHTMLimport ne '') {
 1369:         $inner .= '<table class="LC_data_table LC_tableOfContent">'.$wishlistHTMLimport.'</table>';
 1370:     }
 1371:     else {
 1372:         $inner .= '<span class="LC_info">'.&mt("Your wishlist ist currently empty.").'</span>';
 1373:     }
 1374:     $wishlistHTMLimport = '';
 1375: 
 1376:     $inner .= '</form>';
 1377: 
 1378:     # end_page 
 1379:     my $endPage =  &Apache::loncommon::end_page();
 1380: 
 1381:     # put all page-elements together
 1382:     my $page = $startPage.$js.$inner.$endPage;
 1383: 
 1384:     return $page;
 1385: }
 1386: 
 1387: 
 1388: # Returns the HTML-Markup for error-page
 1389: sub makeErrorPage {
 1390:     # breadcrumbs and start_page 
 1391:     &Apache::lonhtmlcommon::add_breadcrumb(
 1392:               { href => '/adm/wishlist',
 1393:                 text => 'Wishlist'});
 1394:     my $startPage = &Apache::loncommon::start_page('Wishlist');
 1395:     
 1396:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Wishlist '.
 1397:                            '<a title="Online-Hilfe" href="/adm/help/Wishlist.hlp" target="_top">'.
 1398:                            '<img src="/adm/help/help.png" alt="'.&mt('Help').'" '.
 1399:                            'title="'.&mt('Help').'" class="LC_icon" /></a>');
 1400:     &Apache::lonhtmlcommon::clear_breadcrumbs();
 1401: 
 1402:     # error-message
 1403:     my $inner .= '<span class="LC_error">'.&mt('An error occurred! Please try again later.').'</span>';
 1404: 
 1405:     # end_page 
 1406:     my $endPage =  &Apache::loncommon::end_page();
 1407: 
 1408:     # put all page-elements together
 1409:     my $page = $startPage.$breadcrumbs.$inner.$endPage;
 1410: 
 1411:     return $page;
 1412: }
 1413: 
 1414: # ----------------------------------------------------- Main Handler, package lonwishlist
 1415: sub handler {
 1416:     my ($r) = @_;
 1417:     &Apache::loncommon::content_type($r,'text/html');
 1418:     $r->send_http_header;
 1419: 
 1420:     if (&getWishlist() ne 'error') {
 1421:         # get wishlist entries from user-data db-file and build a tree out of these entries
 1422:         %TreeHash = &getWishlist();
 1423:         $root = &Tree::HashToTree();
 1424:         @childrenRt = $root->children();
 1425: 
 1426:         # greate a new entry
 1427:         if ($env{'form.title'}) {
 1428:            &newEntry($env{'form.title'}, $env{'form.path'}, $env{'form.note'});
 1429:         }
 1430: 
 1431:         # get unprocessed_cgi (i.e. marked entries, mode ...) 
 1432:         &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['action','mark','markedToMove','mode','newtitle','note']);
 1433: 
 1434:         # change the order of entries within a level, that means sorting the entries
 1435:         my $changeOrder = 0;
 1436:         if (defined $env{'form.sel'}) {
 1437:             my @sel = &Apache::loncommon::get_env_multiple('form.sel');
 1438:             my $indexNode;
 1439:             my $at;
 1440:             for (my $s=0; $s<($#sel+1); $s++) {
 1441:                 if ($sel[$s] ne '') {
 1442:                     $indexNode = $s;
 1443:                     $at = $sel[$s]-1;
 1444:                 }
 1445:             }
 1446:             if ($at ne '') {
 1447:                 $changeOrder = 1;
 1448:                 &sortEntries($indexNode,$at);
 1449:                 &saveChanges();
 1450:             }
 1451:         }
 1452: 
 1453:         # get all marked (checkboxes) entries
 1454:         my @marked = ();
 1455:         if (defined $env{'form.mark'}) {
 1456:             @marked = &Apache::loncommon::get_env_multiple('form.mark');
 1457:         }
 1458: 
 1459:         # move entries from one folder to another
 1460:         if (defined $env{'form.markedToMove'}) {
 1461:            my $markedToMove = $env{'form.markedToMove'};
 1462:            my @ToMove = split(/\,/,$markedToMove);
 1463:            my $moveTo = $env{'form.mark'};
 1464:            if (defined $moveTo){ 
 1465:                &moveEntries(\@ToMove,$moveTo);
 1466:                &saveChanges();
 1467:            }
 1468:            $changeOrder = 1;
 1469:     
 1470:         }
 1471: 
 1472:         # delete entries
 1473:         if ($env{'form.action'} eq 'delete') {
 1474:             &deleteEntries(\@marked);
 1475:         }
 1476:    
 1477: 
 1478:         # get all titles and notes and save them
 1479:         # only save, if user wants to save changes
 1480:         # do not save, when current action is 'delete' or 'sort' or 'move' 
 1481:         my @newTitles = ();
 1482:         my @newNotes = ();
 1483:         if ((defined $env{'form.newtitle'} || defined $env{'form.newnote'}) && ($env{'form.action'} ne 'noSave') && ($env{'form.action'} ne 'delete') && !$changeOrder) {
 1484:             @newTitles = &Apache::loncommon::get_env_multiple('form.newtitle');
 1485:             @newNotes = &Apache::loncommon::get_env_multiple('form.newnote');
 1486:             my $node = 0;
 1487:             foreach my $t (@newTitles) {
 1488:                &setNewTitle($node, $t);
 1489:                $node++;
 1490:             }
 1491:             $node = 0;
 1492:             foreach my $n (@newNotes) {
 1493:                &setNewNote($node, $n);
 1494:                $node++;
 1495:             }
 1496:             &saveChanges();
 1497:         }
 1498: 
 1499:         # Create HTML-markup
 1500:         my $page;
 1501:         if ($env{'form.mode'} eq 'edit') {
 1502:             $page = &makePage("edit");
 1503:         }
 1504:         elsif ($env{'form.mode'} eq 'move') {
 1505:             $page = &makePage("move", \@marked);
 1506:         }
 1507:         elsif ($env{'form.mode'} eq 'import') {
 1508:             $page = &makePageImport();
 1509:         }
 1510:         elsif ($env{'form.mode'} eq 'set') {
 1511:             $page = &makePageSet();
 1512:         }
 1513:         else {
 1514:             $page = &makePage("view");
 1515:         }
 1516:         @marked = ();
 1517:         $r->print($page);
 1518:     }
 1519:     # An error occured, print an error-page
 1520:     else {
 1521:         my $errorPage = &makeErrorPage();
 1522:         $r->print($errorPage);
 1523:     }
 1524:     return OK;
 1525: }
 1526: 
 1527: # ----------------------------------------------------- package Tree
 1528: # Extend CPAN-Module Tree by function like 'moveNode' or 'deleteNode'
 1529: package Tree;
 1530: 
 1531: # returns the node with a given index from a list of nodes
 1532: sub getNodeByIndex {
 1533:     my $index = shift;
 1534:     my $nodes = shift;
 1535:     my $found;
 1536:     
 1537:     for my $n (@$nodes) {
 1538:         my $curIndex = $n->value()->nindex();
 1539:         if ($n->value()->nindex() == $index) {
 1540:             $found = $n;
 1541:         }
 1542:     }
 1543:     return $found;
 1544: }
 1545: 
 1546: # moves a given node to a new parent or change the position from a node
 1547: # within its siblings (sorting)
 1548: sub moveNode {
 1549:     my $node = shift;
 1550:     my $at = shift;
 1551:     my $newParent = shift;
 1552: 
 1553: 
 1554:     if (!$newParent) {
 1555:         $newParent = $node->parent();
 1556:     }
 1557: 
 1558:     $node->parent()->remove_child($node);
 1559: 
 1560:     if (defined $at) {
 1561:         $newParent->add_child({at => $at},$node);
 1562:     }
 1563:     else {
 1564:         $newParent->add_child($node);
 1565:     }
 1566:     
 1567:     # updating root's children
 1568:     @childrenRt = $root->children();
 1569: }
 1570: 
 1571: # removes a given node
 1572: sub removeNode() {
 1573:     my $node = shift;
 1574:     my @children = $node->children();
 1575: 
 1576:     if ($#children >= 0) {
 1577:         foreach my $c (@children) {
 1578:             &removeNode($c);
 1579:         }
 1580:     }
 1581:     $node->parent()->remove_child($node);
 1582: 
 1583:     # updating root's children
 1584:     @childrenRt = $root->children();
 1585: }
 1586: 
 1587: 
 1588: # set an index for every node in the tree, beginning with 0
 1589: my $count = 0;
 1590: sub TreeIndex {
 1591:     my $children = shift;
 1592: 
 1593:     foreach my $n (@$children) {
 1594:         my @children = $n->children();
 1595:         $n->value()->nindex($count);$count++;
 1596: 
 1597:         if ($#children>=0) {
 1598:             &TreeIndex(\@children);
 1599:         }
 1600:     }
 1601: }
 1602: 
 1603: # reset index counter
 1604: sub setCountZero {
 1605:     $count = 0;
 1606: }
 1607: 
 1608: 
 1609: # convert the tree to a hash
 1610: # each node is one hash-entry
 1611: # keys are the indices, values are all other attributes
 1612: # (containing tile, path, note, date and indices for all direct children)
 1613: # except for root: the key is root and values are
 1614: # just the indices of root's children
 1615: sub RootToHash {
 1616:     my $childrenRt = shift;
 1617:     my @indexarr = ();
 1618: 
 1619:     foreach my $c (@$childrenRt) {
 1620:        push (@indexarr, $c->value()->nindex());
 1621:     }
 1622:     $TreeToHash{'root'} = [@indexarr];
 1623: }
 1624: 
 1625: sub TreeToHash {
 1626:     my $childrenRt = shift;
 1627: 
 1628:     foreach my $n (@$childrenRt) {
 1629:         my @arrtmp = ();
 1630:         $arrtmp[0] = $n->value()->title();
 1631:         $arrtmp[1] = $n->value()->path();
 1632:         $arrtmp[2] = $n->value()->note();
 1633:         $arrtmp[3] = $n->value()->date();
 1634:         my @childrenRt = $n->children();
 1635:         my $co = 4;
 1636:         foreach my $c (@childrenRt) {
 1637:             my $i = $c->value()->nindex();
 1638:             $arrtmp[$co] = $i;
 1639:             $co++;
 1640:         }
 1641:         $TreeToHash{$n->value()->nindex} = [ @arrtmp]; 
 1642:         if ($#childrenRt>=0) {
 1643:             &TreeToHash(\@childrenRt);
 1644:         }
 1645:     }
 1646: }
 1647: 
 1648: 
 1649: # convert the hash to a tree
 1650: # build a tree-object for each entry in the hash
 1651: # afterwards call &buildTree to connect the tree-objects
 1652: sub HashToTree {
 1653:     my @TreeNodes = ();
 1654:     my $root;
 1655: 
 1656:     foreach my $key (keys %TreeHash) {
 1657:         if ($key eq 'root') {
 1658:             $root = Tree->new("root");
 1659:         }
 1660:         else {
 1661:         my @attributes = @{ $TreeHash{$key} };
 1662:         my $tmpNode;
 1663:             $tmpNode = Tree->new(Entry->new(title=>$attributes[0],
 1664:                                             path=>$attributes[1],
 1665:                                             note=>$attributes[2],
 1666:                                             date=>$attributes[3],
 1667:                                             nindex=>$key));
 1668:         push(@TreeNodes, $tmpNode);
 1669:         # shift all attributes except for
 1670:         # the indices representing the children of a node
 1671:         shift(@attributes);
 1672:         shift(@attributes);
 1673:         shift(@attributes);
 1674:         shift(@attributes);
 1675:         $TreeHash{$key} = [ @attributes ];
 1676:         }
 1677:     }
 1678:     # if there are nodes, build up the tree-structure
 1679:     if (defined $TreeHash{'root'} && $TreeHash{'root'} ne '') {
 1680:         my @childrenRtIn = @{ $TreeHash{'root'} };
 1681:         &buildTree(\$root, \@childrenRtIn,\@TreeNodes,\%TreeHash);
 1682:     }
 1683:     return $root; 
 1684: }
 1685: 
 1686: 
 1687: # join the nodes to a tree
 1688: sub buildTree {
 1689:     my ($node, $childrenIn, $TreeNodes, $TreeHash) = @_;
 1690:     bless($node, 'Tree');
 1691:     foreach my $c (@$childrenIn) {
 1692:         my $tmpNode =  &getNodeByIndex($c,$TreeNodes);
 1693:         $$node->add_child($tmpNode);
 1694:         my @childrenIn = @{ $$TreeHash{$tmpNode->value()->nindex()} };
 1695:         &buildTree(\$tmpNode,\@childrenIn,$TreeNodes,$TreeHash);
 1696:     }
 1697: 
 1698: }
 1699: 
 1700: 
 1701: # ----------------------------------------------------- package Entry
 1702: # package that defines the entrys a wishlist could have
 1703: # i.e. folders and links
 1704: package Entry;
 1705: 
 1706: # constructor
 1707: sub new {
 1708:     my $invocant = shift;
 1709:     my $class = ref($invocant) || $invocant;
 1710:     my $self = { @_ }; #set attributes
 1711:     bless($self, $class);
 1712:     return $self;    
 1713: }
 1714: 
 1715: # getter and setter
 1716: sub title {
 1717:     my $self = shift;
 1718:     if ( @_ ) { $self->{title} = shift}
 1719:     return $self->{title};
 1720: }
 1721: 
 1722: sub date {
 1723:     my $self = shift;
 1724:     if ( @_ ) { $self->{date} = shift}
 1725:     return $self->{date};
 1726: }
 1727: 
 1728: sub note {
 1729:     my $self = shift;
 1730:     if ( @_ ) { $self->{note} = shift}
 1731:     return $self->{note};
 1732: }
 1733: 
 1734: sub path {
 1735:     my $self = shift;
 1736:     if ( @_ ) { $self->{path} = shift}
 1737:     return $self->{path};
 1738: }
 1739: 
 1740: sub nindex {
 1741:     my $self = shift;
 1742:     if ( @_ ) { $self->{nindex} = shift}
 1743:     return $self->{nindex};
 1744: }
 1745: 
 1746: 
 1747: 1;
 1748: __END__

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>