Annotation of loncom/interface/lonwishlist.pm, revision 1.1

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

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