Skip to content

Commit

Permalink
[BasicUI] Add support for icons based on conditional rules
Browse files Browse the repository at this point in the history
Depends on openhab/openhab-core#3820 and openhab#1998

Signed-off-by: Laurent Garnier <[email protected]>
  • Loading branch information
lolodomo committed Oct 4, 2023
1 parent 23550c6 commit d567078
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public ItemUIRegistry getItemUIRegistry() {
* @return HTML code
*/
protected String preprocessSnippet(String originalSnippet, Widget w) {
return preprocessSnippet(originalSnippet, w, w.getStaticIcon() != null);
return preprocessSnippet(originalSnippet, w, w.getStaticIcon() != null || !w.getIconRules().isEmpty());
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<img data-icon="%icon_set%:%icon_name%" src="../icon/%icon_name_in_url%?state=%state_in_url%&iconset=%icon_set_in_url%&format=%icon_type%&anyFormat=true" />
<img src="../icon/%icon_name_in_url%?state=%state_in_url%&iconset=%icon_set_in_url%&format=%icon_type%&anyFormat=true" />
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<img data-icon="%icon_set%:%icon_name%" src="../icon/%icon_name_in_url%?iconset=%icon_set_in_url%&format=%icon_type%&anyFormat=true" />
<img src="../icon/%icon_name_in_url%?iconset=%icon_set_in_url%&format=%icon_type%&anyFormat=true" />
197 changes: 150 additions & 47 deletions bundles/org.openhab.ui.basic/web-src/smarthome.js
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,7 @@
var
_t = this,
suppress = false,
noneImageSrc = "/icon/none.png",
splittedIconAttr;
noneImageSrc = "/icon/none.png";

_t.parentNode = parentNode;
if (_t.formRow === undefined) {
Expand All @@ -364,15 +363,46 @@
if (_t.headerRow !== null) {
_t.formHeaderRow = _t.formRow.previousElementSibling;
_t.iconContainer = _t.formHeaderRow.querySelector(o.formIcon);
_t.icon = _t.formHeaderRow.querySelector(o.formIconImg);
_t.label = _t.formHeaderRow.querySelector(o.formLabel);
} else {
_t.formHeaderRow = null;
_t.iconContainer = _t.formRow.querySelector(o.formIcon);
_t.icon = _t.formRow.querySelector(o.formIconImg);
_t.label = _t.formRow.querySelector(o.formLabel);
}

_t.findIcon = function() {
var
formRow = _t.formHeaderRow !== null ? _t.formHeaderRow : _t.formRow;

_t.iconSource = null;
_t.icon = formRow.querySelector(o.formIconImg);
if (_t.icon !== null) {
_t.iconSource = "oh";
} else {
_t.icon = formRow.querySelector(o.formIconSvg);
if (_t.icon !== null) {
_t.iconSource = "oh";
} else {
_t.icon = formRow.querySelector(o.formIconIconify);
if (_t.icon !== null) {
_t.iconSource = "if";
} else {
_t.icon = formRow.querySelector(o.formIconMaterial);
if (_t.icon !== null) {
_t.iconSource = "material";
} else {
_t.icon = formRow.querySelector(o.formIconFramework7);
if (_t.icon !== null) {
_t.iconSource = "f7";
}
}
}
}
}
};

_t.findIcon();

function convertToInlineSVG() {
this.removeEventListener("load", convertToInlineSVG);
if (smarthome.UI.inlineSVG) {
Expand All @@ -386,41 +416,25 @@
this.src = noneImageSrc;
}

if (_t.icon !== null) {
splittedIconAttr = _t.icon.getAttribute(o.iconAttribute).split(":");
_t.iconSet = splittedIconAttr[0];
_t.iconName = splittedIconAttr[1];
if (_t.icon.src !== noneImageSrc) {
_t.icon.addEventListener("load", convertToInlineSVG);
_t.icon.addEventListener("error", replaceImageWithNone);
}
if (_t.icon !== null && _t.iconSource === "oh" && _t.icon.src !== noneImageSrc) {
_t.icon.addEventListener("load", convertToInlineSVG);
_t.icon.addEventListener("error", replaceImageWithNone);
}

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

// 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);
if (_t.headerRow !== null) {
_t.icon = _t.formHeaderRow.querySelector(o.formIconSvg);
} else {
_t.icon = _t.formRow.querySelector(o.formIconSvg);
}
_t.findIcon();
};

_t.getSVGIconAndReplaceWithInline = function(srcUrl, checkCurrentColor, defaultSVG) {
Expand All @@ -443,29 +457,110 @@
});
};

_t.reloadIcon = function(state) {
_t.replaceIcon = function(htmlText) {
var
src;
parser,
doc,
newIconElement;

// Parse the HTML text and turn it into DOM nodes
parser = new DOMParser();
doc = parser.parseFromString(htmlText, "text/html");
newIconElement = doc.body.firstChild;

// Replace the current icon element
_t.iconContainer.replaceChild(newIconElement, _t.icon);
_t.findIcon();
};

_t.reloadIcon = function(state, icon) {
var
src,
splitIcon,
iconSrc = "oh",
iconSet = "classic",
iconName = "none";

// Some widgets don't have icons
if (_t.icon !== null && _t.iconWithState) {
if (state.length < 200) {
src = "/icon/" + encodeURIComponent(_t.iconName) +
if (_t.icon === null) {
return;
}

if (icon === undefined) {
// No reload expected
return;
}

splitIcon = icon.split(":");
if (splitIcon.length === 1) {
iconName = splitIcon[0];
} else if (splitIcon.length === 2) {
iconSrc = splitIcon[0];
iconName = splitIcon[1];
} else if (splitIcon.length === 3) {
iconSrc = splitIcon[0];
iconSet = splitIcon[1];
iconName = splitIcon[2];
}
if (iconSrc === "iconify") {
iconSrc = "if";
}

if (iconSrc === "oh") {
if (_t.iconWithState && state.length < 200) {
src = "/icon/" + encodeURIComponent(iconName) +
"?state=" + encodeURIComponent(state) +
"&iconset=" + encodeURIComponent(_t.iconSet) +
"&iconset=" + encodeURIComponent(iconSet) +
"&format=" + smarthome.UI.iconType +
"&anyFormat=true";
} else {
src = "/icon/" + encodeURIComponent(_t.iconName) +
"?iconset=" + encodeURIComponent(_t.iconSet) +
src = "/icon/" + encodeURIComponent(iconName) +
"?iconset=" + encodeURIComponent(iconSet) +
"&format=" + smarthome.UI.iconType +
"&anyFormat=true";
}
if (_t.icon.tagName.toLowerCase() === "img") {
_t.icon.addEventListener("error", replaceImageWithNone);
_t.icon.setAttribute("src", src);
} else if (smarthome.UI.inlineSVG) {
_t.getSVGIconAndReplaceWithInline(src, false, "<svg/>");
}
if (iconSrc === _t.iconSource) {
if (iconSrc === "oh") {
// TODO inline SVG
if (_t.icon.tagName.toLowerCase() === "img") {
_t.icon.addEventListener("error", replaceImageWithNone);
_t.icon.setAttribute("src", src);
} else if (smarthome.UI.inlineSVG) {
_t.getSVGIconAndReplaceWithInline(src, false, "<svg/>");
}
} else if (iconSrc === "if") {
_t.icon.setAttribute("icon", encodeURIComponent(iconSet) + ":" + encodeURIComponent(iconName));
} else if (iconSrc === "material" || iconSrc === "f7") {
_t.icon.innerHTML = iconName;
}
} else {
// Different icon source => DOM element to be be replaced

if (_t.iconSource === "oh" && _t.icon.src !== noneImageSrc) {
_t.icon.removeEventListener("load", convertToInlineSVG);
_t.icon.removeEventListener("error", replaceImageWithNone);
}

if (iconSrc === "oh") {
src = "<img src=\".." + src + "\" />";
} else if (iconSrc === "if") {
src = "<iconify-icon icon=\"" +
encodeURIComponent(iconSet) + ":" + encodeURIComponent(iconName) +
"\"></iconify-icon>";
} else if (iconSrc === "material") {
src = "<span class=\"material-icons\">" + iconName + "</span>";
} else if (iconSrc === "f7") {
src = "<span class=\"f7-icons\">" + iconName + "</span>";
} else {
src = null;
}
if (src !== null) {
_t.replaceIcon(src);
if (_t.iconSource === "oh" && _t.icon.src !== noneImageSrc) {
_t.icon.addEventListener("load", convertToInlineSVG);
_t.icon.addEventListener("error", replaceImageWithNone);
}
}
}
};
Expand All @@ -486,8 +581,8 @@
_t.visible = state;
};

_t.setValue = function(value, itemState, visible) {
_t.reloadIcon(itemState);
_t.setValue = function(value, itemState, visible, icon) {
_t.reloadIcon(itemState, icon);
if (suppress) {
suppress = false;
} else {
Expand Down Expand Up @@ -520,7 +615,7 @@
};

_t.destroy = function() {
if (_t.icon !== null) {
if (_t.icon !== null && _t.iconSource === "oh") {
_t.icon.removeEventListener("load", convertToInlineSVG);
_t.icon.removeEventListener("error", replaceImageWithNone);
}
Expand Down Expand Up @@ -2025,7 +2120,8 @@
_t.valueNode.innerHTML = value;
}
if (_t.locked) {
_t.reloadIcon(itemState);
// TODO Is reloadIcon expected here ?
// _t.reloadIcon(itemState);
return;
}
if (value.indexOf(" ") > 0) {
Expand Down Expand Up @@ -2465,7 +2561,7 @@
if (value === null) {
value = update.state;
}
widget.setValue(smarthome.UI.escapeHtml(value), update.state, update.visibility);
widget.setValue(smarthome.UI.escapeHtml(value), update.state, update.visibility, update.icon);
}

if (labelColor === "primary") {
Expand Down Expand Up @@ -2530,7 +2626,8 @@
data = JSON.parse(payload.data),
itemIncluded = false,
state = "NULL",
title;
title,
icon;

if (data.TYPE === "ALIVE") {
return;
Expand Down Expand Up @@ -2572,6 +2669,8 @@

title = _t.getTitleFromLabel(data.label);

icon = data.reloadIcon ? data.icon : undefined;

if (
(data.widgetId === smarthome.UI.page) &&
(title !== null)
Expand All @@ -2585,7 +2684,8 @@
label: data.label,
labelcolor: data.labelcolor,
valuecolor: data.valuecolor,
iconcolor: data.iconcolor
iconcolor: data.iconcolor,
icon: icon
};
_t.updateWidget(smarthome.dataModel[data.widgetId], update);
}
Expand Down Expand Up @@ -2653,7 +2753,8 @@
label: widget.label,
labelcolor: widget.labelcolor,
valuecolor: widget.valuecolor,
iconcolor: widget.iconcolor
iconcolor: widget.iconcolor,
icon: widget.icon
};
_t.updateWidget(w, update);
}
Expand Down Expand Up @@ -2909,7 +3010,6 @@
itemStateAttribute: "data-item-state",
unitAttribute: "data-item-unit",
idAttribute: "data-widget-id",
iconAttribute: "data-icon",
iconTypeAttribute: "data-icon-type",
iconWithStateAttribute: "data-icon-with-state",
inlineSvgAttribute: "data-inline-svg",
Expand All @@ -2931,6 +3031,9 @@
formIcon: ".mdl-form__icon",
formIconImg: ".mdl-form__icon img",
formIconSvg: ".mdl-form__icon svg",
formIconIconify: ".mdl-form__icon iconify-icon",
formIconMaterial: ".material-icons",
formIconFramework7: ".f7-icons",
formLabel: ".mdl-form__label",
uiLoadingBar: ".ui__loading",
layoutTitle: ".mdl-layout-title",
Expand Down

0 comments on commit d567078

Please sign in to comment.