/** * Copyright (c) Cisco Systems, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ import { customElementWithCheck } from "@/mixins"; import { LitElement, html, property } from "lit-element"; import styles from "./scss/module.scss"; import "@momentum-ui/web-components/dist/comp/md-icon"; import "@momentum-ui/web-components/dist/comp/md-dropdown"; import "@momentum-ui/web-components/dist/comp/md-input"; import "@momentum-ui/web-components/dist/comp/md-loading"; import { nothing } from "lit-html"; import "../condition/Condition"; export namespace ConditionBlock { @customElementWithCheck("cjaas-condition-block") export class ELEMENT extends LitElement { @property() relation: "AND" | "OR" | undefined; @property() innerRelation: "AND" | "OR" | undefined; @property({ type: Boolean, reflect: true }) root = false; @property() conditions: ConditionBlockInterface | string | undefined; @property({ type: Number }) index = 0; @property() optionsList: any; getOperatorTemplate(index: number) { if (this.root || index === 0) { return nothing; } else if (index > 1 && this.relation) { return html`
${this.relation}
`; } else { return html`
{ this.triggerUpdate(); this.relationUpdated(ev); }} > `; } } relationUpdated(ev: CustomEvent) { this.relation = ev.detail.option; this.dispatchEvent( new CustomEvent("relation-updated", { detail: { relation: this.relation } }) ); } getConditionBlockTemplate(x: any, index: number) { const _relation: any = x.logic; return html` this.setRelation(ev)} @delete-block=${(ev: CustomEvent) => this.deleteBlock(ev)} @updated-condition=${(ev: CustomEvent) => this.updateCondition(ev)} .optionsList=${this.optionsList} > `; } getDefaultConditionTemplate() { return html` this.updateCondition(ev)} @add-condition=${(ev: CustomEvent) => this.addNewCondition(ev, 0)} @add-condition-block=${(ev: CustomEvent) => this.addNewConditionBlock(ev, 0)} > `; } getConditionTemplate(x: string, i: number) { return html` this.deleteCondition(ev, i)} @relation-updated=${(ev: CustomEvent) => this.setRelation(ev)} @updated-condition=${(ev: CustomEvent) => this.updateCondition(ev)} @add-condition=${(ev: CustomEvent) => this.addNewCondition(ev, i)} @add-condition-block=${(ev: CustomEvent) => this.addNewConditionBlock(ev, i)} > `; } setRelation(ev: CustomEvent) { this.innerRelation = ev.detail.relation; if ((this.conditions as MultiLineCondition)?.args && this.innerRelation) { (this.conditions as MultiLineCondition).logic = this.innerRelation; } this.triggerUpdate(); } render() { return html` ${this.getOperatorTemplate(this.index)}
${(this.conditions as MultiLineCondition)?.args ? this.renderMultipleConditions() : this.renderSingleOrDefault()}
`; } renderSingleOrDefault() { if (typeof this.conditions === "string") { return this.getConditionTemplate(this.conditions, 0); } else if (this.conditions?.logic === "SINGLE") { return this.getConditionTemplate(this.conditions.condition, 0); } else { return this.getDefaultConditionTemplate(); } } renderMultipleConditions() { return (this.conditions as MultiLineCondition).args.map((x: any, i: number) => { if (this.isConditionBlock(x)) { return this.getConditionBlockTemplate(x, i); } else if (x) { return this.getConditionTemplate(x, i); } else if (!x) { return this.getConditionTemplate(x, i); } }); } updateCondition(event: CustomEvent) { // update this condition const index = event.detail.fromIndex; const elements: any = this.shadowRoot?.querySelectorAll(".block-container>*"); if (elements) { const _value = elements.item(index).getValue(); if (_value) { this.addConditionToList(index, _value); } } this.triggerUpdate(); this.requestUpdate(); } upsertMultiLineCondition(index: number, _value: any, type: "INSERT" | "UPDATE" = "UPDATE") { if (type === "UPDATE") { (this.conditions as MultiLineCondition).args[index] = _value; } else { (this.conditions as MultiLineCondition).args.splice(index, 0, _value); } } upsertConditionAsString(_value: any, type: "INSERT" | "UPDATE" = "UPDATE") { if (type === "UPDATE") { this.conditions = _value; } else { const oldCondition: string = this.conditions as string; this.conditions = { args: [oldCondition, _value], logic: this.innerRelation as "AND" | "OR" }; } } upsertSingleLineCondition(_value: any, type: "INSERT" | "UPDATE" = "UPDATE") { if (type === "INSERT") { const oldCondition: SingleLineCondition = this.conditions as SingleLineCondition; this.conditions = { args: [oldCondition.condition, _value], logic: "AND" }; } else { this.conditions = _value; } } addConditionToList(index: number, _value: any, type: "INSERT" | "UPDATE" = "UPDATE") { if ((this.conditions as MultiLineCondition)?.args) { this.upsertMultiLineCondition(index, _value, type); } else if (index === 0) { this.conditions = _value; } else if (typeof this.conditions === "string") { this.upsertConditionAsString(_value, type); } else if ((this.conditions as SingleLineCondition)?.logic === "SINGLE") { this.upsertSingleLineCondition(_value, type); } else { if (type === "INSERT") { this.conditions = { args: [_value], logic: "AND" }; } } } addNewCondition(event: CustomEvent, index: number) { this.addConditionToList(index + 1, "", "INSERT"); this.requestUpdate(); } addNewConditionBlock(event: CustomEvent, index: number) { this.addConditionToList( index + 1, { args: [""], logic: "AND" }, "INSERT" ); this.requestUpdate(); } deleteItem(i: number) { const array = (this.conditions as MultiLineCondition).args.slice(); array.splice(i, 1); (this.conditions as MultiLineCondition).args = array; if (array.length === 0) { this.dispatchEvent( new CustomEvent("delete-block", { detail: { index: this.index } }) ); } } deleteCondition(ev: CustomEvent, i: number) { if ((this.conditions as MultiLineCondition)?.args) { this.deleteItem(i); } else if ((this.conditions as SingleLineCondition)?.logic === "SINGLE") { this.conditions = ""; } this.requestUpdate(); } deleteBlock(ev: CustomEvent) { const i = ev.detail.index; this.deleteItem(i); this.requestUpdate(); } static get styles() { return styles; } public getValue() { const relation = this.innerRelation || "AND"; const nodes = this.shadowRoot?.querySelectorAll(".block-container>*"); nodes?.forEach((x, index: number) => { const value = (x as any).getValue(); this.addConditionToList(index, value); }); if (typeof this.conditions === "string" && this.root) { return { logic: "SINGLE", condition: this.conditions }; } else if (typeof this.conditions === "string") { return { args: [this.conditions], logic: relation }; } else if ((this.conditions as SingleLineCondition)?.logic === "SINGLE") { return { args: (this.conditions as SingleLineCondition).condition, logic: relation }; } else { return this.conditions; } } triggerUpdate() { this.dispatchEvent( new CustomEvent("updated-condition", { detail: { fromIndex: this.index, fromBlock: true } }) ); } isConditionBlock(x: any) { if (!x) { return false; } if (typeof x === "object" && x.args) { return true; } } } } declare global { interface HTMLElementTagNameMap { "cjaas-condition-block": ConditionBlock.ELEMENT; } } type ConditionBlockInterface = MultiLineCondition | SingleLineCondition; export interface MultiLineCondition { args: Array; logic: "AND" | "OR"; } export interface SingleLineCondition { logic: "SINGLE"; condition: string; }