Files
itflow/js/ticket_status_form.js

97 lines
3.9 KiB
JavaScript

// New Ticket Status and Edit (admin/modals/ticket_status/ticket_status_form.php).
// The preview is the status's badge as tickets will show it, redrawn as its
// name and colour change - with dark or white text, whichever reads on the
// colour, as ticketStatusBadgeHtml() in functions/ticket_status.php draws it.
// A swatch, the colour picker or a typed hex sets the colour. The server
// checks it all again.
//
// Wrapped in an IIFE because a modal can be opened, closed and opened again
// in one page load, which re-runs this file.
(function () {
// Dark or white text on a #rrggbb colour - tagTextColor() in functions/tags.php
function textColor(value) {
const channel = function (hex) {
const c = parseInt(hex, 16) / 255;
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
};
const luminance = 0.2126 * channel(value.substr(1, 2)) + 0.7152 * channel(value.substr(3, 2)) + 0.0722 * channel(value.substr(5, 2));
return luminance > 0.4 ? '#212529' : '#fff';
}
// #rrggbb from what was typed - null when it isn't a colour yet
function hexColor(value) {
value = String(value).trim().toLowerCase();
if (value.charAt(0) !== '#') {
value = '#' + value;
}
if (/^#[0-9a-f]{3}$/.test(value)) {
value = '#' + value[1] + value[1] + value[2] + value[2] + value[3] + value[3];
}
return /^#[0-9a-f]{6}$/.test(value) ? value : null;
}
document.querySelectorAll('[data-ticket-status-form]:not([data-wired])').forEach(function (form) {
form.setAttribute('data-wired', '1');
const badge = form.querySelector('[data-ticket-status-preview] .badge');
const name = form.querySelector('[data-ticket-status-name]');
const color = form.querySelector('[data-ticket-status-color]');
const pick = form.querySelector('[data-ticket-status-color-pick]');
const hex = form.querySelector('[data-ticket-status-color-hex]');
const swatches = form.querySelectorAll('[data-ticket-status-swatch]');
function draw() {
badge.textContent = name.value.trim() || 'New status';
badge.style.setProperty('--itflow-status-bg', color.value);
badge.style.setProperty('--itflow-status-text', textColor(color.value));
}
// $from says which control set it, so that one isn't rewritten as it is typed in
function setColor(value, from) {
color.value = value;
if (from !== 'pick') {
pick.value = value;
}
if (from !== 'hex') {
hex.value = value;
}
hex.classList.remove('is-invalid');
swatches.forEach(function (swatch) {
const on = swatch.dataset.ticketStatusSwatch === value;
swatch.classList.toggle('active', on);
swatch.setAttribute('aria-pressed', on ? 'true' : 'false');
});
draw();
}
swatches.forEach(function (swatch) {
swatch.addEventListener('click', function () {
setColor(swatch.dataset.ticketStatusSwatch, 'swatch');
});
});
pick.addEventListener('input', function () {
setColor(pick.value.toLowerCase(), 'pick');
});
hex.addEventListener('input', function () {
const value = hexColor(hex.value);
if (value) {
setColor(value, 'hex');
} else {
hex.classList.toggle('is-invalid', hex.value.trim() !== '');
}
});
// A half-typed hex goes back to the colour in use when the field is left
hex.addEventListener('change', function () {
if (!hexColor(hex.value)) {
hex.value = color.value;
hex.classList.remove('is-invalid');
}
});
name.addEventListener('input', draw);
draw();
});
})();