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

1.1       wenzelju    1: # The LearningOnline Network with CAPA
                      2: # Routines to control the wishlist
                      3: #
1.7     ! wenzelju    4: # $Id: lonwishlist.pm,v 1.6 2010/08/20 08:13:41 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: 
1.4       wenzelju   29: =pod
1.1       wenzelju   30: 
1.4       wenzelju   31: =head1 NAME
                     32: 
                     33: Apache::lonwishlist - Wishlist-Module
                     34:   
                     35: =head1 SYNOPSIS
                     36: 
                     37: The wishlist offers a possibility to store links to resources from the resource-pool and external websites in a hierarchical list.
                     38: It is only available for user with access to the resource-pool. The list can be structured by folders.
                     39: 
                     40: The wishlist-module uses the CPAN-module "Tree" for easily handling the directory-structure of the wishlist. Each node in the tree has an index to be referenced by.
                     41: 
                     42: =cut
1.1       wenzelju   43: 
                     44: package Apache::lonwishlist;
                     45: 
                     46: use strict;
                     47: use Apache::Constants qw(:common);
                     48: use Apache::lonnet;
                     49: use Apache::loncommon();
                     50: use Apache::lonhtmlcommon;
                     51: use Apache::lonlocal;
1.2       wenzelju   52: use LONCAPA;
1.1       wenzelju   53: use Tree;
                     54: 
                     55: 
                     56: # Global variables
                     57: my $root;
                     58: my @childrenRt;
                     59: my %TreeHash;
                     60: my %TreeToHash;
                     61: my @allFolders;
                     62: my @allNodes;
                     63: my $indentConst = 20;
                     64: 
1.4       wenzelju   65: =pod
                     66: 
                     67: =head2 Routines for getting and putting the wishlist data from and accordingly to users data.
                     68: 
                     69: =over 4
                     70: 
                     71: =item * &getWishlist()
                     72: 
                     73:      Get the wishlist-data via lonnet::dump() and returns the got data in a hash.
                     74: 
                     75: 
                     76: =item * &putWishlist(wishlist)
                     77: 
                     78:      Parameter is a reference to a hash. Puts the wishlist-data contained in the given hash via lonnet::put() to user-data.
                     79: 
                     80: 
                     81: =item * &deleteWishlist()
                     82: 
                     83:      Deletes all entries from the user-data for wishlist. Do this before putting in new data.
                     84: 
                     85: 
                     86: =back
                     87: 
                     88: =cut
                     89: 
1.1       wenzelju   90: 
                     91: # Read wishlist from user-data
                     92: sub getWishlist {
1.2       wenzelju   93:     my %wishlist = &Apache::lonnet::dump('wishlist');
                     94:     foreach my $i ( keys %wishlist) {
1.1       wenzelju   95:         #File not found. This appears at the first time using the wishlist
                     96:         #Create file and put 'root' into it
                     97:        if ($i =~m/^error:No such file/) {
                     98:            &Apache::lonnet::logthis($i.'! Create file by putting in the "root" of the directory tree.');
                     99:            &Apache::lonnet::put('wishlist', {'root' => ''});
1.2       wenzelju  100:            %wishlist = &Apache::lonnet::dump('wishlist');
1.1       wenzelju  101:        }
                    102:        elsif ($i =~ /^(con_lost|error|no_such_host)/i) {
                    103:            &Apache::lonnet::logthis('ERROR while attempting to get wishlist: '.$i);
                    104:            return 'error';
                    105:        }
                    106:     }
                    107: 
1.2       wenzelju  108:     # if we got no keys in hash returned by dump(), return error.
                    109:     # wishlist will not be loaded, instead the user will be asked to try again later
1.1       wenzelju  110:     if ((keys %wishlist) == 0) {
                    111:         &Apache::lonnet::logthis('ERROR while attempting to get wishlist: no keys retrieved!');
                    112:         return 'error';
                    113:     }
                    114:     
                    115:     return %wishlist;
                    116: }
                    117: 
                    118: 
                    119: # Write wishlist to user-data
                    120: sub putWishlist {
                    121:     my $wishlist = shift;
                    122:     &Apache::lonnet::put('wishlist',$wishlist);
                    123: }
                    124: 
                    125: 
                    126: # Removes all existing entrys for wishlist in user-data
                    127: sub deleteWishlist {
                    128:     my @wishlistkeys = &Apache::lonnet::getkeys('wishlist');
                    129:     my %wishlist = &Apache::lonnet::del('wishlist',\@wishlistkeys);
                    130: }
                    131: 
                    132: 
1.4       wenzelju  133: =pod
                    134: 
                    135: =head2 Routines for changing the directory struture of the wishlist.
                    136: 
                    137: =over 4
                    138: 
                    139: =item * &newEntry(title, path, note)
                    140: 
                    141:      Creates a new entry in the wishlist containing the given informations. Additionally saves the date of creation in the entry.  
                    142: 
                    143: 
                    144: =item * &deleteEntries(marked)
                    145: 
                    146:      Parameter is a reference to an array containing the indices of all nodes that should be removed from the tree. 
                    147: 
                    148: 
                    149: =item * &sortEntries(indexNode, at)
                    150: 
                    151:      Changes the position of a node given by indexNode within its siblings. New position is given by at.
                    152: 
                    153: 
                    154: =item * &moveEntries(indexNodesToMove, indexParent)
                    155: 
                    156:      Parameter is a reference to an array containing the indices of all nodes that should be moved. indexParent specifies the node that will become the new Parent for these nodes. 
                    157: 
                    158: 
                    159: =item * &setNewTitle(nodeindex, newTitle)
                    160: 
                    161:      Sets the title for the node given by nodeindex to newTitle.
                    162: 
                    163: 
                    164: =item * &setNewPath(nodeindex, newPath)
                    165: 
                    166:      Sets the path for the node given by nodeindex to newPath.
                    167: 
                    168: 
                    169: =item * &setNewNote(nodeindex, newNote)
                    170: 
                    171:      Sets the note for the node given by nodeindex to newNote.     
                    172: 
                    173: 
                    174: =item * &saveChanges()
                    175: 
                    176:      Prepares the wishlist-hash to save it via &putWishlist(wishlist).   
                    177: 
                    178: 
                    179: =back
                    180: 
                    181: =cut
                    182: 
                    183: 
1.1       wenzelju  184: # Create a new entry
                    185: sub newEntry() {
                    186:     my ($title, $path, $note) = @_;
                    187:     my $date = gmtime();
                    188:     # Create Entry-Object
                    189:     my $entry = Entry->new(title => $title, path => $path, note => $note, date => $date);
                    190:     # Create Tree-Object, this correspones a node in the wishlist-tree
                    191:     my $tree = Tree->new($entry);
                    192:     # Add this node to wishlist-tree
                    193:     my $folderIndex = $env{'form.folders'};
                    194:     if ($folderIndex ne '') {
                    195:         @allFolders = ();
                    196:         &getFoldersToArray(\@childrenRt);
                    197:         my $folderToInsertOn = &Tree::getNodeByIndex($folderIndex,\@allFolders);
                    198:         $folderToInsertOn->add_child($tree);
                    199:     }
                    200:     else {
                    201:         $root->add_child($tree);
                    202:     }
                    203:     &saveChanges();
                    204: }
                    205: 
                    206: 
                    207: # Delete entries
                    208: sub deleteEntries {
                    209:     my $marked = shift;
                    210:     &getNodesToArray(\@childrenRt);
                    211: 
                    212:     foreach my $m (@$marked) {
                    213:         my $found = &Tree::getNodeByIndex($m, \@allNodes);
                    214:         &Tree::removeNode($found);
                    215:     }
                    216:     @allNodes = ();
                    217:     &saveChanges();
                    218: }
                    219: 
                    220: 
                    221: # Sort entries
                    222: sub sortEntries {
                    223:     my $indexNode = shift;
                    224:     my $at = shift;
                    225:     
                    226:     &getNodesToArray(\@childrenRt);
                    227:     my $foundNode = &Tree::getNodeByIndex($indexNode, \@allNodes);
                    228: 
                    229:     &Tree::moveNode($foundNode,$at,undef);
                    230:     @allNodes = ();
                    231: }
                    232: 
                    233: 
                    234: # Move entries
                    235: sub moveEntries {
                    236:     my $indexNodesToMove = shift;
                    237:     my $indexParent = shift;
                    238:     my @nodesToMove = ();
                    239: 
1.2       wenzelju  240:     # get all nodes that should be moved
1.1       wenzelju  241:     &getNodesToArray(\@childrenRt);
                    242:     foreach my $index (@$indexNodesToMove) {
                    243:         my $foundNode = &Tree::getNodeByIndex($index, \@allNodes);
                    244:         push(@nodesToMove, $foundNode);
                    245:     }
                    246: 
                    247:     foreach my $node (@nodesToMove) {
                    248:         my $foundParent;
                    249:         my $parentIsIn = 0;
                    250:         foreach my $n (@nodesToMove) {
                    251:             if ($node->parent()->value() ne "root") {
                    252:                if ($node->parent()->value()->nindex() == $n->value()->nindex()) {
                    253:                     $parentIsIn = 1;
                    254:                 }
                    255:             }
                    256:         }
                    257:         if (!$parentIsIn) {
                    258:             if ($indexParent ne "root") {
                    259:                 $foundParent = &Tree::getNodeByIndex($indexParent, \@allNodes);
                    260:                 &Tree::moveNode($node,undef,$foundParent);
                    261:             }
                    262:             else {
                    263:                 &Tree::moveNode($node,undef,$root);
                    264:             }
                    265:         }
                    266:     }
                    267:     @allNodes = ();
                    268: }
                    269: 
                    270: 
                    271: # Set a new title for an entry
                    272: sub setNewTitle {
                    273:     my ($nodeindex, $newTitle) = @_;
                    274:     &getNodesToArray(\@childrenRt);
                    275:     my $found = &Tree::getNodeByIndex($nodeindex, \@allNodes);
                    276:     $found->value()->title($newTitle); 
                    277:     @allNodes = ();
                    278: }
                    279: 
                    280: 
1.3       wenzelju  281: # Set a new path for an entry
                    282: sub setNewPath {
                    283:     my ($nodeindex, $newPath) = @_;
                    284:     &getNodesToArray(\@childrenRt);
                    285:     my $found = &Tree::getNodeByIndex($nodeindex, \@allNodes);
                    286:     if ($found->value()->path()) {
                    287:         $found->value()->path($newPath); 
                    288:         return 1;
                    289:     }
                    290:     @allNodes = ();
                    291:     return 0;
                    292: }
                    293: 
                    294: 
1.1       wenzelju  295: # Set a new note for an entry
                    296: sub setNewNote {
                    297:     my ($nodeindex, $newNote) = @_;
                    298:     &getNodesToArray(\@childrenRt);
                    299:     my $found = &Tree::getNodeByIndex($nodeindex, \@allNodes);
                    300:     $found->value()->note($newNote); 
                    301:     @allNodes = ();
                    302: }
                    303: 
                    304: 
                    305: # Save all changes
                    306: sub saveChanges {
                    307:     @childrenRt = $root->children();
                    308:     &Tree::TreeIndex(\@childrenRt);
                    309:     &Tree::setCountZero();
                    310:     &Tree::RootToHash(\@childrenRt);
                    311:     &Tree::TreeToHash(\@childrenRt);
                    312:     &deleteWishlist();
                    313:     &putWishlist(\%TreeToHash);
                    314: 
                    315: }
                    316: 
                    317: 
1.4       wenzelju  318: =pod
                    319: 
                    320: =head2 Routines for handling the directory structure
                    321: 
                    322: =over 4
                    323: 
                    324: =item * &getFoldersForOption(nodes)
                    325: 
                    326:      Return the titles for all exiting folders in an option-tag, used to offer the users a possibility to create a new link or folder in an existing folder.
                    327:      Recursive call starting with all children of the root of the tree (parameter nodes is reference to an array containing the nodes of the current level). 
                    328: 
                    329: 
                    330: =item * &getfoldersOption()
                    331: 
                    332:      Returns the option-tag build by &getFoldersForOption(nodes). Use it to transfer this to other modules (e.g. lonmenu.pm). 
                    333: 
                    334: 
                    335: =item * &getFoldersToArray(children)
                    336: 
                    337:      Puts all nodes that represent folders in the wishlist into an array. 
                    338:      Recursive call starting with all children of the root of the tree (parameter nodes is reference to an array containing the nodes of the current level).     
                    339: 
                    340: 
                    341: =item * &getNodesToArray(children)
                    342: 
                    343:      Puts all existing nodes into an array (apart from the root node, because this one does not represent an entry in the wishlist).
                    344:      Recursive call starting with all children of the root of the tree (parameter nodes is reference to an array containing the nodes of the current level).     
                    345:  
                    346: 
                    347:  =back
                    348: 
                    349: =cut
                    350: 
                    351: 
1.1       wenzelju  352: # Return the names for all exiting folders in option-tags, so
                    353: # a new link or a new folder can be created in an existing folder
                    354: my $indent = 0;
                    355: my $foldersOption;
                    356: sub getFoldersForOption {
                    357:     my $nodes = shift;
                    358: 
                    359:     foreach my $n (@$nodes) {
                    360:         if ($n->value()->path() eq '') {
                    361:             $foldersOption .= '<option value="'.$n->value()->nindex().'" style="margin-left:'.$indent.'px">'.
                    362:                                    $n->value()->title().
                    363:                                '</option>';
                    364: 
                    365:         my @children = $n->children();
                    366:         if ($#children >=0) {
                    367:             $indent += 10;
                    368:             &getFoldersForOption(\@children);
                    369:             $indent -= 10;
                    370:             }
                    371:         }
                    372:     }
                    373: }
                    374: 
                    375: 
                    376: sub getfoldersOption {
                    377:    if (&getWishlist ne 'error') {
                    378:        %TreeHash = &getWishlist();
                    379:        $root = &Tree::HashToTree();
                    380:        @childrenRt = $root->children();
                    381:        &getFoldersForOption(\@childrenRt);
1.2       wenzelju  382:        my $options = '<option value="" selected="selected">('.&mt('Top level').')</option>'.$foldersOption;
1.1       wenzelju  383:        $foldersOption = '';
                    384:        return $options;
                    385:    }
                    386:    else {
                    387:        return '';
                    388:    }
                    389: }
                    390: 
                    391: 
                    392: # Put all folder-nodes to an array
                    393: sub getFoldersToArray {
                    394:     my $children = shift;
                    395:     foreach my $c (@$children) {
                    396:         if ($c->value()->path() eq '') {
                    397:             push(@allFolders,$c);
                    398:         }
                    399:         my @newchildren = $c->children();
                    400:         if ($#newchildren >= 0) {
                    401:             &getFoldersToArray(\@newchildren);
                    402:         }
                    403:     }
                    404: }
                    405: 
                    406: 
                    407: # Put all nodes to an array
                    408: sub getNodesToArray {
                    409:     my $children = shift;
                    410:     foreach my $c (@$children) {
                    411:         push(@allNodes,$c);
                    412:         my @newchildren = $c->children();
                    413:         if ($#newchildren >= 0) {
                    414:             &getNodesToArray(\@newchildren);
                    415:         }
                    416:     }
                    417: }
                    418: 
                    419: 
1.4       wenzelju  420: =pod
                    421: 
                    422: =head2 Routines for the user-interface of the wishlist
                    423: 
                    424: =over 4
                    425: 
                    426: =item * &JSforWishlist()
                    427: 
                    428:      Returns JavaScript-functions needed for wishlist actions like open and close folders.
                    429: 
                    430: 
                    431: =item * &wishlistView(nodes)
                    432: 
                    433:      Returns the table-HTML-markup for the wishlist in mode "view".
                    434:      Recursive call starting with all children of the root of the tree (parameter nodes is reference to an array containing the nodes of the current level).     
                    435: 
                    436: 
                    437: =item * &wishlistEdit(nodes)
                    438: 
                    439:      Returns the table-HTML-markup for the wishlist in mode "edit".
                    440:      Recursive call starting with all children of the root of the tree (parameter nodes is reference to an array containing the nodes of the current level).     
                    441: 
                    442: 
                    443: =item * &wishlistMove(nodes, marked)
                    444: 
                    445:      Returns the table-HTML-markup for the wishlist in mode "move". Highlights all entry "selected to move" contained in marked (reference to array).
                    446:      Recursive call starting with all children of the root of the tree (parameter nodes is reference to an array containing the nodes of the current level).     
                    447: 
                    448: 
                    449: =item * &wishlistImport(nodes)
                    450: 
                    451:      Returns the table-HTML-markup for the wishlist in mode "import".
                    452:      Recursive call starting with all children of the root of the tree (parameter nodes is reference to an array containing the nodes of the current level).     
                    453:  
                    454: 
                    455: =item * &makePage(mode, marked)
                    456: 
                    457:      Returns the HTML-markup for the whole wishlist depending on mode. If mode is "move" we need the marked entries to be highlighted a "selected to move". 
                    458:      Calls &wishlistView(nodes), &wishlistEdit(nodes) or &wishlistMove(nodes, marked).
                    459:  
                    460: 
                    461: =item * &makePageSet()
                    462: 
                    463:      Returns the HTML-Markup for the page shown when a link was set by using the icon when viewing a resource.
                    464: 
                    465: 
                    466: =item * &makePageImport()
                    467: 
                    468:      Returns the HTML-Markup for the page shown when links should be imported into courses.
                    469:  
                    470: 
                    471: =item * &makeErrorPage ()
                    472: 
                    473:      Returns the HTML-Markup for an error-page shown if the wishlist could not be loaded.
                    474:  
                    475: 
                    476: =back
                    477: 
                    478: =cut
                    479: 
                    480: 
1.1       wenzelju  481: # Return a script-tag containing Javascript-function
                    482: # needed for wishlist actions like 'new link' ect.
                    483: sub JSforWishlist {
                    484:     my $startPagePopup = &Apache::loncommon::start_page('Wishlist',undef,
                    485:                                                             {'only_body' => 1,
                    486:                                                              'js_ready'  => 1,
                    487:                                                              'bgcolor'   => '#FFFFFF',});
                    488:     my $endPagePopup = &Apache::loncommon::end_page({'js_ready' => 1});
                    489: 
                    490:     @allFolders = ();
                    491:     &getFoldersToArray(\@childrenRt);
                    492:     &getFoldersForOption(\@childrenRt);
                    493: 
                    494:     # texthash
                    495:     my %lt = &Apache::lonlocal::texthash(
                    496:                  'nl' => 'New Link',
                    497:                  'nf' => 'New Folder',
                    498:                  'lt' => 'Link Title',
                    499:                  'ft' => 'Folder Title',
                    500:                  'pa' => 'Path',
                    501:                  'nt' => 'Note',
                    502:                  'si' => 'Save in',
                    503:                  'cl' => 'Cancel');
                    504: 
                    505: 
                    506:     my $inPageNewLink = '<h1>'.$lt{'nl'}.'</h1>'.
                    507:                         '<form method="post" name="newlink" action="/adm/wishlist" target="wishlist" '.
                    508:                         'onsubmit="return newlinksubmit();" >'.
                    509:                         &Apache::lonhtmlcommon::start_pick_box().
                    510:                         &Apache::lonhtmlcommon::row_title($lt{'lt'}).
                    511:                         '<input type="text" name="title" size="45" value="" />'.
                    512:                         &Apache::lonhtmlcommon::row_closure().
                    513:                         &Apache::lonhtmlcommon::row_title($lt{'pa'}).
                    514:                         '<input type="text" name="path" size="45" value="" />'.
                    515:                         &Apache::lonhtmlcommon::row_closure().
                    516:                         &Apache::lonhtmlcommon::row_title($lt{'nt'}).
                    517:                         '<textarea name="note" rows="3" cols="35" style="width:100%"></textarea>'.
                    518:                         &Apache::lonhtmlcommon::row_closure(1).
                    519:                         &Apache::lonhtmlcommon::end_pick_box().
                    520:                         '<br/><br/>'.
                    521:                         '<input type="submit" value="'.$lt{'si'}.'" />'.
                    522:                         '<select name="folders">'.
1.2       wenzelju  523:                         '<option value="" selected="selected">('.&mt('Top level').')</option>'.
1.1       wenzelju  524:                         $foldersOption.
                    525:                         '</select>'.
                    526:                         '<input type="button" value="'.$lt{'cl'}.'" onclick="javascript:window.close();" />'.
                    527:                         '</form>';
                    528:     
                    529:     my $inPageNewFolder = '<h1>'.$lt{'nf'}.'</h1>'.
                    530:                           '<form method="post" name="newfolder" action="/adm/wishlist" target="wishlist" '.
                    531:                           'onsubmit="return newfoldersubmit();" >'.
                    532:                           &Apache::lonhtmlcommon::start_pick_box().
                    533:                           &Apache::lonhtmlcommon::row_title($lt{'ft'}).
                    534:                           '<input type="text" name="title" size="45" value="" /><br />'.
                    535:                           &Apache::lonhtmlcommon::row_closure().
                    536:                           &Apache::lonhtmlcommon::row_title($lt{'nt'}).
                    537:                           '<textarea name="note" rows="3" cols="35" style="width:100%"></textarea><br />'.
                    538:                           &Apache::lonhtmlcommon::row_closure(1).
                    539:                           &Apache::lonhtmlcommon::end_pick_box().
                    540:                           '<br/><br/>'.
                    541:                           '<input type="submit" value="'.$lt{'si'}.'" />'.
                    542:                           '<select name="folders">'.
1.2       wenzelju  543:                           '<option value="" selected="selected">('.&mt('Top level').')</option>'.
1.1       wenzelju  544:                           $foldersOption.
                    545:                           '</select>'.
                    546:                           '<input type="button" value="'.$lt{'cl'}.'" onclick="javascript:window.close();" />'.
                    547:                           '</form>';
                    548: 
                    549:     # Remove all \n for inserting on javascript document.write
                    550:     $inPageNewLink =~ s/\n//g;
                    551:     $inPageNewFolder =~ s/\n//g;
                    552: 
1.3       wenzelju  553:     # it is checked, wether a path links to a LON-CAPA-resource or an external website. links to course-contents are not allowed
                    554:     # because they probably will return a kind of 'no access' (unless the user is already in the course, the path links to).
                    555:     # also importing these kind of links into a course does not make much sense.
                    556:     # to find out if a path (not starting with /res/...) links to course-contents, the same filter as in lonwrapper is used,
                    557:     # that means that it is checked wether a path contains .problem, .quiz, .exam etc.
                    558:     # this is good for most cases but crashes as soon as a real external website contains one of this pattern in its URL.
                    559:     # so maybe there's a better way to find out wether a given URL belongs to a LON-CAPA-server or not ...?
                    560:     my $warningLinkNotAllowed1 = &mt('You can only insert links to LON-CAPA resources from the resource-pool '.
                    561:                                     'or to external websites. Paths to LON-CAPA resources must be of the form /res/dom/usr... . '.
                    562:                                     'Paths to external websites must contain the network protocol (e.g. http://...).');
                    563:     my $warningLinkNotAllowed2 = &mt('The following link is not allowed: ');
1.1       wenzelju  564:     my $warningLink = &mt('You must insert a title and a path!');
                    565:     my $warningFolder = &mt('You must insert a title!');
                    566:     my $warningDelete = &mt('Are you sure you want to delete the selected entries? Deleting a folder also deletes all entries within this folder!');
                    567:     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.');
                    568:     my $warningMove = &mt('You must select a destination folder!');
                    569:     $foldersOption = '';
                    570: 
                    571:     my $js = &Apache::lonhtmlcommon::scripttag(<<JAVASCRIPT);
                    572:     function newLink() {
                    573:         newlinkWin=window.open('','newlinkWin','width=580,height=320,scrollbars=yes');
                    574:         newlinkWin.document.write('$startPagePopup' 
                    575:                               +'<script type="text\/javascript">'
                    576:                               +'function newlinksubmit(){'
                    577:                               +'var path = document.getElementsByName("path")[0].value;'
                    578:                               +'var title = document.getElementsByName("title")[0].value;'
                    579:                               +'if (!path || !title) {'
                    580:                               +'alert("$warningLink");'
                    581:                               +'return false;}'
1.3       wenzelju  582:                               +'var linkOK = (path.match(/^http:(\\\\/\\\\/)/) || path.match(/^https:(\\\\/\\\\/)/))'
                    583:                               +'&& !(path.match(/\\.problem/) || path.match(/\\.exam/)'
                    584:                               +'|| path.match(/\\.quiz/) || path.match(/\\.assess/)'
                    585:                               +'|| path.match(/\\.survey/) || path.match(/\\.form/)'
                    586:                               +'|| path.match(/\\.library/) || path.match(/\\.page/)'
                    587:                               +'|| path.match(/\\.sequence/));'
                    588:                               +'if (!path.match(/^(\\\\/res\\\\/)/) && !linkOK) {'
                    589:                               +'alert("$warningLinkNotAllowed1");'
                    590:                               +'return false;}'
1.1       wenzelju  591:                               +'else {'
                    592:                               +'window.close();'
                    593:                               +'return true;}}'
                    594:                               +'<\/scr'+'ipt>'
                    595:                               +'$inPageNewLink'
                    596:                               +'$endPagePopup');
                    597:         newlinkWin.document.close();
                    598:     }
                    599: 
                    600:     function newFolder() {
                    601:         newfolderWin=window.open('','newfolderWin','width=580,height=270, scrollbars=yes');
                    602:         newfolderWin.document.write('$startPagePopup' 
                    603:                               +'<script type="text\/javascript">'
                    604:                               +'function newfoldersubmit(){'
                    605:                               +'var title = document.getElementsByName("title")[0].value;'
                    606:                               +'if (!title) {'
                    607:                               +'alert("$warningFolder");'
                    608:                               +'return false;}'
                    609:                               +'else {'
                    610:                               +'window.close();'
                    611:                               +'return true;}}'
                    612:                               +'<\/scr'+'ipt>'
                    613:                               +'$inPageNewFolder'
                    614:                               +'$endPagePopup');
                    615:         newfolderWin.document.close();
                    616:     }
                    617: 
                    618:     function setFormAction(action,mode) {
                    619:         var r = true;
                    620:         setAction('');
                    621:         if (action == 'delete') {
                    622:             r = confirm("$warningDelete");
                    623:             setAction('delete');
                    624:         }
                    625:         else if (action == 'save') {
                    626:             var d = getDifferences();
                    627:             if (d) {
                    628:                 if (!confirm('$warningSave')) {
                    629:                     setAction('noSave');
1.3       wenzelju  630:                     r = true;
                    631:                 }
                    632:                 else {
                    633:                     r = linksOK();
1.1       wenzelju  634:                 }
                    635:             }
1.3       wenzelju  636:         }
                    637:         else if (action == 'saveOK') {
                    638:             r = linksOK();
1.1       wenzelju  639:         }
1.5       wenzelju  640:         else if (action == 'move') {
                    641:             r = selectDestinationFolder();
                    642:         }
1.1       wenzelju  643:         document.getElementsByName('list')[0].setAttribute("action", "/adm/wishlist?mode="+mode); 
1.2       wenzelju  644:         if (r) {
1.1       wenzelju  645:             document.getElementsByName('list')[0].submit(); 
                    646:         }
                    647:     }
                    648: 
                    649:     function setAction(action) {
                    650:         document.getElementById('action').value = action; 
                    651:     }
                    652: 
                    653:     function getDifferences() {
                    654:         var newtitles = document.getElementsByName('newtitle');
                    655:         var i = 0;
                    656:         for (i=0;i<newtitles.length;i++) {
                    657:             var newt = newtitles[i].value;
                    658:             var oldt = newtitles[i].alt;
                    659:             if (newt != oldt) {
                    660:                 return true;
                    661:             }
                    662:         }
1.3       wenzelju  663:         var newpath = document.getElementsByName('newpath');
                    664:         var i = 0;
                    665:         for (i=0;i<newpath.length;i++) {
                    666:             var newp = newpath[i].value;
                    667:             var oldp = newpath[i].alt;
                    668:             if (newp != oldp) {
                    669:                 return true;
                    670:             }
                    671:         }
1.1       wenzelju  672:         var newnote = document.getElementsByName('newnote');
                    673:         var i = 0;
                    674:         for (i=0;i<newnote.length;i++) {
                    675:             var newn = newnote[i].value;
                    676:             var oldn = newnote[i].innerHTML;
                    677:             if (newn != oldn) {
                    678:                 return true;
                    679:             }
                    680:         }
                    681:         return false;
                    682:     }
                    683: 
1.3       wenzelju  684:     function linksOK() {
                    685:         var newpath = document.getElementsByName('newpath');
                    686:         var i = 0;
                    687:         for (i=0;i<newpath.length;i++) {
                    688:             var path = newpath[i].value;
                    689:             var linkOK = (path.match(/^http:\\/\\//) || path.match(/^https:\\/\\//))
                    690:                          && !(path.match(/\\.problem/) || path.match(/\\.exam/)
                    691:                          || path.match(/\\.quiz/) || path.match(/\\.assess/)
                    692:                          || path.match(/\\.survey/) || path.match(/\\.form/)
                    693:                          || path.match(/\\.library/) || path.match(/\\.page/)
                    694:                          || path.match(/\\.sequence/));
                    695:             if (!path.match(/^(\\/res\\/)/) && !linkOK) {
                    696:                 alert("$warningLinkNotAllowed1 $warningLinkNotAllowed2"+path);
                    697:                 return false;
                    698:             }
                    699:          }
                    700:         return true;
                    701:     }
                    702: 
1.1       wenzelju  703:     function onLoadAction(mode) {
                    704:         window.name = 'wishlist';
                    705:         if (mode == "edit") {
                    706:             var deepestRows = getDeepestRows();
                    707:             setDisplaySelect(deepestRows, '');
                    708:         }
                    709:     }
                    710: 
                    711:     function folderAction(rowid) {
                    712:         var row = document.getElementById(rowid);
                    713:         var indent = getIndent(row);
                    714:         var displ;
                    715:         var status;
                    716:         if (getImage(row) == 'closed') {
                    717:             displ = '';
                    718:             status = 'open';
                    719:         }
                    720:         else {
                    721:             displ = 'LC_hidden';
                    722:             status = 'closed';
                    723:         }
                    724:         setImage(row,status);
                    725:         if (getNextRow(row) != null) {
                    726:             var nextIndent = getIndent(getNextRow(row));
                    727:             row = getNextRow(row);
                    728:             while (nextIndent > indent) {
                    729:                 if (displ == '') {
                    730:                     row.className = (row.className).replace('LC_hidden','');
                    731:                 }
                    732:                 else if (displ != '' && !((row.className).match('LC_hidden'))) {
                    733:                     var oldClass = row.className;
                    734:                     row.className = oldClass+' LC_hidden';
                    735:                     setDisplayNote(row.id.replace('row','note'),'LC_hidden');
                    736:                 }
                    737:                 if (status == 'open' && getImage(row).match('closed')) {
                    738:                     row = getNextRowWithIndent(row, getIndent(row));
                    739:                 }
                    740:                 else {
                    741:                     row = getNextRow(row);
                    742:                 } 
                    743:                 if (row != null) {
                    744:                     nextIndent = getIndent(row);
                    745:                 } 
                    746:                 else {
                    747:                     nextIndent = indent;
                    748:                 }
                    749:             }
                    750:         }
                    751:         setClasses();
                    752:         var newtitles = document.getElementsByName('newtitle');
                    753:         if (newtitles.length>0) {
                    754:             var deepestRows = getDeepestRows();
                    755:             var otherRows = getOtherRows(deepestRows);
                    756:             setDisplaySelect(deepestRows,'');
                    757:             setDisplaySelect(otherRows,'LC_hidden');
                    758:         }
                    759:     }
                    760: 
                    761:     function selectAction(rowid) {
                    762:         var row = document.getElementById(rowid);
                    763:         var indent = getIndent(row);
                    764:         var checked = getChecked(row);
                    765:         var previousFolderRows = new Array();
                    766:         if (indent != 0) {
                    767:             previousFolderRows = getPreviousFolderRows(row);
                    768:         }
                    769:         if (getNextRow(row) != null) {
                    770:             var nextIndent = getIndent(getNextRow(row));
                    771:             row = getNextRow(row);
                    772:                 while (nextIndent > indent) {
                    773:                     setChecked(row,checked);
                    774:                     if (status == 'open' && getImage(row).match('closed')) {
                    775:                         row = getNextRowWithIndent(row, getIndent(row));
                    776:                     }
                    777:                     else {
                    778:                         row = getNextRow(row);
                    779:                     }
                    780:                     if (row != null) {
                    781:                         nextIndent = getIndent(row);
                    782:                     }
                    783:                     else {
                    784:                         nextIndent = indent;
                    785:                     }
                    786:                 }
                    787:         }
                    788:         if (!checked) {
                    789:             var i = 0;
                    790:             for (i=0;i<previousFolderRows.length;i++) {
                    791:                 setChecked(previousFolderRows[i], false);
                    792:             }
                    793:         }
                    794:     }
                    795: 
                    796:     function getNextNote(row) {
                    797:         var rowId = row.id;
                    798:         var nextRowId = parseInt(rowId.substr(3,rowId.length))+1;
                    799:         nextRowId = "note"+nextRowId;
                    800:         var nextRow = document.getElementById(nextRowId);
                    801:         return nextRow;
                    802:     }
                    803: 
                    804:     function getNextRow(row) {
                    805:         var rowId = row.id;
                    806:         var nextRowId = parseInt(rowId.substr(3,rowId.length))+1;
                    807:         nextRowId = "row"+nextRowId;
                    808:         var nextRow = document.getElementById(nextRowId);
                    809:         return nextRow;
                    810:     }
                    811: 
                    812:     function getPreviousRow(row) {
                    813:         var rowId = row.id;
                    814:         var previousRowId =  parseInt(rowId.substr(3,rowId.length))-1;
                    815:         previousRowId = "row"+previousRowId;
                    816:         var previousRow =document.getElementById(previousRowId);
                    817:         return previousRow;
                    818:     }
                    819: 
                    820:     function getIndent(row) {
                    821:         var childPADD = document.getElementById(row.id.replace('row','padd'));
                    822:         indent = childPADD.style.paddingLeft;
                    823:         indent = parseInt(indent.substr(0,(indent.length-2)));
                    824:  
                    825:         if (getImage(row).match('link')) {
                    826:             indent -= $indentConst;
                    827:         }
                    828:         return indent;
                    829:     }
                    830: 
                    831:     function getNextRowWithIndent(row, indent) {
                    832:         var nextRow = getNextRow(row);
                    833:         if (nextRow != null) {
                    834:         var nextIndent = getIndent(nextRow);
                    835:         while (nextIndent >= indent) {
                    836:             if (nextIndent == indent) {
                    837:                 return nextRow;
                    838:             }
                    839:             nextRow = getNextRow(nextRow);
                    840:             if (nextRow == null) {
                    841:                 return null;
                    842:             }
                    843:             nextIndent = getIndent(nextRow);
                    844:         }
                    845:         }
                    846:         return nextRow;
                    847:     }
                    848: 
                    849:     function getImage(row) {
                    850:         var childIMG = document.getElementById(row.id.replace('row','img'));
                    851:         if ((childIMG.src).match('closed')) {
                    852:             return 'closed';
                    853:         }
                    854:         else if ((childIMG.src).match('open')) {
                    855:             return 'open;'
                    856:         }
                    857:         else {
                    858:             return 'link';
                    859:         }
                    860:     } 
                    861: 
                    862:     function setImage(row, status) {
                    863:         var childIMG = document.getElementById(row.id.replace('row','img'));
                    864:         var childIMGFolder = document.getElementById(row.id.replace('row','imgFolder'));
                    865:         childIMG.src = "/adm/lonIcons/arrow."+status+".gif";
                    866:         childIMGFolder.src="/adm/lonIcons/navmap.folder."+status+".gif"; 
                    867:     }
                    868: 
                    869:     function getChecked(row) {
                    870:         var childCHECK = document.getElementById(row.id.replace('row','check'));
                    871:         var checked = childCHECK.checked;
                    872:         return checked;
                    873:     }
                    874: 
                    875:     function setChecked(row,checked) {
                    876:         var childCHECK = document.getElementById(row.id.replace('row','check'));
                    877:         childCHECK.checked = checked;
                    878:     }
                    879: 
                    880:     function getPreviousFolderRows(row) {
                    881:         var previousRow = getPreviousRow(row);
                    882:         var indent = getIndent(previousRow);
                    883:         var kindOfEntry = getImage(previousRow);
                    884:         var rows = new Array();
                    885:         if (kindOfEntry != 'link') {
                    886:             rows.push(previousRow);
                    887:         }
                    888: 
                    889:         while (indent >0) {
                    890:             previousRow = getPreviousRow(previousRow);
                    891:             if (previousRow != null) {
                    892:                 indent = getIndent(previousRow);
                    893:                 kindOfEntry = getImage(previousRow);
                    894:                 if (kindOfEntry != 'link') {
                    895:                     rows.push(previousRow);
                    896:                 }
                    897:             }
                    898:             else {
                    899:                 indent = 0; 
                    900:             }
                    901:         }
                    902:         return rows;
                    903:     }
                    904: 
                    905:     function getDeepestRows() {
                    906:         var row = document.getElementById('row0');
                    907:         var firstRow = row;
                    908:         var indent = getIndent(row);
                    909:         var maxIndent = indent;
                    910:         while (getNextRow(row) != null) {
                    911:             row = getNextRow(row);
                    912:             indent = getIndent(row);
                    913:             if (indent>maxIndent && !((row.className).match('LC_hidden'))) {
                    914:                 maxIndent = indent;
                    915:             }
                    916:         }
                    917:         var deepestRows = new Array();
                    918:         row = firstRow;
                    919:         var rowIndent;
                    920:         while (getNextRow(row) != null) {
                    921:             rowIndent = getIndent(row);
                    922:             if (rowIndent == maxIndent) {
                    923:                 deepestRows.push(row);
                    924:             }
                    925:             row = getNextRow(row);
                    926:         }
                    927:         rowIndent = getIndent(row);
                    928:         if (rowIndent == maxIndent) {
                    929:             deepestRows.push(row);
                    930:         }
                    931:         return deepestRows;
                    932:     }
                    933: 
                    934:     function getOtherRows(deepestRows) {
                    935:         var row = document.getElementById('row0');
                    936:         var otherRows = new Array();
                    937:         var isIn = false;
                    938:         while (getNextRow(row) != null) {
                    939:             var i = 0;
                    940:             for (i=0; i < deepestRows.length; i++) {
                    941:                 if (row.id == deepestRows[i].id) {
                    942:                     isIn = true;
                    943:                 }
                    944:             }
                    945:             if (!isIn) {
                    946:                 otherRows.push(row);
                    947:             }
                    948:             row = getNextRow(row);
                    949:             isIn = false;
                    950:         }
                    951:         for (i=0; i < deepestRows.length; i++) {
                    952:             if (row.id == deepestRows[i].id) {
                    953:                 isIn = true;
                    954:             }
                    955:         }
                    956:         if (!isIn) {
                    957:             otherRows.push(row);
                    958:         }
                    959:         return otherRows;
                    960:     }
                    961: 
                    962:     function setDisplaySelect(deepestRows, displ) {
                    963:         var i = 0;
                    964:         for (i = 0; i < deepestRows.length; i++) {
                    965:             var row = deepestRows[i];
                    966:             var childSEL = document.getElementById(row.id.replace('row','sel'));
                    967:             childSEL.className = displ;
                    968:         } 
                    969:     }
                    970: 
                    971:     function submitSelect() {
                    972:        var list = document.getElementsByName('list')[0];
                    973:        list.setAttribute("action","/adm/wishlist?mode=edit");
                    974:        list.submit();
                    975:     }
                    976: 
                    977:     function setDisplayNote(rowid, displ) {
                    978:         var row = document.getElementById(rowid);
                    979:         if (!displ) {
                    980:             if ((row.className).match('LC_hidden')) {
                    981:                 row.className = (row.className).replace('LC_hidden','');
                    982:             }
                    983:             else {
                    984:                 var oldClass = row.className;
                    985:                 row.className = oldClass+' LC_hidden';
                    986:             }
                    987:         }
                    988:         else {
                    989:             if (displ == '') {
                    990:                 row.className = (row.className).replace('LC_hidden','');
                    991:             }
                    992:             else if (displ != '' && !((row.className).match('LC_hidden'))) {
                    993:                 var oldClass = row.className;
                    994:                 row.className = oldClass+' LC_hidden';
                    995:             }
                    996:         }
                    997:         var noteText = document.getElementById(rowid.replace('note','noteText'));
                    998:         var noteImg = document.getElementById(rowid.replace('note','noteImg'));
                    999:         if (noteText.value) {
                   1000:             noteImg.src = "/res/adm/pages/anot2.png";
                   1001:         }
                   1002:         else {
                   1003:             noteImg.src = "/res/adm/pages/anot.png";
                   1004:         }
                   1005: 
                   1006:     }
                   1007: 
                   1008:     function setClasses() {
                   1009:         var row = document.getElementById("row0");
                   1010:         var note = document.getElementById("note0");
                   1011:         var LC_class = 0;
                   1012:         if (getNextRow(row) != null) {
                   1013:             while (getNextRow(row) != null) {
                   1014:                 if (!(row.className).match('LC_hidden')) {
                   1015:                     note.className = (note.className).replace('LC_even_row','');
                   1016:                     note.className = (note.className).replace('LC_odd_row','');
                   1017:                     if (LC_class) {
                   1018:                         row.className = 'LC_even_row';
                   1019:                         note.className = 'LC_even_row'+note.className;
                   1020:                     }
                   1021:                     else {
                   1022:                         row.className = 'LC_odd_row';
                   1023:                         note.className = 'LC_odd_row'+note.className;;
                   1024:                     }
                   1025:                     LC_class = !LC_class;
                   1026:                 }
                   1027:                 note = getNextNote(row);
                   1028:                 row = getNextRow(row);
                   1029:             }
                   1030:         }
                   1031:         if (!(row.className).match('LC_hidden')) {
                   1032:             note.className = (note.className).replace('LC_even_row','');
                   1033:             note.className = (note.className).replace('LC_odd_row','');
                   1034:             if (LC_class) {
                   1035:                 row.className = 'LC_even_row';
                   1036:                 note.className = 'LC_even_row'+note.className;
                   1037:             }
                   1038:             else {
                   1039:                 row.className = 'LC_odd_row';
                   1040:                 note.className = 'LC_odd_row'+note.className;
                   1041:             }
                   1042:         }
                   1043:     }
                   1044: 
                   1045:     function selectDestinationFolder() {
                   1046:         var mark = document.getElementsByName('mark');
                   1047:         var i = 0;
                   1048:         for (i = 0; i < mark.length; i++) {
                   1049:             if (mark[i].checked) {
                   1050:                 document.getElementsByName('list')[0].submit();
                   1051:                 return true;
                   1052:             }
                   1053:         }
                   1054:         alert('$warningMove');
                   1055:         return false;
                   1056:     }
                   1057: 
1.2       wenzelju 1058:     function preview(url) {
1.3       wenzelju 1059:        var newWin;
                   1060:        if (!(url.match(/^http:\\/\\//) || url.match(/^https:\\/\\//))) {
                   1061:            newWin = window.open(url+'?inhibitmenu=yes','preview','width=560,height=350,scrollbars=yes');
                   1062:        }
                   1063:        else {
                   1064:            newWin = window.open(url,'preview','width=560,height=350,scrollbars=yes');
                   1065:        }
1.2       wenzelju 1066:        newWin.focus();
                   1067:     }
                   1068: 
                   1069:     function checkAll() {
                   1070:         var checkboxes = document.getElementsByName('check');
                   1071:         for (var i = 0; i < checkboxes.length; i++) {
                   1072:             checkboxes[i].checked = "checked";
                   1073:         }
                   1074:     }
                   1075: 
                   1076:     function uncheckAll() {
                   1077:         var checkboxes = document.getElementsByName('check');
                   1078:         for (var i = 0; i < checkboxes.length; i++) {
                   1079:             checkboxes[i].checked = "";
                   1080:         }
                   1081:     }
                   1082: 
1.1       wenzelju 1083: JAVASCRIPT
                   1084:    return $js;
                   1085: }
                   1086: 
1.6       wenzelju 1087: sub JSforImport{
                   1088:     my $rat = shift;
                   1089: 
                   1090:     my $js;
                   1091:     if ($rat eq 'simple' || $rat eq '') {
                   1092:         $js = &Apache::lonhtmlcommon::scripttag(<<JAVASCRIPT);
                   1093:         function finish_import() {
                   1094:             opener.document.forms.simpleedit.importdetail.value='';
                   1095:             for (var num = 0; num < document.forms.groupsort.fnum.value; num++) {
                   1096:                 if (eval("document.forms.groupsort.check"+num+".checked") && eval("document.forms.groupsort.filelink"+num+".value") != '') {
                   1097:                     opener.document.forms.simpleedit.importdetail.value+='&'+
                   1098:                     eval("document.forms.groupsort.title"+num+".value")+'='+
                   1099:                     eval("document.forms.groupsort.filelink"+num+".value")+'='+
                   1100:                     eval("document.forms.groupsort.id"+num+".value");
                   1101:                 }
                   1102:             }
                   1103:             opener.document.forms.simpleedit.submit();
                   1104:             self.close();
                   1105:         }
                   1106: JAVASCRIPT
                   1107:     }
                   1108:     else {
                   1109:         $js = &Apache::lonhtmlcommon::scripttag(<<JAVASCRIPT);
                   1110:         function finish_import() {
                   1111:             var linkflag=false;
                   1112:             for (var num=0; num<document.forms.groupsort.fnum.value; num++) {
                   1113:                 if (eval("document.forms.groupsort.check"+num+".checked") && eval("document.forms.groupsort.filelink"+num+".value") != '') {
                   1114:                     insertRowInLastRow();
                   1115:                     placeResourceInLastRow(
                   1116:                         eval("document.forms.groupsort.title"+num+".value"),
                   1117:                         eval("document.forms.groupsort.filelink"+num+".value"),
                   1118:                         eval("document.forms.groupsort.id"+num+".value"),
                   1119:                         linkflag
                   1120:                         );
                   1121:                     linkflag=true;
                   1122:                 }
                   1123:             }
                   1124:             opener.editmode=0;
                   1125:             opener.notclear=0;
                   1126:             opener.linkmode=0;
                   1127:             opener.draw();
                   1128:             self.close();
                   1129:         }
                   1130: 
                   1131:         function insertRowInLastRow() {
                   1132:             opener.insertrow(opener.maxrow);
                   1133:             opener.addobj(opener.maxrow,'e&2');
                   1134:         }
                   1135: 
                   1136:         function placeResourceInLastRow (title,url,id,linkflag) {
                   1137:             opener.mostrecent=opener.newresource(opener.maxrow,2,opener.unescape(title),
                   1138:                               opener.unescape(url),'false','normal',id);
                   1139:             opener.save();
                   1140:             if (linkflag) {
                   1141:                 opener.joinres(opener.linkmode,opener.mostrecent,0);
                   1142:             }
                   1143:             opener.linkmode=opener.mostrecent;
                   1144:         }
                   1145: JAVASCRIPT
                   1146:     }
                   1147:     return $js;
                   1148: }
1.1       wenzelju 1149: 
                   1150: # HTML-Markup for table if in view-mode
                   1151: my $wishlistHTMLview;
                   1152: my $indent = $indentConst;
                   1153: sub wishlistView {
                   1154:     my $nodes = shift;
                   1155: 
                   1156:     foreach my $n (@$nodes) {
                   1157:         my $index = $n->value()->nindex();
                   1158: 
                   1159:         # 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.
                   1160:         # only display the top level entries on load
                   1161:         $wishlistHTMLview .= ($n->parent()->value() eq 'root')?&Apache::loncommon::start_data_table_row('','row'.$index)
                   1162:                                                               :&Apache::loncommon::continue_data_table_row('LC_hidden','row'.$index);
                   1163: 
                   1164:  
                   1165:         # checkboxes
                   1166:         $wishlistHTMLview .= '<td><input type="checkbox" name="mark" id="check'.$index.'" value="'.$index.'" '.
                   1167:                              'onclick="selectAction('."'row".$index."'".')"/></td>';
                   1168: 
                   1169:         # entry is a folder
                   1170:         if ($n->value()->path() eq '') {
                   1171:             $wishlistHTMLview .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;">'.
                   1172:                                  '<a href="javascript:;" onclick="folderAction('."'row".$index."'".')" style="vertical-align:top">'.
                   1173:                                  '<img src="/adm/lonIcons/arrow.closed.gif" id="img'.$index.'" alt = "" class="LC_icon"/>'.
                   1174:                                  '<img src="/adm/lonIcons/navmap.folder.closed.gif" id="imgFolder'.$index.'" alt="folder"/>'.
                   1175:                                  $n->value()->title().'</a></td>';
                   1176:         }
                   1177:         # entry is a link
                   1178:         else {
                   1179:             $wishlistHTMLview .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px; min-width: 220px;">'.
1.2       wenzelju 1180:                                  '<a href="javascript:preview('."'".$n->value()->path()."'".');">'.
1.1       wenzelju 1181:                                  '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link" />'.
1.2       wenzelju 1182:                                  $n->value()->title().'</a></td>';
1.1       wenzelju 1183:         }
                   1184: 
                   1185:         # note-icon, different icons for an entries with note and those without
                   1186:         my $noteIMG = 'anot.png';
                   1187: 
                   1188:         if ($n->value()->note() ne '') {
                   1189:             $noteIMG = 'anot2.png';
                   1190:         }
                   1191: 
                   1192:         $wishlistHTMLview .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
                   1193:                              '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
                   1194:                              ' class="LC_icon"/></a></td>';
                   1195: 
                   1196:         $wishlistHTMLview .= &Apache::loncommon::end_data_table_row();
                   1197: 
                   1198:         # start row containing the textarea for the note, do not display note on default
                   1199:         $wishlistHTMLview .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
                   1200:                              '<td></td><td>'.
                   1201:                              '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
                   1202:                              'name="newnote" >'.
                   1203:                              $n->value()->note().'</textarea></td><td></td>';
                   1204:         $wishlistHTMLview .= &Apache::loncommon::end_data_table_row();
                   1205: 
                   1206:         # if the entry is a folder, it could have other entries as content. if it has, call wishlistView for those entries 
                   1207:         my @children = $n->children();
                   1208:         if ($#children >=0) {
                   1209:             $indent += 20;
                   1210:             &wishlistView(\@children);
                   1211:             $indent -= 20;
                   1212:         }
                   1213:     }
                   1214: }
                   1215: 
                   1216: 
                   1217: # HTML-Markup for table if in edit-mode
                   1218: my $wishlistHTMLedit;
                   1219: my $indent = $indentConst;
                   1220: sub wishlistEdit {
                   1221:     my $nodes = shift;
                   1222:     my $curNode = 1;
                   1223: 
                   1224:     foreach my $n (@$nodes) {
                   1225:         my $index = $n->value()->nindex();
                   1226: 
                   1227:         # start row, use data_table routines to set class to LC_even or LC_odd automatically.
                   1228:         # this rows contains a checkbox, a select-field for sorting entries, the title in an input-field and the note-icon.
                   1229:         # only display the top level entries on load
                   1230:         $wishlistHTMLedit .= ($n->parent()->value() eq 'root')?&Apache::loncommon::start_data_table_row('','row'.$index)
                   1231:                                                               :&Apache::loncommon::continue_data_table_row('LC_hidden','row'.$index);
                   1232: 
                   1233:         # checkboxes
                   1234:         $wishlistHTMLedit .= '<td><input type="checkbox" name="mark" id="check'.$index.'" value="'.$index.'" '.
                   1235:                              'onclick="selectAction('."'row".$index."'".')"/></td>';
                   1236: 
                   1237:         # 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.
                   1238:         # set the number for the current entry into brackets 
                   1239:         my $options;
                   1240:         for (my $i = 1; $i < ((scalar @{$nodes})+1); $i++) {
                   1241:            if ($i == $curNode) {
                   1242:                $options .= '<option selected="selected" value="">('.$i.')</option>';
                   1243:            }
                   1244:            else {
                   1245:                $options .= '<option value="'.$i.'">'.$i.'</option>';
                   1246:            }
                   1247:         }
                   1248:         $curNode++;
                   1249: 
                   1250:         # entry is a folder
                   1251:         if ($n->value()->path() eq '') {
                   1252:             $wishlistHTMLedit .= '<td><select class="LC_hidden" name="sel" id="sel'.$index.'" onchange="submitSelect();">'.
                   1253:                                  $options.'</select></td>'.
                   1254:                                  '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px;">'.
                   1255:                                  '<a href="javascript:;" onclick="folderAction('."'row".$index."'".')" style="vertical-align:top" >'.
                   1256:                                  '<img src="/adm/lonIcons/arrow.closed.gif" id="img'.$index.'" alt = ""  class="LC_icon"/>'.
1.3       wenzelju 1257:                                  '<img src="/adm/lonIcons/navmap.folder.closed.gif" id="imgFolder'.$index.'" alt="folder"/></a>'.
                   1258:                                  '<input type="text" name="newtitle" value="'.$n->value()->title().'" alt = "'.$n->value()->title().'"/>'.
                   1259:                                  '</td><td></td>';
1.1       wenzelju 1260: 
                   1261:         }
                   1262:         # entry is a link
                   1263:         else {
                   1264:             $wishlistHTMLedit .= '<td><select class="LC_hidden" name="sel" id="sel'.$index.'" onchange="submitSelect();">'.
                   1265:                                  $options.'</select></td>'.
                   1266:                                  '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px;">'.
1.3       wenzelju 1267:                                  '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link"/>'.
                   1268:                                  '<input type="text" name="newtitle" value="'.$n->value()->title().'" alt = "'.$n->value()->title().'"/></td>'.
                   1269:                                  '<td><input type="text" name="newpath" value="'.$n->value()->path().'" alt = "'.$n->value()->path().'"/></td>';
1.1       wenzelju 1270:         }
1.3       wenzelju 1271:         
1.1       wenzelju 1272:         # note-icon, different icons for an entries with note and those without
                   1273:         my $noteIMG = 'anot.png';
                   1274: 
                   1275:         if ($n->value()->note() ne '') {
                   1276:             $noteIMG = 'anot2.png';
                   1277:         }
                   1278: 
                   1279:         $wishlistHTMLedit .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
                   1280:                              '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
                   1281:                              ' class="LC_icon"/></a></td>';
                   1282: 
                   1283:         $wishlistHTMLedit .= &Apache::loncommon::end_data_table_row();
                   1284: 
                   1285:         # start row containing the textarea for the note
                   1286:         $wishlistHTMLedit .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
1.3       wenzelju 1287:                              '<td></td><td></td><td colspan="2">'.
1.1       wenzelju 1288:                              '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
                   1289:                              'name="newnote">'.
                   1290:                              $n->value()->note().'</textarea></td><td></td>';
                   1291:         $wishlistHTMLedit .= &Apache::loncommon::end_data_table_row();
                   1292: 
                   1293:         # if the entry is a folder, it could have other entries as content. if it has, call wishlistEdit for those entries 
                   1294:         my @children = $n->children();
                   1295:         if ($#children >=0) {
                   1296:             $indent += 20;
                   1297:             &wishlistEdit(\@children);
                   1298:             $indent -= 20;
                   1299:         }
                   1300:     }
                   1301: }
                   1302: 
                   1303: 
                   1304: 
                   1305: # HTML-Markup for table if in move-mode
                   1306: my $wishlistHTMLmove ='<tr id="root" class="LC_odd_row"><td><input type="radio" name="mark" id="radioRoot" value="root" /></td>'.
                   1307:                       '<td>'.&mt('Top level').'</td><td></td></tr>';
                   1308: my $indent = $indentConst;
                   1309: sub wishlistMove {
                   1310:     my $nodes = shift;
                   1311:     my $marked = shift;
                   1312: 
                   1313:     foreach my $n (@$nodes) {
                   1314:         my $index = $n->value()->nindex();
                   1315: 
                   1316:         #find out wether the current entry was marked to be moved.
                   1317:         my $isIn = 0;
                   1318:         foreach my $m (@$marked) {
                   1319:             if ($index == $m) {
                   1320:                $isIn = 1;
                   1321:             }
                   1322:         }
                   1323:         # 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
                   1324:         $wishlistHTMLmove .= &Apache::loncommon::start_data_table_row('','row'.$index);
                   1325: 
                   1326: 
                   1327:         # entry is a folder
                   1328:         if ($n->value()->path() eq '') {
                   1329:             # display a radio-button, if the folder was not selected to be moved
                   1330:             if (!$isIn) {
                   1331:                 $wishlistHTMLmove .= '<td><input type="radio" name="mark" id="radio'.$index.'" value="'.$index.'" /></td>'.
                   1332:                                      '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;">';
                   1333:             }
                   1334:             # higlight the title, if the folder was selected to be moved
                   1335:             else {
                   1336:                 $wishlistHTMLmove .= '<td></td>'.
                   1337:                                      '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;'.
                   1338:                                      'color:red;">';
                   1339:             }
                   1340:             #arrow- and folder-image, all folders are open, and title
                   1341:             $wishlistHTMLmove .= '<img src="/adm/lonIcons/arrow.open.gif" id="img'.$index.'" alt = "" />'.
                   1342:                                  '<img src="/adm/lonIcons/navmap.folder.open.gif" id="imgFolder'.$index.'" alt="folder"/>'.
                   1343:                                  $n->value()->title().'</td>';
                   1344:         }
                   1345:         # entry is a link
                   1346:         else {
                   1347:             # higlight the title, if the link was selected to be moved
1.2       wenzelju 1348:             my $highlight = '';
                   1349:             if ($isIn) {
                   1350:                $highlight = 'style="color:red;"';
1.1       wenzelju 1351:             }
                   1352:             # link-image and title
1.2       wenzelju 1353:             $wishlistHTMLmove .= '<td></td>'.
                   1354:                                  '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px; min-width: 220px;">'.
                   1355:                                  '<a href="javascript:preview('."'".$n->value()->path()."'".');" '.$highlight.'>'.
                   1356:                                  '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link"/>'.
                   1357:                                  $n->value()->title().'</a></td>';
1.1       wenzelju 1358:         }
                   1359: 
                   1360:         # note-icon, different icons for an entries with note and those without
                   1361:         my $noteIMG = 'anot.png';
                   1362: 
                   1363:         if ($n->value()->note() ne '') {
                   1364:             $noteIMG = 'anot2.png';
                   1365:         }
                   1366: 
                   1367:         $wishlistHTMLmove .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
                   1368:                              '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
                   1369:                              ' class="LC_icon"/></a></td>';
                   1370: 
                   1371:         $wishlistHTMLmove .= &Apache::loncommon::end_data_table_row();
                   1372: 
                   1373:         # start row containing the textarea for the note, readonly in move-mode
                   1374:         $wishlistHTMLmove .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
                   1375:                              '<td></td><td>'.
                   1376:                              '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
                   1377:                              'name="newnote" readonly="readonly">'.
                   1378:                              $n->value()->note().'</textarea></td><td></td>'.
                   1379:                              &Apache::loncommon::end_data_table_row();
                   1380: 
                   1381:         # if the entry is a folder, it could have other entries as content. if it has, call wishlistMove for those entries 
                   1382:         my @children = $n->children();
                   1383:         if ($#children >=0) {
                   1384:             $indent += 20;
                   1385:             &wishlistMove(\@children, $marked);
                   1386:             $indent -= 20;
                   1387:         }
                   1388:     }
                   1389: }
                   1390: 
1.2       wenzelju 1391: 
                   1392: 
                   1393: # HTML-Markup for table if in import-mode
                   1394: my $wishlistHTMLimport;
                   1395: my $indent = $indentConst;
                   1396: my $form = 1;
                   1397: sub wishlistImport {
                   1398:     my $nodes = shift;
                   1399: 
                   1400:     foreach my $n (@$nodes) {
                   1401:         my $index = $n->value()->nindex();
                   1402: 
                   1403:         # 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.
                   1404:         # only display the top level entries on load
                   1405:         $wishlistHTMLimport .= ($n->parent()->value() eq 'root')?&Apache::loncommon::start_data_table_row('','row'.$index)
                   1406:                                                                 :&Apache::loncommon::continue_data_table_row('LC_hidden','row'.$index);
                   1407: 
                   1408:  
                   1409:         # checkboxes
                   1410:         $wishlistHTMLimport .= '<td>'.
                   1411:                                '<input type="checkbox" name="check" id="check'.$index.'" value="'.$index.'" '.
                   1412:                                'onclick="selectAction('."'row".$index."'".')"/>'.
                   1413:                                '<input type="hidden" name="title'.$index.'" value="'.&escape($n->value()->title()).'">'.
                   1414:                                '<input type="hidden" name="filelink'.$index.'" value="'.&escape($n->value()->path()).'">'.
                   1415:                                '<input type="hidden" name="id'.$index.'">'.
                   1416:                                '</td>';
                   1417: 
                   1418:         # entry is a folder
                   1419:         if ($n->value()->path() eq '') {
                   1420:             $wishlistHTMLimport .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;">'.
                   1421:                                    '<a href="javascript:;" onclick="folderAction('."'row".$index."'".')" style="vertical-align:top">'.
                   1422:                                    '<img src="/adm/lonIcons/arrow.closed.gif" id="img'.$index.'" alt = "" class="LC_icon"/>'.
                   1423:                                    '<img src="/adm/lonIcons/navmap.folder.closed.gif" id="imgFolder'.$index.'" alt="folder"/>'.
                   1424:                                    $n->value()->title().'</a></td>';
                   1425:         }
                   1426:         # entry is a link
                   1427:         else {
                   1428:             $wishlistHTMLimport .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px; min-width: 220px;">'.
                   1429:                                    '<a href="javascript:preview('."'".$n->value()->path()."'".');">'.
                   1430:                                    '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link" />'.
                   1431:                                    $n->value()->title().'</a></td>';
                   1432:                                    $form++;
                   1433:         }
                   1434: 
                   1435:         # note-icon, different icons for an entries with note and those without
                   1436:         my $noteIMG = 'anot.png';
                   1437: 
                   1438:         if ($n->value()->note() ne '') {
                   1439:             $noteIMG = 'anot2.png';
                   1440:         }
                   1441: 
                   1442:         $wishlistHTMLimport .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
                   1443:                              '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
                   1444:                              ' class="LC_icon"/></a></td>';
                   1445: 
                   1446:         $wishlistHTMLimport .= &Apache::loncommon::end_data_table_row();
                   1447: 
                   1448:         # start row containing the textarea for the note, do not display note on default, readonly in import-mode
                   1449:         $wishlistHTMLimport .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
                   1450:                              '<td></td><td>'.
                   1451:                              '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
                   1452:                              'name="newnote" readonly="readonly">'.
                   1453:                              $n->value()->note().'</textarea></td><td></td>';
                   1454:         $wishlistHTMLimport .= &Apache::loncommon::end_data_table_row();
                   1455: 
                   1456:         # if the entry is a folder, it could have other entries as content. if it has, call wishlistImport for those entries 
                   1457:         my @children = $n->children();
                   1458:         if ($#children >=0) {
                   1459:             $indent += 20;
                   1460:             &wishlistImport(\@children);
                   1461:             $indent -= 20;
                   1462:         }
                   1463:     }
                   1464: }
                   1465: 
1.1       wenzelju 1466: # Returns the HTML-Markup for wishlist
                   1467: sub makePage {
                   1468:     my $mode = shift;
                   1469:     my $marked = shift;
                   1470: 
                   1471:     # breadcrumbs and start_page
                   1472:     &Apache::lonhtmlcommon::clear_breadcrumbs();
                   1473:     &Apache::lonhtmlcommon::add_breadcrumb(
                   1474:               { href => '/adm/wishlist?mode='.$mode,
                   1475:                 text => 'Wishlist'});
                   1476:     my $startPage = &Apache::loncommon::start_page('Wishlist',undef,
                   1477:                                                      {'add_entries' => {
                   1478:                                                         'onload' => 'javascript:onLoadAction('."'".$mode."'".');',
                   1479:                                                         'onunload' => 'javascript:window.name = '."'loncapaclient'"}});
                   1480: 
1.7     ! wenzelju 1481:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs(&mt('Wishlist').&Apache::loncommon::help_open_topic('Wishlist'));
1.1       wenzelju 1482: 
                   1483:     # get javascript-code for wishlist-interactions
                   1484:     my $js = &JSforWishlist();
                   1485: 
                   1486:     # texthash for items in funtionlist
                   1487:     my %lt = &Apache::lonlocal::texthash(
                   1488:                  'ed' => 'Edit',
                   1489:                  'vw' => 'View',
                   1490:                  'al' => 'Add Link',
                   1491:                  'af' => 'Add Folder',
                   1492:                  'mv' => 'Move Selected',
                   1493:                  'dl' => 'Delete Selected',
                   1494:                  'sv' => 'Save');
                   1495: 
                   1496:     # start functionlist
                   1497:     my $functions = &Apache::lonhtmlcommon::start_funclist();
                   1498: 
                   1499:     # icon for edit-mode, display when in view-mode
                   1500:     if ($mode eq 'view') {
                   1501:         $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
1.3       wenzelju 1502:                           'onclick="setFormAction('."'save','edit'".');" class="LC_menubuttons_link">'.
1.1       wenzelju 1503:                           '<img src="/res/adm/pages/edit-mode-22x22.png" alt="'.$lt{'ed'}.'" '.
                   1504:                           'title="'.$lt{'ed'}.'" class="LC_icon"/> '.
                   1505:                           '<span class="LC_menubuttons_inline_text">'.$lt{'ed'}.'</span></a>');
                   1506:     }
                   1507:     # icon for view-mode, display when in edit-mode
                   1508:     else {
                   1509:         $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
1.3       wenzelju 1510:                           'onclick="setFormAction('."'save','view'".');" class="LC_menubuttons_link">'.
1.1       wenzelju 1511:                           '<img src="/res/adm/pages/view-mode-22x22.png" alt="'.$lt{'vw'}.'" '.
                   1512:                           'title="'.$lt{'vw'}.'" class="LC_icon"/> '.
                   1513:                           '<span class="LC_menubuttons_inline_text">'.$lt{'vw'}.'</span></a>');
                   1514:     }
                   1515:     
                   1516:     # icon for adding a new link
                   1517:     $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
                   1518:                       'onclick="newLink();" class="LC_menubuttons_link">'.
                   1519:                       '<img src="/res/adm/pages/link-new-22x22.png" alt="'.$lt{'al'}.'" '.
                   1520:                       'title="'.$lt{'al'}.'" class="LC_icon"/>'.
                   1521:                       '<span class="LC_menubuttons_inline_text">'.$lt{'al'}.'</span></a>');
                   1522: 
                   1523:     # icon for adding a new folder
                   1524:     $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
                   1525:                       'onclick="newFolder();" class="LC_menubuttons_link">'.
                   1526:                       '<img src="/res/adm/pages/folder-new-22x22.png" alt="'.$lt{'af'}.'" '.
                   1527:                       'title="'.$lt{'af'}.'" class="LC_icon"/>'.
                   1528:                       '<span class="LC_menubuttons_inline_text">'.$lt{'af'}.'</span></a>');
                   1529: 
                   1530:     # icon for moving entries
                   1531:     $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
                   1532:                       'onclick="setFormAction('."'move','move'".'); " class="LC_menubuttons_link">'.
                   1533:                       '<img src="/res/adm/pages/move-22x22.png" alt="'.$lt{'mv'}.'" '.
                   1534:                       'title="'.$lt{'mv'}.'" class="LC_icon" />'.
                   1535:                       '<span class="LC_menubuttons_inline_text">'.$lt{'mv'}.'</span></a>');
                   1536: 
                   1537:     # icon for deleting entries
                   1538:     $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
                   1539:                       'onclick="setFormAction('."'delete','".$mode."'".'); " class="LC_menubuttons_link">'.
                   1540:                       '<img src="/res/adm/pages/del.png" alt="'.$lt{'dl'}.'" '.
                   1541:                       'title="'.$lt{'dl'}.'" class="LC_icon" />'.
                   1542:                       '<span class="LC_menubuttons_inline_text">'.$lt{'dl'}.'</span></a>');
                   1543: 
                   1544:     # icon for saving changes
                   1545:     $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
1.3       wenzelju 1546:                       'onclick="setFormAction('."'saveOK','".$mode."'".'); " class="LC_menubuttons_link">'.
1.1       wenzelju 1547:                       '<img src="/res/adm/pages/save-22x22.png" alt="'.$lt{'sv'}.'" '.
                   1548:                       'title="'.$lt{'sv'}.'" class="LC_icon" />'.
                   1549:                       '<span class="LC_menubuttons_inline_text">'.$lt{'sv'}.'</span></a>');
                   1550: 
                   1551:     # end funtionlist and generate subbox 
                   1552:     $functions.= &Apache::lonhtmlcommon::end_funclist();
                   1553:     my $subbox = &Apache::loncommon::head_subbox($functions);
                   1554: 
                   1555:     # start form 
                   1556:     my $inner .= '<form name="list" action ="/adm/wishlist" method="post">'.
                   1557:                  '<input type="hidden" id="action" name="action" value=""/>';
                   1558:  
                   1559:     # only display subbox in view- or edit-mode
1.2       wenzelju 1560:     if ($mode eq 'view' || $mode eq 'edit') {
1.1       wenzelju 1561:         $inner .= $subbox;
                   1562:     }
                   1563: 
                   1564:     # generate table-content depending on mode
                   1565:     if ($mode eq 'edit') {
                   1566:         &wishlistEdit(\@childrenRt);
                   1567:         if ($wishlistHTMLedit ne '') {
                   1568:             $inner .= &Apache::loncommon::start_data_table("LC_tableOfContent");
                   1569:             $inner .= $wishlistHTMLedit;
                   1570:             $inner .= &Apache::loncommon::end_data_table();
                   1571:         }
                   1572:         else {
1.2       wenzelju 1573:             $inner .= '<span class="LC_info">'.&mt("Your wishlist ist currently empty.").'</span>';
1.1       wenzelju 1574:         }
                   1575:         $wishlistHTMLedit = '';
                   1576:     }
                   1577:     elsif ($mode eq 'view') {
                   1578:         &wishlistView(\@childrenRt);
                   1579:         if ($wishlistHTMLview ne '') {
                   1580:             $inner .= '<table class="LC_data_table LC_tableOfContent">'.$wishlistHTMLview.'</table>';
                   1581:         }
                   1582:         else {
1.2       wenzelju 1583:             $inner .= '<span class="LC_info">'.&mt("Your wishlist ist currently empty.").'</span>';
1.1       wenzelju 1584:         }
                   1585:         $wishlistHTMLview = '';
                   1586:     }
                   1587:     else {
                   1588:         my $markStr = '';
                   1589:         foreach my $m (@$marked) {
                   1590:             $markStr .= $m.',';
                   1591:         }
                   1592:         if ($markStr) {
                   1593:             $markStr = substr($markStr, 0, length($markStr)-1);
                   1594:             $inner .= '<input type="hidden" value="'.$markStr.'" name="markedToMove"/>';
1.2       wenzelju 1595:             $inner .= '<p><span class="LC_info">'.&mt('You have selected the red marked entries to be moved to another folder. '.
                   1596:                                                    'Now choose the new destination folder.').'</span></p>';
1.1       wenzelju 1597:             &wishlistMove(\@childrenRt, $marked);
                   1598:             $inner .= '<table class="LC_data_table LC_tableOfContent">'.$wishlistHTMLmove.'</table><br/><br/>';
1.5       wenzelju 1599:             $inner .= '<input type="button" value="'.&mt('Move').'" onclick="setFormAction('."'move','view'".');"/>'.
1.1       wenzelju 1600:                       '<input type="button" value="'.&mt('Cancel').'" onclick="go('."'/adm/wishlist'".')"/>';
                   1601: 
                   1602:             $wishlistHTMLmove ='<tr id="root" class="LC_odd_row"><td><input type="radio" name="mark" id="radioRoot" value="root" /></td>'.
                   1603:                                '<td>'.&mt('Top level').'</td><td></td></tr>';
                   1604:         }
                   1605:         else {
1.2       wenzelju 1606:             $inner .= '<p><span class="LC_info">'.&mt("You haven't marked any entry to move.").'</span></p>'.
1.1       wenzelju 1607:                       '<input type="button" value="'.&mt('Back').'" onclick="go('."'/adm/wishlist'".')"/>';
                   1608:         }
                   1609:     }
                   1610:     
                   1611:     # end form 
                   1612:     $inner .= '</form>';
                   1613: 
                   1614:     # end_page 
                   1615:     my $endPage =  &Apache::loncommon::end_page();
                   1616: 
1.2       wenzelju 1617:     # put all page-elements together
1.1       wenzelju 1618:     my $page = $startPage.$breadcrumbs.$js.$inner.$endPage;
                   1619: 
                   1620:     return $page;
                   1621: }
                   1622: 
                   1623: 
                   1624: # Returns the HTML-Markup for the page, shown when a link was set
                   1625: sub makePageSet {
                   1626:     # start_page 
                   1627:     my $startPage = &Apache::loncommon::start_page('Wishlist',undef,
                   1628:                                                    {'only_body' => 1});
                   1629:     
                   1630:     # confirm success and offer link to wishlist
                   1631:     my $message = &Apache::lonhtmlcommon::confirm_success(&mt('Link successfully set!'));
                   1632:     $message = &Apache::loncommon::confirmwrapper($message);
                   1633: 
                   1634:     my $inner .= '<br>'.$message.'<br/><br/>'.
                   1635:                  '<a href="javascript:;" onclick="opener.open('."'/adm/wishlist'".');window.close();">'.&mt('Go to wishlist').'</a>'.
                   1636:                  '&nbsp;<a href="javascript:;" onclick="window.close();">'.&mt('Close this window').'</a>';
                   1637: 
                   1638:     # end_page 
                   1639:     my $endPage =  &Apache::loncommon::end_page();
                   1640: 
1.2       wenzelju 1641:     # put all page-elements together
1.1       wenzelju 1642:     my $page = $startPage.$inner.$endPage;
                   1643: 
                   1644:     return $page;
                   1645: }
                   1646: 
                   1647: 
1.2       wenzelju 1648: # Returns the HTML-Markup for the page, shown when links should be imported into a course
                   1649: sub makePageImport {
1.6       wenzelju 1650:     my $rat = shift;
1.2       wenzelju 1651:     # start_page 
                   1652:     my $startPage = &Apache::loncommon::start_page('Wishlist',undef,
                   1653:                                                    {'only_body' => 1});
                   1654:     
                   1655:     # get javascript-code for wishlist-interactions
                   1656:     my $js = &JSforWishlist();
1.6       wenzelju 1657:     $js .= &JSforImport($rat);
1.2       wenzelju 1658: 
                   1659:     my $inner = '<h1>'.&mt('Import Resources from Wishlist').'</h1>';
1.6       wenzelju 1660:     if (!$rat) {
                   1661:         $inner .= '<p><span class="LC_info">'.&mt("Please note that you  can use the checkboxes corresponding to a folder to ".
                   1662:                                                   "easily check all links within this folder. The folder structure itself can't be imported. ".
                   1663:                                                   "All checked links will be imported into the current folder of your course.").'</span></p>';
                   1664:     }
                   1665:     else {
                   1666:         $inner .= '<p><span class="LC_info">'.&mt("Please note that you  can use the checkboxes corresponding to a folder to ".
                   1667:                                                   "easily check all links within this folder. The folder structure itself can't be imported. ")
                   1668:                                                   .'</span></p>';
                   1669:     }
1.2       wenzelju 1670:     my %wishlist = &getWishlist();
                   1671:     my $fnum = (keys %wishlist)-1;
                   1672: 
                   1673:     $inner .= '<form method="post" name="groupsort">'.
                   1674:               '<input type="hidden" value="'.$fnum.'" name="fnum">'.
                   1675:               '<input type="button" onclick="javascript:checkAll()" id="checkallbutton" value="'.&mt('Check All').'">'.
                   1676:               '<input type="button" onclick="javascript:uncheckAll()" id="uncheckallbutton" value="'.&mt('Uncheck All').'">'.
                   1677:               '<input type="button" value="'.&mt('Import Checked').'" onclick="finish_import();">'.    
                   1678:               '<input type="button" value="'.&mt('Cancel').'" onclick="window.close();"><br/><br/>'; 
                   1679: 
                   1680:     
                   1681:     # wishlist-table
                   1682:     &wishlistImport(\@childrenRt);
                   1683:     if ($wishlistHTMLimport ne '') {
                   1684:         $inner .= '<table class="LC_data_table LC_tableOfContent">'.$wishlistHTMLimport.'</table>';
                   1685:     }
                   1686:     else {
                   1687:         $inner .= '<span class="LC_info">'.&mt("Your wishlist ist currently empty.").'</span>';
                   1688:     }
                   1689:     $wishlistHTMLimport = '';
                   1690: 
                   1691:     $inner .= '</form>';
                   1692: 
                   1693:     # end_page 
                   1694:     my $endPage =  &Apache::loncommon::end_page();
                   1695: 
                   1696:     # put all page-elements together
                   1697:     my $page = $startPage.$js.$inner.$endPage;
                   1698: 
                   1699:     return $page;
                   1700: }
                   1701: 
                   1702: 
1.1       wenzelju 1703: # Returns the HTML-Markup for error-page
                   1704: sub makeErrorPage {
                   1705:     # breadcrumbs and start_page 
                   1706:     &Apache::lonhtmlcommon::add_breadcrumb(
                   1707:               { href => '/adm/wishlist',
                   1708:                 text => 'Wishlist'});
                   1709:     my $startPage = &Apache::loncommon::start_page('Wishlist');
                   1710:     
1.7     ! wenzelju 1711:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs(&mt('Wishlist').&Apache::loncommon::help_open_topic('Wishlist'));
1.1       wenzelju 1712:     &Apache::lonhtmlcommon::clear_breadcrumbs();
                   1713: 
                   1714:     # error-message
                   1715:     my $inner .= '<span class="LC_error">'.&mt('An error occurred! Please try again later.').'</span>';
                   1716: 
                   1717:     # end_page 
                   1718:     my $endPage =  &Apache::loncommon::end_page();
                   1719: 
1.2       wenzelju 1720:     # put all page-elements together
1.1       wenzelju 1721:     my $page = $startPage.$breadcrumbs.$inner.$endPage;
                   1722: 
                   1723:     return $page;
                   1724: }
                   1725: 
                   1726: # ----------------------------------------------------- Main Handler, package lonwishlist
                   1727: sub handler {
                   1728:     my ($r) = @_;
                   1729:     &Apache::loncommon::content_type($r,'text/html');
                   1730:     $r->send_http_header;
                   1731: 
                   1732:     if (&getWishlist() ne 'error') {
                   1733:         # get wishlist entries from user-data db-file and build a tree out of these entries
                   1734:         %TreeHash = &getWishlist();
                   1735:         $root = &Tree::HashToTree();
                   1736:         @childrenRt = $root->children();
                   1737: 
                   1738:         # greate a new entry
                   1739:         if ($env{'form.title'}) {
                   1740:            &newEntry($env{'form.title'}, $env{'form.path'}, $env{'form.note'});
                   1741:         }
                   1742: 
                   1743:         # get unprocessed_cgi (i.e. marked entries, mode ...) 
1.6       wenzelju 1744:         &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['action','mark','markedToMove','mode','newtitle','note','rat']);
1.1       wenzelju 1745: 
                   1746:         # change the order of entries within a level, that means sorting the entries
                   1747:         my $changeOrder = 0;
                   1748:         if (defined $env{'form.sel'}) {
                   1749:             my @sel = &Apache::loncommon::get_env_multiple('form.sel');
                   1750:             my $indexNode;
                   1751:             my $at;
                   1752:             for (my $s=0; $s<($#sel+1); $s++) {
                   1753:                 if ($sel[$s] ne '') {
                   1754:                     $indexNode = $s;
                   1755:                     $at = $sel[$s]-1;
                   1756:                 }
                   1757:             }
                   1758:             if ($at ne '') {
                   1759:                 $changeOrder = 1;
                   1760:                 &sortEntries($indexNode,$at);
                   1761:                 &saveChanges();
                   1762:             }
                   1763:         }
                   1764: 
                   1765:         # get all marked (checkboxes) entries
                   1766:         my @marked = ();
                   1767:         if (defined $env{'form.mark'}) {
                   1768:             @marked = &Apache::loncommon::get_env_multiple('form.mark');
                   1769:         }
                   1770: 
                   1771:         # move entries from one folder to another
                   1772:         if (defined $env{'form.markedToMove'}) {
                   1773:            my $markedToMove = $env{'form.markedToMove'};
                   1774:            my @ToMove = split(/\,/,$markedToMove);
                   1775:            my $moveTo = $env{'form.mark'};
                   1776:            if (defined $moveTo){ 
                   1777:                &moveEntries(\@ToMove,$moveTo);
                   1778:                &saveChanges();
                   1779:            }
                   1780:            $changeOrder = 1;
                   1781:     
                   1782:         }
                   1783: 
                   1784:         # delete entries
                   1785:         if ($env{'form.action'} eq 'delete') {
                   1786:             &deleteEntries(\@marked);
                   1787:         }
                   1788:    
                   1789: 
                   1790:         # get all titles and notes and save them
                   1791:         # only save, if user wants to save changes
                   1792:         # do not save, when current action is 'delete' or 'sort' or 'move' 
                   1793:         my @newTitles = ();
1.3       wenzelju 1794:         my @newPaths = ();
1.1       wenzelju 1795:         my @newNotes = ();
1.3       wenzelju 1796:         if ((defined $env{'form.newtitle'} || defined $env{'form.newpath'} || defined $env{'form.newnote'})
                   1797:             && ($env{'form.action'} ne 'noSave') && ($env{'form.action'} ne 'delete') && !$changeOrder) {
1.1       wenzelju 1798:             @newTitles = &Apache::loncommon::get_env_multiple('form.newtitle');
1.3       wenzelju 1799:             @newPaths = &Apache::loncommon::get_env_multiple('form.newpath');
1.1       wenzelju 1800:             @newNotes = &Apache::loncommon::get_env_multiple('form.newnote');
                   1801:             my $node = 0;
                   1802:             foreach my $t (@newTitles) {
                   1803:                &setNewTitle($node, $t);
                   1804:                $node++;
                   1805:             }
                   1806:             $node = 0;
1.3       wenzelju 1807:             my $path = 0;
                   1808:             for (my $i = 0; $i < ($#newTitles+1); $i++ ) {
                   1809:                if (&setNewPath($node, $newPaths[$path])) {
                   1810:                      $path++;
                   1811:                }
                   1812:                $node++;
                   1813:             }
                   1814:             $node = 0;
1.1       wenzelju 1815:             foreach my $n (@newNotes) {
                   1816:                &setNewNote($node, $n);
                   1817:                $node++;
                   1818:             }
                   1819:             &saveChanges();
                   1820:         }
                   1821: 
                   1822:         # Create HTML-markup
                   1823:         my $page;
                   1824:         if ($env{'form.mode'} eq 'edit') {
                   1825:             $page = &makePage("edit");
                   1826:         }
                   1827:         elsif ($env{'form.mode'} eq 'move') {
                   1828:             $page = &makePage("move", \@marked);
                   1829:         }
1.2       wenzelju 1830:         elsif ($env{'form.mode'} eq 'import') {
1.6       wenzelju 1831:             $page = &makePageImport($env{'form.rat'});
1.2       wenzelju 1832:         }
1.1       wenzelju 1833:         elsif ($env{'form.mode'} eq 'set') {
                   1834:             $page = &makePageSet();
                   1835:         }
                   1836:         else {
                   1837:             $page = &makePage("view");
                   1838:         }
                   1839:         @marked = ();
                   1840:         $r->print($page);
                   1841:     }
                   1842:     # An error occured, print an error-page
                   1843:     else {
                   1844:         my $errorPage = &makeErrorPage();
                   1845:         $r->print($errorPage);
                   1846:     }
                   1847:     return OK;
                   1848: }
                   1849: 
                   1850: # ----------------------------------------------------- package Tree
                   1851: # Extend CPAN-Module Tree by function like 'moveNode' or 'deleteNode'
                   1852: package Tree;
                   1853: 
1.4       wenzelju 1854: =pod
                   1855: 
                   1856: =head2 Routines from package Tree
                   1857: 
                   1858: =over 4
                   1859: 
                   1860: =item * &getNodeByIndex(index, nodes)
                   1861: 
                   1862:      Searches for a node, specified by the index, in nodes (reference to array) and returns it. 
                   1863:  
                   1864: 
                   1865: =item * &moveNode(node, at, newParent)
                   1866: 
                   1867:      Moves a given node to a new parent (if new parents is defined) or change the position from a node within its siblings (means sorting, at must be defined).
                   1868: 
                   1869: 
                   1870: =item * &removeNode(node)
                   1871: 
                   1872:      Removes a node given by node from the tree.
                   1873: 
                   1874: 
                   1875: =item * &TreeIndex(children)
                   1876: 
                   1877:      Sets an index for every node in the tree, beginning with 0.
                   1878:      Recursive call starting with all children of the root of the tree (parameter children is reference to an array containing the nodes of the current level).     
                   1879: 
                   1880: 
                   1881: =item * &setCountZero()
                   1882: 
                   1883:      Resets index counter.
                   1884: 
                   1885: 
                   1886: =item * &RootToHash(childrenRt)
                   1887: 
                   1888:      Converts the root-node to a hash-entry: the key is root and values are just the indices of root's children.
                   1889:    
                   1890: 
                   1891: =item * &TreeToHash(childrenRt)
                   1892: 
                   1893:      Converts all other nodes in the tree to hash. Each node is one hash-entry where the keys are the index of a node and the values are all other attributes (containing tile, path, note, date and indices for all direct children).
                   1894:      Recursive call starting with all children of the root of the tree (parameter childrenRT is reference to an array containing the nodes of the current level).     
                   1895: 
                   1896: 
                   1897: =item * &HashToTree()
                   1898: 
                   1899:      Converts the hash to a tree. Builds a tree-object for each entry in the hash. Afterwards call &buildTree(node, childrenIn, TreeNodes, TreeHash) to connect the tree-objects.
                   1900: 
                   1901: 
                   1902: =item * &buildTree(node, childrenIn, TreeNodes, TreeHash)
                   1903: 
                   1904:      Joins the nodes to a tree.
                   1905:      Recursive call starting with root and all children of root (parameter childrenIn is reference to an array containing the nodes indices of the current level).
                   1906:    
                   1907: 
                   1908: =back
                   1909: 
                   1910: =cut
                   1911: 
                   1912: 
1.1       wenzelju 1913: # returns the node with a given index from a list of nodes
                   1914: sub getNodeByIndex {
                   1915:     my $index = shift;
                   1916:     my $nodes = shift;
                   1917:     my $found;
                   1918:     
                   1919:     for my $n (@$nodes) {
                   1920:         my $curIndex = $n->value()->nindex();
                   1921:         if ($n->value()->nindex() == $index) {
                   1922:             $found = $n;
                   1923:         }
                   1924:     }
                   1925:     return $found;
                   1926: }
                   1927: 
                   1928: # moves a given node to a new parent or change the position from a node
                   1929: # within its siblings (sorting)
                   1930: sub moveNode {
                   1931:     my $node = shift;
                   1932:     my $at = shift;
                   1933:     my $newParent = shift;
                   1934: 
                   1935: 
                   1936:     if (!$newParent) {
                   1937:         $newParent = $node->parent();
                   1938:     }
                   1939: 
                   1940:     $node->parent()->remove_child($node);
                   1941: 
                   1942:     if (defined $at) {
                   1943:         $newParent->add_child({at => $at},$node);
                   1944:     }
                   1945:     else {
                   1946:         $newParent->add_child($node);
                   1947:     }
                   1948:     
                   1949:     # updating root's children
                   1950:     @childrenRt = $root->children();
                   1951: }
                   1952: 
                   1953: # removes a given node
                   1954: sub removeNode() {
                   1955:     my $node = shift;
                   1956:     my @children = $node->children();
                   1957: 
                   1958:     if ($#children >= 0) {
                   1959:         foreach my $c (@children) {
                   1960:             &removeNode($c);
                   1961:         }
                   1962:     }
                   1963:     $node->parent()->remove_child($node);
                   1964: 
                   1965:     # updating root's children
                   1966:     @childrenRt = $root->children();
                   1967: }
                   1968: 
                   1969: 
                   1970: # set an index for every node in the tree, beginning with 0
                   1971: my $count = 0;
                   1972: sub TreeIndex {
                   1973:     my $children = shift;
                   1974: 
                   1975:     foreach my $n (@$children) {
                   1976:         my @children = $n->children();
                   1977:         $n->value()->nindex($count);$count++;
                   1978: 
                   1979:         if ($#children>=0) {
                   1980:             &TreeIndex(\@children);
                   1981:         }
                   1982:     }
                   1983: }
                   1984: 
                   1985: # reset index counter
                   1986: sub setCountZero {
                   1987:     $count = 0;
                   1988: }
                   1989: 
                   1990: 
                   1991: # convert the tree to a hash
                   1992: # each node is one hash-entry
                   1993: # keys are the indices, values are all other attributes
                   1994: # (containing tile, path, note, date and indices for all direct children)
                   1995: # except for root: the key is root and values are
                   1996: # just the indices of root's children
                   1997: sub RootToHash {
                   1998:     my $childrenRt = shift;
                   1999:     my @indexarr = ();
                   2000: 
                   2001:     foreach my $c (@$childrenRt) {
                   2002:        push (@indexarr, $c->value()->nindex());
                   2003:     }
                   2004:     $TreeToHash{'root'} = [@indexarr];
                   2005: }
                   2006: 
                   2007: sub TreeToHash {
                   2008:     my $childrenRt = shift;
                   2009: 
                   2010:     foreach my $n (@$childrenRt) {
                   2011:         my @arrtmp = ();
                   2012:         $arrtmp[0] = $n->value()->title();
                   2013:         $arrtmp[1] = $n->value()->path();
                   2014:         $arrtmp[2] = $n->value()->note();
                   2015:         $arrtmp[3] = $n->value()->date();
                   2016:         my @childrenRt = $n->children();
                   2017:         my $co = 4;
                   2018:         foreach my $c (@childrenRt) {
                   2019:             my $i = $c->value()->nindex();
                   2020:             $arrtmp[$co] = $i;
                   2021:             $co++;
                   2022:         }
                   2023:         $TreeToHash{$n->value()->nindex} = [ @arrtmp]; 
                   2024:         if ($#childrenRt>=0) {
                   2025:             &TreeToHash(\@childrenRt);
                   2026:         }
                   2027:     }
                   2028: }
                   2029: 
                   2030: 
                   2031: # convert the hash to a tree
                   2032: # build a tree-object for each entry in the hash
                   2033: # afterwards call &buildTree to connect the tree-objects
                   2034: sub HashToTree {
                   2035:     my @TreeNodes = ();
                   2036:     my $root;
                   2037: 
                   2038:     foreach my $key (keys %TreeHash) {
                   2039:         if ($key eq 'root') {
                   2040:             $root = Tree->new("root");
                   2041:         }
                   2042:         else {
                   2043:         my @attributes = @{ $TreeHash{$key} };
                   2044:         my $tmpNode;
                   2045:             $tmpNode = Tree->new(Entry->new(title=>$attributes[0],
                   2046:                                             path=>$attributes[1],
                   2047:                                             note=>$attributes[2],
                   2048:                                             date=>$attributes[3],
                   2049:                                             nindex=>$key));
                   2050:         push(@TreeNodes, $tmpNode);
                   2051:         # shift all attributes except for
                   2052:         # the indices representing the children of a node
                   2053:         shift(@attributes);
                   2054:         shift(@attributes);
                   2055:         shift(@attributes);
                   2056:         shift(@attributes);
                   2057:         $TreeHash{$key} = [ @attributes ];
                   2058:         }
                   2059:     }
                   2060:     # if there are nodes, build up the tree-structure
1.2       wenzelju 2061:     if (defined $TreeHash{'root'} && $TreeHash{'root'} ne '') {
1.1       wenzelju 2062:         my @childrenRtIn = @{ $TreeHash{'root'} };
                   2063:         &buildTree(\$root, \@childrenRtIn,\@TreeNodes,\%TreeHash);
                   2064:     }
                   2065:     return $root; 
                   2066: }
                   2067: 
                   2068: 
                   2069: # join the nodes to a tree
                   2070: sub buildTree {
                   2071:     my ($node, $childrenIn, $TreeNodes, $TreeHash) = @_;
                   2072:     bless($node, 'Tree');
                   2073:     foreach my $c (@$childrenIn) {
                   2074:         my $tmpNode =  &getNodeByIndex($c,$TreeNodes);
                   2075:         $$node->add_child($tmpNode);
                   2076:         my @childrenIn = @{ $$TreeHash{$tmpNode->value()->nindex()} };
                   2077:         &buildTree(\$tmpNode,\@childrenIn,$TreeNodes,$TreeHash);
                   2078:     }
                   2079: 
                   2080: }
                   2081: 
                   2082: 
                   2083: # ----------------------------------------------------- package Entry
                   2084: # package that defines the entrys a wishlist could have
                   2085: # i.e. folders and links
                   2086: package Entry;
                   2087: 
                   2088: # constructor
                   2089: sub new {
                   2090:     my $invocant = shift;
                   2091:     my $class = ref($invocant) || $invocant;
                   2092:     my $self = { @_ }; #set attributes
                   2093:     bless($self, $class);
                   2094:     return $self;    
                   2095: }
                   2096: 
                   2097: # getter and setter
                   2098: sub title {
                   2099:     my $self = shift;
                   2100:     if ( @_ ) { $self->{title} = shift}
                   2101:     return $self->{title};
                   2102: }
                   2103: 
                   2104: sub date {
                   2105:     my $self = shift;
                   2106:     if ( @_ ) { $self->{date} = shift}
                   2107:     return $self->{date};
                   2108: }
                   2109: 
                   2110: sub note {
                   2111:     my $self = shift;
                   2112:     if ( @_ ) { $self->{note} = shift}
                   2113:     return $self->{note};
                   2114: }
                   2115: 
                   2116: sub path {
                   2117:     my $self = shift;
                   2118:     if ( @_ ) { $self->{path} = shift}
                   2119:     return $self->{path};
                   2120: }
                   2121: 
                   2122: sub nindex {
                   2123:     my $self = shift;
                   2124:     if ( @_ ) { $self->{nindex} = shift}
                   2125:     return $self->{nindex};
                   2126: }
                   2127: 
                   2128: 
                   2129: 1;
                   2130: __END__

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.