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