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