mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-18 13:39:41 -04:00
Another file converted
This commit is contained in:
@@ -1,22 +1,28 @@
|
|||||||
(function (window) {
|
(function (window) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
// This module creates dynamic add/remove input lists. It lets users add multiple entries
|
||||||
|
// (like email addresses or domains) with "Add another" and "Remove" buttons. It handles
|
||||||
|
// min/max entry limits, focus management, and preserves input attributes.
|
||||||
|
// We're keeping this for now but it's not currently being used in the application.
|
||||||
|
|
||||||
var Modules = window.NotifyModules;
|
var Modules = window.NotifyModules;
|
||||||
var lists = [],
|
var lists = [],
|
||||||
listEntry,
|
listEntry,
|
||||||
ListEntry;
|
ListEntry;
|
||||||
|
|
||||||
ListEntry = function (elm) {
|
ListEntry = function (elm) {
|
||||||
var $elm = $(elm),
|
var idPattern = elm.id;
|
||||||
idPattern = $elm.prop('id');
|
|
||||||
|
|
||||||
if (!idPattern) { return false; }
|
if (!idPattern) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
this.idPattern = idPattern;
|
this.idPattern = idPattern;
|
||||||
this.elementSelector = '.list-entry, .input-list__button--remove, .input-list__button--add';
|
this.elementSelector = '.list-entry, .input-list__button--remove, .input-list__button--add';
|
||||||
this.entries = [];
|
this.entries = [];
|
||||||
this.$wrapper = $elm;
|
this.wrapper = elm;
|
||||||
this.minEntries = 2;
|
this.minEntries = 2;
|
||||||
this.listItemName = this.$wrapper.data('listItemName');
|
this.listItemName = this.wrapper.dataset.listItemName;
|
||||||
this.getSharedAttributes();
|
this.getSharedAttributes();
|
||||||
this.getOriginalClasses();
|
this.getOriginalClasses();
|
||||||
|
|
||||||
@@ -26,33 +32,43 @@
|
|||||||
this.render();
|
this.render();
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
};
|
};
|
||||||
ListEntry.optionalAttributes = ['aria-describedby'];
|
ListEntry.escapeHtml = function(unsafe) {
|
||||||
|
if (!unsafe) return '';
|
||||||
|
return String(unsafe)
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/'/g, "'");
|
||||||
|
};
|
||||||
ListEntry.prototype.renderEntry = function(data) {
|
ListEntry.prototype.renderEntry = function(data) {
|
||||||
|
var escapeHtml = ListEntry.escapeHtml;
|
||||||
return `
|
return `
|
||||||
<div class="list-entry">
|
<div class="list-entry">
|
||||||
<label for="${data.id}" class="usa-label">
|
<label for="${escapeHtml(data.id)}" class="usa-label">
|
||||||
<span class="usa-sr-only">${data.listItemName} number </span>${data.number}.
|
<span class="usa-sr-only">${escapeHtml(data.listItemName)} number </span>${escapeHtml(data.number)}.
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
class="usa-input ${data.classes || ''}"
|
class="usa-input ${escapeHtml(data.classes || '')}"
|
||||||
name="${data.name}"
|
name="${escapeHtml(data.name)}"
|
||||||
id="${data.id}"
|
id="${escapeHtml(data.id)}"
|
||||||
${data.value ? `value="${data.value}"` : ''}
|
${data.value ? `value="${escapeHtml(data.value)}"` : ''}
|
||||||
${data.sharedAttributes}
|
${data.sharedAttributes}
|
||||||
/>
|
/>
|
||||||
${data.button ? `
|
${data.button ? `
|
||||||
<button type="button" class="usa-button usa-button--unstyled input-list__button--remove">
|
<button type="button" class="usa-button usa-button--unstyled input-list__button--remove">
|
||||||
Remove<span class="usa-sr-only"> ${data.listItemName} number ${data.number}</span>
|
Remove<span class="usa-sr-only"> ${escapeHtml(data.listItemName)} number ${escapeHtml(data.number)}</span>
|
||||||
</button>
|
</button>
|
||||||
` : ''}
|
` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
ListEntry.prototype.renderAddButton = function(data) {
|
ListEntry.prototype.renderAddButton = function(data) {
|
||||||
return `<button type="button" class="usa-button usa-button--outline input-list__button--add margin-top-4">Add another ${data.listItemName} (${data.entriesLeft} remaining)</button>`;
|
var escapeHtml = ListEntry.escapeHtml;
|
||||||
|
return `<button type="button" class="usa-button usa-button--outline input-list__button--add margin-top-4">Add another ${escapeHtml(data.listItemName)} (${escapeHtml(data.entriesLeft)} remaining)</button>`;
|
||||||
};
|
};
|
||||||
ListEntry.prototype.getSharedAttributes = function () {
|
ListEntry.prototype.getSharedAttributes = function () {
|
||||||
var $inputs = this.$wrapper.find('input'),
|
var inputs = this.wrapper.querySelectorAll('input'),
|
||||||
generatedAttributes = ['id', 'name', 'value', 'class'],
|
generatedAttributes = ['id', 'name', 'value', 'class'],
|
||||||
attributes = [],
|
attributes = [],
|
||||||
attrIdx,
|
attrIdx,
|
||||||
@@ -64,15 +80,16 @@
|
|||||||
elmIdx = attrsByElm.length,
|
elmIdx = attrsByElm.length,
|
||||||
existingAttributes = [],
|
existingAttributes = [],
|
||||||
elmAttrs,
|
elmAttrs,
|
||||||
attrIdx;
|
attrIdx,
|
||||||
|
escapeHtml = ListEntry.escapeHtml;
|
||||||
|
|
||||||
while (elmIdx--) {
|
while (elmIdx--) {
|
||||||
elmAttrs = attrsByElm[elmIdx];
|
elmAttrs = attrsByElm[elmIdx];
|
||||||
attrIdx = elmAttrs.length;
|
attrIdx = elmAttrs.length;
|
||||||
while (attrIdx--) {
|
while (attrIdx--) {
|
||||||
// prevent duplicates
|
// prevent duplicates
|
||||||
if ($.inArray(elmAttrs[attrIdx].name, existingAttributes) === -1) {
|
if (existingAttributes.indexOf(elmAttrs[attrIdx].name) === -1) {
|
||||||
attrStr += ` ${elmAttrs[attrIdx].name}="${elmAttrs[attrIdx].value}"`;
|
attrStr += ` ${escapeHtml(elmAttrs[attrIdx].name)}="${escapeHtml(elmAttrs[attrIdx].value)}"`;
|
||||||
existingAttributes.push(elmAttrs[attrIdx].name);
|
existingAttributes.push(elmAttrs[attrIdx].name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,11 +97,11 @@
|
|||||||
return attrStr;
|
return attrStr;
|
||||||
};
|
};
|
||||||
|
|
||||||
$inputs.each(function (idx, elm) {
|
inputs.forEach(function (elm) {
|
||||||
attrIdx = elm.attributes.length;
|
attrIdx = elm.attributes.length;
|
||||||
elmAttributes = [];
|
elmAttributes = [];
|
||||||
while(attrIdx--) {
|
while(attrIdx--) {
|
||||||
if ($.inArray(elm.attributes[attrIdx].name, generatedAttributes) === -1) {
|
if (generatedAttributes.indexOf(elm.attributes[attrIdx].name) === -1) {
|
||||||
elmAttributes.push({
|
elmAttributes.push({
|
||||||
'name': elm.attributes[attrIdx].name,
|
'name': elm.attributes[attrIdx].name,
|
||||||
'value': elm.attributes[attrIdx].value
|
'value': elm.attributes[attrIdx].value
|
||||||
@@ -99,9 +116,9 @@
|
|||||||
this.sharedAttributes = (attributes.length) ? getAttributesHTML(attributes) : '';
|
this.sharedAttributes = (attributes.length) ? getAttributesHTML(attributes) : '';
|
||||||
};
|
};
|
||||||
ListEntry.prototype.getOriginalClasses = function () {
|
ListEntry.prototype.getOriginalClasses = function () {
|
||||||
var $firstInput = this.$wrapper.find('input').first();
|
var firstInput = this.wrapper.querySelector('input');
|
||||||
if ($firstInput.length) {
|
if (firstInput) {
|
||||||
var classList = $firstInput.attr('class');
|
var classList = firstInput.getAttribute('class');
|
||||||
if (classList) {
|
if (classList) {
|
||||||
// Preserve any additional classes from the original input
|
// Preserve any additional classes from the original input
|
||||||
this.additionalClasses = classList;
|
this.additionalClasses = classList;
|
||||||
@@ -114,8 +131,8 @@
|
|||||||
};
|
};
|
||||||
ListEntry.prototype.getValues = function () {
|
ListEntry.prototype.getValues = function () {
|
||||||
this.entries = [];
|
this.entries = [];
|
||||||
this.$wrapper.find('input').each(function (idx, elm) {
|
this.wrapper.querySelectorAll('input').forEach(function (elm) {
|
||||||
var val = $(elm).val();
|
var val = elm.value;
|
||||||
|
|
||||||
this.entries.push(val);
|
this.entries.push(val);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
@@ -144,11 +161,12 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
ListEntry.prototype.bindEvents = function () {
|
ListEntry.prototype.bindEvents = function () {
|
||||||
this.$wrapper.on('click', '.input-list__button--remove', function (e) {
|
this.wrapper.addEventListener('click', function (e) {
|
||||||
this.removeEntry($(e.target));
|
if (e.target.closest('.input-list__button--remove')) {
|
||||||
}.bind(this));
|
this.removeEntry(e.target);
|
||||||
this.$wrapper.on('click', '.input-list__button--add', function (e) {
|
} else if (e.target.closest('.input-list__button--add')) {
|
||||||
this.addEntry();
|
this.addEntry();
|
||||||
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
};
|
};
|
||||||
ListEntry.prototype.shiftFocus = function (opts) {
|
ListEntry.prototype.shiftFocus = function (opts) {
|
||||||
@@ -159,7 +177,13 @@
|
|||||||
} else { // opts.action === 'add'
|
} else { // opts.action === 'add'
|
||||||
numberTargeted = opts.entryNumberFocused + 1;
|
numberTargeted = opts.entryNumberFocused + 1;
|
||||||
}
|
}
|
||||||
this.$wrapper.find('.list-entry').eq(numberTargeted - 1).find('input').focus();
|
var entries = this.wrapper.querySelectorAll('.list-entry');
|
||||||
|
if (entries[numberTargeted - 1]) {
|
||||||
|
var input = entries[numberTargeted - 1].querySelector('input');
|
||||||
|
if (input) {
|
||||||
|
input.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
ListEntry.prototype.removeEntryFromEntries = function (entryNumber) {
|
ListEntry.prototype.removeEntryFromEntries = function (entryNumber) {
|
||||||
var idx,
|
var idx,
|
||||||
@@ -173,7 +197,7 @@
|
|||||||
}
|
}
|
||||||
this.entries = newEntries;
|
this.entries = newEntries;
|
||||||
};
|
};
|
||||||
ListEntry.prototype.addEntry = function ($removeButton) {
|
ListEntry.prototype.addEntry = function () {
|
||||||
var currentLastEntryNumber = this.entries.length;
|
var currentLastEntryNumber = this.entries.length;
|
||||||
|
|
||||||
this.getValues();
|
this.getValues();
|
||||||
@@ -181,8 +205,23 @@
|
|||||||
this.render();
|
this.render();
|
||||||
this.shiftFocus({ 'action' : 'add', 'entryNumberFocused' : currentLastEntryNumber });
|
this.shiftFocus({ 'action' : 'add', 'entryNumberFocused' : currentLastEntryNumber });
|
||||||
};
|
};
|
||||||
ListEntry.prototype.removeEntry = function ($removeButton) {
|
ListEntry.prototype.removeEntry = function (removeButton) {
|
||||||
var entryNumber = parseInt($removeButton.find('span').text().match(/\d+/)[0], 10);
|
var button = removeButton.closest('.input-list__button--remove');
|
||||||
|
if (!button) {
|
||||||
|
console.error('ListEntry: Remove button not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var span = button.querySelector('span');
|
||||||
|
if (!span) {
|
||||||
|
console.error('ListEntry: Entry number span not found in remove button');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var match = span.textContent.match(/\d+/);
|
||||||
|
if (!match) {
|
||||||
|
console.error('ListEntry: Could not find entry number in remove button');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var entryNumber = parseInt(match[0], 10);
|
||||||
|
|
||||||
this.getValues();
|
this.getValues();
|
||||||
this.removeEntryFromEntries(entryNumber);
|
this.removeEntryFromEntries(entryNumber);
|
||||||
@@ -190,8 +229,10 @@
|
|||||||
this.shiftFocus({ 'action' : 'remove', 'entryNumberFocused' : entryNumber });
|
this.shiftFocus({ 'action' : 'remove', 'entryNumberFocused' : entryNumber });
|
||||||
};
|
};
|
||||||
ListEntry.prototype.render = function () {
|
ListEntry.prototype.render = function () {
|
||||||
this.$wrapper.find(this.elementSelector).remove();
|
this.wrapper.querySelectorAll(this.elementSelector).forEach(function(el) {
|
||||||
$.each(this.entries, function (idx, entry) {
|
el.remove();
|
||||||
|
});
|
||||||
|
this.entries.forEach(function (entry, idx) {
|
||||||
var entryNumber = idx + 1,
|
var entryNumber = idx + 1,
|
||||||
dataObj = {
|
dataObj = {
|
||||||
'id' : this.getId(entryNumber),
|
'id' : this.getId(entryNumber),
|
||||||
@@ -207,10 +248,10 @@
|
|||||||
if (entryNumber > 1) {
|
if (entryNumber > 1) {
|
||||||
dataObj.button = true;
|
dataObj.button = true;
|
||||||
}
|
}
|
||||||
this.$wrapper.append(this.renderEntry(dataObj));
|
this.wrapper.insertAdjacentHTML('beforeend', this.renderEntry(dataObj));
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
if (this.entries.length < this.maxEntries) {
|
if (this.entries.length < this.maxEntries) {
|
||||||
this.$wrapper.append(this.renderAddButton({
|
this.wrapper.insertAdjacentHTML('beforeend', this.renderAddButton({
|
||||||
'listItemName' : this.listItemName,
|
'listItemName' : this.listItemName,
|
||||||
'entriesLeft' : (this.maxEntries - this.entries.length)
|
'entriesLeft' : (this.maxEntries - this.entries.length)
|
||||||
}));
|
}));
|
||||||
@@ -219,7 +260,7 @@
|
|||||||
|
|
||||||
Modules['list-entry'] = function () {
|
Modules['list-entry'] = function () {
|
||||||
|
|
||||||
this.start = component => lists.push(new ListEntry($(component)));
|
this.start = component => lists.push(new ListEntry(component));
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user