Skip to content

Commit

Permalink
[TASK] Improve icon rendering on mandatory fields
Browse files Browse the repository at this point in the history
Mandatory fields are indicated with a red colored icon
(or yellow/orange, if it is mandatory in certain scenarios).
When a mandatory field is filled, the icon color
switches to green.

To improve usability, we now also change the icon from
an exclamation mark (in a triangle) to a checkmark.

Colors and icon visibility are now set with a new backend
stylesheet, which also support the color modes in TYPO3 v13.
Icon colors pass WCAG AA in both color modes.
  • Loading branch information
sebkln committed Oct 18, 2024
1 parent 692ab13 commit 7c87a12
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 38 deletions.
46 changes: 26 additions & 20 deletions Classes/Form/Element/TermsInputElement.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,17 @@ class TermsInputElement extends AbstractFormElement
*/
protected $pictureTermsRepository;

protected $iconFactory;

public function injectIconFactory(IconFactory $iconFactory)
{
$this->iconFactory = $iconFactory;
}

public function __construct(
NodeFactory $nodeFactory,
IconFactory $iconFactory
NodeFactory $nodeFactory
) {
$this->nodeFactory = $nodeFactory;
$this->iconFactory = $iconFactory;
$this->pictureTermsRepository = GeneralUtility::makeInstance(PictureTermsRepository::class);
}

Expand All @@ -60,33 +65,31 @@ public function render(): array
{
$row = $this->data['databaseRow'];
$parameterArray = $this->data['parameterArray'];
$resultArray = $this->initializeResultArray();

// Don't render field if no picture terms are selected:
if ((int)current($row['terms']) === 0) {
return $resultArray = [];
return $resultArray;
}

$fieldInformationResult = $this->renderFieldInformation();
$fieldInformationHtml = $fieldInformationResult['html'];
$resultArray = $this->mergeChildReturnIntoExistingResult($this->initializeResultArray(), $fieldInformationResult, false);
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);

// Needed to keep TYPO3 v12 compatibility:
$resultArray['labelHasBeenHandled'] = true;

$itemValue = $parameterArray['itemFormElValue'];

$icons = [
'empty' => 'miscellaneous-placeholder',
'exclamation' => 'actions-exclamation-circle-alt'
];
$colors = [
'notMandatory' => 'transparent',
'ok' => '#79a548',
'mandatory' => '#c83c3c',
'mandatoryIfPresent' => '#e8a33d'
'empty' => $this->iconFactory->getIcon('miscellaneous-placeholder', Icon::SIZE_SMALL)->render('inline'),
'exclamation' => $this->iconFactory->getIcon('actions-exclamation-triangle-alt', Icon::SIZE_SMALL)->render('inline'),
'checkmark' => $this->iconFactory->getIcon('actions-check-circle-alt', Icon::SIZE_SMALL)->render('inline')
];
$icon = $icons['empty'];
$iconColor = $colors['notMandatory'];
$iconClass = '';
$iconChecked = '';
$hasInitialValue = ($itemValue) ? ' has-value' : '';

$fieldId = StringUtility::getUniqueId('formengine-input-');
$renderedLabel = $this->renderLabel($fieldId);
Expand Down Expand Up @@ -115,14 +118,16 @@ public function render(): array

// Depending on field configuration: don't render field, or set mandatory hints:
if ($fieldType === MetadataFieldType::HIDDEN) {
return $resultArray = [];
return $resultArray = $this->initializeResultArray();
} elseif ($fieldType === MetadataFieldType::MANDATORY) {
$iconClass = ' is-mandatory';
$icon = $icons['exclamation'];
$iconColor = ($itemValue) ? $colors['ok'] : $colors['mandatory'];
$iconChecked = '<span class="t3js-termsinput-icon-checked">' . $icons['checkmark'] . '</span>';
$attributes['class'] .= ' t3js-mandatory-term';
} elseif ($fieldType === MetadataFieldType::MANDATORY_IF_PRESENT) {
$iconClass = ' is-mandatory-if-present';
$icon = $icons['exclamation'];
$iconColor = ($itemValue) ? $colors['ok'] : $colors['mandatoryIfPresent'];
$iconChecked = '<span class="t3js-termsinput-icon-checked">' . $icons['checkmark'] . '</span>';
$attributes['class'] .= ' t3js-mandatory-term t3js-mandatory-term-if-present';
}

Expand All @@ -135,7 +140,7 @@ public function render(): array
} catch (\RuntimeException $ignoredException) {
// deliberately empty
} catch (DBALException $e) {
return $resultArray = [];
return $resultArray = $this->initializeResultArray();
}

$html = [];
Expand All @@ -146,8 +151,9 @@ public function render(): array
$html[] = '<div class="form-wizards-wrap">';
$html[] = '<div class="form-wizards-element">';
$html[] = '<div class="input-group">';
$html[] = '<span class="input-group-addon input-group-icon t3js-form-field-termsinput-icon" style="color: ' . $iconColor . ';">';
$html[] = $this->iconFactory->getIcon($icon, Icon::SIZE_SMALL)->render();
$html[] = '<span class="input-group-text input-group-icon t3js-termsinput-icons' . $iconClass . $hasInitialValue . '">';
$html[] = '<span class="t3js-termsinput-icon-default">' . $icon . '</span>';
$html[] = $iconChecked;
$html[] = '</span>';
$html[] = '<input type="text"' . GeneralUtility::implodeAttributes($attributes, true) . ' />';
$html[] = '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars((string)$itemValue) . '" />';
Expand Down
32 changes: 32 additions & 0 deletions Resources/Public/Css/picturecredits.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
:root {
--picturecredits-color-ok: #247554;
--picturecredits-color-ok-dark: #3cc38c;
--picturecredits-color-mandatory: #a72e25;
--picturecredits-color-mandatory-dark: #da6158;
--picturecredits-color-mandatory-if-present: #c95b00;
--picturecredits-color-mandatory-if-present-dark: #ffc857;
}

.is-mandatory .t3js-termsinput-icon-default {
color: light-dark(var(--picturecredits-color-mandatory), var(--picturecredits-color-mandatory-dark));
}

.is-mandatory-if-present .t3js-termsinput-icon-default {
color: light-dark(var(--picturecredits-color-mandatory-if-present), var(--picturecredits-color-mandatory-if-present-dark));
}

.t3js-termsinput-icons.has-value {
color: light-dark(var(--picturecredits-color-ok), var(--picturecredits-color-ok-dark));
}

.t3js-termsinput-icon-checked {
display: none;
}

.t3js-termsinput-icons.has-value .t3js-termsinput-icon-default {
display: none;
}

.t3js-termsinput-icons.has-value .t3js-termsinput-icon-checked {
display: block;
}
2 changes: 1 addition & 1 deletion Resources/Public/Icons/picture_terms.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 10 additions & 17 deletions Resources/Public/JavaScript/MandatoryEvaluation.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* Changes the icon color of fields with RenderType "termsInput",
* depending on existing value and MetadataFieldType.
* Toggles a CSS class on fields with RenderType "termsInput",
* depending on a given value.
* The class controls display and color of icons (see 'picturecredits.css').
* @author Sebastian Klein <[email protected]>
*/
import DocumentService from "@typo3/core/document-service.js";
Expand All @@ -14,40 +15,32 @@ class MandatoryEvaluation {

evaluateFields() {
const tceForms = document.getElementById('EditDocumentController');
const colors = {
ok: '#79a548',
mandatory: '#c83c3c',
mandatoryIfPresent: '#e8a33d'
};
const classes = {
term: '.t3js-mandatory-term',
icon: '.t3js-form-field-termsinput-icon',
ifPresent: 't3js-mandatory-term-if-present'
icon: '.t3js-termsinput-icons',
hasValue: 'has-value'
};
const mandatoryFields = tceForms.querySelectorAll(classes.term);

const setColor = (event) => {
const checkForValue = (event) => {
let field = event.target;
let value = field.value;
let icon = field.parentElement.parentElement.querySelector(classes.icon);
let isMandatoryIfPresent = field.classList.contains(classes.ifPresent);

if (value) {
icon.style.color = colors.ok;
} else if (isMandatoryIfPresent) {
icon.style.color = colors.mandatoryIfPresent;
icon.classList.add(classes.hasValue);
} else {
icon.style.color = colors.mandatory;
icon.classList.remove(classes.hasValue);
}
};

if (mandatoryFields !== null) {
mandatoryFields.forEach(f => {
f.addEventListener('input', (e) => {
setColor(e);
checkForValue(e);
});
f.addEventListener('change', (e) => {
setColor(e);
checkForValue(e);
});
});
}
Expand Down
3 changes: 3 additions & 0 deletions ext_localconf.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
}
')
);

$GLOBALS['TYPO3_CONF_VARS']['BE']['stylesheets']['picturecredits']
= 'EXT:picturecredits/Resources/Public/Css/';
};

$boot();
Expand Down

0 comments on commit 7c87a12

Please sign in to comment.