From 07ab8ef9fcefff6a97c688599fb08fb0d462332e Mon Sep 17 00:00:00 2001 From: Ryan Cramer Date: Thu, 31 May 2018 14:27:39 -0400 Subject: [PATCH] Add support for multi-language options support to InputfieldSelect, and modules that descend from it (radios, checkboxes, asmSelect, selectMultiple, etc). This enables you to use selectable options in multiple languages when used in FormBuilder or any other tool that uses InputfieldSelect without a Fieldtype. --- .../Inputfield/InputfieldSelect.module | 306 ++++++++++++++---- 1 file changed, 245 insertions(+), 61 deletions(-) diff --git a/wire/modules/Inputfield/InputfieldSelect.module b/wire/modules/Inputfield/InputfieldSelect.module index 8c2d6c8a..904c4bd4 100644 --- a/wire/modules/Inputfield/InputfieldSelect.module +++ b/wire/modules/Inputfield/InputfieldSelect.module @@ -9,6 +9,8 @@ * Subclasses that select multiple values should implement the InputfieldHasArrayValue interface. * * @property string|int $defaultValue + * @property array|string $options Get or set options, array of [value => label], or use options string. + * @property array $optionAttributes * */ class InputfieldSelect extends Inputfield { @@ -25,6 +27,14 @@ class InputfieldSelect extends Inputfield { */ protected $optionAttributes = array(); + /** + * Alternate language labels for options, array of [ languageID => [ optionValue => optionLabel ] ] + * + * @var array + * + */ + protected $optionLanguageLabels = array(); + /** * Return information about this module * @@ -38,6 +48,10 @@ class InputfieldSelect extends Inputfield { ); } + /** + * Construct + * + */ public function __construct() { parent::__construct(); $this->set('defaultValue', ''); @@ -84,6 +98,59 @@ class InputfieldSelect extends Inputfield { return $this; } + /** + * Set/replace all options + * + * @param array $options Array of options to add. It is assumed that array keys are the option value, and array + * values are the option labels, unless overridden by the $assoc argument. + * @param bool $assoc Is $options an associative array? (default=true). Specify false if $options is intended to be + * a regular PHP array, where the array keys/indexes should be ignored, and option value will also be the label. + * @return $this + * + */ + public function setOptions(array $options, $assoc = true) { + $this->options = array(); + return $this->addOptions($options, $assoc); + } + + /** + * Get or set alternative language label(s) + * + * @param Language|int|string $language Language object, id or name (required). + * @param string|null|bool $key Option key/value to get/set label for, + * OR omit to return all currently set option language labels for language, + * OR boolean false to remove all language labels for this option value/key. + * OR array of [ optionValue => optionLabel ] to add multiple option values for language. + * @param $label|string|bool Translated label text to set, + * OR omit to GET language label. + * OR boolean false to remove. + * @return string|array|Inputfield Return value depends on given arguments + * + */ + public function optionLanguageLabel($language, $key = null, $label = null) { + if(is_string($language) && !ctype_digit("$language")) { + $language = $this->wire('languages')->get($language); + } + $languageID = (int) "$language"; // converts Page or string to id + if(!isset($this->optionLanguageLabels[$languageID])) { + $this->optionLanguageLabels[$languageID] = array(); + } + if($key === null) { + return $this->optionLanguageLabels[$languageID]; + } else if($key === false) { + unset($this->optionLanguageLabels[$languageID]); + } else if(is_array($key)) { + foreach($key as $k => $v) $this->optionLanguageLabels[$languageID][$k] = $v; + } else if($label === null) { + return isset($this->optionLanguageLabels[$languageID][$key]) ? $this->optionLanguageLabels[$languageID][$key] : ''; + } else if($label === false) { + unset($this->optionLanguageLabels[$languageID][$key]); + } else { + $this->optionLanguageLabels[$languageID][$key] = $label; + } + return $this; + } + /** * Given a multi-line string, convert it to options, one per line * @@ -163,6 +230,26 @@ class InputfieldSelect extends Inputfield { return $this; } + /** + * Add/modify existing option labels from a line separated key=value string, primarily for multi-language support + * + * @param string $str String of optionValue=optionLabel with each on its own line + * @param int $languageID Language ID to set for, or omit for default language + * + */ + protected function addOptionLabelsString($str, $languageID = 0) { + foreach(explode("\n", $str) as $line) { + $line = trim($line); + if(!strpos($line, '=')) continue; // 0 or false OK + list($key, $label) = explode('=', $line, 2); + if($languageID) { + $this->optionLanguageLabel($languageID, $key, $label); + } else { + $this->addOption($key, $label); + } + } + } + /** * Remove the option with the given value * @@ -261,6 +348,75 @@ class InputfieldSelect extends Inputfield { } return $disabled; } + + /** + * Get an attributes array intended for an item (or for all items) + * + * @param string|int|null $key Option value, or omit to return ALL option attributes indexed by option value + * @return array Array of attributes + * + */ + public function getOptionAttributes($key = null) { + if($key === null) return $this->optionAttributes; + if(!isset($this->optionAttributes[$key])) return array(); + return $this->optionAttributes[$key]; + } + + /** + * Set/replace entire attributes array for an item + * + * @param string|int|array $key Option value, or specify associative array (indexed by option value) to set ALL option attributes + * @param array $attrs Array of attributes to set, or omit if you specified array for first argument. + * @return $this + * + */ + public function setOptionAttributes($key, array $attrs = array()) { + if(is_array($key)) { + $this->optionAttributes = $key; + } else { + $this->optionAttributes[$key] = $attrs; + } + return $this; + } + + /** + * Add attributes for an item (without removing existing attributes), or for multiple items + * + * @param string|int|array $key Option value, or array of option attributes indexed by option value. + * @param array $attrs Array of attributes to set, or omit if you specified array for first argument. + * @return $this + * + */ + public function addOptionAttributes($key, array $attrs = array()) { + if(is_array($key)) { + foreach($key as $k => $v) { + $this->addOptionAttributes($k, $v); + } + } else { + $value = isset($this->optionAttributes[$key]) ? $this->optionAttributes[$key] : array(); + $this->optionAttributes[$key] = array_merge($value, $attrs); + } + return $this; + } + + /** + * Get an attributes string intended for the