Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BasicUI] Add support for icons based on conditional rules #2020

Merged
merged 1 commit into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 data-icon="%icon_set%:%icon_name%" src="../icon/%icon_name_in_url%?iconset=%icon_set_in_url%&format=%icon_type%&anyFormat=true&state=%state_in_url%" />
203 changes: 161 additions & 42 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,55 @@
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
splitIconAttr,
formRow = _t.formHeaderRow !== null ? _t.formHeaderRow : _t.formRow;

_t.iconSource = null;
_t.icon = formRow.querySelector(o.formIconImg);
if (_t.icon !== null) {
_t.iconSource = "oh";
splitIconAttr = _t.icon.getAttribute(o.iconAttribute).split(":");
if (splitIconAttr.length === 2) {
_t.iconSet = splitIconAttr[0];
_t.iconName = splitIconAttr[1];
}
return;
}
_t.icon = formRow.querySelector(o.formIconSvg);
if (_t.icon !== null) {
_t.iconSource = "oh";
splitIconAttr = _t.icon.getAttribute(o.iconAttribute).split(":");
if (splitIconAttr.length === 2) {
_t.iconSet = splitIconAttr[0];
_t.iconName = splitIconAttr[1];
}
return;
}
_t.icon = formRow.querySelector(o.formIconIconify);
if (_t.icon !== null) {
_t.iconSource = "if";
return;
}
_t.icon = formRow.querySelector(o.formIconMaterial);
if (_t.icon !== null) {
_t.iconSource = "material";
return;
}
_t.icon = formRow.querySelector(o.formIconFramework7);
if (_t.icon !== null) {
_t.iconSource = "f7";
}
};

function convertToInlineSVG() {
this.removeEventListener("load", convertToInlineSVG);
if (smarthome.UI.inlineSVG) {
Expand All @@ -386,14 +425,10 @@
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);
}
_t.findIcon();
if (_t.icon !== null && _t.iconSource === "oh") {
_t.icon.addEventListener("load", convertToInlineSVG);
_t.icon.addEventListener("error", replaceImageWithNone);
}

_t.replaceIconWithInlineSVG = function(svgText) {
Expand All @@ -416,11 +451,7 @@

// 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 +474,109 @@
});
};

_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;

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

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

_t.findIcon();
if (_t.iconSource === "oh") {
_t.icon.addEventListener("load", convertToInlineSVG);
_t.icon.addEventListener("error", replaceImageWithNone);
}
};

_t.reloadIcon = function(state, icon) {
var
src,
imgURL,
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) +
"?state=" + encodeURIComponent(state) +
"&iconset=" + encodeURIComponent(_t.iconSet) +
"&format=" + smarthome.UI.iconType +
"&anyFormat=true";
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") {
imgURL = "/icon/" + encodeURIComponent(iconName) +
"?iconset=" + encodeURIComponent(iconSet) +
"&format=" + smarthome.UI.iconType +
"&anyFormat=true";
if (_t.iconWithState && state.length < 200) {
imgURL += "&state=" + encodeURIComponent(state);
}
}
if (iconSrc === _t.iconSource) {
if (iconSrc === "oh") {
if (iconSet !== _t.iconSet || iconName !== _t.iconName) {
src = "<img data-icon=\"" + iconSet + ":" + iconName + "\" src=\".." + imgURL + "\" />";
_t.replaceIcon(src);
} else if (_t.icon.tagName.toLowerCase() === "img" && !_t.icon.src.endsWith(noneImageSrc)) {
_t.icon.addEventListener("error", replaceImageWithNone);
_t.icon.setAttribute("src", imgURL);
} else if (_t.icon.tagName.toLowerCase() === "svg" && smarthome.UI.inlineSVG) {
_t.getSVGIconAndReplaceWithInline(imgURL, 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 (iconSrc === "oh") {
src = "<img data-icon=\"" + iconSet + ":" + iconName + "\" src=\".." + imgURL + "\" />";
} 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 = "/icon/" + encodeURIComponent(_t.iconName) +
"?iconset=" + encodeURIComponent(_t.iconSet) +
"&format=" + smarthome.UI.iconType +
"&anyFormat=true";
src = null;
}
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 (src !== null) {
_t.replaceIcon(src);
}
}
};
Expand All @@ -486,8 +597,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 +631,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 @@ -2465,7 +2576,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 +2641,8 @@
data = JSON.parse(payload.data),
itemIncluded = false,
state = "NULL",
title;
title,
icon;

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

title = _t.getTitleFromLabel(data.label);

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

if (
(data.widgetId === smarthome.UI.page) &&
(title !== null)
Expand All @@ -2585,7 +2699,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 +2768,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 @@ -2931,6 +3047,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