Skip to content

Commit

Permalink
netteForms: modernized code
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed May 4, 2024
1 parent 5be52f1 commit 7b8b1a8
Showing 1 changed file with 79 additions and 141 deletions.
220 changes: 79 additions & 141 deletions src/assets/netteForms.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,56 +79,38 @@
* @return {*}
*/
Nette.getValue = function(elem) {
if (!elem) {
return null;

} else if (!elem.tagName) { // RadioNodeList
return elem[0] ? Nette.getValue(elem[0]) : null;

} else if (elem.type === 'radio') {
for (let input of expandRadioElement(elem)) {
if (input.checked) {
return input.value;
}
}
return null;

} else if (elem.type === 'file') {
return elem.files || elem.value;

} else if (elem.tagName.toLowerCase() === 'select') {
let index = elem.selectedIndex,
options = elem.options,
values = [];

if (elem.type === 'select-one') {
return index < 0 ? null : options[index].value;
}

for (let i = 0; i < options.length; i++) {
if (options[i].selected) {
values.push(options[i].value);
}
}
return values;

} else if (elem.name && elem.name.endsWith('[]')) { // multiple elements []
let values = [];
for (let input of expandRadioElement(elem)) {
if (input.type !== 'checkbox' || input.checked) {
values.push(input.value);
}
if (elem instanceof HTMLInputElement) {
if (elem.type === 'radio') {
return expandRadioElement(elem)
.find((input) => input.checked)
?.value ?? null;

} else if (elem.type === 'file') {
return elem.files;

} else if (elem.type === 'checkbox') {
return elem.name.endsWith('[]') // checkbox list
? expandRadioElement(elem)
.filter((input) => input.checked)
.map((input) => input.value)
: elem.checked;
} else {
return elem.value.replace('\r', '').replace(/^\s+|\s+$/g, '');
}
return values;

} else if (elem.type === 'checkbox') {
return elem.checked;
} else if (elem instanceof HTMLSelectElement) {
return elem.multiple
? Array.from(elem.selectedOptions, (option) => option.value)
: elem.selectedOptions[0]?.value ?? null;

} else if (elem.tagName.toLowerCase() === 'textarea') {
} else if (elem instanceof HTMLTextAreaElement) {
return elem.value.replace('\r', '');

} else if (elem instanceof RadioNodeList) {
return Nette.getValue(elem[0]);

} else {
return elem.value.replace('\r', '').replace(/^\s+|\s+$/g, '');
return null;
}
};

Expand All @@ -139,7 +121,7 @@
* @param {boolean} filter
* @return {*}
*/
Nette.getEffectiveValue = function(elem, filter) {
Nette.getEffectiveValue = function(elem, filter = false) {
let val = Nette.getValue(elem);
if (val === elem.getAttribute('data-nette-empty-value')) {
val = '';
Expand All @@ -164,14 +146,13 @@
* @param {?boolean} emptyOptional
* @return {boolean}
*/
Nette.validateControl = function(elem, rules, onlyCheck, value, emptyOptional) {
rules = rules || JSON.parse(elem.getAttribute('data-nette-rules') || '[]');
value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
emptyOptional = emptyOptional === undefined ? !Nette.validateRule(elem, ':filled', null, value) : emptyOptional;

for (let id = 0, len = rules.length; id < len; id++) {
let rule = rules[id],
op = rule.op.match(/(~)?([^?]+)/),
Nette.validateControl = function(elem, rules, onlyCheck = false, value= null, emptyOptional = null) {
rules ??= JSON.parse(elem.getAttribute('data-nette-rules') || '[]');
value ??= {value: Nette.getEffectiveValue(elem)};
emptyOptional ??= !Nette.validateRule(elem, ':filled', null, value);

for (const rule of rules) {
let op = rule.op.match(/(~)?([^?]+)/),
curElem = rule.control ? getFormElement(elem.form, rule.control) : elem;

rule.neg = op[1];
Expand Down Expand Up @@ -220,7 +201,7 @@
* @param {boolean} onlyCheck
* @return {boolean}
*/
Nette.validateForm = function(sender, onlyCheck) {
Nette.validateForm = function(sender, onlyCheck = false) {
let form = sender.form || sender,
scope = false;

Expand All @@ -238,9 +219,7 @@

let radios = {};

for (let i = 0; i < form.elements.length; i++) {
let elem = form.elements[i];

for (const elem of form.elements) {
if (elem.willValidate && elem.validity.badInput) {
elem.reportValidity();
return false;
Expand Down Expand Up @@ -280,12 +259,8 @@
*/
Nette.isDisabled = function(elem) {
if (elem.type === 'radio') {
for (let input of expandRadioElement(elem)) {
if (!input.disabled) {
return false;
}
}
return true;
return expandRadioElement(elem)
.every((input) => input.disabled);
}
return elem.disabled;
};
Expand Down Expand Up @@ -313,15 +288,12 @@
let messages = [],
focusElem;

for (let i = 0; i < errors.length; i++) {
let elem = errors[i].element,
message = errors[i].message;
for (const error of errors) {
if (messages.indexOf(error.message) < 0) {
messages.push(error.message);

if (messages.indexOf(message) < 0) {
messages.push(message);

if (!focusElem && elem.focus) {
focusElem = elem;
if (!focusElem && error.element.focus) {
focusElem = error.element;
}
}
}
Expand Down Expand Up @@ -380,21 +352,22 @@
return op === ':filled';
}

value = value === undefined ? {value: Nette.getEffectiveValue(elem, true)} : value;
value ??= {value: Nette.getEffectiveValue(elem, true)};

if (op.charAt(0) === ':') {
op = op.substring(1);
}
op = op.replace('::', '_');
op = op.replace(/\\/g, '');

let arr = Array.isArray(arg) ? arg.slice(0) : [arg];
for (let i = 0, len = arr.length; i < len; i++) {
if (arr[i] && arr[i].control) {
let control = getFormElement(elem.form, arr[i].control);
arr[i] = control === elem ? value.value : Nette.getEffectiveValue(control, true);
let arr = Array.isArray(arg) ? arg : [arg];
arr = arr.map((arg) => {
if (arg?.control) {
let control = getFormElement(elem.form, arg.control);
return control === elem ? value.value : Nette.getEffectiveValue(control, true);
}
}
return arg;
});

return Nette.validators[op]
? Nette.validators[op](elem, Array.isArray(arg) ? arr : arr[0], value.value, value)
Expand Down Expand Up @@ -433,9 +406,9 @@
val = Array.isArray(val) ? val : [val];
arg = Array.isArray(arg) ? arg : [arg];
loop:
for (let i1 = 0, len1 = val.length; i1 < len1; i1++) {
for (let i2 = 0, len2 = arg.length; i2 < len2; i2++) {
if (toString(val[i1]) === toString(arg[i2])) {
for (const a of val) {
for (const b of arg) {
if (toString(a) === toString(b)) {
continue loop;
}
}
Expand Down Expand Up @@ -499,17 +472,9 @@
regExp = new RegExp('^(?:' + arg + ')$', caseInsensitive ? 'i' : '');
}

if (val instanceof FileList) {
for (let i = 0; i < val.length; i++) {
if (!regExp.test(val[i].name)) {
return false;
}
}

return true;
}

return regExp.test(val);
return val instanceof FileList
? Array.from(val).every((file) => regExp.test(file.name))
: regExp.test(val);
} catch (e) {} // eslint-disable-line no-empty
},

Expand Down Expand Up @@ -567,32 +532,15 @@
},

fileSize: function(elem, arg, val) {
for (let i = 0; i < val.length; i++) {
if (val[i].size > arg) {
return false;
}
}
return true;
return Array.from(val).every((file) => file.size <= arg);
},

mimeType: function (elem, arg, val) {
mimeType: function (elem, args, val) {
let re = [];
arg = Array.isArray(arg) ? arg : [arg];
for (let i = 0, len = arg.length; i < len; i++) {
re.push('^' + arg[i].replace(/([^\w])/g, '\\$1').replace('\\*', '.*') + '$');
}
args = Array.isArray(args) ? args : [args];
args.map((arg) => re.push('^' + arg.replace(/([^\w])/g, '\\$1').replace('\\*', '.*') + '$'));
re = new RegExp(re.join('|'));

if (val instanceof FileList) {
for (let i = 0; i < val.length; i++) {
if (val[i].type && !re.test(val[i].type)) {
return false;
} else if (elem.validity.badInput) {
return null;
}
}
}
return true;
return Array.from(val).every((file) => !file.type || re.test(file.type));
},

image: function (elem, arg, val) {
Expand All @@ -612,9 +560,9 @@
*/
Nette.toggleForm = function(form, event) {
formToggles = {};
for (let i = 0; i < form.elements.length; i++) {
if (form.elements[i].tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1}) {
Nette.toggleControl(form.elements[i], null, null, !event);
for (const elem of form.elements) {
if (elem.tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1}) {
Nette.toggleControl(elem, null, null, !event);
}
}

Expand All @@ -634,20 +582,19 @@
* @param {?boolean} emptyOptional
* @return {boolean}
*/
Nette.toggleControl = function(elem, rules, success, firsttime, value, emptyOptional) {
rules = rules || JSON.parse(elem.getAttribute('data-nette-rules') || '[]');
value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
emptyOptional = emptyOptional === undefined ? !Nette.validateRule(elem, ':filled', null, value) : emptyOptional;
Nette.toggleControl = function(elem, rules, success, firsttime, value= null, emptyOptional = null) {
rules ??= JSON.parse(elem.getAttribute('data-nette-rules') || '[]');
value ??= {value: Nette.getEffectiveValue(elem)};
emptyOptional ??= !Nette.validateRule(elem, ':filled', null, value);

let has = false,
handler = function (e) {
Nette.toggleForm(elem.form, e);
},
curSuccess;

for (let id = 0, len = rules.length; id < len; id++) {
let rule = rules[id],
op = rule.op.match(/(~)?([^?]+)/),
for (const rule of rules) {
let op = rule.op.match(/(~)?([^?]+)/),
curElem = rule.control ? getFormElement(elem.form, rule.control) : elem;

rule.neg = op[1];
Expand Down Expand Up @@ -677,7 +624,7 @@
if ((rule.condition && Nette.toggleControl(elem, rule.rules, curSuccess, firsttime, value, rule.op === ':blank' ? false : emptyOptional)) || rule.toggle) {
has = true;
if (firsttime) {
for (let el of expandRadioElement(curElem)) {
for (const el of expandRadioElement(curElem)) {
if (!toggleListeners.has(el)) {
el.addEventListener('change', handler);
toggleListeners.set(el, null);
Expand Down Expand Up @@ -705,10 +652,8 @@
if (/^\w[\w.:-]*$/.test(selector)) { // id
selector = '#' + selector;
}
let elems = document.querySelectorAll(selector);
for (let i = 0; i < elems.length; i++) {
elems[i].hidden = !visible;
}
Array.from(document.querySelectorAll(selector))
.forEach((elem) => elem.hidden = !visible);
};


Expand All @@ -719,8 +664,7 @@
Nette.compactCheckboxes = function(form) {
let values = {};

for (let i = 0; i < form.elements.length; i++) {
let elem = form.elements[i];
for (const elem of form.elements) {
if (elem.tagName.toLowerCase() === 'input'
&& elem.type === 'checkbox'
) {
Expand All @@ -740,7 +684,7 @@
}
}

for (let name in values) {
for (const name in values) {
let elem = form.elements.namedItem(name);
if (!elem) {
elem = document.createElement('input');
Expand All @@ -765,12 +709,7 @@
});
}

check: {
for (let i = 0; i < form.elements.length; i++) {
if (form.elements[i].getAttribute('data-nette-rules')) {
break check;
}
}
if (!Array.from(form.elements).some((elem) => elem.getAttribute('data-nette-rules'))) {
return;
}

Expand Down Expand Up @@ -801,9 +740,8 @@
*/
Nette.initOnLoad = function() {
Nette.onDocumentReady(() => {
for (let i = 0; i < document.forms.length; i++) {
Nette.initForm(document.forms[i]);
}
Array.from(document.forms)
.forEach((form) => Nette.initForm(form));

document.body.addEventListener('click', (e) => {
let target = e.target;
Expand Down

0 comments on commit 7b8b1a8

Please sign in to comment.