const textField = document.createElement('template') textField.innerHTML = `
` customElements.define('text-field', class extends HTMLElement { constructor() { super() this.attachShadow({ mode: 'open' }).append(textField.content.cloneNode(true)) this.textField = this.shadowRoot.querySelector('.text-field') this.textContainer = this.textField.children[0] this.editButton = this.textField.querySelector('.edit-button') this.isTextEditable = false this.isDisabled = false } static get observedAttributes() { return ['disabled'] } get value() { return this.text } set value(val) { this.text = val this.textContainer.textContent = val this.setAttribute('value', val) } set disabled(val) { this.isDisabled = val if (this.isDisabled) this.setAttribute('disabled', '') else this.removeAttribute('disabled') } setEditable = () => { if (this.isTextEditable) return this.textContainer.contentEditable = true this.setAttribute('editable', '') this.textContainer.focus() document.execCommand('selectAll', false, null); this.editButton.textContent = 'Done' this.isTextEditable = true } setNonEditable = () => { if (!this.isTextEditable) return this.textContainer.contentEditable = false this.removeAttribute('editable') if (this.text !== this.textContainer.textContent.trim()) { this.setAttribute('value', this.textContainer.textContent) this.text = this.textContainer.textContent.trim() this.dispatchEvent(new CustomEvent('change', { bubbles: true, cancelable: true, composed: true })); } this.editButton.textContent = 'Edit' this.isTextEditable = false } toggleEditable = () => { if (this.isTextEditable) this.setNonEditable() else this.setEditable() } revert = () => { if (this.textContainer.isContentEditable) { this.value = this.text this.setNonEditable() } } connectedCallback() { this.text if (this.hasAttribute('value')) { this.text = this.getAttribute('value') this.textContainer.textContent = this.text } if (this.hasAttribute('disabled')) this.isDisabled = true else this.isDisabled = false if (!this.isDisabled) { this.textContainer.addEventListener('dblclick', this.setEditable) this.editButton.addEventListener('click', this.toggleEditable) } } attributeChangedCallback(name) { if (name === 'disabled') { if (this.hasAttribute('disabled')) { this.editButton.classList.add('hide') this.textContainer.removeEventListener('dblclick', this.setEditable) this.editButton.removeEventListener('click', this.toggleEditable) this.revert() } else { this.editButton.classList.remove('hide') this.textContainer.addEventListener('dblclick', this.setEditable) this.editButton.addEventListener('click', this.toggleEditable) } } } disconnectedCallback() { this.textContainer.removeEventListener('dblclick', this.setEditable) this.editButton.removeEventListener('click', this.toggleEditable) } })