--- 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&filter=$filter&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 #