--- loncom/interface/lonpreferences.pm 2024/03/02 16:09:04 1.196.4.28.2.5 +++ loncom/interface/lonpreferences.pm 2025/03/05 05:24:42 1.247 @@ -1,7 +1,7 @@ # The LearningOnline Network # Preferences # -# $Id: lonpreferences.pm,v 1.196.4.28.2.5 2024/03/02 16:09:04 raeburn Exp $ +# $Id: lonpreferences.pm,v 1.247 2025/03/05 05:24:42 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -165,7 +165,7 @@ sub texenginechanger { my %mathchoices=('' => 'Default', 'tth' => 'tth (TeX to HTML)', #'ttm' => 'TeX to MathML', - 'MathJax' => 'MathJax', + 'MathJax' => 'MathJax', 'mimetex' => 'mimetex (Convert to Images)', 'raw' => 'Raw (Screen Reader)' ); @@ -182,7 +182,7 @@ sub texenginechanger { 'change' => 'Save', 'exmpl' => 'Examples', 'mathjax' => 'MathJax:', - 'mathjaxinfo' => 'MathJax provides rendered equations whose source code can be extracted in TeX and MathML formats by right clicking the equation.', + 'mathjaxinfo' => 'MathJax provides rendered equations whose source code can be extracted in TeX and MathML formats by right clicking the equation.', 'tth' => 'tth (TeX to HTML):', 'mimetex' => 'mimetex (Convert to Images):', ); @@ -280,7 +280,7 @@ sub rolesprefchanger { my $hotlist_n=$userenv{'recentrolesn'}; my ($checkedon,$checkedoff); if ($hotlist_flag) { - $checkedon = 'checked="checked"'; + $checkedon = 'checked="checked"'; } else { $checkedoff = 'checked="checked"'; } @@ -491,24 +491,24 @@ sub screennamechanger { text => 'Change Screen Name'}); $r->print(Apache::loncommon::start_page('Personal Data')); $r->print(Apache::lonhtmlcommon::breadcrumbs('Change Screen Name')); - $r->print('

' + $r->print('

' .&mt('Change the name that is displayed in your posts.') .'

' ); $r->print('
' .'' .&Apache::lonhtmlcommon::start_pick_box() - .&Apache::lonhtmlcommon::row_title(&mt('Screenname').' '.&mt('(shown if you post anonymously)')) - .'' + .&Apache::lonhtmlcommon::row_title(' '.&mt('(shown if you post anonymously)')) + .'' .&Apache::lonhtmlcommon::row_closure() - .&Apache::lonhtmlcommon::row_title(&mt('Nickname').' '.&mt('(shown if you post non-anonymously)')) - .'' + .&Apache::lonhtmlcommon::row_title(' '.&mt('(shown if you post non-anonymously)')) + .'' .&Apache::lonhtmlcommon::row_closure() - .&Apache::lonhtmlcommon::row_title() + .&Apache::lonhtmlcommon::row_title(''.&mt('Submit').':','','','',1) .'' .&Apache::lonhtmlcommon::row_closure(1) .&Apache::lonhtmlcommon::end_pick_box() - .'
' + .'
' ); } @@ -683,16 +683,51 @@ sub verify_and_change_clicker { my $r = shift; my $user = $env{'user.name'}; my $domain = $env{'user.domain'}; + my $uhome = $env{'user.home'}; my $newclickers = $env{'form.clickers'}; + my $message; $newclickers=~s/[^\w\:\-]+/\,/gs; $newclickers=~tr/a-z/A-Z/; $newclickers=~s/[\:\-]+/\-/g; $newclickers=~s/\,+/\,/g; $newclickers=~s/^\,//; $newclickers=~s/\,$//; - &Apache::lonnet::put('environment',{'clickers' => $newclickers}); - &Apache::lonnet::appenv({'environment.clickers' => $newclickers}); - my $message=&Apache::lonhtmlcommon::confirm_success(&mt('Registering clickers: [_1]',$newclickers)); + my @oldclickers = split(/,/,$env{'environment.clickers'}); + my @newclickers = split(/,/,$newclickers); + my %newuniq; + map { $newuniq{$_} = 1; } @newclickers; + @newclickers = sort(keys(%newuniq)); + my @differences = &Apache::loncommon::compare_arrays(\@oldclickers,\@newclickers); + if (@differences) { + my $putres = &Apache::lonnet::put('environment',{'clickers' => $newclickers}); + if ($putres eq 'ok') { + my @adds = (); + my @dels = (); + foreach my $item (@differences) { + if (grep(/^\Q$item\E$/,@newclickers)) { + push(@adds,$item); + } else { + push(@dels,$item); + } + } + if (@dels) { + my %delclicker; + map { $delclicker{$_} = $user; } @dels; + my $putresult = &Apache::lonnet::iddel($domain,\%delclicker,$uhome,'clickers'); + } + if (@adds) { + my %addclicker; + map { $addclicker{$_} = $user; } @adds; + my $putresult = &Apache::lonnet::updateclickers($domain,'add',\%addclicker,$uhome,1); + } + &Apache::lonnet::appenv({'environment.clickers' => $newclickers}); + $message=&Apache::lonhtmlcommon::confirm_success(&mt('Registering clickers: [_1]',$newclickers)); + } else { + $message=&Apache::lonhtmlcommon::confirm_success(&mt('Error saving clicker ID').1); + } + } else { + $message=''.&mt('Clicker information unchanged').''; + } $message=&Apache::loncommon::confirmwrapper($message); &print_main_menu($r, $message); } @@ -829,6 +864,7 @@ sub msgforwardchanger { my $validatescript = &Apache::lonhtmlcommon::javascript_valid_email(); my $jscript = qq| |; $r->print(<'.$colortypes{$item}.''. - &Apache::loncommon::end_data_table_row()."\n"; + ''.$colortypes{$item}.''. + &Apache::loncommon::end_data_table_row()."\n"; } my $end_data_table = &Apache::loncommon::end_data_table(); my $pjump_def = &Apache::lonhtmlcommon::pjump_javascript_definition(); @@ -1154,7 +1192,8 @@ sub colorschanger { my $resetbuttondesc = &mt('Reset All Colors to Default'); my $colorchooser=&Apache::lonhtmlcommon::color_picker(); $r->print(' '); $r->print(< $color}); @@ -1237,7 +1276,8 @@ sub passwordchanger { text => 'Change Password'}); unless ($caller eq 'reset_by_email') { $r->print(Apache::loncommon::start_page('Personal Data')); - $r->print(Apache::lonhtmlcommon::breadcrumbs('Change Password')); + $r->print(Apache::lonhtmlcommon::breadcrumbs('Change Password'). + '
'); } if ((!defined($caller)) || ($caller eq 'preferences')) { $user = $env{'user.name'}; @@ -1285,9 +1325,9 @@ sub passwordchanger { } else { $r->print( '

' - .&mt('Sorry, the URL generated when you requested reset of' - .' your password contained incomplete information.') - .'

' + .&mt('Sorry, the URL generated when you requested reset of' + .' your password contained incomplete information.') + .'

' ); return; } @@ -1336,7 +1376,7 @@ sub passwordchanger { $r->print(< +

@@ -1402,7 +1442,7 @@ sub jscript_send { var posspass = this.document.client.elements.newpass_1.value; if (min > 0) { if (posspass.length < min) { - errors.push("$js_lt{'short'}"); + errors.push("$js_lt{'short'}"); } } if (currauth == 'internal:') { @@ -1431,7 +1471,7 @@ sub jscript_send { } else if (rules[i] == 'spec') { var pattern = /^[!@#$%^&*()_+\\-=\\[\\]{};':"\\\|,.\\/?]/; if (!posspass.match(pattern)) { - errors.push("$js_lt{'spec'}"); + errors.push("$js_lt{'spec'}"); } } } @@ -1445,7 +1485,7 @@ sub jscript_send { ENDJS my $output = qq| |; } @@ -1522,16 +1563,16 @@ sub client_form { } else { $output .= &Apache::lonhtmlcommon::row_title( '') - .'' + .'' .&Apache::lonhtmlcommon::row_closure(); } $output .= &Apache::lonhtmlcommon::row_title( '') - .'' + .'' .&Apache::lonhtmlcommon::row_closure() .&Apache::lonhtmlcommon::row_title( '') - .'' + .'' .&Apache::lonhtmlcommon::row_closure(1) .&Apache::lonhtmlcommon::end_pick_box(); if ($caller eq 'reset_by_email') { @@ -1546,7 +1587,6 @@ sub client_form { -

|; return $output; } @@ -1725,10 +1765,10 @@ ENDERROR } else { my $warning = &Apache::loncommon::check_passwd_rules($domain,$newpass1); if ($warning) { - &passwordchanger($r,''. - $warning. - &mt('Please try again.').'', - $caller,$mailtoken,$timelimit,$extrafields); + &passwordchanger($r,''. + $warning. + &mt('Please try again.').'', + $caller,$mailtoken,$timelimit,$extrafields); if ($caller eq 'reset_by_email') { return 'rules'; } else { @@ -2046,7 +2086,11 @@ sub author_space_settings { my ($showdomdefs,$js,$args,@items); my $returnurl = &HTML::Entities::encode($env{'form.returnurl'},'"<>&\''); if (&expanded_authoring_settings()) { - @items = ('nocodemirror','copyright','sourceavail'); + @items = ('nocodemirror'); + if (&daxe_permitted(\%author_roles)) { + push(@items,'daxecollapse'); + } + push(@items,('copyright','sourceavail')); $showdomdefs = 1; $js = &toggle_options_js(); my $onload; @@ -2062,13 +2106,15 @@ sub author_space_settings { my %domdefs = &Apache::lonnet::get_domain_defaults($domain); my %staticdefaults = ( 'nocodemirror' => '0', + 'daxecollapse' => '0', 'copyright' => 'default', 'sourceavail' => 'closed', ); my %lt = &authoring_settings_text(); my %titles = &authoring_settings_titles(); - $r->print("

$lt{'auss'}



\n". + $r->print("

$lt{'auss'}

". '
'."\n". + '

'."\n". ''."\n". ''."\n"); foreach my $item (@items) { @@ -2090,22 +2136,41 @@ sub author_space_settings { $userelem = &selectbox('userchoice_'.$item,$userenv{$item},'', \&Apache::loncommon::source_copyrightdescription, (&Apache::loncommon::source_copyrightids)); - } elsif ($item eq 'nocodemirror') { + } elsif (($item eq 'nocodemirror') || ($item eq 'daxecollapse')) { if ($domdef) { - $domdefdisplay = $lt{'yes'}; + if ($item eq 'daxecollapse') { + $domdefdisplay = $lt{'coll'}; + } else { + $domdefdisplay = $lt{'yes'}; + } } else { - $domdefdisplay = $lt{'no'}; + if ($item eq 'daxecollapse') { + $domdefdisplay = $lt{'expa'}; + } else { + $domdefdisplay = $lt{'no'}; + } } - my %checked; + my (%checked,%text); $checked{'no'} = ' checked="checked"'; if ($userenv{$item} eq 'yes') { $checked{'yes'} = $checked{'no'}; $checked{'no'} = ''; } + if ($item eq 'daxecollapse') { + %text = ( + yes => $lt{'coll'}, + no => $lt{'expa'}, + ); + } else { + %text = ( + yes => $lt{'yes'}, + no => $lt{'no'}, + ); + } $userelem = ''; foreach my $choice ('yes','no') { $userelem .= '   '; + $checked{$choice}.' />'.$text{$choice}.'   '; } $userelem .= ''; } @@ -2126,8 +2191,7 @@ $userelem

END } - $r->print('
'. - ''. + $r->print(''. '
'."\n"); } else { my $constchecked=''; @@ -2171,7 +2235,11 @@ sub change_authoring_settings { $message=&Apache::lonhtmlcommon::confirm_success(&mt('Set [_1] to [_2]',''.&mt('Deactivate CodeMirror in Authoring Space').'',''.$status.'')); $message=&Apache::loncommon::confirmwrapper($message); } else { - my @items = ('nocodemirror','copyright','sourceavail'); + my @items = ('nocodemirror'); + if (&daxe_permitted(\%author_roles)) { + push(@items,'daxecollapse'); + } + push(@items,('copyright','sourceavail')); my %oldsettings = &Apache::lonnet::get('environment',\@items); my %domdefs = &Apache::lonnet::get_domain_defaults($domain); my %lt = &authoring_settings_text(); @@ -2187,7 +2255,7 @@ sub change_authoring_settings { } elsif ($env{'form.'.$item} eq 'user') { my $newval = $env{'form.userchoice_'.$item}; my @possibles; - if ($item eq 'nocodemirror') { + if (($item eq 'nocodemirror') || ($item eq 'daxecollapse')) { if ($newval =~ /^yes|no$/) { $newsettings{$item} = $newval; } @@ -2242,6 +2310,12 @@ sub change_authoring_settings { my $value = $changes{$item}; if ($item eq 'nocodemirror') { $value = $lt{$changes{$item}}; + } elsif ($item eq 'daxecollapse') { + if ($value eq 'yes') { + $value = $lt{'coll'}; + } else { + $value = $lt{'expa'}; + } } elsif ($item eq 'copyright') { $value = &Apache::loncommon::copyrightdescription($changes{$item}); } elsif ($item eq 'sourceavail') { @@ -2289,12 +2363,15 @@ sub authoring_settings_text { 'save' => 'Save', 'yes' => 'Deactivated', 'no' => 'Activated', + 'expa' => 'Start Expanded', + 'coll' => 'Start Collapsed', ); } sub authoring_settings_titles { return &Apache::lonlocal::texthash( 'nocodemirror' => 'CodeMirror for EditXML editor', + 'daxecollapse' => 'Daxe editor: collapsible standard LON-CAPA menus', 'copyright' => 'Default Copyright/Distribution in new metadata file', 'sourceavail' => 'Default Source Available in new metadata file', ); @@ -2302,30 +2379,43 @@ sub authoring_settings_titles { sub expanded_authoring_settings { my $reqdmajor = 2; - my $reqdminor = 11; - my $reqddotnum = 4; - my $reqddotlett= 'B'; - my $reqdreldate = '2024030109'; - my $reqletterfail; + my $reqdminor = 12; my $loncaparev = &Apache::lonnet::get_server_loncaparev($env{'user.domain'},$env{'user.home'}); - my ($major,$minor,$dotrel,$reldate) = ($loncaparev =~ /^\'?(\d+)\.(\d+)\.([\w.]+)\-(\d+)\'?$/); - my ($dotnum,$dotlett) = split(/\./,$dotrel); - my %lettdig = &Apache::lonnet::letter_to_digits(); - if ((exists($lettdig{$dotlett})) && (exists($lettdig{$reqddotlett}))) { - if ($lettdig{$reqddotlett} > $lettdig{$dotlett}) { - $reqletterfail = 1; - } - } + my ($major,$minor) = ($loncaparev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/); unless (($major eq '' && $minor eq '') || - ($reqdmajor > $major) || (($reqdmajor == $major) && ($reqdminor > $minor)) || - (($reqdmajor == $major) && ($reqdminor == $minor) && ($reqddotnum > $dotnum)) || - (($reqdmajor == $major) && ($reqdminor == $minor) && ($reqddotnum == $dotnum) && $reqletterfail) || - (($reqdmajor == $major) && ($reqdminor == $minor) && ($reqddotnum == $dotnum) && ($reqdreldate > $reldate))) { + ($reqdmajor > $major) || (($reqdmajor == $major) && ($reqdminor > $minor))) { return 1; } return; } +sub daxe_permitted { + my ($aurolesref) = @_; + my $hasdaxe; + if (ref($aurolesref) eq 'HASH') { + my %editors; + foreach my $key (keys(%{$aurolesref})) { + if ($key =~ /^:$LONCAPA::match_domain:au$/) { + if (exists($env{'environment.editors'})) { + if (grep(/^daxe$/,split(/,/,$env{'environment.editors'}))) { + $hasdaxe = 1; + last; + } + } + } else { + my ($auname,$audom) = ($key =~ /^($LONCAPA::match_username):($LONCAPA::match_domain):(ca|aa)$/); + if (exists($env{"environment.internal.editors./$audom/$auname"})) { + if (grep(/^daxe$/,split(/,/,$env{"environment.internal.editors./$audom/$auname"}))) { + $hasdaxe = 1; + last; + } + } + } + } + } + return $hasdaxe; +} + sub lockednameschanger { my $r = shift; my %userenv = &Apache::lonnet::get('environment',['lockedname']); @@ -2528,6 +2618,7 @@ my @menu= permission => $permissions{'aboutme'}, #help => 'Prefs_About_Me', icon => 'system-users.png', + alttext => 'About Me Icon', linktitle => 'Edit information about yourself that should be displayed on your public profile.' }, { linktext => 'Screen Name', @@ -2535,6 +2626,7 @@ my @menu= permission => 'F', #help => 'Prefs_Screen_Name_Nickname', icon => 'preferences-desktop-font.png', + alttext => 'Nickname Icon', linktitle => 'Change the name that is displayed in your posts.' }, ] @@ -2546,6 +2638,7 @@ my @menu= permission => 'F', #help => 'Prefs_Language', icon => 'preferences-desktop-locale.png', + alttext => 'Language Icon', linktitle => 'Choose the default language for this user.' }, { linktext => $role.' Page', @@ -2553,6 +2646,7 @@ my @menu= permission => 'F', #help => '', icon => 'role_hotlist.png', + alttext => 'Switch Role Icon', linktitle => 'Configure the roles hotlist.' }, { linktext => 'Math display settings', @@ -2560,6 +2654,7 @@ my @menu= permission => 'F', #help => '', icon => 'dismath.png', + alttext => 'Math Icon', linktitle => 'Change how math is displayed.' }, { @@ -2568,6 +2663,7 @@ my @menu= permission => $permissions{'timezone'}, #help => '', icon => 'timezone.png', + alttext => 'Clock Icon', linktitle => 'Set your time zone.', } ] @@ -2579,6 +2675,7 @@ my @menu= permission => 'F', #help => 'Change_Colors', icon => 'preferences-desktop-theme.png', + alttext => 'Colors Icon', linktitle => 'Change LON-CAPA default colors.' }, { linktext => 'Menu Display', @@ -2586,6 +2683,7 @@ my @menu= permission => 'F', #help => '', icon => 'preferences-system-windows.png', + alttext => 'Menus Icon', linktitle => 'Change whether the menus are displayed with icons or icons and text.' } ] @@ -2597,6 +2695,7 @@ my @menu= permission => 'F', #help => 'Prefs_Messages', icon => 'mail-reply-all.png', + alttext => 'Notifications Icon', linktitle => 'Change messageforwarding or notifications settings.' }, { linktext => 'Discussion Display', @@ -2604,6 +2703,7 @@ my @menu= permission => 'F', #help => 'Change_Discussion_Display', icon => 'chat.png', + alttext => 'Discussions Icon', linktitle => 'Set display preferences for discussion posts for both discussion boards and individual resources in all your courses.' }, ] @@ -2618,6 +2718,7 @@ if (keys(%author_coauthor_roles) > 0) { url => '/adm/preferences?action=authorsettings', permission => 'F', icon => 'codemirror.png', + alttext => 'Coding Icon', linktitle => 'Settings for your authoring space.', }, ] @@ -2630,6 +2731,7 @@ if (keys(%author_coauthor_roles) > 0) { permission => 'F', #help => '', icon => 'system-lock-screen.png', + alttext => 'Lock Icon', linktitle => 'Restrict domain coordinator access.', }); } @@ -2642,11 +2744,12 @@ push(@menu, permission => 'F', #help => '', icon => 'network-workgroup.png', + alttext => 'Clicker Icon', linktitle => 'Register your clicker.' }, ] }, - ); +); if ($currentauth =~ /^(unix|internal):/) { push(@{ $menu[0]->{items} }, { @@ -2655,28 +2758,10 @@ push(@menu, permission => 'F', #help => 'Change_Password', icon => 'emblem-readonly.png', + alttext => 'Secure Icon', linktitle => 'Change your password.', }); } - if ($env{'environment.remote'} eq 'off') { - push(@{ $menu[1]->{items} }, { - linktext => 'Launch Remote Control', - url => '/adm/remote?url=/adm/preferences&action=launch', - permission => 'F', - #help => '', - icon => 'remotecontrol.png', - linktitle => 'Launch the remote control for LON-CAPA.', - }); - }else{ -push(@{ $menu[1]->{items} }, { - linktext => 'Collapse Remote Control', - url => '/adm/remote?url=/adm/preferences&action=collapse', - permission => 'F', - #help => '', - icon => 'remotecontrol.png', - linktitle => 'Collapse the remote control for LON-CAPA.', - }); - } if (&can_toggle_namelocking()) { push(@{ $menu[0]->{items} }, { @@ -2685,6 +2770,7 @@ push(@{ $menu[1]->{items} }, { permission => 'F', #help => '', icon => 'system-lock-screen.png', + alttext => 'Screen Lock Icon', linktitle => 'Allow/disallow propagation of name changes from institutional directory service', }); } @@ -2698,6 +2784,7 @@ push(@{ $menu[-1]->{items} }, { permission => 'F', #help => '', icon => 'course_ini.png', + alttext => 'Course Launch Icon', linktitle => 'Set the default page to be displayed when you select a course role.', }); @@ -2710,14 +2797,15 @@ push(@{ $menu[-1]->{items} }, { permission => 'F', #help => '', icon => 'blog.png', + alttext => 'Debugging Icon', linktitle => 'Toggle Debug Messages.', }); } $r->print(&Apache::loncommon::start_page('My Space')); $r->print(Apache::lonhtmlcommon::breadcrumbs('Change Preferences')); - $r->print($message); - $r->print(Apache::lonhtmlcommon::generate_menu(@menu)); + $r->print('
'."\n".$message); + $r->print(Apache::lonhtmlcommon::generate_menu(@menu)."\n".'
'); $r->print(Apache::loncommon::end_page()); } @@ -2766,10 +2854,11 @@ sub handler { text => $brtxt, help => $brhelp,}); if(!exists $env{'form.action'}) { - &print_main_menu($r); - $ended = 1; + &print_main_menu($r); + $ended = 1; }elsif($env{'form.action'} eq 'changepass'){ &passwordchanger($r); + $r->print('
'); }elsif($env{'form.action'} eq 'verify_and_change_pass'){ &verify_and_change_password($r,'preferences','','','',\$ended); }elsif($env{'form.action'} eq 'changescreenname'){