@furo/ui5
Version:
SAP UI5 Web Components data bindings for furo-web
218 lines (198 loc) • 6.19 kB
JavaScript
import { LitElement, css } from 'lit';
import { FBP } from '@furo/fbp';
import { NodeEvent } from '@furo/framework/src/EventTreeNode.js';
/**
* `furo-ui5-property`
* Field for type **furo.Property**. This can be used to display "dynamic" fields aka properties.
*
* `furo-ui5-property` works with repeated types and non repeating property types.
*
* ```html
* <furo-ui5-property fn-bind-data="--entity(*.single_type_property)"></furo-ui5-property>
* ```
*
* **Example data for the data-object looks like this**
*
* ```json
* "single_type_property": {
* "data": {
* "@type": "google.type.Date",
* "day": 8,
* "month": 11,
* "year": 2022
* },
* "display_name": "a date",
* "id": "date",
* "code": "date",
* "meta": {
* "fields": {
* "data": {
* "meta": {
* "label": "Additional fields",
* "hint": "this is data"
* },
* "constraints": {
* "min": {
* "value": "2019-09-09",
* "message": "to small"
* }
* }
* }
* }
* }
* }
* ```
*
* @summary ????? bind types of type any
* @element
* @demo demo-furo-ui5-property
* @appliesMixin FBP
*/
export class FuroUi5Property extends FBP(LitElement) {
constructor() {
super();
// default context
this.context = 'form';
}
bindData(propertyField) {
this.field = propertyField;
if (propertyField._isRepeater) {
// we want a fresh list on every update of the list, because the types and order of the list items can change
// eslint-disable-next-line no-param-reassign
propertyField.clearListOnNewData = true;
// add flow repeat to parent and inject on repeated changes
// repeated
const r = document.createElement('flow-repeat');
r.setAttribute('identity-path', 'id._value');
let attrs = '';
const l = this.attributes.length;
// eslint-disable-next-line no-plusplus
for (let i = 0; i < l; ++i) {
const { nodeName } = this.attributes.item(i);
const { nodeValue } = this.attributes.item(i);
if (!nodeName.startsWith('@') && !nodeName.startsWith('ƒ')) {
attrs += `${nodeName}="${nodeValue}"`;
}
}
r.innerHTML = `<template><furo-ui5-property fn-bind-data='--init' ${attrs}></furo-ui5-property></template>`;
const repeater = this.parentNode.insertBefore(r, this);
this._createdRepeater = repeater;
this.field.addEventListener('this-repeated-field-changed', () => {
repeater.injectItems(this.field.repeats);
});
// inject if data is already here
if (this.field.repeats.length > 0) {
repeater.injectItems(this.field.repeats);
}
} else {
// data already in data-object
// eslint-disable-next-line no-lonely-if
if (this.field.data['@type']) {
this._createPropComponent(propertyField);
} else {
this.field.data.addEventListener(
'branch-value-changed',
() => {
this._createPropComponent(propertyField);
},
{ once: true }
);
}
}
}
/**
* @private
* @return {Object}
*/
static get properties() {
return {
/**
* Set the context, for the renderers.
*
* @type String
*/
context: { type: String },
};
}
/**
*
* @param propertyField
* @private
*/
_createPropComponent(propertyField) {
if (!this._property_created) {
const type = propertyField.data['@type']._value.replace(/.*\//, '');
this.renderName = `${this.context}-${type
.replace(/.*\//, '')
.replaceAll('.', '-')
.replaceAll('_', '-')
.toLocaleLowerCase()}`;
const e = document.createElement(this.renderName);
/**
* Append all additional flags
*/
if (propertyField.flags && propertyField.flags.repeats.length) {
const len = propertyField.flags.repeats.length;
// eslint-disable-next-line no-plusplus
for (let f = 0; f < len; ++f) {
const flag = propertyField.flags.repeats[f]._value;
if (!flag.startsWith('@') && !flag.startsWith('ƒ')) {
e.setAttribute(flag, '');
}
}
}
// Grab all of the original's attributes, and pass them to the replacement
const l = this.attributes.length;
// eslint-disable-next-line no-plusplus
for (let i = 0; i < l; ++i) {
const { nodeName } = this.attributes.item(i);
const { nodeValue } = this.attributes.item(i);
if (!nodeName.startsWith('@') && !nodeName.startsWith('ƒ')) {
e.setAttribute(nodeName, nodeValue);
}
}
if (e.bindData) {
switch (type) {
// the input elements for string and number are just working with scalar values
case 'google.protobuf.FloatValue':
case 'google.protobuf.Int32Value':
case 'google.protobuf.UInt32Value':
case 'google.protobuf.Int64Value':
case 'google.protobuf.UInt64Value':
case 'google.protobuf.StringValue':
case 'google.protobuf.BoolValue':
case 'google.protobuf.DoubleValue':
e.bindData(propertyField.data.value);
break;
default:
e.bindData(propertyField.data);
}
this._createdProp = this.parentNode.insertBefore(e, this);
propertyField.data.dispatchNodeEvent(
new NodeEvent('this-metas-changed', propertyField.data, false)
);
this._property_created = true;
} else {
// eslint-disable-next-line no-console
console.warn(e, ': bind-data missing or not imported', this);
}
}
}
disconnectedCallback() {
if (this._createdProp) {
this._createdProp.remove();
}
if (this._createdRepeater) {
this._createdRepeater.remove();
}
}
static get styles() {
// language=CSS
return css`
:host {
display: none;
}
`;
}
}
window.customElements.define('furo-ui5-property', FuroUi5Property);