-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add renderer for KeyValueList attributes
Issue #19
- Loading branch information
Showing
6 changed files
with
335 additions
and
0 deletions.
There are no files selected for viewing
123 changes: 123 additions & 0 deletions
123
...enderer/Html/Trellis/Runtime/Attribute/KeyValueList/HtmlKeyValueListAttributeRenderer.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
<?php | ||
|
||
namespace Honeybee\Ui\Renderer\Html\Trellis\Runtime\Attribute\KeyValueList; | ||
|
||
use Honeybee\Common\Util\StringToolkit; | ||
use Honeybee\Infrastructure\Config\SettingsInterface; | ||
use Honeybee\Ui\Renderer\Html\Trellis\Runtime\Attribute\HtmlAttributeRenderer; | ||
use Trellis\Runtime\Attribute\KeyValueList\KeyValueListAttribute; | ||
|
||
class HtmlKeyValueListAttributeRenderer extends HtmlAttributeRenderer | ||
{ | ||
protected function getDefaultTemplateIdentifier() | ||
{ | ||
$view_scope = $this->getOption('view_scope', 'missing_view_scope.collection'); | ||
if (StringToolkit::endsWith($view_scope, 'collection')) { | ||
return $this->output_format->getName() . '/attribute/key-value-list/as_itemlist_item_cell.twig'; | ||
} | ||
|
||
return $this->output_format->getName() . '/attribute/key-value-list/as_input.twig'; | ||
} | ||
|
||
protected function getTemplateParameters() | ||
{ | ||
$params = parent::getTemplateParameters(); | ||
|
||
$params['allowed_keys'] = $this->attribute->getOption(KeyValueListAttribute::OPTION_ALLOWED_KEYS, $this->getOption('allowed_keys', [])); | ||
$params['allowed_values'] = $this->attribute->getOption(KeyValueListAttribute::OPTION_ALLOWED_VALUES, $this->getOption('allowed_values', [])); | ||
|
||
if ($this->attribute->hasOption(KeyValueListAttribute::OPTION_ALLOWED_PAIRS) || $this->hasOption('allowed_pairs')) { | ||
$params['allowed_pairs'] = $this->getOption( | ||
'allowed_pairs', | ||
$this->attribute->getOption(KeyValueListAttribute::OPTION_ALLOWED_PAIRS, []) | ||
); | ||
if ($params['allowed_pairs'] instanceof SettingsInterface) { | ||
$params['allowed_pairs'] = $params['allowed_pairs']->toArray(); | ||
} | ||
$params['allowed_keys'] = array_keys($params['allowed_pairs']); | ||
$params['allowed_values'] = array_values($params['allowed_pairs']); | ||
} | ||
|
||
|
||
$params['hide_pair_labels'] = $this->getOption('hide_pair_labels', false); | ||
$params['key_maxlength'] = $this->getOption('key_maxlength'); | ||
$params['value_maxlength'] = $this->getOption( | ||
'value_maxlength', | ||
$this->attribute->getOption(KeyValueListAttribute::OPTION_MAX_LENGTH) | ||
); | ||
$params['value_type'] = $this->getOption( | ||
'value_type', | ||
$this->attribute->getOption(KeyValueListAttribute::OPTION_VALUE_TYPE, 'text') | ||
); | ||
switch ($params['value_type']) { | ||
case 'integer': | ||
case 'float': | ||
$params['value_type'] = 'number'; | ||
$params['min'] = $this->getOption('min', $this->attribute->getOption(KeyValueListAttribute::OPTION_MIN_VALUE)); | ||
$params['max'] = $this->getOption('max', $this->attribute->getOption(KeyValueListAttribute::OPTION_MAX_VALUE)); | ||
break; | ||
case 'boolean': | ||
// @todo implement | ||
// break; | ||
default: | ||
$params['value_type'] = 'text'; | ||
break; | ||
} | ||
|
||
$params['attribute_value'] = $this->normalizeAttributeValue( | ||
$params['attribute_value'], | ||
[ | ||
'key_maxlength' => $params['key_maxlength'], | ||
'value_maxlength' => $params['value_maxlength'] | ||
] | ||
); | ||
|
||
return $params; | ||
} | ||
|
||
protected function determineAttributeValue($attribute_name, $default_value = []) | ||
{ | ||
$value = []; | ||
|
||
if ($this->hasOption('value')) { | ||
return $this->getOption('value', $default_value); | ||
} | ||
|
||
$value_path = $this->getOption('attribute_value_path'); | ||
if (!empty($value_path)) { | ||
$value = AttributeValuePath::getAttributeValueByPath($this->getPayload('resource'), $value_path); | ||
} else { | ||
$value = $this->getPayload('resource')->getValue($attribute_name); | ||
} | ||
|
||
if (!is_array($value)) { | ||
throw new RuntimeError('Attribute value is not an array of key/value pairs.'); | ||
} | ||
|
||
if ($value === $this->attribute->getNullValue()) { | ||
return $default_value; | ||
} else { | ||
return $value; | ||
} | ||
} | ||
|
||
protected function normalizeAttributeValue($attribute_value, $options) | ||
{ | ||
// @todo Purge invalid keys/values | ||
// Purge values not compliant wth other options | ||
|
||
if (isset($options['key_maxlength']) && is_numeric($options['key_maxlength'])) { | ||
foreach ($attribute_value as $key => $value) { | ||
unset($attribute_value[$key]); | ||
$attribute_value[substr($key, 0, $options['key_maxlength'])] = $value; | ||
} | ||
} | ||
if (isset($options['value_maxlength']) && is_numeric($options['value_maxlength'])) { | ||
foreach ($attribute_value as $key => $value) { | ||
$attribute_value[$key] = substr($value, 0, $options['value_maxlength']); | ||
} | ||
} | ||
|
||
return $attribute_value; | ||
} | ||
} |
132 changes: 132 additions & 0 deletions
132
app/templates/html/attribute/key-value-list/as_input.twig
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
{%- block field -%} {# this block exists for whitespace control #} | ||
{%- set errors = errors | default([]) -%} | ||
<div | ||
class="hb-field {{ css|default('') }}" data-hb-field-name="{{ field_name }}" {% for attr, val in html_attributes %} {{ attr }}="{{ val }}" {% endfor %}> | ||
<div class="hb-field__content"> | ||
<div class="hb-field__label"> | ||
<label for="{{ field_id }}">{{ _(field_name~'.field_name', translation_domain) }}</label> | ||
</div> | ||
</div><!-- | ||
--><div class="hb-field__value"> | ||
<div class="hb-key-value-list"> | ||
{% if attribute_value is iterable %} | ||
<div class="hb-key-value-list__head {% if hide_pair_labels %} hb-key-value-list__head--hidden{% endif %}"> | ||
<label class="hb-key-value-head__label">{{ _(field_name~'.key_label', translation_domain) }}</label> | ||
<label class="hb-key-value-head__label">{{ _(field_name~'.value_label', translation_domain) }}</label> | ||
</div> | ||
<div class="hb-key-value-list__items"> | ||
{% for key, value in attribute_value %} | ||
<div class="hb-key-value-list__item"> | ||
<div class="hb-key-value-item__key"> | ||
{% if allowed_keys is empty or readonly %} | ||
<input | ||
type="text" | ||
name="{{grouped_base_path}}[{{key}}]" | ||
class="hb-key-value-item__key-{{key}}" | ||
{{ readonly|default('') }} {{ disabled|default('') }} | ||
{{ required|default('') }} maxlength="{{ key_maxlength|default('') }}" | ||
placeholder="{{ translations.placeholder|default('') }}" | ||
title="{{ translations.title|default('') }}" | ||
value="{{key}}" | ||
/> | ||
{% else %} | ||
<select class="hb-key-value-item__key-{{key}}"> | ||
{% for key in allowed_keys %} | ||
<option value="{{key}}">{{key}}</option> | ||
{% endfor %} | ||
</select> | ||
{% endif %} | ||
</div> | ||
<div class="hb-key-value-item__value"> | ||
{% if allowed_values is empty or readonly %} | ||
<input | ||
type="{{ value_type }}" | ||
name="{{grouped_base_path}}[{{key}}]" | ||
class="hb-key-value-item__value-{{key}}" | ||
{{ readonly|default('') }} {{ disabled|default('') }} | ||
{{ required|default('') }} maxlength="{{ value_maxlength|default('') }}" | ||
{{ pattern|default('')|raw }} placeholder="{{ translations.placeholder|default('') }}" | ||
title="{{ translations.title|default('') }}" | ||
value="{{value}}" | ||
min="{{min|default('')}}" | ||
max="{{max|default('')}}" | ||
/> | ||
{% else %} | ||
<select class="hb-key-value-item__value-{{key}}"> | ||
{% for value in allowed_values %} | ||
<option value="{{value}}">{{value}}</option> | ||
{% endfor %} | ||
</select> | ||
{% endif %} | ||
</div> | ||
</div> | ||
{% endfor %} | ||
</div> | ||
{% endif %} | ||
{% if not readonly and not disabled %} | ||
<div class="hb-key-value-list__new-item"> | ||
<div class="hb-key-value-item__key"> | ||
{% if allowed_keys is empty %} | ||
<input | ||
type="text" | ||
name="{{grouped_base_path}}[new]" | ||
class="hb-key-value__key-new" | ||
{{ readonly|default('') }} {{ disabled|default('') }} | ||
{{ required|default('') }} maxlength="{{ key_maxlength|default('') }}" | ||
placeholder="{{ translations.placeholder|default('') }}" | ||
title="{{ translations.title|default('') }}" | ||
value="" | ||
/> | ||
{% else %} | ||
<select class="hb-key-value__key-new"> | ||
{% for allowed_key in allowed_keys %} | ||
<option value="{{allowed_key}}">{{allowed_key}}</option> | ||
{% endfor %} | ||
</select> | ||
{% endif %} | ||
</div> | ||
<div class="hb-key-value-item__value"> | ||
{% if allowed_values is empty %} | ||
<input | ||
type="{{ value_type }}" | ||
name="{{grouped_base_path}}[new]" | ||
class="hb-key-value__value-new" | ||
{{ readonly|default('') }} {{ disabled|default('') }} | ||
{{ required|default('') }} maxlength="{{ value_maxlength|default('') }}" | ||
{{ pattern|default('')|raw }} placeholder="{{ translations.placeholder|default('') }}" | ||
title="{{ translations.title|default('') }}" | ||
value="" | ||
min="{{min|default('')}}" | ||
max="{{max|default('')}}" | ||
/> | ||
{% else %} | ||
<select class="hb-key-value__value-new"> | ||
{% for allowed_value in allowed_values %} | ||
<option value="{{allowed_value}}">{{allowed_value}}</option> | ||
{% endfor %} | ||
</select> | ||
{% endif %} | ||
</div> | ||
</div> | ||
{% endif %} | ||
</div> | ||
<ul class="errors"> | ||
{%- block field_errors -%} | ||
{%- for error in errors -%} | ||
<li class="error">{{error}}</li> | ||
{%- endfor -%} | ||
{%- endblock -%} | ||
</ul> | ||
{% if translations.input_help is defined %} | ||
<div class="input_help">{{ translations.input_help|raw }}</div> | ||
{% endif %} | ||
{% if translations.input_hint is defined %} | ||
<div class="input_hint">{{ translations.input_hint|raw }}</div> | ||
{% endif %} | ||
{% if translations.input_focus_hint is defined %} | ||
<div class="input_hint focus">{{ translations.input_focus_hint|raw }}</div> | ||
{% endif %} | ||
</div><!-- | ||
--><div class="hb-field__extra"></div> | ||
</div> | ||
{%- endblock -%} |
17 changes: 17 additions & 0 deletions
17
app/templates/html/attribute/key-value-list/as_itemlist_item_cell.twig
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{%- block field -%} {# this block exists for whitespace control #} | ||
<div class="hb-field hb-attribute {{ css|default('') }}" data-hb-field-name="{{ field_name }}"><!-- | ||
--><div class="hb-field__content"><!-- | ||
--><div class="hb-field__label">{{ _(field_name~'.field_name', translation_domain) }}</div><!-- | ||
--><div class="hb-field__value"> | ||
{% if attribute_value is iterable %} | ||
{%- for key, value in attribute_value -%} | ||
<div class="hb-field__pair-key">{{key}}:</div> | ||
<div class="hb-field__pair-value">{{value}}</div> | ||
{%- endfor -%} | ||
{%- else -%} | ||
{{ attribute_value }} | ||
{%- endif -%} | ||
</div><!-- | ||
--></div><!-- | ||
--></div> | ||
{%- endblock field -%} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
pub/static/themes/whitelabel/components/field/_components.field.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,23 @@ | ||
.hb-field { | ||
margin-bottom: 1.43em; // 20/14 | ||
|
||
// KeyValueList attribute | ||
.hb-field__pair-key, | ||
.hb-field__pair-value { | ||
display: inline-block; | ||
} | ||
|
||
.hb-field__pair-key { | ||
font-style: italic; | ||
} | ||
|
||
.hb-field__pair-value { | ||
&:after { | ||
content: ','; | ||
margin-right: 0.2em; | ||
} | ||
&:last-child { | ||
&:after { content: ''; } | ||
} | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
pub/static/themes/whitelabel/components/key-value-list/_components.key-value-list.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
.hb-key-value-list { | ||
display: table; | ||
table-layout: fixed; | ||
width: 100%; | ||
|
||
margin-top: $small-spacing; | ||
margin-bottom: $small-spacing; | ||
|
||
@at-root { | ||
.hb-key-value-list__head { | ||
display: table-header-group; | ||
|
||
&.hb-key-value-list__head--hidden { | ||
display: none; | ||
} | ||
} | ||
.hb-key-value-head__label { | ||
display: table-cell; | ||
} | ||
.hb-key-value-list__items { | ||
display: table-row-group; | ||
} | ||
|
||
.hb-key-value-list__item { | ||
display: table-row; | ||
} | ||
|
||
.hb-key-value-item__key, | ||
.hb-key-value-item__value { | ||
display: table-cell; | ||
width: 50%; | ||
} | ||
|
||
.hb-key-value-list__new-item { | ||
display: table-footer-group; | ||
|
||
.hb-key-value-item__key { | ||
padding-top: $small-spacing; | ||
} | ||
} | ||
} | ||
} |