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