10a5b05ebSAndreas Gohr<?php 20a5b05ebSAndreas Gohr 30a5b05ebSAndreas Gohrnamespace dokuwiki\plugin\config\core\Setting; 40a5b05ebSAndreas Gohr 50a5b05ebSAndreas Gohr/** 60a5b05ebSAndreas Gohr * Class setting_multicheckbox 70a5b05ebSAndreas Gohr */ 88c7c53b0SAndreas Gohrclass SettingMulticheckbox extends SettingString 98c7c53b0SAndreas Gohr{ 10467c1427SAndreas Gohr protected $choices = []; 11467c1427SAndreas Gohr protected $combine = []; 120a5b05ebSAndreas Gohr protected $other = 'always'; 130a5b05ebSAndreas Gohr 140a5b05ebSAndreas Gohr /** @inheritdoc */ 15*d868eb89SAndreas Gohr public function update($input) 16*d868eb89SAndreas Gohr { 170a5b05ebSAndreas Gohr if ($this->isProtected()) return false; 180a5b05ebSAndreas Gohr 190a5b05ebSAndreas Gohr // split any combined values + convert from array to comma separated string 20467c1427SAndreas Gohr $input = $input ?: []; 210a5b05ebSAndreas Gohr $input = $this->array2str($input); 220a5b05ebSAndreas Gohr 230a5b05ebSAndreas Gohr $value = is_null($this->local) ? $this->default : $this->local; 240a5b05ebSAndreas Gohr if ($value == $input) return false; 250a5b05ebSAndreas Gohr 260a5b05ebSAndreas Gohr if ($this->pattern && !preg_match($this->pattern, $input)) { 270a5b05ebSAndreas Gohr $this->error = true; 280a5b05ebSAndreas Gohr $this->input = $input; 290a5b05ebSAndreas Gohr return false; 300a5b05ebSAndreas Gohr } 310a5b05ebSAndreas Gohr 320a5b05ebSAndreas Gohr $this->local = $input; 330a5b05ebSAndreas Gohr return true; 340a5b05ebSAndreas Gohr } 350a5b05ebSAndreas Gohr 360a5b05ebSAndreas Gohr /** @inheritdoc */ 37*d868eb89SAndreas Gohr public function html(\admin_plugin_config $plugin, $echo = false) 38*d868eb89SAndreas Gohr { 390a5b05ebSAndreas Gohr 400a5b05ebSAndreas Gohr $disable = ''; 410a5b05ebSAndreas Gohr 420a5b05ebSAndreas Gohr if ($this->isProtected()) { 430a5b05ebSAndreas Gohr $value = $this->protected; 440a5b05ebSAndreas Gohr $disable = 'disabled="disabled"'; 45467c1427SAndreas Gohr } elseif ($echo && $this->error) { 460a5b05ebSAndreas Gohr $value = $this->input; 470a5b05ebSAndreas Gohr } else { 480a5b05ebSAndreas Gohr $value = is_null($this->local) ? $this->default : $this->local; 490a5b05ebSAndreas Gohr } 500a5b05ebSAndreas Gohr 510a5b05ebSAndreas Gohr $key = htmlspecialchars($this->key); 520a5b05ebSAndreas Gohr 530a5b05ebSAndreas Gohr // convert from comma separated list into array + combine complimentary actions 540a5b05ebSAndreas Gohr $value = $this->str2array($value); 550a5b05ebSAndreas Gohr $default = $this->str2array($this->default); 560a5b05ebSAndreas Gohr 570a5b05ebSAndreas Gohr $input = ''; 580a5b05ebSAndreas Gohr foreach ($this->choices as $choice) { 590a5b05ebSAndreas Gohr $idx = array_search($choice, $value); 600a5b05ebSAndreas Gohr $idx_default = array_search($choice, $default); 610a5b05ebSAndreas Gohr 620a5b05ebSAndreas Gohr $checked = ($idx !== false) ? 'checked="checked"' : ''; 630a5b05ebSAndreas Gohr 640a5b05ebSAndreas Gohr // @todo ideally this would be handled using a second class of "default" 65467c1427SAndreas Gohr $class = (($idx !== false) === (false !== $idx_default)) ? " selectiondefault" : ""; 660a5b05ebSAndreas Gohr 67467c1427SAndreas Gohr $prompt = ($plugin->getLang($this->key . '_' . $choice) ?: htmlspecialchars($choice)); 680a5b05ebSAndreas Gohr 690a5b05ebSAndreas Gohr $input .= '<div class="selection' . $class . '">' . "\n"; 700a5b05ebSAndreas Gohr $input .= '<label for="config___' . $key . '_' . $choice . '">' . $prompt . "</label>\n"; 710a5b05ebSAndreas Gohr $input .= '<input id="config___' . $key . '_' . $choice . '" name="config[' . $key . 720a5b05ebSAndreas Gohr '][]" type="checkbox" class="checkbox" value="' . $choice . '" ' . $disable . ' ' . $checked . "/>\n"; 730a5b05ebSAndreas Gohr $input .= "</div>\n"; 740a5b05ebSAndreas Gohr 750a5b05ebSAndreas Gohr // remove this action from the disabledactions array 760a5b05ebSAndreas Gohr if ($idx !== false) unset($value[$idx]); 770a5b05ebSAndreas Gohr if ($idx_default !== false) unset($default[$idx_default]); 780a5b05ebSAndreas Gohr } 790a5b05ebSAndreas Gohr 800a5b05ebSAndreas Gohr // handle any remaining values 810a5b05ebSAndreas Gohr if ($this->other != 'never') { 82467c1427SAndreas Gohr $other = implode(',', $value); 830a5b05ebSAndreas Gohr // test equivalent to ($this->_other == 'always' || ($other && $this->_other == 'exists') 840a5b05ebSAndreas Gohr // use != 'exists' rather than == 'always' to ensure invalid values default to 'always' 850a5b05ebSAndreas Gohr if ($this->other != 'exists' || $other) { 860a5b05ebSAndreas Gohr $class = ( 87467c1427SAndreas Gohr (count($default) === count($value)) && 88467c1427SAndreas Gohr (count($value) === count(array_intersect($value, $default))) 890a5b05ebSAndreas Gohr ) ? 900a5b05ebSAndreas Gohr " selectiondefault" : ""; 910a5b05ebSAndreas Gohr 920a5b05ebSAndreas Gohr $input .= '<div class="other' . $class . '">' . "\n"; 930a5b05ebSAndreas Gohr $input .= '<label for="config___' . $key . '_other">' . 940a5b05ebSAndreas Gohr $plugin->getLang($key . '_other') . 950a5b05ebSAndreas Gohr "</label>\n"; 960a5b05ebSAndreas Gohr $input .= '<input id="config___' . $key . '_other" name="config[' . $key . 970a5b05ebSAndreas Gohr '][other]" type="text" class="edit" value="' . htmlspecialchars($other) . 980a5b05ebSAndreas Gohr '" ' . $disable . " />\n"; 990a5b05ebSAndreas Gohr $input .= "</div>\n"; 1000a5b05ebSAndreas Gohr } 1010a5b05ebSAndreas Gohr } 1020a5b05ebSAndreas Gohr $label = '<label>' . $this->prompt($plugin) . '</label>'; 103467c1427SAndreas Gohr return [$label, $input]; 1040a5b05ebSAndreas Gohr } 1050a5b05ebSAndreas Gohr 1060a5b05ebSAndreas Gohr /** 1070a5b05ebSAndreas Gohr * convert comma separated list to an array and combine any complimentary values 1080a5b05ebSAndreas Gohr * 1090a5b05ebSAndreas Gohr * @param string $str 1100a5b05ebSAndreas Gohr * @return array 1110a5b05ebSAndreas Gohr */ 112*d868eb89SAndreas Gohr protected function str2array($str) 113*d868eb89SAndreas Gohr { 1140a5b05ebSAndreas Gohr $array = explode(',', $str); 1150a5b05ebSAndreas Gohr 1160a5b05ebSAndreas Gohr if (!empty($this->combine)) { 1170a5b05ebSAndreas Gohr foreach ($this->combine as $key => $combinators) { 118467c1427SAndreas Gohr $idx = []; 1190a5b05ebSAndreas Gohr foreach ($combinators as $val) { 1200a5b05ebSAndreas Gohr if (($idx[] = array_search($val, $array)) === false) break; 1210a5b05ebSAndreas Gohr } 1220a5b05ebSAndreas Gohr 1230a5b05ebSAndreas Gohr if (count($idx) && $idx[count($idx) - 1] !== false) { 1240a5b05ebSAndreas Gohr foreach ($idx as $i) unset($array[$i]); 1250a5b05ebSAndreas Gohr $array[] = $key; 1260a5b05ebSAndreas Gohr } 1270a5b05ebSAndreas Gohr } 1280a5b05ebSAndreas Gohr } 1290a5b05ebSAndreas Gohr 1300a5b05ebSAndreas Gohr return $array; 1310a5b05ebSAndreas Gohr } 1320a5b05ebSAndreas Gohr 1330a5b05ebSAndreas Gohr /** 1340a5b05ebSAndreas Gohr * convert array of values + other back to a comma separated list, incl. splitting any combined values 1350a5b05ebSAndreas Gohr * 1360a5b05ebSAndreas Gohr * @param array $input 1370a5b05ebSAndreas Gohr * @return string 1380a5b05ebSAndreas Gohr */ 139*d868eb89SAndreas Gohr protected function array2str($input) 140*d868eb89SAndreas Gohr { 1410a5b05ebSAndreas Gohr 1420a5b05ebSAndreas Gohr // handle other 1430a5b05ebSAndreas Gohr $other = trim($input['other']); 144467c1427SAndreas Gohr $other = empty($other) ? [] : explode(',', str_replace(' ', '', $input['other'])); 1450a5b05ebSAndreas Gohr unset($input['other']); 1460a5b05ebSAndreas Gohr 1470a5b05ebSAndreas Gohr $array = array_unique(array_merge($input, $other)); 1480a5b05ebSAndreas Gohr 1490a5b05ebSAndreas Gohr // deconstruct any combinations 1500a5b05ebSAndreas Gohr if (!empty($this->combine)) { 1510a5b05ebSAndreas Gohr foreach ($this->combine as $key => $combinators) { 1520a5b05ebSAndreas Gohr $idx = array_search($key, $array); 1530a5b05ebSAndreas Gohr if ($idx !== false) { 1540a5b05ebSAndreas Gohr unset($array[$idx]); 1550a5b05ebSAndreas Gohr $array = array_merge($array, $combinators); 1560a5b05ebSAndreas Gohr } 1570a5b05ebSAndreas Gohr } 1580a5b05ebSAndreas Gohr } 1590a5b05ebSAndreas Gohr 160467c1427SAndreas Gohr return implode(',', array_unique($array)); 1610a5b05ebSAndreas Gohr } 1620a5b05ebSAndreas Gohr} 163