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