1<?php 2/** 3 * DokuWiki Plugin lightweightcss (Action Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author i-net /// software <tools@inetsoftware.de> 7 */ 8 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12class action_plugin_lightweightcss extends DokuWiki_Action_Plugin { 13 14 private const DEFAULT_ADMIN_INCLUDE = array( 15 '/css/admin/', 16 '/lib/plugins/config/', 17 '/lib/plugins/searchindex/', 18 '/lib/plugins/sync/', 19 '/lib/plugins/batchedit/', 20 '/lib/plugins/usermanager/', 21 '/lib/plugins/upgrade/', 22 '/lib/plugins/extension/', 23 '/lib/plugins/tagsections/', 24 '/lib/plugins/move/', 25 '/lib/plugins/acl/', 26 '/lib/plugins/multiorphan/', 27 '/lib/plugins/edittable/', 28 '/lib/plugins/sectionedit/', 29 '/lib/plugins/wrap/', 30 '/lib/scripts/', 31 '/lib/styles/', 32 ); 33 34 private const DEFAULT_INCLUDE = array( 35 '/lib/tpl/', 36 '/lib/plugins/', 37 ); 38 39 private const DEFAULT_EXCLUDE = array( 40 '/css/admin/', 41 '/lib/plugins/dw2pdf/', 42 '/lib/plugins/box2/', 43 '/lib/plugins/config/', 44 '/lib/plugins/uparrow/', 45 '/lib/plugins/imagebox/', 46 '/lib/plugins/imagereference/', 47 48 '/lib/plugins/searchindex/', 49 '/lib/plugins/poll/', 50 '/lib/plugins/cloud/', 51 '/lib/plugins/sync/', 52 '/lib/plugins/wrap/', 53 '/lib/plugins/blog/', 54 '/lib/plugins/batchedit/', 55 '/lib/plugins/usermanager/', 56 '/lib/plugins/upgrade/', 57 '/lib/plugins/imagebox/', 58 '/lib/plugins/extension/', 59 '/lib/plugins/tagsections/', 60 '/lib/plugins/javadoc/', 61 '/lib/plugins/toctweak/', 62 '/lib/plugins/move/', 63 '/lib/plugins/acl/', 64 '/lib/plugins/multiorphan/', 65 '/lib/plugins/edittable/', 66 '/lib/plugins/sectionedit/', 67 '/lib/plugins/styling/', 68 '/lib/plugins/tag/', 69/* 70 'lib/scripts/', 71 'lib/styles/', 72 'conf/userall', 73*/ 74 ); 75 76 private const templateStyles = null; 77 78 /** 79 * Registers a callback function for a given event 80 * 81 * @param Doku_Event_Handler $controller DokuWiki's event controller object 82 * @return void 83 */ 84 public function register(Doku_Event_Handler $controller) { 85 global $INPUT; 86 $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handle_tpl_metaheader_output'); 87 $controller->register_hook('CSS_STYLES_INCLUDED', 'BEFORE', $this, 'handle_css_styles'); 88 89 $controller->register_hook('CSS_CACHE_USE', 'BEFORE', $this, 'handle_use_cache'); 90 } 91 92 /** 93 * Insert an extra script tag for users that have AUTH_EDIT or better 94 * 95 * @param Doku_Event $event event object by reference 96 * @param mixed $param [the parameters passed as fifth argument to register_hook() when this 97 * handler was registered] 98 * @return void 99 */ 100 public function handle_tpl_metaheader_output(Doku_Event &$event, $param) { 101 global $ID, $updateVersion, $conf; 102 103 // add css if user has better auth than AUTH_EDIT 104 if ( auth_quickaclcheck( $ID ) >= AUTH_EDIT ) { 105 $tseed = $updateVersion; 106 $tseed = md5($tseed.'admin'); 107 $event->data['link'][] = array( 108 'rel' => 'stylesheet', 'type'=> 'text/css', 109 'href'=> DOKU_BASE.'lib/exe/css.php?t='.rawurlencode($conf['template']).'&f=admin&tseed='.$tseed 110 ); 111 } 112 } 113 114 /** 115 * This function serves debugging purposes and has to be enabled in the register phase 116 * 117 * @param Doku_Event $event event object by reference 118 * @param mixed $param [the parameters passed as fifth argument to register_hook() when this 119 * handler was registered] 120 * @return void 121 */ 122 public function handle_use_cache(Doku_Event &$event, $param) { 123 global $INPUT; 124 125 // We need different keys for each style sheet. 126 $event->data->key .= $INPUT->str('f', 'style'); 127 $event->data->cache = getCacheName( $event->data->key, $event->data->ext ); 128 129 return true; 130 } 131 132 /** 133 * Finally, handle the JS script list. The script would be fit to do even more stuff / types 134 * but handles only admin and default currently. 135 * 136 * @param Doku_Event $event event object by reference 137 * @param mixed $param [the parameters passed as fifth argument to register_hook() when this 138 * handler was registered] 139 * @return void 140 */ 141 public function handle_css_styles(Doku_Event &$event, $param) { 142 global $INPUT; 143 144 $this->setupStyles(); 145 146 switch( $event->data['mediatype'] ) { 147 148 case 'print': 149 case 'screen': 150 case 'all': 151 // Filter for user styles 152 $allowed = array_filter( array_keys($event->data['files']), array($this, 'filter_css') ); 153 $event->data['files'] = array_intersect_key($event->data['files'], array_flip($allowed)); 154 //$event->data['encapsulate'] = $INPUT->str('f', 'style') != 'admin'; 155 break; 156 157 case 'speech': 158 case 'DW_DEFAULT': 159 $event->preventDefault(); 160 break; 161 } 162 } 163 164 /** 165 * A simple filter function to check the input string against a list of path-parts that are allowed 166 * 167 * @param string $str the script file to check against the list 168 * @param mixed $list the list of path parts to test 169 * @return boolean 170 */ 171 private function includeFilter( $str, $list ) { 172 foreach( $list as $entry ) { 173 if ( strpos( $str, $entry ) ) return true; 174 } 175 176 return false; 177 } 178 179 /** 180 * A simple filter function to check the input string against a list of path-parts that are allowed 181 * Is the inversion of includeFilter( $str, $list ) 182 * 183 * @param string $str the script file to check against the list 184 * @param mixed $list the list of path parts to test 185 * @return boolean 186 */ 187 private function excludeFilter( $str, $list ) { 188 return !$this->includeFilter( $str, $list ); 189 } 190 191 /** 192 * Filters scripts that are intended for admins only 193 * 194 * @param string $script the script file to check against the list 195 * @return boolean 196 */ 197 private function filter_css( $script ) { 198 global $INPUT; 199 if ( $INPUT->str('f', 'style') == 'admin' ) { 200 return $this->includeFilter( $script, $this->templateStyles['admin'] ); 201 } else { 202 return $this->includeFilter( $script, $this->templateStyles['include']) && $this->excludeFilter( $script, $this->templateStyles['exclude']); 203 } 204 } 205 206 private function setupStyles() { 207 global $CONF; 208 global $INPUT; 209 210 if ( !is_null( $this->templateStyles) ) { 211 return; 212 } 213 214 $this->templateStyles = array( 215 'admin' => action_plugin_lightweightcss::DEFAULT_ADMIN_INCLUDE, 216 'include' => action_plugin_lightweightcss::DEFAULT_INCLUDE, 217 'exclude' => action_plugin_lightweightcss::DEFAULT_EXCLUDE 218 ); 219 220 $tpl = $INPUT->str('t', $conf['template']); 221 $inifile = DOKU_INC . 'lib/tpl/' . $tpl . '/style.ini'; 222 223 if (!file_exists($inifile)) { 224 return; 225 } 226 227 $styleini = parse_ini_file($inifile, true); 228 if ( array_key_exists('lightweightcss', $styleini) ) { 229 230 foreach( $styleini['lightweightcss'] as $file => $mode ) { 231 232 switch( $mode ) { 233 case 'admin': 234 case 'include': 235 case 'exclude': 236 break; 237 default: 238 continue 2; 239 } 240 241 if ( !array_key_exists($mode, $this->templateStyles) ) { 242 $this->templateStyles[$mode] = array(); 243 } 244 245 array_push( $this->templateStyles[$mode], $file); 246 $this->templateStyles[$mode] = array_unique( $this->templateStyles[$mode] ); 247 } 248 } 249 } 250} 251 252// vim:ts=4:sw=4:et: 253