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

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

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