From f57dba2a4cf65201621d33e73ebf70b8a191b6ea Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 3 May 2024 16:41:02 +0200 Subject: [PATCH] TermInput: Allow to enable read-only terms and style them --- asset/css/search-base.less | 28 +++++++++++++++++ asset/js/widget/TermInput.js | 2 +- src/FormElement/TermInput.php | 34 ++++++++++++++++++++- src/FormElement/TermInput/TermContainer.php | 19 ++++++++---- 4 files changed, 75 insertions(+), 8 deletions(-) diff --git a/asset/css/search-base.less b/asset/css/search-base.less index e4af764b..f96c341b 100644 --- a/asset/css/search-base.less +++ b/asset/css/search-base.less @@ -209,6 +209,34 @@ outline-width: 3px; outline-offset: ~"calc(-@{labelPad} + 3px)"; } + + &.read-only { + [data-index] { + position: relative; + + input { + padding-left: 1.5em; + text-align: center; + cursor: pointer; + + &:disabled { + cursor: default; + } + + + i { + position: absolute; + display: none; + top: .5em; + left: .5em; + } + + &:not(:disabled):hover + i, + &:not(:disabled):focus + i { + display: revert; + } + } + } + } } .search-suggestions { diff --git a/asset/js/widget/TermInput.js b/asset/js/widget/TermInput.js index 554a6424..7e8e891e 100644 --- a/asset/js/widget/TermInput.js +++ b/asset/js/widget/TermInput.js @@ -99,7 +99,7 @@ define(["../notjQuery", "BaseInput"], function ($, BaseInput) { const label = super.renderTerm(termData, termIndex); if (this.readOnly) { - label.firstChild.type = 'button'; + label.firstChild.readOnly = true; label.appendChild($.render('')); } diff --git a/src/FormElement/TermInput.php b/src/FormElement/TermInput.php index 184be1da..9310ffe6 100644 --- a/src/FormElement/TermInput.php +++ b/src/FormElement/TermInput.php @@ -40,6 +40,9 @@ class TermInput extends FieldsetElement /** @var bool Whether term direction is vertical */ protected $verticalTermDirection = false; + /** @var bool Whether registered terms are read-only */ + protected $readOnly = false; + /** @var array Changes to transmit to the client */ protected $changes = []; @@ -103,6 +106,30 @@ public function getTermDirection(): ?string return $this->verticalTermDirection ? 'vertical' : null; } + /** + * Set whether registered terms are read-only + * + * @param bool $state + * + * @return $this + */ + public function setReadOnly(bool $state = true): self + { + $this->readOnly = $state; + + return $this; + } + + /** + * Get whether registered terms are read-only + * + * @return bool + */ + public function getReadOnly(): bool + { + return $this->readOnly; + } + /** * Set terms * @@ -415,6 +442,7 @@ public function getValueAttribute() 'data-with-multi-completion' => true, 'data-no-auto-submit-on-remove' => true, 'data-term-direction' => $this->getTermDirection(), + 'data-read-only-terms' => $this->getReadOnly(), 'data-data-input' => '#' . $dataInputId, 'data-term-input' => '#' . $termInputId, 'data-term-container' => '#' . $termContainer->getAttribute('id')->getValue(), @@ -436,7 +464,11 @@ public function getValueAttribute() $mainInput->prependWrapper((new HtmlElement( 'div', - Attributes::create(['class' => ['term-input-area', $this->getTermDirection()]]), + Attributes::create(['class' => [ + 'term-input-area', + $this->getTermDirection(), + $this->getReadOnly() ? 'read-only' : null + ]]), $termContainer, new HtmlElement('label', null, $mainInput) ))); diff --git a/src/FormElement/TermInput/TermContainer.php b/src/FormElement/TermInput/TermContainer.php index c5a614cd..5d3643ab 100644 --- a/src/FormElement/TermInput/TermContainer.php +++ b/src/FormElement/TermInput/TermContainer.php @@ -6,6 +6,7 @@ use ipl\Html\BaseHtmlElement; use ipl\Html\HtmlElement; use ipl\Web\FormElement\TermInput; +use ipl\Web\Widget\Icon; class TermContainer extends BaseHtmlElement { @@ -29,26 +30,32 @@ public function __construct(TermInput $input) protected function assemble() { foreach ($this->input->getTerms() as $i => $term) { - $label = $term->getLabel() ?: $term->getSearchValue(); + $value = $term->getLabel() ?: $term->getSearchValue(); - $this->addHtml(new HtmlElement( + $label = new HtmlElement( 'label', Attributes::create([ 'class' => $term->getClass(), 'data-search' => $term->getSearchValue(), - 'data-label' => $label, + 'data-label' => $value, 'data-index' => $i ]), new HtmlElement( 'input', Attributes::create([ 'type' => 'text', - 'value' => $label, + 'value' => $value, 'pattern' => $term->getPattern(), - 'data-invalid-msg' => $term->getMessage() + 'data-invalid-msg' => $term->getMessage(), + 'readonly' => $this->input->getReadOnly() ]) ) - )); + ); + if ($this->input->getReadOnly()) { + $label->addHtml(new Icon('trash')); + } + + $this->addHtml($label); } } }