window.xtermToRGB = function(idx) {
idx = parseInt(idx);
if (idx < 0 || idx > 255) return [0,0,0];
if (idx < 16) {
var a = [[0,0,0],[170,0,0],[0,170,0],[170,170,0],[0,0,170],[170,0,170],[0,170,170],[170,170,170],
[85,85,85],[255,85,85],[85,255,85],[255,255,85],[85,85,255],[255,85,255],[85,255,255],[255,255,255]];
return a[idx];
}
if (idx < 232) {
var n = idx - 16;
var cube = [0,95,135,175,215,255];
return [cube[Math.floor(n/36)], cube[Math.floor((n%36)/6)], cube[n%6]];
}
var g = 8 + (idx-232)*10;
return [g,g,g];
};
window.xtermIdxToHex = function(idx) {
idx = parseInt(idx) || 0;
return idx.toString(16).toUpperCase().padStart(2,'0');
};
window.hexToXtermIdx = function(hex) {
return parseInt(hex, 16);
};
window.xtermToCss = function(idx) {
var rgb = xtermToRGB(idx);
return '#' + ((rgb[0]<<16)|(rgb[1]<<8)|rgb[2]).toString(16).padStart(6,'0').toUpperCase();
};
window.resolveColor = function(v) {
if (!v) return '#3a3a6a';
v = v.toUpperCase().replace(/[^0-9A-F]/g,'');
if (v.length === 2) return xtermToCss(parseInt(v,16));
return '#' + v.substring(0,6).padEnd(6,'0');
};
window.hexLuminance = function(hex) {
hex = hex.replace('#','').toUpperCase();
var r = parseInt(hex.substring(0,2),16)/255;
var g = parseInt(hex.substring(2,4),16)/255;
var b = parseInt(hex.substring(4,6),16)/255;
return 0.299*r + 0.587*g + 0.114*b;
};
window.cssToXtermIdx = function(css) {
css = css.replace('#','').toUpperCase();
if (css.length < 6) return 0;
var tr = parseInt(css.substring(0,2),16);
var tg = parseInt(css.substring(2,4),16);
var tb = parseInt(css.substring(4,6),16);
var best = 0, bestDist = Infinity;
for (var i = 0; i < 256; i++) {
var srgb = xtermToRGB(i);
var dr = tr-srgb[0], dg = tg-srgb[1], db = tb-srgb[2];
var d = dr*dr + dg*dg + db*db;
if (d < bestDist) { bestDist = d; best = i; }
}
return best;
};
(function() {
var pickerEl = null, boundInput = null, boundSwatch = null;
window._colorPickerActive = false;
function ensurePicker() {
if (pickerEl) return;
pickerEl = document.createElement('div');
pickerEl.id = '__cp_popover';
pickerEl.style.cssText = 'display:none;position:fixed;z-index:200;background:var(--panel);border:1px solid var(--border);border-radius:6px;padding:8px;box-shadow:0 4px 20px rgba(0,0,0,.5);min-width:280px';
pickerEl.innerHTML = buildPickerHTML();
document.body.appendChild(pickerEl);
pickerEl.addEventListener('click', function(e) {
var sw = e.target.closest('.cp-swatch');
if (sw) {
var idx = parseInt(sw.getAttribute('data-idx'));
var hex = xtermIdxToHex(idx);
if (boundInput) boundInput.value = hex;
if (boundSwatch) boundSwatch.style.background = xtermToCss(idx);
if (boundInput) boundInput.dispatchEvent(new Event('input', {bubbles:true}));
hidePicker();
}
});
}
function buildPickerHTML() {
var h = '
';
h += '';
h += '';
h += '';
h += '
';
h += '';
for (var i = 0; i < 256; i++) {
var css = xtermToCss(i);
h += '
';
}
h += '
';
return h;
}
window.showColorPicker = function(inputEl, swatchEl) {
ensurePicker();
boundInput = inputEl;
boundSwatch = swatchEl;
var raw = (inputEl.value || '').toUpperCase().replace(/[^0-9A-F]/g,'');
var idx;
if (raw.length === 2) {
idx = parseInt(raw, 16);
} else if (raw.length >= 6) {
idx = cssToXtermIdx(raw);
} else {
idx = parseInt(raw, 16) || 0;
}
var hex = xtermIdxToHex(idx);
window._colorPickerActive = true;
inputEl.value = hex;
if (swatchEl) swatchEl.style.background = xtermToCss(idx);
$('#__cp_hex').value = hex;
$('#__cp_preview').style.background = xtermToCss(idx);
updatePickerSelection(idx);
var rect = inputEl.getBoundingClientRect();
pickerEl.style.display = 'block';
var pw = pickerEl.offsetWidth;
var left = rect.left;
if (left + pw > window.innerWidth - 10) left = Math.max(10, window.innerWidth - pw - 10);
pickerEl.style.left = left + 'px';
pickerEl.style.top = (rect.bottom + 4) + 'px';
$('#__cp_hex').oninput = function() {
var v = this.value.toUpperCase().replace(/[^0-9A-F]/g,'').substring(0,2);
this.value = v;
if (v.length === 2) {
var i = parseInt(v, 16);
inputEl.value = v;
if (swatchEl) swatchEl.style.background = xtermToCss(i);
updatePickerSelection(i);
}
};
$('#__cp_close').onclick = hidePicker;
};
function updatePickerSelection(idx) {
var swatches = document.querySelectorAll('.cp-swatch');
for (var i = 0; i < swatches.length; i++) swatches[i].classList.remove('selected');
var s = document.querySelector('.cp-swatch[data-idx="'+idx+'"]');
if (s) s.classList.add('selected');
}
window.hideColorPicker = hidePicker;
function hidePicker() {
if (pickerEl) pickerEl.style.display = 'none';
var input = boundInput;
boundInput = null; boundSwatch = null;
window._colorPickerActive = false;
if (input && input.isConnected) {
input.dispatchEvent(new Event('input', {bubbles:true}));
}
}
document.addEventListener('click', function(e) {
if (!pickerEl || pickerEl.style.display === 'none') return;
if (!pickerEl.contains(e.target) && e.target !== boundInput && e.target !== (boundSwatch || {}).parentElement) {
hidePicker();
}
});
window.bindColorField = function(fieldEl) {
var input = fieldEl.querySelector('input[type=text]') || fieldEl.querySelector('input:not([type])');
var swatch = fieldEl.querySelector('.color-swatch');
if (!input) return;
fieldEl.addEventListener('click', function(e) {
if (e.target === input || e.target === swatch) {
showColorPicker(input, swatch);
}
});
var raw = (input.value || '').toUpperCase().replace(/[^0-9A-F]/g,'');
if (raw.length === 2) {
if (swatch) swatch.style.background = xtermToCss(parseInt(raw, 16));
} else if (raw.length >= 6) {
var idx = cssToXtermIdx(raw);
input.value = xtermIdxToHex(idx);
if (swatch) swatch.style.background = xtermToCss(idx);
}
input.addEventListener('input', function() {
var v = this.value.toUpperCase().replace(/[^0-9A-F]/g,'').substring(0,2);
this.value = v;
if (v.length === 2 && swatch) {
swatch.style.background = xtermToCss(parseInt(v, 16));
}
});
input.setAttribute('maxlength', '2');
input.setAttribute('placeholder', '00');
input.style.textTransform = 'uppercase';
};
})();