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