Monochrome / popup / popup.js
popup.js
Raw
var bIsChrome = /Chrome/.test(navigator.userAgent);
var state = null;

function Swatch(x, y, id, radius, hue, saturation, lightness) {
    this.x = x;
    this.y = y;
    this.id = id;
    this.hovered = false;
    this.radius = radius;
    this.hue = hue;
    this.saturation = saturation;
    this.lightness = lightness;
    this.hsl = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
}

function updateSwatch(swatch, hue, saturation, lightness) {
    swatch.hue = hue;
    swatch.saturation = saturation;
    swatch.lightness = lightness;
    swatch.hsl = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
};

var lightnessSlider = document.getElementById("lightness");
var lightnessValue = document.getElementById("lightness-value");

var info = document.getElementById("info");
var infoText = document.querySelector("#info p");

var changeColorsCheckbox = document.getElementById("change-colors");
var alwaysCheckbox = document.getElementById("always");
var alwaysLabel = document.getElementById("always-label");

var foreBtn = document.getElementById("fore");
var backBtn = document.getElementById("back");
var linkBtn = document.getElementById("link");
var resetBtn = document.getElementById("reset");

var foreSwatch = document.getElementById("fore-swatch");
var backSwatch = document.getElementById("back-swatch");
var linkSwatch = document.getElementById("link-swatch");

changeColorsCheckbox.onclick = () => {
    sendRuntimeMessage('changeColors', changeColorsCheckbox.checked);
};

alwaysCheckbox.onclick = () => {
    sendRuntimeMessage('always', alwaysCheckbox.checked);
};

function alwaysMouseover() {
    if (!state.activeTabId) {
        return;
    }
    // infoText.textContent = `Current new host: ${state.activeTabHostname}`;
    // info.style.opacity = 1;
}

function alwaysMouseout() {
    info.style.opacity = 0;
}

alwaysCheckbox.onmouseover = alwaysMouseover;
alwaysCheckbox.onmouseout = alwaysMouseout;
alwaysLabel.onmouseover = alwaysMouseover;
alwaysLabel.onmouseout = alwaysMouseout;

resetBtn.onclick = function() {
    sendRuntimeMessage('reset');
}

lightnessSlider.oninput = function() {
    lightnessValue.childNodes[0].nodeValue = `${this.value}%`;
}

lightnessSlider.onchange = function() {
    lightnessValue.childNodes[0].nodeValue = `${this.value}%`;
    let lightness = parseInt(this.value);
    sendRuntimeMessage('changeLightness', lightness);
}

function handleFore() {
    saveStorage({ activeBtn: 'fore', lightness: state.fg.lightness });
}

function handleBack() {
    saveStorage({ activeBtn: 'back', lightness: state.bg.lightness });
}

function handleLink() {
    saveStorage({ activeBtn: 'link', lightness: state.li.lightness });
}

foreSwatch.onclick = handleFore;
foreBtn.onclick = handleFore;
backSwatch.onclick = handleBack;
backBtn.onclick = handleBack;
linkSwatch.onclick = handleLink;
linkBtn.onclick = handleLink;

function setActiveColorButton() {
    foreBtn.classList.remove("active-btn");
    backBtn.classList.remove("active-btn");
    linkBtn.classList.remove("active-btn");
    document.getElementById(state.activeBtn).classList.add("active-btn");

    foreSwatch.classList.remove("active-swatch");
    backSwatch.classList.remove("active-swatch");
    linkSwatch.classList.remove("active-swatch");
    document.getElementById(`${state.activeBtn}-swatch`).classList.add("active-swatch");
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Canvas
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
canvas.width = document.querySelector("canvas").offsetWidth;
canvas.height = document.querySelector("canvas").offsetHeight;
var canvasHeight = document.querySelector("canvas").offsetHeight;

var originX = canvas.width / 2;
var originY = canvas.height / 2;

var bigRadius = canvasHeight / 6;
var littleRadius = canvasHeight / 30;
var ellipseLength = 1.5;

var gap = canvasHeight / 14;
var littleGap = canvasHeight / 30;
var numSwatches = 16;
var steps = numSwatches / 2;
var rings = 3;
var saturationSteps = 100 / rings;
var strokeColor = "#000000";

let strokeHoverWidth = 5;

let zeroSatOffsetX = originX - canvas.width * 0.40;
let zeroSatOffsetY = originY + canvas.width * 0.3;

let zeroSatTextOffsetY = zeroSatOffsetY - 30;
let satRadius = bigRadius * 0.5;

var hoverId = null;

var swatches = {};

function toRads(degrees) {
    return degrees * (Math.PI / 180);
}

function drawCanvas() {
    ctx.fillStyle = "white";
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    ctx.fillStyle = "black";
    ctx.textAlign = "center";
    ctx.font = '16pt Helvetica';
    ctx.fillText("Gray", zeroSatOffsetX, zeroSatTextOffsetY);

    ctx.beginPath();
    ctx.arc(zeroSatOffsetX, zeroSatOffsetY, satRadius, 0, 2 * Math.PI, true);
    ctx.fillStyle = `hsl(0, 0%, ${state.lightness}%)`;
    ctx.fill();
    ctx.strokeStyle = strokeColor;
    // hoverId === "zero" ? ctx.lineWidth = strokeHoverWidth : ctx.lineWidth = 1;

    if (
        (state.activeBtn === "fore" && state.fg.chosenId === "zero") ||
        (state.activeBtn === "back" && state.bg.chosenId === "zero") ||
        (state.activeBtn === "link" && state.li.chosenId === "zero")) {
        ctx.strokeStyle = "#000000";
        ctx.lineWidth = strokeHoverWidth;
        ctx.setLineDash([5, 2]);
    }
    ctx.stroke();
    ctx.setLineDash([0]);
    ctx.lineWidth = 1;

    if (swatches["zero"]) {
        updateSwatch(swatches["zero"], 0, 0, state.lightness);
    } else {
        swatches["zero"] = new Swatch(zeroSatOffsetX, zeroSatOffsetY, "zero", satRadius, 0, 0, state.lightness);
    }

    for (var j = 0; j < rings; j++) {
        let adjustedNumSwatches = numSwatches + (j * steps);
        for (var i = 0; i < adjustedNumSwatches; i++) {
            let angle = 360 / adjustedNumSwatches;
            let x = originX + ((bigRadius + gap + (j * littleGap) + (j * littleRadius * 2)) * Math.cos(toRads(angle * i)));
            let y = originY + ((bigRadius + gap + (j * littleGap) + (j * littleRadius * 2)) * Math.sin(toRads(angle * i)));

            let hue = angle * i;
            let saturation = (j * saturationSteps + (100 - (saturationSteps * (rings - 1))));

            let id = `${j}-${i}`;

            ctx.beginPath();
            ctx.ellipse(x, y, littleRadius, littleRadius * ellipseLength, toRads(hue - 45), 0, 2 * Math.PI, false);
            ctx.fillStyle = `hsl(${hue}, ${saturation}%, ${state.lightness}%)`;
            ctx.fill();

            if (swatches[id]) {
                updateSwatch(swatches[id], hue, saturation, state.lightness);
            } else {
                swatches[id] = new Swatch(x, y, id, littleRadius, hue, saturation, state.lightness);
            }

            ctx.strokeStyle = strokeColor;
            // hoverId === id ? ctx.lineWidth = strokeHoverWidth : ctx.lineWidth = 1;

            if ((state.activeBtn === "fore" && state.fg.chosenId === id) ||
                (state.activeBtn === "back" && state.bg.chosenId === id) ||
                (state.activeBtn === "link" && state.li.chosenId === id)) {
                ctx.strokeStyle = "#000000";
                ctx.lineWidth = strokeHoverWidth;
                ctx.setLineDash([5, 2]);
            }
            ctx.stroke();
            ctx.setLineDash([0]);
            ctx.lineWidth = 1;
        }
    }

    // if (hoverId) {
    //   ctx.beginPath();
    //   ctx.arc(originX, originY, bigRadius, 0, 2 * Math.PI, false);
    //   ctx.fillStyle = swatches[hoverId].hsl;
    //   ctx.fill();
    //   ctx.closePath();
    //   ctx.lineWidth = 1;
    //   ctx.strokeStyle = strokeColor;
    //   ctx.stroke();
    // }
}

function checkCollision(swatches, x, y) {
    for (var s in swatches) {
        var left = swatches[s].x - swatches[s].radius;
        var right = swatches[s].x + swatches[s].radius;
        var top = swatches[s].y - swatches[s].radius;
        var bottom = swatches[s].y + swatches[s].radius;

        if (right >= x &&
            left <= x &&
            bottom >= y &&
            top <= y) {
            return swatches[s];
        }
    }
    return null;
}

canvas.onclick = function(e) {
    var swatch = checkCollision(swatches, e.offsetX, e.offsetY);
    if (!swatch) return;
    sendRuntimeMessage('updateChosenColor', swatch);
}

canvas.onmouseout = function() {
    hoverId = null;
    drawCanvas();
}

canvas.onmousemove = function(e) {
    var swatch = checkCollision(swatches, e.offsetX, e.offsetY);

    if (swatch) {
        hoverId = swatch.id;

        drawCanvas();

        canvas.style.cursor = 'pointer';
    } else {
        canvas.style.cursor = 'default';
    }
};

/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////

function saveStorage(obj, response) {
    response = response || (() => {});
    if (bIsChrome) {
        chrome.storage.sync.set({...obj }, response);
    } else {
        browser.storage.sync.set({...obj }, response);
    }
}

function getStorage(obj, response) {
    response = response || (() => {});
    if (bIsChrome) {
        chrome.storage.sync.get(obj, response);
    } else {
        browser.storage.sync.get(obj, response);
    }
}

function updateUi() {
    getStorage(null, theState => {
        state = theState;
        foreSwatch.style.background = state.fg.hsl;
        backSwatch.style.background = state.bg.hsl;
        linkSwatch.style.background = state.li.hsl;

        changeColorsCheckbox.checked = state.changeColors;
        alwaysCheckbox.checked = state.always;
        lightnessSlider.value = state.lightness;
        lightnessValue.childNodes[0].nodeValue = `${state.lightness}%`;

        setActiveColorButton();
        drawCanvas();
    });
}

function sendRuntimeMessage(message, payload, response) {
    if (bIsChrome) {
        chrome.runtime.sendMessage({ message, payload }, response);
    } else {
        browser.runtime.sendMessage({ message, payload }, response);
    }
}

if (bIsChrome) {
    chrome.storage.onChanged.addListener(updateUi);
} else {
    browser.storage.onChanged.addListener(updateUi);
}

window.onload = updateUi;