1<?php 2 3if(!defined('DOKU_PLUGIN')) die('meh'); 4 5class siteexport_toc 6{ 7 private $emptyNSToc = true; 8 private $functions = null; 9 public $translation = null; 10 11 public function siteexport_toc($functions) 12 { 13 $this->emptyNSToc = !empty($_REQUEST['emptyTocElem']); 14 $this->functions = $functions; 15 16 if ( $functions->settings->TOCMapWithoutTranslation ) 17 { 18 plugin_load('helper', 'translation' ); 19 } 20 } 21 22 private function shortenByTranslation(&$inputURL, $deepSearch = false) 23 { 24 if ( $this->translation ) 25 { 26 $inputURL = str_replace(':', '/', $inputURL); 27 $url = explode('/', $inputURL); 28 29 for( $i=0; $i<count($url); $i++ ) 30 { 31 if ( in_array($url[$i], $this->translation->trans ) ) 32 { 33 // Rauswerfen und weg 34 $url[$i] = ''; 35 break; 36 } 37 38 if ( !$deepSearch ) 39 { 40 break; 41 } 42 43 // Ok, remove anyway 44 $url[$i] = ''; 45 } 46 47 $inputURL = implode('/', $url); 48 $inputURL = preg_replace("$\/+$", "/", $inputURL); 49 } 50 51 if ( strlen($inputURL) > 0 && substr($inputURL, 0, 1) == '/' ) 52 { 53 $inputURL = substr($inputURL, 1); 54 } 55 56 return $inputURL; 57 } 58 59 /** 60 * Build the Java Documentation TOC XML 61 **/ 62 public function __getJavaHelpTOCXML($DATA) { 63 64 if ( count ( $DATA) == 0 ) { 65 return false; 66 } 67 68 $TOCXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<toc>"; 69 $MAPXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<map version=\"1.0\">"; 70 // usort($DATA, array($this, 'sortFunction')); 71 72 // Go through the pages 73 $CHECKDATA = array(); 74 $nData = $DATA; 75 $DATA = array(); 76 $check = array(); 77 $startPageID = null; 78 79 foreach ( $nData as $elem ) 80 { 81 // Check if available 82 $anchor = ( !empty($elem['anchor']) ? '#' . $elem['anchor'] : '' ); 83 $elem['url'] = $this->functions->getSiteName($elem['id'], true); // Override - we need a clean name 84 $elem['mapURL'] = $elem['url']; 85 $this->shortenByTranslation($elem['url']); 86 87 // only add an url once 88 if ( in_array($elem['url'], $CHECKDATA) ) { continue; } 89 90 if ( !isset($elem['exists']) ) { 91 resolve_pageid(getNS($elem['id']),$elem['id'],$elem['exists']); 92 $this->functions->debug->message("EXISTS previously not set.", $elem, 1); 93 } 94 95 // if not there, no map ids will be generated 96 $elem['mapID'] = intval($elem['exists']) == 1 ? $this->getMapID($elem, $check) : array(); 97 98 if ( empty($elem['depth']) ) $elem['depth'] = count(explode('/', $elem['url'])); 99 $CHECKDATA[] = $elem['url']; 100 101 if ( $startPageID == null ) 102 { 103 $startPageID = $elem['mapID'][0]; 104 } 105 106 if ( empty( $elem['name'] ) || $elem['name'] == NoNs($elem['id']) ) { 107 $elem['name'] = $this->functions->getSiteTitle($elem['id']); 108 } 109 110 // Go on building mapXML 111 $this->shortenByTranslation($elem['mapURL'], true); // true to already remove all language stuff - false if not 112 foreach ( $elem['mapID'] as $VIEWID ) { 113 $MAPXML .= "\n\t<mapID target=\"$VIEWID\" url=\"" . $elem['mapURL'] . $anchor . "\"/>"; 114 } 115 116 $elem['tocNS'] = getNS(cleanID($elem['url'])); 117 $elem['tocNS'] = explode('/', $this->shortenByTranslation($elem['tocNS'], true)); 118 $this->functions->debug->message("This will be the TOC elements data:", $elem, 1); 119 120 $this->__buildTOCTree($DATA, $elem['tocNS'], $elem); 121 } 122 123 $TOCXML .= $this->__writeTOCTree($DATA) . "\n</toc>"; 124 $MAPXML .= "\n</map>"; 125/* 126 // http://documentation:81/documentation/clear-reports/remote-interface-help/configuration/configuration/index?JavaHelpDocZip=1&depthType=1&diInv=1&do=siteexport&ens=documentation%3Aclear-reports%3Aremote-interface-help%3Aconfiguration&renderer=&template=clearreports-setup&useTocFile=1 127 print "<html><pre>"; 128 print_r($DATA); 129 $TOCXML = str_replace("<", "<", str_replace(">", ">", $TOCXML)); 130 print "$TOCXML"; 131 132 $MAPXML = str_replace("<", "<", str_replace(">", ">", $MAPXML)); 133 print "$MAPXML"; 134 135 print "</pre></html>"; 136 exit; 137/*/ 138 return array($TOCXML, $MAPXML, $startPageID); 139//*/ 140 } 141 142 /** 143 * Prepare the TOC Tree 144 **/ 145 private function __buildTOCTree(&$DATA, $currentNSArray, $elemToAdd) 146 { 147 global $conf; 148 149 if ( empty($currentNSArray) ) 150 { 151 // In Depth, let go! 152 $DATA[noNS($elemToAdd['id'])] = $elemToAdd; 153 return; 154 } else if (count($currentNSArray) == 1 && $currentNSArray[0] == '' && noNS($elemToAdd['id']) == $conf['start'] ) 155 { 156 // Wird gebraucht um die erste Ebene sauber zu bauen … kann aber irgendwelche Nebeneffekte haben 157 $DATA[noNS($elemToAdd['id'])] = $elemToAdd; 158 return; 159 } 160 161 $currentLevel = array_shift($currentNSArray); 162 if ( empty($DATA[$currentLevel]) ) { 163 $DATA[$currentLevel] = array(); 164 } 165 166 $this->__buildTOCTree($DATA[$currentLevel], $currentNSArray, $elemToAdd); 167 } 168 169 /** 170 * Create a single TOC Item 171 **/ 172 private function __TOCItem($item, $depth, $selfClosed=true) 173 { 174 $targetID = $item['mapID'][0]; 175 if ( empty($targetID) ) { 176 $targetID = strtolower($item['name']); 177 } 178 return "\n" . str_repeat("\t", max($depth, 0)+1) . "<tocitem target=\"$targetID\"" . (intval($item['exists']) == 1 ? " text=\"" . $item['name'] . "\"" : "") . ($selfClosed?'/':'') . ">"; 179 } 180 181 /** 182 * Create a single TOC Item 183 **/ 184 private function __TOCItemClose($depth) 185 { 186 return "\n" . str_repeat("\t", max($depth, 0)+1) . "</tocitem>"; 187 } 188 189 /** 190 * Write the whole TOC TREE 191 **/ 192 private function __writeTOCTree($CURRENTNODE, $CURRENTNODENAME = null, $DEPTH=0) { 193 global $conf; 194 195 $XML = ''; 196 $didOpenItem = false; 197 if ( !is_array($CURRENTNODE) || empty($CURRENTNODE) ) 198 { 199 // errr … no. 200 return $XML; 201 } 202 203 // This is an element! 204 if ( !empty($CURRENTNODE['id']) ) 205 { 206 // This has to be an item! 207 return $this->__TOCItem($CURRENTNODE, $DEPTH); 208 } 209 210 // Look for start page 211 if ( !empty($CURRENTNODE[$conf['start']]) ) 212 { 213 // YAY! StartPage found. 214 $didOpenItem = !(count($CURRENTNODE) == 1); 215 $XML .= $this->__TOCItem($CURRENTNODE[$conf['start']], $DEPTH, !$didOpenItem ); 216 unset($CURRENTNODE[$conf['start']]); 217 } else if ($CURRENTNODENAME != null) { 218 // We have a parent node for what is comming … lets honor that 219 $didOpenItem = !(count($CURRENTNODE) == 0); 220 $XML .= $this->__TOCItem(array('name' => ucwords($CURRENTNODENAME)), $DEPTH, !$didOpenItem ); 221 } else { 222 // Woohoo … empty node? do not count up! 223 $DEPTH --; 224 } 225 226 // Circle through the entries 227 foreach ( $CURRENTNODE as $NODENAME => $ELEM ) 228 { 229 // a node should have more than only one entry … otherwise we will not tell our name! 230 $XML .= $this->__writeTOCTree($ELEM, count($ELEM) >= 1 ? $NODENAME : null, $DEPTH+1); 231 } 232 233 // Close and return 234 return $XML . ($didOpenItem?$this->__TOCItemClose($DEPTH):''); 235 } 236 237 238 function post(&$value, $key, array $additional){ 239 $inner_glue = $additional[0]; 240 $prefix = isset($additional[1])? $additional[1] : false; 241 if($prefix === false) $prefix = $key; 242 243 $value = $value.$inner_glue.$prefix; 244 } 245 246 function mapIDWithAnchor(&$n, $key, $postfix) 247 { 248 if ( empty($postfix) ) return; 249 $n .= '-' . $postfix; 250 } 251 252 function getMapID($elem, &$check) 253 { 254 $meta = p_get_metadata($elem['id'], 'context', true); 255 $mapID = explode('|', empty( $meta['id'] ) ? sectionID($elem['name'], $check) : $meta['id']); 256 257 array_walk($mapID, array($this, 'mapIDWithAnchor'), $elem['anchor']); 258 259 return $mapID; 260 } 261 262 /** 263 * internal Sort function 264 * @param unknown_type $a 265 * @param unknown_type $b 266 */ 267 private function sortFunction($a, $b) 268 { 269 $idA = $a['id']; 270 $idB = $b['id']; 271 272 $depthA = explode(':', getNS($idA)); 273 $depthB = explode(':', getNS($idB)); 274 275 for ( $i=0; $i < min(count($depthA), count($depthB)); $i++ ) 276 { 277 $NSCMP = strcmp($depthA[$i], $depthB[$i]); 278 if ( $NSCMP != 0 ) 279 { 280 // Something is different! 281 return $NSCMP; 282 } 283 } 284 285 // There is mor in B, than in A! 286 if ( count($depthA) < count($depthB) ) 287 { 288 return -1; 289 } else if ( count($depthA) > count($depthB) ) 290 { 291 // there is more in A than in B 292 return 1; 293 } 294 295 if ( $NSCMP == 0 ) 296 { 297 // Something is different! 298 return strcmp(noNS($idA), noNS($idB)); 299 } 300 301 return 0; 302 } 303 304 /** 305 * Build the Eclipse Documentation TOC XML 306 **/ 307 public function __getTOCXML($DATA, $XML="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?NLS TYPE=\"org.eclipse.help.toc\"?>\n") { 308 309 $pagesArray = array(); 310 311 // Go through the pages 312 foreach ( $DATA as $elem ) { 313 314 $site = $elem['id']; 315 $elems = explode('/', $this->functions->getSiteName($site)); 316 317 // Strip Site 318 array_pop( $elems ); 319 320 // build the topic Tree 321 $this->__buildTopicTree($pagesArray, $elems, $site); 322 } 323 324 $XML .= $this->__addXMLTopic($pagesArray, 'toc'); 325 326 return $XML; 327 328 } 329 330 /** 331 * Load the topic Tree for the TOC - recursive 332 **/ 333 private function __buildTopicTree( &$PAGES, $DATA, $SITE, $INSERTDATA = null ) { 334 335 if ( empty( $DATA ) || !is_array($DATA) ) { 336 337 if ( $INSERTDATA == null ) 338 { 339 $INSERTDATA = $SITE; 340 } 341 342 // This is already a namespace 343 if ( is_array($PAGES[noNS($SITE)]) ) { 344 // The root already exists! 345 if ( !empty($PAGES[noNS($SITE)][noNS($SITE)]) ) { 346 if ( strstr($PAGES[noNS($SITE)][noNS($SITE)], $SITE) ) { 347 // The SITE is in the parent Namespace, and the current Namespace has an index with same name 348 $PAGES['__' . noNS($SITE)] = $INSERTDATA; 349 } else { 350 $PAGES['__' . noNS($SITE)] = $PAGES[noNS($SITE)][noNS($SITE)]; 351 $PAGES[noNS($SITE)][noNS($SITE)] = $INSERTDATA; 352 } 353 } else { 354 $PAGES[noNS($SITE)][noNS($SITE)] = $INSERTDATA; 355 } 356 } else { 357 // just a Page 358 $PAGES[noNS($SITE)] = $INSERTDATA; 359 } 360 return; 361 } 362 363 $NS = array_shift($DATA); 364 if ( !is_array( $PAGES[$NS] ) ) $PAGES[$NS] = empty($PAGES[$NS]) ? array() : array($PAGES[$NS]); 365 $this->__buildTopicTree( $PAGES[$NS], $DATA, $SITE, $INSERTDATA ); 366 367 return; 368 } 369 370 /** 371 * Build the Topic Tree for TOC.xml 372 **/ 373 private function __addXMLTopic($DATA, $ITEM='topic', $LEVEL=0, $NODENAME='') { 374 global $conf; 375 376 $DEPTH = str_repeat("\t", $LEVEL); 377 378 if ( !is_array($DATA) ) { 379 return $DEPTH . '<' . $ITEM . ' label="' . $this->functions->getSiteTitle($DATA) . '" ' . ($ITEM != 'topic' ? 'topic' : 'href' ) . '="' . $this->functions->getSiteName($DATA) . "\" />\n"; 380 } 381 // Is array from this point on 382 list($indexTitle, $indexFile) = $this->__getIndexItem($DATA, $NODENAME); 383 384 if ( empty( $indexTitle) ) $indexTitle = $this->functions->getSiteTitle( $conf['start'] ); 385 if ( !empty( $indexFile) ) $indexFile = ($ITEM != 'topic' ? 'topic' : 'href' ) . "=\"$indexFile\""; 386 387 $isEmptyNode = count($DATA) == 1 && empty($indexFile); 388 389 if ( !$isEmptyNode && ($this->emptyNSToc || count($DATA) > 0) ) 390 $XML = "$DEPTH<$ITEM label=\"$indexTitle\" $indexFile>"; 391 392 if ( !$isEmptyNode && count ($DATA) > 0 ) $XML .= "\n"; 393 394 foreach( $DATA as $NODENAME => $NS ) { 395 396 $XML .= $this->__addXMLTopic($NS, ( !($this->emptyNSToc || count($DATA) > 1) && $ITEM != 'topic' ? $ITEM : 'topic' ), $LEVEL+(!$isEmptyNode ? 1 : 0), $NODENAME); 397 398 } 399 400 if ( !$isEmptyNode && count ($DATA) > 0 ) $XML .= "$DEPTH"; 401 if ( !$isEmptyNode && ($this->emptyNSToc || count($DATA) > 0) ) { 402 $XML .= "</$ITEM>\n"; 403 } 404 405 return $XML; 406 } 407 408 409 /** 410 * Get the context XML 411 **/ 412 public function __getContextXML($DATA) { 413 414 $XML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?NLS TYPE=\"org.eclipse.help.context\"?>\n<contexts>\n"; 415 416 $check = array(); 417 foreach ( $DATA as $elem ) 418 { 419 $ID = $elem['id']; 420 $meta = p_get_metadata($ID, 'context', true); 421 if ( empty( $meta['id'] ) ) { continue; } 422 423 $TITLE = empty( $meta['title'] ) ? $this->functions->getSiteTitle($ID) : $meta['title']; 424 425 // support more than one view IDs ... for more than one reference 426 $VIEWIDs = $this->getMapID($elem, $check); 427 428 $DESCRIPTION = $this->functions->xmlEntities(p_get_metadata($ID, 'description abstract')); 429 430 // Build topic Links 431 $url = $this->functions->getSiteName($ID); 432 $this->shortenByTranslation($url); 433 434 $TOPICS = array( $url => $TITLE . " (Details)" ); 435 $REFS = p_get_metadata($ID, 'relation references', true); 436 if ( is_array($REFS) ) 437 foreach ( $REFS as $REL => $EXISTS ) { 438 if ( !$EXISTS ) { continue; } 439 $TOPICS[$this->functions->getSiteName($REL)] = $this->functions->getSiteTitle($REL); 440 } 441 442 // build XML - include multi view IDs 443 foreach ( $VIEWIDs as $VIEWID ) { 444 $XML .= "\t<context id=\"$VIEWID\" title=\"$TITLE\">\n"; 445 $XML .= "\t\t<description>$DESCRIPTION</description>\n"; 446 447 foreach ( $TOPICS as $URL => $LABEL ) { 448 $XML .= "\t\t<topic label=\"$LABEL\" href=\"$URL\" />\n"; 449 } 450 451 $XML .= "\t</context>\n"; 452 } 453 } 454 455 $XML .= "</contexts>"; 456 return $XML; 457 458 } 459 460 /** 461 * Determine if this is an index - and if so, find its Title 462 **/ 463 private function __getIndexItem(&$DATA, $NODENAME='') { 464 global $conf; 465 466 if ( !is_array($DATA) ) { return; } 467 468 $indexTitle = ''; 469 $indexFile = ''; 470 foreach ( $DATA as $NODE => $indexSearch) { 471 // Skip next Namespaces 472 if ( is_array($indexSearch) ) { continue; } 473 474 // Skip if this is not a start 475 if ( $NODE != $conf['start'] ) { continue; } 476 477 $indexTitle = $this->functions->getSiteTitle( $indexSearch ); 478 $indexFile = $indexSearch; 479 unset($DATA[$NODE]); 480 break; 481 } 482 483 if ( empty($indexFile) && !empty($DATA[$NODENAME]) ) { 484 $indexTitle = $this->functions->getSiteTitle( $DATA[$NODENAME] ); 485 $indexFile = $DATA[$NODENAME]; 486 unset($DATA[$NODENAME]); 487 } 488 489 return array($indexTitle, $this->functions->getSiteName($indexFile)); 490 } 491} 492 493?>