Skip to content

Commit

Permalink
Add renderer for KeyValueList attributes
Browse files Browse the repository at this point in the history
Issue #19
  • Loading branch information
Pictor13 committed Aug 2, 2016
1 parent b1ef600 commit d88aa21
Show file tree
Hide file tree
Showing 6 changed files with 335 additions and 0 deletions.
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 app/templates/html/attribute/key-value-list/as_input.twig
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 -%}
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 -%}
1 change: 1 addition & 0 deletions pub/static/themes/whitelabel/_lib.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
@import "components/primary-activities/components.primary-activities";
@import "components/subheader-activities/components.subheader-activities";
@import "components/itemlist/components.itemlist";
@import "components/key-value-list/components.key-value-list";
@import "components/image-list/components.image-list";
@import "components/breadcrumb/components.breadcrumb";
@import "components/datepicker/components.datepicker";
Expand Down
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: ''; }
}
}
}
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;
}
}
}
}

0 comments on commit d88aa21

Please sign in to comment.