iobroker.schedule-switcher
Version:
Switch states over scheduler
285 lines (256 loc) • 12.2 kB
JavaScript
(async () => {
class ConditionAction extends HTMLElement {
constructor() {
super();
this.sr = this.createShadowRoot();
this.data = "{}";
this.actionType = "";
this.sr.querySelector("#withConstant").addEventListener("click", this.onWithConstantClick.bind(this));
this.sr
.querySelector("#selectConditionStateId1")
.addEventListener("change", this.onConditionState1Change.bind(this));
this.sr
.querySelector("#selectConditionStateId2")
.addEventListener("change", this.onConditionState2Change.bind(this));
this.sr.querySelector("#selectSign").addEventListener("change", this.onSignChange.bind(this));
this.sr
.querySelector("#inputConditionConstant")
.addEventListener("input", this.onConditionConstantInput.bind(this));
this.sr.querySelector(".button.delete").addEventListener("click", this.onConditionDeleteClick.bind(this));
}
connectedCallback() {
this.createConditionStateSelectOptions("#selectConditionStateId1");
this.createConditionStateSelectOptions("#selectConditionStateId2");
}
static get observedAttributes() {
return ["data", "edit"];
}
attributeChangedCallback(attr) {
if (attr === "data") {
this.onDataChange();
} else if (attr === "edit") {
this.onEditChange();
}
}
get withConstant() {
return this.sr.querySelector("#withConstant").classList.contains("checked");
}
set withConstant(withConstant) {
if (withConstant) {
this.sr.querySelector("#withConstant").classList.add("checked");
} else {
this.sr.querySelector("#withConstant").classList.remove("checked");
}
this.sr.querySelector(
`#${this.withConstant ? "inputConditionConstant" : "selectConditionStateId2"}`,
).style.display = null;
this.sr.querySelector(
`#${!this.withConstant ? "inputConditionConstant" : "selectConditionStateId2"}`,
).style.display = "none";
}
get parsedData() {
return JSON.parse(this.data);
}
set parsedData(data) {
this.setAttribute("data", JSON.stringify(data));
this.sr.dispatchEvent(new CustomEvent("data", { composed: true }));
}
get edit() {
const attrValue = this.getAttribute("edit");
return attrValue === "true";
}
set edit(value) {
this.setAttribute("edit", value ? "true" : "false");
}
onDataChange() {
const dataAttribute = this.getAttribute("data");
if (this.data !== this.dataAttribute) {
this.data = dataAttribute;
const parsed = JSON.parse(this.data);
this.actionType = parsed.action.type;
this.showAction(parsed.action);
this.showCondition(parsed.condition);
}
}
onActionChanged() {
const data = JSON.parse(this.getAttribute("data"));
data.action = JSON.parse(this.getActionElement(true).getAttribute("data"));
this.setAttribute("data", JSON.stringify(data));
this.sr.dispatchEvent(new CustomEvent("data", { composed: true }));
}
onEditChange() {
if (this.edit) {
this.sr.querySelector(".container.edit").style.display = null;
this.sr.querySelector(".container.view").style.display = "none";
} else {
this.sr.querySelector(".container.edit").style.display = "none";
this.sr.querySelector(".container.view").style.display = null;
}
}
onWithConstantClick() {
const toggle = this.sr.querySelector("#withConstant");
toggle.classList.toggle("checked");
const data = this.parsedData;
if (this.withConstant) {
data.condition.type = "StringStateAndConstantCondition";
data.condition.stateId = data.condition.stateId1;
data.condition.constant = "true";
delete data.condition.stateId1;
delete data.condition.stateId2;
} else {
data.condition.type = "StringStateAndStateCondition";
data.condition.stateId1 = data.condition.stateId;
data.condition.stateId2 = data.condition.stateId;
delete data.condition.stateId;
delete data.condition.constant;
}
this.parsedData = data;
}
onConditionDeleteClick() {
this.sr.dispatchEvent(new CustomEvent("delete-condition", { composed: true }));
}
onConditionState1Change() {
const data = this.parsedData;
const select = this.sr.querySelector("#selectConditionStateId1");
const selectedValue = select.options[select.options.selectedIndex].value;
if (data.condition.type === "StringStateAndStateCondition") {
data.condition.stateId1 = selectedValue;
} else {
data.condition.stateId = selectedValue;
}
this.parsedData = data;
}
onConditionState2Change() {
const data = this.parsedData;
const select = this.sr.querySelector("#selectConditionStateId2");
data.condition.stateId2 = select.options[select.options.selectedIndex].value;
this.parsedData = data;
}
onSignChange() {
const data = this.parsedData;
const select = this.sr.querySelector("#selectSign");
data.condition.sign = select.options[select.options.selectedIndex].value;
this.parsedData = data;
}
onConditionConstantInput() {
const data = this.parsedData;
const select = this.sr.querySelector("#inputConditionConstant");
data.condition.constant = select.value;
this.parsedData = data;
}
getActionElement(edit) {
return this.sr.querySelector(
`.container.${edit ? "edit" : "view"} .action ${this.getElementNameForActionType(this.actionType)}`,
);
}
showAction(action) {
const elementName = this.getElementNameForActionType(action.type);
let actionView = this.sr.querySelector(`.container.view .action ${elementName}`);
if (!actionView) {
actionView = document.createElement(elementName);
actionView.setAttribute("edit", "false");
this.sr.querySelector(".container.view .action").appendChild(actionView);
}
let actionEdit = this.sr.querySelector(`.container.edit .action ${elementName}`);
if (!actionEdit) {
actionEdit = document.createElement(elementName);
actionEdit.setAttribute("edit", "true");
actionEdit.addEventListener("data", this.onActionChanged.bind(this));
this.sr.querySelector(".container.edit .action").appendChild(actionEdit);
}
actionView.setAttribute("data", JSON.stringify(action));
actionEdit.setAttribute("data", JSON.stringify(action));
}
showCondition(condition) {
// Wait for options of selects to be set
setTimeout(() => {
const viewDiv = this.sr.querySelector(`.container.view .condition`);
if (condition.type === "StringStateAndConstantCondition") {
this.withConstant = true;
this.sr.querySelector("#inputConditionConstant").value = condition.constant;
this.selectOption("#selectConditionStateId1", condition.stateId);
viewDiv.textContent = `${
this.conditionStateIdsAndAlias().find((s) => s.id === condition.stateId)?.alias
} ${condition.sign} ${condition.constant}`;
} else {
this.withConstant = false;
this.selectOption("#selectConditionStateId1", condition.stateId1);
this.selectOption("#selectConditionStateId2", condition.stateId2);
viewDiv.textContent = `${
this.conditionStateIdsAndAlias().find((s) => s.id === condition.stateId1)?.alias
} ${condition.sign} ${
this.conditionStateIdsAndAlias().find((s) => s.id === condition.stateId2)?.alias
}`;
}
this.selectOption("#selectSign", condition.sign);
}, 100);
}
getElementNameForActionType(type) {
if (type === "OnOffStateAction") {
return "app-on-off-state-action-schedule";
} else if (type === "ConditionAction") {
return "app-condition-action-schedule";
} else {
throw Error("No widget for action found");
}
}
createConditionStateSelectOptions(id) {
const selectConditionId = this.sr.querySelector(`.container.edit .condition-body ${id}`);
while (selectConditionId.firstChild !== null) {
selectConditionId.removeChild(selectConditionId.firstChild);
}
this.conditionStateIdsAndAlias().forEach((e) => {
const optionElement = document.createElement("option");
optionElement.text = `${e.alias} ${this.showConditionIds() ? `(${e.id})` : ``}`;
optionElement.value = e.id;
selectConditionId.appendChild(optionElement);
});
}
selectOption(id, option) {
for (const o of this.sr.querySelector(id).options) {
o.selected = o.value === option;
}
}
showConditionIds() {
return vis.widgets[this.getAttribute("widgetid")].data.showConditionIds;
}
conditionStateIdsAndAlias() {
return vis.binds["schedule-switcher"].getConditionStateIdsAndAlias(this.getAttribute("widgetid"));
}
createShadowRoot() {
const shadowRoot = this.attachShadow({ mode: "open" });
shadowRoot.innerHTML = `
<link rel="stylesheet" href="widgets/schedule-switcher/css/material-toggle-switch.css" />
<link rel="stylesheet" href="widgets/schedule-switcher/css/ConditionAction.css" />
<div class="container view">
<div class="action"></div>
<div class="condition"></div>
</div>
<div class="container edit" style="display: none">
<div class="action"></div>
<div class="condition-header">
<div>${vis.binds["schedule-switcher"].translate("condition")}</div>
<img class="button delete" src="widgets/schedule-switcher/img/delete-24px.svg" width="28px"
height="28px" title="${vis.binds["schedule-switcher"].translate("removeCondition")}"/>
</div>
<div class="condition-body">
<select id="selectConditionStateId1" required></select>
<select id="selectSign" required>
<option value="==">${vis.binds["schedule-switcher"].translate("equals")}</option>
<option value="!=">${vis.binds["schedule-switcher"].translate("equalsNot")}</option>
</select>
<div id="withConstant" class="md-switch-container">
<div class="md-switch-track"></div>
<div class="md-switch-handle"></div>
<div class="md-switch-label">${vis.binds["schedule-switcher"].translate("withConstant")}</div>
</div>
<select id="selectConditionStateId2"></select>
<input id="inputConditionConstant" type="text" style="display: none;"/>
</div>
</div>
`;
return shadowRoot;
}
}
customElements.define("app-condition-action-schedule", ConditionAction);
})();