--- loncom/interface/loncommon.pm	2011/12/12 00:13:43	1.1036
+++ loncom/interface/loncommon.pm	2012/01/04 00:42:19	1.1051
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1036 2011/12/12 00:13:43 www Exp $
+# $Id: loncommon.pm,v 1.1051 2012/01/04 00:42:19 www Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -154,6 +154,8 @@ sub ssi_with_retries {
 # ----------------------------------------------- Filetypes/Languages/Copyright
 my %language;
 my %supported_language;
+my %latex_language;		# For choosing hyphenation in <transl..>
+my %latex_language_bykey;	# for choosing hyphenation from metadata
 my %cprtag;
 my %scprtag;
 my %fe; my %fd; my %fm;
@@ -186,11 +188,15 @@ BEGIN {
             while (my $line = <$fh>) {
                 next if ($line=~/^\#/);
                 chomp($line);
-                my ($key,$two,$country,$three,$enc,$val,$sup)=(split(/\t/,$line));
+                my ($key,$two,$country,$three,$enc,$val,$sup,$latex)=(split(/\t/,$line));
                 $language{$key}=$val.' - '.$enc;
                 if ($sup) {
                     $supported_language{$key}=$sup;
                 }
+		if ($latex) {
+		    $latex_language_bykey{$key} = $latex;
+		    $latex_language{$two} = $latex;
+		}
             }
             close($fh);
         }
@@ -1198,6 +1204,8 @@ sub help_open_topic {
 
     if (!$stayOnPage) {
 	$link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');";
+    } elsif ($stayOnPage eq 'popup') {
+        $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
     } else {
 	$link = "/adm/help/${filename}.hlp";
     }
@@ -1230,27 +1238,22 @@ sub help_open_topic {
 # This is a quicky function for Latex cheatsheet editing, since it 
 # appears in at least four places
 sub helpLatexCheatsheet {
-    my ($topic,$text,$not_author) = @_;
+    my ($topic,$text,$not_author,$stayOnPage) = @_;
     my $out;
     my $addOther = '';
     if ($topic) {
-	$addOther = '<span>'.&Apache::loncommon::help_open_topic($topic,&mt($text),
-							       undef, undef, 600).
-								   '</span> ';
+	$addOther = '<span>'.&help_open_topic($topic,&mt($text),$stayOnPage, undef, 600).'</span> ';
     }
     $out = '<span>' # Start cheatsheet
 	  .$addOther
           .'<span>'
-	  .&Apache::loncommon::help_open_topic('Greek_Symbols',&mt('Greek Symbols'),
-					       undef,undef,600)
+	  .&help_open_topic('Greek_Symbols',&mt('Greek Symbols'),$stayOnPage,undef,600)
 	  .'</span> <span>'
-	  .&Apache::loncommon::help_open_topic('Other_Symbols',&mt('Other Symbols'),
-					       undef,undef,600)
+	  .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600)
 	  .'</span>';
     unless ($not_author) {
         $out .= ' <span>'
-	       .&Apache::loncommon::help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),
-	                                            undef,undef,600)
+	       .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
 	       .'</span>';
     }
     $out .= '</span>'; # End cheatsheet
@@ -3230,11 +3233,29 @@ sub languagedescription {
 	    ($supported_language{$code}?' ('.&mt('interface available').')':'');
 }
 
+=pod
+
+=item * &plainlanguagedescription
+
+Returns both the plain language description (e.g. 'Creoles and Pidgins, English-based (Other)')
+and the language character encoding (e.g. ISO) separated by a ' - ' string.
+
+=cut
+
 sub plainlanguagedescription {
     my $code=shift;
     return $language{$code};
 }
 
+=pod
+
+=item * &supportedlanguagecode
+
+Returns the supported language code (e.g. sptutf maps to pt) given a language
+code.
+
+=cut
+
 sub supportedlanguagecode {
     my $code=shift;
     return $supported_language{$code};
@@ -3242,6 +3263,35 @@ sub supportedlanguagecode {
 
 =pod
 
+=item * &latexlanguage()
+
+Given a language key code returns the correspondnig language to use
+to select the correct hyphenation on LaTeX printouts.  This is undef if there
+is no supported hyphenation for the language code.
+
+=cut
+
+sub latexlanguage {
+    my $code = shift;
+    return $latex_language{$code};
+}
+
+=pod
+
+=item * &latexhyphenation()
+
+Same as above but what's supplied is the language as it might be stored
+in the metadata.
+
+=cut
+
+sub latexhyphenation {
+    my $key = shift;
+    return $latex_language_bykey{$key};
+}
+
+=pod
+
 =item * &copyrightids() 
 
 returns list of all copyrights
@@ -4983,7 +5033,6 @@ body {
 a:focus,
 a:focus img {
   color: red;
-  background: yellow;
 }
 
 form, .inline {
@@ -5078,35 +5127,36 @@ div.LC_confirm_box .LC_success img {
 }
 
 .LC_discussion {
-  background: $tabbg;
+  background: $data_table_dark;
   border: 1px solid black;
   margin: 2px;
 }
 
-.LC_disc_action_links_bar {
-  background: $tabbg;
-  border: none;
-  margin: 4px;
-}
-
 .LC_disc_action_left {
+  background: $sidebg;
   text-align: left;
+  padding: 4px;
+  margin: 2px;
 }
 
 .LC_disc_action_right {
+  background: $sidebg;
   text-align: right;
+  padding: 4px;
+  margin: 2px;
 }
 
 .LC_disc_new_item {
   background: white;
   border: 2px solid red;
-  margin: 2px;
+  margin: 4px;
+  padding: 4px;
 }
 
 .LC_disc_old_item {
   background: white;
-  border: 1px solid black;
-  margin: 2px;
+  margin: 4px;
+  padding: 4px;
 }
 
 table.LC_pastsubmission {
@@ -5228,7 +5278,7 @@ td.LC_table_cell_checkbox {
   vertical-align: middle;
 }
 
-li.LC_menubuttons_inline_text img,a {
+li.LC_menubuttons_inline_text img {
   cursor:pointer;
   text-decoration: none;
 }
@@ -6083,7 +6133,6 @@ div.LC_createcourse {
   display:none;
 }
 
-a:hover,
 ol.LC_primary_menu a:hover,
 ol#LC_MenuBreadcrumbs a:hover,
 ol#LC_PathBreadcrumbs a:hover,
@@ -6317,6 +6366,12 @@ ul.LC_TabContent li.active a {
   background:#FFFFFF;
   outline: none;
 }
+
+ul.LC_TabContent li.goback {
+  float: left;
+  border-left: none;
+}
+
 #maincoursedoc {
   clear:both;
 }
@@ -6566,6 +6621,10 @@ a#LC_content_toolbar_changefolder_toggle
   background-image:url(/res/adm/pages/open-all-folders.gif);
 }
 
+a#LC_content_toolbar_edittoplevel {
+  background-image:url(/res/adm/pages/edittoplevel.gif);
+}
+
 ul#LC_toolbar li a:hover {
   background-position: bottom center;
 }
@@ -6740,7 +6799,9 @@ sub headtag {
 	&& !$args->{'frameset'}) {
 	$result .= &help_menu_js();
         $result.=&modal_window();
+        $result.=&togglebox_script();
         $result.=&wishlist_window();
+        $result.=&LCprogressbarUpdate_script();
     } else {
         if ($args->{'add_modal'}) {
            $result.=&modal_window();
@@ -6748,6 +6809,12 @@ sub headtag {
         if ($args->{'add_wishlist'}) {
            $result.=&wishlist_window();
         }
+        if ($args->{'add_togglebox'}) {
+           $result.=&togglebox_script();
+        }
+        if ($args->{'add_progressbar'}) {
+           $result.=&LCprogressbarUpdate_script();
+        }
     }
     if (ref($args->{'redirect'})) {
 	my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
@@ -6964,7 +7031,7 @@ sub end_page {
 
 sub wishlist_window {
     return(<<'ENDWISHLIST');
-<script type="text/javascript" lang="javascript">
+<script type="text/javascript">
 // <![CDATA[
 // <!-- BEGIN LON-CAPA Internal
 function set_wishlistlink(title, path) {
@@ -6986,7 +7053,7 @@ ENDWISHLIST
 
 sub modal_window {
     return(<<'ENDMODAL');
-<script type="text/javascript" lang="javascript">
+<script type="text/javascript">
 // <![CDATA[
 // <!-- BEGIN LON-CAPA Internal
 var modalWindow = {
@@ -7041,7 +7108,7 @@ sub modal_link {
 sub modal_adhoc_script {
     my ($funcname,$width,$height,$content)=@_;
     return (<<ENDADHOC);
-<script type="text/javascript" lang="javascript">
+<script type="text/javascript">
 // <![CDATA[
         var $funcname = function()
         {
@@ -7056,8 +7123,8 @@ sub modal_adhoc_script {
 ENDADHOC
 }
 
-sub modal_adhoc_window {
-    my ($funcname,$width,$height,$content,$linktext)=@_;
+sub modal_adhoc_inner {
+    my ($funcname,$width,$height,$content)=@_;
     my $innerwidth=$width-20;
     $content=&js_ready(
                &start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}).
@@ -7066,8 +7133,175 @@ sub modal_adhoc_window {
                  &end_scrollbox().
                &end_page()
              );
-    return &modal_adhoc_script($funcname,$width,$height,$content).
-         "<a href=\"javascript:$funcname();void(0);\">".$linktext."</a>";
+    return &modal_adhoc_script($funcname,$width,$height,$content);
+}
+
+sub modal_adhoc_window {
+    my ($funcname,$width,$height,$content,$linktext)=@_;
+    return &modal_adhoc_inner($funcname,$width,$height,$content).
+           "<a href=\"javascript:$funcname();void(0);\">".$linktext."</a>";
+}
+
+sub modal_adhoc_launch {
+    my ($funcname,$width,$height,$content)=@_;
+    return &modal_adhoc_inner($funcname,$width,$height,$content).(<<ENDLAUNCH);
+<script type="text/javascript">
+// <![CDATA[
+$funcname();
+// ]]>
+</script>
+ENDLAUNCH
+}
+
+sub modal_adhoc_close {
+    return (<<ENDCLOSE);
+<script type="text/javascript">
+// <![CDATA[
+modalWindow.close();
+// ]]>
+</script>
+ENDCLOSE
+}
+
+sub togglebox_script {
+   return(<<ENDTOGGLE);
+<script type="text/javascript"> 
+// <![CDATA[
+function LCtoggleDisplay(id,hidetext,showtext) {
+   link = document.getElementById(id + "link").childNodes[0];
+   with (document.getElementById(id).style) {
+      if (display == "none" ) {
+          display = "inline";
+          link.nodeValue = hidetext;
+        } else {
+          display = "none";
+          link.nodeValue = showtext;
+       }
+   }
+}
+// ]]>
+</script>
+ENDTOGGLE
+}
+
+sub start_togglebox {
+    my ($id,$heading,$headerbg,$hidetext,$showtext)=@_;
+    unless ($heading) { $heading=''; } else { $heading.=' '; }
+    unless ($showtext) { $showtext=&mt('show'); }
+    unless ($hidetext) { $hidetext=&mt('hide'); }
+    unless ($headerbg) { $headerbg='#FFFFFF'; }
+    return &start_data_table().
+           &start_data_table_header_row().
+           '<td bgcolor="'.$headerbg.'">'.$heading.
+           '[<a id="'.$id.'link" href="javascript:LCtoggleDisplay(\''.$id.'\',\''.$hidetext.'\',\''.
+           $showtext.'\')">'.$showtext.'</a>]</td>'.
+           &end_data_table_header_row().
+           '<tr id="'.$id.'" style="display:none""><td>';
+}
+
+sub end_togglebox {
+    return '</td></tr>'.&end_data_table();
+}
+
+sub LCprogressbar_script {
+   my ($id)=@_;
+   return(<<ENDPROGRESS);
+<script type="text/javascript">
+// <![CDATA[
+\$('#progressbar$id').progressbar({
+  value: 0,
+  change: function(event, ui) {
+    var newVal = \$(this).progressbar('option', 'value');
+    \$('.pblabel', this).text(LCprogressTxt);
+  }
+});
+// ]]>
+</script>
+ENDPROGRESS
+}
+
+sub LCprogressbarUpdate_script {
+   return(<<ENDPROGRESSUPDATE);
+<style type="text/css">
+.ui-progressbar { position:relative; }
+.pblabel { position: absolute; width: 100%; text-align: center; line-height: 1.9em; }
+</style>
+<script type="text/javascript">
+// <![CDATA[
+var LCprogressTxt='---';
+
+function LCupdateProgress(percent,progresstext,id) {
+   LCprogressTxt=progresstext;
+   \$('#progressbar'+id).progressbar('value',percent);
+}
+// ]]>
+</script>
+ENDPROGRESSUPDATE
+}
+
+my $LClastpercent;
+my $LCidcnt;
+my $LCcurrentid;
+
+sub LCprogressbar {
+    my ($r)=(@_);
+    $LClastpercent=0;
+    $LCidcnt++;
+    $LCcurrentid=$$.'_'.$LCidcnt;
+    my $starting=&mt('Starting');
+    my $content=(<<ENDPROGBAR);
+<p>
+  <div id="progressbar$LCcurrentid">
+    <span class="pblabel">$starting</span>
+  </div>
+</p>
+ENDPROGBAR
+    &r_print($r,$content.&LCprogressbar_script($LCcurrentid));
+}
+
+sub LCprogressbarUpdate {
+    my ($r,$val,$text)=@_;
+    unless ($val) { 
+       if ($LClastpercent) {
+           $val=$LClastpercent;
+       } else {
+           $val=0;
+       }
+    }
+    if ($val<0) { $val=0; }
+    if ($val>100) { $val=0; }
+    $LClastpercent=$val;
+    unless ($text) { $text=$val.'%'; }
+    $text=&js_ready($text);
+    &r_print($r,<<ENDUPDATE);
+<script type="text/javascript">
+// <![CDATA[
+LCupdateProgress($val,'$text','$LCcurrentid');
+// ]]>
+</script>
+ENDUPDATE
+}
+
+sub LCprogressbarClose {
+    my ($r)=@_;
+    $LClastpercent=0;
+    &r_print($r,<<ENDCLOSE);
+<script type="text/javascript">
+// <![CDATA[
+\$("#progressbar$LCcurrentid").hide('slow'); 
+// ]]>
+</script>
+ENDCLOSE
+}
+
+sub r_print {
+    my ($r,$to_print)=@_;
+    if ($r) {
+      $r->print($to_print);
+      $r->rflush();
+    } else {
+      print($to_print);
+    }
 }
 
 sub html_encode {
@@ -7077,6 +7311,7 @@ sub html_encode {
     
     return $result;
 }
+
 sub js_ready {
     my ($result) = @_;
 
@@ -8407,7 +8642,8 @@ sub get_standard_codeitems {
 
 =item * sorted_slots()
 
-Sorts an array of slot names in order of slot start time (earliest first). 
+Sorts an array of slot names in order of an optional sort key,
+default sort is by slot start time (earliest first). 
 
 Inputs:
 
@@ -8417,15 +8653,16 @@ slotsarr  - Reference to array of unsort
 
 slots     - Reference to hash of hash, where outer hash keys are slot names.
 
+sortkey   - Name of key in inner hash to be sorted on (e.g., starttime).
+
 =back
 
 Returns:
 
 =over 4
 
-sorted   - An array of slot names sorted by the start time of the slot.
-
-=back
+sorted   - An array of slot names sorted by a specified sort key 
+           (default sort key is start time of the slot).
 
 =back
 
@@ -8433,13 +8670,16 @@ sorted   - An array of slot names sorted
 
 
 sub sorted_slots {
-    my ($slotsarr,$slots) = @_;
+    my ($slotsarr,$slots,$sortkey) = @_;
+    if ($sortkey eq '') {
+        $sortkey = 'starttime';
+    }
     my @sorted;
     if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) {
         @sorted =
             sort {
                      if (ref($slots->{$a}) && ref($slots->{$b})) {
-                         return $slots->{$a}{'starttime'} <=> $slots->{$b}{'starttime'}
+                         return $slots->{$a}{$sortkey} <=> $slots->{$b}{$sortkey}
                      }
                      if (ref($slots->{$a})) { return -1;}
                      if (ref($slots->{$b})) { return 1;}
@@ -8449,6 +8689,131 @@ sub sorted_slots {
     return @sorted;
 }
 
+=pod
+
+=item * get_future_slots()
+
+Inputs:
+
+=over 4
+
+cnum - course number
+
+cdom - course domain
+
+now - current UNIX time
+
+symb - optional symb
+
+=back
+
+Returns:
+
+=over 4
+
+sorted_reservable - ref to array of student_schedulable slots currently 
+                    reservable, ordered by end date of reservation period.
+
+reservable_now - ref to hash of student_schedulable slots currently
+                 reservable.
+
+    Keys in inner hash are:
+    (a) symb: either blank or symb to which slot use is restricted.
+    (b) endreserve: end date of reservation period. 
+
+sorted_future - ref to array of student_schedulable slots reservable in
+                the future, ordered by start date of reservation period.
+
+future_reservable - ref to hash of student_schedulable slots reservable
+                    in the future.
+
+    Keys in inner hash are:
+    (a) symb: either blank or symb to which slot use is restricted.
+    (b) startreserve:  start date of reservation period.
+
+=back
+
+=cut
+
+sub get_future_slots {
+    my ($cnum,$cdom,$now,$symb) = @_;
+    my (%reservable_now,%future_reservable,@sorted_reservable,@sorted_future);
+    my %slots = &Apache::lonnet::get_course_slots($cnum,$cdom);
+    foreach my $slot (keys(%slots)) {
+        next unless($slots{$slot}->{'type'} eq 'schedulable_student');
+        if ($symb) {
+            next if (($slots{$slot}->{'symb'} ne '') && 
+                     ($slots{$slot}->{'symb'} ne $symb));
+        }
+        if (($slots{$slot}->{'starttime'} > $now) &&
+            ($slots{$slot}->{'endtime'} > $now)) {
+            if (($slots{$slot}->{'allowedsections'}) || ($slots{$slot}->{'allowedusers'})) {
+                my $userallowed = 0;
+                if ($slots{$slot}->{'allowedsections'}) {
+                    my @allowed_sec = split(',',$slots{$slot}->{'allowedsections'});
+                    if (!defined($env{'request.role.sec'})
+                        && grep(/^No section assigned$/,@allowed_sec)) {
+                        $userallowed=1;
+                    } else {
+                        if (grep(/^\Q$env{'request.role.sec'}\E$/,@allowed_sec)) {
+                            $userallowed=1;
+                        }
+                    }
+                    unless ($userallowed) {
+                        if (defined($env{'request.course.groups'})) {
+                            my @groups = split(/:/,$env{'request.course.groups'});
+                            foreach my $group (@groups) {
+                                if (grep(/^\Q$group\E$/,@allowed_sec)) {
+                                    $userallowed=1;
+                                    last;
+                                }
+                            }
+                        }
+                    }
+                }
+                if ($slots{$slot}->{'allowedusers'}) {
+                    my @allowed_users = split(',',$slots{$slot}->{'allowedusers'});
+                    my $user = $env{'user.name'}.':'.$env{'user.domain'};
+                    if (grep(/^\Q$user\E$/,@allowed_users)) {
+                        $userallowed = 1;
+                    }
+                }
+                next unless($userallowed);
+            }
+            my $startreserve = $slots{$slot}->{'startreserve'};
+            my $endreserve = $slots{$slot}->{'endreserve'};
+            my $symb = $slots{$slot}->{'symb'};
+            if (($startreserve < $now) &&
+                (!$endreserve || $endreserve > $now)) {
+                my $lastres = $endreserve;
+                if (!$lastres) {
+                    $lastres = $slots{$slot}->{'starttime'};
+                }
+                $reservable_now{$slot} = {
+                                           symb       => $symb,
+                                           endreserve => $lastres
+                                         };
+            } elsif (($startreserve > $now) &&
+                     (!$endreserve || $endreserve > $startreserve)) {
+                $future_reservable{$slot} = {
+                                              symb         => $symb,
+                                              startreserve => $startreserve
+                                            };
+            }
+        }
+    }
+    my @unsorted_reservable = keys(%reservable_now);
+    if (@unsorted_reservable > 0) {
+        @sorted_reservable = 
+            &sorted_slots(\@unsorted_reservable,\%reservable_now,'endreserve');
+    }
+    my @unsorted_future = keys(%future_reservable);
+    if (@unsorted_future > 0) {
+        @sorted_future =
+            &sorted_slots(\@unsorted_future,\%future_reservable,'startreserve');
+    }
+    return (\@sorted_reservable,\%reservable_now,\@sorted_future,\%future_reservable);
+}
 
 =pod