diff --git a/admin/tool/policy/tests/behat/consent.feature b/admin/tool/policy/tests/behat/consent.feature index 88563462dadde..1548b3382d60a 100644 --- a/admin/tool/policy/tests/behat/consent.feature +++ b/admin/tool/policy/tests/behat/consent.feature @@ -11,7 +11,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | sitepolicyhandler | tool_policy | And I am on site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "link" Then I should not see "I understand and agree" And I set the following fields to these values: | Username | user1 | @@ -45,7 +45,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | P1 | This privacy policy | | full text2 | short text2 | draft | And I am on site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "link" Then I should not see "I understand and agree" And I set the following fields to these values: | Username | user1 | @@ -80,7 +80,7 @@ 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 site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "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 guests policy | 0 | | full text4 | short text4 | active | guest | And I am on site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "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" @@ -188,7 +188,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | This site policy | | full text2 | short text2 | active | And I am on site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "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" @@ -239,7 +239,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 | And I am on site homepage And I follow "Log in" - And I press "Create new account" + And I click on "Create new account" "link" And I should see "This site policy" And I press "Next" And I should see "This privacy policy" @@ -494,7 +494,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 site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "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" @@ -526,7 +526,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@address.invalid" And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "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" @@ -628,7 +628,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign And I press "Log in as a guest" # Now sign up And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "link" Then I should see "This site policy" And I should see "short text2" And I should see "full text2" @@ -677,7 +677,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | Terms of Service | We teach, you learn | Here goes content. | 1 | And I am on site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "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" @@ -841,7 +841,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign | Terms of Service | We teach, you learn | Here goes content. | 1 | guest | And I am on site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "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" diff --git a/admin/tool/policy/tests/behat/optional.feature b/admin/tool/policy/tests/behat/optional.feature index 77e5f0165a563..441519e07d2cf 100644 --- a/admin/tool/policy/tests/behat/optional.feature +++ b/admin/tool/policy/tests/behat/optional.feature @@ -65,7 +65,7 @@ Feature: Optional policies | OwnPageOptional1 | full text5 | short text5 | 1 | 1 | And I am on site homepage And I follow "Log in" - And I press "Create new account" + And I click on "Create new account" "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" diff --git a/auth/classes/output/login.php b/auth/classes/output/login.php index c98048b932747..1ee9f8fa66c4c 100644 --- a/auth/classes/output/login.php +++ b/auth/classes/output/login.php @@ -70,6 +70,8 @@ class login implements renderable, templatable { public $signupurl; /** @var string The user name to pre-fill the form with. */ public $username; + /** @var string The language selector menu. */ + public $languagemenu; /** @var string The csrf token to limit login to requests that come from the login form. */ public $logintoken; /** @var string Maintenance message, if Maintenance is enabled. */ @@ -82,10 +84,13 @@ class login implements renderable, templatable { * @param string $username The username to display. */ public function __construct(array $authsequence, $username = '') { - global $CFG; + global $CFG, $OUTPUT, $PAGE; $this->username = $username; + $languagedata = new \core\output\language_menu($PAGE); + + $this->languagemenu = $languagedata->export_for_action_menu($OUTPUT); $this->canloginasguest = $CFG->guestloginbutton and !isguestuser(); $this->canloginbyemail = !empty($CFG->authloginviaemail); $this->cansignup = $CFG->registerauth == 'email' || !empty($CFG->registerauth); @@ -111,8 +116,12 @@ public function __construct(array $authsequence, $username = '') { $this->instructions = get_string('loginsteps', 'core', 'signup.php'); } - if ($CFG->maintenance_enabled == true && !empty($CFG->maintenance_message)) { - $this->maintenance = $CFG->maintenance_message; + if ($CFG->maintenance_enabled == true) { + if (!empty($CFG->maintenance_message)) { + $this->maintenance = $CFG->maintenance_message; + } else { + $this->maintenance = get_string('sitemaintenance', 'admin'); + } } // Identity providers. @@ -152,6 +161,7 @@ public function export_for_template(renderer_base $output) { $data->username = $this->username; $data->logintoken = $this->logintoken; $data->maintenance = format_text($this->maintenance, FORMAT_MOODLE); + $data->languagemenu = $this->languagemenu; return $data; } diff --git a/auth/email/tests/behat/signup.feature b/auth/email/tests/behat/signup.feature index 234006ca15556..19c241c357245 100644 --- a/auth/email/tests/behat/signup.feature +++ b/auth/email/tests/behat/signup.feature @@ -10,7 +10,7 @@ Feature: User must accept policy when logging in and signing up | passwordpolicy | 0 | And I am on site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "link" Then I should not see "I understand and agree" And I set the following fields to these values: | Username | user1 | @@ -40,7 +40,7 @@ Feature: User must accept policy when logging in and signing up | sitepolicy | https://moodle.org | And I am on site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "link" Then the field "I understand and agree" matches value "0" And I set the following fields to these values: | Username | user1 | @@ -74,7 +74,7 @@ Feature: User must accept policy when logging in and signing up | s1 | John | Doe | s1@example.com | And I am on site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "link" And I set the following fields to these values: | Username | s2 | | Password | test | diff --git a/auth/tests/behat/loginform.feature b/auth/tests/behat/loginform.feature new file mode 100644 index 0000000000000..394892ccddda3 --- /dev/null +++ b/auth/tests/behat/loginform.feature @@ -0,0 +1,104 @@ +@auth @core_auth @javascript +Feature: Test if the login form provides the correct feedback + In order to check if the login form provides correct feedback + As a user + I need to go on login page and see feedback on incorrect username or password. + + Background: + Given the following "users" exist: + | username | + | teacher1 | + + Scenario: Check invalid login message + Given I follow "Log in" + 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" + + Scenario: Test login language selector + Given I log in as "admin" + And I navigate to "Language > Language packs" in site administration + And I set the field "Available language packs" to "nl,es" + And I press "Install selected language pack(s)" + And I trigger cron + And I am on homepage + And I log out + And I follow "Log in" + And I open the action menu in "region-main" "region" + # The line below contains the unicode character U+200E before and after the brackets, please be very careful editing this line. + And I choose "Nederlands ‎(nl)‎" in the open action menu + Then I should see "Gebruikersnaam" + + @_file_upload + Scenario: Set logo for loginpage + Given I log in as "admin" + And I navigate to "Appearance > Logos" in site administration + And I upload "course/tests/fixtures/image.jpg" file to "Logo" filemanager + And I press "Save changes" + And I log out + And I follow "Log in" + Then "//img[@id='logoimage']" "xpath_element" should exist + + Scenario: Add a custom welcome message + Given the following config values are set as admin: + | auth_instructions | Lorem ipsum dolor sit amet | + And I follow "Log in" + Then I should see "Lorem ipsum dolor sit amet" + + Scenario: Show the maintenance mode message + Given the following config values are set as admin: + | maintenance_enabled | Disabled | + | maintenance_message | Back online tomorrow | + And I follow "Log in" + Then I should see "Back online tomorrow" + + Scenario: User self registration + Given the following config values are set as admin: + | registerauth | Email-based self-registration | + And I follow "Log in" + Then I should see "Create new account" + + Scenario: Set OAuth providers + Given I log in as "admin" + And I navigate to "Plugins > Authentication > Manage authentication" in site administration + And I click on "Enable" "link" in the "OAuth 2" "table_row" + And I navigate to "Server > OAuth 2 services" in site administration + And I press "Google" + And I set the field "Client ID" to "1234" + And I set the field "Client secret" to "1234" + And I press "Save changes" + And I press "Facebook" + And I set the field "Client ID" to "1234" + And I set the field "Client secret" to "1234" + And I press "Save changes" + And I press "Microsoft" + And I set the field "Client ID" to "1234" + And I set the field "Client secret" to "1234" + And I press "Save changes" + And I log out + And I follow "Log in" + Then I should see "Google" + And I should see "Facebook" + And I should see "Microsoft" + + Scenario: Test the login page auto focus feature + Given the following config values are set as admin: + | loginpageautofocus | Enabled | + And I follow "Log in" + Then the focused element is "Username" "field" + And I set the field "Username" to "admin" + And I set the field "Password" to "admin" + And I set the field "Remember username" to "1" + And I press "Log in" + And I log out + And I follow "Log in" + Then the focused element is "Password" "field" + + Scenario: Test the login page focus after error feature + Given I follow "Log in" + And I set the field "Username" to "admin" + And I set the field "Password" to "wrongpassword" + And I press "Log in" + And I press the tab key + Then the focused element is "Username" "field" diff --git a/auth/tests/behat/verifyageofconsent.feature b/auth/tests/behat/verifyageofconsent.feature index 8782f895cb7df..2dc80fd9127ac 100644 --- a/auth/tests/behat/verifyageofconsent.feature +++ b/auth/tests/behat/verifyageofconsent.feature @@ -13,24 +13,24 @@ Feature: Test the 'Digital age of consent verification' feature works. # Try to access the sign up page. Given I am on homepage When I click on "Log in" "link" in the ".logininfo" "css_element" - And I press "Create new account" + And I click on "Create new account" "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" And I press "Proceed" Then I should see "New account" - And I should see "Choose your username and password" + And I should see "Username" # Try to access the sign up page again. When I press "Cancel" - And I press "Create new account" + And I click on "Create new account" "link" Then I should see "New account" - And I should see "Choose your username and password" + 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 When I click on "Log in" "link" in the ".logininfo" "css_element" - And I press "Create new account" + And I click on "Create new account" "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" @@ -40,6 +40,6 @@ Feature: Test the 'Digital age of consent verification' feature works. # Try to access the sign up page again. When I click on "Back to the site home" "link" And I click on "Log in" "link" in the ".logininfo" "css_element" - And I press "Create new account" + And I click on "Create new account" "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:" diff --git a/lang/en/deprecated.txt b/lang/en/deprecated.txt index cb6a296e2e86c..d38721c0e5ba4 100644 --- a/lang/en/deprecated.txt +++ b/lang/en/deprecated.txt @@ -161,3 +161,5 @@ coursepage,core_admin invalidpersistenterror,core_competency mediapluginswf,core_admin mediapluginswfnote,core_admin +createuserandpass,core +supplyinfo,core diff --git a/lang/en/moodle.php b/lang/en/moodle.php index d57e02e276ede..d3913ab83624a 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -419,7 +419,6 @@ $string['createnewcourse'] = 'Create new course'; $string['createnewsubcategory'] = 'Create new subcategory'; $string['createsubcategoryof'] = 'Create subcategory of {$a}'; -$string['createuserandpass'] = 'Choose your username and password'; $string['createuser'] = 'Create user'; $string['createziparchive'] = 'Create zip archive'; $string['creatingblocks'] = 'Creating blocks'; @@ -2064,7 +2063,6 @@ $string['summary'] = 'Summary'; $string['summary_help'] = 'The idea of a summary is a short text to prepare students for the activities within the topic or week. The text is shown on the course page under the section name.'; $string['summaryof'] = 'Summary of {$a}'; -$string['supplyinfo'] = 'More details'; $string['suspended'] = 'Suspended'; $string['suspendedusers'] = 'Suspended users'; $string['switchdevicedefault'] = 'Switch to the standard theme'; @@ -2350,4 +2348,6 @@ $string['registrationno'] = 'No, I do not wish to receive any emails'; // Deprecated since Moodle 4.0. +$string['createuserandpass'] = 'Choose your username and password'; $string['descriptiona'] = 'Description: {$a}'; +$string['supplyinfo'] = 'More details'; diff --git a/lib/classes/navigation/output/primary.php b/lib/classes/navigation/output/primary.php index f8103a6c1841e..3f1b34a5f9e8c 100644 --- a/lib/classes/navigation/output/primary.php +++ b/lib/classes/navigation/output/primary.php @@ -58,9 +58,11 @@ public function export_for_template(?renderer_base $output = null): array { $menudata = (object) array_merge($this->get_primary_nav(), $this->get_custom_menu($output)); $moremenu = new \core\navigation\output\more_menu($menudata, 'navbar-nav', false); + $languagemenu = new \core\output\language_menu($this->page); + return [ 'moremenu' => $moremenu->export_for_template($output), - 'lang' => !isloggedin() || isguestuser() ? $this->get_lang_menu($output) : [], + 'lang' => !isloggedin() || isguestuser() ? $languagemenu->export_for_template($output) : [], 'user' => $this->get_user_menu($output), ]; } @@ -111,47 +113,6 @@ protected function get_custom_menu(renderer_base $output): array { return $nodes; } - /** - * Get a list of options for the lang picker. - * - * @param renderer_base $output - * @return array - */ - protected function get_lang_menu(renderer_base $output): array { - // Early return if a lang menu does not exists. - if (empty($output->lang_menu())) { - return []; - } - - $currentlang = current_language(); - $langs = get_string_manager()->get_list_of_translations(); - $nodes = []; - $activelanguage = ''; - - // Add the lang picker if needed. - foreach ($langs as $langtype => $langname) { - $isactive = $langtype == $currentlang; - $node = [ - 'title' => $langname, - 'text' => $langname, - 'link' => true, - 'isactive' => $isactive, - 'url' => $isactive ? new \moodle_url('#') : new \moodle_url($this->page->url, ['lang' => $langtype]), - ]; - - $nodes[] = $node; - - if ($isactive) { - $activelanguage = $langname; - } - } - - return [ - 'title' => $activelanguage, - 'items' => $nodes, - ]; - } - /** * Get/Generate the user menu. * @@ -229,7 +190,8 @@ public function get_user_menu(renderer_base $output): array { }, $info->navitems); // Include the language menu as a submenu within the user menu. - $langmenu = $this->get_lang_menu($output); + $languagemenu = new \core\output\language_menu($this->page); + $langmenu = $languagemenu->export_for_template($output); if (!empty($langmenu)) { $languageitems = $langmenu['items']; // If there are available languages, generate the data for the the language selector submenu. diff --git a/lib/classes/output/language_menu.php b/lib/classes/output/language_menu.php new file mode 100644 index 0000000000000..9f694fc31b14a --- /dev/null +++ b/lib/classes/output/language_menu.php @@ -0,0 +1,161 @@ +. + +/** + * Contains class \core\output\language_menu + * + * @package core + * @category output + * @copyright 2021 Adrian Greeve + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\output; + +/** + * Class for creating the language menu + * + * @package core + * @category output + * @copyright 2021 Adrian Greeve + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class language_menu implements \renderable, \templatable { + + /** @var moodle_page $page the moodle page that the languague menu belongs to */ + protected $page; + + /** @var string current language code */ + protected $currentlang; + + /** @var array localised list of installed translations */ + protected $langs; + + /** + * Language menu constructor. + * + * @param moodle_page $page the moodle page that the languague menu belongs to. + */ + public function __construct($page) { + $this->page = $page; + $this->currentlang = \current_language(); + $this->langs = \get_string_manager()->get_list_of_translations(); + } + + /** + * Determine if the language menu should be shown. + * + * @return bool true if the language menu should be shown. + */ + protected function show_language_menu(): bool { + global $CFG; + + if (empty($CFG->langmenu)) { + return false; + } + + if ($this->page->course != SITEID and !empty($this->page->course->lang)) { + // Do not show lang menu if language forced. + return false; + } + + if (count($this->langs) < 2) { + return false; + } + return true; + } + + /** + * Export the data. + * + * @param \renderer_base $output + * @return array with the title for the menu and an array of items. + */ + public function export_for_template(\renderer_base $output): array { + // Early return if a lang menu does not exists. + if (!$this->show_language_menu()) { + return []; + } + + $nodes = []; + $activelanguage = ''; + + // Add the lang picker if needed. + foreach ($this->langs as $langtype => $langname) { + $isactive = $langtype == $this->currentlang; + $node = [ + 'title' => $langname, + 'text' => $langname, + 'link' => true, + 'isactive' => $isactive, + 'url' => $isactive ? new \moodle_url('#') : new \moodle_url($this->page->url, ['lang' => $langtype]), + ]; + + $nodes[] = $node; + + if ($isactive) { + $activelanguage = $langname; + } + } + + return [ + 'title' => $activelanguage, + 'items' => $nodes, + ]; + } + + /** + * Export the data providing a structure for the core/action_menu template. + * + * @param \renderer_base $output + * @return \stdClass action_menu data export. + */ + public function export_for_action_menu(\renderer_base $output): \stdClass { + $languagedata = $this->export_for_template($output); + if (empty($languagedata)) { + return []; + } + $langmenu = new \action_menu(); + $menuname = \get_string('language'); + if (!empty($languagedata['title'])) { + $menuname = $languagedata['title']; + } + $langmenu->set_menu_trigger($menuname); + foreach ($languagedata['items'] as $node) { + $lang = new \action_menu_link_secondary($node['url'], null, $node['title'], + ['data-lang' => $node['url']->get_param('lang')]); + $langmenu->add($lang); + } + return $langmenu->export_for_template($output); + } + + /** + * Export the data providing a structure for the core/single_select template. + * + * @param \renderer_base $output + * @return \stdClass single_select data export. + */ + public function export_for_single_select(\renderer_base $output): \stdClass { + if (!$this->show_language_menu()) { + return ''; + } + $singleselect = new \single_select($this->page->url, 'lang', $this->langs, $this->currentlang, null); + $singleselect->label = get_accesshide(\get_string('language')); + $singleselect->class = 'langmenu'; + return $singleselect->export_for_template($output); + } + +} diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index 692eb4f62795c..0bb513bbbf4b2 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -1644,28 +1644,9 @@ public function get_generated_color_for_id($id) { * @return string The lang menu HTML or empty string */ public function lang_menu() { - global $CFG; - - if (empty($CFG->langmenu)) { - return ''; - } - - if ($this->page->course != SITEID and !empty($this->page->course->lang)) { - // do not show lang menu if language forced - return ''; - } - - $currlang = current_language(); - $langs = get_string_manager()->get_list_of_translations(); - - if (count($langs) < 2) { - return ''; - } - - $s = new single_select($this->page->url, 'lang', $langs, $currlang, null); - $s->label = get_accesshide(get_string('language')); - $s->class = 'langmenu'; - return $this->render($s); + $languagemenu = new \core\output\language_menu($this->page); + $data = $languagemenu->export_for_single_select($this); + return $this->render_from_template('core/single_select', $data); } /** diff --git a/lib/templates/auth_digital_minor_page.mustache b/lib/templates/auth_digital_minor_page.mustache index 7ee6759db36c6..44c018393c926 100644 --- a/lib/templates/auth_digital_minor_page.mustache +++ b/lib/templates/auth_digital_minor_page.mustache @@ -26,33 +26,15 @@ "homelink": "/" } }} -
-
-
-
-
-
- {{#logourl}} -

{{sitename}}

- {{/logourl}} - {{^logourl}} -

{{sitename}}

- {{/logourl}} -
-
-
-

{{#str}}considereddigitalminor{{/str}}

-
-
-

{{#str}}digitalminor_desc{{/str}}

-

{{{supportname}}}

-

{{{supportemail}}}

-
- -
-
-
-
+ +
+

{{#str}}considereddigitalminor{{/str}}

+
+
+

{{#str}}digitalminor_desc{{/str}}

+

{{{supportname}}}

+

{{{supportemail}}}

+
+ diff --git a/lib/templates/auth_verify_age_location_page.mustache b/lib/templates/auth_verify_age_location_page.mustache index a1659aad2b8a0..6e73f9cfcbbee 100644 --- a/lib/templates/auth_verify_age_location_page.mustache +++ b/lib/templates/auth_verify_age_location_page.mustache @@ -25,40 +25,23 @@ "formhtml": "(Form html would go here)" } }} -
-
-
-
-
-
- {{#logourl}} -

{{sitename}}

- {{/logourl}} - {{^logourl}} -

{{sitename}}

- {{/logourl}} -
-
- {{#error}} - - {{/error}} -
-

{{#str}}agelocationverification{{/str}}

-
-
- {{{formhtml}}} -
-
-
-

{{#str}}whyisthisrequired{{/str}}

-
-
-

{{#str}}explanationdigitalminor{{/str}}

-
-
-
+
+ {{#error}} + + {{/error}} +
+

{{#str}}agelocationverification{{/str}}

+
+
+ {{{formhtml}}} +
+
+
+

{{#str}}whyisthisrequired{{/str}}

+
+
+

{{#str}}explanationdigitalminor{{/str}}

diff --git a/lib/templates/loginform.mustache b/lib/templates/loginform.mustache index a02a573f923f6..1c969f5bd131c 100644 --- a/lib/templates/loginform.mustache +++ b/lib/templates/loginform.mustache @@ -91,175 +91,134 @@ "logourl": false, "sitename": "Beer & Chips", "logintoken": "randomstring", - "maintenance": "For full access to this site, you need to login in as an admin." + "maintenance": "For full access to this site, you need to login in as an admin.", + "languagemenu": "Choose language" } }} -
-
-
-
-
- {{#logourl}} -

- {{sitename}}: {{#str}} login {{/str}} - -

- {{/logourl}} - {{^logourl}} -

{{sitename}}

- {{/logourl}} -
- {{#cansignup}} - - {{/cansignup}} - - {{#error}} -
- {{error}} - -
- {{/error}} - -
-
-
- - - -
- - -
-
- - -
- {{#rememberusername}} -
- - -
- {{/rememberusername}} - - -
-
- -
- - -
- {{#str}} cookiesenabled {{/str}} - {{{cookieshelpiconformatted}}} -
- {{#canloginasguest}} -
-

{{#str}}someallowguest{{/str}}

-
- - - - -
-
- {{/canloginasguest}} - - {{#hasidentityproviders}} -

{{#str}} potentialidps, auth {{/str}}

-
- {{#identityproviders}} - - {{/identityproviders}} -
- {{/hasidentityproviders}} +
+ {{#languagemenu}} + + {{/languagemenu}} + {{#logourl}} + + {{/logourl}} + {{^logourl}} +

{{sitename}} {{#str}} login {{/str}}

+ {{/logourl}} + {{#maintenance}} + + {{/maintenance}} + {{#error}} + {{error}} + + {{/error}} + {{#cansignup}} + {{#str}} tocreatenewaccount {{/str}} + {{/cansignup}} +
-
-
-
- - -{{#hasinstructions}} -
-
-
-
-
-

{{#str}}firsttime{{/str}}

+ -
- {{{instructions}}} - {{#cansignup}} - - - - {{/cansignup}} + + {{#hasidentityproviders}} + + + {{/hasidentityproviders}} + {{#hasinstructions}} + + + {{/hasinstructions}} + {{#cansignup}} + + {{/cansignup}} + {{#canloginasguest}} + + +
+ + + + +
+ {{/canloginasguest}} + +
-
-
-{{/hasinstructions}} -{{#maintenance}} -
-
-
-
-
-

{{#str}}sitemaintenance, core_admin{{/str}}

-
-
- {{{maintenance}}} -
-
-
-
-
-{{/maintenance}} {{#js}} - {{#error}} - require(['jquery'], function($) { - $('#loginerrormessage').focus(); - }); - {{/error}} {{^error}} {{#autofocusform}} - require(['jquery'], function($) { - if ($('#username').val()) { - $('#password').focus(); - } else { - $('#username').focus(); - } - }); + var userNameField = document.getElementById('username'); + if (userNameField.value.length == 0) { + userNameField.focus(); + } else { + document.getElementById('password').focus(); + } {{/autofocusform}} {{/error}} + {{#error}} + document.getElementById('loginerrormessage').focus(); + {{/error}} {{/js}} diff --git a/lib/templates/signup_form_layout.mustache b/lib/templates/signup_form_layout.mustache index 13ec49558007a..c8e4d9842193a 100644 --- a/lib/templates/signup_form_layout.mustache +++ b/lib/templates/signup_form_layout.mustache @@ -8,26 +8,7 @@ "formhtml": "

(Form html would go here)

" } }} -
-
-
-
-
-
- {{#logourl}} -

{{sitename}}

- {{/logourl}} - {{^logourl}} -

{{sitename}}

- {{/logourl}} -
-
-
-

{{#str}}newaccount{{/str}}

-
- {{{formhtml}}} -
-
-
-
+
+

{{#str}} newaccount {{/str}}

+ {{{formhtml}}}
diff --git a/lib/tests/navigation/output/primary_test.php b/lib/tests/navigation/output/primary_test.php index 2c4031b3078e6..b6aac00b7ab32 100644 --- a/lib/tests/navigation/output/primary_test.php +++ b/lib/tests/navigation/output/primary_test.php @@ -145,128 +145,6 @@ public function test_primary_export_provider(): array { ]; } - /** - * Test the get_lang_menu - * - * @dataProvider get_lang_menu_provider - * @param bool $withadditionallangs - * @param string $language - * @param array $expected - */ - public function test_get_lang_menu(bool $withadditionallangs, string $language, array $expected) { - global $CFG, $PAGE; - - // Mimic multiple langs installed. To trigger responses 'get_list_of_translations'. - // Note: The text/title of the nodes generated will be 'English(fr), English(de)' but we don't care about this. - // We are testing whether the nodes gets generated when the lang menu is available. - if ($withadditionallangs) { - mkdir("$CFG->dataroot/lang/de", 0777, true); - mkdir("$CFG->dataroot/lang/fr", 0777, true); - // Ensure the new langs are picked up and not taken from the cache. - $stringmanager = get_string_manager(); - $stringmanager->reset_caches(true); - } - - force_current_language($language); - - $output = new primary($PAGE); - $method = new ReflectionMethod('core\navigation\output\primary', 'get_lang_menu'); - $method->setAccessible(true); - $renderer = $PAGE->get_renderer('core'); - - $response = $method->invoke($output, $renderer); - - if ($withadditionallangs) { // If there are multiple languages installed. - // Assert that the title of the language menu matches the expected one. - $this->assertEquals($expected['title'], $response['title']); - // Assert that the number of language menu items matches the number of the expected items. - $this->assertEquals(count($expected['items']), count($response['items'])); - foreach ($expected['items'] as $expecteditem) { - // We need to manually generate the url key and its value in the expected item array as this cannot - // be done in the data provider due to the change of the state of $PAGE. - $expecteditem['url'] = $expecteditem['isactive'] ? new \moodle_url('#') : - new \moodle_url($PAGE->url, ['lang' => $expecteditem['lang']]); - // The lang value is only used to generate the url, so this key can be removed. - unset($expecteditem['lang']); - - // Assert that the given expected item exists in the returned items. - $this->assertTrue(in_array($expecteditem, $response['items'])); - } - } else { // No multiple languages. - $this->assertEquals($expected, $response); - } - } - - /** - * Provider for test_get_lang_menu - * - * @return array - */ - public function get_lang_menu_provider(): array { - return [ - 'Lang menu with only the current language' => [ - false, 'en', [] - ], - 'Lang menu with only multiple languages installed' => [ - true, 'en', [ - 'title' => 'English ‎(en)‎', - 'items' => [ - [ - 'title' => 'English ‎(en)‎', - 'text' => 'English ‎(en)‎', - 'link' => true, - 'isactive' => true, - 'lang' => 'en' - ], - [ - 'title' => 'English ‎(de)‎', - 'text' => 'English ‎(de)‎', - 'link' => true, - 'isactive' => false, - 'lang' => 'de' - ], - - [ - 'title' => 'English ‎(fr)‎', - 'text' => 'English ‎(fr)‎', - 'link' => true, - 'isactive' => false, - 'lang' => 'fr' - ], - ], - ], - ], - 'Lang menu with only multiple languages installed and other than EN set active.' => [ - true, 'de', [ - 'title' => 'English ‎(de)‎', - 'items' => [ - [ - 'title' => 'English ‎(en)‎', - 'text' => 'English ‎(en)‎', - 'link' => true, - 'isactive' => false, - 'lang' => 'en' - ], - [ - 'title' => 'English ‎(de)‎', - 'text' => 'English ‎(de)‎', - 'link' => true, - 'isactive' => true, - 'lang' => 'de' - ], - [ - 'title' => 'English ‎(fr)‎', - 'text' => 'English ‎(fr)‎', - 'link' => true, - 'isactive' => false, - 'lang' => 'fr' - ], - ], - ], - ], - ]; - } - /** * Test the custom menu getter to confirm the nodes gets generated and are returned correctly. * diff --git a/lib/tests/output/language_menu_test.php b/lib/tests/output/language_menu_test.php new file mode 100644 index 0000000000000..eccf12e974e68 --- /dev/null +++ b/lib/tests/output/language_menu_test.php @@ -0,0 +1,159 @@ +. + +namespace core\output; + +use ReflectionMethod; + +/** + * Primary navigation renderable test + * + * @package core + * @category output + * @copyright 2021 onwards Peter Dias + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class language_menu_test extends \advanced_testcase { + /** + * Basic setup to make sure the nav objects gets generated without any issues. + */ + public function setUp(): void { + global $PAGE; + $this->resetAfterTest(); + $PAGE->set_url('/'); + } + /** + * Test the get_lang_menu + * + * @dataProvider get_lang_menu_provider + * @param bool $withadditionallangs + * @param string $language + * @param array $expected + */ + public function test_get_lang_menu(bool $withadditionallangs, string $language, array $expected) { + global $CFG, $PAGE; + + // Mimic multiple langs installed. To trigger responses 'get_list_of_translations'. + // Note: The text/title of the nodes generated will be 'English(fr), English(de)' but we don't care about this. + // We are testing whether the nodes gets generated when the lang menu is available. + if ($withadditionallangs) { + mkdir("$CFG->dataroot/lang/de", 0777, true); + mkdir("$CFG->dataroot/lang/fr", 0777, true); + // Ensure the new langs are picked up and not taken from the cache. + $stringmanager = get_string_manager(); + $stringmanager->reset_caches(true); + } + + force_current_language($language); + + $output = new language_menu($PAGE); + $method = new ReflectionMethod('\core\output\language_menu', 'export_for_template'); + $method->setAccessible(true); + $renderer = $PAGE->get_renderer('core'); + + $response = $method->invoke($output, $renderer); + + if ($withadditionallangs) { // If there are multiple languages installed. + // Assert that the title of the language menu matches the expected one. + $this->assertEquals($expected['title'], $response['title']); + // Assert that the number of language menu items matches the number of the expected items. + $this->assertEquals(count($expected['items']), count($response['items'])); + foreach ($expected['items'] as $expecteditem) { + // We need to manually generate the url key and its value in the expected item array as this cannot + // be done in the data provider due to the change of the state of $PAGE. + $expecteditem['url'] = $expecteditem['isactive'] ? new \moodle_url('#') : + new \moodle_url($PAGE->url, ['lang' => $expecteditem['lang']]); + // The lang value is only used to generate the url, so this key can be removed. + unset($expecteditem['lang']); + + // Assert that the given expected item exists in the returned items. + $this->assertTrue(in_array($expecteditem, $response['items'])); + } + } else { // No multiple languages. + $this->assertEquals($expected, $response); + } + } + + /** + * Provider for test_get_lang_menu + * + * @return array + */ + public function get_lang_menu_provider(): array { + return [ + 'Lang menu with only the current language' => [ + false, 'en', [] + ], + 'Lang menu with only multiple languages installed' => [ + true, 'en', [ + 'title' => 'English ‎(en)‎', + 'items' => [ + [ + 'title' => 'English ‎(en)‎', + 'text' => 'English ‎(en)‎', + 'link' => true, + 'isactive' => true, + 'lang' => 'en' + ], + [ + 'title' => 'English ‎(de)‎', + 'text' => 'English ‎(de)‎', + 'link' => true, + 'isactive' => false, + 'lang' => 'de' + ], + + [ + 'title' => 'English ‎(fr)‎', + 'text' => 'English ‎(fr)‎', + 'link' => true, + 'isactive' => false, + 'lang' => 'fr' + ], + ], + ], + ], + 'Lang menu with only multiple languages installed and other than EN set active.' => [ + true, 'de', [ + 'title' => 'English ‎(de)‎', + 'items' => [ + [ + 'title' => 'English ‎(en)‎', + 'text' => 'English ‎(en)‎', + 'link' => true, + 'isactive' => false, + 'lang' => 'en' + ], + [ + 'title' => 'English ‎(de)‎', + 'text' => 'English ‎(de)‎', + 'link' => true, + 'isactive' => true, + 'lang' => 'de' + ], + [ + 'title' => 'English ‎(fr)‎', + 'text' => 'English ‎(fr)‎', + 'link' => true, + 'isactive' => false, + 'lang' => 'fr' + ], + ], + ], + ], + ]; + } +} diff --git a/login/forgot_password.php b/login/forgot_password.php index ba54ce2f8dce9..6e830af47ee75 100644 --- a/login/forgot_password.php +++ b/login/forgot_password.php @@ -47,10 +47,8 @@ // setup text strings $strforgotten = get_string('passwordforgotten'); -$strlogin = get_string('login'); -$PAGE->navbar->add($strlogin, get_login_url()); -$PAGE->navbar->add($strforgotten); +$PAGE->set_pagelayout('login'); $PAGE->set_title($strforgotten); $PAGE->set_heading($COURSE->fullname); diff --git a/login/signup_form.php b/login/signup_form.php index 82e8fbdf01a2d..356ab0823ab86 100644 --- a/login/signup_form.php +++ b/login/signup_form.php @@ -36,8 +36,6 @@ function definition() { $mform = $this->_form; - $mform->addElement('header', 'createuserandpass', get_string('createuserandpass'), ''); - $mform->addElement('text', 'username', get_string('username'), 'maxlength="100" size="12" autocapitalize="none"'); $mform->setType('username', PARAM_RAW); $mform->addRule('username', get_string('missingusername'), 'required', null, 'client'); @@ -53,8 +51,6 @@ function definition() { $mform->setType('password', core_user::get_property_type('password')); $mform->addRule('password', get_string('missingpassword'), 'required', null, 'client'); - $mform->addElement('header', 'supplyinfo', get_string('supplyinfo'),''); - $mform->addElement('text', 'email', get_string('email'), 'maxlength="100" size="25"'); $mform->setType('email', core_user::get_property_type('email')); $mform->addRule('email', get_string('missingemail'), 'required', null, 'client'); @@ -110,6 +106,7 @@ function definition() { $manager->signup_form($mform); // buttons + $this->set_display_vertical(); $this->add_action_buttons(true, get_string('createaccount')); } diff --git a/theme/boost/lang/en/theme_boost.php b/theme/boost/lang/en/theme_boost.php index a57d8208c77d1..16f509b45d958 100644 --- a/theme/boost/lang/en/theme_boost.php +++ b/theme/boost/lang/en/theme_boost.php @@ -35,6 +35,8 @@ $string['currentinparentheses'] = '(current)'; $string['configtitle'] = 'Boost'; $string['generalsettings'] = 'General settings'; +$string['loginbackgroundimage'] = 'Background image for the login page'; +$string['loginbackgroundimage_desc'] = 'The image to display as a background for the login page.'; $string['nobootswatch'] = 'None'; $string['pluginname'] = 'Boost'; $string['presetfiles'] = 'Additional theme preset files'; diff --git a/theme/boost/lib.php b/theme/boost/lib.php index cf8b7fe83afbc..04b56d332a700 100644 --- a/theme/boost/lib.php +++ b/theme/boost/lib.php @@ -54,6 +54,14 @@ function theme_boost_get_extra_scss($theme) { $content .= ' }'; } + // 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 .= ' }'; + } + // Always return the background image with the scss when we have it. return !empty($theme->settings->scss) ? $theme->settings->scss . ' ' . $content : $content; } @@ -71,7 +79,8 @@ function theme_boost_get_extra_scss($theme) { * @return bool */ function theme_boost_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) { - if ($context->contextlevel == CONTEXT_SYSTEM && ($filearea === 'logo' || $filearea === 'backgroundimage')) { + if ($context->contextlevel == CONTEXT_SYSTEM && ($filearea === 'logo' || $filearea === 'backgroundimage' || + $filearea === 'loginbackgroundimage')) { $theme = theme_config::load('boost'); // By default, theme files must be cache-able by both browsers and proxies. if (!array_key_exists('cacheability', $options)) { diff --git a/theme/boost/scss/moodle/core.scss b/theme/boost/scss/moodle/core.scss index 6fd222e7d9248..4d18e021af2eb 100644 --- a/theme/boost/scss/moodle/core.scss +++ b/theme/boost/scss/moodle/core.scss @@ -528,21 +528,6 @@ a.skip:active { display: inline-block; } -// Login -.login-page { - [name="username"] { - margin-bottom: -1px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - } - - [type="password"] { - margin-bottom: 10px; - border-top-left-radius: 0; - border-top-right-radius: 0; - } -} - // Notes .notepost { margin-bottom: 1em; diff --git a/theme/boost/scss/moodle/login.scss b/theme/boost/scss/moodle/login.scss index 05fb5028a0746..c29772d785259 100644 --- a/theme/boost/scss/moodle/login.scss +++ b/theme/boost/scss/moodle/login.scss @@ -1,9 +1,69 @@ -.pagelayout-login .card-title h2 img { - max-width: 100%; - max-height: 100px; -} +$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; .pagelayout-login #region-main { border: 0; background-color: inherit; } + +.pagelayout-login #page { + background: $loginbackground-gradient-from; + @include gradient-x($loginbackground-gradient-from, $loginbackground-gradient-to, 0%, 100%); + div[role="main"] { + height: 100%; + } +} + +.login-wrapper { + display: flex; + align-items: center; + justify-content: center; + height: 100%; +} + +.login-container { + background-color: $logincontainer-bg; + padding: $logincontainer-padding; + box-shadow: $logincontainer-shadow; + .login-languagemenu { + display: flex; + justify-content: flex-end; + margin-bottom: 1rem; + } + .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; + } + } +} + +@include media-breakpoint-up(md) { + .login-container { + max-width: 600px; + } +} diff --git a/theme/boost/settings.php b/theme/boost/settings.php index 1f2bad2e87dd5..08ddf3d96d7f7 100644 --- a/theme/boost/settings.php +++ b/theme/boost/settings.php @@ -65,6 +65,14 @@ $setting->set_updatedcallback('theme_reset_all_caches'); $page->add($setting); + // Login Background image setting. + $name = 'theme_boost/loginbackgroundimage'; + $title = get_string('loginbackgroundimage', 'theme_boost'); + $description = get_string('loginbackgroundimage_desc', 'theme_boost'); + $setting = new admin_setting_configstoredfile($name, $title, $description, 'loginbackgroundimage'); + $setting->set_updatedcallback('theme_reset_all_caches'); + $page->add($setting); + // Variable $body-color. // We use an empty default value because the default colour should come from the preset. $name = 'theme_boost/brandcolor'; diff --git a/theme/boost/style/moodle.css b/theme/boost/style/moodle.css index 1c0982ce38ea7..276b911410d9e 100644 --- a/theme/boost/style/moodle.css +++ b/theme/boost/style/moodle.css @@ -10324,16 +10324,6 @@ a.skip:active { .groupselector label { display: inline-block; } -.login-page [name="username"] { - margin-bottom: -1px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; } - -.login-page [type="password"] { - margin-bottom: 10px; - border-top-left-radius: 0; - border-top-right-radius: 0; } - .notepost { margin-bottom: 1em; } @@ -17307,14 +17297,50 @@ textarea[data-auto-rows] { .input-group.form-inset.form-inset-right .form-inset-item { right: 0; } -.pagelayout-login .card-title h2 img { - max-width: 100%; - max-height: 100px; } - .pagelayout-login #region-main { border: 0; background-color: inherit; } +.pagelayout-login #page { + background: #f8f9fa; + background-image: linear-gradient(to right, #f8f9fa 0%, #dee2e6 100%); + background-repeat: repeat-x; } + .pagelayout-login #page div[role="main"] { + height: 100%; } + +.login-wrapper { + display: flex; + align-items: center; + justify-content: center; + height: 100%; } + +.login-container { + background-color: #fff; + padding: 3rem; + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); } + .login-container .login-languagemenu { + display: flex; + justify-content: flex-end; + margin-bottom: 1rem; } + .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 { + font-size: 1.875rem; } + .login-container h2.login-heading { + font-size: 1.40625rem; } + .login-container .login-identityproviders .login-identityprovider-btn { + border: 1px solid #dee2e6; } + +@media (min-width: 768px) { + .login-container { + max-width: 600px; } } + /* modules.less */ select { width: auto; } diff --git a/theme/boost/templates/login.mustache b/theme/boost/templates/login.mustache index 4b378c5f4df59..b1b06b1930adc 100644 --- a/theme/boost/templates/login.mustache +++ b/theme/boost/templates/login.mustache @@ -41,10 +41,12 @@
-
- {{{ output.course_content_header }}} +
+
diff --git a/theme/classic/lib.php b/theme/classic/lib.php index c7be24df4f69d..9861e6eb824a8 100644 --- a/theme/classic/lib.php +++ b/theme/classic/lib.php @@ -101,6 +101,14 @@ function theme_classic_get_extra_scss($theme) { '/theme/classic/scss/classic/body-background.scss'); } + // 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 .= ' }'; + } + if (!empty($theme->settings->navbardark)) { $content .= file_get_contents($CFG->dirroot . '/theme/classic/scss/classic/navbar-dark.scss'); @@ -137,7 +145,7 @@ function theme_classic_get_precompiled_css() { * @return bool */ function theme_classic_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) { - if ($context->contextlevel == CONTEXT_SYSTEM && ($filearea === 'backgroundimage')) { + if ($context->contextlevel == CONTEXT_SYSTEM && ($filearea === 'backgroundimage' || $filearea === 'loginbackgroundimage')) { $theme = theme_config::load('classic'); // By default, theme files must be cache-able by both browsers and proxies. if (!array_key_exists('cacheability', $options)) { diff --git a/theme/classic/settings.php b/theme/classic/settings.php index 97619800db973..66049cbb6651b 100644 --- a/theme/classic/settings.php +++ b/theme/classic/settings.php @@ -75,6 +75,13 @@ $setting->set_updatedcallback('theme_reset_all_caches'); $page->add($setting); + $name = 'theme_classic/loginbackgroundimage'; + $title = get_string('loginbackgroundimage', 'theme_boost'); + $description = get_string('loginbackgroundimage_desc', 'theme_boost'); + $setting = new admin_setting_configstoredfile($name, $title, $description, 'loginbackgroundimage'); + $setting->set_updatedcallback('theme_reset_all_caches'); + $page->add($setting); + // Variable $body-color. // We use an empty default value because the default colour should come from the preset. $name = 'theme_classic/brandcolor'; diff --git a/theme/classic/style/moodle.css b/theme/classic/style/moodle.css index 9a2ee240142d0..878253a266b93 100644 --- a/theme/classic/style/moodle.css +++ b/theme/classic/style/moodle.css @@ -10324,16 +10324,6 @@ a.skip:active { .groupselector label { display: inline-block; } -.login-page [name="username"] { - margin-bottom: -1px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; } - -.login-page [type="password"] { - margin-bottom: 10px; - border-top-left-radius: 0; - border-top-right-radius: 0; } - .notepost { margin-bottom: 1em; } @@ -17307,14 +17297,50 @@ textarea[data-auto-rows] { .input-group.form-inset.form-inset-right .form-inset-item { right: 0; } -.pagelayout-login .card-title h2 img { - max-width: 100%; - max-height: 100px; } - .pagelayout-login #region-main { border: 0; background-color: inherit; } +.pagelayout-login #page { + background: #f8f9fa; + background-image: linear-gradient(to right, #f8f9fa 0%, #dee2e6 100%); + background-repeat: repeat-x; } + .pagelayout-login #page div[role="main"] { + height: 100%; } + +.login-wrapper { + display: flex; + align-items: center; + justify-content: center; + height: 100%; } + +.login-container { + background-color: #fff; + padding: 3rem; + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); } + .login-container .login-languagemenu { + display: flex; + justify-content: flex-end; + margin-bottom: 1rem; } + .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 { + font-size: 1.875rem; } + .login-container h2.login-heading { + font-size: 1.40625rem; } + .login-container .login-identityproviders .login-identityprovider-btn { + border: 1px solid #dee2e6; } + +@media (min-width: 768px) { + .login-container { + max-width: 600px; } } + /* modules.less */ select { width: auto; } diff --git a/user/tests/behat/custom_profile_fields.feature b/user/tests/behat/custom_profile_fields.feature index de738a2d54025..77455b4343270 100644 --- a/user/tests/behat/custom_profile_fields.feature +++ b/user/tests/behat/custom_profile_fields.feature @@ -67,7 +67,7 @@ Feature: Custom profile fields should be visible and editable by those with the Scenario: Visible custom profile fields can be part of the sign up form for anonymous users. Given I am on site homepage And I follow "Log in" - When I press "Create new account" + When I click on "Create new account" "link" And I expand all fieldsets Then I should not see "notvisible_field" And I should see "uservisible_field" @@ -79,7 +79,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 press "Create new account" + When I click on "Create new account" "link" And I expand all fieldsets Then I should not see "notvisible_field" And I should see "uservisible_field" diff --git a/user/tests/behat/name_fields.feature b/user/tests/behat/name_fields.feature index 131b61447fb20..78242878ce167 100644 --- a/user/tests/behat/name_fields.feature +++ b/user/tests/behat/name_fields.feature @@ -10,7 +10,7 @@ Feature: Both first name and surname are always available for every user | passwordpolicy | 0 | And I am on site homepage And I follow "Log in" - And I press "Create new account" + And I click on "Create new account" "link" When I set the following fields to these values: | Username | mrwhitespace | | Password | Gue$$m3ifY0uC&n |