diff --git a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/RegisterIT.java b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/RegisterIT.java
index 9ce64e18065e..db104a5c051e 100644
--- a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/RegisterIT.java
+++ b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/RegisterIT.java
@@ -243,7 +243,8 @@ void registerJohnSmith(boolean isModal, boolean closedWiki, boolean withRegistra
{
AbstractRegistrationPage registrationPage = setUp(testUtils, isModal, closedWiki, withRegistrationConfig);
registrationPage.fillInJohnSmithValues();
- assertTrue(validateAndRegister(testUtils, isModal, registrationPage));
+ assertTrue(validateAndRegister(testUtils, isModal, registrationPage), String.format("isModal: %s close "
+ + "wiki: %s withRegistrationConfig: %s", isModal, closedWiki, withRegistrationConfig));
tryToLoginAsJohnSmith(testUtils, AbstractRegistrationPage.JOHN_SMITH_PASSWORD, registrationPage);
}
@@ -345,7 +346,6 @@ void registerWikiSyntaxName(boolean isModal, boolean closedWiki, boolean withReg
AbstractRegistrationPage.JOHN_SMITH_USERNAME, password, password, "wiki@example.com");
assertTrue(validateAndRegister(testUtils, isModal, registrationPage), String.format("isModal: %s close "
+ "wiki: %s withRegistrationConfig: %s", isModal, closedWiki, withRegistrationConfig));
-
// TODO: looks like a pretty strange behavior, there might be a message box title missing somewhere
String messagePrefix = closedWiki ? "" : "Information ";
diff --git a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/Registration.xml b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/Registration.xml
index 957d4d847c11..f677d13a6dce 100644
--- a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/Registration.xml
+++ b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/Registration.xml
@@ -155,31 +155,7 @@
* Removing or renaming any of these fields will result in undefined behavior.
*
*###
- #set($fields = [])
- ##
- ## The first name field, no checking.
- #set($field =
- {'name' : 'register_first_name',
- 'label' : $services.localization.render('core.register.firstName'),
- 'params' : {
- 'type' : 'text',
- 'size' : '60',
- 'autocomplete' : 'given-name'
- }
- })
- #set($discard = $fields.add($field))
- ##
- ## The last name field, no checking.
- #set($field =
- {'name' : 'register_last_name',
- 'label' : $services.localization.render('core.register.lastName'),
- 'params' : {
- 'type' : 'text',
- 'size' : '60',
- 'autocomplete' : 'family-name'
- }
- })
- #set($discard = $fields.add($field))
+ #set($mainFields = [])
##
## The user name field, mandatory and programmatically checked to make sure the username doesn't exist.
#set($field =
@@ -201,7 +177,7 @@
}
}
})
- #set($discard = $fields.add($field))
+ #set($discard = $mainFields.add($field))
## Make sure the chosen user name is not already taken
## This macro is called by programmaticValidation for xwikiname (above)
#macro (nameAvailable, $name)
@@ -212,7 +188,7 @@
##
##The password field, mandatory and must be at least 6 characters long.
##The confirm password field, mandatory, must match password field, and must also be 6+ characters long.
- #definePasswordFields($fields, 'register_password', 'register2_password', $registrationConfig.passwordOptions)
+ #definePasswordFields($mainFields, 'register_password', 'register2_password', $registrationConfig.passwordOptions)
##
## The email address field, regex checked with an email pattern. Mandatory if registration uses email verification
#set($field =
@@ -233,7 +209,7 @@
#if($registrationConfig.useEmailVerification)
#set($field.validate.mandatory = {'failureMessage' : $services.localization.render('core.validation.required.message')})
#end
- #set($discard = $fields.add($field))
+ #set($discard = $mainFields.add($field))
##
#*********
## Uncomment this code to see an example of how you can easily add a field to the registration page
@@ -259,7 +235,7 @@
},
'doAfterRegistration' : '#saveFavoriteColor()'
})
- #set($discard = $fields.add($field))
+ #set($discard = $mainFields.add($field))
## Save the user's favorite color on their user page.
#macro(saveFavoriteColor)
#set($xwikiname = $request.get('xwikiname'))
@@ -270,6 +246,31 @@
$userDoc.saveWithProgrammingRights("Saved favorite color from registration form.")
#end
*********###
+ #set($aboutYouFields = [])
+ ##
+ ## The first name field, no checking.
+ #set($field =
+ {'name' : 'register_first_name',
+ 'label' : $services.localization.render('core.register.firstName'),
+ 'params' : {
+ 'type' : 'text',
+ 'size' : '60',
+ 'autocomplete' : 'given-name'
+ }
+ })
+ #set($discard = $aboutYouFields.add($field))
+ ##
+ ## The last name field, no checking.
+ #set($field =
+ {'name' : 'register_last_name',
+ 'label' : $services.localization.render('core.register.lastName'),
+ 'params' : {
+ 'type' : 'text',
+ 'size' : '60',
+ 'autocomplete' : 'family-name'
+ }
+ })
+ #set($discard = $aboutYouFields.add($field))
##
## To disable the CAPTCHA on this page, comment out the next entry.
## The CAPTCHA, not really an input field but still defined the same way.
@@ -283,10 +284,11 @@
## Also, not filled back in if there is an error ('noReturn').
#set($field =
{'name' : 'captcha_placeholder',
- 'label' : $services.localization.render('core.captcha.instruction'),
+ 'label' : $services.localization.render('core.captcha.label')
'skipLabelFor' : true,
'type' : 'html',
- 'html' : "$!{services.captcha.default.display()}",
+ 'html' : "<span class='xHint'>$escapetool.xml($services.localization.render('core.captcha.instruction'))
+ </span> $!{services.captcha.default.display()}",
'validate' : {
'programmaticValidation' : {
'code' : '#if (!$services.captcha.default.isValid())failed#end',
@@ -295,7 +297,7 @@
},
'noReturn' : true
})
- #set($discard = $fields.add($field))
+ #set($discard = $aboutYouFields.add($field))
#end
## Pass the redirect parameter on so that the login page may redirect to the right place.
## Not necessary in Firefox 3.0.10 or Opera 9.64, I don't know about IE or Safari.
@@ -305,7 +307,10 @@
'type' : 'hidden'
}
})
- #set($discard = $fields.add($field))
+ #set($discard = $aboutYouFields.add($field))
+ #set($fields = [])
+ #set($discard = $fields.addAll($mainFields))
+ #set($discard = $fields.addAll($aboutYouFields))
##
#######################################################################
## The Code.
@@ -365,7 +370,11 @@
#end
</div>
## Note that the macro inject the form_token field.
- #generateHtml($fields, $request)
+ #generateHtml($mainFields, $request, 'false')
+ <h2>$services.localization.render('core.register.aboutYou')</h2>
+ #generateHtml($aboutYouFields, $request, 'false')
+ <input type="hidden" name="form_token" value="$services.csrf.getToken()" />
+ #generateJavascript($fields)
<p class="buttons">
<span class="buttonwrapper">
<input type="submit" value="$services.localization.render('core.register.submit')" class="button"/>
@@ -452,7 +461,9 @@
#set($redirect = $registrationConfig.defaultRedirect)
#end
## Display a "registration successful" message
-
+ ## Define some strings which may be used by the welcome message
+ #set($firstName = $escapetool.xml($!request.get('register_first_name')))
+ #set($lastName = $escapetool.xml($!request.get('register_last_name')))
#evaluate($registrationConfig.registrationSuccessMessage)
## Empty line prevents message from being forced into a <p> block.
@@ -470,6 +481,14 @@
<span class="buttonwrapper">
<input type="submit" value="$services.localization.render('login')" class="button"/>
</span>
+ #set ($mainPage = $services.wiki.currentWikiDescriptor.mainPageReference)
+ #if ($xwiki.checkAccess($mainPage, 'view'))
+ <span class="buttonwrapper">
+ <a href="$!xwiki.getURL($mainPage)" rel="home" class="button secondary">
+ $services.localization.render('core.register.successful.backtohome')
+ </a>
+ </span>
+ #end
</div>
</form>
## We don't want autoLogin if we are administrators adding users...
@@ -487,6 +506,16 @@
##
#end## createUser Macro
{{/velocity}}
+
+ registration_success_hero.svg
+ image/svg+xml
+ UTF-8
+ xwiki:XWiki.Admin
+ 1.2
+
+ PHN2ZyBkYXRhLW5hbWU9IkxheWVyIDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjY4MC44Mzg1OCIgaGVpZ2h0PSI1ODQuMjMyMDciIHZpZXdCb3g9IjAgMCA2ODAuODM4NTggNTg0LjIzMjA3IiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PHBhdGggaWQ9ImI5Y2NhZTVhLWZmZGQtNGY1Yy05YzFlLTA1YWY5ZjBmMzM3Mi0xNzciIGRhdGEtbmFtZT0iUGF0aCA0MzgiIGQ9Ik0zMTAuNzA1NjksNjk0LjAyODE4YTI0LjIxNDU5LDI0LjIxNDU5LDAsMCwwLDIzLjM4MjY5LTQuMTE4NzdjOC4xODk3Ny02Ljg3NDQxLDEwLjc1OC0xOC4xOTYsMTIuODQ2Ny0yOC42ODE5MWw2LjE3OTczLTMxLjAxNjU3LTEyLjkzNzcsOC45MDgzN2MtOS4zMDQ2NSw2LjQwNjQxLTE4LjgxODI2LDEzLjAxODY2LTI1LjI2MDExLDIyLjI5Nzg1cy05LjI1MjIzLDIxLjk0NzA3LTQuMDc3OTIsMzEuOTg4IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjU5LjU4MDcxIC0xNTcuODgzOTYpIiBmaWxsPSIjZTZlNmU2Ii8+PHBhdGggaWQ9ImY0YWQxZDA2LWJkMDMtNGNlZC1hNWM0LWMxOWE2NWFiNGVlNS0xNzgiIGRhdGEtbmFtZT0iUGF0aCA0MzkiIGQ9Ik0zMTIuNzAzNCw3MzMuNzM4NzRjLTEuNjI4MzktMTEuODYzNjgtMy4zMDM4Mi0yMy44ODA3OC0yLjE1ODg0LTM1Ljg3MTY3LDEuMDE0NjctMTAuNjQ5MzIsNC4yNjM3My0yMS4wNDg4MSwxMC44NzgzMS0yOS41NzkzOGE0OS4yMDU5Miw0OS4yMDU5MiwwLDAsMSwxMi42MjQ2Ni0xMS40NDAzOWMxLjI2MjE1LS43OTY0OCwyLjQyNDA5LDEuMjAzNTQsMS4xNjczMywxLjk5N2E0Ni43Nzk0OSw0Ni43Nzk0OSwwLDAsMC0xOC41MDQ0NiwyMi4zMjU2MmMtNC4wMjg1NywxMC4yNDYwNy00LjY3NTQ1LDIxLjQxNTgyLTMuOTgxNTQsMzIuMzAwMy40MTk0NCw2LjU4MjE4LDEuMzEwNzQsMTMuMTIxMiwyLjIwNTg4LDE5LjY1MjUxYTEuMTk4MTcsMS4xOTgxNywwLDAsMS0uODA4LDEuNDIyNTEsMS4xNjM0OCwxLjE2MzQ4LDAsMCwxLTEuNDIyNTMtLjgwOFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yNTkuNTgwNzEgLTE1Ny44ODM5NikiIGZpbGw9IiNmMmYyZjIiLz48cGF0aCBpZD0iYmFmNzg1ZjgtYjRjNi00MmNmLTg1YmQtOGExNjAzNzg0NWY3LTE3OSIgZGF0YS1uYW1lPSJQYXRoIDQ0MiIgZD0iTTMyNC40MjQ0Myw3MTQuNzAyMjlhMTcuODI1MTMsMTcuODI1MTMsMCwwLDAsMTUuNTMxNDEsOC4wMTg2MmM3Ljg2NDQtLjM3MzE4LDE0LjQxODA2LTUuODU5NzMsMjAuMzE3MTMtMTEuMDcwMjdsMTcuNDUyLTE1LjQwODgtMTEuNTQ5ODctLjU1MjgxYy04LjMwNjE5LS4zOTc4NC0xNi44MjY3Mi0uNzcxLTI0LjczODEzLDEuNzkzMzhzLTE1LjIwNzU4LDguNzI2MzktMTYuNjU0LDE2LjkxNTQxIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjU5LjU4MDcxIC0xNTcuODgzOTYpIiBmaWxsPSIjZTZlNmU2Ii8+PHBhdGggaWQ9ImExNGU0MzMwLTcxMjUtNGUwMy1hODU2LWQ2NDUzYzM0ZjZjYy0xODAiIGRhdGEtbmFtZT0iUGF0aCA0NDMiIGQ9Ik0zMDguMTAwNDIsNzQwLjU1ODQzYzcuODM5NzItMTMuODcxNDIsMTYuOTMyMzQtMjkuMjg3OTQsMzMuMTgwOC0zNC4yMTU1MmEzNy4wMjYwOSwzNy4wMjYwOSwwLDAsMSwxMy45NTU0NS0xLjQ0MWMxLjQ4MTg5LjEyOCwxLjExMTc5LDIuNDExNzQtLjM2NywyLjI4NDU0YTM0LjM5ODMzLDM0LjM5ODMzLDAsMCwwLTIyLjI3MTY0LDUuODkyMTVjLTYuMjc5OTQsNC4yNzQ1My0xMS4xNjk3NSwxMC4yMTc1NS0xNS4zMDc4MSwxNi41MTkwNy0yLjUzNTExLDMuODYwNTEtNC44MDU3Niw3Ljg4NDQ1LTcuMDc2NDIsMTEuOTAzQzMwOS40ODgyNCw3NDIuNzg1MTMsMzA3LjM2NjQxLDc0MS44NTc1OSwzMDguMTAwNDIsNzQwLjU1ODQzWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTI1OS41ODA3MSAtMTU3Ljg4Mzk2KSIgZmlsbD0iI2YyZjJmMiIvPjxwYXRoIGlkPSJhYzIwYTEwNi03ZWI4LTRhNDUtODgzNS02NzRlZjNiZjMyMjItMTgxIiBkYXRhLW5hbWU9IlBhdGggMTQxIiBkPSJNOTM1LjM5NTcsNTY5LjMxNjU0SDUwMy4xODA5MmE1LjAzMDE0LDUuMDMwMTQsMCwwLDEtNS4wMjM1OS01LjAyMzU5VjE2Mi45MDc1NGE1LjAzMDE3LDUuMDMwMTcsMCwwLDEsNS4wMjM1OS01LjAyMzU4SDkzNS4zOTU3YTUuMDMwMTcsNS4wMzAxNywwLDAsMSw1LjAyMzU5LDUuMDIzNThWNTY0LjI5MmE1LjAyOTIyLDUuMDI5MjIsMCwwLDEtNS4wMjM1OSw1LjAyMzU5WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTI1OS41ODA3MSAtMTU3Ljg4Mzk2KSIgZmlsbD0iI2ZmZiIvPjxwYXRoIGlkPSJhODg3ODA3OS1jN2NkLTQwNmYtYTQzNC04YjE1YjkxNGI5YjQtMTgyIiBkYXRhLW5hbWU9IlBhdGggMTQxIiBkPSJNOTM1LjM5NTcsNTY5LjMxNjU0SDUwMy4xODA5MmE1LjAzMDE0LDUuMDMwMTQsMCwwLDEtNS4wMjM1OS01LjAyMzU5VjE2Mi45MDc1NGE1LjAzMDE3LDUuMDMwMTcsMCwwLDEsNS4wMjM1OS01LjAyMzU4SDkzNS4zOTU3YTUuMDMwMTcsNS4wMzAxNywwLDAsMSw1LjAyMzU5LDUuMDIzNThWNTY0LjI5MmE1LjAyOTIyLDUuMDI5MjIsMCwwLDEtNS4wMjM1OSw1LjAyMzU5Wk01MDMuMTgwOTIsMTU5Ljg4OTQ0YTMuMDE4MDgsMy4wMTgwOCwwLDAsMC0zLjAxMTUyLDMuMDExNTFWNTY0LjI5MmEzLjAxODA4LDMuMDE4MDgsMCwwLDAsMy4wMTE1MiwzLjAxMTUySDkzNS4zOTU3YTMuMDE3MTcsMy4wMTcxNywwLDAsMCwzLjAxMTUzLTMuMDExNTJWMTYyLjkwNzU0YTMuMDE4MDksMy4wMTgwOSwwLDAsMC0zLjAxMTUzLTMuMDExNTFaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjU5LjU4MDcxIC0xNTcuODgzOTYpIiBmaWxsPSIjY2FjYWNhIi8+PHBhdGggaWQ9ImFmNjRmOTYxLWU5YTItNGM1My1hMzMzLTUwNjBjN2Y4NTBkMi0xODMiIGRhdGEtbmFtZT0iUGF0aCAxNDIiIGQ9Ik03MDcuNDEwMjMsMjYyLjE4NTI4YTMuNDEwNTMsMy40MTA1MywwLDAsMCwwLDYuODIxMDVIODk0LjU1MzA1YTMuNDEwNTMsMy40MTA1MywwLDAsMCwwLTYuODIxMDVaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjU5LjU4MDcxIC0xNTcuODgzOTYpIiBmaWxsPSIjZTRlNGU0Ii8+PHBhdGggaWQ9ImJhYWQ0Y2ZiLTE1OGQtNDQzOS05Y2MzLTIyNDc1YmY0N2IyMi0xODQiIGRhdGEtbmFtZT0iUGF0aCAxNDMiIGQ9Ik03MDcuNDEwMjMsMjgyLjY1MDM3YTMuNDEwNTQsMy40MTA1NCwwLDAsMCwwLDYuODIxMDZoOTUuNTQwMTlhMy40MTA1NCwzLjQxMDU0LDAsMCwwLDAtNi44MjEwNloiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yNTkuNTgwNzEgLTE1Ny44ODM5NikiIGZpbGw9IiNlNGU0ZTQiLz48cGF0aCBpZD0iZjM0NTYyNzktOTFlNS00OWFkLWFhNDMtOTgzOGIyNmZiNmNhLTE4NSIgZGF0YS1uYW1lPSJQYXRoIDE0MiIgZD0iTTU0My44NDE0NiwzOTIuNzA0NmEzLjQxMDU0LDMuNDEwNTQsMCwwLDAsMCw2LjgyMTA2aDM1MC44OTM3YTMuNDEwNTQsMy40MTA1NCwwLDAsMCwwLTYuODIxMDZaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjU5LjU4MDcxIC0xNTcuODgzOTYpIiBmaWxsPSIjZTRlNGU0Ii8+PHBhdGggaWQ9ImEzMjg4YWRmLTQ5ZjgtNDg1Zi04YWU5LTFlNGYxYTEzZDg0OS0xODYiIGRhdGEtbmFtZT0iUGF0aCAxNDMiIGQ9Ik01NDMuODQxNDYsNDEzLjE2OTdhMy40MTA1NCwzLjQxMDU0LDAsMCwwLDAsNi44MjEwNkg4MDMuMTMyNTRhMy40MTA1NCwzLjQxMDU0LDAsMCwwLDAtNi44MjEwNloiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yNTkuNTgwNzEgLTE1Ny44ODM5NikiIGZpbGw9IiNlNGU0ZTQiLz48cGF0aCBpZD0iZTYzYTViNDgtNWE3ZC00MGEyLWI5YjAtNmFkZWMzMjYzNDhhLTE4NyIgZGF0YS1uYW1lPSJQYXRoIDE0MiIgZD0iTTU0My44NDE0Niw0MzMuMTcxNzdhMy40MTA1NCwzLjQxMDU0LDAsMCwwLDAsNi44MjEwNmgzNTAuODkzN2EzLjQxMDU0LDMuNDEwNTQsMCwwLDAsMC02LjgyMTA2WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTI1OS41ODA3MSAtMTU3Ljg4Mzk2KSIgZmlsbD0iI2U0ZTRlNCIvPjxwYXRoIGlkPSJhMWM2NjliNC1kZmMzLTRjZmEtYTdiZS02NmI3MTM5OTg0NGQtMTg4IiBkYXRhLW5hbWU9IlBhdGggMTQzIiBkPSJNNTQzLjg0MTQ2LDQ1My42MzY4N2EzLjQxMDU0LDMuNDEwNTQsMCwwLDAsMCw2LjgyMTA2SDgwMy4xMzI1NGEzLjQxMDU0LDMuNDEwNTQsMCwwLDAsMC02LjgyMTA2WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTI1OS41ODA3MSAtMTU3Ljg4Mzk2KSIgZmlsbD0iI2U0ZTRlNCIvPjxwYXRoIGlkPSJiZmVjNTBkMS1mZmIxLTRkZTYtYTllZi1hMTA4NWU0MGUwMTYtMTg5IiBkYXRhLW5hbWU9IlBhdGggMTQyIiBkPSJNNTQzLjg0MTQ2LDQ3NC4xNzE3N2EzLjQxMDU0LDMuNDEwNTQsMCwwLDAsMCw2LjgyMTA2aDM1MC44OTM3YTMuNDEwNTQsMy40MTA1NCwwLDAsMCwwLTYuODIxMDZaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjU5LjU4MDcxIC0xNTcuODgzOTYpIiBmaWxsPSIjZTRlNGU0Ii8+PHBhdGggaWQ9ImJjOTY5NmVjLWVjOTktNDFkNS05MTE2LTNhZDk3MzdhMzhhYy0xOTAiIGRhdGEtbmFtZT0iUGF0aCAxNDMiIGQ9Ik01NDMuODQxNDYsNDk0LjYzNjg3YTMuNDEwNTQsMy40MTA1NCwwLDAsMCwwLDYuODIxMDZIODAzLjEzMjU0YTMuNDEwNTQsMy40MTA1NCwwLDAsMCwwLTYuODIxMDZaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjU5LjU4MDcxIC0xNTcuODgzOTYpIiBmaWxsPSIjZTRlNGU0Ii8+PHBhdGggZD0iTTU5OS40MTk0MywzMjQuODI4MTJhNDksNDksMCwxLDEsNDguOTk5NTItNDlBNDkuMDU1NjcsNDkuMDU1NjcsMCwwLDEsNTk5LjQxOTQzLDMyNC44MjgxMloiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yNTkuNTgwNzEgLTE1Ny44ODM5NikiIGZpbGw9IiMzZTc5YmMiLz48cGF0aCBkPSJNNDUwLjY3ODMzLDUxMC4xMDA0MWExMi4yNDc1NCwxMi4yNDc1NCwwLDAsMC0xNC45NTMtMTEuMzYyMzFsLTE2LjE5NjQxLTIyLjgyNTIxLTE2LjI3MTM4LDYuNDU5NDUsMjMuMzI1MTksMzEuOTEyMzdhMTIuMzEzOTIsMTIuMzEzOTIsMCwwLDAsMjQuMDk1NTktNC4xODQzWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTI1OS41ODA3MSAtMTU3Ljg4Mzk2KSIgZmlsbD0iI2EwNjE2YSIvPjxwYXRoIGQ9Ik00MTkuMTEyMTEsNTA4LjQwODg4bC00OS4wMDc3NC02My41Nzc3N0wzODguNDY3MTQsMzg3LjEyYzEuMzQ1NjMtMTQuNTA5MzYsMTAuNDI1LTE4LjU2MDg5LDEwLjgxMTM1LTE4LjcyNjQ1bC41ODkzLS4yNTI4MSwxNS45NzksNDIuNjExOS0xMS43MzIzNSwzMS4yODYyNSwyOC43OTY3MSw0OC40MzE5WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTI1OS41ODA3MSAtMTU3Ljg4Mzk2KSIgZmlsbD0iIzNmM2Q1NiIvPjxwYXRoIGQ9Ik01ODkuMzA3OTQsMzEyLjQxOTkzYTEyLjI0NzU4LDEyLjI0NzU4LDAsMCwwLTEwLjE3MjE5LDE1Ljc4NjcybC0yMS41MDQ2MywxNy45MTI2OSw3LjY5ODE2LDE1LjcyMzI2LDMwLjAxMzQzLTI1LjcyMjcyYTEyLjMxMzkyLDEyLjMxMzkyLDAsMCwwLTYuMDM0NzctMjMuNjk5OTVaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjU5LjU4MDcxIC0xNTcuODgzOTYpIiBmaWxsPSIjYTA2MTZhIi8+PHBhdGggZD0iTTU5MC4wNjIwNiwzNDQuMDIyNDRsLTU5LjU5ODM1LDUzLjc3NjY1LTU4Ljk1ODE1LTEzLjg0NTc4Yy0xNC41Ny0uMjE5NzktMTkuMzExMzYtOC45NTg3LTE5LjUwNjI5LTkuMzMxMTNsLS4yOTc2MS0uNTY4LDQxLjI0ODktMTkuMjI1NzgsMzIuMDk5Nyw5LjI3ODI4LDQ2LjA2MDQ2LTMyLjQ1NTA5WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTI1OS41ODA3MSAtMTU3Ljg4Mzk2KSIgZmlsbD0iIzNmM2Q1NiIvPjxwb2x5Z29uIHBvaW50cz0iMjI3LjI0OCA1NjguNDM3IDI0My4yNjEgNTY4LjQzNiAyNTAuODc4IDUwNi42NzIgMjI3LjI0NSA1MDYuNjczIDIyNy4yNDggNTY4LjQzNyIgZmlsbD0iI2EwNjE2YSIvPjxwYXRoIGQ9Ik00ODMuMzk3MzMsNzIxLjc0NDc2aDUwLjMyNjE0YTAsMCwwLDAsMSwwLDBWNzQxLjE4OWEwLDAsMCwwLDEsMCwwaC0zNi4yMDdhMTQuMTE5MTQsMTQuMTE5MTQsMCwwLDEtMTQuMTE5MTQtMTQuMTE5MTR2LTUuMzI1MDVBMCwwLDAsMCwxLDQ4My4zOTczMyw3MjEuNzQ0NzZaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg3NTcuNTczNDggMTMwNS4wMjY1NCkgcm90YXRlKDE3OS45OTczOCkiIGZpbGw9IiMyZjJlNDEiLz48cG9seWdvbiBwb2ludHM9IjE2My4yNDcgNTY4LjQzNyAxNzkuMjYgNTY4LjQzNiAxODYuODc4IDUwNi42NzIgMTYzLjI0NSA1MDYuNjczIDE2My4yNDcgNTY4LjQzNyIgZmlsbD0iI2EwNjE2YSIvPjxwYXRoIGQ9Ik00MTkuMzk3LDcyMS43NDQ3Nkg0NjkuNzIzMWEwLDAsMCwwLDEsMCwwVjc0MS4xODlhMCwwLDAsMCwxLDAsMGgtMzYuMjA3QTE0LjExOTE0LDE0LjExOTE0LDAsMCwxLDQxOS4zOTcsNzI3LjA2OTgxdi01LjMyNTA1YTAsMCwwLDAsMSwwLDBaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg2MjkuNTcyNzMgMTMwNS4wMjk0Nikgcm90YXRlKDE3OS45OTczOCkiIGZpbGw9IiMyZjJlNDEiLz48cG9seWdvbiBwb2ludHM9IjE1Ny41NTIgMzQyLjk5MSAxNTguODU4IDQzNC40MiAxNjAuMTY1IDU1NC41ODQgMTg4Ljg5OSA1NTEuOTcyIDIwMy4yNjcgMzg2LjA5NCAyMjEuNTUzIDU1MS45NzIgMjUxLjIxOCA1NTEuOTcyIDI1NC4yMDYgMzg0Ljc4OCAyNDMuNzU3IDM0OC4yMTYgMTU3LjU1MiAzNDIuOTkxIiBmaWxsPSIjMmYyZTQxIi8+PHBhdGggZD0iTTQ3My4zNzQxNyw1MTMuMTUzMWMtMzEuMjY1MzMuMDAyMzktNjAuMDQ0NzEtMTQuMTQ4MzktNjAuNDMzMTktMTQuMzQyNjNsLS4zMjI3My0uMTYxMzYtMi42MjM3My02Mi45NjYzN2MtLjc2MDgyLTIuMjI1MDktMTUuNzQyNjMtNDYuMTMwOTEtMTguMjgtNjAuMDg2MjUtMi41NzA4My0xNC4xMzg4MiwzNC42ODg0Mi0yNi41NDc0MiwzOS4yMTMtMjcuOTk4NTNsMS4wMjY3OC0xMS4zNzQwNSw0MS43NTM2Ni00LjQ5OTE4LDUuMjkyLDE0LjU1MzYsMTQuOTc5NDIsNS42MTY4YTcuNDA5MjQsNy40MDkyNCwwLDAsMSw0LjU5MjEyLDguNzA0M2wtOC4zMjUzOSwzMy44NTYxOSwyMC4zMzMyNSwxMTIuMDEyNjYtNC4zNzc1NS4xODk0NkM0OTUuNzA5LDUxMS4zOTY1OCw0ODQuMzg0MjUsNTEzLjE1MjUsNDczLjM3NDE3LDUxMy4xNTMxWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTI1OS41ODA3MSAtMTU3Ljg4Mzk2KSIgZmlsbD0iIzNmM2Q1NiIvPjxjaXJjbGUgY3g9IjQ1NC40NjczOCIgY3k9IjI5NC40NTk2NSIgcj0iMzAuMDYyODQiIHRyYW5zZm9ybT0ibWF0cml4KDAuODc3NDUsIC0wLjQ3OTY2LCAwLjQ3OTY2LCAwLjg3NzQ1LCAtMzQ1LjEyODI0LCA5Ni4xOTAzNykiIGZpbGw9IiNhMDYxNmEiLz48cGF0aCBkPSJNNDMwLjExNjYsMzIzLjU2MTMyYzUuNzI5MjYsNi4xMDI4OSwxNi4zNjkyNywyLjgyNjcyLDE3LjExNTgtNS41MTA2OWExMC4wNzE1MywxMC4wNzE1MywwLDAsMC0uMDEyNjgtMS45NDUyM2MtLjM4NTQ0LTMuNjkzMTEtMi41MTktNy4wNDYtMi4wMDgtMTAuOTQ1NDJhNS43Mzk3NCw1LjczOTc0LDAsMCwxLDEuMDUwNDYtMi42ODdjNC41NjU0OC02LjExMzU5LDE1LjI4MjYzLDIuNzM0NDQsMTkuNTkxMzgtMi44LDIuNjQyLTMuMzkzNTktLjQ2MzY0LTguNzM2NjQsMS41NjM4MS0xMi41Mjk1NiwyLjY3NTkxLTUuMDA2LDEwLjYwMTgzLTIuNTM2NTQsMTUuNTcyMjItNS4yNzgwOSw1LjUzMDE3LTMuMDUwMzIsNS4xOTk0LTExLjUzNTE3LDEuNTU5MDctMTYuNjk2MS00LjQzOTU1LTYuMjk0LTEyLjIyMzQ4LTkuNjUyNDEtMTkuOTEwNDQtMTAuMTM2NDNzLTE1LjMyMDk0LDEuNTkzOTQtMjIuNDk3NCw0LjM5MDY5Yy04LjE1MzkyLDMuMTc3NjctMTYuMjM5NjksNy41NjkyNS0yMS4yNTc0OSwxNC43MzktNi4xMDIxOCw4LjcxOTE5LTYuNjg5NDIsMjAuNDQxMzItMy42Mzc2LDMwLjYzNjc3QzQxOS4xMDIyMiwzMTEuMDAxMyw0MjUuNDM4MDUsMzE4LjU3NzY2LDQzMC4xMTY2LDMyMy41NjEzMloiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yNTkuNTgwNzEgLTE1Ny44ODM5NikiIGZpbGw9IiMyZjJlNDEiLz48cGF0aCBkPSJNNjQxLjU4MDcxLDc0MS45NjI2aC0zODFhMSwxLDAsMCwxLDAtMmgzODFhMSwxLDAsMCwxLDAsMloiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yNTkuNTgwNzEgLTE1Ny44ODM5NikiIGZpbGw9IiNjYWNhY2EiLz48cGF0aCBkPSJNNTk2LjU4OTg0LDI5NC4zMzU0NWEzLjQ4OCwzLjQ4OCwwLDAsMS0yLjM4MTM0LS45MzU1NWwtMTYuMTU3MjMtMTUuMDA3MzJhMy40OTk5NCwzLjQ5OTk0LDAsMCwxLDQuNzYzNjctNS4xMjg5MWwxMy42ODU1NSwxMi43MTE5MiwyNy4wNzY2Ni0yNy4wNzYxOGEzLjUsMy41LDAsMSwxLDQuOTQ5MjIsNC45NTAybC0yOS40NjA5NCwyOS40NjA5NEEzLjQ5Mjc1LDMuNDkyNzUsMCwwLDEsNTk2LjU4OTg0LDI5NC4zMzU0NVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yNTkuNTgwNzEgLTE1Ny44ODM5NikiIGZpbGw9IiNmZmYiLz48L3N2Zz4=
+ 8462
+ XWiki.Registration
@@ -763,4 +792,109 @@
XWiki.XWikiGuest
+
diff --git a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/RegistrationConfig.xml b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/RegistrationConfig.xml
index 6d9b5914c331..57dc2dd59b5b 100644
--- a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/RegistrationConfig.xml
+++ b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/RegistrationConfig.xml
@@ -522,9 +522,30 @@
0
- #set($message = $services.localization.render('core.register.successful', 'xwiki/2.1', ['USERLINK', $userName]))
+ #set($discard = $xwiki.ssx.use("XWiki.RegistrationConfig"))
+#set($displayName = "$!firstName $!lastName")
+#set($noReadableName = ($!firstName == "") || ($!lastName == ""))
+#if($noReadableName)
+ #set($displayName = $userName)
+#end
+#set($headline = $services.localization.render('core.register.successful.welcome', [$displayName]))
#set($userLink = $xwiki.getUserName("$userSpace$userName"))
-{{info}}$message.replace('USERLINK', "{{html clean=false}}$userLink{{/html}}"){{/info}}
+#set($successAndLogin = $services.localization.render('core.register.successful.successandlogin'))
+[[image:registration_success_hero.svg||data-xwiki-image-style-alignment="center" height="50vh"]]
+
+{{html}}
+<div class="registration-success-headline">
+ <h2>$escapetool.xml($headline) </h2>
+ #if(!$noReadableName)
+ <p class="registration-success-subtitle">
+ ($escapetool.xml($userName))
+ </p>
+ #end
+</div>
+<p class="registration-success-hint">
+ $escapetool.xml($successAndLogin)
+</p>
+{{/html}}0
@@ -533,4 +554,138 @@
{{translation key="core.register.welcome"/}}
+
diff --git a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/drawer.vm b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/drawer.vm
index be12627a0a0a..e63018881ee3 100644
--- a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/drawer.vm
+++ b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/drawer.vm
@@ -41,21 +41,6 @@ aria-label="$escapetool.xml($services.localization.render('core.menu.drawer.labe
#elseif($xcontext.user == 'XWiki.XWikiGuest' && $xcontext.inactiveUserReference)
$!xwiki.getUserName($xcontext.inactiveUserReference, false)
$logoutLink
- #else
- ## If xredirect is not set
- #if (!$request.xredirect)
- ## Define redirect URL value using current document relative request URL
- #set($redirectURL = $escapetool.url($xwiki.relativeRequestURL))
- ## If xredirect is already set
- #else
- ## Reuse the current value in the login link
- #set($redirectURL = $escapetool.url($request.xredirect))
- #end
-
- $services.icon.renderHTML('log-in') $escapetool.xml($services.localization.render('login'))
- #if ($xwiki.hasAccessLevel('register', 'XWiki.XWikiPreferences'))
- $services.icon.renderHTML('log-in') $escapetool.xml($services.localization.render('register'))
- #end
#end
##
## UIX
diff --git a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/less/action-menus.less b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/less/action-menus.less
index e0e7b00dcd88..180f97d2cbf8 100644
--- a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/less/action-menus.less
+++ b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/less/action-menus.less
@@ -79,6 +79,16 @@
}
}
}
+// Authentication buttons ========================================================
+// Reduce the spacing between both items if there's both
+li:has(#tmLogin) + li #tmRegister {
+ padding-right: 8px;
+}
+li:has(+ li #tmRegister) #tmLogin {
+ padding-left: 8px;
+}
+
+// Quick search ========================================================
#globalsearch {
display: flex;
diff --git a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/less/drawer.less b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/less/drawer.less
index a2799f7a504f..9f39be8b4cdb 100644
--- a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/less/drawer.less
+++ b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/less/drawer.less
@@ -191,7 +191,7 @@
margin: 12px 0;
}
-// Special styling for login/logout/register =============================
-#tmLogin, #tmLogout, #tmRegister {
+// Special styling for logout =============================
+#tmLogout {
font-style: italic;
}
diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/resources/ApplicationResources.properties b/xwiki-platform-core/xwiki-platform-oldcore/src/main/resources/ApplicationResources.properties
index 5e39c4ab3554..7398bda6b982 100644
--- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/resources/ApplicationResources.properties
+++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/resources/ApplicationResources.properties
@@ -1681,7 +1681,10 @@ core.register.invalidUsername=Invalid username provided. Please use only letters
core.register.mailSenderWronglyConfigured=The user has been created but the validation email has not been sent. Please check the Mail Sending Configuration and consider recreating the user.
core.register.invalidCaptcha=Incorrect CAPTCHA answer.
core.register.registerFailed=Registration has failed due to unknown reasons. (Error code: {0})
-core.register.successful={0} ({1}): Registration successful.
+core.register.successful.welcome=Welcome {0}
+core.register.successful.successandlogin=Registration successful. You can now log into your account.
+core.register.successful.backtohome=Back to Home
+core.register.aboutYou = About you
core.register.firstName=First Name
core.register.lastName=Last Name
core.register.username=Username
@@ -1707,6 +1710,7 @@ core.validation.valid.message=Ok.
# Captcha
core.captcha.captchaAnswerIsWrong=Incorrect answer, please try again.
+core.captcha.label=CAPTCHA
core.captcha.instruction=Please validate the CAPTCHA to prove you are not a robot
# History
@@ -5655,6 +5659,11 @@ platform.index.spaceIndex=Space Index
platform.index.spaceIndexDescription=Pages in the {0} space:
platform.index.spaceIndexDocumentListCreate=Create a new page
+#######################################
+## until 16.10.0RC1
+#######################################
+core.register.successful={0} ({1}): Registration successful.
+
## Used to indicate where deprecated keys end
#@deprecatedend
diff --git a/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/BasePage.java b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/BasePage.java
index db0ef0374ada..0ba6fd8a2443 100644
--- a/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/BasePage.java
+++ b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/BasePage.java
@@ -426,7 +426,6 @@ public boolean hasLoginLink()
*/
public LoginPage login()
{
- getDrawerMenu().toggle();
this.loginLink.click();
return new LoginPage();
}
@@ -511,7 +510,6 @@ public void logout()
*/
public RegistrationPage register()
{
- getDrawerMenu().toggle();
this.registerLink.click();
return new RegistrationPage();
}
diff --git a/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/RegistrationPage.java b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/RegistrationPage.java
index 3eb0ef141f2e..780e9c665dfe 100644
--- a/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/RegistrationPage.java
+++ b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/RegistrationPage.java
@@ -61,9 +61,12 @@ public void clickRegister()
*/
public Optional getRegistrationSuccessMessage()
{
- List infos = getDriver().findElements(By.className("infomessage"));
+ List infos = getDriver().findElements(
+ By.xpath("//*[contains(@class, 'infomessage') or" +
+ " contains(@class, 'registration-success-headline')]"));
for (WebElement info : infos) {
- if (info.getText().contains("Registration successful.")) {
+ if (info.getText().contains("Registration successful.") ||
+ info.getText().contains("Welcome ")) {
return Optional.of(info.getText().replaceAll("\n", " "));
}
}
diff --git a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/register_macros.vm b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/register_macros.vm
index 4aacec73774f..16e6d170fc3a 100644
--- a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/register_macros.vm
+++ b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/register_macros.vm
@@ -19,7 +19,7 @@
## ---------------------------------------------------------------------------
## Defines what server generated error messages should look like
## The error message when a field is entered incorrectly
-#set ($failureMessageParams = {'class': 'LV_validation_message LV_invalid'})
+#set ($failureMessageParams = {'class': 'LV_invalid'})
## 'LV_validation_message LV_invalid' depends on this:
$xwiki.get('ssfx').use('uicomponents/widgets/validation/livevalidation.css', true)
##
@@ -114,8 +114,12 @@ $xwiki.get('ssfx').use('uicomponents/widgets/validation/livevalidation.css', tru
*
* @param $fields The array of fields to use for generating HTML code.
* @param $request The request that is made by submitting the form.
+ * @param $isOnlyBlock Whether the fields are the only block of the form
*#
-#macro (generateHtml, $fields, $request)
+#macro (generateHtml, $fields, $request, $isOnlyBlock)
+ #if(!$isOnlyBlock)
+ #set($isOnlyBlock = 'true')
+ #end
## Put the same values back into the fields (if is there any problem with a field from the request that is made).
#getParams($fields, $request)
@@ -158,12 +162,67 @@ $xwiki.get('ssfx').use('uicomponents/widgets/validation/livevalidation.css', tru
#end
#end
/>
- #if ($field.error)
- $field.error
+
+ $services.icon.renderHTML('accept') ##
+ $services.icon.renderHTML('cross') ##
+ ## Add the proper content to the validation string if it's a failure on initialisation
+ ## If it's a regex validation, we also want to make sure to keep it shown at all times, we still put the
+ ## message. Note that the class displaying the state of this validation will change though.
+ #if($field.error && $field.error == $!validation.failureMessage ||
+ $!extraValidationClass.toString().contains('regex'))
+ $!validation.failureMessage
+ #end
+
+ #end
+ #set($extraValidationClass = '')
+ #if ($field.validate.mandatory)
+ #set($extraValidationClass = 'mandatory')
+ #set($validation = $field.validate.mandatory)
+ $validationContainer
+ #end
+ #if ($field.validate.mustMatch)
+ #set($extraValidationClass = 'must-match')
+ #set($validation = $field.validate.mustMatch)
+ $validationContainer
+ #end
+ #if ($field.validate.programmaticValidation)
+ #set($extraValidationClass = 'programmatic-validation')
+ #set($validation = $field.validate.programmaticValidation)
+ $validationContainer
+ #end
+ #if ($field.validate.regex)
+ #set($extraValidationClass = 'regex')
+ #set($validation = $field.validate.regex)
+ $validationContainer
+ #end
+ #foreach ($regex in $field.validate.regexes)
+ #set($extraValidationClass = 'regex-'+ $foreach.count)
+ #set($validation = $regex)
+ $validationContainer
#end
#end
@@ -172,8 +231,10 @@ $xwiki.get('ssfx').use('uicomponents/widgets/validation/livevalidation.css', tru
#end
#end
-
- #generateJavascript($fields)
+ #if ($isOnlyBlock == 'true')
+
+ #generateJavascript($fields)
+ #end
#end
##
#macro (validateRegexJS $regex $fieldName)
@@ -190,7 +251,12 @@ $xwiki.get('ssfx').use('uicomponents/widgets/validation/livevalidation.css', tru
#set ($failMessage = $regex.failureMessage)
#end
#if ($pattern != '' && $failMessage != '' && !$regex.noscript)
- ${fieldName}Validator.add(Validate.Format, {pattern: $pattern, failureMessage: "$failMessage"});
+ ## We assume here that the field uses either `regex` or `regexes`, not both at the same time.
+ #if(!$validate.regex)
+ ${fieldName}Validator.add(Validate.Format, {pattern: $pattern, failureMessage: "$failMessage", identifier: 'regex-'+ $foreach.count});
+ #else
+ ${fieldName}Validator.add(Validate.Format, {pattern: $pattern, failureMessage: "$failMessage", identifier: 'regex'});
+ #end
#end
#end
#*
@@ -225,15 +291,15 @@ $xwiki.get('ssfx').use('uicomponents/widgets/validation/livevalidation.css', tru
#if ($validate.mandatory)
#set ($mandatory = $validate.mandatory)
#if ($mandatory.failureMessage && !$mandatory.noscript)
- ${fieldName}Validator.add(Validate.Presence, {failureMessage: "$!mandatory.failureMessage"});
+ ${fieldName}Validator.add(Validate.Presence, {failureMessage: "$!mandatory.failureMessage", identifier: 'mandatory'});
#end
#end
##
#if ($validate.mustMatch)
#set ($mustMatch = $validate.mustMatch)
#if ($mustMatch.name && $mustMatch.failureMessage && !$mustMatch.noscript)
- ${fieldName}Validator.add(Validate.Confirmation, {match: $$("input[name=$!mustMatch.name]")[0],
- failureMessage: "$!mustMatch.failureMessage"});
+ ${fieldName}Validator.add(Validate.Confirmation, {match: $$("input[name=$!mustMatch.name]")[0],
+ failureMessage: "$!mustMatch.failureMessage", identifier: 'must-match'});
#end
#end
##
diff --git a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/validation/livevalidation.css b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/validation/livevalidation.css
index 3cbffc34b1fe..649e91d3ab99 100644
--- a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/validation/livevalidation.css
+++ b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/validation/livevalidation.css
@@ -3,7 +3,6 @@
font-size: 0.8em;
line-height: 1.8em;
margin: 0 0 0 0.5em;
- position: absolute;
}
.LV_valid {
@@ -14,3 +13,19 @@
color: $theme.notificationErrorColor;
}
+.LV_validation_message_valid_icon,
+.LV_validation_message_invalid_icon {
+ display: none;
+ margin-right: .5rem;
+}
+
+.LV_valid .LV_validation_message_valid_icon,
+.LV_invalid .LV_validation_message_invalid_icon {
+ display: unset;
+}
+
+/* We don't want to display anything when some kind of validations are successful.*/
+.LV_valid.mandatory,
+.LV_valid.must-match {
+ display: none;
+}
\ No newline at end of file
diff --git a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/validation/livevalidation_prototype.js b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/validation/livevalidation_prototype.js
index 962cc6ad75e0..2739d54c2d5a 100644
--- a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/validation/livevalidation_prototype.js
+++ b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/validation/livevalidation_prototype.js
@@ -100,17 +100,15 @@ LiveValidation.prototype = {
// hooks
beforeValidation: function(){},
beforeValid: function(){},
- onValid: function(){ this.insertMessage(this.createMessageSpan()); this.addFieldClass(); },
+ onValid: function(){this.addFieldClass(); },
afterValid: function(){},
beforeInvalid: function(){},
- onInvalid: function(){ this.insertMessage(this.createMessageSpan()); this.addFieldClass(); },
+ onInvalid: function(){this.addFieldClass(); },
afterInvalid: function(){},
afterValidation: function(){},
}, optionsObj || {});
var node = this.options.insertAfterWhatNode || this.element;
this.options.insertAfterWhatNode = $(node);
- this.messageHolder = this.createMessageSpan();
- this.options.insertAfterWhatNode.up().appendChild(this.messageHolder);
Object.extend(this, this.options); // copy the options to the actual object
// add to form if it has been provided
if(this.form){
@@ -171,18 +169,36 @@ LiveValidation.prototype = {
}
}
this.validations = [];
- this.removeMessageAndFieldClass();
+ this.removeFieldClass();
},
/**
- * adds a validation to perform to a LiveValidation object
+ * adds a validation to perform on a LiveValidation object
*
* @param validationFunction {Function} - validation function to be used (ie Validate.Presence )
* @param validationParamsObj {Object} - parameters for doing the validation, if wanted or necessary
* @return {Object} - the LiveValidation object itself so that calls can be chained
*/
add: function(validationFunction, validationParamsObj){
- this.validations.push( { type: validationFunction, params: validationParamsObj || {} } );
+ let validationMessageHolder;
+ /* The identifier helps us give specific behaviour to different kinds of validations. The user expectations change
+ * depending on the validation type, and this identifier makes sure we can retrieve the right message from the set
+ * of messages in the template. */
+ if (validationParamsObj.identifier) {
+ validationMessageHolder = this.options.insertAfterWhatNode.up().querySelector("." + validationParamsObj.identifier);
+ /* We use the failure message as a fallback for the success message for regexes. This ensures that the regex stays
+ * shown to the user at all times. */
+ if (validationParamsObj.identifier.includes("regex") && validationParamsObj.validMessage == null) {
+ validationParamsObj.validMessage = validationParamsObj.failureMessage;
+ }
+ } else {
+ /* If we don't have an identifier for the validation, this is a legacy use of the livevalidation.
+ We create a message holder from scratch to make it compatible with the way the new implementation works. */
+ validationMessageHolder = this.createMessageSpan();
+ this.options.insertAfterWhatNode.up().appendChild(validationMessageHolder);
+ }
+ /* We add one validation object to the list of validations for the current field. */
+ this.validations.push( { type: validationFunction, params: validationParamsObj || {}, messageHolder: validationMessageHolder } );
return this;
},
@@ -204,7 +220,6 @@ LiveValidation.prototype = {
* makes the validation wait the alotted time from the last keystroke
*/
deferValidation: function(e){
- if(this.wait >= 300) this.removeMessageAndFieldClass();
if(this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(this.validate.bind(this), this.wait);
},
@@ -222,7 +237,7 @@ LiveValidation.prototype = {
*/
doOnFocus: function(){
this.focused = true;
- this.removeMessageAndFieldClass();
+ this.removeFieldClass();
},
/**
@@ -264,11 +279,11 @@ LiveValidation.prototype = {
doValidations: function(){
this.validationFailed = false;
for(var i = 0, len = this.validations.length; i < len; ++i){
- this.validationFailed = !this.validateElement(this.validations[i].type, this.validations[i].params);
- if(this.validationFailed) return false;
+ let isValid = this.validateElement(this.validations[i].type, this.validations[i].params);
+ this.insertMessage(this.validations[i], isValid);
+ this.validationFailed = this.validationFailed || !isValid;
}
- this.message = this.validMessage;
- return true;
+ return !this.validationFailed;
},
/**
@@ -364,50 +379,64 @@ LiveValidation.prototype = {
/** Message insertion methods ****************************
*
- * These are only used in the onValid and onInvalid callback functions and so if you overide the default callbacks,
- * you must either impliment your own functions to do whatever you want, or call some of these from them if you
+ * These are only used in the onValid and onInvalid callback functions and so if you override the default callbacks,
+ * you must either implement your own functions to do whatever you want, or call some of these from them if you
* want to keep some of the functionality
*/
/**
- * makes a span containg the passed or failed message
+ * makes a span to contain the passed or failed message
*
- * @return {HTMLSpanObject} - a span element with the message in it
+ * @return {HTMLSpanObject} - an empty span element to contain the message.
*/
createMessageSpan: function(){
var span = document.createElement('span');
+ span.classList.add(this.messageClass);
span.setAttribute('aria-live', 'polite');
return span;
},
-
+
/**
- * inserts the element to contain the message in place of the element that already exists (if it does)
- *
- * @param elementToInsert {HTMLElementObject} - an element node to insert
- */
- insertMessageHolder: function(elementToInsert){
- var className = this.validationFailed ? this.invalidClass : this.validClass;
- $(elementToInsert).addClassName(this.messageClass + ' ' + className);
- var parent = this.options.insertAfterWhatNode.up();
- var nxtSibling = this.options.insertAfterWhatNode.next();
- if (nxtSibling) {
- parent.insertBefore(elementToInsert, nxtSibling);
- }else{
- parent.appendChild(elementToInsert);
+ * inserts the message in its container.
+ */
+ insertMessage: function(validation, isValid) {
+ let messageHolder = validation.messageHolder;
+ if(validation.params.validMessage=="" && !validation.params.validMessage) return; // dont insert anything if validMessage is an empty string
+ if( (this.displayMessageWhenEmpty && (this.elementType == LiveValidation.CHECKBOX || this.element.value == '')) ||
+ this.element.value != '' ||
+ validation.params.identifier.includes("regex")){
+ this.removeMessageClass(messageHolder);
+ /* If the isValid state is null, we assume that the validation did not occur yet. We do not add any class that
+ * would give a false hint towards a result. */
+ if(isValid != null) {
+ this.addMessageClass(messageHolder, isValid);
+ }
+ // We change just the lastChild textContent. This last child is a text node. This allows to not remove the icons.
+ let validMessage = validation.params.validMessage ? validation.params.validMessage : this.options.validMessage;
+ let newMessageContent = isValid ? validMessage : validation.params.failureMessage;
+ if (messageHolder.lastChild != null) {
+ messageHolder.lastChild.textContent = newMessageContent;
+ } else {
+ messageHolder.textContent = newMessageContent;
+ }
+
}
},
/**
- * inserts the message in its container of the message that already exists (if it does)
+ * Add a class for the holder of the validation message.
*/
- insertMessage: function() {
- this.removeMessage();
- if(!this.validationFailed && !this.validMessage) return; // dont insert anything if validMesssage has been set to false or empty string
- if( (this.displayMessageWhenEmpty && (this.elementType == LiveValidation.CHECKBOX || this.element.value == '')) || this.element.value != '' ){
- var className = this.validationFailed ? this.invalidClass : this.validClass;
- this.messageHolder.addClassName(this.messageClass + ' ' + className);
- this.messageHolder.textContent = this.message;
- }
+ removeMessageClass: function(messageHolder) {
+ messageHolder.removeClassName(this.invalidClass);
+ messageHolder.removeClassName(this.validClass);
+ },
+
+ /**
+ * Add a class for the holder of the validation message.
+ */
+ addMessageClass: function(messageHolder, isValid) {
+ let className = isValid ? this.validClass : this.invalidClass;
+ messageHolder.addClassName(className);
},
/**
@@ -425,15 +454,18 @@ LiveValidation.prototype = {
},
/**
- * removes the message element if it exists
+ * Empties out the message elements if they exist
*/
removeMessage: function(){
- this.messageHolder.className = 'message-holder';
- this.messageHolder.textContent = '';
+ for (let i = 0; i < this.validations.length; i++) {
+ let messageHolder = this.validations[i].messageHolder;
+ this.removeMessageClass(messageHolder);
+ messageHolder.lastChild.textContent = '';
+ }
},
/**
- * removes the class that has been applied to the field to indicte if valid or not
+ * removes the class that has been applied to the field to indicate if valid or not
*/
removeFieldClass: function(){
this.element.removeClassName(this.invalidFieldClass);