diff --git a/assets/js/ticket.js b/assets/js/ticket.js index 316ee34..a174d9e 100644 --- a/assets/js/ticket.js +++ b/assets/js/ticket.js @@ -183,15 +183,35 @@ function toggleEditMode() { } /** - * Compute avatar color class from display name (mirrors PHP crc32 % 4 logic) + * CRC-32 (IEEE 802.3 / zlib polynomial), matching PHP's crc32(). Operates on + * the UTF-8 byte sequence, same as PHP, so results agree for non-ASCII names. + */ +function crc32(str) { + var bytes = unescape(encodeURIComponent(str)); + var table = crc32._table || (crc32._table = (function () { + var t = []; + for (var n = 0; n < 256; n++) { + var c = n; + for (var k = 0; k < 8; k++) { + c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1); + } + t[n] = c; + } + return t; + })()); + var crc = -1; + for (var i = 0; i < bytes.length; i++) { + crc = (crc >>> 8) ^ table[(crc ^ bytes.charCodeAt(i)) & 0xFF]; + } + return (crc ^ -1) >>> 0; +} + +/** + * Compute avatar color class from display name (mirrors PHP's crc32 % 4 logic) */ function avatarColorClass(displayName) { var colors = ['lt-avatar--orange', 'lt-avatar--green', 'lt-avatar--purple', '']; - var h = 0; - for (var i = 0; i < displayName.length; i++) { - h = ((h << 5) - h + displayName.charCodeAt(i)) | 0; - } - return colors[Math.abs(h) % 4]; + return colors[crc32(displayName) % 4]; } /** diff --git a/views/TicketView.php b/views/TicketView.php index 58ecf95..905cb80 100644 --- a/views/TicketView.php +++ b/views/TicketView.php @@ -1006,9 +1006,7 @@ document.addEventListener('DOMContentLoaded', function () { shown.forEach(function (w) { var words = (w.display_name || '').trim().split(/\s+/).filter(Boolean); var initials = words.slice(0, 2).map(function (x) { return x[0].toUpperCase(); }).join(''); - var hash = 0; - for (var i = 0; i < (w.display_name || '').length; i++) hash = ((hash << 5) - hash + (w.display_name || '').charCodeAt(i)) | 0; - var color = avatarColors[Math.abs(hash) % 4]; + var color = avatarColors[crc32(w.display_name || '') % 4]; html += '