Annotation of loncom/interface/lonwishlist.pm, revision 1.14
1.1 wenzelju 1: # The LearningOnline Network with CAPA
1.9 wenzelju 2: # Utility-routines for wishlist
1.1 wenzelju 3: #
1.14 ! bisitz 4: # $Id: lonwishlist.pm,v 1.13 2012/05/16 11:26:03 bisitz 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:
1.10 wenzelju 481: =item * &makePopUpNewLink(title, path)
482:
483: Returns the HTML-markup for the pop-up-window 'Add Link'. If this is called up from a browsed resource, the input-fields titel and path are pre-filled with the resources' meta-data-title and it's path.
484:
485:
486: =item * &makePopUpNewFolder()
487:
488: Returns the HTML-markup for the pop-up-window 'Add Folder'.
489:
490:
1.4 wenzelju 491: =item * &makePageSet()
492:
493: Returns the HTML-Markup for the page shown when a link was set by using the icon when viewing a resource.
494:
495:
496: =item * &makePageImport()
497:
498: Returns the HTML-Markup for the page shown when links should be imported into courses.
499:
500:
501: =item * &makeErrorPage ()
502:
503: Returns the HTML-Markup for an error-page shown if the wishlist could not be loaded.
504:
505:
506: =back
507:
508: =cut
509:
510:
1.1 wenzelju 511: # Return a script-tag containing Javascript-function
512: # needed for wishlist actions like 'new link' ect.
513: sub JSforWishlist {
1.12 raeburn 514: my $startPagePopup = &Apache::loncommon::start_page('Stored Links',undef,
1.1 wenzelju 515: {'only_body' => 1,
516: 'js_ready' => 1,
517: 'bgcolor' => '#FFFFFF',});
518: my $endPagePopup = &Apache::loncommon::end_page({'js_ready' => 1});
519:
520: @allFolders = ();
521: &getFoldersToArray(\@childrenRt);
522: &getFoldersForOption(\@childrenRt);
523:
1.3 wenzelju 524: # it is checked, wether a path links to a LON-CAPA-resource or an external website. links to course-contents are not allowed
525: # because they probably will return a kind of 'no access' (unless the user is already in the course, the path links to).
526: # also importing these kind of links into a course does not make much sense.
527: # to find out if a path (not starting with /res/...) links to course-contents, the same filter as in lonwrapper is used,
528: # that means that it is checked wether a path contains .problem, .quiz, .exam etc.
529: # this is good for most cases but crashes as soon as a real external website contains one of this pattern in its URL.
530: # so maybe there's a better way to find out wether a given URL belongs to a LON-CAPA-server or not ...?
1.14 ! bisitz 531: my $warningLinkNotAllowed1 =
! 532: &mt('You can only insert links to LON-CAPA resources from the resource-pool'.
! 533: ' or to external websites.'.
! 534: ' Paths to LON-CAPA resources must be of the form /res/domain/user/...'.
! 535: ' Paths to external websites must contain the network protocol, e.g. http://...');
! 536: my $warningLinkNotAllowed2 = &mt('The following link is not allowed:').' ';
1.1 wenzelju 537: my $warningLink = &mt('You must insert a title and a path!');
538: my $warningFolder = &mt('You must insert a title!');
539: my $warningDelete = &mt('Are you sure you want to delete the selected entries? Deleting a folder also deletes all entries within this folder!');
1.14 ! bisitz 540: 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 541: my $warningMoveS = &mt('You must select at minimum one entry to move!');
542: my $warningMoveD = &mt('You must select a destination folder!');
1.1 wenzelju 543: $foldersOption = '';
544:
545: my $js = &Apache::lonhtmlcommon::scripttag(<<JAVASCRIPT);
546: function newLink() {
1.10 wenzelju 547: newlinkWin=window.open('/adm/wishlist?mode=newLink','newlinkWin','width=580,height=350, scrollbars=yes');
1.1 wenzelju 548: }
549:
550: function newFolder() {
1.10 wenzelju 551: newfolderWin=window.open('/adm/wishlist?mode=newFolder','newfolderWin','width=580,height=270, scrollbars=yes');
1.1 wenzelju 552: }
553:
554: function setFormAction(action,mode) {
555: var r = true;
556: setAction('');
557: if (action == 'delete') {
558: r = confirm("$warningDelete");
559: setAction('delete');
560: }
561: else if (action == 'save') {
562: var d = getDifferences();
563: if (d) {
564: if (!confirm('$warningSave')) {
565: setAction('noSave');
1.3 wenzelju 566: r = true;
567: }
568: else {
569: r = linksOK();
1.1 wenzelju 570: }
571: }
1.3 wenzelju 572: }
573: else if (action == 'saveOK') {
574: r = linksOK();
1.1 wenzelju 575: }
1.5 wenzelju 576: else if (action == 'move') {
1.9 wenzelju 577: r = selectDestinationFolder(mode);
1.5 wenzelju 578: }
1.1 wenzelju 579: document.getElementsByName('list')[0].setAttribute("action", "/adm/wishlist?mode="+mode);
1.2 wenzelju 580: if (r) {
1.1 wenzelju 581: document.getElementsByName('list')[0].submit();
582: }
583: }
584:
585: function setAction(action) {
586: document.getElementById('action').value = action;
587: }
588:
589: function getDifferences() {
590: var newtitles = document.getElementsByName('newtitle');
591: var i = 0;
592: for (i=0;i<newtitles.length;i++) {
593: var newt = newtitles[i].value;
594: var oldt = newtitles[i].alt;
595: if (newt != oldt) {
596: return true;
597: }
598: }
1.3 wenzelju 599: var newpath = document.getElementsByName('newpath');
600: var i = 0;
601: for (i=0;i<newpath.length;i++) {
602: var newp = newpath[i].value;
603: var oldp = newpath[i].alt;
604: if (newp != oldp) {
605: return true;
606: }
607: }
1.1 wenzelju 608: var newnote = document.getElementsByName('newnote');
609: var i = 0;
610: for (i=0;i<newnote.length;i++) {
611: var newn = newnote[i].value;
612: var oldn = newnote[i].innerHTML;
613: if (newn != oldn) {
614: return true;
615: }
616: }
617: return false;
618: }
619:
1.3 wenzelju 620: function linksOK() {
621: var newpath = document.getElementsByName('newpath');
622: var i = 0;
623: for (i=0;i<newpath.length;i++) {
624: var path = newpath[i].value;
625: var linkOK = (path.match(/^http:\\/\\//) || path.match(/^https:\\/\\//))
626: && !(path.match(/\\.problem/) || path.match(/\\.exam/)
627: || path.match(/\\.quiz/) || path.match(/\\.assess/)
628: || path.match(/\\.survey/) || path.match(/\\.form/)
629: || path.match(/\\.library/) || path.match(/\\.page/)
630: || path.match(/\\.sequence/));
631: if (!path.match(/^(\\/res\\/)/) && !linkOK) {
632: alert("$warningLinkNotAllowed1 $warningLinkNotAllowed2"+path);
633: return false;
634: }
635: }
636: return true;
637: }
638:
1.1 wenzelju 639: function onLoadAction(mode) {
640: window.name = 'wishlist';
641: if (mode == "edit") {
642: var deepestRows = getDeepestRows();
643: setDisplaySelect(deepestRows, '');
644: }
645: }
646:
647: function folderAction(rowid) {
648: var row = document.getElementById(rowid);
649: var indent = getIndent(row);
650: var displ;
651: var status;
652: if (getImage(row) == 'closed') {
653: displ = '';
654: status = 'open';
655: }
656: else {
657: displ = 'LC_hidden';
658: status = 'closed';
659: }
660: setImage(row,status);
661: if (getNextRow(row) != null) {
662: var nextIndent = getIndent(getNextRow(row));
663: row = getNextRow(row);
664: while (nextIndent > indent) {
665: if (displ == '') {
666: row.className = (row.className).replace('LC_hidden','');
667: }
668: else if (displ != '' && !((row.className).match('LC_hidden'))) {
669: var oldClass = row.className;
670: row.className = oldClass+' LC_hidden';
671: setDisplayNote(row.id.replace('row','note'),'LC_hidden');
672: }
673: if (status == 'open' && getImage(row).match('closed')) {
674: row = getNextRowWithIndent(row, getIndent(row));
675: }
676: else {
677: row = getNextRow(row);
678: }
679: if (row != null) {
680: nextIndent = getIndent(row);
681: }
682: else {
683: nextIndent = indent;
684: }
685: }
686: }
687: setClasses();
688: var newtitles = document.getElementsByName('newtitle');
689: if (newtitles.length>0) {
690: var deepestRows = getDeepestRows();
691: var otherRows = getOtherRows(deepestRows);
692: setDisplaySelect(deepestRows,'');
693: setDisplaySelect(otherRows,'LC_hidden');
694: }
695: }
696:
697: function selectAction(rowid) {
698: var row = document.getElementById(rowid);
699: var indent = getIndent(row);
700: var checked = getChecked(row);
701: var previousFolderRows = new Array();
702: if (indent != 0) {
703: previousFolderRows = getPreviousFolderRows(row);
704: }
705: if (getNextRow(row) != null) {
706: var nextIndent = getIndent(getNextRow(row));
707: row = getNextRow(row);
708: while (nextIndent > indent) {
709: setChecked(row,checked);
710: if (status == 'open' && getImage(row).match('closed')) {
711: row = getNextRowWithIndent(row, getIndent(row));
712: }
713: else {
714: row = getNextRow(row);
715: }
716: if (row != null) {
717: nextIndent = getIndent(row);
718: }
719: else {
720: nextIndent = indent;
721: }
722: }
723: }
724: if (!checked) {
725: var i = 0;
726: for (i=0;i<previousFolderRows.length;i++) {
727: setChecked(previousFolderRows[i], false);
728: }
729: }
730: }
731:
732: function getNextNote(row) {
733: var rowId = row.id;
734: var nextRowId = parseInt(rowId.substr(3,rowId.length))+1;
735: nextRowId = "note"+nextRowId;
736: var nextRow = document.getElementById(nextRowId);
737: return nextRow;
738: }
739:
740: function getNextRow(row) {
741: var rowId = row.id;
742: var nextRowId = parseInt(rowId.substr(3,rowId.length))+1;
743: nextRowId = "row"+nextRowId;
744: var nextRow = document.getElementById(nextRowId);
745: return nextRow;
746: }
747:
748: function getPreviousRow(row) {
749: var rowId = row.id;
750: var previousRowId = parseInt(rowId.substr(3,rowId.length))-1;
751: previousRowId = "row"+previousRowId;
752: var previousRow =document.getElementById(previousRowId);
753: return previousRow;
754: }
755:
756: function getIndent(row) {
757: var childPADD = document.getElementById(row.id.replace('row','padd'));
758: indent = childPADD.style.paddingLeft;
759: indent = parseInt(indent.substr(0,(indent.length-2)));
760:
761: if (getImage(row).match('link')) {
762: indent -= $indentConst;
763: }
764: return indent;
765: }
766:
767: function getNextRowWithIndent(row, indent) {
768: var nextRow = getNextRow(row);
769: if (nextRow != null) {
770: var nextIndent = getIndent(nextRow);
771: while (nextIndent >= indent) {
772: if (nextIndent == indent) {
773: return nextRow;
774: }
775: nextRow = getNextRow(nextRow);
776: if (nextRow == null) {
777: return null;
778: }
779: nextIndent = getIndent(nextRow);
780: }
781: }
782: return nextRow;
783: }
784:
785: function getImage(row) {
786: var childIMG = document.getElementById(row.id.replace('row','img'));
787: if ((childIMG.src).match('closed')) {
788: return 'closed';
789: }
790: else if ((childIMG.src).match('open')) {
791: return 'open;'
792: }
793: else {
794: return 'link';
795: }
796: }
797:
798: function setImage(row, status) {
799: var childIMG = document.getElementById(row.id.replace('row','img'));
800: var childIMGFolder = document.getElementById(row.id.replace('row','imgFolder'));
801: childIMG.src = "/adm/lonIcons/arrow."+status+".gif";
802: childIMGFolder.src="/adm/lonIcons/navmap.folder."+status+".gif";
803: }
804:
805: function getChecked(row) {
806: var childCHECK = document.getElementById(row.id.replace('row','check'));
807: var checked = childCHECK.checked;
808: return checked;
809: }
810:
811: function setChecked(row,checked) {
812: var childCHECK = document.getElementById(row.id.replace('row','check'));
813: childCHECK.checked = checked;
814: }
815:
816: function getPreviousFolderRows(row) {
817: var previousRow = getPreviousRow(row);
818: var indent = getIndent(previousRow);
819: var kindOfEntry = getImage(previousRow);
820: var rows = new Array();
821: if (kindOfEntry != 'link') {
822: rows.push(previousRow);
823: }
824:
825: while (indent >0) {
826: previousRow = getPreviousRow(previousRow);
827: if (previousRow != null) {
828: indent = getIndent(previousRow);
829: kindOfEntry = getImage(previousRow);
830: if (kindOfEntry != 'link') {
831: rows.push(previousRow);
832: }
833: }
834: else {
835: indent = 0;
836: }
837: }
838: return rows;
839: }
840:
841: function getDeepestRows() {
842: var row = document.getElementById('row0');
843: var firstRow = row;
844: var indent = getIndent(row);
845: var maxIndent = indent;
846: while (getNextRow(row) != null) {
847: row = getNextRow(row);
848: indent = getIndent(row);
849: if (indent>maxIndent && !((row.className).match('LC_hidden'))) {
850: maxIndent = indent;
851: }
852: }
853: var deepestRows = new Array();
854: row = firstRow;
855: var rowIndent;
856: while (getNextRow(row) != null) {
857: rowIndent = getIndent(row);
858: if (rowIndent == maxIndent) {
859: deepestRows.push(row);
860: }
861: row = getNextRow(row);
862: }
863: rowIndent = getIndent(row);
864: if (rowIndent == maxIndent) {
865: deepestRows.push(row);
866: }
867: return deepestRows;
868: }
869:
870: function getOtherRows(deepestRows) {
871: var row = document.getElementById('row0');
872: var otherRows = new Array();
873: var isIn = false;
874: while (getNextRow(row) != null) {
875: var i = 0;
876: for (i=0; i < deepestRows.length; i++) {
877: if (row.id == deepestRows[i].id) {
878: isIn = true;
879: }
880: }
881: if (!isIn) {
882: otherRows.push(row);
883: }
884: row = getNextRow(row);
885: isIn = false;
886: }
887: for (i=0; i < deepestRows.length; i++) {
888: if (row.id == deepestRows[i].id) {
889: isIn = true;
890: }
891: }
892: if (!isIn) {
893: otherRows.push(row);
894: }
895: return otherRows;
896: }
897:
898: function setDisplaySelect(deepestRows, displ) {
899: var i = 0;
900: for (i = 0; i < deepestRows.length; i++) {
901: var row = deepestRows[i];
902: var childSEL = document.getElementById(row.id.replace('row','sel'));
903: childSEL.className = displ;
904: }
905: }
906:
907: function submitSelect() {
908: var list = document.getElementsByName('list')[0];
909: list.setAttribute("action","/adm/wishlist?mode=edit");
910: list.submit();
911: }
912:
913: function setDisplayNote(rowid, displ) {
914: var row = document.getElementById(rowid);
915: if (!displ) {
916: if ((row.className).match('LC_hidden')) {
917: row.className = (row.className).replace('LC_hidden','');
918: }
919: else {
920: var oldClass = row.className;
921: row.className = oldClass+' LC_hidden';
922: }
923: }
924: else {
925: if (displ == '') {
926: row.className = (row.className).replace('LC_hidden','');
927: }
928: else if (displ != '' && !((row.className).match('LC_hidden'))) {
929: var oldClass = row.className;
930: row.className = oldClass+' LC_hidden';
931: }
932: }
933: var noteText = document.getElementById(rowid.replace('note','noteText'));
934: var noteImg = document.getElementById(rowid.replace('note','noteImg'));
935: if (noteText.value) {
936: noteImg.src = "/res/adm/pages/anot2.png";
937: }
938: else {
939: noteImg.src = "/res/adm/pages/anot.png";
940: }
941:
942: }
943:
944: function setClasses() {
945: var row = document.getElementById("row0");
946: var note = document.getElementById("note0");
947: var LC_class = 0;
948: if (getNextRow(row) != null) {
949: while (getNextRow(row) != null) {
950: if (!(row.className).match('LC_hidden')) {
951: note.className = (note.className).replace('LC_even_row','');
952: note.className = (note.className).replace('LC_odd_row','');
953: if (LC_class) {
954: row.className = 'LC_even_row';
955: note.className = 'LC_even_row'+note.className;
956: }
957: else {
958: row.className = 'LC_odd_row';
959: note.className = 'LC_odd_row'+note.className;;
960: }
961: LC_class = !LC_class;
962: }
963: note = getNextNote(row);
964: row = getNextRow(row);
965: }
966: }
967: if (!(row.className).match('LC_hidden')) {
968: note.className = (note.className).replace('LC_even_row','');
969: note.className = (note.className).replace('LC_odd_row','');
970: if (LC_class) {
971: row.className = 'LC_even_row';
972: note.className = 'LC_even_row'+note.className;
973: }
974: else {
975: row.className = 'LC_odd_row';
976: note.className = 'LC_odd_row'+note.className;
977: }
978: }
979: }
980:
1.9 wenzelju 981: function selectDestinationFolder(mode) {
1.1 wenzelju 982: var mark = document.getElementsByName('mark');
983: var i = 0;
984: for (i = 0; i < mark.length; i++) {
985: if (mark[i].checked) {
986: document.getElementsByName('list')[0].submit();
987: return true;
988: }
989: }
1.9 wenzelju 990: if (mode == 'move') {
991: alert('$warningMoveS');
992: }
993: else {
994: alert('$warningMoveD');
995: }
1.1 wenzelju 996: return false;
997: }
998:
1.2 wenzelju 999: function preview(url) {
1.3 wenzelju 1000: var newWin;
1001: if (!(url.match(/^http:\\/\\//) || url.match(/^https:\\/\\//))) {
1002: newWin = window.open(url+'?inhibitmenu=yes','preview','width=560,height=350,scrollbars=yes');
1003: }
1004: else {
1005: newWin = window.open(url,'preview','width=560,height=350,scrollbars=yes');
1006: }
1.2 wenzelju 1007: newWin.focus();
1008: }
1009:
1010: function checkAll() {
1011: var checkboxes = document.getElementsByName('check');
1012: for (var i = 0; i < checkboxes.length; i++) {
1013: checkboxes[i].checked = "checked";
1014: }
1015: }
1016:
1017: function uncheckAll() {
1018: var checkboxes = document.getElementsByName('check');
1019: for (var i = 0; i < checkboxes.length; i++) {
1020: checkboxes[i].checked = "";
1021: }
1022: }
1023:
1.1 wenzelju 1024: JAVASCRIPT
1025: return $js;
1026: }
1027:
1.6 wenzelju 1028: sub JSforImport{
1029: my $rat = shift;
1030:
1031: my $js;
1032: if ($rat eq 'simple' || $rat eq '') {
1033: $js = &Apache::lonhtmlcommon::scripttag(<<JAVASCRIPT);
1034: function finish_import() {
1035: opener.document.forms.simpleedit.importdetail.value='';
1036: for (var num = 0; num < document.forms.groupsort.fnum.value; num++) {
1037: if (eval("document.forms.groupsort.check"+num+".checked") && eval("document.forms.groupsort.filelink"+num+".value") != '') {
1038: opener.document.forms.simpleedit.importdetail.value+='&'+
1039: eval("document.forms.groupsort.title"+num+".value")+'='+
1040: eval("document.forms.groupsort.filelink"+num+".value")+'='+
1041: eval("document.forms.groupsort.id"+num+".value");
1042: }
1043: }
1044: opener.document.forms.simpleedit.submit();
1045: self.close();
1046: }
1047: JAVASCRIPT
1048: }
1049: else {
1050: $js = &Apache::lonhtmlcommon::scripttag(<<JAVASCRIPT);
1051: function finish_import() {
1052: var linkflag=false;
1053: for (var num=0; num<document.forms.groupsort.fnum.value; num++) {
1054: if (eval("document.forms.groupsort.check"+num+".checked") && eval("document.forms.groupsort.filelink"+num+".value") != '') {
1055: insertRowInLastRow();
1056: placeResourceInLastRow(
1057: eval("document.forms.groupsort.title"+num+".value"),
1058: eval("document.forms.groupsort.filelink"+num+".value"),
1059: eval("document.forms.groupsort.id"+num+".value"),
1060: linkflag
1061: );
1062: linkflag=true;
1063: }
1064: }
1065: opener.editmode=0;
1066: opener.notclear=0;
1067: opener.linkmode=0;
1068: opener.draw();
1069: self.close();
1070: }
1071:
1072: function insertRowInLastRow() {
1073: opener.insertrow(opener.maxrow);
1074: opener.addobj(opener.maxrow,'e&2');
1075: }
1076:
1077: function placeResourceInLastRow (title,url,id,linkflag) {
1078: opener.mostrecent=opener.newresource(opener.maxrow,2,opener.unescape(title),
1079: opener.unescape(url),'false','normal',id);
1080: opener.save();
1081: if (linkflag) {
1082: opener.joinres(opener.linkmode,opener.mostrecent,0);
1083: }
1084: opener.linkmode=opener.mostrecent;
1085: }
1086: JAVASCRIPT
1087: }
1088: return $js;
1089: }
1.1 wenzelju 1090:
1091: # HTML-Markup for table if in view-mode
1092: my $wishlistHTMLview;
1093: my $indent = $indentConst;
1094: sub wishlistView {
1095: my $nodes = shift;
1096:
1097: foreach my $n (@$nodes) {
1098: my $index = $n->value()->nindex();
1099:
1100: # 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.
1101: # only display the top level entries on load
1102: $wishlistHTMLview .= ($n->parent()->value() eq 'root')?&Apache::loncommon::start_data_table_row('','row'.$index)
1103: :&Apache::loncommon::continue_data_table_row('LC_hidden','row'.$index);
1104:
1105:
1106: # checkboxes
1107: $wishlistHTMLview .= '<td><input type="checkbox" name="mark" id="check'.$index.'" value="'.$index.'" '.
1.11 raeburn 1108: 'onclick="selectAction('."'row".$index."'".')" /></td>';
1.1 wenzelju 1109:
1110: # entry is a folder
1111: if ($n->value()->path() eq '') {
1112: $wishlistHTMLview .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;">'.
1113: '<a href="javascript:;" onclick="folderAction('."'row".$index."'".')" style="vertical-align:top">'.
1114: '<img src="/adm/lonIcons/arrow.closed.gif" id="img'.$index.'" alt = "" class="LC_icon"/>'.
1115: '<img src="/adm/lonIcons/navmap.folder.closed.gif" id="imgFolder'.$index.'" alt="folder"/>'.
1116: $n->value()->title().'</a></td>';
1117: }
1118: # entry is a link
1119: else {
1120: $wishlistHTMLview .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px; min-width: 220px;">'.
1.2 wenzelju 1121: '<a href="javascript:preview('."'".$n->value()->path()."'".');">'.
1.1 wenzelju 1122: '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link" />'.
1.2 wenzelju 1123: $n->value()->title().'</a></td>';
1.1 wenzelju 1124: }
1125:
1126: # note-icon, different icons for an entries with note and those without
1127: my $noteIMG = 'anot.png';
1128:
1129: if ($n->value()->note() ne '') {
1130: $noteIMG = 'anot2.png';
1131: }
1132:
1133: $wishlistHTMLview .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
1134: '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
1135: ' class="LC_icon"/></a></td>';
1136:
1137: $wishlistHTMLview .= &Apache::loncommon::end_data_table_row();
1138:
1139: # start row containing the textarea for the note, do not display note on default
1140: $wishlistHTMLview .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
1141: '<td></td><td>'.
1142: '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
1143: 'name="newnote" >'.
1144: $n->value()->note().'</textarea></td><td></td>';
1145: $wishlistHTMLview .= &Apache::loncommon::end_data_table_row();
1146:
1147: # if the entry is a folder, it could have other entries as content. if it has, call wishlistView for those entries
1148: my @children = $n->children();
1149: if ($#children >=0) {
1150: $indent += 20;
1151: &wishlistView(\@children);
1152: $indent -= 20;
1153: }
1154: }
1155: }
1156:
1157:
1158: # HTML-Markup for table if in edit-mode
1159: my $wishlistHTMLedit;
1160: my $indent = $indentConst;
1161: sub wishlistEdit {
1162: my $nodes = shift;
1163: my $curNode = 1;
1164:
1165: foreach my $n (@$nodes) {
1166: my $index = $n->value()->nindex();
1167:
1168: # start row, use data_table routines to set class to LC_even or LC_odd automatically.
1169: # this rows contains a checkbox, a select-field for sorting entries, the title in an input-field and the note-icon.
1170: # only display the top level entries on load
1171: $wishlistHTMLedit .= ($n->parent()->value() eq 'root')?&Apache::loncommon::start_data_table_row('','row'.$index)
1172: :&Apache::loncommon::continue_data_table_row('LC_hidden','row'.$index);
1173:
1174: # checkboxes
1175: $wishlistHTMLedit .= '<td><input type="checkbox" name="mark" id="check'.$index.'" value="'.$index.'" '.
1.11 raeburn 1176: 'onclick="selectAction('."'row".$index."'".')" /></td>';
1.1 wenzelju 1177:
1178: # 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.
1179: # set the number for the current entry into brackets
1180: my $options;
1181: for (my $i = 1; $i < ((scalar @{$nodes})+1); $i++) {
1182: if ($i == $curNode) {
1183: $options .= '<option selected="selected" value="">('.$i.')</option>';
1184: }
1185: else {
1186: $options .= '<option value="'.$i.'">'.$i.'</option>';
1187: }
1188: }
1189: $curNode++;
1190:
1191: # entry is a folder
1192: if ($n->value()->path() eq '') {
1193: $wishlistHTMLedit .= '<td><select class="LC_hidden" name="sel" id="sel'.$index.'" onchange="submitSelect();">'.
1194: $options.'</select></td>'.
1195: '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px;">'.
1196: '<a href="javascript:;" onclick="folderAction('."'row".$index."'".')" style="vertical-align:top" >'.
1197: '<img src="/adm/lonIcons/arrow.closed.gif" id="img'.$index.'" alt = "" class="LC_icon"/>'.
1.3 wenzelju 1198: '<img src="/adm/lonIcons/navmap.folder.closed.gif" id="imgFolder'.$index.'" alt="folder"/></a>'.
1.11 raeburn 1199: '<input type="text" name="newtitle" value="'.$n->value()->title().'" alt = "'.$n->value()->title().'" />'.
1.3 wenzelju 1200: '</td><td></td>';
1.1 wenzelju 1201:
1202: }
1203: # entry is a link
1204: else {
1205: $wishlistHTMLedit .= '<td><select class="LC_hidden" name="sel" id="sel'.$index.'" onchange="submitSelect();">'.
1206: $options.'</select></td>'.
1207: '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px;">'.
1.3 wenzelju 1208: '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link"/>'.
1.11 raeburn 1209: '<input type="text" name="newtitle" value="'.$n->value()->title().'" alt = "'.$n->value()->title().'" /></td>'.
1210: '<td><input type="text" name="newpath" value="'.$n->value()->path().'" alt = "'.$n->value()->path().'" /></td>';
1.1 wenzelju 1211: }
1.3 wenzelju 1212:
1.1 wenzelju 1213: # note-icon, different icons for an entries with note and those without
1214: my $noteIMG = 'anot.png';
1215:
1216: if ($n->value()->note() ne '') {
1217: $noteIMG = 'anot2.png';
1218: }
1219:
1220: $wishlistHTMLedit .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
1221: '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
1222: ' class="LC_icon"/></a></td>';
1223:
1224: $wishlistHTMLedit .= &Apache::loncommon::end_data_table_row();
1225:
1226: # start row containing the textarea for the note
1227: $wishlistHTMLedit .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
1.3 wenzelju 1228: '<td></td><td></td><td colspan="2">'.
1.1 wenzelju 1229: '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
1230: 'name="newnote">'.
1231: $n->value()->note().'</textarea></td><td></td>';
1232: $wishlistHTMLedit .= &Apache::loncommon::end_data_table_row();
1233:
1234: # if the entry is a folder, it could have other entries as content. if it has, call wishlistEdit for those entries
1235: my @children = $n->children();
1236: if ($#children >=0) {
1237: $indent += 20;
1238: &wishlistEdit(\@children);
1239: $indent -= 20;
1240: }
1241: }
1242: }
1243:
1244:
1245:
1246: # HTML-Markup for table if in move-mode
1247: my $wishlistHTMLmove ='<tr id="root" class="LC_odd_row"><td><input type="radio" name="mark" id="radioRoot" value="root" /></td>'.
1248: '<td>'.&mt('Top level').'</td><td></td></tr>';
1249: my $indent = $indentConst;
1250: sub wishlistMove {
1251: my $nodes = shift;
1252: my $marked = shift;
1253:
1254: foreach my $n (@$nodes) {
1255: my $index = $n->value()->nindex();
1256:
1257: #find out wether the current entry was marked to be moved.
1258: my $isIn = 0;
1259: foreach my $m (@$marked) {
1260: if ($index == $m) {
1261: $isIn = 1;
1262: }
1263: }
1264: # 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
1265: $wishlistHTMLmove .= &Apache::loncommon::start_data_table_row('','row'.$index);
1266:
1267:
1268: # entry is a folder
1269: if ($n->value()->path() eq '') {
1270: # display a radio-button, if the folder was not selected to be moved
1271: if (!$isIn) {
1272: $wishlistHTMLmove .= '<td><input type="radio" name="mark" id="radio'.$index.'" value="'.$index.'" /></td>'.
1273: '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;">';
1274: }
1.14 ! bisitz 1275: # highlight the title, if the folder was selected to be moved
1.1 wenzelju 1276: else {
1277: $wishlistHTMLmove .= '<td></td>'.
1278: '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;'.
1279: 'color:red;">';
1280: }
1281: #arrow- and folder-image, all folders are open, and title
1282: $wishlistHTMLmove .= '<img src="/adm/lonIcons/arrow.open.gif" id="img'.$index.'" alt = "" />'.
1283: '<img src="/adm/lonIcons/navmap.folder.open.gif" id="imgFolder'.$index.'" alt="folder"/>'.
1284: $n->value()->title().'</td>';
1285: }
1286: # entry is a link
1287: else {
1288: # higlight the title, if the link was selected to be moved
1.2 wenzelju 1289: my $highlight = '';
1290: if ($isIn) {
1291: $highlight = 'style="color:red;"';
1.1 wenzelju 1292: }
1293: # link-image and title
1.2 wenzelju 1294: $wishlistHTMLmove .= '<td></td>'.
1295: '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px; min-width: 220px;">'.
1296: '<a href="javascript:preview('."'".$n->value()->path()."'".');" '.$highlight.'>'.
1297: '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link"/>'.
1298: $n->value()->title().'</a></td>';
1.1 wenzelju 1299: }
1300:
1301: # note-icon, different icons for an entries with note and those without
1302: my $noteIMG = 'anot.png';
1303:
1304: if ($n->value()->note() ne '') {
1305: $noteIMG = 'anot2.png';
1306: }
1307:
1308: $wishlistHTMLmove .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
1309: '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
1310: ' class="LC_icon"/></a></td>';
1311:
1312: $wishlistHTMLmove .= &Apache::loncommon::end_data_table_row();
1313:
1314: # start row containing the textarea for the note, readonly in move-mode
1315: $wishlistHTMLmove .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
1316: '<td></td><td>'.
1317: '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
1318: 'name="newnote" readonly="readonly">'.
1319: $n->value()->note().'</textarea></td><td></td>'.
1320: &Apache::loncommon::end_data_table_row();
1321:
1322: # if the entry is a folder, it could have other entries as content. if it has, call wishlistMove for those entries
1323: my @children = $n->children();
1324: if ($#children >=0) {
1325: $indent += 20;
1326: &wishlistMove(\@children, $marked);
1327: $indent -= 20;
1328: }
1329: }
1330: }
1331:
1.2 wenzelju 1332:
1333:
1334: # HTML-Markup for table if in import-mode
1335: my $wishlistHTMLimport;
1336: my $indent = $indentConst;
1337: my $form = 1;
1338: sub wishlistImport {
1339: my $nodes = shift;
1340:
1341: foreach my $n (@$nodes) {
1342: my $index = $n->value()->nindex();
1343:
1344: # 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.
1345: # only display the top level entries on load
1346: $wishlistHTMLimport .= ($n->parent()->value() eq 'root')?&Apache::loncommon::start_data_table_row('','row'.$index)
1347: :&Apache::loncommon::continue_data_table_row('LC_hidden','row'.$index);
1348:
1349:
1350: # checkboxes
1351: $wishlistHTMLimport .= '<td>'.
1352: '<input type="checkbox" name="check" id="check'.$index.'" value="'.$index.'" '.
1.11 raeburn 1353: 'onclick="selectAction('."'row".$index."'".')" />'.
1354: '<input type="hidden" name="title'.$index.'" value="'.&escape($n->value()->title()).'" />'.
1355: '<input type="hidden" name="filelink'.$index.'" value="'.&escape($n->value()->path()).'" />'.
1356: '<input type="hidden" name="id'.$index.'" />'.
1.2 wenzelju 1357: '</td>';
1358:
1359: # entry is a folder
1360: if ($n->value()->path() eq '') {
1361: $wishlistHTMLimport .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<0?0:($indent-$indentConst)).'px; min-width: 220px;">'.
1362: '<a href="javascript:;" onclick="folderAction('."'row".$index."'".')" style="vertical-align:top">'.
1363: '<img src="/adm/lonIcons/arrow.closed.gif" id="img'.$index.'" alt = "" class="LC_icon"/>'.
1364: '<img src="/adm/lonIcons/navmap.folder.closed.gif" id="imgFolder'.$index.'" alt="folder"/>'.
1365: $n->value()->title().'</a></td>';
1366: }
1367: # entry is a link
1368: else {
1369: $wishlistHTMLimport .= '<td id="padd'.$index.'" style="padding-left:'.(($indent-$indentConst)<=0?$indentConst:$indent).'px; min-width: 220px;">'.
1370: '<a href="javascript:preview('."'".$n->value()->path()."'".');">'.
1371: '<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link" />'.
1372: $n->value()->title().'</a></td>';
1373: $form++;
1374: }
1375:
1376: # note-icon, different icons for an entries with note and those without
1377: my $noteIMG = 'anot.png';
1378:
1379: if ($n->value()->note() ne '') {
1380: $noteIMG = 'anot2.png';
1381: }
1382:
1383: $wishlistHTMLimport .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
1384: '<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
1385: ' class="LC_icon"/></a></td>';
1386:
1387: $wishlistHTMLimport .= &Apache::loncommon::end_data_table_row();
1388:
1389: # start row containing the textarea for the note, do not display note on default, readonly in import-mode
1390: $wishlistHTMLimport .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
1391: '<td></td><td>'.
1392: '<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
1393: 'name="newnote" readonly="readonly">'.
1394: $n->value()->note().'</textarea></td><td></td>';
1395: $wishlistHTMLimport .= &Apache::loncommon::end_data_table_row();
1396:
1397: # if the entry is a folder, it could have other entries as content. if it has, call wishlistImport for those entries
1398: my @children = $n->children();
1399: if ($#children >=0) {
1400: $indent += 20;
1401: &wishlistImport(\@children);
1402: $indent -= 20;
1403: }
1404: }
1405: }
1406:
1.1 wenzelju 1407: # Returns the HTML-Markup for wishlist
1408: sub makePage {
1.9 wenzelju 1409: my $rootgiven = shift;
1.1 wenzelju 1410: my $mode = shift;
1411: my $marked = shift;
1412:
1.9 wenzelju 1413: $root = $rootgiven;
1414: @childrenRt = $root->children();
1415:
1.1 wenzelju 1416: # breadcrumbs and start_page
1417: &Apache::lonhtmlcommon::clear_breadcrumbs();
1418: &Apache::lonhtmlcommon::add_breadcrumb(
1419: { href => '/adm/wishlist?mode='.$mode,
1.12 raeburn 1420: text => 'Stored Links'});
1421: my $startPage = &Apache::loncommon::start_page('Stored Links',undef,
1.1 wenzelju 1422: {'add_entries' => {
1423: 'onload' => 'javascript:onLoadAction('."'".$mode."'".');',
1424: 'onunload' => 'javascript:window.name = '."'loncapaclient'"}});
1425:
1.12 raeburn 1426: my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs(&mt('Stored Links').&Apache::loncommon::help_open_topic('Wishlist'));
1.1 wenzelju 1427:
1428: # get javascript-code for wishlist-interactions
1429: my $js = &JSforWishlist();
1430:
1431: # texthash for items in funtionlist
1432: my %lt = &Apache::lonlocal::texthash(
1433: 'ed' => 'Edit',
1434: 'vw' => 'View',
1435: 'al' => 'Add Link',
1436: 'af' => 'Add Folder',
1437: 'mv' => 'Move Selected',
1438: 'dl' => 'Delete Selected',
1439: 'sv' => 'Save');
1440:
1441: # start functionlist
1442: my $functions = &Apache::lonhtmlcommon::start_funclist();
1443:
1444: # icon for edit-mode, display when in view-mode
1445: if ($mode eq 'view') {
1446: $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
1.3 wenzelju 1447: 'onclick="setFormAction('."'save','edit'".');" class="LC_menubuttons_link">'.
1.1 wenzelju 1448: '<img src="/res/adm/pages/edit-mode-22x22.png" alt="'.$lt{'ed'}.'" '.
1449: 'title="'.$lt{'ed'}.'" class="LC_icon"/> '.
1450: '<span class="LC_menubuttons_inline_text">'.$lt{'ed'}.'</span></a>');
1451: }
1452: # icon for view-mode, display when in edit-mode
1453: else {
1454: $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
1.3 wenzelju 1455: 'onclick="setFormAction('."'save','view'".');" class="LC_menubuttons_link">'.
1.1 wenzelju 1456: '<img src="/res/adm/pages/view-mode-22x22.png" alt="'.$lt{'vw'}.'" '.
1457: 'title="'.$lt{'vw'}.'" class="LC_icon"/> '.
1458: '<span class="LC_menubuttons_inline_text">'.$lt{'vw'}.'</span></a>');
1459: }
1460:
1461: # icon for adding a new link
1462: $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
1463: 'onclick="newLink();" class="LC_menubuttons_link">'.
1464: '<img src="/res/adm/pages/link-new-22x22.png" alt="'.$lt{'al'}.'" '.
1465: 'title="'.$lt{'al'}.'" class="LC_icon"/>'.
1466: '<span class="LC_menubuttons_inline_text">'.$lt{'al'}.'</span></a>');
1467:
1468: # icon for adding a new folder
1469: $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
1470: 'onclick="newFolder();" class="LC_menubuttons_link">'.
1471: '<img src="/res/adm/pages/folder-new-22x22.png" alt="'.$lt{'af'}.'" '.
1472: 'title="'.$lt{'af'}.'" class="LC_icon"/>'.
1473: '<span class="LC_menubuttons_inline_text">'.$lt{'af'}.'</span></a>');
1474:
1475: # icon for moving entries
1476: $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
1477: 'onclick="setFormAction('."'move','move'".'); " class="LC_menubuttons_link">'.
1478: '<img src="/res/adm/pages/move-22x22.png" alt="'.$lt{'mv'}.'" '.
1479: 'title="'.$lt{'mv'}.'" class="LC_icon" />'.
1480: '<span class="LC_menubuttons_inline_text">'.$lt{'mv'}.'</span></a>');
1481:
1482: # icon for deleting entries
1483: $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
1484: 'onclick="setFormAction('."'delete','".$mode."'".'); " class="LC_menubuttons_link">'.
1485: '<img src="/res/adm/pages/del.png" alt="'.$lt{'dl'}.'" '.
1486: 'title="'.$lt{'dl'}.'" class="LC_icon" />'.
1487: '<span class="LC_menubuttons_inline_text">'.$lt{'dl'}.'</span></a>');
1488:
1489: # icon for saving changes
1490: $functions .= &Apache::lonhtmlcommon::add_item_funclist('<a href="javascript:;" '.
1.3 wenzelju 1491: 'onclick="setFormAction('."'saveOK','".$mode."'".'); " class="LC_menubuttons_link">'.
1.1 wenzelju 1492: '<img src="/res/adm/pages/save-22x22.png" alt="'.$lt{'sv'}.'" '.
1493: 'title="'.$lt{'sv'}.'" class="LC_icon" />'.
1494: '<span class="LC_menubuttons_inline_text">'.$lt{'sv'}.'</span></a>');
1495:
1496: # end funtionlist and generate subbox
1497: $functions.= &Apache::lonhtmlcommon::end_funclist();
1498: my $subbox = &Apache::loncommon::head_subbox($functions);
1499:
1500: # start form
1501: my $inner .= '<form name="list" action ="/adm/wishlist" method="post">'.
1.11 raeburn 1502: '<input type="hidden" id="action" name="action" value="" />';
1.1 wenzelju 1503:
1504: # only display subbox in view- or edit-mode
1.2 wenzelju 1505: if ($mode eq 'view' || $mode eq 'edit') {
1.1 wenzelju 1506: $inner .= $subbox;
1507: }
1508:
1509: # generate table-content depending on mode
1510: if ($mode eq 'edit') {
1511: &wishlistEdit(\@childrenRt);
1512: if ($wishlistHTMLedit ne '') {
1513: $inner .= &Apache::loncommon::start_data_table("LC_tableOfContent");
1514: $inner .= $wishlistHTMLedit;
1515: $inner .= &Apache::loncommon::end_data_table();
1516: }
1517: else {
1.13 bisitz 1518: $inner .= '<span class="LC_info">'.&mt("Your Stored Links list is currently empty.").'</span>';
1.1 wenzelju 1519: }
1520: $wishlistHTMLedit = '';
1521: }
1522: elsif ($mode eq 'view') {
1523: &wishlistView(\@childrenRt);
1524: if ($wishlistHTMLview ne '') {
1525: $inner .= '<table class="LC_data_table LC_tableOfContent">'.$wishlistHTMLview.'</table>';
1526: }
1527: else {
1.12 raeburn 1528: $inner .= '<span class="LC_info">'.&mt("Your Stored Links list is currently empty.").'</span>';
1.1 wenzelju 1529: }
1530: $wishlistHTMLview = '';
1531: }
1532: else {
1533: my $markStr = '';
1534: foreach my $m (@$marked) {
1535: $markStr .= $m.',';
1536: }
1537: if ($markStr) {
1538: $markStr = substr($markStr, 0, length($markStr)-1);
1.11 raeburn 1539: $inner .= '<input type="hidden" value="'.$markStr.'" name="markedToMove" />';
1.2 wenzelju 1540: $inner .= '<p><span class="LC_info">'.&mt('You have selected the red marked entries to be moved to another folder. '.
1541: 'Now choose the new destination folder.').'</span></p>';
1.1 wenzelju 1542: &wishlistMove(\@childrenRt, $marked);
1543: $inner .= '<table class="LC_data_table LC_tableOfContent">'.$wishlistHTMLmove.'</table><br/><br/>';
1.11 raeburn 1544: $inner .= '<input type="button" value="'.&mt('Move').'" onclick="setFormAction('."'move','view'".');" />'.
1545: '<input type="button" value="'.&mt('Cancel').'" onclick="go('."'/adm/wishlist'".')" />';
1.1 wenzelju 1546:
1547: $wishlistHTMLmove ='<tr id="root" class="LC_odd_row"><td><input type="radio" name="mark" id="radioRoot" value="root" /></td>'.
1548: '<td>'.&mt('Top level').'</td><td></td></tr>';
1549: }
1550: else {
1.2 wenzelju 1551: $inner .= '<p><span class="LC_info">'.&mt("You haven't marked any entry to move.").'</span></p>'.
1.11 raeburn 1552: '<input type="button" value="'.&mt('Back').'" onclick="go('."'/adm/wishlist'".')" />';
1.1 wenzelju 1553: }
1554: }
1555:
1556: # end form
1557: $inner .= '</form>';
1558:
1559: # end_page
1560: my $endPage = &Apache::loncommon::end_page();
1561:
1.2 wenzelju 1562: # put all page-elements together
1.1 wenzelju 1563: my $page = $startPage.$breadcrumbs.$js.$inner.$endPage;
1564:
1565: return $page;
1566: }
1567:
1568:
1.9 wenzelju 1569: # Returns the HTML-Markup for the PopUp, shown when a new link should set, when NOT
1570: # beeing in the wishlist-interface (method is called in lonmenu and lonsearchcat)
1.10 wenzelju 1571: sub makePopUpNewLink {
1572: my ($title, $path) = @_;
1.9 wenzelju 1573:
1574: # Get all existing folders to offer posibility to set a new link
1575: # into a folder
1576: my %TreeHashLink = &Apache::lonwishlist::getWishlist();
1577: my $rootLink = &Apache::Tree::HashToTree(\%TreeHashLink);
1578: my @childrenRtLink = $rootLink->children();
1579:
1580: $foldersOption = '';
1581: @allFolders = ();
1582: &getFoldersToArray(\@childrenRtLink);
1583: &getFoldersForOption(\@childrenRtLink);
1584:
1585: my $options = '<option value="" selected="selected">('.&mt('Top level').')</option>'.$foldersOption;
1586: $foldersOption = '';
1587: @allFolders = ();
1588:
1.10 wenzelju 1589: # HTML-Markup for the Pop-Up-window 'Set a link for this resource to wishlist'
1590: my $startPageWishlistlink =
1.12 raeburn 1591: &Apache::loncommon::start_page('Save to Stored Links',undef,
1.10 wenzelju 1592: {'only_body' => 1,
1593: 'bgcolor' => '#FFFFFF',});
1.9 wenzelju 1594:
1595: my $warningLink = &mt('You must insert a title!');
1.14 ! bisitz 1596: my $warningLinkNotAllowed1 =
! 1597: &mt('You can only insert links to LON-CAPA resources from the resource-pool'.
! 1598: ' or to external websites.'.
! 1599: ' Paths to LON-CAPA resources must be of the form /res/domain/user/...'.
! 1600: ' Paths to external websites must contain the network protocol, e.g. http://...');
1.10 wenzelju 1601:
1.12 raeburn 1602: my $inPageWishlistlink1 = '<h1>'.&mt('Save to Stored Links').'</h1>';
1.10 wenzelju 1603: # If no title is delivered, 'New Link' is called up from the wishlist-interface, so after
1604: # submitting the window should close instead of offering a link to wishlist (like it should do
1605: # if we call 'Set New Link' from within a browsed ressource)
1606: if (!$title) {
1607: $inPageWishlistlink1 .= '<form method="post" name="newlink" action="/adm/wishlist" target="wishlist"'.
1608: 'onsubmit="return newlinksubmit();" >';
1609: }
1610: else {
1611: $inPageWishlistlink1 .= '<form method="post" name="newlink" action="/adm/wishlist?mode=set" '.
1612: 'onsubmit="return newlinksubmit();" >';
1613: }
1614: $inPageWishlistlink1 .= &Apache::lonhtmlcommon::start_pick_box().
1615: &Apache::lonhtmlcommon::row_title(&mt('Link Title'));
1616:
1617: my $inPageWishlistlink2 = &Apache::lonhtmlcommon::row_closure().
1618: &Apache::lonhtmlcommon::row_title(&mt('Path'));
1.9 wenzelju 1619:
1.10 wenzelju 1620: my $inPageWishlistlink3 = &Apache::lonhtmlcommon::row_closure().
1621: &Apache::lonhtmlcommon::row_title(&mt('Note')).
1622: '<textarea name="note" rows="3" cols="35" style="width:100%"></textarea>'.
1623: &Apache::lonhtmlcommon::row_closure(1).
1624: &Apache::lonhtmlcommon::end_pick_box().
1625: '<br/><br/>'.
1626: '<input type="submit" value="'.&mt('Save in').'" />'.
1627: '<select name="folders">'.
1628: $options.
1629: '</select>'.
1.14 ! bisitz 1630: '<input type="button" value="'.&mt('Cancel').'" onclick="javascript:window.close();" />'.
1.10 wenzelju 1631: '</form>';
1.9 wenzelju 1632: $options = '';
1633:
1.10 wenzelju 1634: my $endPageWishlistlink = &Apache::loncommon::end_page();
1635:
1636: my $popUp = $startPageWishlistlink.
1637: $inPageWishlistlink1.
1.11 raeburn 1638: '<input type="text" name="title" size="45" value="" />'.
1.10 wenzelju 1639: $inPageWishlistlink2.
1.11 raeburn 1640: '<input type="text" name="path" size="45" value="" />'.
1.10 wenzelju 1641: $inPageWishlistlink3;
1642:
1643: # JavaScript-function to set title and path of ressource automatically
1644: # and show warning, if no title was set or path is invalid
1645: $popUp .= <<SCRIPT;
1646: <script type="text\/javascript">
1647: document.getElementsByName("title")[0].value = '$title';
1648: document.getElementsByName("path")[0].value = '$path';
1649: var fromwishlist = false;
1650: var titleget = '$title';
1651: if (!titleget) {
1652: fromwishlist = true;
1653: }
1654: function newlinksubmit(){
1655: var title = document.getElementsByName("title")[0].value;
1656: var path = document.getElementsByName("path")[0].value;
1657: if (!title) {
1658: alert("$warningLink");
1659: return false;}
1660: var linkOK = (path.match(/\^http:(\\\/\\\/)/) || path.match(/\^https:(\\\/\\\/)/))
1661: && !(path.match(/\\.problem/) || path.match(/\\.exam/)
1662: || path.match(/\\.quiz/) || path.match(/\\.assess/)
1663: || path.match(/\\.survey/) || path.match(/\\.form/)
1664: || path.match(/\\.library/) || path.match(/\\.page/)
1665: || path.match(/\\.sequence/));
1666: if (!path.match(/\^(\\\/res\\\/)/) && !linkOK) {
1667: alert("$warningLinkNotAllowed1");
1668: return false;}
1669: if (fromwishlist) {
1670: window.close();
1671: }
1672: return true;}
1673: <\/script>
1.9 wenzelju 1674: SCRIPT
1675:
1.10 wenzelju 1676: $popUp .= $endPageWishlistlink;
1677:
1678: return $popUp;
1679: }
1680:
1681: sub makePopUpNewFolder {
1682: # Get all existing folders to offer posibility to create a new folder
1683: # into an existing folder
1684: my %TreeHashLink = &Apache::lonwishlist::getWishlist();
1685: my $rootLink = &Apache::Tree::HashToTree(\%TreeHashLink);
1686: my @childrenRtLink = $rootLink->children();
1687:
1688: $foldersOption = '';
1689: @allFolders = ();
1690: &getFoldersToArray(\@childrenRtLink);
1691: &getFoldersForOption(\@childrenRtLink);
1692:
1693: my $options = '<option value="" selected="selected">('.&mt('Top level').')</option>'.$foldersOption;
1694: $foldersOption = '';
1695: @allFolders = ();
1696:
1697: # HTML-Markup for the Pop-Up-window 'New Folder'
1698: my $startPageWishlistfolder =
1699: &Apache::loncommon::start_page('New Folder',undef,
1700: {'only_body' => 1,
1701: 'bgcolor' => '#FFFFFF',});
1702:
1703: my $warningFolder = &mt('You must insert a title!');
1704:
1705:
1706: my $inPageNewFolder = '<h1>'.&mt('New Folder').'</h1>'.
1707: '<form method="post" name="newfolder" action="/adm/wishlist" target="wishlist" '.
1708: 'onsubmit="return newfoldersubmit();" >'.
1709: &Apache::lonhtmlcommon::start_pick_box().
1710: &Apache::lonhtmlcommon::row_title(&mt('Folder title')).
1711: '<input type="text" name="title" size="45" value="" /><br />'.
1712: &Apache::lonhtmlcommon::row_closure().
1713: &Apache::lonhtmlcommon::row_title(&mt('Note')).
1714: '<textarea name="note" rows="3" cols="35" style="width:100%"></textarea><br />'.
1715: &Apache::lonhtmlcommon::row_closure(1).
1716: &Apache::lonhtmlcommon::end_pick_box().
1717: '<br/><br/>'.
1718: '<input type="submit" value="'.&mt('Save in').'" />'.
1719: '<select name="folders">'.
1720: $options.
1721: '</select>'.
1722: '<input type="button" value="'.&mt('Cancel').'" onclick="javascript:window.close();" />'.
1723: '</form>';
1724: my $endPageWishlistfolder = &Apache::loncommon::end_page();
1725:
1726: my $popUp = $startPageWishlistfolder.
1727: $inPageNewFolder;
1728:
1729: $popUp .= <<SCRIPT;
1730: <script type="text\/javascript">
1731: function newfoldersubmit(){
1732: var title = document.getElementsByName("title")[0].value;
1733: if (!title) {
1734: alert("$warningFolder");
1735: return false;}
1736: else {
1737: window.close();
1738: return true;}}
1739: <\/script>
1740: SCRIPT
1741:
1742: $popUp .= $endPageWishlistfolder;
1743:
1744: return $popUp;
1.9 wenzelju 1745: }
1746:
1.1 wenzelju 1747: # Returns the HTML-Markup for the page, shown when a link was set
1748: sub makePageSet {
1749: # start_page
1.12 raeburn 1750: my $startPage = &Apache::loncommon::start_page('Stored Links',undef,
1.1 wenzelju 1751: {'only_body' => 1});
1752:
1753: # confirm success and offer link to wishlist
1.12 raeburn 1754: my $message = &Apache::lonhtmlcommon::confirm_success(&mt('Link successfully saved!'));
1.1 wenzelju 1755: $message = &Apache::loncommon::confirmwrapper($message);
1756:
1757: my $inner .= '<br>'.$message.'<br/><br/>'.
1.12 raeburn 1758: '<a href="javascript:;" onclick="opener.open('."'/adm/wishlist'".');window.close();">'.&mt('Go to Stored Links').'</a>'.(' ' x 3).
1759: '<a href="javascript:;" onclick="window.close();">'.&mt('Close this window').'</a>';
1.1 wenzelju 1760:
1761: # end_page
1762: my $endPage = &Apache::loncommon::end_page();
1763:
1.2 wenzelju 1764: # put all page-elements together
1.1 wenzelju 1765: my $page = $startPage.$inner.$endPage;
1766:
1767: return $page;
1768: }
1769:
1770:
1.2 wenzelju 1771: # Returns the HTML-Markup for the page, shown when links should be imported into a course
1772: sub makePageImport {
1.9 wenzelju 1773: my $rootgiven = shift;
1.6 wenzelju 1774: my $rat = shift;
1.9 wenzelju 1775:
1776: $root = $rootgiven;
1777: @childrenRt = $root->children();
1.2 wenzelju 1778: # start_page
1.12 raeburn 1779: my $startPage = &Apache::loncommon::start_page('Stored Links',undef,
1.2 wenzelju 1780: {'only_body' => 1});
1781:
1782: # get javascript-code for wishlist-interactions
1783: my $js = &JSforWishlist();
1.6 wenzelju 1784: $js .= &JSforImport($rat);
1.2 wenzelju 1785:
1.12 raeburn 1786: my $inner = '<h1>'.&mt('Import Resources from Stored Links').'</h1>';
1.6 wenzelju 1787: if (!$rat) {
1.14 ! bisitz 1788: $inner .=
! 1789: '<p class="LC_info">'.
! 1790: &mt('Please note that you can use the checkboxes corresponding to a folder to '.
! 1791: 'easily check all links within this folder.'.
! 1792: ' The folder structure itself cannot be imported.').
! 1793: ' '.&mt('All checked links will be imported into the current folder of your course.').
! 1794: '</p>';
1.6 wenzelju 1795: }
1796: else {
1.14 ! bisitz 1797: $inner .=
! 1798: '<p class="LC_info">'.
! 1799: &mt('Please note that you can use the checkboxes corresponding to a folder to '.
! 1800: 'easily check all links within this folder.'.
! 1801: ' The folder structure itself cannot be imported.').
! 1802: '</p>';
1.6 wenzelju 1803: }
1.2 wenzelju 1804: my %wishlist = &getWishlist();
1.9 wenzelju 1805:
1806: #FIXME Saved string containing all folders in wishlist.db-file (key 'folders') in first version of lonwishlist
1807: #After splitting lonwishlist into two modules, this is not necessary anymore. So, dependent from when the wishlist
1808: #was first called (i.e. when wishlist.db was created), there might be an entry 'folders' or not. Number of links in
1809: #wishlist.db depends on wether this entry exists or not...JW
1810: my $fnum;
1811: if (defined $wishlist{'folders'}) {
1812: $fnum = (keys %wishlist)-2;
1813: }
1814: else {
1815: $fnum = (keys %wishlist)-1;
1816: }
1.2 wenzelju 1817:
1.11 raeburn 1818: $inner .= '<form method="post" name="groupsort" action="">'.
1819: '<input type="hidden" value="'.$fnum.'" name="fnum" />'.
1820: '<input type="button" onclick="javascript:checkAll()" id="checkallbutton" value="'.&mt('Check All').'" />'.
1821: '<input type="button" onclick="javascript:uncheckAll()" id="uncheckallbutton" value="'.&mt('Uncheck All').'" />'.
1822: '<input type="button" value="'.&mt('Import Checked').'" onclick="finish_import();" />'.
1823: '<input type="button" value="'.&mt('Cancel').'" onclick="window.close();" /><br/><br/>';
1.2 wenzelju 1824:
1825:
1826: # wishlist-table
1827: &wishlistImport(\@childrenRt);
1828: if ($wishlistHTMLimport ne '') {
1829: $inner .= '<table class="LC_data_table LC_tableOfContent">'.$wishlistHTMLimport.'</table>';
1830: }
1831: else {
1.12 raeburn 1832: $inner .= '<span class="LC_info">'.&mt("Your Stored Links list is currently empty.").'</span>';
1.2 wenzelju 1833: }
1834: $wishlistHTMLimport = '';
1835:
1836: $inner .= '</form>';
1837:
1838: # end_page
1839: my $endPage = &Apache::loncommon::end_page();
1840:
1841: # put all page-elements together
1842: my $page = $startPage.$js.$inner.$endPage;
1843:
1844: return $page;
1845: }
1846:
1847:
1.1 wenzelju 1848: # Returns the HTML-Markup for error-page
1849: sub makeErrorPage {
1850: # breadcrumbs and start_page
1851: &Apache::lonhtmlcommon::add_breadcrumb(
1852: { href => '/adm/wishlist',
1853: text => 'Wishlist'});
1.12 raeburn 1854: my $startPage = &Apache::loncommon::start_page('Stored Links');
1.1 wenzelju 1855:
1.12 raeburn 1856: my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs(&mt('Stored Links').&Apache::loncommon::help_open_topic('Wishlist'));
1.1 wenzelju 1857: &Apache::lonhtmlcommon::clear_breadcrumbs();
1858:
1859: # error-message
1860: my $inner .= '<span class="LC_error">'.&mt('An error occurred! Please try again later.').'</span>';
1861:
1862: # end_page
1863: my $endPage = &Apache::loncommon::end_page();
1864:
1.2 wenzelju 1865: # put all page-elements together
1.1 wenzelju 1866: my $page = $startPage.$breadcrumbs.$inner.$endPage;
1867:
1868: return $page;
1869: }
1870:
1871:
1872: # ----------------------------------------------------- package Tree
1873: # Extend CPAN-Module Tree by function like 'moveNode' or 'deleteNode'
1.9 wenzelju 1874: package Apache::Tree;
1.1 wenzelju 1875:
1.4 wenzelju 1876: =pod
1877:
1878: =head2 Routines from package Tree
1879:
1880: =over 4
1881:
1882: =item * &getNodeByIndex(index, nodes)
1883:
1884: Searches for a node, specified by the index, in nodes (reference to array) and returns it.
1885:
1886:
1887: =item * &moveNode(node, at, newParent)
1888:
1889: 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).
1890:
1891:
1892: =item * &removeNode(node)
1893:
1894: Removes a node given by node from the tree.
1895:
1896:
1897: =item * &TreeIndex(children)
1898:
1899: Sets an index for every node in the tree, beginning with 0.
1900: 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).
1901:
1902:
1903: =item * &setCountZero()
1904:
1905: Resets index counter.
1906:
1907:
1908: =item * &RootToHash(childrenRt)
1909:
1910: Converts the root-node to a hash-entry: the key is root and values are just the indices of root's children.
1911:
1912:
1913: =item * &TreeToHash(childrenRt)
1914:
1915: 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).
1916: 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).
1917:
1918:
1919: =item * &HashToTree()
1920:
1921: 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.
1922:
1923:
1924: =item * &buildTree(node, childrenIn, TreeNodes, TreeHash)
1925:
1926: Joins the nodes to a tree.
1927: 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).
1928:
1929:
1930: =back
1931:
1932: =cut
1933:
1934:
1.1 wenzelju 1935: # returns the node with a given index from a list of nodes
1936: sub getNodeByIndex {
1937: my $index = shift;
1938: my $nodes = shift;
1939: my $found;
1940:
1.9 wenzelju 1941: foreach my $n (@$nodes) {
1.1 wenzelju 1942: my $curIndex = $n->value()->nindex();
1.9 wenzelju 1943: if ($curIndex == $index) {
1.1 wenzelju 1944: $found = $n;
1945: }
1946: }
1947: return $found;
1948: }
1949:
1950: # moves a given node to a new parent or change the position from a node
1951: # within its siblings (sorting)
1952: sub moveNode {
1953: my $node = shift;
1954: my $at = shift;
1955: my $newParent = shift;
1956:
1957:
1958: if (!$newParent) {
1959: $newParent = $node->parent();
1960: }
1961:
1962: $node->parent()->remove_child($node);
1963:
1964: if (defined $at) {
1965: $newParent->add_child({at => $at},$node);
1966: }
1967: else {
1968: $newParent->add_child($node);
1969: }
1970:
1971: # updating root's children
1972: @childrenRt = $root->children();
1973: }
1974:
1975: # removes a given node
1976: sub removeNode() {
1977: my $node = shift;
1978: my @children = $node->children();
1979:
1980: if ($#children >= 0) {
1981: foreach my $c (@children) {
1982: &removeNode($c);
1983: }
1984: }
1985: $node->parent()->remove_child($node);
1986:
1987: # updating root's children
1988: @childrenRt = $root->children();
1989: }
1990:
1991:
1992: # set an index for every node in the tree, beginning with 0
1993: my $count = 0;
1994: sub TreeIndex {
1995: my $children = shift;
1996:
1997: foreach my $n (@$children) {
1998: my @children = $n->children();
1999: $n->value()->nindex($count);$count++;
2000:
2001: if ($#children>=0) {
2002: &TreeIndex(\@children);
2003: }
2004: }
2005: }
2006:
2007: # reset index counter
2008: sub setCountZero {
2009: $count = 0;
2010: }
2011:
2012:
2013: # convert the tree to a hash
2014: # each node is one hash-entry
2015: # keys are the indices, values are all other attributes
2016: # (containing tile, path, note, date and indices for all direct children)
2017: # except for root: the key is root and values are
2018: # just the indices of root's children
2019: sub RootToHash {
2020: my $childrenRt = shift;
2021: my @indexarr = ();
2022:
2023: foreach my $c (@$childrenRt) {
2024: push (@indexarr, $c->value()->nindex());
2025: }
2026: $TreeToHash{'root'} = [@indexarr];
2027: }
2028:
2029: sub TreeToHash {
2030: my $childrenRt = shift;
2031:
2032: foreach my $n (@$childrenRt) {
2033: my @arrtmp = ();
2034: $arrtmp[0] = $n->value()->title();
2035: $arrtmp[1] = $n->value()->path();
2036: $arrtmp[2] = $n->value()->note();
2037: $arrtmp[3] = $n->value()->date();
2038: my @childrenRt = $n->children();
2039: my $co = 4;
2040: foreach my $c (@childrenRt) {
2041: my $i = $c->value()->nindex();
2042: $arrtmp[$co] = $i;
2043: $co++;
2044: }
2045: $TreeToHash{$n->value()->nindex} = [ @arrtmp];
2046: if ($#childrenRt>=0) {
2047: &TreeToHash(\@childrenRt);
2048: }
2049: }
2050: }
2051:
2052:
2053: # convert the hash to a tree
2054: # build a tree-object for each entry in the hash
2055: # afterwards call &buildTree to connect the tree-objects
2056: sub HashToTree {
1.9 wenzelju 2057: my $TreeHash = shift;
1.1 wenzelju 2058: my @TreeNodes = ();
2059: my $root;
2060:
1.9 wenzelju 2061: foreach my $key (keys %$TreeHash) {
1.1 wenzelju 2062: if ($key eq 'root') {
2063: $root = Tree->new("root");
2064: }
1.8 wenzelju 2065: elsif ($key ne 'folders') {
1.9 wenzelju 2066: my @attributes = @{ $$TreeHash{$key} };
1.1 wenzelju 2067: my $tmpNode;
2068: $tmpNode = Tree->new(Entry->new(title=>$attributes[0],
2069: path=>$attributes[1],
2070: note=>$attributes[2],
2071: date=>$attributes[3],
2072: nindex=>$key));
2073: push(@TreeNodes, $tmpNode);
2074: # shift all attributes except for
2075: # the indices representing the children of a node
2076: shift(@attributes);
2077: shift(@attributes);
2078: shift(@attributes);
2079: shift(@attributes);
1.9 wenzelju 2080: $$TreeHash{$key} = [ @attributes ];
1.1 wenzelju 2081: }
2082: }
2083: # if there are nodes, build up the tree-structure
1.9 wenzelju 2084: if (defined $$TreeHash{'root'} && $$TreeHash{'root'} ne '') {
2085: my @childrenRtIn = @{ $$TreeHash{'root'} };
2086: &buildTree(\$root, \@childrenRtIn,\@TreeNodes,$TreeHash);
1.1 wenzelju 2087: }
2088: return $root;
2089: }
2090:
2091:
2092: # join the nodes to a tree
2093: sub buildTree {
2094: my ($node, $childrenIn, $TreeNodes, $TreeHash) = @_;
2095: bless($node, 'Tree');
2096: foreach my $c (@$childrenIn) {
2097: my $tmpNode = &getNodeByIndex($c,$TreeNodes);
2098: $$node->add_child($tmpNode);
2099: my @childrenIn = @{ $$TreeHash{$tmpNode->value()->nindex()} };
2100: &buildTree(\$tmpNode,\@childrenIn,$TreeNodes,$TreeHash);
2101: }
2102:
2103: }
2104:
2105:
2106: # ----------------------------------------------------- package Entry
2107: # package that defines the entrys a wishlist could have
2108: # i.e. folders and links
2109: package Entry;
2110:
2111: # constructor
2112: sub new {
2113: my $invocant = shift;
2114: my $class = ref($invocant) || $invocant;
2115: my $self = { @_ }; #set attributes
2116: bless($self, $class);
2117: return $self;
2118: }
2119:
2120: # getter and setter
2121: sub title {
2122: my $self = shift;
2123: if ( @_ ) { $self->{title} = shift}
2124: return $self->{title};
2125: }
2126:
2127: sub date {
2128: my $self = shift;
2129: if ( @_ ) { $self->{date} = shift}
2130: return $self->{date};
2131: }
2132:
2133: sub note {
2134: my $self = shift;
2135: if ( @_ ) { $self->{note} = shift}
2136: return $self->{note};
2137: }
2138:
2139: sub path {
2140: my $self = shift;
2141: if ( @_ ) { $self->{path} = shift}
2142: return $self->{path};
2143: }
2144:
2145: sub nindex {
2146: my $self = shift;
2147: if ( @_ ) { $self->{nindex} = shift}
2148: return $self->{nindex};
2149: }
2150:
2151:
2152: 1;
2153: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>