--- loncom/interface/lonhtmlcommon.pm	2012/04/16 19:24:59	1.309
+++ loncom/interface/lonhtmlcommon.pm	2012/09/24 10:47:26	1.324
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common html routines
 #
-# $Id: lonhtmlcommon.pm,v 1.309 2012/04/16 19:24:59 raeburn Exp $
+# $Id: lonhtmlcommon.pm,v 1.324 2012/09/24 10:47:26 foxr Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -95,7 +95,7 @@ sub direct_parm_link {
     $filter=&entity_encode($filter);
     $part=&entity_encode($part);
     if (($symb) && (&Apache::lonnet::allowed('opa')) && ($target ne 'tex')) {
-       return "<a target='_top' href='/adm/parmset?symb=$symb&filter=$filter&part=$part'><span class='LC_setting'>$linktext</span></a>";
+       return "<a target='_top' href='/adm/parmset?symb=$symb&amp;filter=$filter&amp;part=$part'><span class='LC_setting'>$linktext</span></a>";
     } else {
        return $linktext;
     }
@@ -209,9 +209,10 @@ dependencies for a web page uploaded dir
 =cut
 
 sub dependencycheck_js {
-    my ($symb,$title) = @_;
+    my ($symb,$title,$url) = @_;
     my $link = '/adm/dependencies?symb='.&HTML::Entities::encode($symb,'<>&"').
-               '&title='.&HTML::Entities::encode($title,'<>&"');
+               '&title='.&HTML::Entities::encode($title,'<>&"').
+               '&url='.&HTML::Entities::encode($url,'<>&"');
     return <<ENDJS;
                 <script type="text/javascript">
                 // <![CDATA[
@@ -951,21 +952,8 @@ Inputs
 
 =item $r Apache request
 
-=item $title The title of the progress window
-
-=item $heading A description (usually 1 line) of the process being initiated.
-
 =item $number_to_do The total number of items being processed.
 
-=item $type Either 'popup' or 'inline' (popup is assumed if nothing is
-       specified)
-
-=item $width Specify the width in charaters of the input field.
-
-=item $formname Only useful in the inline case, if a form already exists, this needs to be used and specfiy the name of the form, otherwise the Progress line will be created in a new form of it's own
-
-=item $inputname Only useful in the inline case, if a form and an input of type text exists, use this to specify the name of the input field 
-
 =back
 
 Returns a hash containing the progress state data structure.
@@ -1221,8 +1209,12 @@ ENDEDITOR
 <script type="text/javascript" src="/adm/jpicker/js/jpicker-1.1.6.min.js" >
 </script>
 <link rel="stylesheet" type="text/css" href="/adm/jpicker/css/jPicker-1.1.6.min.css" />
-<script type='text/javascript' src='/adm/countdown/js/jquery.countdown.js'></script>
-<link rel="stylesheet" type="text/css" src='/adm/countdown/css/jquery.countdown.css' />
+<script type="text/javascript" src="/adm/countdown/js/jquery.countdown.js"></script>
+<link rel="stylesheet" type="text/css" href="/adm/countdown/css/jquery.countdown.css" />
+
+<script type="text/javascript" src="/adm/spellchecker/js/jquery.spellchecker.min.js"></script>
+<link rel="stylesheet" type="text/css" href="/adm/spellchecker/css/spellchecker.css" />
+
 ENDJQUERY
 	return $s;
 }
@@ -1383,7 +1375,9 @@ sub htmlareaselectactive {
     #   is used to determine when the countdown timer turns red to warn the user
     #   to think about submitting.
 
-    my $dueDateLayout = '<b>' .  &mt('Due in: {dn} {dl} {hnn}{sep}{mnn}{sep}{snn} - Submit early!') . '</b>';
+    my $dueDateLayout = &mt('Due in: {dn} {dl} {hnn}{sep}{mnn}{sep}{snn} [_1]',"<span id='submitearly'></span>");
+    my $early = '- <b>'.&mt('Submit Early').'</b>';
+    my $pastdue = '- <b>'.&mt('Past Due').'</b>';
     $output .= <<JAVASCRIPT;
 
     var documentReadyTime;
@@ -1395,6 +1389,12 @@ sub htmlareaselectactive {
          layout: "$dueDateLayout",
          onTick: function (periods) {
 	    var latencyEstimate = (documentReadyTime - clientTime) * 2;
+            if(\$.countdown.periodsToSeconds(periods) < (300 + latencyEstimate)) {
+               \$("#submitearly").html("$early");
+               if (\$.countdown.periodsToSeconds(periods) < 1) {
+                    \$("#submitearly").html("$pastdue");
+               }
+            }
             if(\$.countdown.periodsToSeconds(periods) < (60 + latencyEstimate)) {
                \$(this).css("color", "red");   //Highlight last minute.
             }
@@ -1402,6 +1402,35 @@ sub htmlareaselectactive {
       });
    }
 });
+
+    /* This code describes the spellcheck options that will be used for
+       items with class 'spellchecked'.  It is necessary for those objects'
+       to explicitly request checking (e.g. onblur is a nice event for that).
+     */
+     \$(document).ready(function() {
+	 \$(".spellchecked").spellchecker({
+	   url: "/ajax/spellcheck",
+	   lang: "en",                      
+	   engine: "pspell",
+	   suggestionBoxPosition: "below",
+	   innerDocument: true
+					  });
+	 \$("textarea.spellchecked").spellchecker({
+	   url: "/ajax/spellcheck",
+	   lang: "en",                      
+	   engine: "pspell",
+	   suggestionBoxPosition: "below",
+	   innerDocument: true
+					  });
+
+			});
+
+    function doSpellcheck(element, lang) {
+	\$(element).spellchecker('option', {lang: lang});
+	\$(element).spellchecker('check');
+    }
+
+
 JAVASCRIPT
     if ($dragmath_prefix ne '') {
         $output .= '
@@ -1458,7 +1487,7 @@ sub show_return_link {
 
     unless ($env{'request.course.id'}) { return 0; }
     if ($env{'request.noversionuri'}=~m{^/priv/} ||
-        $env{'request.uri'}=~m{^/~}) { return 1; }
+        $env{'request.uri'}=~m{^/priv/}) { return 1; }
 
     if (($env{'request.noversionuri'} =~ m{^/adm/(viewclasslist|navmaps)($|\?)})
         || ($env{'request.noversionuri'} =~ m{^/adm/.*/aboutme($|\?)})) {
@@ -1497,8 +1526,9 @@ sub set_due_date {
     # The code should correct for gross differences between the server
     # and client's time setting
 
-    my $js = "
-<script type='text/javascript'>
+     return <<"END";
+
+<script type="text/javascript">
   //<![CDATA[
 var serverDueDate = $duems;
 var serverTime    = $now;
@@ -1507,9 +1537,8 @@ var dueDate       = new Date(serverDueDa
 
   //]]>
 </script>
-";
 
-    return $js;
+END
 }
 ##
 # Sets the time at which the problem finished computing.
@@ -1521,17 +1550,16 @@ var dueDate       = new Date(serverDueDa
 sub set_compute_end_time {
 
     my $now = time()*1000;	# Javascript times are in ms.
-    my $js = "
-<script type='text/javascript'>
+    return <<"END";
+
+<script type="text/javascript">
 //<![CDATA[
 serverTime = $now;
 clientTime = (new Date()).getTime();
 //]]>
 </script>
 
-";
-    return $js;
-    
+END
 }
 
 ############################################################
@@ -1581,7 +1609,8 @@ returns: nothing
     my %tools = ();
     
     sub breadcrumbs {
-        my ($component,$component_help,$menulink,$helplink,$css_class,$no_mt, $CourseBreadcrumbs) = @_;
+        my ($component,$component_help,$menulink,$helplink,$css_class,$no_mt, 
+            $CourseBreadcrumbs) = @_;
         #
         $css_class ||= 'LC_breadcrumbs';
 
@@ -1622,9 +1651,11 @@ returns: nothing
         my $links;
         if ((&show_return_link) && (!$CourseBreadcrumbs)) {
             my $alttext = &mt('Go Back');
-            $links=&htmltag( 'a',"<img src='/res/adm/pages/reload.png' border='0' style='vertical-align:middle;' alt='$alttext' />",
+            $links=&htmltag( 'a','<img src="/res/adm/pages/tolastloc.png" alt="'.$alttext.'" class="LC_icon" />',
                             { href => '/adm/flip?postdata=return:',
-                              title => &mt("Back to most recent content resource") });
+                              title => &mt('Back to most recent content resource'),
+                              class => 'LC_menubuttons_link',
+                            });
             $links=&htmltag('li',$links);
         }
         $links.= join "", 
@@ -1656,8 +1687,6 @@ returns: nothing
         $links .= &htmltag( 'li', htmltag($CourseBreadcrumbs ? 'b' : 'h1',
                 $lasttext), {title => $lasttext});
 
-	$links .=   '<li> <span id="duedatecountdown"></span></li>'; 
-
         my $icons = '';
         $faq  = $last->{'faq'}  if (exists($last->{'faq'}));
         $bug  = $last->{'bug'}  if (exists($last->{'bug'}));
@@ -1735,7 +1764,7 @@ Currently there are 3 possible values fo
 left of breadcrumbs line
 
 =item tools 
-right of breadcrumbs line
+remaining items in right of breadcrumbs line
 
 =item advtools 
 advanced tools shown in a separate box below breadcrumbs line 
@@ -1885,15 +1914,19 @@ returns: nothing
 my @row_count;
 
 sub start_pick_box {
-    my ($css_class) = @_;
+    my ($css_class,$id) = @_;
     if (defined($css_class)) {
 	$css_class = 'class="'.$css_class.'"';
     } else {
 	$css_class= 'class="LC_pick_box"';
     }
+    my $table_id;
+    if (defined($id)) {
+        $table_id = ' id="'.$id.'"';
+    }
     unshift(@row_count,0);
     my $output = <<"END";
- <table $css_class>
+ <table $css_class $table_id>
 END
     return $output;
 }
@@ -2225,15 +2258,19 @@ sub resource_info_box {
 # 1. number to display.
 #    If input for number is empty only the title will be displayed. 
 # 2. title text to display.
+# 3. optional id for the <div>
 # Outputs - a scalar containing html mark-up for the div.
 
 sub topic_bar {
-    my ($num,$title) = @_;
+    my ($num,$title,$id) = @_;
     my $number = '';
     if ($num ne '') {
         $number = '<span>'.$num.'</span>';
     }
-    return '<div class="LC_topic_bar">'.$number.$title.'</div>';
+    if ($id ne '') {
+        $id = 'id="'.$id.'"';
+    }
+    return '<div class="LC_topic_bar" '.$id.'>'.$number.$title.'</div>';
 }
 
 ##############################################
@@ -2696,6 +2733,270 @@ ENDSCRIPT
 
 ##############################################
 ##############################################
+
+sub resize_scrollbox_js {
+    my ($context,$tabidstr) = @_;
+    my (%names,$paddingwfrac,$offsetwfrac,$offsetv,$minw,$minv);
+    if ($context eq 'docs') {
+        %names = (
+                   boxw   => 'contenteditor',
+                   item   => 'contentlist',
+                   header => 'uploadfileresult',
+                   scroll => 'contentscroll',
+                   boxh   => 'contenteditor',
+                 );
+        $paddingwfrac = 0.09; 
+        $offsetwfrac = 0.015;
+        $offsetv = 20;
+        $minw = 250;
+        $minv = 200;
+    } elsif ($context eq 'params') {
+        %names = (
+                   boxw   => 'parameditor',
+                   item   => 'mapmenuinner',
+                   header => 'parmstep1',
+                   scroll => 'mapmenuscroll',
+                   boxh   => 'parmlevel',
+                 );
+        $paddingwfrac = 0.2;
+        $offsetwfrac = 0.015;
+        $offsetv = 80;
+        $minw = 100;
+        $minv = 100; 
+    }
+    my $viewport_js = &Apache::loncommon::viewport_geometry_js();
+    my $output = '
+
+window.onresize=callResize;
+
+';
+    if ($context eq 'docs') {
+        $output .= '
+var activeTab;
+';
+    }
+    $output .=  <<"FIRST";
+
+$viewport_js
+
+function resize_scrollbox(scrollboxname,chkw,chkh) {
+    var scrollboxid = 'div_'+scrollboxname;
+    var scrolltableid = 'table_'+scrollboxname;
+    var scrollbox;
+    var scrolltable;
+
+    if (document.getElementById("$names{'boxw'}") == null) {
+        return;
+    }
+
+    if (document.getElementById(scrollboxid) == null) {
+        return;
+    } else {
+        scrollbox = document.getElementById(scrollboxid);
+    }
+
+
+    if (document.getElementById(scrolltableid) == null) {
+        return;
+    } else {
+        scrolltable = document.getElementById(scrolltableid);
+    }
+
+    init_geometry();
+    var vph = Geometry.getViewportHeight();
+    var vpw = Geometry.getViewportWidth();
+
+FIRST
+    if ($context eq 'docs') {
+        $output .= "
+    var alltabs = ['$tabidstr'];
+";
+    } elsif ($context eq 'params') {
+        $output .= "
+    if (document.getElementById('$names{'boxh'}') == null) {
+        return;
+    }
+";
+    }
+    $output .= <<"SECOND";
+    var listwchange;
+    if (chkw == 1) {
+        var boxw = document.getElementById("$names{'boxw'}").offsetWidth;
+        var itemw;
+        var itemid = document.getElementById("$names{'item'}");
+        if (itemid != null) {
+            itemw = itemid.offsetWidth;
+        }
+        var itemwstart = itemw;
+
+        var scrollboxw = scrollbox.offsetWidth;
+        var scrollboxscrollw = scrollbox.scrollWidth;
+
+        var offsetw = parseInt(vpw * $offsetwfrac);
+        var paddingw = parseInt(vpw * $paddingwfrac);
+
+        var minscrollboxw = $minw;
+        var maxcolw = 0;
+SECOND
+    if ($context eq 'docs') {
+        $output .= <<"DOCSONE";
+        var actabw = 0;
+        for (var i=0; i<alltabs.length; i++) {
+            if (activeTab == alltabs[i]) {
+                actabw = document.getElementById(alltabs[i]).offsetWidth;
+                if (actabw > maxcolw) {
+                    maxcolw = actabw;
+                }
+            } else {
+                if (document.getElementById(alltabs[i]) != null) {
+                    var thistab = document.getElementById(alltabs[i]);
+                    thistab.style.visibility = 'hidden';
+                    thistab.style.display = 'block';
+                    var tabw = document.getElementById(alltabs[i]).offsetWidth;
+                    thistab.style.display = 'none';
+                    thistab.style.visibility = '';
+                    if (tabw > maxcolw) {
+                        maxcolw = tabw;
+                    }
+                }
+            }
+        }
+DOCSONE
+    } elsif ($context eq 'params') {
+        $output .= <<"PARAMSONE";
+        var parmlevelrows = new Array();
+        var mapmenucells = new Array();
+        parmlevelrows = document.getElementById("$names{'boxh'}").rows;
+        var numrows = parmlevelrows.length;
+        if (numrows > 1) {
+            mapmenucells = parmlevelrows[2].getElementsByTagName('td');
+        }
+        maxcolw = mapmenucells[0].offsetWidth;
+PARAMSONE
+    }
+    $output .= <<"THIRD";
+        if (maxcolw > 0) {
+            var newscrollboxw;
+            if (maxcolw+paddingw+scrollboxscrollw<boxw) {
+                newscrollboxw = boxw-paddingw-maxcolw;
+                if (newscrollboxw < minscrollboxw) {
+                    newscrollboxw = minscrollboxw;
+                }
+                scrollbox.style.width = newscrollboxw+"px";
+                if (newscrollboxw != scrollboxw) {
+                    var newitemw = newscrollboxw-offsetw;
+                    itemid.style.width = newitemw+"px";
+                }
+            } else {
+                newscrollboxw = boxw-paddingw-maxcolw;
+                if (newscrollboxw < minscrollboxw) {
+                    newscrollboxw = minscrollboxw;
+                }
+                scrollbox.style.width = newscrollboxw+"px";
+                if (newscrollboxw != scrollboxw) {
+                    var newitemw = newscrollboxw-offsetw;
+                    itemid.style.width = newitemw+"px";
+                }
+            }
+
+            if (newscrollboxw != scrollboxw) {
+                var newscrolltablew = newscrollboxw+offsetw;
+                scrolltable.style.width = newscrolltablew+"px";
+            }
+        }
+
+        if (itemid.offsetWidth != itemwstart) {
+            listwchange = 1;
+        }
+THIRD
+    if ($context eq 'docs') {
+        $output .= <<"DOCSTWO";
+        if (activeTab == 'cc1') {
+            if (document.getElementById('cc_hrule') != null) {
+                document.getElementById('cc_hrule').style.width=actabw+"px";
+            }
+        } else {
+            if (activeTab == 'bb1') {
+                if (document.getElementById('bb_hrule') != null) {
+                    document.getElementById('bb_hrule').style.width=actabw+"px";
+                }
+            } else {
+                if (activeTab == 'ee2') {
+                    if (document.getElementById('ee_hrule') != null) {
+                        document.getElementById('ee_hrule').style.width=actabw+"px";
+                    }
+                }
+            }
+        }
+DOCSTWO
+    }
+    $output .= <<"FOURTH";
+    }
+    if ((chkh == 1) || (listwchange)) {
+        var primaryheight = document.getElementById('LC_nav_bar').offsetHeight;
+        var secondaryheight = document.getElementById('LC_secondary_menu').offsetHeight;
+        var crumbsheight = document.getElementById('LC_breadcrumbs').offsetHeight;
+        var dccidheight = 0;
+        if (document.getElementById('dccid') != null) {
+            dccidheight = document.getElementById('dccid').offsetHeight;
+        }
+        var headerheight = 0;
+        if (document.getElementById("$names{'header'}") != null) {
+            headerheight = document.getElementById("$names{'header'}").offsetHeight;
+        }
+        var tabbedheight = document.getElementById("tabbededitor").offsetHeight;
+        var boxheight = document.getElementById("$names{'boxh'}").offsetHeight;
+        var freevspace = vph-(primaryheight+secondaryheight+crumbsheight+dccidheight+headerheight+tabbedheight+boxheight);
+
+        var scrollboxheight = scrollbox.offsetHeight;
+        var scrollboxscrollheight = scrollbox.scrollHeight;
+
+        var minvscrollbox = $minv;
+        var offsetv = $offsetv;
+        var newscrollboxheight;
+        if (freevspace < 0) {
+            newscrollboxheight = scrollboxheight+freevspace-offsetv;
+            if (newscrollboxheight < minvscrollbox) {
+                newscrollboxheight = minvscrollbox;
+            }
+            scrollbox.style.height = newscrollboxheight + "px";
+        } else {
+            if (scrollboxscrollheight > scrollboxheight) {
+                if (freevspace > offsetv) {
+                    newscrollboxheight = scrollboxheight+freevspace-offsetv;
+                    if (newscrollboxheight < minvscrollbox) {
+                        newscrollboxheight = minvscrollbox;
+                    }
+                    scrollbox.style.height = newscrollboxheight+"px";
+                }
+            }
+        }
+        scrollboxheight = scrollbox.offsetHeight;
+        var itemh = document.getElementById("$names{'item'}").offsetHeight;
+
+        if (scrollboxscrollheight <= scrollboxheight) {
+            if ((itemh+offsetv)<scrollboxheight) {
+                newscrollheight = itemh+offsetv;
+                scrollbox.style.height = newscrollheight+"px";
+            }
+        }
+    }
+    return;
+}
+
+function callResize() {
+    var timer;
+    clearTimeout(timer);
+    timer=setTimeout('resize_scrollbox("$names{'scroll'}","1","1")',500);
+}
+
+FOURTH
+    return $output;
+}
+
+
+##############################################
+##############################################
 
 # javascript_valid_email
 #