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