Skip to content

Commit

Permalink
[BasicUI] Use inline SVG for "colorless" SVG icons
Browse files Browse the repository at this point in the history
Related to #1743

Use a HTML svg element (inline SVG) instead of a img element
when the icon servlet returns a SVG icon containing "currentColor".

Then it is possible to adjust the color of these icons by using the
iconcolor sitemapo attribute.

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
  • Loading branch information
lolodomo committed Mar 18, 2023
1 parent 6836ce5 commit 5d3468b
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 21 deletions.
9 changes: 9 additions & 0 deletions bundles/org.openhab.ui.basic/web-src/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@
height: 28px;
}
}
svg {
width: 32px;
height: 32px;
object-fit: contain;
html.ui-layout-condensed & {
width: 28px;
height: 28px;
}
}
iconify-icon {
font-size: 32px;
vertical-align: middle;
Expand Down
92 changes: 71 additions & 21 deletions bundles/org.openhab.ui.basic/web-src/smarthome.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,13 @@
_t.visible = !_t.formRow.classList.contains(o.formRowHidden);
_t.label = _t.parentNode.parentNode.querySelector(o.formLabel);

function convertToInlineSVG() {
this.removeEventListener("load", convertToInlineSVG);
_t.getSVGIconAndReplaceWithInline(this.src, true, null);
}

function replaceImageWithNone() {
this.removeEventListener("load", convertToInlineSVG);
this.removeEventListener("error", replaceImageWithNone);
this.src = noneImageSrc;
}
Expand All @@ -349,36 +355,78 @@
_t.iconSet = splittedIconAttr[0];
_t.iconName = splittedIconAttr[1];
if (_t.icon.src !== noneImageSrc) {
_t.icon.addEventListener("load", convertToInlineSVG);
_t.icon.addEventListener("error", replaceImageWithNone);
}
}

_t.replaceIconWithInlineSVG = function(svgText) {
var
parser,
docSvg,
newIconElement,
dataIcon;

// Parse the SVG text and turn it into DOM nodes
parser = new DOMParser();
docSvg = parser.parseFromString(svgText, "image/svg+xml");
newIconElement = docSvg.querySelector("svg");

// Keep the attribute data-icon
dataIcon = _t.icon.getAttribute("data-icon");
if (dataIcon !== null) {
newIconElement.setAttribute("data-icon", dataIcon);
}

// Replace the current icon element with the built inline SVG
_t.iconContainer.replaceChild(newIconElement, _t.icon);
_t.icon = _t.parentNode.parentNode.querySelector(o.formIconSvg);
};

_t.getSVGIconAndReplaceWithInline = function(srcUrl, checkCurrentColor, defaultSVG) {
// fetch(srcUrl, { cache: "force-cache" }).then(function(response) {
fetch(srcUrl).then(function(response) {
if (response.ok && response.headers.get("content-type") === "image/svg+xml") {
response.text().then(function(data) {
if (!checkCurrentColor || data.indexOf("currentColor") !== -1) {
_t.replaceIconWithInlineSVG(data);
} else if (defaultSVG !== null) {
_t.replaceIconWithInlineSVG(defaultSVG);
}
});
} else if (defaultSVG !== null) {
_t.replaceIconWithInlineSVG(defaultSVG);
}
}).catch(function() {
if (defaultSVG !== null) {
_t.replaceIconWithInlineSVG(defaultSVG);
}
});
};

_t.reloadIcon = function(state) {
var
src;

// Some widgets don't have icons
if (_t.icon !== null) {
_t.icon.addEventListener("error", replaceImageWithNone);
if (state.length < 200) {
_t.icon.setAttribute("src",
"/icon/" +
encodeURIComponent(_t.iconName) +
"?state=" +
encodeURIComponent(state) +
"&iconset=" +
encodeURIComponent(_t.iconSet) +
"&format=" +
smarthome.UI.iconType +
"&anyFormat=true"
);
src = "/icon/" + encodeURIComponent(_t.iconName) +
"?state=" + encodeURIComponent(state) +
"&iconset=" + encodeURIComponent(_t.iconSet) +
"&format=" + smarthome.UI.iconType +
"&anyFormat=true";
} else {
src = "/icon/" + encodeURIComponent(_t.iconName) +
"?iconset=" + encodeURIComponent(_t.iconSet) +
"&format=" + smarthome.UI.iconType +
"&anyFormat=true";
}
if (_t.icon.tagName.toLowerCase() === "img") {
_t.icon.addEventListener("error", replaceImageWithNone);
_t.icon.setAttribute("src", src);
} else {
_t.icon.setAttribute("src",
"/icon/" +
encodeURIComponent(_t.iconName) +
"?iconset=" +
encodeURIComponent(_t.iconSet) +
"&format=" +
smarthome.UI.iconType +
"&anyFormat=true"
);
_t.getSVGIconAndReplaceWithInline(src, false, "<svg/>");
}
}
};
Expand Down Expand Up @@ -428,6 +476,7 @@

_t.destroy = function() {
if (_t.icon !== null) {
_t.icon.removeEventListener("load", convertToInlineSVG);
_t.icon.removeEventListener("error", replaceImageWithNone);
}

Expand Down Expand Up @@ -2444,6 +2493,7 @@
formRadioControl: ".mdl-radio__button",
formIcon: ".mdl-form__icon",
formIconImg: ".mdl-form__icon img",
formIconSvg: ".mdl-form__icon svg",
formLabel: ".mdl-form__label",
uiLoadingBar: ".ui__loading",
layoutTitle: ".mdl-layout-title",
Expand Down

0 comments on commit 5d3468b

Please sign in to comment.