<?php
namespace YahnisElsts\AdminMenuEditor\Customizable\Controls;
use YahnisElsts\AdminMenuEditor\Customizable\Schemas\Enum;
use YahnisElsts\AdminMenuEditor\ProCustomizable\Settings\CssLengthSetting;
use YahnisElsts\AdminMenuEditor\ProCustomizable\Settings\WithSchema\CssLengthSetting as CssLengthSettingWithSchema;
use YahnisElsts\AdminMenuEditor\Customizable\HtmlHelper;
use YahnisElsts\AdminMenuEditor\Customizable\Rendering\Renderer;
use YahnisElsts\AdminMenuEditor\Customizable\Settings;
use YahnisElsts\AdminMenuEditor\Customizable\Settings\Setting;
class NumberInput extends AbstractNumericControl {
protected $type = 'fancyNumber';
protected $koComponentName = 'ame-number-input';
/**
* @var string|null
*/
protected $fixedUnit = null;
/**
* @var Settings\AbstractSetting|null
*/
protected $unitSetting = null;
public function __construct($settings = [], $params = []) {
$this->hasPrimaryInput = true;
parent::__construct($settings, $params);
//Units can be specified in a number of ways.
if ( isset($settings['unit']) ) {
$this->unitSetting = $settings['unit'];
}
if ( !$this->unitSetting ) {
if ( array_key_exists('unit', $params) ) {
if ( is_string($params['unit']) ) {
$this->fixedUnit = $params['unit'];
} else if ( $params['unit'] instanceof Settings\AbstractSetting ) {
$this->unitSetting = $params['unit'];
}
} else if (
($this->mainSetting instanceof CssLengthSetting)
|| ($this->mainSetting instanceof CssLengthSettingWithSchema)
) {
$unitSetting = $this->mainSetting->getUnitSetting();
if ( $unitSetting instanceof Settings\AbstractSetting ) {
$this->unitSetting = $unitSetting;
} else {
$this->fixedUnit = $this->mainSetting->getUnit();
}
}
}
//Add the "ame-small-number-input" class to controls where the expected
//number of digits is 4 or less. This only applies if both the min and
//max values are known.
if ( is_numeric($this->min) && is_numeric($this->max) ) {
$digits = 1;
//Digits before the decimal point = greatest log10 of abs(min) and abs(max).
//Add 1 because log10 is one less than the number of digits (e.g. log10(1) = 0).
//Note the use of loose comparison to avoid "0 !== 0.0" issues.
if ( ($this->min != 0) ) {
$digits = max($digits, floor(log10(abs($this->min))) + 1);
}
if ( ($this->max != 0) ) {
$digits = max($digits, floor(log10(abs($this->max))) + 1);
}
//Add the digits after the decimal point if the step is a decimal number.
$defaultStep = $this->getDefaultStep();
$fraction = abs($defaultStep - floor($defaultStep));
if ( ($fraction != 0) ) {
$digits += floor(abs(log10(abs($fraction))));
}
if ( ($digits <= 4) && !in_array('ame-small-number-input', $this->inputClasses) ) {
$this->inputClasses[] = 'ame-small-number-input';
}
}
}
public function renderContent(Renderer $renderer) {
$hasUnitDropdown = (
($this->unitSetting instanceof Settings\EnumSetting)
|| (
($this->unitSetting instanceof Settings\WithSchema\SettingWithSchema)
&& ($this->unitSetting->getSchema() instanceof Enum)
)
);
$currentUnitValue = $this->getCurrentUnit();
if ( $hasUnitDropdown || !empty($currentUnitValue) ) {
$unitElementId = $this->getUnitElementId();
} else {
$unitElementId = null;
}
$value = $this->getMainSettingValue();
$sliderRanges = $this->getSliderRanges();
$wrapperClasses = ['ame-number-input-control'];
if ( !empty($sliderRanges) ) {
$wrapperClasses[] = 'ame-container-with-popup-slider';
}
$wrapperClasses = array_merge($wrapperClasses, $this->classes);
echo HtmlHelper::tag(
'fieldset',
[
'class' => $wrapperClasses,
'data-bind' => $this->makeKoDataBind($this->getKoEnableBinding()),
]
);
if ( $hasUnitDropdown ) {
echo '<div class="ame-input-group">';
}
$attributes = $this->getBasicInputAttributes();
$attributes['value'] = $value;
$inputClasses = [];
if ( !empty($sliderRanges) ) {
$inputClasses[] = 'ame-input-with-popup-slider';
}
$inputClasses[] = 'ame-number-input';
//buildInputElement() will add $this->inputClasses, so no need to do it here.
$attributes['class'] = implode(' ', $inputClasses);
if ( !empty($unitElementId) ) {
$attributes['data-unit-element-id'] = $unitElementId;
}
if ( !empty($sliderRanges) ) {
$attributes['data-slider-ranges'] = wp_json_encode($sliderRanges);
}
$attributes['data-bind'] = $this->makeKoDataBind(array_merge([
'value' => $this->getKoObservableExpression($value),
'ameObservableChangeEvents' => 'true',
], $this->getKoEnableBinding()));
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- buildInputElement() is safe
echo $this->buildInputElement($attributes);
if ( $hasUnitDropdown ) {
$this->renderUnitDropdown($this->unitSetting, [
'name' => $this->getFieldName(null, $this->unitSetting),
'id' => $unitElementId,
'class' => 'ame-input-group-secondary ame-number-input-unit',
'data-ac-setting-id' => $this->unitSetting->getId(),
]);
} else {
$unit = $this->getCurrentUnit();
if ( !empty($unit) ) {
echo HtmlHelper::tag(
'span',
[
'id' => $unitElementId,
'class' => 'ame-number-input-unit',
'data-number-unit' => $unit,
],
' ' . esc_html($unit)
);
}
}
if ( $hasUnitDropdown ) {
echo '</div>';
}
//Slider
if ( !empty($sliderRanges) ) {
PopupSlider::basic()->render();
}
echo '</fieldset>';
static::enqueueDependencies();
}
protected function getCurrentUnit() {
if ( $this->unitSetting instanceof Settings\AbstractSetting ) {
return $this->unitSetting->getValue();
}
return $this->fixedUnit;
}
protected function getUnitElementId() {
return $this->getPrimaryInputId() . '__unit';
}
protected function getKoComponentParams() {
$params = parent::getKoComponentParams();
$unitText = $this->getCurrentUnit();
$hasUnitDropdown = false;
$units = ChoiceControlOption::tryGenerateFromSetting($this->unitSetting);
if ( !empty($units) ) {
$hasUnitDropdown = true;
$params['hasUnitDropdown'] = true;
$params['unitDropdownOptions'] = ChoiceControlOption::generateKoOptions($units);
} else if ( !empty($unitText) ) {
$params['unitText'] = $unitText;
}
if ( $hasUnitDropdown || !empty($unitText) ) {
$params['unitElementId'] = $this->getUnitElementId();
}
return $params;
}
public function serializeForJs() {
$result = parent::serializeForJs();
if ( $this->unitSetting instanceof Settings\AbstractSetting ) {
if ( empty($result['settings']) ) {
$result['settings'] = [];
}
$result['settings']['unit'] = $this->unitSetting->getId();
}
return $result;
}
public function enqueueKoComponentDependencies() {
parent::enqueueKoComponentDependencies();
//The slider automatically enqueues its dependencies when it's rendered
//via PopupSlider::render(), but KO components don't use that method.
//We need to enqueue the dependencies explicitly.
PopupSlider::enqueueDependencies();
}
} |