Skip to content

Commit

Permalink
refactor custom-ui-only (#132)
Browse files Browse the repository at this point in the history
* refactor custom-ui-only

clear all more-info remnants

add color to Entity card ! thank you @elchininet

rename Hooks

add some comments

* console.groupCollapsed

* add attributes icon_color and templates

in description constants

* add hook for core button-card

* Update custom-ui-only.js
  • Loading branch information
Mariusthvdb committed Jan 11, 2024
1 parent f8cb658 commit 127153a
Showing 1 changed file with 82 additions and 114 deletions.
196 changes: 82 additions & 114 deletions custom-ui-only.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
// Define constants for the custom-ui component
const Name = "Custom-ui";
const Version = "20230802";
const Description = "add icon_color and templates";
const Name = "Custom-ui only";
const Version = "20240110";
const Description = "add attributes icon_color and templates";
const Url = "https://github.com/Mariusthvdb/custom-ui";

// Log information about the custom-ui component
console.info(
`%c ${Name} \n%c Version ${Version} ${Description}`,
console.groupCollapsed(
`%c ${Name} ${Version} is installed \n%c ${Description} `,
"color: gold; font-weight: bold; background: black",
"color: white; font-weight: bold; background: steelblue"
);
"color: white; font-weight: bold; background: steelblue"),
console.log("Readme:",Url),
console.groupEnd()

// Define the custom-ui object and its methods
window.customUI = {
// Helper function to find an element either in shadowRoot or regular DOM
// Helper function to find an element either in shadowRoot or regular DOM
lightOrShadow: (elem, selector) =>
elem.shadowRoot
? elem.shadowRoot.querySelector(selector)
: elem.querySelector(selector),
// Apply template attributes to an entity's attributes

// Apply template attributes to an entity's attributes
async maybeApplyTemplateAttributes(hass, states, entity) {
const newAttributes = {};
const templateKeys = Object.keys(entity.attributes.templates);
Expand Down Expand Up @@ -52,82 +54,9 @@ window.customUI = {
};
return newEntity;
},
// Update the more-info dialog to hide certain attributes based on custom logic
// async updateMoreInfo(ev) {
// if (!ev.detail.expanded) return;
// const moreInfoInfo = document
// .querySelector("home-assistant")
// .shadowRoot.querySelector("ha-more-info-dialog")
// .shadowRoot.querySelector("ha-dialog")
// .getElementsByClassName("content")[0]
// .querySelector("ha-more-info-info");
//
// try {
// let t;
// {
// let moreInfoNodeName;
// const contentChild = moreInfoInfo.shadowRoot.querySelector(
// "more-info-content"
// ).childNodes;
// for (const nodeItem of contentChild) {
// if (nodeItem.nodeName.toLowerCase().startsWith("more-info-")) {
// moreInfoNodeName = nodeItem.nodeName.toLowerCase();
// break;
// }
// }
// if (moreInfoNodeName == "more-info-group") {
// let moreInfoNestedNodeName;
// const contentChildNested =
// moreInfoInfo.shadowRoot
// .querySelector("more-info-group")
// .shadowRoot.childNodes;
// for (const nodeItemNested of contentChildNested) {
// if (
// nodeItemNested.nodeName.toLowerCase().startsWith("more-info-")
// ) {
// moreInfoNestedNodeName = nodeItemNested.nodeName.toLowerCase();
// break;
// }
// }
// t = moreInfoInfo.shadowRoot
// .querySelector("more-info-group")
// .shadowRoot.querySelector(moreInfoNestedNodeName)
// .shadowRoot.querySelector("ha-attributes")
// .shadowRoot.querySelectorAll(".data-entry");
// } else {
// t = moreInfoInfo.shadowRoot
// .querySelector(moreInfoNodeName)
// .shadowRoot.querySelector("ha-attributes")
// .shadowRoot.querySelectorAll(".data-entry");
// }
// }
// if (t.length) {
// let e;
// for (const node of t) {
// const o = node.getElementsByClassName("key")[0];
// if (o.innerText.toLowerCase().trim() == "hide attributes") {
// e = o.parentNode
// .getElementsByClassName("value")[0]
// .innerText.split(",")
// .map((item) => item.replace("_", " ").trim());
// e.push("hide attributes");
// }
// }
// for (const node of t) {
// const o = node.getElementsByClassName("key")[0];
// if (
// e.includes(o.innerText.toLowerCase().trim()) ||
// e.includes("all")
// ) {
// o.parentNode.style.display = "none";
// }
// }
// }
// } catch (err) {}
// },

// Install a hook to update the states with template attributes
installStatesHook() {
// Install a hook to update the states with template attributes
installTemplateAttributesHook() {
customElements.whenDefined("home-assistant").then(() => {
const homeAssistant = customElements.get("home-assistant");
if (!homeAssistant?.prototype?._updateHass) return;
Expand All @@ -146,9 +75,9 @@ window.customUI = {
obj.states,
entity
);
if (hass.states && entity !== hass.states[key]) {
if (hass.states && JSON.stringify(entity) !== JSON.stringify(hass.states[key])) {
obj.states[key] = newEntity;
} else if (entity !== newEntity) {
} else if (JSON.stringify(entity) !== JSON.stringify(newEntity)) {
obj.states[key] = newEntity;
}
});
Expand All @@ -157,8 +86,57 @@ window.customUI = {
};
});
},
// Install a hook to update the state badge with custom styling
installStateBadge() {

// Install a hook to update the button card with custom styling
installButtonCardStylingHook() {
customElements.whenDefined("hui-button-card").then(() => {
const buttonCard = customElements.get("hui-button-card");
if (!buttonCard) return;
if (buttonCard.prototype?.updated) {
const originalUpdated = buttonCard.prototype.updated;
buttonCard.prototype.updated = function customUpdated(changedProps) {
if (!changedProps.has('_stateObj')) {
return;
}
const { _stateObj } = this;
if (_stateObj.attributes?.icon_color) {
this.style?.setProperty('--icon-primary-color', _stateObj.attributes.icon_color);
}
originalUpdated.call(this, changedProps);
}
}
});
},

// Install a hook to update the entity card with custom styling
installEntityCardStylingHook() {
customElements.whenDefined("hui-entity-card").then(() => {
const entityCard = customElements.get("hui-entity-card");
if (!entityCard) return;
if (entityCard.prototype?.updated) {
const originalUpdated = entityCard.prototype.updated;
entityCard.prototype.updated = function customUpdated(changedProps) {
if (
!changedProps.has('_config') ||
!changedProps.has('hass')
) {
return;
}
const { _config, hass } = this;
const entityId = _config?.entity;
const states = hass?.states;
const iconColor = states?.[entityId]?.attributes?.icon_color;
if (iconColor) {
this.style?.setProperty('--paper-item-icon-color', iconColor);
}
originalUpdated.call(this, changedProps);
}
}
});
},

// Install a hook to update the state badge with custom styling
installStateBadgeStylingHook() {
customElements.whenDefined("state-badge").then(() => {
const stateBadge = customElements.get("state-badge");
if (!stateBadge) return;
Expand All @@ -182,16 +160,20 @@ window.customUI = {
}
});
},
// Install the hooks for updating states and state badges
installClassHooks() {
window.customUI.installStatesHook();
window.customUI.installStateBadge();

// Install the hooks for updating states, entity cards, and state badges
installCustomHooks() {
window.customUI.installTemplateAttributesHook();
window.customUI.installButtonCardStylingHook();
window.customUI.installEntityCardStylingHook();
window.customUI.installStateBadgeStylingHook();
},

async init() {
// Check if initialization has already been done
// Check if initialization has already been done
if (window.customUI.initDone) return;

// Wait for the hass.states to be populated
// Wait for the hass.states to be populated
const main = window.customUI.lightOrShadow(document, "home-assistant");
await new Promise((resolve) => {
const intervalId = setInterval(() => {
Expand All @@ -202,22 +184,20 @@ window.customUI = {
}, 100);
});

// Install the hooks and mark initialization as done
window.customUI.installClassHooks();
// Install the hooks and mark initialization as done
window.customUI.installCustomHooks();
window.customUI.initDone = true;

// Add an event listener for expanded-changed events
// window.addEventListener("expanded-changed", window.customUI.updateMoreInfo);

// Push custom-ui information to a global list
// Push custom-ui information to a global list
window.CUSTOM_UI_LIST = window.CUSTOM_UI_LIST || [];
window.CUSTOM_UI_LIST.push({
name: Name,
version: `${Version} ${Description}`,
url: Url
});
},
// Evaluate a template expression

// Evaluate a template expression
computeTemplate(
template,
hass,
Expand Down Expand Up @@ -245,18 +225,6 @@ window.customUI = {
}
}
};

// Initialize the custom-ui component
window.customUI.init();


// The code you provided seems to be responsible for initializing and setting up some hooks in your application. Here are a few suggestions for potential improvements:
//
// Consolidate Hook Installation: Currently, the installClassHooks function checks if the hooks have already been installed and then sets a flag to avoid repeated installation. Instead of checking the flag in both installClassHooks and init functions, you can move the flag check to the init function and directly call installClassHooks without the need for a separate flag.
// Use setTimeout with Promises: In the init function, you're using setTimeout to delay the initialization if main.hass.states is falsy. Instead of using setTimeout, you can use await with a Promise to wait for a certain condition to be met. For example, you could wrap the initialization logic in a Promise and use await to delay the execution until main.hass.states is truthy.
// Error Handling in computeTemplate: In the computeTemplate function, you catch SyntaxError and ReferenceError exceptions and log a warning. However, you rethrow other types of exceptions. It might be beneficial to handle all types of exceptions consistently, either by logging warnings or by throwing them.

// Here are the applied recommendations:
//
// Consolidate Hook Installation: The flag check for installation has been moved to the init function, and the installClassHooks function is directly called without the need for a separate flag.
// Use setTimeout with Promises: The use of setTimeout has been replaced with await and a Promise to wait for the main.hass.states to be populated before initializing.
// Error Handling in computeTemplate: The error handling in computeTemplate has been updated to log a warning for all types of exceptions consistently.

0 comments on commit 127153a

Please sign in to comment.