1<?php 2/** 3 * Configuration Manager admin plugin 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Christopher Smith <chris@jalakai.co.uk> 7 * @author Ben Coburn <btcoburn@silicodon.net> 8 */ 9 10use dokuwiki\plugin\config\core\Configuration; 11use dokuwiki\plugin\config\core\Setting; 12use dokuwiki\plugin\config\core\SettingFieldset; 13use dokuwiki\plugin\config\core\SettingHidden; 14 15/** 16 * All DokuWiki plugins to extend the admin function 17 * need to inherit from this class 18 */ 19class admin_plugin_config extends DokuWiki_Admin_Plugin { 20 21 const METADATA = __DIR__ . 'settings/config.metadata.php'; 22 const IMGDIR = DOKU_BASE . 'lib/plugins/config/images/'; 23 24 protected $_localised_prompts = false; 25 26 /** @var Configuration */ 27 protected $configuration; 28 29 /** 30 * admin_plugin_config constructor. 31 */ 32 public function __construct() { 33 $this->configuration = new Configuration(); 34 } 35 36 /** 37 * handle user request 38 */ 39 public function handle() { 40 global $ID, $INPUT; 41 42 if(!$INPUT->bool('save') || !checkSecurityToken()) { 43 return; 44 } 45 46 // don't go any further if the configuration is locked 47 if($this->configuration->isLocked()) return; 48 49 // update settings and redirect of successful 50 $ok = $this->configuration->updateSettings($INPUT->arr('config')); 51 if($ok) { // no errors 52 try { 53 if($this->configuration->hasChanged()) { 54 $this->configuration->save(); 55 } else { 56 $this->configuration->touch(); 57 } 58 msg($this->getLang('updated'), -1); 59 } catch(Exception $e) { 60 msg($this->getLang('error'), -1); 61 } 62 send_redirect(wl($ID, array('do' => 'admin', 'page' => 'config'), true, '&')); 63 } 64 } 65 66 /** 67 * output appropriate html 68 */ 69 public function html() { 70 $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here. 71 global $lang; 72 global $ID; 73 74 $this->setupLocale(true); 75 76 print $this->locale_xhtml('intro'); 77 78 ptln('<div id="config__manager">'); 79 80 if($this->configuration->isLocked()) { 81 ptln('<div class="info">' . $this->getLang('locked') . '</div>'); 82 } 83 84 // POST to script() instead of wl($ID) so config manager still works if 85 // rewrite config is broken. Add $ID as hidden field to remember 86 // current ID in most cases. 87 ptln('<form action="' . script() . '" method="post">'); 88 ptln('<div class="no"><input type="hidden" name="id" value="' . $ID . '" /></div>'); 89 formSecurityToken(); 90 $this->_print_h1('dokuwiki_settings', $this->getLang('_header_dokuwiki')); 91 92 $in_fieldset = false; 93 $first_plugin_fieldset = true; 94 $first_template_fieldset = true; 95 foreach($this->configuration->getSettings() as $setting) { 96 if(is_a($setting, SettingHidden::class)) { 97 continue; 98 } else if(is_a($setting, settingFieldset::class)) { 99 // config setting group 100 if($in_fieldset) { 101 ptln(' </table>'); 102 ptln(' </div>'); 103 ptln(' </fieldset>'); 104 } else { 105 $in_fieldset = true; 106 } 107 // fixme this should probably be a function in setting: 108 if($first_plugin_fieldset && substr($setting->getKey(), 0, 10) == 'plugin' . Configuration::KEYMARKER) { 109 $this->_print_h1('plugin_settings', $this->getLang('_header_plugin')); 110 $first_plugin_fieldset = false; 111 } else if($first_template_fieldset && substr($setting->getKey(), 0, 7) == 'tpl' . Configuration::KEYMARKER) { 112 $this->_print_h1('template_settings', $this->getLang('_header_template')); 113 $first_template_fieldset = false; 114 } 115 ptln(' <fieldset id="' . $setting->getKey() . '">'); 116 ptln(' <legend>' . $setting->prompt($this) . '</legend>'); 117 ptln(' <div class="table">'); 118 ptln(' <table class="inline">'); 119 } else { 120 // config settings 121 list($label, $input) = $setting->html($this, $this->_error); 122 123 $class = $setting->is_default() 124 ? ' class="default"' 125 : ($setting->is_protected() ? ' class="protected"' : ''); 126 $error = $setting->error() 127 ? ' class="value error"' 128 : ' class="value"'; 129 $icon = $setting->caution() 130 ? '<img src="' . self::IMGDIR . $setting->caution() . '.png" ' . 131 'alt="' . $setting->caution() . '" title="' . $this->getLang($setting->caution()) . '" />' 132 : ''; 133 134 ptln(' <tr' . $class . '>'); 135 ptln(' <td class="label">'); 136 ptln(' <span class="outkey">' . $setting->_out_key(true, true) . '</span>'); 137 ptln(' ' . $icon . $label); 138 ptln(' </td>'); 139 ptln(' <td' . $error . '>' . $input . '</td>'); 140 ptln(' </tr>'); 141 } 142 } 143 144 ptln(' </table>'); 145 ptln(' </div>'); 146 if($in_fieldset) { 147 ptln(' </fieldset>'); 148 } 149 150 // show undefined settings list 151 $undefined_settings = $this->configuration->getUndefined(); 152 if($allow_debug && !empty($undefined_settings)) { 153 /** 154 * Callback for sorting settings 155 * 156 * @param Setting $a 157 * @param Setting $b 158 * @return int if $a is lower/equal/higher than $b 159 */ 160 function _setting_natural_comparison($a, $b) { 161 return strnatcmp($a->getKey(), $b->getKey()); 162 } 163 164 usort($undefined_settings, '_setting_natural_comparison'); 165 $this->_print_h1('undefined_settings', $this->getLang('_header_undefined')); 166 ptln('<fieldset>'); 167 ptln('<div class="table">'); 168 ptln('<table class="inline">'); 169 $undefined_setting_match = array(); 170 foreach($undefined_settings as $setting) { 171 if( 172 preg_match( 173 '/^(?:plugin|tpl)' . Configuration::KEYMARKER . '.*?' . Configuration::KEYMARKER . '(.*)$/', 174 $setting->getKey(), 175 $undefined_setting_match 176 ) 177 ) { 178 $undefined_setting_key = $undefined_setting_match[1]; 179 } else { 180 $undefined_setting_key = $setting->getKey(); 181 } 182 ptln(' <tr>'); 183 ptln( 184 ' <td class="label"><span title="$meta[\'' . $undefined_setting_key . '\']">$' . 185 'conf' . '[\'' . $setting->_out_key() . '\']</span></td>' 186 ); 187 ptln(' <td>' . $this->getLang('_msg_' . get_class($setting)) . '</td>'); 188 ptln(' </tr>'); 189 } 190 ptln('</table>'); 191 ptln('</div>'); 192 ptln('</fieldset>'); 193 } 194 195 // finish up form 196 ptln('<p>'); 197 ptln(' <input type="hidden" name="do" value="admin" />'); 198 ptln(' <input type="hidden" name="page" value="config" />'); 199 200 if(!$this->configuration->isLocked()) { 201 ptln(' <input type="hidden" name="save" value="1" />'); 202 ptln(' <button type="submit" name="submit" accesskey="s">' . $lang['btn_save'] . '</button>'); 203 ptln(' <button type="reset">' . $lang['btn_reset'] . '</button>'); 204 } 205 206 ptln('</p>'); 207 208 ptln('</form>'); 209 ptln('</div>'); 210 } 211 212 /** 213 * @param bool $prompts 214 */ 215 public function setupLocale($prompts = false) { 216 parent::setupLocale(); 217 if(!$prompts || $this->_localised_prompts) return; 218 $this->configuration->getLangs(); 219 $this->_localised_prompts = true; 220 } 221 222 /** 223 * Generates a two-level table of contents for the config plugin. 224 * 225 * @author Ben Coburn <btcoburn@silicodon.net> 226 * 227 * @return array 228 */ 229 public function getTOC() { 230 $this->setupLocale(true); 231 232 $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here. 233 234 // gather toc data 235 $toc = array('conf' => array(), 'plugin' => array(), 'template' => null); 236 foreach($this->configuration->getSettings() as $setting) { 237 if(is_a($setting, 'setting_fieldset')) { 238 // FIXME as above this should go into Setting class 239 if(substr($setting->getKey(), 0, 10) == 'plugin' . Configuration::KEYMARKER) { 240 $toc['plugin'][] = $setting; 241 } else if(substr($setting->getKey(), 0, 7) == 'tpl' . Configuration::KEYMARKER) { 242 $toc['template'] = $setting; 243 } else { 244 $toc['conf'][] = $setting; 245 } 246 } 247 } 248 249 // build toc 250 $t = array(); 251 252 $check = false; 253 $title = $this->getLang('_configuration_manager'); 254 $t[] = html_mktocitem(sectionID($title, $check), $title, 1); 255 $t[] = html_mktocitem('dokuwiki_settings', $this->getLang('_header_dokuwiki'), 1); 256 /** @var setting $setting */ 257 foreach($toc['conf'] as $setting) { 258 $name = $setting->prompt($this); 259 $t[] = html_mktocitem($setting->getKey(), $name, 2); 260 } 261 if(!empty($toc['plugin'])) { 262 $t[] = html_mktocitem('plugin_settings', $this->getLang('_header_plugin'), 1); 263 } 264 foreach($toc['plugin'] as $setting) { 265 $name = $setting->prompt($this); 266 $t[] = html_mktocitem($setting->getKey(), $name, 2); 267 } 268 if(isset($toc['template'])) { 269 $t[] = html_mktocitem('template_settings', $this->getLang('_header_template'), 1); 270 $setting = $toc['template']; 271 $name = $setting->prompt($this); 272 $t[] = html_mktocitem($setting->getKey(), $name, 2); 273 } 274 if(count($this->configuration->getUndefined()) && $allow_debug) { 275 $t[] = html_mktocitem('undefined_settings', $this->getLang('_header_undefined'), 1); 276 } 277 278 return $t; 279 } 280 281 /** 282 * @param string $id 283 * @param string $text 284 */ 285 protected function _print_h1($id, $text) { 286 ptln('<h1 id="' . $id . '">' . $text . '</h1>'); 287 } 288 289 /** 290 * Adds a translation to this plugin's language array 291 * 292 * @param string $key 293 * @param string $value 294 */ 295 public function addLang($key, $value) { 296 if(!$this->localised) $this->setupLocale(); 297 $this->lang[$key] = $value; 298 } 299} 300