/***************************** Touch handler ************************************/
    
    var timerTouchDown;
    
    function touchHandler(event)
    {
        event.preventDefault();
        var touches = event.changedTouches,
            first = touches[0],
            type = "",
            mouseButton = 0;
        switch(event.type)
        {
            case "touchstart":
                type = "mousedown";
                break;
            case "touchmove":
                type = "mousemove";
                break;        
            case "touchend":
                type = "mouseup";
                break;
            default:
                return;
        }
        
        var simulatedEvent = document.createEvent("MouseEvent");
        simulatedEvent.initMouseEvent(type, true, true, window, 1, 
                                      first.screenX, first.screenY, 
                                      first.clientX, first.clientY, false, 
                                      false, false, false, mouseButton, null);
        first.target.dispatchEvent(simulatedEvent);
        event.preventDefault();
    }
    
    /**************************** END: Touch handler ***************************************/
    
    /***************************** Move Window function ************************************/
    
    function moveWindow(windowBlock, windowTitlebar) {
        var offsetX = 0, offsetY = 0, posX = 0, posY = 0;
        windowTitlebar.onmousedown = dragMouseDown;
        windowBlock.style.position = "absolute";
        function dragMouseDown(event) {
            event = event || window.event;
            event.preventDefault();
            posX = event.clientX;
            posY = event.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }
        function elementDrag(event) {
            event = event || window.event;
            event.preventDefault();
            offsetX = posX - event.clientX;
            offsetY = posY - event.clientY;
            posX = event.clientX;
            posY = event.clientY;
            
            windowBlock.style.top = (windowBlock.offsetTop - offsetY) + "px";
            windowBlock.style.left = (windowBlock.offsetLeft - offsetX) + "px";
        }
        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;
        }
    }
    
    function windowElementsClick(element, event) {
        
        if (document.onmouseup != null) {
            document.getElementById(element).classList.remove("offset_light");
        } else {
            document.getElementById(element).classList.add("offset_light");
        }
    }
    
    /************************** END: Move Window function **********************************/
    
    /***************************** HSL Line color changer NEW ************************************/
    
    function hslColorLineChanger(movingArea, colorCursor, maxValue, fieldResult) {
        movingArea = document.getElementById(movingArea);
        colorCursor = document.getElementById(colorCursor);
        
        movingArea.onmousedown = mouseDownEvent;
        colorCursor.onmousedown = mouseDownEvent;
        
        function mouseDownEvent(e) {
            var coords = getCoords(colorCursor);
            var shiftX = movingArea.offsetLeft - coords.left;
            
            moveAt(e);
            function moveAt(e) {
                var bounds = movingArea.getBoundingClientRect();
                var blockSizeX = parseInt(getComputedStyle(movingArea).width);
                var x = parseInt(e.clientX - bounds.left);
                
                if (x > blockSizeX)
                    x = parseInt(blockSizeX);
                if (x <= 0)
                    x = 0;
                
                
                colorCursor.style.left = parseInt(x - 6) + 'px';
                document.getElementById(fieldResult).value = Math.abs(parseInt(parseInt(x) / parseInt(blockSizeX) * maxValue));
                hueValuesChanged();
                changePickerCursor();
            }
            document.onmousemove = function(e) {
                moveAt(e);
            };
            document.onmouseup = function() {
                document.onmousemove = null;
                document.onmouseup = null;
            };
        }
        colorCursor.ondragstart = function() {
            return false;
        };
        function getCoords(elem) {
            var box = elem.getBoundingClientRect();
            return {
                left: box.left + pageXOffset
            };
        };
    }
    
    /************************** END: HSL Line color changer NEW **********************************/
    
    /*************************/
    /* Input filter function */
    
    function setInputFilter(textbox, inputFilter) {
        ["input", "keydown", "keyup", "mousedown", "mouseup", "select", "drop"].forEach(function(event) {
          textbox.addEventListener(event, function() {
            if (inputFilter(this.value)) {
              this.oldValue = this.value;
              this.oldSelectionStart = this.selectionStart;
              this.oldSelectionEnd = this.selectionEnd;
            } else if (this.hasOwnProperty("oldValue")) {
              this.value = this.oldValue;
              this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
            } else {
              this.value = "";
            }
          });
        });
    }
    
    /* END: Input filter function */
    /******************************/
    
    /**************************************************************************************/
    /***************************** Convert code functions *********************************/
    
    function HSLToRGB(h, s, l) {
        // Must be fractions of 1
        s /= 100;
        l /= 100;
        
        let c = (1 - Math.abs(2 * l - 1)) * s,
            x = c * (1 - Math.abs((h / 60) % 2 - 1)),
            m = l - c/2,
            r = 0,
            g = 0,
            b = 0;
        if (0 <= h && h < 60) {
            r = c; g = x; b = 0;  
        } else if (60 <= h && h < 120) {
            r = x; g = c; b = 0;
        } else if (120 <= h && h < 180) {
            r = 0; g = c; b = x;
        } else if (180 <= h && h < 240) {
            r = 0; g = x; b = c;
        } else if (240 <= h && h < 300) {
            r = x; g = 0; b = c;
        } else if (300 <= h && h < 360) {
            r = c; g = 0; b = x;
        }
        
        r = Math.round((r + m) * 255);
        g = Math.round((g + m) * 255);
        b = Math.round((b + m) * 255);
        
        return [r, g, b];
    }
    
    function RGBToHSL(r, g, b) {
        r /= 255, g /= 255, b /= 255;
        var max = Math.max(r, g, b), min = Math.min(r, g, b);
        var h, s, l = (max + min) / 2;
        if (max == min) {
            h = s = 0;
        } else {
            var d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch (max) {
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                case g: h = (b - r) / d + 2; break;
                case b: h = (r - g) / d + 4; break;
            }
            h /= 6;
        }
        return [parseInt(h * 360), parseInt(s * 100), parseInt(l * 100)];
    }
        
    function RGBToHex(r, g, b) {
        r = r.toString(16);
        g = g.toString(16);
        b = b.toString(16);
        if (r.length == 1)
            r = "0" + r;
        if (g.length == 1)
            g = "0" + g;
        if (b.length == 1)
            b = "0" + b;
        return "#" + r + g + b;
    }
    
    function RGBAToHexA(r, g, b, a) {
        r = r.toString(16);
        g = g.toString(16);
        b = b.toString(16);
        a = Math.round(a * 255).toString(16);
        if (r.length == 1)
            r = "0" + r;
        if (g.length == 1)
            g = "0" + g;
        if (b.length == 1)
            b = "0" + b;
        if (a.length == 1)
            a = "0" + a;
        return "#" + r + g + b + a;
    }
    
    function hexToRGB(h) {
        let r = 0, g = 0, b = 0;
        
        if (h.length == 3) {
            r = "0x" + h[0] + h[0];
            g = "0x" + h[1] + h[1];
            b = "0x" + h[2] + h[2];
        } else if (h.length == 6) {
            r = "0x" + h[0] + h[1];
            g = "0x" + h[2] + h[3];
            b = "0x" + h[4] + h[5];
        }
        
        return [+r, +g, +b];
    }
    
    function hexToHSL(h) {
        var rgb = hexToRGB(h);
        return RGBToHSL(rgb[0], rgb[1], rgb[2]);
    }
    
    function HSLAToRGBA(h, s, l, a) {
        var rgb = HSLToRGB(h, s, l);
        return [rgb[0], rgb[1], rgb[2], a];
    }
    
    function RGBAToHSLA(r, g, b, a) {
        var hsl = RGBToHSL(r, g, b);
        return [hsl[0], hsl[1], hsl[2], a];
    }
    
    function HSVtoHSL(h, s, v) {
        var _h = h,
            _s = s / 100 * v / 100,
            _l = (2 - (s / 100)) * v / 100;
        _s /= (_l <= 100) ? (_l === 0 ? 100 : _l) : 200 - _l;
        _l /= 2;
        return [_h, _s * 100, _l * 100];
    }
    
    function HSLtoHSV(h, s, l) {
        var _h = h,
            _s,
            _v;
        
        s = (s === 0) ? 0 : s / 100;
        l = (l === 0) ? 0 : l / 100;
        l *= 2;
        s *= (l <= 1) ? l : 2 - l;
        _v = ((l + s) === 0) ? 0 : (l + s) / 2;
        _s = ((l + s) === 0) ? 0 : (2 * s) / (l + s);
        return [_h, _s * 100, _v * 100];
    }
    
    /*************************** END: Convert code functions ******************************/
    
    /***************************** Interface variables ************************************/
    
    /* Fields */
    
    var hueNumberInput = document.getElementById("getcolor-hslcodeblock__hsl_h");
    var satNumberInput = document.getElementById("getcolor-hslcodeblock__hsl_s");
    var lightNumberInput = document.getElementById("getcolor-hslcodeblock__hsl_l");
    var alphaHSLNumberInput = document.getElementById("getcolor-hslcodeblock__hsl_a");
    
    var redInputValue = document.getElementById("getcolor-hexcodeblock__codefield_red");
    var greenInputValue = document.getElementById("getcolor-hexcodeblock__codefield_green");
    var blueInputValue = document.getElementById("getcolor-hexcodeblock__codefield_blue");
    var alphaNumberInput = document.getElementById("getcolor-hexcodeblock__codefield_alpha");
    
    var hexNumberInput = document.getElementById("getcolor-hexcodeblock__codefield_hex");
    
    /* END: Fields */
    
    /* Color gallery buttons */
    
    var colorGalleryButtons = document.getElementsByClassName("getcolor-colorsblock__color");
    
    /* END: Color gallery buttons */
    
    /************************* END: Interface variables ***********************************/
    
    /**************************** Output code strings *************************************/
    
    function getRGBString() {
        return  "rgb(" 
                + redInputValue.value + ", "
                + greenInputValue.value + ", "
                + blueInputValue.value + ")";
    }
    
    function getRGBAString() {
        return  "rgba(" 
                + redInputValue.value + ", "
                + greenInputValue.value + ", "
                + blueInputValue.value + ", "
                + alphaNumberInput.value + ")";
    }
    
    function getHSLString() {
        return  "hsl(" 
                + hueNumberInput.value + ", "
                + satNumberInput.value + "%, "
                + lightNumberInput.value + "%)";
    }
    
    function getHSLAString() {
        return  "hsla(" 
                + hueNumberInput.value + ", "
                + satNumberInput.value + "%, "
                + lightNumberInput.value + "%, "
                + alphaHSLNumberInput.value + ")";
    }
    
    function getHexString() {
        return RGBToHex(
            parseInt(redInputValue.value),
            parseInt(greenInputValue.value),
            parseInt(blueInputValue.value)
        );
    }
    
    function getHexAString() {
        return RGBAToHexA(
            parseInt(redInputValue.value),
            parseInt(greenInputValue.value),
            parseInt(blueInputValue.value),
            parseInt(alphaNumberInput.value)
        );
    }
    
    function getHSLArray(){
        return [parseInt(hueNumberInput.value),
            parseInt(satNumberInput.value),
            parseInt(lightNumberInput.value)];
    }
    
    /************************** END: Output code strings **********************************/
    /**************************************************************************************/
    
    /************************************/
    /* Functions for Popup info message */
    
    /* Timer for Message */
    var showMessageTimer;
    
    /* Shows message width %textMessage% */
    /* When timer is out message is close by closeMessage() */
    function showMessage(textMessage) {
        document.getElementById("message__text").textContent = textMessage;
        document.getElementById("message").style.transform = "translateY(8rem)";
        showMessageTimer = window.setTimeout(function(){closeMessage();}, 2500);
    }
    
    /* Close message and stop timer */
    function closeMessage() {
        window.clearTimeout(showMessageTimer);
        document.getElementById("message").style.transform = "translateY(-5rem)";
    }
    
    /* Message:on button close clicked */
    ["click", "touchend"].forEach(function(eventType){
        document.getElementById("message__btn-close").addEventListener(eventType, function() {
            closeMessage();
        });
    });
    
    /* END: Functions for Popup info message */
    /*****************************************/
    
    /***********************/
    /* Application starter */
    
    function startApplication() {
        document.getElementById("wrapper").style.opacity = "0.0";
        document.getElementById("app-interface").style.opacity = "1.0";
        window.setTimeout(function() {
            document.getElementById("wrapper").classList.toggle("unvisible");
            document.getElementById("app-interface").classList.toggle("unvisible");
            document.getElementById("app-interface").classList.toggle("no-selection");
        }, 50);
    }
    
    function closeApplication() {
        document.getElementById("app-interface").style.opacity = "0.0";
        document.getElementById("wrapper").style.opacity = "1.0";
        window.setTimeout(function() {
            document.getElementById("app-interface").classList.toggle("unvisible");
            document.getElementById("wrapper").classList.toggle("unvisible");
            document.getElementById("app-interface").classList.toggle("no-selection");
        }, 50);
        
        showMessage("Приложение закрыто, можно закрыть вкладку браузера");
    }
    
    /* END: Application starter */
    /****************************/
    
    /*****************************/
    /*        Dialog logic       */
    
    /* Dialog show function */
    function showDialog(dialogWidth, dialogHeight, dialogTitle, dialogContent) {
        document.getElementById("app-dialog__window").style.width = dialogWidth;
        document.getElementById("app-dialog__window").style.height = dialogHeight;
        document.getElementById("app-dialog__window").style.left = "calc(50% - " + (parseFloat(dialogWidth) / 2) + "rem)";
        document.getElementById("app-dialog__window").style.top = "calc(30% - " + (parseFloat(dialogHeight) / 2) + "rem)";
        document.getElementById("app-dialog").classList.toggle("unvisible");
        document.getElementById("app-dialog").style.opacity = "1.0";
        document.getElementById("app-dialog__titlebarcaption").textContent = dialogTitle;
        document.getElementById("getcolor-helpblock").innerHTML = dialogContent;
    }
    
    /*      END: Dialog logic    */
    /*****************************/
    
    /**********************/
    /* Main program logic */
    /* On App component clicked */
    document.getElementById("app").addEventListener("click", function() {
        closeMessage();
        startApplication();
        moveWindow(document.getElementById("app-interface__window"), document.getElementById("app-interface__titlebar"));
        moveWindow(document.getElementById("app-dialog__window"), document.getElementById("app-dialog__titlebar"));
        ["mousedown", "mouseup"].forEach(function(event) {
            document.getElementById("app-interface__titlebaricon").addEventListener(event, function(e) {
                windowElementsClick("app-interface__titlebaricon", e.type);
            });
            document.getElementById("app-interface__closebutton").addEventListener(event, function(e) {
                windowElementsClick("app-interface__closebutton", e.type);
            });
            document.getElementById("app-dialog__titlebaricon").addEventListener(event, function(e) {
                windowElementsClick("app-dialog__titlebaricon", e.type);
            });
            document.getElementById("app-dialog__closebutton").addEventListener(event, function(e) {
                windowElementsClick("app-dialog__closebutton", e.type);
            });
        });
        document.getElementById("app-interface__titlebaricon").addEventListener("mouseup", function(e) {
            windowElementsClick("app-interface__titlebaricon");
        });
        
        document.addEventListener("touchstart", touchHandler, true);
        document.addEventListener("touchmove", touchHandler, true);
        document.addEventListener("touchend", touchHandler, true);
        document.addEventListener("touchcancel", touchHandler, true);
        
        moveColorCursor("getcolor-pickerblock__picker-cursor", "getcolor-pickerblock__picker");
        
        hslColorLineChanger("getcolor-huelineblock__table", "getcolor-huelineblock__picker-cursor", 359, "getcolor-hslcodeblock__hsl_h");
        hslColorLineChanger("getcolor-satlineblock__table", "getcolor-satlineblock__picker-cursor", 100, "getcolor-hslcodeblock__hsl_s");
        hslColorLineChanger("getcolor-lightlineblock__table", "getcolor-lightlineblock__picker-cursor", 100, "getcolor-hslcodeblock__hsl_l");
        
        rgbValuesChanged();
    });
    
    /* On Window's titlebar icon clicked */
    ["click", "touchend"].forEach(function(eventType) {
        document.getElementById("app-interface__titlebaricon").addEventListener(eventType, function(){
            showMessage("Сервис получения кода цвета от Popov.Dev");
        });
    });
    
    /* On Window's titlebar close button clicked */
    ["click", "touchend"].forEach(function(eventType) {
        document.getElementById("app-interface__closebutton").addEventListener(eventType, function(){
            closeMessage();
            closeApplication();
        });
    });
    
    /* On Dialog's titlebar icon clicked */
    ["click", "touchend"].forEach(function(eventType) {
        document.getElementById("app-dialog__titlebaricon").addEventListener(eventType, function(){
            showMessage("Сервис получения кода цвета от Popov.Dev");
        });
    });
    
    /* On Dialog's titlebar close button clicked */
    ["click", "touchend"].forEach(function(eventType) {
        document.getElementById("app-dialog__closebutton").addEventListener(eventType, function(){
            closeMessage();
            document.getElementById("app-dialog").style.opacity = "0.0";
            document.getElementById("app-dialog").classList.toggle("unvisible");
        });
    });
    
    /***************************** Move color cursor function ************************************/
    
    function moveColorCursor(colorCursor, movingArea) {
        colorCursor = document.getElementById(colorCursor);
        movingArea = document.getElementById(movingArea);
        
        movingArea.onmousedown = function(e) {
            var coords = getCoords(colorCursor);
            var shiftX = movingArea.offsetLeft - coords.left;
            var shiftY = movingArea.offsetTop - coords.top;
      
            colorCursor.style.position = 'absolute';
            moveAt(e);
            function moveAt(e) {
                var bounds = movingArea.getBoundingClientRect();
                var blockSizeX = parseInt(getComputedStyle(movingArea).width);
                var blockSizeY = parseInt(getComputedStyle(movingArea).height);
                var x = parseInt(e.clientX - bounds.left);
                var y = parseInt(e.clientY - bounds.top);
                
                if (x >= blockSizeX)
                    x = parseInt(blockSizeX);
                if (x <= 0)
                    x = 0;
                if (y >= blockSizeY)
                    y = parseInt(blockSizeY);
                if (y <= 0)
                    y = 0;
                
                colorCursor.style.left = parseInt(x - 6) + 'px';
                colorCursor.style.top = parseInt(y - 6) + 'px';
                satNumberInput.value = Math.abs(parseInt(parseInt(x) / parseInt(blockSizeX) * 100));
                lightNumberInput.value = Math.abs(parseInt(parseInt(y) / parseInt(blockSizeY) * 50) - 50);
                hueValuesChanged();
                changeLinePickerCursor()
            }
            document.onmousemove = function(e) {
                moveAt(e);
            };
            document.onmouseup = function() {
                document.onmousemove = null;
                document.onmouseup = null;
            };
        };
        colorCursor.ondragstart = function() {
            return false;
        };
        function getCoords(elem) {
            var box = elem.getBoundingClientRect();
            return {
                top: box.top + pageYOffset,
                left: box.left + pageXOffset
            };
        };
    }
    
    /************************** END: Move color cursor function **********************************/
    
    /******************************* HSL BLOCK ****************************************************/
    /* On field input hue */
    setInputFilter(hueNumberInput, function(value) {
        if (value.length > 1)
            hueNumberInput.value = parseInt(hueNumberInput.value);
        
        if (value > 360)
            hueNumberInput.value = 360;
        return /^\d*$/.test(value);
    });
    
    /* On field input sat */
    setInputFilter(satNumberInput, function(value) {
        if (value.length > 1)
            satNumberInput.value = parseInt(satNumberInput.value);
        
        if (value > 100)
            satNumberInput.value = 100;
        return /^\d*$/.test(value);
    });
    
    /* On field input light */
    setInputFilter(lightNumberInput, function(value) {
        if (value.length > 1)
            lightNumberInput.value = parseInt(lightNumberInput.value);
        
        if (value > 100)
            lightNumberInput.value = 100;
        return /^\d*$/.test(value);
    });
    
    // On field input number of alpha
    setInputFilter(alphaHSLNumberInput, function(value) {
        if (parseFloat(value) > parseFloat(1.0))
            alphaHSLNumberInput.value = '1.0';
        return /^[10]?\.?\d*$/.test(value);
    });
    
    
    /******************************* END: HSL BLOCK ***********************************************/
    
    /********************* RGBA-HEX BLOCK **********************************************************/
    /* On field input number of Red */
    setInputFilter(redInputValue, function(value) {
        if (value.length > 1)
            redInputValue.value = parseInt(redInputValue.value);
        
        if (value > 255)
            redInputValue.value = 255;
        return /^\d*$/.test(value);
    });
    
    /* On field input number of Green */
    setInputFilter(greenInputValue, function(value) {
        if (value.length > 1)
            greenInputValue.value = parseInt(greenInputValue.value);
        
        if (value > 255)
            greenInputValue.value = 255;
        return /^\d*$/.test(value);
    });
    
    /* On field input number of Blue */
    setInputFilter(blueInputValue, function(value) {
        if (value.length > 1)
            blueInputValue.value = parseInt(blueInputValue.value);
        
        if (value > 255)
            blueInputValue.value = 255;
        return /^\d*$/.test(value);
    });
    
    // On field input number of alpha
    setInputFilter(alphaNumberInput, function(value) {
        if (parseFloat(value) > parseFloat(1.0))
            alphaNumberInput.value = '1.0';
        return /^[10]?\.?\d*$/.test(value);
    });
    
    /* On field input HEX number */
    setInputFilter(hexNumberInput, function(value) {
        return /^[\dabcdefABCDEF]*$/.test(value);
    });
    /********************* END: RGBA-HEX BLOCK *******************************************************/
    
    /**************************** Mouse numbers scrolling ********************************************/
    
    /* On alpha numbers mouse scrolling event */
    [alphaHSLNumberInput, alphaNumberInput].forEach(function(alphaFields) {
        alphaFields.addEventListener("wheel", function(event) {
            if (event.deltaY < 0) {
                if (parseFloat(alphaFields.value).toPrecision(2) < parseFloat(1.0).toPrecision(2))
                    alphaFields.value = parseFloat(parseFloat(alphaFields.value) + parseFloat(0.1)).toPrecision(2);
            } else {
                if (parseFloat(alphaFields.value).toPrecision(2) > parseFloat(0.0).toPrecision(2)) {
                    alphaFields.value = parseFloat(parseFloat(alphaFields.value) - parseFloat(0.1)).toPrecision(2);
                }
            }
            
            if (alphaFields.id.includes("hsl")) {
                hueValuesChanged();
                changePickerCursor();
                changeLinePickerCursor();
            } else {
                rgbValuesChanged();
            }
        });
    });
    
    /* On RGB numbers mouse scrolling event */
    [redInputValue, greenInputValue, blueInputValue].forEach(function(rgbFields) {
        rgbFields.addEventListener("wheel", function(event) {
            if (event.deltaY < 0) {
                if (parseInt(rgbFields.value) < parseInt(255))
                    rgbFields.value = parseInt(parseInt(rgbFields.value) + parseInt(1));
            } else {
                if (parseInt(rgbFields.value) > parseInt(0))
                    rgbFields.value = parseInt(parseInt(rgbFields.value) - parseInt(1));
            }
            
            rgbValuesChanged();
        });
    });
    
    /* On hue number mouse scrolling event */
    hueNumberInput.addEventListener("wheel", function(event) {
        if (event.deltaY < 0) {
            if (parseInt(hueNumberInput.value) < parseInt(359))
                hueNumberInput.value = parseInt(parseInt(hueNumberInput.value) + parseInt(1));
        } else {
            if (parseInt(hueNumberInput.value) > parseInt(0))
                hueNumberInput.value = parseInt(parseInt(hueNumberInput.value) - parseInt(1));
        }
        
        hueValuesChanged();
        changePickerCursor();
        changeLinePickerCursor();
    });
    
    /* On SL numbers mouse scrolling event */
    [satNumberInput, lightNumberInput].forEach(function(slFields) {
        slFields.addEventListener("wheel", function(event) {
            if (event.deltaY < 0) {
                if (parseInt(slFields.value) < parseInt(100))
                    slFields.value = parseInt(parseInt(slFields.value) + parseInt(1));
            } else {
                if (parseInt(slFields.value) > parseInt(0))
                    slFields.value = parseInt(parseInt(slFields.value) - parseInt(1));
            }
            
            hueValuesChanged();
            changePickerCursor();
            changeLinePickerCursor();
        });
    });
    
    
    /**************************** Mouse numbers scrolling ********************************************/
    
    /********************* Buttons block *************************************************************/
    
    /* On copy color code button clicked */
    ["click", "touchend"].forEach(function(eventType) {
        document.getElementById("getcolor-buttonsblock__button_rgb").addEventListener(eventType, () => copyColorButton(getRGBString()));
        document.getElementById("getcolor-buttonsblock__button_rgba").addEventListener(eventType, () => copyColorButton(getRGBAString()));
        document.getElementById("getcolor-buttonsblock__button_hsl").addEventListener(eventType, () => copyColorButton(getHSLString()));
        document.getElementById("getcolor-buttonsblock__button_hsla").addEventListener(eventType, () => copyColorButton(getHSLAString()));
        document.getElementById("getcolor-buttonsblock__button_hex").addEventListener(eventType, () => copyColorButton(getHexString()));
        document.getElementById("getcolor-buttonsblock__button_hexa").addEventListener(eventType, () => copyColorButton(getHexAString()));
    });
    
    /* Copy to clipboard color code */
    function copyColorButton(copyString) {
        if (window.navigator.clipboard) {
            window.navigator.clipboard.writeText(copyString);
            showMessage("Скопировано: " + copyString);
        } else {
            try {
                fallbackTextCopy(copyString);
                showMessage("Скопировано: " + copyString);
            } catch(error) {
                showMessage("Ошибка копирования");
            }
        }
    }
    
    /* If browser not support Clipboard API */
    function fallbackTextCopy (text) {
        var tmpBlock = document.createElement("textarea");
        document.body.appendChild(tmpBlock);
        tmpBlock.value = text;
        tmpBlock.select();
        document.execCommand("copy");
        document.body.removeChild(tmpBlock);
    }
    
    /* On button change clicked */
    ["click", "touchend"].forEach(function(eventType) {
        document.getElementById("getcolor-buttonsblock__button_change").addEventListener(eventType, function() {
            document.getElementById("getcolor-buttonsblock__button_rgb").classList.toggle("unvisible");
            document.getElementById("getcolor-buttonsblock__button_rgba").classList.toggle("unvisible");
            document.getElementById("getcolor-buttonsblock__button_hsl").classList.toggle("unvisible");
            document.getElementById("getcolor-buttonsblock__button_hsla").classList.toggle("unvisible");
            document.getElementById("getcolor-buttonsblock__button_hex").classList.toggle("unvisible");
            document.getElementById("getcolor-buttonsblock__button_hexa").classList.toggle("unvisible");
        });
    });
    
    /* On button help clicked */
    ["click", "touchend"].forEach(function(eventType) {
        document.getElementById("getcolor-buttonsblock__button_help").addEventListener(eventType, function() {
            showDialog("20rem", "9rem", "Get Color! - Помощь", "<h2>Как добавлять цвета в библиотеку?</h2>\
                <p>Сверху уже есть готовые цвета, нажимая на выбранном цвете правой кнопкой или долгое нажатие для смартфонов на цвете, устанавливает в выбранной ячейке текущий цвет.</p><br> \
                <h2>Как вернуть старый цвет?</h2>\
                <p>В библиотеке готовых цветов необходимо зажать клавишу Ctrl или Cmd и сделать правый клик на выбранном цвете.</p><br> \
                <h2>Скопировать код HSLA, RGBA и HexA</h2> \
                <p>Необходимо нажать на кнопку <i class='fas fa-fill'></i> и затем нажать на одну из появившихся кнопок слева</p>");
        });
    });
    
    /* On button Color clicked */
    ["click", "touchend"].forEach(function(eventType) {
        document.getElementById("getcolor__color").addEventListener(eventType, function() {
            showDialog("20rem", "9rem", "Get Color! - свойства цвета", "<h2>Коды цвета</h2>\
                <a><p id='getcolor__color_rgb'>" + getRGBString() + "</p></a> \
                <a><p id='getcolor__color_rgba'>" + getRGBAString() + "</p></a> \
                <a><p id='getcolor__color_hsl'>" + getHSLString() + "</p></a> \
                <a><p id='getcolor__color_hsla'>" + getHSLAString() + "</p></a> \
                <a><p id='getcolor__color_hex'>" + getHexString() + "</p></a> \
                <a><p id='getcolor__color_hexa'>" + getHexAString() + "</p></a>");
            
            ["getcolor__color_rgb", "getcolor__color_rgba", "getcolor__color_hsl",
             "getcolor__color_hsla", "getcolor__color_hex", "getcolor__color_hexa"].forEach(function(colorLink) {
                if (document.getElementById(colorLink).getAttribute('function') !== 'true') {
                    document.getElementById(colorLink).setAttribute('function', 'true');
                    document.getElementById(colorLink).addEventListener(eventType, () => copyColorButton(
                        document.getElementById(colorLink).textContent));
                }
            });
        });
    });
    
    /******************** END: Buttons Block *********************************************************/
    
    /*********************** Input logic **************************/
    
    ["focusout", "change"].forEach(function(event) {
        [hueNumberInput, satNumberInput, lightNumberInput, alphaHSLNumberInput].forEach(function(changedElement) {
            changedElement.addEventListener(event, function() {
                hueValuesChanged();
                changePickerCursor();
                changeLinePickerCursor();
            });
        });
        [redInputValue, greenInputValue, blueInputValue, alphaNumberInput].forEach(function(changedElement) {
            changedElement.addEventListener(event, function() {
                rgbValuesChanged();
            });
        });
        hexNumberInput.addEventListener(event, function() {
            hexValueChanged();
        });
    });
    
    /******************** END: Input logic ************************/
    
    /************************ HSL line event **********************/
    
    function setHueValue(value) {
        hueNumberInput.value = value;
        hueValuesChanged();
        changePickerCursor();
        changeLinePickerCursor();
    }
    
    function setSatValue(value) {
        satNumberInput.value = value;
        hueValuesChanged();
        changePickerCursor();
        changeLinePickerCursor();
    }
    
    function setLightValue(value) {
        lightNumberInput.value = value;
        hueValuesChanged();
        changePickerCursor();
        changeLinePickerCursor();
    }
    
    /********************* END: HSL line event ********************/
    
    /******************** Change Value Events *********************/
    
    function hueValuesChanged() {
        var rgba = HSLAToRGBA(
            parseInt(hueNumberInput.value),
            parseInt(satNumberInput.value),
            parseInt(lightNumberInput.value),
            parseFloat(alphaHSLNumberInput.value)
        );
        
        var hex = RGBToHex(
            parseInt(rgba[0]),
            parseInt(rgba[1]),
            parseInt(rgba[2])
        );
        
        redInputValue.value = rgba[0];
        greenInputValue.value = rgba[1];
        blueInputValue.value = rgba[2];
        alphaNumberInput.value = rgba[3].toPrecision(2);
        hexNumberInput.value = hex.slice(1);
        
        changeSLLinesColor();
        setMainColor();
        changePickerColor();
    }
    
    function rgbValuesChanged() {
        var hsla = RGBAToHSLA(
            parseInt(redInputValue.value),
            parseInt(greenInputValue.value),
            parseInt(blueInputValue.value),
            parseFloat(alphaNumberInput.value)
        );
        
        var hex = RGBToHex(
            parseInt(redInputValue.value),
            parseInt(greenInputValue.value),
            parseInt(blueInputValue.value)
        );
        
        hueNumberInput.value = hsla[0];
        satNumberInput.value = hsla[1];
        lightNumberInput.value = hsla[2];
        alphaHSLNumberInput.value = hsla[3].toPrecision(2);
        hexNumberInput.value = hex.slice(1);
        
        changeSLLinesColor();
        setMainColor();
        changePickerColor();
        changePickerCursor();
        changeLinePickerCursor();
    }
    
    function hexValueChanged() {
        var rgb = hexToRGB(hexNumberInput.value);
        var hsl = hexToHSL(hexNumberInput.value);
        
        redInputValue.value = rgb[0];
        greenInputValue.value = rgb[1];
        blueInputValue.value = rgb[2];
        alphaNumberInput.value = "1.0";
        
        hueNumberInput.value = hsl[0];
        satNumberInput.value = hsl[1];
        lightNumberInput.value = hsl[2];
        alphaHSLNumberInput.value = "1.0";
        
        changeSLLinesColor();
        setMainColor();
        changePickerColor();
        changePickerCursor();
        changeLinePickerCursor();
    }
    
    function changePickerColor() {
        var hue = parseInt(hueNumberInput.value);
        document.getElementById("getcolor-pickerblock__picker").style.background = "linear-gradient(90deg, hsl(" + hue + ", 100%, 100%) 0%, hsl(" + hue + ", 100%, 50%) 100%)";
    }
    
    function changePickerCursor() {
        var pickerArea = document.getElementById("getcolor-pickerblock__picker"),
            pickerCursor = document.getElementById("getcolor-pickerblock__picker-cursor"),
            hsv = HSLtoHSV(parseInt(hueNumberInput.value),
                           parseInt(satNumberInput.value),
                           parseInt(lightNumberInput.value)),
            cursorPosX = parseInt(hsv[1] / 100 * parseInt(getComputedStyle(pickerArea).width)),
            cursorPosY = parseInt(Math.abs(hsv[2] / 100 * parseInt(getComputedStyle(pickerArea).height) - 100));
        
        pickerCursor.style.left = parseInt(cursorPosX - 6) + 'px';
        pickerCursor.style.top = parseInt(cursorPosY - 6) + 'px';
    }
    
    function changeLinePickerCursor() {
        colorCursors = [document.getElementById("getcolor-huelineblock__picker-cursor"),
            document.getElementById("getcolor-satlineblock__picker-cursor"),
            document.getElementById("getcolor-lightlineblock__picker-cursor")];
        movingAreaSize = parseInt(getComputedStyle(document.getElementById("getcolor-huelineblock__table")).width);
        hsl = getHSLArray();
        
        colorCursors[0].style.left = parseInt(hsl[0] / 360 * movingAreaSize - 4) + 'px';
        colorCursors[1].style.left = parseInt(hsl[1] / 100 * movingAreaSize - 4) + 'px';
        colorCursors[2].style.left = parseInt(hsl[2] / 100 * movingAreaSize - 4) + 'px';
    }
    
    function changeSLLinesColor() {
        changeSatLineColor();
        changeLightLineColor();
    }
    
    function changeSatLineColor() {
        var node = '<td class="getcolor-satlineblock__line" style="background:linear-gradient(to right, hsl(' 
            + parseInt(hueNumberInput.value) + ',0%,50%),hsl(' + parseInt(hueNumberInput.value) + ',100%,50%))"></td>';
        
        document.getElementById("getcolor-satlineblock__table").innerHTML = "<tbody><tr>" + node + "</tr></tbody>";
    }
    
    function changeLightLineColor() {
        var node = '<td class="getcolor-lightlineblock__line" style="background:linear-gradient(to right, hsl('
            + parseInt(hueNumberInput.value) + ',100%,0%),hsl(' + parseInt(hueNumberInput.value) + ',100%,50%),hsl('
            + parseInt(hueNumberInput.value) + ',100%,100%))"></td>';
        
        document.getElementById("getcolor-lightlineblock__table").innerHTML = "<tbody><tr>" + node + "</tr></tbody>";
    }
    
    function setMainColor() {
        document.getElementById("getcolor__color").style.backgroundColor = getRGBAString();
    }
    
    /***************** END: Change Value Events *******************/
    
    /****************** Color gallery Block **********************/
    
    for (var i = 0; i <= 47; i++) {
        ["click", "touchend"].forEach(function(eventType){
            colorGalleryButtons[i].addEventListener(eventType, function(event) {
                var colorData = window.getComputedStyle(this, null).getPropertyValue("background-color");
                var [r,g,b,a] = colorData.match(/[\d\.]+/g).map(Number);
                
                if (!colorData.includes("rgba")) {
                    a = parseFloat(1.0);
                }
                
                redInputValue.value = r;
                greenInputValue.value = g;
                blueInputValue.value = b;
                alphaNumberInput.value = a.toPrecision(2);
                rgbValuesChanged();
            });
        });
        
        colorGalleryButtons[i].addEventListener("mouseup", function(event) {
            window.clearTimeout(timerTouchDown);
        });
        
        colorGalleryButtons[i].addEventListener("mousedown", function(event) {
            var galleryButton = this.id;
            timerTouchDown = window.setTimeout(function() {
                setGalleryButton(event, galleryButton);
            }, 500);
            return;
        });
        
        colorGalleryButtons[i].addEventListener("contextmenu", function(event) {
            event.preventDefault();
            setGalleryButton(event, this.id);
        });
        
        function setGalleryButton(event, galleryButton) {
            galleryButton = document.getElementById(galleryButton);
            if (event.ctrlKey || event.metaKey) {
                galleryButton.removeAttribute("style");
            } else {
                galleryButton.style.backgroundColor = getRGBAString();
            }
        }
    }
    
    /*************** END: Color gallery Block *******************/
    
    /* END: Main program logic */
    /***************************/