[30114] | 1 | <?php
|
---|
| 2 | /**
|
---|
| 3 | * A plugin to provide compatibility between the marked up text format used
|
---|
| 4 | * by the Greenstone Documentation Generation scripts and Dokuwiki
|
---|
| 5 | *
|
---|
| 6 | * Features:
|
---|
| 7 | * - hide the <!-- id:XXX --> markers used during translation process
|
---|
| 8 | *
|
---|
| 9 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
---|
| 10 | */
|
---|
| 11 |
|
---|
| 12 | if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
|
---|
| 13 | if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
|
---|
| 14 | require_once(DOKU_PLUGIN.'syntax.php');
|
---|
| 15 |
|
---|
| 16 | /**
|
---|
| 17 | * All DokuWiki plugins to extend the parser/rendering mechanism
|
---|
| 18 | * need to inherit from this class
|
---|
| 19 | */
|
---|
| 20 | class syntax_plugin_greenstonedocs
|
---|
| 21 | extends DokuWiki_Syntax_Plugin
|
---|
| 22 | {
|
---|
| 23 |
|
---|
| 24 | /** The plugin should only effect pages within this namespace.
|
---|
| 25 | */
|
---|
| 26 | private $target_namespace_prefix;
|
---|
| 27 |
|
---|
| 28 |
|
---|
| 29 | /** @function __construct()
|
---|
| 30 | */
|
---|
| 31 | public function __construct()
|
---|
| 32 | {
|
---|
| 33 | global $conf;
|
---|
| 34 |
|
---|
| 35 | $this->target_namespace_prefix = $this->getConf('currentnamespace');
|
---|
| 36 | // Prerequisite testing. Ensure the following list of plugins are also
|
---|
| 37 | // installed and complain otherwise.
|
---|
| 38 | if ($this->getConf('checkprereq'))
|
---|
| 39 | {
|
---|
| 40 | $prereqs = array_flip(explode(' ', $this->getConf('prerequisiteplugins')));
|
---|
| 41 | if ($dh = opendir(DOKU_PLUGIN))
|
---|
| 42 | {
|
---|
| 43 | while (($file = readdir($dh)) !== false)
|
---|
| 44 | {
|
---|
| 45 | $path = DOKU_PLUGIN . $file;
|
---|
| 46 | if (substr($file, 0, 1) != '.' && is_dir($path))
|
---|
| 47 | {
|
---|
| 48 | if (isset($prereqs[$file]))
|
---|
| 49 | {
|
---|
| 50 | unset($prereqs[$file]);
|
---|
| 51 | }
|
---|
| 52 | }
|
---|
| 53 | }
|
---|
| 54 | closedir($dh);
|
---|
| 55 | }
|
---|
| 56 | if (count($prereqs) > 0)
|
---|
| 57 | {
|
---|
| 58 | ksort($prereqs);
|
---|
| 59 | foreach ($prereqs as $plugin_name => $value)
|
---|
| 60 | {
|
---|
| 61 | msg("The Greenstone Wiki requires the plugin: " . $plugin_name, -1);
|
---|
| 62 | }
|
---|
| 63 | }
|
---|
| 64 | else
|
---|
| 65 | {
|
---|
| 66 | $this->_resetConf('checkprereq');
|
---|
| 67 | }
|
---|
| 68 | }
|
---|
| 69 | // Check the plugin configuration and, if checked, proceed to auto-
|
---|
| 70 | // matically update the internal links within the Greenstone wiki pages
|
---|
| 71 | // to have a different base namespace
|
---|
[30310] | 72 | $update_namespace = $this->getConf('updatenamespace');
|
---|
| 73 | if ($update_namespace != 0)
|
---|
[30114] | 74 | {
|
---|
| 75 | // Determine the starting point for the update
|
---|
[30226] | 76 | $base_dir = DOKU_INC . 'data/pages/';
|
---|
[30310] | 77 | // - ensure trailing : for consistency in namespaces
|
---|
| 78 | $current_namespace = $this->getConf('currentnamespace');
|
---|
| 79 | if (!empty($current_namespace))
|
---|
[30226] | 80 | {
|
---|
[30310] | 81 | $base_dir .= $current_namespace . '/';
|
---|
[30226] | 82 | }
|
---|
[30114] | 83 | if (strlen($current_namespace) > 0 && substr($current_namespace, -1) != ':')
|
---|
| 84 | {
|
---|
| 85 | $current_namespace .= ':';
|
---|
| 86 | }
|
---|
| 87 | $old_namespace = $this->getConf('oldnamespace');
|
---|
| 88 | if (strlen($old_namespace) > 0 && substr($old_namespace, -1) != ':')
|
---|
| 89 | {
|
---|
| 90 | $old_namespace .= ':';
|
---|
| 91 | }
|
---|
| 92 | // - recursive call to do the actual search and replace
|
---|
| 93 | $raw_child_namespaces = explode(' ', $this->getConf('childnamespaces'));
|
---|
| 94 | $child_namespaces = array();
|
---|
| 95 | foreach ($raw_child_namespaces as $raw_child_namespace)
|
---|
| 96 | {
|
---|
| 97 | if (strlen($raw_child_namespace) > 0 && substr($raw_child_namespace, -1) != ':')
|
---|
| 98 | {
|
---|
| 99 | $raw_child_namespace .= ':';
|
---|
| 100 | }
|
---|
| 101 | $child_namespaces[] = $raw_child_namespace;
|
---|
| 102 | }
|
---|
| 103 | // Begin search
|
---|
| 104 | $this->_replaceInternalLinkNamespace($base_dir, $old_namespace, $current_namespace, $child_namespaces);
|
---|
| 105 | // Finally, we reset the configuration option back to off.
|
---|
| 106 | $this->_resetConf('updatenamespace');
|
---|
| 107 | // Let users know what has happened
|
---|
| 108 | msg("Sucessfully performed one-time update of namespace in Greenstone Documentation.", 1);
|
---|
| 109 | }
|
---|
| 110 | }
|
---|
| 111 | /** __construct() **/
|
---|
| 112 |
|
---|
| 113 |
|
---|
| 114 | /**
|
---|
| 115 | */
|
---|
| 116 | function _resetConf($key)
|
---|
| 117 | {
|
---|
| 118 | // Reset the configuration option back to off.
|
---|
| 119 | // - file on disk
|
---|
| 120 | $config_file_path = DOKU_CONF . 'local.php';
|
---|
| 121 | $content = file_get_contents($config_file_path);
|
---|
| 122 | $option_prefix = '$conf[\'plugin\'][\'greenstonedocs\'][\'' . $key . '\']';
|
---|
| 123 | if (strpos($content, $option_prefix) !== false)
|
---|
| 124 | {
|
---|
| 125 | $content = str_replace($option_prefix . ' = 1;',
|
---|
| 126 | $option_prefix . ' = 0;',
|
---|
| 127 | $content);
|
---|
| 128 | }
|
---|
| 129 | else
|
---|
| 130 | {
|
---|
| 131 | $content .= "\n" . $option_prefix . " = 0;";
|
---|
| 132 | }
|
---|
| 133 | file_put_contents($config_file_path, $content);
|
---|
| 134 | // - in memory cache
|
---|
| 135 | $conf[$key] = 0;
|
---|
| 136 | }
|
---|
| 137 | /** _resetConf($key) **/
|
---|
| 138 |
|
---|
| 139 |
|
---|
| 140 | /** @function _replaceInternalLinkNamespace()
|
---|
| 141 | */
|
---|
| 142 | function _replaceInternalLinkNamespace($dir, $old_namespace, $new_namespace, $child_namespaces)
|
---|
| 143 | {
|
---|
| 144 | $files = array();
|
---|
| 145 | if ($dh = opendir($dir))
|
---|
| 146 | {
|
---|
| 147 | while (($file = readdir($dh)) !== false)
|
---|
| 148 | {
|
---|
| 149 | if (substr($file, 0, 1) != '.')
|
---|
| 150 | {
|
---|
| 151 | $files[] = $file;
|
---|
| 152 | }
|
---|
| 153 | }
|
---|
| 154 | closedir($dh);
|
---|
| 155 | }
|
---|
| 156 | foreach ($files as $file)
|
---|
| 157 | {
|
---|
| 158 | $path = $dir . $file;
|
---|
| 159 | // - continue the recursive search through child directories
|
---|
| 160 | if (is_dir($path))
|
---|
| 161 | {
|
---|
| 162 | $this->_replaceInternalLinkNamespace($path . '/', $old_namespace, $new_namespace, $child_namespaces);
|
---|
| 163 | }
|
---|
| 164 | else if (substr($file, -4) == '.txt')
|
---|
| 165 | {
|
---|
| 166 | // - none of these files are *that* large, so read them
|
---|
| 167 | // into memory for processing
|
---|
| 168 | $page_content = file_get_contents($path);
|
---|
| 169 | // - we are looking for internal links that contain the
|
---|
| 170 | // old namespace (or '') followed by an expected child
|
---|
| 171 | // namespace - and then replace the old namespace
|
---|
| 172 | $pattern = '/(\[\[)' . $old_namespace . '(' . implode('|', $child_namespaces) . ')(.+?\]\])/';
|
---|
| 173 | $replace = '${1}'. $new_namespace . '${2}${3}';
|
---|
| 174 | $replace_count = 0;
|
---|
| 175 | $page_content = preg_replace($pattern, $replace, $page_content, -1, $replace_count);
|
---|
| 176 | // - special case: also fix up the mismatched imgcaption tags
|
---|
| 177 | $pattern = '/(<imgcaption .+?>)(<\/imgcaption>)\s*(\{\{.+?\}\})/s';
|
---|
| 178 | $replace = '${1}${3}${2}';
|
---|
[30226] | 179 | $image_replace_count = 0;
|
---|
| 180 | $page_content = preg_replace($pattern, $replace, $page_content, -1, $image_replace_count);
|
---|
| 181 | $replace_count = $replace_count + $image_replace_count;
|
---|
[30114] | 182 | if ($replace_count > 0)
|
---|
| 183 | {
|
---|
| 184 | file_put_contents($path, $page_content);
|
---|
| 185 | }
|
---|
| 186 | }
|
---|
| 187 | }
|
---|
| 188 | }
|
---|
| 189 | /** @function _replaceInternalLinkNamespace() **/
|
---|
| 190 |
|
---|
| 191 |
|
---|
| 192 | /**
|
---|
| 193 | * Should return the type of syntax this plugin defines.
|
---|
| 194 | * - notice that the typo (substition == substitution) is necessary
|
---|
| 195 | */
|
---|
| 196 | function getType()
|
---|
| 197 | {
|
---|
| 198 | return 'substition';
|
---|
| 199 | }
|
---|
| 200 |
|
---|
| 201 | /**
|
---|
| 202 | * Returns a number used to determine in which order modes are added.
|
---|
| 203 | */
|
---|
| 204 | function getSort()
|
---|
| 205 | {
|
---|
| 206 | return 0;
|
---|
| 207 | }
|
---|
| 208 |
|
---|
| 209 | /**
|
---|
| 210 | * Connect lookup pattern to lexer.
|
---|
| 211 | */
|
---|
| 212 | function connectTo($mode)
|
---|
| 213 | {
|
---|
| 214 | $current_full_namespace = getNS(getID('id',true));
|
---|
| 215 | // Note that the result is FALSE if no match, and should be 0 if name-
|
---|
| 216 | // space starts with prefix.
|
---|
[30226] | 217 | if (empty($this->target_namespace_prefix) || strpos($current_full_namespace, $this->target_namespace_prefix) === 0)
|
---|
[30114] | 218 | {
|
---|
| 219 | // Hiding the section/translation ID tags in headers
|
---|
| 220 | $this->Lexer->addSpecialPattern( '^[ \t]*={2,6}\s?<!-- s?id:.+? -->[^\n]+={2,6}[ \t]*(?=\n)', $mode, 'plugin_greenstonedocs');
|
---|
| 221 | // Hiding the translation ID tags in paragraph text
|
---|
| 222 | $this->Lexer->addSpecialPattern('<!-- id:[^\s]+ -->', $mode, 'plugin_greenstonedocs');
|
---|
| 223 | // Hiding the translation ID tags in image captions
|
---|
| 224 | $this->Lexer->addSpecialPattern('\%!-- id:[^\s]+ --\%', $mode, 'plugin_greenstonedocs');
|
---|
| 225 | }
|
---|
| 226 | }
|
---|
| 227 |
|
---|
| 228 | /**
|
---|
| 229 | * Handler to prepare matched data for the rendering process.
|
---|
| 230 | *
|
---|
| 231 | * <p>
|
---|
| 232 | * The <tt>$aState</tt> parameter gives the type of pattern
|
---|
| 233 | * which triggered the call to this method:
|
---|
| 234 | * </p>
|
---|
| 235 | * <dl>
|
---|
| 236 | * <dt>DOKU_LEXER_ENTER</dt>
|
---|
| 237 | * <dd>a pattern set by <tt>addEntryPattern()</tt></dd>
|
---|
| 238 | * <dt>DOKU_LEXER_MATCHED</dt>
|
---|
| 239 | * <dd>a pattern set by <tt>addPattern()</tt></dd>
|
---|
| 240 | * <dt>DOKU_LEXER_EXIT</dt>
|
---|
| 241 | * <dd> a pattern set by <tt>addExitPattern()</tt></dd>
|
---|
| 242 | * <dt>DOKU_LEXER_SPECIAL</dt>
|
---|
| 243 | * <dd>a pattern set by <tt>addSpecialPattern()</tt></dd>
|
---|
| 244 | * <dt>DOKU_LEXER_UNMATCHED</dt>
|
---|
| 245 | * <dd>ordinary text encountered within the plugin's syntax mode
|
---|
| 246 | * which doesn't match any pattern.</dd>
|
---|
| 247 | * </dl>
|
---|
| 248 | * @param $aMatch String The text matched by the patterns.
|
---|
| 249 | * @param $aState Integer The lexer state for the match.
|
---|
| 250 | * @param $aPos Integer The character position of the matched text.
|
---|
| 251 | * @param $aHandler Object Reference to the Doku_Handler object.
|
---|
| 252 | * @return Integer The current lexer state for the match.
|
---|
| 253 | * @public
|
---|
| 254 | * @see render()
|
---|
| 255 | * @static
|
---|
| 256 | */
|
---|
| 257 | function handle($match, $state, $pos, &$handler)
|
---|
| 258 | {
|
---|
| 259 | if (preg_match('/wiki/i', $match))
|
---|
| 260 | {
|
---|
| 261 | return array($state, $match, array('action'=>'debug',
|
---|
| 262 | 'pos'=>$pos));
|
---|
| 263 | }
|
---|
| 264 | // Special case for IDs (section and language) in header strings
|
---|
| 265 | if (preg_match('/={2,6}\s?<!-- (s?id):.+? -->[^\n]+={2,6}/', $match))
|
---|
| 266 | {
|
---|
| 267 | //msg("<b>[DEBUG]</b> Title: " . htmlspecialchars($match), 2, '', '', MSG_ADMINS_ONLY);
|
---|
| 268 | $match = preg_replace('/<!-- sid:.+? -->/', '', $match);
|
---|
| 269 | $match = preg_replace('/<!-- id:.+? -->/', '', $match);
|
---|
| 270 | $handler->header($match, $state, $pos);
|
---|
| 271 | return true;
|
---|
| 272 | }
|
---|
| 273 | // any other match gets replaced with empty string
|
---|
| 274 | return array($state, $match, array('action'=>'erase', 'pos'=>$pos));
|
---|
| 275 | }
|
---|
| 276 |
|
---|
| 277 | /**
|
---|
| 278 | * Handle the actual output creation.
|
---|
| 279 | *
|
---|
| 280 | * <p>
|
---|
| 281 | * The method checks for the given <tt>$aFormat</tt> and returns
|
---|
| 282 | * <tt>FALSE</tt> when a format isn't supported. <tt>$aRenderer</tt>
|
---|
| 283 | * contains a reference to the renderer object which is currently
|
---|
| 284 | * handling the rendering. The contents of <tt>$aData</tt> is the
|
---|
| 285 | * return value of the <tt>handle()</tt> method.
|
---|
| 286 | * </p>
|
---|
| 287 | * @see handle()
|
---|
| 288 | */
|
---|
| 289 | function render($mode, &$renderer, $data)
|
---|
| 290 | {
|
---|
| 291 | if($mode == 'xhtml')
|
---|
| 292 | {
|
---|
| 293 | list($state, $match, $params) = $data;
|
---|
| 294 | switch ($params['action'])
|
---|
| 295 | {
|
---|
| 296 | case 'debug':
|
---|
| 297 | $renderer->doc .= 'SQUIG-squig-squig';
|
---|
| 298 | break;
|
---|
| 299 | // By default we do an erase replace
|
---|
| 300 | default:
|
---|
| 301 | $renderer->doc .= '';
|
---|
| 302 | }
|
---|
| 303 | return true;
|
---|
| 304 | }
|
---|
| 305 | return false;
|
---|
| 306 | }
|
---|
| 307 | }
|
---|
| 308 |
|
---|
| 309 | //Setup VIM: ex: et ts=4 enc=utf-8 :
|
---|
| 310 | ?> |
---|