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