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

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

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