1<?php 2use dokuwiki\Extension\AdminPlugin; 3use dokuwiki\StyleUtils; 4/** 5 * DokuWiki Plugin styling (Admin Component) 6 * 7 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 8 * @author Andreas Gohr <andi@splitbrain.org> 9 */ 10class admin_plugin_styling extends AdminPlugin 11{ 12 13 public $ispopup = false; 14 15 /** 16 * @return int sort number in admin menu 17 */ 18 public function getMenuSort() 19 { 20 return 1000; 21 } 22 23 /** 24 * @return bool true if only access for superuser, false is for superusers and moderators 25 */ 26 public function forAdminOnly() 27 { 28 return true; 29 } 30 31 /** 32 * handle the different actions (also called from ajax) 33 */ 34 public function handle() 35 { 36 global $INPUT; 37 $run = $INPUT->extract('run')->str('run'); 38 if (!$run) return; 39 if (!checkSecurityToken()) return; 40 $run = 'run'.ucfirst($run); 41 $this->$run(); 42 } 43 44 /** 45 * Render HTML output, e.g. helpful text and a form 46 */ 47 public function html() 48 { 49 $class = 'nopopup'; 50 if ($this->ispopup) $class = 'ispopup page'; 51 52 echo '<div id="plugin__styling" class="'.$class.'">'; 53 ptln('<h1>'.$this->getLang('menu').'</h1>'); 54 $this->form(); 55 echo '</div>'; 56 } 57 58 /** 59 * Create the actual editing form 60 */ 61 public function form() 62 { 63 global $conf; 64 global $ID; 65 66 $styleUtil = new StyleUtils($conf['template'], true, true); 67 $styleini = $styleUtil->cssStyleini(); 68 $replacements = $styleini['replacements']; 69 70 if ($this->ispopup) { 71 $target = DOKU_BASE.'lib/plugins/styling/popup.php'; 72 } else { 73 $target = wl($ID, ['do' => 'admin', 'page' => 'styling']); 74 } 75 76 if (empty($replacements)) { 77 echo '<p class="error">'.$this->getLang('error').'</p>'; 78 } else { 79 echo $this->locale_xhtml('intro'); 80 81 echo '<form class="styling" method="post" action="'.$target.'">'; 82 formSecurityToken(); 83 84 echo '<table><tbody>'; 85 foreach ($replacements as $key => $value) { 86 $name = tpl_getLang($key); 87 if (empty($name)) $name = $this->getLang($key); 88 if (empty($name)) $name = $key; 89 90 echo '<tr>'; 91 echo '<td><label for="tpl__'.hsc($key).'">'.$name.'</label></td>'; 92 echo '<td><input type="'.$this->colorType($value).'" name="tpl['.hsc($key).']" id="tpl__'.hsc($key).'" 93 value="'.hsc($this->colorValue($value)).'" dir="ltr" required="required"/></td>'; 94 echo '</tr>'; 95 } 96 echo '</tbody></table>'; 97 98 echo '<p>'; 99 echo '<button type="submit" name="run[preview]" class="btn_preview primary">'. 100 $this->getLang('btn_preview').'</button> '; 101 #FIXME only if preview.ini exists: 102 echo '<button type="submit" name="run[reset]">'.$this->getLang('btn_reset').'</button>'; 103 echo '</p>'; 104 105 echo '<p>'; 106 echo '<button type="submit" name="run[save]" class="primary">'.$this->getLang('btn_save').'</button>'; 107 echo '</p>'; 108 109 echo '<p>'; 110 #FIXME only if local.ini exists: 111 echo '<button type="submit" name="run[revert]">'.$this->getLang('btn_revert').'</button>'; 112 echo '</p>'; 113 114 echo '</form>'; 115 116 echo tpl_locale_xhtml('style'); 117 } 118 } 119 120 /** 121 * Adjust three char color codes to the 6 char one supported by browser's color input 122 * 123 * @param string $value 124 * @return string 125 */ 126 protected function colorValue($value) 127 { 128 if (preg_match('/^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/', $value, $match)) { 129 return '#' . $match[1] . $match[1] . $match[2] . $match[2] . $match[3] . $match[3]; 130 } 131 return $value; 132 } 133 134 /** 135 * Decide the input type based on the value 136 * 137 * @param string $value 138 * @return string color|text 139 */ 140 protected function colorType($value) 141 { 142 if (preg_match('/^#([0-9a-fA-F]{3}){1,2}$/', $value)) { 143 return 'color'; 144 } else { 145 return 'text'; 146 } 147 } 148 149 /** 150 * saves the preview.ini (alos called from ajax directly) 151 */ 152 public function runPreview() 153 { 154 global $conf; 155 $ini = $conf['cachedir'].'/preview.ini'; 156 io_saveFile($ini, $this->makeini()); 157 } 158 159 /** 160 * deletes the preview.ini 161 */ 162 protected function runReset() 163 { 164 global $conf; 165 $ini = $conf['cachedir'].'/preview.ini'; 166 io_saveFile($ini, ''); 167 } 168 169 /** 170 * deletes the local style.ini replacements 171 */ 172 protected function runRevert() 173 { 174 $this->replaceIni(''); 175 $this->runReset(); 176 } 177 178 /** 179 * save the local style.ini replacements 180 */ 181 protected function runSave() 182 { 183 $this->replaceIni($this->makeini()); 184 $this->runReset(); 185 } 186 187 /** 188 * create the replacement part of a style.ini from submitted data 189 * 190 * @return string 191 */ 192 protected function makeini() 193 { 194 global $INPUT; 195 196 $ini = "[replacements]\n"; 197 $ini .= ";These overwrites have been generated from the Template styling Admin interface\n"; 198 $ini .= ";Any values in this section will be overwritten by that tool again\n"; 199 foreach ($INPUT->arr('tpl') as $key => $val) { 200 $ini .= $key.' = "'.addslashes($val).'"'."\n"; 201 } 202 203 return $ini; 204 } 205 206 /** 207 * replaces the replacement parts in the local ini 208 * 209 * @param string $new the new ini contents 210 */ 211 protected function replaceIni($new) 212 { 213 global $conf; 214 $ini = DOKU_CONF."tpl/".$conf['template']."/style.ini"; 215 if (file_exists($ini)) { 216 $old = io_readFile($ini); 217 $old = preg_replace('/\[replacements\]\n.*?(\n\[.*]|$)/s', '\\1', $old); 218 $old = trim($old); 219 } else { 220 $old = ''; 221 } 222 223 io_makeFileDir($ini); 224 io_saveFile($ini, "$old\n\n$new"); 225 } 226} 227 228// vim:ts=4:sw=4:et: 229