229 lines
6.2 KiB
JavaScript
229 lines
6.2 KiB
JavaScript
// Shared browser helpers for web UI escaping and formatting.
|
|
|
|
(function () {
|
|
var urlValidationMessage = 'Please enter a URL.';
|
|
|
|
function isUrlInput(input) {
|
|
return input && input.matches && input.matches('input[type="url"]');
|
|
}
|
|
|
|
function isValidHttpUrl(input) {
|
|
input.setCustomValidity('');
|
|
var value = String(input.value || '').trim();
|
|
var hasValidNativeUrl = input.validity.valid;
|
|
var hasExplicitHttpScheme = /^https?:\/\/[^\s]+$/i.test(value);
|
|
var isValid = hasValidNativeUrl && hasExplicitHttpScheme;
|
|
if (!isValid) {
|
|
input.setCustomValidity(urlValidationMessage);
|
|
}
|
|
return isValid;
|
|
}
|
|
|
|
function getUrlFeedback(input) {
|
|
if (input._urlFeedback && input._urlFeedback.parentNode) {
|
|
return input._urlFeedback;
|
|
}
|
|
|
|
var feedbackId = input.id ? input.id + '-url-feedback' : '';
|
|
var feedback = feedbackId ? document.getElementById(feedbackId) : null;
|
|
if (feedback) {
|
|
var inputGroup = input.closest ? input.closest('.input-group') : null;
|
|
var feedbackAnchor = inputGroup || input;
|
|
feedbackAnchor.parentNode.insertBefore(feedback, feedbackAnchor.nextSibling);
|
|
input._urlFeedback = feedback;
|
|
return feedback;
|
|
}
|
|
|
|
feedback = document.createElement('div');
|
|
if (feedbackId) {
|
|
feedback.id = feedbackId;
|
|
}
|
|
feedback.className = 'invalid-feedback';
|
|
feedback.setAttribute('role', 'alert');
|
|
feedback.textContent = urlValidationMessage;
|
|
|
|
var inputGroup = input.closest ? input.closest('.input-group') : null;
|
|
var feedbackAnchor = inputGroup || input;
|
|
feedbackAnchor.parentNode.insertBefore(feedback, feedbackAnchor.nextSibling);
|
|
if (input.id) {
|
|
input.setAttribute('aria-describedby', feedback.id);
|
|
}
|
|
input._urlFeedback = feedback;
|
|
return feedback;
|
|
}
|
|
|
|
function updateUrlValidation(input, showFeedback) {
|
|
if (!isUrlInput(input)) {
|
|
return true;
|
|
}
|
|
|
|
var isValid = isValidHttpUrl(input);
|
|
if (!isValid && showFeedback) {
|
|
var feedback = getUrlFeedback(input);
|
|
feedback.hidden = false;
|
|
feedback.classList.add('d-block');
|
|
input.classList.add('is-invalid');
|
|
} else if (isValid) {
|
|
if (input.id) {
|
|
document.querySelectorAll('[id="' + input.id + '-url-feedback"]').forEach(function (feedback) {
|
|
feedback.hidden = true;
|
|
feedback.classList.remove('d-block');
|
|
});
|
|
} else if (input._urlFeedback) {
|
|
input._urlFeedback.hidden = true;
|
|
input._urlFeedback.classList.remove('d-block');
|
|
}
|
|
input.classList.remove('is-invalid');
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
function initializeUrlValidation() {
|
|
if (typeof document === 'undefined') {
|
|
return;
|
|
}
|
|
|
|
document.addEventListener('input', function (event) {
|
|
if (isUrlInput(event.target)) {
|
|
updateUrlValidation(event.target, true);
|
|
}
|
|
});
|
|
document.addEventListener('invalid', function (event) {
|
|
if (isUrlInput(event.target)) {
|
|
event.preventDefault();
|
|
updateUrlValidation(event.target, true);
|
|
}
|
|
}, true);
|
|
}
|
|
|
|
function escapeHtml(value) {
|
|
return String(value ?? '')
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|
|
|
|
function formatDashboardDate(value, useTwentyFourHour) {
|
|
if (!value) {
|
|
return '';
|
|
}
|
|
|
|
var date = new Date(value);
|
|
if (Number.isNaN(date.getTime())) {
|
|
return '';
|
|
}
|
|
|
|
var formatOptions = {
|
|
month: 'short',
|
|
day: '2-digit',
|
|
year: 'numeric',
|
|
hour: 'numeric',
|
|
minute: '2-digit',
|
|
second: '2-digit'
|
|
};
|
|
|
|
if (useTwentyFourHour) {
|
|
formatOptions.hour12 = false;
|
|
}
|
|
|
|
return new Intl.DateTimeFormat('en-US', formatOptions).format(date);
|
|
}
|
|
|
|
function getClientRowKey(client) {
|
|
return String(client && client.id ? client.id : client && client.clientId ? client.clientId : client && client.screen_slug ? client.screen_slug : client && client.deviceId ? client.deviceId : '').trim();
|
|
}
|
|
|
|
function getClientDisplayName(client) {
|
|
if (client && client.client_name) {
|
|
return String(client.client_name).trim();
|
|
}
|
|
|
|
var clientId = String(client && client.clientId ? client.clientId : '').trim();
|
|
if (clientId) {
|
|
return clientId;
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
function setButtonVariant(button, classesToRemove, classToAdd) {
|
|
if (!button) {
|
|
return;
|
|
}
|
|
|
|
if (button.classList) {
|
|
classesToRemove.forEach(function (className) {
|
|
button.classList.remove(className);
|
|
});
|
|
if (classToAdd) {
|
|
button.classList.add(classToAdd);
|
|
}
|
|
return;
|
|
}
|
|
|
|
var className = String(button.className || '');
|
|
classesToRemove.forEach(function (removeClass) {
|
|
className = className.replace(new RegExp('(^|\\s)' + removeClass + '(?=\\s|$)', 'g'), ' ');
|
|
});
|
|
if (classToAdd) {
|
|
className += ' ' + classToAdd;
|
|
}
|
|
button.className = className.replace(/\s+/g, ' ').trim();
|
|
}
|
|
|
|
function normalizeDisplayIp(value) {
|
|
var ip = String(value || '').trim();
|
|
if (!ip) {
|
|
return '';
|
|
}
|
|
|
|
if (ip.toLowerCase().indexOf('::ffff:') === 0) {
|
|
return ip.slice(7).trim();
|
|
}
|
|
|
|
return ip;
|
|
}
|
|
|
|
initializeUrlValidation();
|
|
|
|
async function blobToText(blob) {
|
|
if (!blob) {
|
|
return '';
|
|
}
|
|
|
|
if (typeof blob.text === 'function') {
|
|
return blob.text();
|
|
}
|
|
|
|
if (typeof FileReader === 'function') {
|
|
return await new Promise(function (resolve, reject) {
|
|
var reader = new FileReader();
|
|
reader.onload = function () {
|
|
resolve(String(reader.result || ''));
|
|
};
|
|
reader.onerror = function () {
|
|
reject(reader.error || new Error('Failed to read blob.'));
|
|
};
|
|
reader.readAsText(blob);
|
|
});
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
window.blobToText = blobToText;
|
|
window.escapeHtml = escapeHtml;
|
|
window.pendingByRegionId = window.pendingByRegionId || Object.create(null);
|
|
|
|
window.webUiHelpers = {
|
|
escapeHtml: escapeHtml,
|
|
formatDashboardDate: formatDashboardDate,
|
|
getClientRowKey: getClientRowKey,
|
|
getClientDisplayName: getClientDisplayName,
|
|
setButtonVariant: setButtonVariant,
|
|
normalizeDisplayIp: normalizeDisplayIp
|
|
};
|
|
}()); |