/* global Module, MM, NCCFormatDuration */ Module.register("MMM-NextcloudCookbook", { defaults: { controlPath: "/MMM-NextcloudCookbook/control", controlUrl: "", animationSpeed: 400, shareUrl: "", sharePassword: "" }, start() { this.state = { active: false, recipe: null, error: null }; this.hiddenModules = false; this.sendSocketNotification("CONFIG", this.config); }, getStyles() { return ["MMM-NextcloudCookbook.css"]; }, getScripts() { return ["lib/format-duration.js"]; }, socketNotificationReceived(notification, payload) { if (notification !== "STATE") return; this.state = payload; this.setRecipeMode(Boolean(payload.active)); this.updateDom(this.config.animationSpeed); }, setRecipeMode(active) { if (active && !this.hiddenModules) { MM.getModules().exceptModule(this).enumerate((module) => { module.hide(this.config.animationSpeed, { lockString: this.name }); }); this.hiddenModules = true; } else if (!active && this.hiddenModules) { MM.getModules().exceptModule(this).enumerate((module) => { module.show(this.config.animationSpeed, { lockString: this.name }); }); this.hiddenModules = false; } }, getDom() { const root = document.createElement("section"); root.className = this.state.active ? "ncc-root ncc-active" : "ncc-root ncc-idle"; const qr = document.createElement("a"); qr.className = "ncc-qr"; qr.href = this.config.controlUrl || this.config.controlPath; qr.setAttribute("aria-label", "Open recipe controller"); const qrLabel = document.createElement("span"); qrLabel.textContent = "Recipe mode control:"; const qrImage = document.createElement("img"); qrImage.src = "/MMM-NextcloudCookbook/qr.svg"; qrImage.alt = "Recipe controller QR code"; qr.append(qrLabel, qrImage); root.appendChild(qr); if (!this.state.active) return root; if (this.state.error) { const error = document.createElement("p"); error.className = "ncc-error"; error.textContent = this.state.error; root.appendChild(error); return root; } if (!this.state.recipe) { const loading = document.createElement("p"); loading.className = "ncc-loading"; loading.textContent = "Loading recipe…"; root.appendChild(loading); return root; } root.appendChild(this.renderRecipe(this.state.recipe)); return root; }, renderRecipe(recipe) { const article = document.createElement("article"); article.className = "ncc-recipe"; const header = document.createElement("header"); const title = document.createElement("h1"); title.textContent = recipe.name || "Untitled recipe"; header.appendChild(title); const metadata = [ ["Yield", recipe.recipeYield], ["Prep", NCCFormatDuration(recipe.prepTime)], ["Cook", NCCFormatDuration(recipe.cookTime)], ["Total", NCCFormatDuration(recipe.totalTime)] ].filter(([, value]) => value); if (metadata.length) { const list = document.createElement("dl"); list.className = "ncc-meta"; metadata.forEach(([label, value]) => { const term = document.createElement("dt"); term.textContent = label; const detail = document.createElement("dd"); detail.textContent = value; list.append(term, detail); }); header.appendChild(list); } article.appendChild(header); const columns = document.createElement("div"); columns.className = "ncc-columns"; const ingredients = document.createElement("section"); const ingredientsTitle = document.createElement("h2"); ingredientsTitle.textContent = "Ingredients"; ingredients.appendChild(ingredientsTitle); const ingredientList = document.createElement("ul"); (recipe.recipeIngredient || []).forEach((ingredient) => { const item = document.createElement("li"); item.textContent = ingredient; ingredientList.appendChild(item); }); ingredients.appendChild(ingredientList); const instructions = document.createElement("section"); const instructionsTitle = document.createElement("h2"); instructionsTitle.textContent = "Instructions"; instructions.appendChild(instructionsTitle); const instructionList = document.createElement("ol"); this.flattenInstructions(recipe.recipeInstructions || []).forEach((step) => { const item = document.createElement("li"); item.textContent = step; instructionList.appendChild(item); }); instructions.appendChild(instructionList); columns.append(ingredients, instructions); article.appendChild(columns); return article; }, flattenInstructions(instructions) { return instructions.flatMap((instruction) => { if (typeof instruction === "string") return [instruction]; if (Array.isArray(instruction.itemListElement)) { return this.flattenInstructions(instruction.itemListElement); } return instruction.text ? [instruction.text] : []; }); } });