Merge branch 'MDL-87546-main' of https://github.com/HuongNV13/moodle

This commit is contained in:
Michael Hawkins
2026-03-12 12:36:22 +08:00
28 changed files with 887 additions and 224 deletions
+45 -2
View File
@@ -51,8 +51,49 @@ class manager {
'tool_mfa' => [
'guidance',
],
'theme_*' => [
'loginbackgroundimage',
],
];
/**
* Returns allowed fileareas for a component.
*
* Supports exact component matches and wildcard suffix matches such as `theme_*`.
*
* @param string $component the component to check.
* @return array|null the allowed fileareas, or null if the component is not allowed.
*/
protected static function get_allowed_fileareas_for_component(string $component): ?array {
if (array_key_exists($component, static::ALLOWED_COMPONENTS)) {
return static::ALLOWED_COMPONENTS[$component];
}
foreach (static::ALLOWED_COMPONENTS as $pattern => $fileareas) {
if (!str_ends_with($pattern, '*')) {
continue;
}
$prefix = substr($pattern, 0, -1);
if ($prefix !== '' && str_starts_with($component, $prefix)) {
return $fileareas;
}
}
return null;
}
/**
* Checks whether a filearea is allowed.
*
* @param string $filearea the filearea to check.
* @param array $allowedfileareas the allowed fileareas for the component, where '*' allows all fileareas.
* @return bool
*/
protected static function is_allowed_filearea(string $filearea, array $allowedfileareas): bool {
return in_array('*', $allowedfileareas) || in_array($filearea, $allowedfileareas);
}
/**
* Displays a debug table with current factor information.
*
@@ -469,13 +510,15 @@ class manager {
$component = clean_param(array_shift($args), PARAM_COMPONENT);
$filearea = clean_param(array_shift($args), PARAM_AREA);
$allowedfileareas = static::get_allowed_fileareas_for_component($component);
// Check allowed components.
if (!array_key_exists($component, static::ALLOWED_COMPONENTS)) {
if ($allowedfileareas === null) {
return self::REDIRECT;
}
// Check allowed fileareas.
if (!in_array($filearea, static::ALLOWED_COMPONENTS[$component])) {
if (!static::is_allowed_filearea($filearea, $allowedfileareas)) {
return self::REDIRECT;
}
@@ -277,6 +277,14 @@ final class manager_test extends \advanced_testcase {
$guideurl = new \moodle_url('/pluginfile.php/1/tool_mfa/guidance/0/capybara.png');
$this->assertEquals(\tool_mfa\manager::NO_REDIRECT, \tool_mfa\manager::should_require_mfa($guideurl, false));
// Access the allowed theme pluginfile area via wildcard component rules.
$themeurl = new \moodle_url('/pluginfile.php/1/theme_boost/loginbackgroundimage/0/background.jpg');
$this->assertEquals(\tool_mfa\manager::NO_REDIRECT, \tool_mfa\manager::should_require_mfa($themeurl, false));
// Access a different theme pluginfile area which is not explicitly allowed.
$themeurl = new \moodle_url('/pluginfile.php/1/theme_classic/customfield/0/example.txt');
$this->assertEquals(\tool_mfa\manager::REDIRECT, \tool_mfa\manager::should_require_mfa($themeurl, false));
// Access private area.
$user3 = $this->getDataGenerator()->create_user();
$privateurl = new \moodle_url("/pluginfile.php/{$user3->id}/user/private/privatefile.png");
@@ -14,7 +14,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
| passwordpolicy | 0 |
| sitepolicyhandler | tool_policy |
And I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
Then I should not see "I understand and agree"
And I set the following fields to these values:
| Username | user1 |
@@ -47,7 +47,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
| P1 | This site policy | | full text1 | short text1 | draft |
| P1 | This privacy policy | | full text2 | short text2 | draft |
And I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
Then I should not see "I understand and agree"
And I set the following fields to these values:
| Username | user1 |
@@ -81,7 +81,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
| P1 | This site policy | | full text2 | short text2 | active |
| P1 | This site policy | | full text3 | short text3 | draft |
And I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
Then I should see "This site policy" in the "region-main" "region"
And I should see "short text2"
And I should see "full text2"
@@ -128,7 +128,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
| This privacy policy | 1 | | full text3 | short text3 | active | loggedin |
| This guests policy | 0 | | full text4 | short text4 | active | guest |
And I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
Then I should see "This site policy" in the "region-main" "region"
And I should see "short text2"
And I should see "full text2"
@@ -187,7 +187,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
| Name | Revision | Content | Summary | Status |
| This site policy | | full text2 | short text2 | active |
And I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
Then I should see "Age and location verification"
And I set the field "What is your age?" to "16"
And I set the field "In which country do you live?" to "DZ"
@@ -237,7 +237,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
| This site policy | 0 | | full text2 | short text2 | active | all |
| This privacy policy | 1 | | full text3 | short text3 | active | loggedin |
And I am on homepage
And I click on "Create new account" "link"
And I click on "Sign up" "link"
And I should see "This site policy"
And I press "Next"
And I should see "This privacy policy"
@@ -457,7 +457,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
| This guests policy | 0 | | full text4 | short text4 | active | guest |
And I am on homepage
And I change window size to "large"
When I press "Access as a guest"
When I press "Log in as guest"
Then I should see "If you continue browsing this website, you agree to our policies"
# Confirm when navigating, the pop-up policies are displayed.
When I am on the "My courses" page
@@ -489,7 +489,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
| This privacy policy | 1 | | full text3 | short text3 | active | loggedin |
| This guests policy | 0 | | full text4 | short text4 | active | guest |
And I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
Then I should see "This site policy" in the "region-main" "region"
And I should see "short text2"
And I should see "full text2"
@@ -521,7 +521,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
Then I should see "Confirm your account"
And I should see "An email should have been sent to your address at user1@example.com"
And I follow "Log in"
When I click on "Create new account" "link"
When I click on "Sign up" "link"
# Confirm that the user can view and accept policies when attempting to create another account.
Then I should see "This site policy" in the "region-main" "region"
And I should see "short text2"
@@ -617,10 +617,10 @@ Feature: User must accept policy managed by this plugin when logging in and sign
| P1 | This site policy | | full text3 | short text3 | draft |
And I am on homepage
# First log in as a guest
And I press "Access as a guest"
And I press "Log in as guest"
# Now sign up
And I follow "Log in"
When I click on "Create new account" "link"
When I click on "Sign up" "link"
Then I should see "This site policy"
And I should see "short text2"
And I should see "full text2"
@@ -668,7 +668,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
| Cookies policy | We eat cookies, srsly | Here goes content. | 0 |
| Terms of Service | We teach, you learn | Here goes content. | 1 |
And I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
# The first policy with the agreement style "on its own page" must be accepted first.
Then I should see "Digital maturity declaration" in the "region-main" "region"
And I should see "You declare be old enough"
@@ -831,7 +831,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
| Cookies policy | We eat cookies, srsly | Here goes content. | 1 | loggedin |
| Terms of Service | We teach, you learn | Here goes content. | 1 | guest |
And I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
# All the policies to be displayed one by one with a button to accept each of them prior seeing the next.
Then I should see "Digital maturity declaration" in the "region-main" "region"
And I should see "You declare be old enough"
@@ -64,7 +64,7 @@ Feature: Optional policies
| OwnPageCompulsory1 | full text4 | short text4 | 1 | 0 |
| OwnPageOptional1 | full text5 | short text5 | 1 | 1 |
And I am on homepage
And I click on "Create new account" "link"
And I click on "Sign up" "link"
# Compulsory policies displayed on own page are shown first and must be agreed.
And I should see "OwnPageCompulsory1" in the "region-main" "region"
And I should see "short text4" in the "region-main" "region"
+14 -5
View File
@@ -53,6 +53,8 @@ class login implements renderable, templatable {
public $cookieshelpicon;
/** @var string The error message, if any. */
public $error;
/** @var string The error title, shown as bold heading above the error message for credential failures. */
public $errortitle;
/** @var string The info message, if any. */
public $info;
/** @var moodle_url Forgot password URL. */
@@ -114,7 +116,7 @@ class login implements renderable, templatable {
if (is_enabled_auth('none')) {
$this->instructions = get_string('loginstepsnone');
} else if ($CFG->registerauth == 'email' && empty($this->instructions)) {
$this->instructions = get_string('loginsteps', 'core', 'signup.php');
$this->instructions = get_string('logindonthaveaccount');
}
if ($CFG->maintenance_enabled == true) {
@@ -142,12 +144,19 @@ class login implements renderable, templatable {
}
/**
* Set the error message.
* Set the error message. For the AUTH_LOGIN_FAILED case, also sets
* an errortitle so the template can render a bold heading above the detail text.
*
* @param string $error The error message.
* @param int $errorcode The error code from login/index.php.
*/
public function set_error($error) {
$this->error = $error;
public function set_error(string $error, int $errorcode = 0): void {
if ($errorcode === AUTH_LOGIN_FAILED) {
$this->errortitle = get_string('logininvalidlogintitle');
$this->error = get_string('logininvalidlogindetail');
} else {
$this->error = $error;
}
}
/**
@@ -170,10 +179,10 @@ class login implements renderable, templatable {
$data->cansignup = $this->cansignup;
$data->cookieshelpicon = $this->cookieshelpicon->export_for_template($output);
$data->error = $this->error;
$data->errortitle = $this->errortitle;
$data->info = $this->info;
$data->forgotpasswordurl = $this->forgotpasswordurl->out(false);
$data->hasidentityproviders = !empty($this->identityproviders);
$data->hasinstructions = !empty($this->instructions) || $this->cansignup;
$data->identityproviders = $identityproviders;
list($data->instructions, $data->instructionsformat) = \core_external\util::format_text($this->instructions, FORMAT_MOODLE,
context_system::instance()->id);
+3 -3
View File
@@ -9,7 +9,7 @@ Feature: User must accept policy when logging in and signing up
| registerauth | email |
| passwordpolicy | 0 |
And I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
Then I should not see "I understand and agree"
And I set the following fields to these values:
| Username | user1 |
@@ -38,7 +38,7 @@ Feature: User must accept policy when logging in and signing up
| passwordpolicy | 0 |
| sitepolicy | https://moodle.org |
And I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
Then the field "I understand and agree" matches value "0"
And I set the following fields to these values:
| Username | user1 |
@@ -71,7 +71,7 @@ Feature: User must accept policy when logging in and signing up
| username | firstname | lastname | email |
| s1 | John | Doe | s1@example.com |
And I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
And I set the following fields to these values:
| Username | s2 |
| Password | test |
@@ -18,7 +18,7 @@ Feature: Test the 'showlogfailures' feature works.
And I set the field "Username" to "teacher1"
And I set the field "Password" to "wrongpass"
And I press "Log in"
And I should see "Invalid login, please try again"
And I should see "Unable to log in"
# Now, log in with the correct credentials.
When I set the field "Username" to "teacher1"
And I set the field "Password" to "teacher1"
@@ -38,7 +38,7 @@ Feature: Test the 'showlogfailures' feature works.
And I set the field "Username" to "admin"
And I set the field "Password" to "wrongpass"
And I press "Log in"
And I should see "Invalid login, please try again"
And I should see "Unable to log in"
# Now, log in with the correct credentials.
When I set the field "Username" to "admin"
And I set the field "Password" to "admin"
+1 -1
View File
@@ -35,7 +35,7 @@ Feature: Authentication
And I set the field "Username" to "testuser"
And I set the field "Password" to "unexisting"
And I press "Log in"
Then I should see "Invalid login, please try again"
Then I should see "Unable to log in"
Scenario: Log out using the Log out link
Given I log in as "admin"
+2 -2
View File
@@ -16,7 +16,7 @@ Feature: Test if the login form provides the correct feedback
And I set the field "Username" to "teacher1"
And I set the field "Password" to "incorrect"
When I press "Log in"
Then I should see "Invalid login, please try again"
Then I should see "Unable to log in"
Scenario: Test login language selector
Given remote langimport tests are enabled
@@ -60,7 +60,7 @@ Feature: Test if the login form provides the correct feedback
Given the following config values are set as admin:
| registerauth | Email-based self-registration |
And I am on homepage
Then I should see "Create new account"
Then I should see "Sign up"
Scenario: Set OAuth providers
Given I log in as "admin"
@@ -12,7 +12,7 @@ Feature: Test the 'Digital age of consent verification' feature works.
Scenario: User that is not considered a digital minor attempts to self-register on the site.
# Try to access the sign up page.
Given I am on homepage
And I click on "Create new account" "link"
And I click on "Sign up" "link"
Then I should see "Age and location verification"
When I set the field "What is your age?" to "16"
And I set the field "In which country do you live?" to "DZ"
@@ -21,14 +21,14 @@ Feature: Test the 'Digital age of consent verification' feature works.
And I should see "Username"
# Try to access the sign up page again.
When I press "Cancel"
And I click on "Create new account" "link"
And I click on "Sign up" "link"
Then I should see "New account"
And I should see "Username"
Scenario: User that is considered a digital minor attempts to self-register on the site.
# Try to access the sign up page.
Given I am on homepage
And I click on "Create new account" "link"
And I click on "Sign up" "link"
Then I should see "Age and location verification"
When I set the field "What is your age?" to "12"
And I set the field "In which country do you live?" to "AT"
@@ -37,6 +37,6 @@ Feature: Test the 'Digital age of consent verification' feature works.
And I should see "Please ask your parent/guardian to contact:"
# Try to access the sign up page again.
When I click on "Back to the site home" "link"
And I click on "Create new account" "link"
And I click on "Sign up" "link"
Then I should see "You are too young to create an account on this site."
And I should see "Please ask your parent/guardian to contact:"
@@ -28,7 +28,7 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
| Custom instance name | Test student enrolment |
And I log out
When I am on "Course 1" course homepage
And I press "Access as a guest"
And I press "Log in as guest"
Then I should see "Guests cannot access this course. Please log in."
And I press "Continue"
And I should see "Log in"
+22 -2
View File
@@ -1233,20 +1233,40 @@ $string['loggedinasguest'] = 'You are currently using guest access';
$string['loggedinnot'] = 'You are not logged in.';
$string['login'] = 'Log in';
$string['loginactivity'] = 'Login activity';
$string['loginagain'] = 'Log in again';
$string['loginalready'] = 'You are already logged in';
$string['loginas'] = 'Log in as';
$string['loginasguest'] = 'Log in as guest';
$string['loginaspasswordexplain'] = '<p>You must enter the special "loginas password" to use this feature.<br />If you do not know it, ask your server administrator.</p>';
$string['logindonthaveaccount'] = 'Don\'t have an account?';
$string['loginenterpassword'] = 'Enter your password';
$string['loginenterusernameoremail'] = 'Enter your username or email';
$string['login_failure_logs'] = 'Login failure logs';
$string['loginforgotpassword'] = 'Forgot password?';
$string['loginguest'] = 'Access as a guest';
$string['logininvalidlogindetail'] = 'Your login info may be incorrect. Please try again.';
$string['logininvalidlogintitle'] = 'Unable to log in';
$string['loginpaneltagline'] = 'You\'re part of a global learning community';
$string['loginrequired'] = 'Login required';
$string['loginseparatoror'] = 'OR';
$string['loginsite'] = 'Log in to the site';
$string['loginstartsignup'] = 'Sign up';
$string['loginstatcountries'] = 'countries';
$string['loginstatcountries_value'] = '200+';
$string['loginstatsites'] = 'sites';
$string['loginstatsites_value'] = '150K';
$string['loginstatusers'] = 'users';
$string['loginstatusers_value'] = '500M';
$string['loginsteps'] = 'For full access to this site, you first need to create an account.';
$string['loginstepsnone'] = '<p>Hi!</p>
<p>For full access to courses you\'ll need to create yourself an account.</p>
<p>All you need to do is make up a username and password and use it in the form on this page!</p>
<p>If someone else has already chosen your username then you\'ll have to try again using a different username.</p>';
$string['loginto'] = 'Log in to {$a}';
$string['loginagain'] = 'Log in again';
$string['loginrequired'] = 'Login required';
$string['loginwelcomeback'] = 'Welcome back';
$string['loginwelcomedescription'] = 'Your learning journey starts here. Access courses, connect with peers, and achieve your goals.';
$string['loginwelcometitle'] = 'Welcome to Moodle';
$string['loginwith'] = 'Log in with';
$string['logoof'] = 'Logo of {$a}';
$string['logout'] = 'Log out';
$string['logoutconfirm'] = 'Do you really want to log out?';
+4 -1
View File
@@ -364,8 +364,10 @@ if (!empty($SESSION->loginerrormsg) || !empty($SESSION->logininfomsg)) {
// We had some messages before redirect, show them now.
$errormsg = $SESSION->loginerrormsg ?? '';
$infomsg = $SESSION->logininfomsg ?? '';
$errorcode = (int) ($SESSION->loginerrorcode ?? 0);
unset($SESSION->loginerrormsg);
unset($SESSION->logininfomsg);
unset($SESSION->loginerrorcode);
} else if ($testsession) {
// No need to redirect here.
@@ -376,6 +378,7 @@ if (!empty($SESSION->loginerrormsg) || !empty($SESSION->logininfomsg)) {
// We must redirect after every password submission.
if ($errormsg) {
$SESSION->loginerrormsg = $errormsg;
$SESSION->loginerrorcode = $errorcode;
}
// Add redirect param to url.
@@ -404,7 +407,7 @@ if (isloggedin() and !isguestuser()) {
echo $OUTPUT->box_end();
} else {
$loginform = new \core_auth\output\login($authsequence, $frm->username);
$loginform->set_error($errormsg);
$loginform->set_error($errormsg, $errorcode);
$loginform->set_info($infomsg);
echo $OUTPUT->render($loginform);
}
+1 -1
View File
@@ -21,6 +21,6 @@ Feature: Login using email address
Examples:
| authloginviaemail | login | message |
| 0 | testuser | You are logged in as |
| 0 | user@example.com | Invalid login, please try again |
| 0 | user@example.com | Unable to log in |
| 1 | testuser | You are logged in as |
| 1 | user@example.com | You are logged in as |
@@ -29,7 +29,7 @@ Feature: Guest and not logged users could see the option to add new post or repl
| teacher | forum | Forum discussion 1 | How awesome is this forum discussion? |
And I log out
And I am on "Course 1" course homepage
When I press "Access as a guest"
When I press "Log in as guest"
And I am on the "Forum" "forum activity" page
Then I should not see "Add discussion topic"
And I should see "Forum discussion 1"
@@ -48,7 +48,7 @@ Feature: Guest and not logged users could see the option to add new post or repl
| forum | Forum (single discussion) | C1 | forum | single |
And I log out
And I am on "Course 1" course homepage
When I press "Access as a guest"
When I press "Log in as guest"
And I am on the "Forum (single discussion)" "forum activity" page
Then I should not see "Add discussion topic"
And I should see "Forum (single discussion)"
@@ -63,7 +63,7 @@ Feature: Guest and not logged users could see the option to add new post or repl
| teacher | forum | Forum discussion 1 | How awesome is this forum discussion? |
And I log out
And I am on "Course 1" course homepage
When I press "Access as a guest"
When I press "Log in as guest"
And I am on the "Forum" "forum activity" page
Then I should not see "Add discussion topic"
And I should see "Forum discussion 1"
@@ -80,7 +80,7 @@ Feature: Guest and not logged users could see the option to add new post or repl
| teacher | forum | Forum discussion 1 | How awesome is this forum discussion? |
And I log out
And I am on "Course 1" course homepage
When I press "Access as a guest"
When I press "Log in as guest"
And I am on the "Forum" "forum activity" page
Then I should see "Add discussion topic"
And I click on "Add discussion topic" "link"
@@ -108,7 +108,7 @@ Feature: Guest and not logged users could see the option to add new post or repl
| forum | Forum (single discussion) | C1 | forum | single |
And I log out
And I am on "Course 1" course homepage
When I press "Access as a guest"
When I press "Log in as guest"
And I am on the "Forum (single discussion)" "forum activity" page
And I should see "Forum (single discussion)"
Then I should see "Reply"
@@ -131,7 +131,7 @@ Feature: Guest and not logged users could see the option to add new post or repl
| teacher | forum | Forum discussion 1 | How awesome is this forum discussion? |
And I log out
And I am on "Course 1" course homepage
When I press "Access as a guest"
When I press "Log in as guest"
And I am on the "Forum" "forum activity" page
Then I should see "Add discussion topic"
And I click on "Add discussion topic" "link"
@@ -16,6 +16,7 @@
namespace theme_boost\output;
use context_course;
use moodle_url;
use html_writer;
use get_string;
@@ -252,4 +253,29 @@ class core_renderer extends \core_renderer {
}
return $firstview;
}
/**
* Renders the Boost login form context.
*
* @param \core_auth\output\login $form The renderable.
* @return string
*/
public function render_login(\core_auth\output\login $form) {
global $CFG, $SITE;
$context = $form->export_for_template($this);
$url = $this->get_logo_url();
if ($url) {
$url = $url->out(false);
}
$context->logourl = $url;
$context->sitename = format_string(
$SITE->fullname,
true,
['context' => context_course::instance(SITEID), 'escape' => false]
);
$context->hasauthinstructions = !empty($CFG->auth_instructions);
return $this->render_from_template('core/loginform', $context);
}
}
+8 -2
View File
@@ -26,11 +26,17 @@ defined('MOODLE_INTERNAL') || die();
$bodyattributes = $OUTPUT->body_attributes();
// Left-panel instructions.
$leftinstructions = get_string('loginwelcomedescription');
if (!empty($CFG->auth_instructions)) {
$leftinstructions = $CFG->auth_instructions;
}
$templatecontext = [
'sitename' => format_string($SITE->shortname, true, ['context' => context_course::instance(SITEID), "escape" => false]),
'output' => $OUTPUT,
'bodyattributes' => $bodyattributes
'bodyattributes' => $bodyattributes,
'leftinstructions' => $leftinstructions,
];
echo $OUTPUT->render_from_template('theme_boost/login', $templatecontext);
+3 -2
View File
@@ -58,8 +58,9 @@ function theme_boost_get_extra_scss($theme) {
// Sets the login background image.
$loginbackgroundimageurl = $theme->setting_file_url('loginbackgroundimage', 'loginbackgroundimage');
if (!empty($loginbackgroundimageurl)) {
$content .= 'body.pagelayout-login #page { ';
$content .= "background-image: url('$loginbackgroundimageurl'); background-size: cover;";
$content .= 'body.pagelayout-login #page .login-layout-left { ';
$content .= "background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), " .
"url('$loginbackgroundimageurl'); background-size: cover;";
$content .= ' }';
}
+143 -63
View File
@@ -1,84 +1,164 @@
$loginbackground-gradient-from: $gray-100 !default;
$loginbackground-gradient-to: $gray-300 !default;
$logincontainer-bg: $white !default;
$logincontainer-padding: 3rem !default;
$logincontainer-shadow: $box-shadow !default;
$logindivider-margin-top: 1.5rem !default;
$logindivider-margin-bottom: 1.5rem !default;
$logindivider-border: $border-color !default;
$login-identity-provider-btn-border: $border-color !default;
$login-layout-left-bg: $primary !default;
$login-layout-panel-padding: 3rem !default;
$login-layout-content-width: 576px !default;
$login-layout-copy-width: 360px !default;
$login-input-bg: $gray-100 !default;
.pagelayout-login #region-main {
border: 0;
background-color: inherit;
}
.pagelayout-login {
#region-main,
#region-main-box {
border: 0;
background-color: transparent;
}
.pagelayout-login #page {
background: $loginbackground-gradient-from;
@include gradient-x($loginbackground-gradient-from, $loginbackground-gradient-to, 0%, 100%);
div[role="main"] {
height: 100%;
#page {
margin: 0;
min-height: 100vh;
background-color: $white;
}
}
.login-wrapper {
.login-layout-left {
background-color: $login-layout-left-bg;
color: color-contrast($login-layout-left-bg);
position: sticky;
top: 0;
align-self: flex-start;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: $login-layout-panel-padding;
}
.login-layout-left-content {
max-width: $login-layout-copy-width;
text-align: center;
}
.login-layout-stats {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
justify-items: center;
}
.login-layout-stat {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.login-layout-stat-value {
font-size: $h5-font-size;
line-height: 1;
}
.login-layout-right {
min-height: 100vh;
padding: $login-layout-panel-padding;
display: flex;
justify-content: center;
}
.login-layout-right-content {
width: 100%;
max-width: $login-layout-content-width;
margin: auto 0;
}
.login-container {
background-color: $logincontainer-bg;
padding: $logincontainer-padding;
box-shadow: $logincontainer-shadow;
margin-bottom: 2rem;
@include border-radius();
.login-languagemenu {
.login-form {
.form-control {
background-color: $login-input-bg;
box-shadow: none;
&:hover {
background-color: $login-input-bg;
}
&:focus {
background-color: $login-input-bg;
border-color: $input-focus-border-color;
box-shadow: $input-focus-box-shadow;
}
}
.toggle-sensitive-wrapper .toggle-sensitive-btn {
--bs-btn-bg: #{$login-input-bg};
--bs-btn-border-color: #{$input-border-color};
--bs-btn-hover-bg: #{$login-input-bg};
--bs-btn-hover-border-color: #{$input-border-color};
--bs-btn-active-bg: #{$login-input-bg};
--bs-btn-active-border-color: #{$input-border-color};
border-inline-start: none;
color: $gray-700;
&:focus,
&:focus-visible {
background-color: $login-input-bg;
border-color: $input-focus-border-color;
box-shadow: $input-focus-box-shadow;
}
}
}
.login-separator {
display: flex;
justify-content: flex-start;
align-items: center;
gap: 0.75rem;
color: $gray-600;
font-size: $font-size-sm;
text-transform: uppercase;
letter-spacing: 0.08em;
&::before,
&::after {
content: "";
flex: 1;
border-top: $border-width solid $border-color;
}
}
.login-identityprovider-btn {
width: 100%;
background-color: $white;
border-color: $gray-400;
color: $gray-600;
&:hover,
&:focus {
background-color: $gray-100;
border-color: $gray-500;
}
}
.login-cookiesnotice {
.btn-link {
font-size: $font-size-sm;
color: $gray-600;
&:hover,
&:focus {
color: $gray-700;
}
}
}
.login-languagemenu {
.dropdown-menu {
max-height: 300px;
overflow-y: auto;
}
}
.login-logo {
display: flex;
justify-content: center;
margin-bottom: 1rem;
}
.login-divider {
margin-top: $logindivider-margin-top;
margin-bottom: $logindivider-margin-bottom;
border-top: $border-width solid $logindivider-border;
}
h1.login-heading {
font-size: $h2-font-size;
}
h2.login-heading {
font-size: $h4-font-size;
}
.login-identityproviders {
.login-identityprovider-btn {
border: $border-width solid $login-identity-provider-btn-border;
}
}
.divider {
width: $border-width;
background-color: $gray-300;
height: $font-size-base * 2;
}
.action-menu-trigger {
a {
margin: 0.5rem 0;
}
}
}
@include media-breakpoint-up(md) {
.login-container {
width: 500px !important; /* stylelint-disable-line declaration-no-important */
@include media-breakpoint-down(lg) {
.login-layout-right {
padding: 1.5rem 1rem;
}
.login-layout-right-content {
max-width: 100%;
margin: 0;
}
}
+111 -48
View File
@@ -35550,72 +35550,135 @@ textarea[data-auto-rows] {
opacity: 1;
}
.pagelayout-login #region-main {
.pagelayout-login #region-main,
.pagelayout-login #region-main-box {
border: 0;
background-color: inherit;
background-color: transparent;
}
.pagelayout-login #page {
background: #f8f9fa;
background-image: linear-gradient(to right, #f8f9fa 0%, #dee2e6 100%);
}
.pagelayout-login #page div[role=main] {
height: 100%;
margin: 0;
min-height: 100vh;
background-color: #ffffff;
}
.login-wrapper {
.login-layout-left {
background-color: #0f6cbf;
color: #ffffff;
position: sticky;
top: 0;
align-self: flex-start;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: 3rem;
}
.login-container {
background-color: #ffffff;
padding: 3rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
margin-bottom: 2rem;
border-radius: 0.5rem;
.login-layout-left-content {
max-width: 360px;
text-align: center;
}
.login-container .login-languagemenu {
.login-layout-stats {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
justify-items: center;
}
.login-layout-stat {
display: flex;
justify-content: flex-start;
flex-direction: column;
gap: 0.25rem;
}
.login-layout-stat-value {
font-size: 1.25rem;
line-height: 1;
}
.login-layout-right {
min-height: 100vh;
padding: 3rem;
display: flex;
justify-content: center;
}
.login-layout-right-content {
width: 100%;
max-width: 576px;
margin: auto 0;
}
.login-container .login-form .form-control {
background-color: #f8f9fa;
box-shadow: none;
}
.login-container .login-form .form-control:hover {
background-color: #f8f9fa;
}
.login-container .login-form .form-control:focus {
background-color: #f8f9fa;
border-color: #87b6df;
box-shadow: 0 0 0 0.25rem rgba(15, 108, 191, 0.75);
}
.login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn {
--bs-btn-bg: #f8f9fa;
--bs-btn-border-color: var(--bs-gray-500);
--bs-btn-hover-bg: #f8f9fa;
--bs-btn-hover-border-color: var(--bs-gray-500);
--bs-btn-active-bg: #f8f9fa;
--bs-btn-active-border-color: var(--bs-gray-500);
border-inline-start: none;
color: #495057;
}
.login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn:focus, .login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn:focus-visible {
background-color: #f8f9fa;
border-color: #87b6df;
box-shadow: 0 0 0 0.25rem rgba(15, 108, 191, 0.75);
}
.login-container .login-separator {
display: flex;
align-items: center;
gap: 0.75rem;
color: #6a737b;
font-size: 0.875rem;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.login-container .login-separator::before, .login-container .login-separator::after {
content: "";
flex: 1;
border-top: 1px solid #dee2e6;
}
.login-container .login-identityprovider-btn {
width: 100%;
background-color: #ffffff;
border-color: #ced4da;
color: #6a737b;
}
.login-container .login-identityprovider-btn:hover, .login-container .login-identityprovider-btn:focus {
background-color: #f8f9fa;
border-color: #8f959e;
}
.login-container .login-cookiesnotice .btn-link {
font-size: 0.875rem;
color: #6a737b;
}
.login-container .login-cookiesnotice .btn-link:hover, .login-container .login-cookiesnotice .btn-link:focus {
color: #495057;
}
.login-container .login-languagemenu .dropdown-menu {
max-height: 300px;
overflow-y: auto;
}
.login-container .login-logo {
display: flex;
justify-content: center;
margin-bottom: 1rem;
}
.login-container .login-divider {
margin-top: 1.5rem;
margin-bottom: 1.5rem;
border-top: 1px solid #dee2e6;
}
.login-container h1.login-heading, .login-container .login-heading.h1 {
font-size: 2rem;
}
.login-container h2.login-heading, .login-container .login-heading.h2 {
font-size: 1.5rem;
}
.login-container .login-identityproviders .login-identityprovider-btn {
border: 1px solid #dee2e6;
}
.login-container .divider {
width: 1px;
background-color: #dee2e6;
height: 2rem;
}
.login-container .action-menu-trigger a {
margin: 0.5rem 0;
}
@media (min-width: 768px) {
.login-container {
width: 500px !important; /* stylelint-disable-line declaration-no-important */
@media (max-width: 991.98px) {
.login-layout-right {
padding: 1.5rem 1rem;
}
.login-layout-right-content {
max-width: 100%;
margin: 0;
}
}
/* modules.less */
@@ -0,0 +1,48 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core/login_layout
Split-screen layout for login-flow pages (login, MFA, etc.).
Provides a two-column structure: a decorative left panel (hidden on mobile)
and a right panel that receives the page's main content. The left panel
content is loaded from the core/login_panel partial, which themes can
override to customise the welcome copy and branding.
Context variables required for this template:
* output - The core renderer output object (provides main_content).
Example context (json):
{
"output": {
"main_content": "<h1>Login form goes here</h1>"
}
}
}}
<div id="page-content" class="min-vh-100 row g-0">
<aside class="login-layout-left col-lg-6 d-none d-lg-flex" aria-hidden="true">
{{> core/login_panel }}
</aside>
<div id="region-main" class="login-layout-right col-12 col-lg-6">
<div id="region-main-box" class="login-layout-right-content">
<div class="login-container">
{{{ output.main_content }}}
</div>
</div>
</div>
</div>
@@ -0,0 +1,49 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core/login_panel
Default content for the left panel of the split-screen login layout.
Example context (json):
{
"leftinstructions": "<p>Your learning journey starts here. Access courses, connect with peers, and achieve your goals.</p>"
}
}}
<div class="login-layout-left-content">
<h1 class="h2 mb-3">{{#str}}loginwelcometitle{{/str}}</h1>
<div class="mx-auto mb-4 text-start">
{{#leftinstructions}}
{{{leftinstructions}}}
{{/leftinstructions}}
</div>
<p class="mx-auto mb-4">{{#str}}loginpaneltagline{{/str}}</p>
<div class="login-layout-stats" role="presentation">
<div class="login-layout-stat">
<strong class="login-layout-stat-value">{{#str}}loginstatusers_value{{/str}}</strong>
<span>{{#str}}loginstatusers{{/str}}</span>
</div>
<div class="login-layout-stat">
<strong class="login-layout-stat-value">{{#str}}loginstatsites_value{{/str}}</strong>
<span>{{#str}}loginstatsites{{/str}}</span>
</div>
<div class="login-layout-stat">
<strong class="login-layout-stat-value">{{#str}}loginstatcountries_value{{/str}}</strong>
<span>{{#str}}loginstatcountries{{/str}}</span>
</div>
</div>
</div>
@@ -0,0 +1,253 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core/loginform
Moodle template for the login page.
Context variables required for this template:
* autofocusform: Auto focus on form ?,
* canloginasguest - Is guest login allowed?,
* canloginbyemail - Is login by email allowed?,
* cansignup - Signup allowed?,
* showloginform - Hide the standard login form if it not necessary (only OAuth2 for example)
* error - Any errors in the form?,
* errortitle - Optional bold heading shown above the error message (credential failures only),
* hasauthinstructions - Flag, set to true when auth_instructions is configured,
* info - Info notification to display,
* forgotpasswordurl - Forgot password url,
* hasidentityproviders - Flag, set to true to hide identity providers,
* identityproviders - List of identity providers,
* instructions - Instructions,
* loginurl - Login url,
* signupurl - Signup url,
* logourl - Flag, logo url,
* sitename - Name of site.,
* logintoken - Random token to protect login request.,
* maintenance - Maintenance message
Example context (json):
{
"autofocusform": false,
"canloginasguest": "1",
"canloginbyemail": false,
"cansignup": true,
"showloginform": true,
"error": "",
"errortitle": "",
"hasauthinstructions": false,
"info": "",
"forgotpasswordurl": "http://localhost/stable_master/login/forgot_password.php",
"hasidentityproviders": false,
"identityproviders": [],
"instructions": "For full access to this site, you first need to create an account.",
"loginurl": "http://localhost/stable_master/login/index.php",
"signupurl": "http://localhost/stable_master/login/signup.php",
"logourl": false,
"sitename": "Beer & Chips",
"logintoken": "randomstring",
"maintenance": "For full access to this site, you need to login in as an admin.",
"languagemenu": "Choose language",
"togglepassword": true,
"smallscreensonly": true
}
}}
<div class="loginform">
{{#logourl}}
<div id="loginlogo" class="d-flex justify-content-center mb-4">
<img id="logoimage" src="{{logourl}}" class="img-fluid" alt="{{sitename}}"/>
</div>
{{/logourl}}
<h1 class="h2">{{#str}}loginwelcomeback{{/str}}</h1>
<p class="text-muted mb-4">{{#str}} loginto, core, {{sitename}} {{/str}}</p>
{{#maintenance}}
<div class="alert alert-danger login-maintenance">
{{{maintenance}}}
</div>
{{/maintenance}}
{{#error}}
<div class="alert alert-danger" id="loginerrormessage" role="alert">
{{#errortitle}}<strong class="d-block mb-1">{{errortitle}}</strong>{{/errortitle}}
{{error}}
</div>
{{/error}}
{{#info}}
<div class="alert alert-info" id="logininfomessage" role="status">{{info}}</div>
{{/info}}
{{#showloginform}}
<form class="login-form" action="{{loginurl}}" method="post" id="login">
<input id="anchor" type="hidden" name="anchor" value="">
<script>document.getElementById('anchor').value = location.hash;</script>
<input type="hidden" name="logintoken" value="{{logintoken}}">
<div class="login-form-username mb-3">
<label for="username" class="form-label">
{{^canloginbyemail}}
{{#str}} username {{/str}}
{{/canloginbyemail}}
{{#canloginbyemail}}
{{#str}} usernameemail {{/str}}
{{/canloginbyemail}}
</label>
<input type="text" name="username" id="username" {{!
!}}class="form-control" {{!
!}}value="{{username}}" {{!
!}}placeholder="{{^canloginbyemail}}{{#str}}enterusername{{/str}}{{/canloginbyemail}}{{!
!}}{{#canloginbyemail}}{{#str}}loginenterusernameoremail{{/str}}{{/canloginbyemail}}" {{!
!}}autocomplete="username">
</div>
<div class="login-form-password mb-3">
<label for="password" class="form-label">{{#str}} password {{/str}}</label>
<input type="password" name="password" id="password" value="" {{!
!}}class="form-control" {{!
!}}placeholder="{{#str}}loginenterpassword{{/str}}" {{!
!}}autocomplete="current-password">
</div>
{{#recaptcha}}
<div class="login-form-recaptcha mb-3">
{{{recaptcha}}}
</div>
{{/recaptcha}}
<div class="text-end mb-3">
<a href="{{forgotpasswordurl}}">{{#str}}loginforgotpassword{{/str}}</a>
</div>
<div class="login-form-submit mb-3">
<button class="btn btn-primary w-100" type="submit" id="loginbtn">{{#str}}login{{/str}}</button>
</div>
</form>
{{/showloginform}}
{{#hasauthinstructions}}
<div class="d-lg-none small mb-3">
{{{instructions}}}
</div>
{{/hasauthinstructions}}
{{^hasauthinstructions}}
{{#cansignup}}
<div class="text-center small mb-3">
{{#instructions}}
<span class="text-muted me-1">{{{instructions}}}</span>
{{/instructions}}
<a href="{{signupurl}}">{{#str}}loginstartsignup{{/str}}</a>
</div>
{{/cansignup}}
{{^cansignup}}
{{#instructions}}
<p class="small mb-3">{{{instructions}}}</p>
{{/instructions}}
{{/cansignup}}
{{/hasauthinstructions}}
{{#hasauthinstructions}}
{{#cansignup}}
<div class="text-center small mb-3">
<a href="{{signupurl}}">{{#str}}loginstartsignup{{/str}}</a>
</div>
{{/cansignup}}
{{/hasauthinstructions}}
{{#hasidentityproviders}}
<div class="login-separator my-5">{{#str}}loginseparatoror{{/str}}</div>
{{/hasidentityproviders}}
{{^hasidentityproviders}}
{{#canloginasguest}}
<div class="login-separator my-5">{{#str}}loginseparatoror{{/str}}</div>
{{/canloginasguest}}
{{/hasidentityproviders}}
{{#hasidentityproviders}}
<div class="login-identityproviders">
{{#identityproviders}}
<a class="btn login-identityprovider-btn btn-outline-secondary mb-3" href="{{url}}">
{{#iconurl}}
<img src="{{iconurl}}" alt="" width="24" height="24"/>
{{/iconurl}}
{{#str}}loginwith{{/str}} {{name}}
</a>
{{/identityproviders}}
</div>
{{/hasidentityproviders}}
{{#canloginasguest}}
<form action="{{loginurl}}" method="post" id="guestlogin" class="mb-4">
<input type="hidden" name="logintoken" value="{{logintoken}}">
<input type="hidden" name="username" value="guest" />
<input type="hidden" name="password" value="guest" />
<button class="btn btn-outline-secondary login-identityprovider-btn" type="submit" id="loginguestbtn"><i class="fa fa-user me-2" aria-hidden="true"></i>{{#str}}loginasguest{{/str}}</button>
</form>
{{/canloginasguest}}
{{#languagemenu}}
<div class="login-languagemenu d-flex justify-content-center my-5">
{{>core/action_menu}}
</div>
{{/languagemenu}}
<div class="login-cookiesnotice text-center">
<button type="button" class="btn btn-link p-0" {{!
}} data-modal="alert"{{!
}} data-modal-title-str='["cookiesenabled", "core"]' {{!
}} data-modal-content-str='["cookiesenabled_help_html", "core"]'{{!
}}>{{#str}}cookiesnotice{{/str}}</button>
</div>
</div>
{{#js}}
{{^error}}
{{#autofocusform}}
require(['core_form/events'], function(FormEvent) {
function autoFocus() {
const userNameField = document.getElementById('username');
const passwordField = document.getElementById('password');
if (userNameField && userNameField.value.length == 0) {
userNameField.focus();
} else if (passwordField) {
passwordField.focus();
}
}
autoFocus();
window.addEventListener(FormEvent.eventTypes.fieldStructureChanged, autoFocus);
});
{{/autofocusform}}
{{/error}}
require(['core/pending'], function(Pending) {
const errorMessageDiv = document.getElementById('loginerrormessage');
const infoMessageDiv = document.getElementById('logininfomessage');
const errorMessage = errorMessageDiv?.textContent.trim();
const infoMessage = infoMessageDiv?.textContent.trim();
if (errorMessage || infoMessage) {
const pendingJS = new Pending('login-move-focus');
const usernameField = document.getElementById('username');
setTimeout(function() {
if (errorMessage && usernameField) {
usernameField.focus();
}
if (errorMessage) {
errorMessageDiv.innerHTML += "&nbsp;";
}
if (infoMessage) {
infoMessageDiv.innerHTML += "&nbsp;";
}
pendingJS.resolve();
}, 500);
}
});
{{#togglepassword}}
require(['core/togglesensitive'], function(ToggleSensitive) {
ToggleSensitive.init("password", {{smallscreensonly}});
});
{{/togglepassword}}
require(['core_form/submit'], function(Submit) {
Submit.init("loginbtn");
{{#canloginasguest}}
Submit.init("loginguestbtn");
{{/canloginasguest}}
});
{{/js}}
+2 -12
View File
@@ -38,18 +38,8 @@
{{{ output.standard_top_of_body_html }}}
<div id="page" class="container-fluid pt-5 mt-0">
<div id="page-content" class="row">
<div id="region-main-box" class="col-12">
<div id="region-main" class="col-12 h-100">
<div class="login-wrapper">
<div class="login-container">
{{{ output.main_content }}}
</div>
</div>
</div>
</div>
</div>
<div id="page" class="mt-0">
{{> core/login_layout }}
</div>
{{> theme_boost/footer }}
</div>
+3 -2
View File
@@ -109,8 +109,9 @@ function theme_classic_get_extra_scss($theme) {
// Sets the login background image.
$loginbackgroundimageurl = $theme->setting_file_url('loginbackgroundimage', 'loginbackgroundimage');
if (!empty($loginbackgroundimageurl)) {
$content .= 'body.pagelayout-login #page { ';
$content .= "background-image: url('$loginbackgroundimageurl'); background-size: cover;";
$content .= 'body.pagelayout-login #page .login-layout-left { ';
$content .= "background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), " .
"url('$loginbackgroundimageurl'); background-size: cover;";
$content .= ' }';
}
+111 -48
View File
@@ -35550,72 +35550,135 @@ textarea[data-auto-rows] {
opacity: 1;
}
.pagelayout-login #region-main {
.pagelayout-login #region-main,
.pagelayout-login #region-main-box {
border: 0;
background-color: inherit;
background-color: transparent;
}
.pagelayout-login #page {
background: #f8f9fa;
background-image: linear-gradient(to right, #f8f9fa 0%, #dee2e6 100%);
}
.pagelayout-login #page div[role=main] {
height: 100%;
margin: 0;
min-height: 100vh;
background-color: #fff;
}
.login-wrapper {
.login-layout-left {
background-color: #0f6cbf;
color: #fff;
position: sticky;
top: 0;
align-self: flex-start;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: 3rem;
}
.login-container {
background-color: #fff;
padding: 3rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
margin-bottom: 2rem;
border-radius: 0.375rem;
.login-layout-left-content {
max-width: 360px;
text-align: center;
}
.login-container .login-languagemenu {
.login-layout-stats {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
justify-items: center;
}
.login-layout-stat {
display: flex;
justify-content: flex-start;
flex-direction: column;
gap: 0.25rem;
}
.login-layout-stat-value {
font-size: 1.25rem;
line-height: 1;
}
.login-layout-right {
min-height: 100vh;
padding: 3rem;
display: flex;
justify-content: center;
}
.login-layout-right-content {
width: 100%;
max-width: 576px;
margin: auto 0;
}
.login-container .login-form .form-control {
background-color: #f8f9fa;
box-shadow: none;
}
.login-container .login-form .form-control:hover {
background-color: #f8f9fa;
}
.login-container .login-form .form-control:focus {
background-color: #f8f9fa;
border-color: #87b6df;
box-shadow: 0 0 0 0.25rem rgba(15, 108, 191, 0.75);
}
.login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn {
--bs-btn-bg: #f8f9fa;
--bs-btn-border-color: #8f959e;
--bs-btn-hover-bg: #f8f9fa;
--bs-btn-hover-border-color: #8f959e;
--bs-btn-active-bg: #f8f9fa;
--bs-btn-active-border-color: #8f959e;
border-inline-start: none;
color: #495057;
}
.login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn:focus, .login-container .login-form .toggle-sensitive-wrapper .toggle-sensitive-btn:focus-visible {
background-color: #f8f9fa;
border-color: #87b6df;
box-shadow: 0 0 0 0.25rem rgba(15, 108, 191, 0.75);
}
.login-container .login-separator {
display: flex;
align-items: center;
gap: 0.75rem;
color: #6a737b;
font-size: 0.875rem;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.login-container .login-separator::before, .login-container .login-separator::after {
content: "";
flex: 1;
border-top: 1px solid #dee2e6;
}
.login-container .login-identityprovider-btn {
width: 100%;
background-color: #fff;
border-color: #ced4da;
color: #6a737b;
}
.login-container .login-identityprovider-btn:hover, .login-container .login-identityprovider-btn:focus {
background-color: #f8f9fa;
border-color: #8f959e;
}
.login-container .login-cookiesnotice .btn-link {
font-size: 0.875rem;
color: #6a737b;
}
.login-container .login-cookiesnotice .btn-link:hover, .login-container .login-cookiesnotice .btn-link:focus {
color: #495057;
}
.login-container .login-languagemenu .dropdown-menu {
max-height: 300px;
overflow-y: auto;
}
.login-container .login-logo {
display: flex;
justify-content: center;
margin-bottom: 1rem;
}
.login-container .login-divider {
margin-top: 1.5rem;
margin-bottom: 1.5rem;
border-top: 1px solid #dee2e6;
}
.login-container h1.login-heading, .login-container .login-heading.h1 {
font-size: 2rem;
}
.login-container h2.login-heading, .login-container .login-heading.h2 {
font-size: 1.5rem;
}
.login-container .login-identityproviders .login-identityprovider-btn {
border: 1px solid #dee2e6;
}
.login-container .divider {
width: 1px;
background-color: #dee2e6;
height: 2rem;
}
.login-container .action-menu-trigger a {
margin: 0.5rem 0;
}
@media (min-width: 768px) {
.login-container {
width: 500px !important; /* stylelint-disable-line declaration-no-important */
@media (max-width: 991.98px) {
.login-layout-right {
padding: 1.5rem 1rem;
}
.login-layout-right-content {
max-width: 100%;
margin: 0;
}
}
/* modules.less */
@@ -32,7 +32,7 @@ Feature: Custom profile fields should be visible and editable by those with the
@javascript
Scenario: Visible custom profile fields can be part of the sign up form for anonymous users.
Given I am on homepage
When I click on "Create new account" "link"
When I click on "Sign up" "link"
And I expand all fieldsets
Then I should not see "notvisible_field"
And I should see "uservisible_field"
@@ -44,7 +44,7 @@ Feature: Custom profile fields should be visible and editable by those with the
Given I log in as "guest"
And I am on site homepage
And I follow "Log in"
When I click on "Create new account" "link"
When I click on "Sign up" "link"
And I expand all fieldsets
Then I should not see "notvisible_field"
And I should see "uservisible_field"
+1 -1
View File
@@ -10,7 +10,7 @@ Feature: Both first name and last name are always available for every user
| registerauth | email |
| passwordpolicy | 0 |
And I am on homepage
And I click on "Create new account" "link"
And I click on "Sign up" "link"
When I set the following fields to these values:
| Username | mrwhitespace |
| Password | Gue$$m3ifY0uC&n |