--- loncom/interface/loncommon.pm 2023/11/03 01:31:57 1.1415 +++ loncom/interface/loncommon.pm 2024/03/23 22:05:16 1.1428 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.1415 2023/11/03 01:31:57 raeburn Exp $ +# $Id: loncommon.pm,v 1.1428 2024/03/23 22:05:16 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -1372,7 +1372,7 @@ sub helpLatexCheatsheet { $out .= '<span>' .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600) .'</span> <span>' - .&help_open_topic('Authoring_Multilingual_Problems',&mt('How to create problems in different languages'),$stayOnPage,undef,600) + .&help_open_topic('Authoring_Multilingual_Problems',&mt('Languages'),$stayOnPage,undef,600) .'</span>'; } $out .= '</span>'; # End cheatsheet @@ -1764,8 +1764,6 @@ the id of the element to resize, second surrounds everything that comes after the textarea, this routine needs to be attached to the <body> for the onload and onresize events. -=back - =cut sub resize_textarea_js { @@ -2439,6 +2437,168 @@ sub show_crsfiles_js { END } +sub crsauthor_rights { + my ($rightsfile,$path,$docroot,$cnum,$cdom) = @_; + my $sourcerights = "$path/$rightsfile"; + my $now = time; + if (!-e $sourcerights) { + my $cid = $cdom.'_'.$cnum; + if (!-e "$docroot/priv/$cdom") { + mkdir("$docroot/priv/$cdom",0755); + } + if (!-e "$docroot/priv/$cdom/$cnum") { + mkdir("$docroot/priv/$cdom/$cnum",0755); + } + if (open(my $fh,">$sourcerights")) { + print $fh <<END; +<accessrule effect="deny" realm="" type="course" role="" /> +<accessrule effect="allow" realm="$cid" type="course" role="" /> +END + close($fh); + } + } + if (!-e "$sourcerights.meta") { + if (open(my $fh,">$sourcerights.meta")) { + my $author=$env{'environment.firstname'}.' '. + $env{'environment.middlename'}.' '. + $env{'environment.lastname'}.' '. + $env{'environment.generation'}; + $author =~ s/\s+$//; + print $fh <<"END"; + +<abstract></abstract> +<author>$author</author> +<authorspace>$cnum:$cdom</authorspace> +<copyright>private</copyright> +<creationdate>$now</creationdate> +<customdistributionfile></customdistributionfile> +<dependencies></dependencies> +<domain>$cdom</domain> +<highestgradelevel>0</highestgradelevel> +<keywords></keywords> +<language>notset </language> +<lastrevisiondate>$now</lastrevisiondate> +<lowestgradelevel>0</lowestgradelevel> +<mime>rights</mime> +<modifyinguser>$env{'user.name'}:$env{'user.domain'}</modifyinguser> +<notes></notes> +<obsolete></obsolete> +<obsoletereplacement></obsoletereplacement> +<owner>$cnum:$cdom</owner> +<rule>deny:::course,allow:$cid::course</rule> +<sourceavail></sourceavail> +<standards></standards> +<subject></subject> +<title>Course Authoring Rights</title> +END + close($fh); + } + } + return; +} + +=pod + +=item * &iframe_wrapper_headjs() + +emits javascript containing two global vars to facilitate handling of resizing +by code in iframe_wrapper_resizejs() used when an iframe is present in a page +with standard LON-CAPA menus. + +=cut + +# +# Where iframe is in use, if window.onload() executes before the custom resize function +# has been defined (jQuery), two global javascript vars (LCnotready and LCresizedef) +# are used to ensure document.ready() triggers a call to resize, so the iframe contents +# do not obscure the Functions menu. +# + +sub iframe_wrapper_headjs { + return <<"ENDJS"; +<script type="text/javascript"> +// <![CDATA[ +var LCnotready = 0; +var LCresizedef = 0; +// ]]> +</script> + +ENDJS + +} + +=pod + +=item * &iframe_wrapper_resizejs() + +emits javascript used to handle resizing for a page containing +an iframe, to ensure that the iframe does not obscure any +standard LON-CAPA menu items. + +=back + +=cut + +# +# jQuery to use when iframe is in use and a page resize occurs. +# This script will ensure that the iframe does not obscure any +# standard LON-CAPA inline menus (primary, secondary, and/or +# breadcrumbs and Functions menus. Expects javascript from +# &iframe_wrapper_headjs() to be in head portion of the web page, +# e.g., by inclusion in second arg passed to &start_page(). +# + +sub iframe_wrapper_resizejs { + my $offset = 5; + &get_unprocessed_cgi($ENV{'QUERY_STRING'},['inhibitmenu']); + if (($env{'form.inhibitmenu'} eq 'yes') || ($env{'form.only_body'})) { + $offset = 0; + } + return &Apache::lonhtmlcommon::scripttag(<<SCRIPT); + \$(document).ready( function() { + \$(window).unbind('resize').resize(function(){ + var header = null; + var offset = $offset; + var height = 0; + var hdrtop = 0; + if (\$('div.LC_menus_content:first').length) { + if (\$('div.LC_menus_content:first').hasClass ("shown")) { + header = \$('div.LC_menus_content:first'); + offset = 12; + } + } else if (\$('div.LC_head_subbox:first').length) { + header = \$('div.LC_head_subbox:first'); + offset = 9; + } else { + if (\$('#LC_breadcrumbs').length) { + header = \$('#LC_breadcrumbs'); + } + } + if (header != null && header.length) { + height = header.height(); + hdrtop = header.position().top; + } + var pos = height + hdrtop + offset; + \$('.LC_iframecontainer').css('top', pos); + }); + LCresizedef = 1; + if (LCnotready == 1) { + LCnotready = 0; + \$(window).trigger('resize'); + } + }); + window.onload = function(){ + if (LCresizedef) { + LCnotready = 0; + \$(window).trigger('resize'); + } else { + LCnotready = 1; + } + }; +SCRIPT + +} + =pod =head1 Excel and CSV file utility routines @@ -6461,6 +6621,109 @@ sub CSTR_pageheader { return $output; } +############################################## +=pod + +=item * &nocodemirror() + +Input: None + +Returns: 1 if CodeMirror is deactivated based on + user's preference, or domain default, + if user indicated use of default. + +=cut + +sub nocodemirror { + my $nocodem = $env{'environment.nocodemirror'}; + unless ($nocodem) { + my %domdefs = &Apache::lonnet::get_domain_defaults($env{'user.domain'}); + if ($domdefs{'nocodemirror'}) { + $nocodem = 'yes'; + } + } + if ($nocodem eq 'yes') { + return 1; + } + return; +} + +############################################## +=pod + +=item * &permitted_editors() + +Input: $uri (optional) + +Returns: %editors hash in which keys are editors + permitted in current Authoring Space. + Value for each key is 1. Possible keys + are: edit, xml, and daxe. If no specific + set of editors has been set for the Author + who owns the Authoring Space, then the + domain default will be used. If no domain + default has been set, then the keys will be + edit and xml. + +=cut + +sub permitted_editors { + my ($uri) = @_; + my ($is_author,$is_coauthor,$auname,$audom,%editors); + if ($env{'request.role'} =~ m{^au\./}) { + $is_author = 1; + } elsif ($env{'request.role'} =~ m{^(?:ca|aa)\./($match_domain)/($match_username)}) { + ($audom,$auname) = ($1,$2); + if (($audom ne '') && ($auname ne '')) { + if (($env{'user.domain'} eq $audom) && + ($env{'user.name'} eq $auname)) { + $is_author = 1; + } else { + $is_coauthor = 1; + } + } + } elsif ($env{'request.course.id'}) { + if ($env{'request.editurl'} =~ m{^/priv/($match_domain)/($match_username)/}) { + ($audom,$auname) = ($1,$2); + } elsif ($env{'request.uri'} =~ m{^/priv/($match_domain)/($match_username)/}) { + ($audom,$auname) = ($1,$2); + } elsif (($uri eq '/daxesave') && + ($env{'form.path'} =~ m{^/daxeopen/priv/($match_domain)/($match_username)/})) { + ($audom,$auname) = ($1,$2); + } + if (($audom ne '') && ($auname ne '')) { + if (($env{'user.domain'} eq $audom) && + ($env{'user.name'} eq $auname)) { + $is_author = 1; + } else { + $is_coauthor = 1; + } + } + } + if ($is_author) { + if (exists($env{'environment.editors'})) { + map { $editors{$_} = 1; } split(/,/,$env{'environment.editors'}); + } else { + %editors = ( edit => 1, + xml => 1, + ); + } + } elsif ($is_coauthor) { + if (exists($env{"environment.internal.editors./$audom/$auname"})) { + map { $editors{$_} = 1; } split(/,/,$env{"environment.internal.editors./$audom/$auname"}); + } else { + %editors = ( edit => 1, + xml => 1, + ); + } + } else { + %editors = ( edit => 1, + xml => 1, + ); + } + return %editors; +} + ############################################### ############################################### @@ -6687,10 +6950,33 @@ sub bodytag { $bodytag .= Apache::lonhtmlcommon::scripttag( Apache::lonmenu::utilityfunctions($httphost), 'start'); + my $collapsible; + if ($args->{'collapsible_header'} ne '') { + $collapsible = 1; + my ($menustate,$tiptext,$divclass); + if ($args->{'start_collapsed'}) { + $menustate = 'collapsed'; + $tiptext = 'display'; + $divclass = 'hidden'; + } else { + $menustate = 'expanded'; + $tiptext = 'hide'; + $divclass = 'shown'; + } + my $alttext = &mt('menu state: '.$menustate); + my $tooltip = &mt($tiptext.' standard menus'); + $bodytag .= <<"END"; +<div id="LC_expandingContainer" style="display:inline;"> +<div id="LC_collapsible" class="LC_collapse_trigger" style="position: absolute;top: -5px;left: 0px; z-index:101; display:inline;"> +<a href="#" style="text-decoration:none;"><img class="LC_collapsible_indicator" alt="$alttext" title="$tooltip" src="/res/adm/pages/$menustate.png" style="border:0;margin:0;padding:0;max-width:100%;height:auto" /></a></div> +<div class="LC_menus_content $divclass"> +END + } unless ($args->{'no_primary_menu'}) { my ($left,$right) = Apache::lonmenu::primary_menu($crstype,$ltimenu,$menucoll,$menuref, $args->{'links_disabled'}, - $args->{'links_target'}); + $args->{'links_target'}, + $collapsible); if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) { if ($dc_info) { @@ -6749,7 +7035,11 @@ sub bodytag { $bodytag .= '<hr style="clear:both" />'; $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end'); } - + if ($args->{'collapsible_header'} ne '') { + $bodytag .= $args->{'collapsible_header'}. + '<div id="LC_collapsible_separator"></div>'. + '</div></div>'; + } return $bodytag; } @@ -6942,6 +7232,14 @@ form, .inline { display: inline; } +.LC_menus_content.shown{ + display: block; +} + +.LC_menus_content.hidden { + display: none; +} + .LC_right { text-align:right; } @@ -6962,6 +7260,12 @@ form, .inline { width:400px; } +#LC_collapsible_separator { + border: 1px solid black; + width: 99.9%; + height: 0px; +} + .LC_iframecontainer { width: 98%; margin: 0; @@ -17721,6 +18025,17 @@ sub init_user_environment { \%userenv,\%domdef,\%is_adv); } + if ((ref($userroles) eq 'HASH') && ($userroles->{'user.author'}) && + (exists($userroles->{"user.role.au./$domain/"}))) { + if ($userenv{'authoreditors'}) { + $userenv{'editors'} = $userenv{'authoreditors'}; + } elsif ($domdef{'editors'} ne '') { + $userenv{'editors'} = $domdef{'editors'}; + } else { + $userenv{'editors'} = 'edit,xml'; + } + } + $userenv{'canrequest.author'} = &Apache::lonnet::usertools_access($username,$domain,'requestauthor', 'reload','requestauthor',