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:
parent
341d3ebcf7
commit
b9ff88f41c
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue