fix(communities): Naming validation for communities

Channel, channels category name and community name handled according to the new validation.

Fixes: #2297
This commit is contained in:
Sale Djenic 2021-06-29 14:47:28 +02:00 committed by Iuri Matias
parent 341d3ebcf7
commit b9ff88f41c
5 changed files with 151 additions and 149 deletions

View File

@ -13,29 +13,29 @@ ModalPopup {
property var channels: []
property bool isEdit: false
readonly property int maxDescChars: 140
property string nameValidationError: ""
property bool isValid: nameInput.isValid
readonly property int maxCategoryNameLength: 30
readonly property var categoryNameValidator: Utils.Validate.NoEmpty
| Utils.Validate.TextLength
| Utils.Validate.TextLowercase
id: popup
height: 453
onOpened: {
nameInput.text = isEdit ? categoryName : "";
if(isEdit){
nameInput.text = categoryName
channels = JSON.parse(chatsModel.communities.activeCommunity.getChatIdsByCategory(categoryId))
}
nameInput.forceActiveFocus(Qt.MouseFocusReason)
if(isEdit){
validate();
}
}
onClosed: destroy()
function validate() {
nameInput.validate()
return isValid
function isFormValid() {
return Utils.validateAndReturnError(nameInput.text,
categoryNameValidator,
qsTr("category name"),
maxCategoryNameLength) === ""
}
title: isEdit ?
@ -65,25 +65,15 @@ ModalPopup {
Input {
id: nameInput
placeholderText: qsTr("Category title")
validationError: popup.nameValidationError
property bool isValid: false
maxLength: maxCategoryNameLength
onTextEdited: {
validate()
}
text = Utils.convertSpacesToDashesAndUpperToLowerCase(text);
function validate() {
validationError = ""
if (nameInput.text === "") {
//% "You need to enter a name"
validationError = qsTrId("you-need-to-enter-a-name")
} else if (nameInput.text.length > 100) {
//% "Your name needs to be 100 characters or shorter"
validationError = qsTrId("your-name-needs-to-be-100-characters-or-shorter")
}
isValid = validationError === ""
return validationError
validationError = Utils.validateAndReturnError(text,
categoryNameValidator,
qsTr("category name"),
maxCategoryNameLength)
}
}
@ -213,13 +203,13 @@ ModalPopup {
}
footer: StatusButton {
enabled: popup.isValid
enabled: isFormValid()
text: isEdit ?
qsTr("Save") :
qsTr("Create")
anchors.right: parent.right
onClicked: {
if (!validate()) {
if (!isFormValid()) {
scrollView.scrollBackUp()
return
}

View File

@ -12,15 +12,18 @@ ModalPopup {
property QtObject channel
property bool isEdit: false
property string categoryId: ""
readonly property int maxDescChars: 140
property string nameValidationError: ""
readonly property int maxChannelNameLength: 30
readonly property var channelNameValidator: Utils.Validate.NoEmpty
| Utils.Validate.TextLength
| Utils.Validate.TextLowercaseLettersNumberAndDashes
readonly property int maxChannelDescLength: 140
readonly property var channelDescValidator: Utils.Validate.NoEmpty
| Utils.Validate.TextLength
property Component pinnedMessagesPopupComponent
property bool isValid:
nameInput.isValid &&
descriptionTextArea.isValid
id: popup
height: 475
@ -37,10 +40,15 @@ ModalPopup {
}
onClosed: destroy()
function validate() {
nameInput.validate()
descriptionTextArea.validate()
return isValid
function isFormValid() {
return Utils.validateAndReturnError(nameInput.text,
channelNameValidator,
qsTr("channel name"),
maxChannelNameLength) === ""
&& Utils.validateAndReturnError(descriptionTextArea.text,
channelDescValidator,
qsTr("channel decription"),
maxChannelDescLength) === ""
}
//% "New channel"
@ -70,30 +78,15 @@ ModalPopup {
id: nameInput
//% "A cool name"
placeholderText: qsTrId("a-cool-name")
validationError: popup.nameValidationError
property bool isValid: false || isEdit
maxLength: popup.maxChannelNameLength
onTextEdited: {
if (text.includes(" ")) {
text = text.replace(" ", "-")
}
validate()
}
text = Utils.convertSpacesToDashesAndUpperToLowerCase(text);
function validate() {
validationError = ""
if (nameInput.text === "") {
//% "You need to enter a name"
validationError = qsTrId("you-need-to-enter-a-name")
} else if (!(/^[a-z0-9\-]+$/.test(nameInput.text))) {
validationError = qsTr("Use only lowercase letters (a to z), numbers & dashes (-). Do not use chat keys.")
} else if (nameInput.text.length > 100) {
//% "Your name needs to be 100 characters or shorter"
validationError = qsTrId("your-name-needs-to-be-100-characters-or-shorter")
}
isValid = validationError === ""
return validationError
validationError = Utils.validateAndReturnError(text,
channelNameValidator,
qsTr("channel name"),
maxChannelNameLength)
}
}
@ -103,36 +96,28 @@ ModalPopup {
label: qsTrId("channel-description")
//% "What your channel is about"
placeholderText: qsTrId("what-your-channel-is-about")
//% "The description cannot exceed %1 characters"
validationError: descriptionTextArea.text.length > popup.maxDescChars ? qsTrId("the-description-cannot-exceed-140-characters") :
popup.descriptionValidationError || ""
anchors.top: nameInput.bottom
anchors.topMargin: Style.current.bigPadding
customHeight: 88
property bool isValid: false || isEdit
onTextChanged: validate()
function resetValidation() {
isValid = false
validationError = ""
}
function validate() {
validationError = ""
if (text.length > popup.maxDescChars) {
validationError = qsTrId("the-description-cannot-exceed-140-characters")
onTextChanged: {
if(text.length > maxChannelDescLength)
{
textField.remove(maxChannelDescLength, text.length)
return
}
if (text === "") {
validationError = qsTr("You need to enter a description")
}
isValid = validationError === ""
validationError = Utils.validateAndReturnError(text,
channelDescValidator,
qsTr("channel decription"),
maxChannelDescLength)
}
}
StyledText {
id: charLimit
text: `${descriptionTextArea.text.length}/${maxDescChars}`
text: `${descriptionTextArea.text.length}/${maxChannelDescLength}`
anchors.top: descriptionTextArea.bottom
anchors.topMargin: !descriptionTextArea.validationError ? 5 : - Style.current.smallPadding
anchors.right: descriptionTextArea.right
@ -223,14 +208,14 @@ ModalPopup {
}
footer: StatusButton {
enabled: popup.isValid
enabled: isFormValid()
text: isEdit ?
qsTr("Save") :
//% "Create"
qsTrId("create")
anchors.right: parent.right
onClicked: {
if (!validate()) {
if (!isFormValid()) {
scrollView.scrollBackUp()
return
}

View File

@ -7,15 +7,20 @@ import "../../../../shared"
import "../../../../shared/status"
ModalPopup {
readonly property int maxDescChars: 140
property QtObject community: chatsModel.communities.activeCommunity
property bool isEdit: false
property bool isValid:
nameInput.isValid &&
descriptionTextArea.isValid &&
colorPicker.isValid
readonly property int maxCommunityNameLength: 30
readonly property var communityNameValidator: Utils.Validate.NoEmpty
| Utils.Validate.TextLength
readonly property int maxCommunityDescLength: 140
readonly property var communityDescValidator: Utils.Validate.NoEmpty
| Utils.Validate.TextLength
readonly property var communityColorValidator: Utils.Validate.NoEmpty
| Utils.Validate.TextHexColor
id: popup
height: 600
@ -34,11 +39,17 @@ ModalPopup {
}
onClosed: destroy()
function validate() {
nameInput.validate()
descriptionTextArea.validate()
colorPicker.validate()
return isValid
function isFormValid() {
return Utils.validateAndReturnError(nameInput.text,
communityNameValidator,
qsTr("community name"),
maxCommunityNameLength) === ""
&& Utils.validateAndReturnError(descriptionTextArea.text,
communityDescValidator,
qsTr("community decription"),
maxCommunityDescLength) === ""
&& Utils.validateAndReturnError(colorPicker.text,
communityColorValidator) === ""
}
title: isEdit ?
@ -78,28 +89,13 @@ ModalPopup {
label: qsTrId("name-your-community")
//% "A catchy name"
placeholderText: qsTrId("name-your-community-placeholder")
property bool isValid: false
maxLength: maxCommunityNameLength
onTextEdited: {
if (text.includes(" ")) {
text = text.replace(" ", "-")
}
validate()
}
function validate() {
validationError = ""
if (nameInput.text === "") {
//% "You need to enter a name"
validationError = qsTrId("you-need-to-enter-a-name")
} else if (!(/^[a-z0-9\-]+$/.test(nameInput.text))) {
validationError = qsTr("Use only lowercase letters (a to z), numbers & dashes (-). Do not use chat keys.")
} else if (nameInput.text.length > 100) {
//% "Your name needs to be 100 characters or shorter"
validationError = qsTrId("your-name-needs-to-be-100-characters-or-shorter")
}
isValid = validationError === ""
return validationError
validationError = Utils.validateAndReturnError(text,
communityNameValidator,
qsTr("community name"),
maxCommunityNameLength)
}
}
@ -109,37 +105,29 @@ ModalPopup {
label: qsTrId("give-a-short-description-community")
//% "What your community is about"
placeholderText: qsTrId("what-your-community-is-about")
//% "The description cannot exceed 140 characters"
validationError: descriptionTextArea.text.length > popup.maxDescChars ? qsTrId("the-description-cannot-exceed-140-characters") :
popup.descriptionValidationError || ""
anchors.top: nameInput.bottom
anchors.topMargin: Style.current.bigPadding
customHeight: 88
textField.wrapMode: TextEdit.Wrap
property bool isValid: false
onTextChanged: validate()
function resetValidation() {
isValid = false
validationError = ""
}
function validate() {
validationError = ""
if (text.length > popup.maxDescChars) {
validationError = qsTrId("the-description-cannot-exceed-140-characters")
onTextChanged: {
if(text.length > maxCommunityDescLength)
{
textField.remove(maxCommunityDescLength, text.length)
return
}
if (text === "") {
validationError = qsTr("You need to enter a description")
}
isValid = validationError === ""
validationError = Utils.validateAndReturnError(text,
communityDescValidator,
qsTr("community decription"),
maxCommunityDescLength)
}
}
StyledText {
id: charLimit
text: `${descriptionTextArea.text.length}/${popup.maxDescChars}`
text: `${descriptionTextArea.text.length}/${maxCommunityDescLength}`
anchors.top: descriptionTextArea.bottom
anchors.topMargin: !descriptionTextArea.validationError ? 5 : - Style.current.smallPadding
anchors.right: descriptionTextArea.right
@ -285,7 +273,6 @@ ModalPopup {
Input {
property string defaultColor: Style.current.blue
property bool isValid: true
id: colorPicker
label: qsTr("Community color")
@ -295,21 +282,8 @@ ModalPopup {
textField.text: defaultColor
textField.onReleased: colorDialog.open()
onTextChanged: validate()
function resetValidation() {
isValid = true
validationError = ""
}
function validate() {
validationError = ""
if (text === "") {
validationError = qsTr("Please enter a color")
} else if (!Utils.isHexColor(colorPicker.text)) {
validationError = qsTr("Must be an hexadecimal color (eg: #4360DF)")
}
isValid = validationError === ""
onTextChanged: {
validationError = Utils.validateAndReturnError(text, communityColorValidator)
}
StatusIconButton {
@ -447,6 +421,7 @@ ModalPopup {
}
StatusButton {
id: btnCreateEdit
enabled: isFormValid()
text: isEdit ?
//% "Save"
qsTrId("Save") :
@ -454,7 +429,7 @@ ModalPopup {
qsTrId("create")
anchors.right: parent.right
onClicked: {
if (!validate()) {
if (!isFormValid()) {
scrollView.scrollBackUp()
return
}

View File

@ -556,6 +556,57 @@ QtObject {
return Array.from(new Set(array))
}
function hasUpperCaseLetter(str) {
return (/[A-Z]/.test(str))
}
function convertSpacesToDashesAndUpperToLowerCase(str)
{
if (str.includes(" "))
str = str.replace(/ /g, "-")
if(hasUpperCaseLetter(str))
str = str.toLowerCase()
return str
}
/* Validation section start */
enum Validate {
NoEmpty = 0x01,
TextLength = 0x02,
TextHexColor = 0x04,
TextLowercaseLettersNumberAndDashes = 0x08
}
function validateAndReturnError(str, validation, fieldName = "field", limit = 0)
{
let errMsg = ""
if(validation & Utils.Validate.NoEmpty && str === "") {
errMsg = qsTr("You need to enter a %1").arg(fieldName)
}
if(validation & Utils.Validate.TextLength && str.length > limit) {
errMsg = qsTr("The %1 cannot exceed %2 characters").arg(fieldName, limit)
}
if(validation & Utils.Validate.TextHexColor && !isHexColor(str)) {
errMsg = qsTr("Must be an hexadecimal color (eg: #4360DF)")
}
if(validation & Utils.Validate.TextLowercaseLettersNumberAndDashes && !isValidChannelName(str)) {
errMsg = qsTr("Use only lowercase letters (a to z), numbers & dashes (-). Do not use chat keys.")
}
return errMsg
}
/* Validation section end */
// Leave this function at the bottom of the file as QT Creator messes up the code color after this
function isPunct(c) {
return /(!|\@|#|\$|%|\^|&|\*|\(|\)|_|\+|\||-|=|\\|{|}|[|]|"|;|'|<|>|\?|,|\.|\/)/.test(c)

View File

@ -9,6 +9,7 @@ Item {
property string placeholderText: "My placeholder"
property string placeholderTextColor: Style.current.secondaryText
property alias text: inputValue.text
property alias maxLength: inputValue.maximumLength
property string validationError: ""
property alias validationErrorAlignment: validationErrorText.horizontalAlignment
property int validationErrorTopMargin: 1