1<?php 2/** 3 * Action Plugin stylingpages 4 * 5 * @license GPL-2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Flávio J. Saraiva <flaviojs2005@gmail.com> 7 */ 8 9/** 10 * Allows users to change the css/js files of this plugin with wikitext. 11 * 12 * @see README 13 */ 14class action_plugin_stylingpages extends DokuWiki_Action_Plugin 15{ 16 /** 17 * Registers callback functions. 18 * 19 * @param Doku_Event_Handler $controller 20 */ 21 public function register(Doku_Event_Handler $controller) 22 { 23 $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'BEFORE', $this, 'handleSaveBefore', null, 10); 24 $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'AFTER', $this, 'handleSaveAfter', null, 10); 25 } 26 27 /** 28 * Trigger update when there are no changes. 29 */ 30 public function handleSaveBefore(Doku_Event $event, $param) 31 { 32 if (!$event->data['contentChanged']) { 33 // the AFTER event is not called 34 $this->tryUpdate($event); 35 } 36 } 37 38 /** 39 * Trigger update when there are changes. 40 */ 41 public function handleSaveAfter(Doku_Event $event, $param) 42 { 43 $this->tryUpdate($event); 44 } 45 46 /** 47 * Update files only if there are file patterns for 48 * the page and you are allowed to write in it. 49 */ 50 public function tryUpdate(Doku_Event $event) 51 { 52 $page = $event->data['id']; 53 54 // get file patterns of the page 55 $patterns = array(); 56 $entries = $this->getConf('page_files'); 57 foreach ($entries as $entry) { 58 $parts = explode('=', $entry, 2); // "page=file_pattern" 59 if (count($parts) === 2 && $parts[0] === $page) { 60 $pattern = $parts[1]; 61 if (@preg_match($pattern, '') === false) { 62 msg('Invalid pattern <code>' . hsc($pattern) . '</code>', -1); 63 } else { 64 $patterns[] = $parts[1]; 65 } 66 } 67 } 68 69 // check update requirements 70 if (count($patterns) > 0 && auth_quickaclcheck($page) >= AUTH_WRITE) { 71 $wikitext = $event->data['newContent']; 72 $this->update($patterns, $wikitext); 73 } 74 } 75 76 /** 77 * Update files matching the patterns 78 * with the code blocks in the wikitext. 79 */ 80 public function update($patterns, $wikitext) 81 { 82 global $conf; 83 global $config_cascade; 84 85 $dir = DOKU_PLUGIN . 'stylingpages/'; 86 $haschanges = false; 87 88 // get file contents from wikitext 89 $contents = array(); // array(file => content) 90 $instructions = p_get_instructions($wikitext); 91 foreach ($instructions as $instruction) { 92 // array('code', array(content, format, file), pos) 93 if ($instruction[0] === 'code' && count($instruction[1]) > 2) { 94 $content = $instruction[1][0]; 95 $file = $instruction[1][2]; 96 if (isset($contents[$file])) { 97 $contents[$file] .= $content; // multiple blocks with the same file are appended 98 } else { 99 $contents[$file] = $content; 100 } 101 } 102 } 103 104 // delete unreferenced files 105 $it = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS); 106 $it = new RecursiveIteratorIterator($it); 107 $it->rewind(); 108 while ($it->valid()) { 109 $file = $it->getSubPathName(); 110 $file = str_replace('\\', '/', $file); 111 foreach ($patterns as $pattern) { 112 if (preg_match($pattern, $file) && !isset($contents[$file])) { 113 $haschanges = true; 114 $path = $dir . $file; 115 $msg = $this->getLang('deleting_file'); 116 $msg = str_replace('$1', $file, $msg); 117 msg($msg); 118 @unlink($path); 119 } 120 } 121 $it->next(); 122 } 123 124 // create or replace referenced files 125 foreach ($contents as $file => $content) { 126 foreach ($patterns as $pattern) { 127 if (preg_match($pattern, $file)) { 128 $haschanges = true; 129 $path = $dir . $file; 130 if (file_exists($path)) { 131 $msg = $this->getLang('replacing_file'); 132 $msg = str_replace('$1', $file, $msg); 133 msg($msg); 134 } else { 135 $msg = $this->getLang('creating_file'); 136 $msg = str_replace('$1', $file, $msg); 137 msg($msg); 138 @mkdir(dirname($path), $conf['dmode'], true); 139 } 140 $fh = @fopen($path, 'wb') ; 141 @fwrite($fh, $content); 142 @fclose($fh); 143 } 144 } 145 } 146 147 // purge cache (from helper_plugin_extension_extension::purgeCache) 148 if ($haschanges) { 149 @touch(reset($config_cascade['main']['local'])); 150 } 151 } 152} 153