Pregunta

I have a frameless window with a titlebar set up much like in the node-webkit sample apps (that is, with buttons that have -webkit-app-region: no-drag; so that they accept user input).

Because I'd like my app to be completely themeable, I decided to implement the minimize/maximize/close buttons as SVG and manipulate their color/opacity through JavaScript.

Example

As an example, I have the following close button close.svg:

<svg class="close-icon" xmlns="http://www.w3.org/2000/svg" width="30" height="26">
    <g>
        <title>Close</title>
        <path class="close-icon-bg" fill="#c8c8c8" d="M0 0h30v26h-30z"/>
        <path class="close-icon-fg" d="M11.766 8l-1.766 1.766 3.221 3.221-3.221 3.247 1.766 1.766 3.221-3.247 3.247 3.247 1.766-1.766-3.247-3.247 3.247-3.221-1.766-1.766-3.247 3.221-3.221-3.221z"/>
    </g>
</svg>

I then have the following in my titlebar div:

<object id="close-btn" data="img/close.svg" type="image/svg+xml"></object>

Then in JavaScript I have the following:

function refreshTheme(theme) {

    var but2 = {
        "default": {
            "bg": {"color": "#000000", "opacity": "0.0"},
            "fg": {"color": "#000000", "opacity": "0.2"}
        },
        "hover": {
            "bg": {"color": "#ac4142", "opacity": "1.0"},
            "fg": {"color": "#e0e0e0", "opacity": "1.0"}
        },
        "click": {
            "bg": {"color": "#000000", "opacity": "1.0"},
            "fg": {"color": "#e0e0e0", "opacity": "1.0"}
        }
    };

    createButton("close", but2, dummy);
}

function createButton(name, theme, func) {
    var svgobj = document.getElementById(name + "-btn"), svg = svgobj.contentDocument;

    styleIcon(svg, name, theme.default);

    svgobj.onmouseover = function() {
        styleIcon(svg, name, theme.hover);
    };

    svgobj.onmouseout = function() {
        styleIcon(svg, name, theme.default);
    };

    svgobj.onmousedown = function() {
        styleIcon(svg, name, theme.click);
    };

    svgobj.onclick = function() {
        func();
    };
}

function styleIcon(icon, name, theme) {
    var bg = icon.getElementsByClassName(name + "-icon-bg")[0];
    bg.setAttribute("fill", theme.bg.color);
    bg.setAttribute("fill-opacity", theme.bg.opacity);

    var fg = icon.getElementsByClassName(name + "-icon-fg")[0];
    fg.setAttribute("fill", theme.fg.color);
    fg.setAttribute("fill-opacity", theme.fg.opacity);
}

Essentially what happens is, I have a hard-coded JSON object but2 encapsulating the button states, which I pass to createButton(), which is responsible for setting up the various mouse events. I can confirm that the onmouseover and onmouseout events work well:

Above is onmouseout, below is onmouseover

The top screenshot shows onmouseout, the bottom onmouseover.

The Problem

What doesn't work are the onmousedown and onclick events! They appear to be set up correctly in the debug window and no errors are present in the console, but they never get fired.

I was under the impression that <object> tags accept all standard HTML events, so this should work. Is there something I'm missing? Some node-webkit caveat maybe? Something to do with SVG's?

How can I get the onmousedown and onclick events to fire properly?

¿Fue útil?

Solución

It turns out this is an actual problem with SVG's in browsers. The solution, as noted here, is to have the SVG hold the mouse up/down/click events in a transparent (fill-opacity="0.0") rectangle spanning the whole image.

In my case, the solution was:

var svg_click = svg.getElementsByClassName(name + "-icon-click")[0];

svg_click.onmousedown = function() {
    styleIcon(svg, name, theme.click);
};

// etc...

I'm not terribly pleased with it, considering it should also work from the <object> tag, but hey...it's still a solution.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top