feat: add date and multiselect custom fields

This commit is contained in:
Barış Soner Uşaklı
2024-11-20 11:01:01 -05:00
parent e375038ce0
commit 9cf85cede3
8 changed files with 44 additions and 8 deletions

View File

@@ -12,7 +12,9 @@
"input-type-text": "Input (Text)",
"input-type-link": "Input (Link)",
"input-type-number": "Input (Number)",
"input-type-date": "Input (Date)",
"input-type-select": "Select",
"input-type-select-multi": "Select Multiple",
"select-options": "Options",
"select-options-help": "Add one option per line for the select element",
"minimum-reputation": "Minimum reputation",

View File

@@ -213,6 +213,7 @@
"custom-user-field-select-value-invalid": "Custom field selected option is invalid, %1",
"custom-user-field-invalid-link": "Custom field link is invalid, %1",
"custom-user-field-invalid-number": "Custom field number is invalid, %1",
"custom-user-field-invalid-date": "Custom field date is invalid, %1",
"invalid-custom-user-field": "Invalid custom user field, \"%1\" is already used by NodeBB",
"post-already-flagged": "You have already flagged this post",
"user-already-flagged": "You have already flagged this user",

View File

@@ -69,7 +69,7 @@ define('admin/manage/user/custom-fields', [
label: '[[global:save]]',
callback: function () {
const formData = modal.find('form').serializeObject();
if (formData.type === 'select') {
if (formData.type === 'select' || formData.type === 'select-multi') {
formData.selectOptionsFormatted = formData['select-options'].trim().split('\n').join(', ');
}
@@ -91,7 +91,7 @@ define('admin/manage/user/custom-fields', [
modal.find('#type-select').on('change', function () {
const type = $(this).val();
modal.find(`[data-input-type]`).addClass('hidden');
modal.find(`[data-input-type="${type}"]`).removeClass('hidden');
modal.find(`[data-input-type-${type}]`).removeClass('hidden');
});
modal.find('#icon-select').on('click', function () {

View File

@@ -46,8 +46,18 @@ define('forum/account/edit', [
const els = $('[component="group/badge/list"] [component="group/badge/item"][data-selected="true"]');
return els.map((i, el) => $(el).attr('data-value')).get();
}
const editForm = $('form[component="profile/edit/form"]');
const userData = editForm.serializeObject();
// stringify multi selects
editForm.find('select[multiple]').each((i, el) => {
const name = $(el).attr('name');
if (userData[name] && !Array.isArray(userData[name])) {
userData[name] = [userData[name]];
}
userData[name] = JSON.stringify(userData[name] || []);
});
const userData = $('form[component="profile/edit/form"]').serializeObject();
userData.uid = ajaxify.data.uid;
userData.groupTitle = userData.groupTitle || '';
userData.groupTitle = JSON.stringify(getGroupSelection());

View File

@@ -144,14 +144,23 @@ helpers.getCustomUserFields = async function (userData) {
});
fields.forEach((f) => {
let userValue = userData[f.key];
if (f.type === 'select-multi' && userValue) {
userValue = JSON.parse(userValue || '[]');
}
f['select-options'] = f['select-options'].split('\n').filter(Boolean).map(
opt => ({
value: opt,
selected: opt === userData[f.key],
selected: Array.isArray(userValue) ?
userValue.includes(opt) :
opt === userValue,
})
);
if (userData[f.key]) {
f.value = validator.escape(String(userData[f.key]));
if (userValue) {
if (Array.isArray(userValue)) {
userValue = userValue.join(', ');
}
f.value = validator.escape(String(userValue));
}
});
return fields;

View File

@@ -113,6 +113,10 @@ module.exports = function (User) {
throw new Error(tx.compile(
'error:custom-user-field-invalid-number', field.name
));
} else if (value && type === 'input-date' && !validator.isDate(value)) {
throw new Error(tx.compile(
'error:custom-user-field-invalid-date', field.name
));
} else if (value && field.type === 'input-link' && !validator.isURL(String(value))) {
throw new Error(tx.compile(
'error:custom-user-field-invalid-link', field.name
@@ -124,6 +128,14 @@ module.exports = function (User) {
'error:custom-user-field-select-value-invalid', field.name
));
}
} else if (field.type === 'select-multi') {
const opts = field['select-options'].split('\n').filter(Boolean);
const values = JSON.parse(value || '[]');
if (!Array.isArray(values) || !values.every(value => opts.includes(value))) {
throw new Error(tx.compile(
'error:custom-user-field-select-value-invalid', field.name
));
}
}
}
});

View File

@@ -35,7 +35,7 @@
<td class="text-nowrap">{{{ if ./icon }}}<i class="text-muted {./icon}"></i> {{{ end }}}{./name}</td>
<td>
{./type}
{{{ if (./type == "select") }}}
{{{ if ((./type == "select") || (./type == "select-multi")) }}}
<div class="text-muted">
({./selectOptionsFormatted})
</div>

View File

@@ -5,7 +5,9 @@
<option value="input-text" {{{ if (type == "input-text") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-text]]</option>
<option value="input-link" {{{ if (type == "input-link") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-link]]</option>
<option value="input-number" {{{ if (type == "input-number") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-number]]</option>
<option value="input-date" {{{ if (type == "input-date") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-date]]</option>
<option value="select" {{{ if (type == "select") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-select]]</option>
<option value="select-multi" {{{ if (type == "select-multi") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-select-multi]]</option>
</select>
</div>
@@ -33,7 +35,7 @@
<p class="form-text">[[admin/manage/user-custom-fields:minimum-reputation-help]]</p>
</div>
<div class="mb-3 {{{ if (type != "select") }}}hidden{{{ end }}}" data-input-type="select">
<div class="mb-3 {{{ if ((type != "select") && (type != "select-multi")) }}}hidden{{{ end }}}" data-input-type data-input-type-select data-input-type-select-multi>
<label class="form-label">[[admin/manage/user-custom-fields:select-options]]</label>
<textarea class="form-control" name="select-options" rows="6">{./select-options}</textarea>
<p class="form-text">[[admin/manage/user-custom-fields:select-options-help]]</p>