- <%= label_tag "link_link#{i}", _('URL'), class: "control-label" %>
- <%= text_field_tag 'link_link', l['link'], class: "form-control", id: "link_link#{i}", 'data-validation': 'url' %>
+ <% links.each_with_index do |l, i| %>
+
+
+
+ <%= label_tag "link_link#{i}", _('URL'), class: "control-label" %>
+ <%= text_field_tag 'link_link', l['link'], class: "form-control", id: "link_link#{i}", 'data-validation': 'url' %>
+
-
diff --git a/lib/assets/javascripts/utils/links.js b/lib/assets/javascripts/utils/links.js
index 14cf6e1..e616479 100644
--- a/lib/assets/javascripts/utils/links.js
+++ b/lib/assets/javascripts/utils/links.js
@@ -1,16 +1,19 @@
import 'number-to-text/converters/en-us';
import { convertToText } from 'number-to-text/index';
-import { isFunction, isObject } from './isType';
-import { isValidText } from './isValidInputType';
+import { isFunction } from './isType';
import { enableValidations, disableValidations } from './validation';
const getLinks = elem =>
$(elem).find('.link').map((i, el) => {
- const linkVal = $(el).find('input[name="link_link"]').val();
- const textVal = $(el).find('input[name="link_text"]').val();
- if (linkVal.length > 0 && textVal.length > 0) {
+ const link = $(el);
+ const linkVal = link.find('input[name="link_link"]').val();
+ const textVal = link.find('input[name="link_text"]').val();
+ if (linkVal || textVal) { // Validations are enabled if non-empty value is found
+ enableValidations(link);
return { link: linkVal, text: textVal };
}
+ // If linkVal and textVal are empty trigger delete handler
+ link.find('.delete').first().trigger('click');
return undefined;
}).get();
@@ -25,7 +28,6 @@
$('.links').each((i, el) => {
cb($(el).attr('data-context'), getLinks(el));
});
- eachLinks.done();
}
return eachLinks;
};
@@ -35,34 +37,6 @@
}
};
-const enableLinkValidations = (ctx) => {
- if (isObject(ctx)) {
- let validatable = false;
- const fields = $(ctx).find('input');
-
- // Determine if ANY one of the values has been populated
- fields.each((i, el) => {
- if (isValidText($(el).val())) {
- validatable = true;
- }
- });
-
- // If one field has been populated make both fields required otherwise remove any validations
- if (validatable) {
- $(ctx).find('input').attr('aria-required', 'true');
- enableValidations(ctx);
- } else {
- $(ctx).find('input').removeAttr('aria-required');
- disableValidations(ctx);
- }
- }
-};
-const addValidationHandlers = (ctx) => {
- $(ctx).find('input').on('blur', () => {
- enableLinkValidations(ctx);
- });
-};
-
$(() => {
const regExp = /([^\d]*)(\d)+/;
const replacer = (match, p1, p2) => `${p1}${(p2 * 1) + 1}`;
@@ -89,16 +63,23 @@
const clonedLink = lastLink.clone();
changeIds(clonedLink);
clearVals(clonedLink);
+ // disableVaidations since a cloned element might contain invalid value for link_{link|text}
disableValidations(clonedLink);
- addValidationHandlers(clonedLink);
lastLink.after(clonedLink);
+ // enableValidations for the newly added inputs
+ enableValidations(clonedLink);
}
});
+
$('.links').on('click', '.delete', (e) => {
e.preventDefault();
const target = $(e.target);
if (linksLength(target) > 1) {
target.closest('.link').remove();
+ } else {
+ const link = target.closest('.link');
+ clearVals(link);
+ disableValidations(link);
}
});
@@ -107,12 +88,6 @@
const max = target.closest('.links').attr('data-max-number-links');
target.text(convertToText(max).toLowerCase());
});
-
- // Initialize validation on entries with data and add change handlers to toggle validation
- $('.link').each((i, el) => {
- enableLinkValidations(el);
- addValidationHandlers(el);
- });
});
export { eachLinks as default };
diff --git a/lib/assets/javascripts/utils/validation.js b/lib/assets/javascripts/utils/validation.js
index c21b476..480517e 100644
--- a/lib/assets/javascripts/utils/validation.js
+++ b/lib/assets/javascripts/utils/validation.js
@@ -3,6 +3,7 @@
import * as constants from '../constants';
import * as validator from './isValidInputType';
+const isValidatableField = ctx => $(ctx).attr('data-validatable') === 'true';
const validatableFields = (ctx) => {
if (isObject(ctx)) {
return $(ctx).find('[data-validation], [aria-required="true"]');
@@ -138,40 +139,38 @@
$(el).next().show();
};
const addValidationMessage = (el) => {
- if (isString($(el).attr('id'))) {
- const id = $(el).attr('id');
- if (!isString($(el).attr('aria-describedby'))) {
- $(el).after(blockHelp(`help-${id}`, getValidationMessage(el)));
- $(el).attr('aria-describedby', `help-${id}`);
- $(el).attr('data-validatable', 'true');
+ const target = $(el);
+ if (isString(target.attr('id'))) {
+ const id = target.attr('id');
+ if (!isString(target.attr('aria-describedby'))) {
+ target.after(blockHelp(`help-${id}`, getValidationMessage(el)));
+ target.attr('aria-describedby', `help-${id}`);
+ target.attr('data-validatable', 'true');
}
}
};
const removeValidationMessage = (el) => {
- if (isString($(el).attr('id'))) {
- $(el).parent().find('.help-block').remove();
- $(el).removeAttr('aria-describedby');
- $(el).removeAttr('data-validatable');
+ const target = $(el);
+ if (isString(target.attr('id'))) {
+ const parent = target.parent();
+ parent.removeClass(validationStates.hasError);
+ parent.find('.help-block').remove();
+ target.removeAttr('aria-describedby');
+ target.removeAttr('data-validatable');
}
};
-const isRequired = (ctx) => {
- if (isObject(ctx)) {
- return ($(ctx).attr('aria-required') && $(ctx).attr('aria-required') === 'true');
- }
- return false;
-};
+
const checkValidations = (el) => {
const type = getValidationTypeForElement(el);
const value = getValue(type, el);
-
- // If the field is required or it has a value (runs basic validations against the input type)
- if (isRequired(el) || isString(value)) {
+ // A field is validatable if has data-validatable attribute set to true
+ if (isValidatableField(el)) {
if (isValid(type, value)) {
valid(el);
- } else {
- invalid(el);
- return false;
+ return true;
}
+ invalid(el);
+ return false;
}
return true;
};
diff --git a/lib/assets/javascripts/views/org_admin/templates/edit.js b/lib/assets/javascripts/views/org_admin/templates/edit.js
index 8e18de1..f1a8452 100644
--- a/lib/assets/javascripts/views/org_admin/templates/edit.js
+++ b/lib/assets/javascripts/views/org_admin/templates/edit.js
@@ -1,4 +1,5 @@
import { Tinymce } from '../../../utils/tinymce';
+import { enableValidations, validate } from '../../../utils/validation';
import { eachLinks } from '../../../utils/links';
import { isObject, isString } from '../../../utils/isType';
import { renderNotice, renderAlert } from '../../../utils/notificationHelper';
@@ -6,18 +7,20 @@
$(() => {
Tinymce.init({ selector: '.template' });
+ enableValidations($('.edit_template'));
$('.template_show_link').on('click', (e) => {
e.preventDefault();
$(e.target).closest('.template_edit').hide();
$(e.target).closest('.tab-pane').find('.template_show').show();
});
- $('.edit_template').on('submit', () => {
+ $('.edit_template').on('ajax:before', (e) => {
const links = {};
eachLinks((ctx, value) => {
links[ctx] = value;
}).done(() => {
$('#template-links').val(JSON.stringify(links));
});
+ return validate(e.target);
});
$('.edit_template').on('ajax:success', (e, data) => {
if (isObject(data) && isString(data.msg)) {
diff --git a/lib/assets/javascripts/views/orgs/admin_edit.js b/lib/assets/javascripts/views/orgs/admin_edit.js
index 4c6e799..90175f5 100644
--- a/lib/assets/javascripts/views/orgs/admin_edit.js
+++ b/lib/assets/javascripts/views/orgs/admin_edit.js
@@ -23,15 +23,14 @@
enableValidations($('#edit_org_profile_form'));
$('#edit_org_profile_form').on('submit', (e) => {
+ const links = {};
+ eachLinks((ctx, value) => {
+ links[ctx] = value;
+ }).done(() => {
+ $('#org_links').val(JSON.stringify(links));
+ });
if (!validate(e.target)) {
e.preventDefault();
- } else {
- const links = {};
- eachLinks((ctx, value) => {
- links[ctx] = value;
- }).done(() => {
- $('#org_links').val(JSON.stringify(links));
- });
}
});
});