UNPKG

@jinntec/fore

Version:

Fore - declarative user interfaces in plain HTML

162 lines (142 loc) 4.82 kB
import { evaluateXPath, evaluateXPathToString, resolveId } from '../xpath-evaluation.js'; import FxControl from './fx-control.js'; import { Fore } from '../fore.js'; import { XPathUtil } from '../xpath-util.js'; /** * FxItems provides a templated list over its bound nodes. It is not standalone but expects to be used * within an fx-control element. * * * * @demo demo/selects3.html */ export class FxItems extends FxControl { static get properties() { return { ...super.properties, valueAttr: { type: String, }, }; } constructor() { super(); this.valueAttr = this.hasAttribute('value') ? this.getAttribute('value') : null; } connectedCallback() { super.connectedCallback(); // Some other library is stealing focus when clicking on the label of a checkbox list. // The browser should handle this, but we need to manually focus the checkbox if the label is pressed // TODO: find a better solution this.addEventListener('mousedown', e => { // const items = this.querySelectorAll('[value]'); if (!Fore.isWidget(e.target)) { e.preventDefault(); e.stopImmediatePropagation(); } if (e.target.nodeName === 'LABEL') { const target = resolveId(e.target.getAttribute('for'), this); target.focus(); } }); // Some other library is stealing focus when clicking on the label of a checkbox list. // The browser should handle this, but we need to manually focus the checkbox if the label is pressed // TODO: find a better solution this.addEventListener('mousedown', e => { const items = this.querySelectorAll('[value]'); if (e.target.nodeName === 'LABEL') { const target = resolveId(e.target.getAttribute('for'), this); target.focus(); } }); this.addEventListener('click', e => { e.preventDefault; e.stopPropagation(); const items = this.querySelectorAll('[value]'); let target; if (e.target.nodeName === 'LABEL') { target = resolveId(e.target.getAttribute('for'), this); target.checked = !target.checked; } let val = ''; Array.from(items).forEach(item => { if (item.checked) { val += ` ${item.getAttribute('value')}`; } }); this.setAttribute('value', val.trim()); // ### check for parent control const parentBind = XPathUtil.getClosest('[ref]', this.parentNode); if (!parentBind) return; const modelitem = parentBind.getModelItem(); const setval = this.shadowRoot.getElementById('setvalue'); setval.setValue(modelitem, val.trim()); setval.actionPerformed(); }); } getWidget() { return this; } async updateWidgetValue() { // console.log('setting items value'); const parentBind = XPathUtil.getClosest('[ref]', this.parentNode); if (parentBind) { this.value = parentBind.value; } this.setAttribute('value', this.value); } /** * Updates an entry by setting the label and the value. * * Will connect label and control with `for` attribute with generated id. * * attention: limitations here: assumes that there's an `label` element plus an element with an `value` * attribute which it will update. * * * * @param newEntry * @param node */ updateEntry(newEntry, node) { // console.log('fx-items updateEntry', this.value); // ### create unique id to connect label and input const id = Fore.createUUID(); // ### handle 'label' const label = newEntry.querySelector('label'); const lblExpr = Fore.getExpression(label.textContent); // ### xml / JSON if (node.nodeType) { const lblEvaluated = evaluateXPathToString(lblExpr, node, this); label.textContent = lblEvaluated; } else { const labelExpr = Fore.getExpression(lblExpr); label.textContent = node[labelExpr]; } label.setAttribute('for', id); // ### handle the 'value' // getting element which has 'value' attr const input = newEntry.querySelector('[value]'); // getting expr const expr = input.value; // const cutted = expr.substring(1, expr.length - 1); const cutted = Fore.getExpression(expr); let evaluated; if (node.nodeType) { evaluated = evaluateXPathToString(cutted, node, newEntry); } else { evaluated = node[cutted]; } // adding space around value to allow matching of 'words' const spaced = ` ${evaluated} `; const valAttr = ` ${this.getAttribute('value')} `; input.value = evaluated; input.setAttribute('id', id); if (valAttr.indexOf(spaced) !== -1) { input.checked = true; } } } if (!customElements.get('fx-items')) { customElements.define('fx-items', FxItems); }