RFC #7438: Docheaders: Module Help > TypoScript Help: No docheader
[Packages/TYPO3.CMS.git] / typo3 / sysext / tsconfig_help / mod1 / index.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2007 Stephane Schitter <stephane.schitter@free.fr>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25
26 // DEFAULT initialization of a module [BEGIN]
27 unset($MCONF);
28 require_once('conf.php');
29 require_once($BACK_PATH.'init.php');
30 require_once($BACK_PATH.'template.php');
31 require_once($BACK_PATH.'mod/tools/em/class.em_unzip.php');
32
33 $LANG->includeLLFile('EXT:tsconfig_help/mod1/locallang.xml');
34 require_once(PATH_t3lib.'class.t3lib_scbase.php');
35 $BE_USER->modAccess($MCONF,1); // This checks permissions and exits if the users has no permission for entry.
36 // DEFAULT initialization of a module [END]
37
38
39 /**
40 * Module 'TypoScript Help' for the 'tsconfig_help' extension.
41 *
42 * @author Stephane Schitter <stephane.schitter@free.fr>
43 * @package TYPO3
44 * @subpackage tx_tsconfighelp
45 */
46 class tx_tsconfighelp_module1 extends t3lib_SCbase {
47 var $pageinfo;
48 var $objStringsPerExtension = array(); // This is used to count how many times the same obj_string appears in each extension manual
49 var $allObjStrings = array(); // This is used to count how many times the same obj_string appears across all extensions
50
51 /**
52 * Initializes the Module
53 * @return void
54 */
55 function init() {
56 global $BE_USER,$LANG,$BACK_PATH,$TCA_DESCR,$TCA,$CLIENT,$TYPO3_CONF_VARS;
57 parent::init();
58 }
59
60 /**
61 * Adds items to the ->MOD_MENU array. Used for the function menu selector.
62 *
63 * @return void
64 */
65 function menuConfig() {
66 global $LANG;
67 $this->MOD_MENU = array(
68 'function' => array(
69 '1' => $LANG->getLL('display')
70 )
71 );
72
73 if($GLOBALS['BE_USER']->user['admin']) {
74 $this->MOD_MENU['function']['2'] = $LANG->getLL('rebuild');
75 }
76
77 parent::menuConfig();
78 }
79
80 /**
81 * Main function of the module. Write the content to $this->content
82 *
83 * @return void
84 */
85 function main() {
86 global $BE_USER,$LANG,$BACK_PATH,$TCA_DESCR,$TCA,$CLIENT,$TYPO3_CONF_VARS;
87
88 // Access check!
89 // The page will show only if there is a valid page and if this page may be viewed by the user
90 $this->pageinfo = t3lib_BEfunc::readPageAccess($this->id,$this->perms_clause);
91 $access = is_array($this->pageinfo) ? 1 : 0;
92
93 // Draw the header.
94 $this->doc = t3lib_div::makeInstance('template');
95 $this->doc->backPath = $BACK_PATH;
96 $this->doc->setModuleTemplate('templates/tsconfig_help.html');
97 $this->doc->docType = 'xhtml_trans';
98
99 if (($this->id && $access) || ($BE_USER->user['admin'] && !$this->id)) {
100
101 $this->doc->form = '<form action="" method="POST">';
102
103 // JavaScript
104 $this->doc->JScode = '
105 <script language="javascript" type="text/javascript">
106 script_ended = 0;
107 function jumpToUrl(URL) {
108 document.location = URL;
109 }
110 </script>
111 ';
112 $this->doc->postCode = '
113 <script language="javascript" type="text/javascript">
114 script_ended = 1;
115 if (top.fsMod) top.fsMod.recentIds["web"] = 0;
116 </script>
117 ';
118
119 $headerSection = $this->doc->getHeader('pages',$this->pageinfo,$this->pageinfo['_thePath']).'<br />'.$LANG->sL('LLL:EXT:lang/locallang_core.xml:labels.path').': '.t3lib_div::fixed_lgd_pre($this->pageinfo['_thePath'],50);
120
121 $this->content .= $this->doc->header($LANG->getLL('title'));
122 $this->content .= $this->doc->spacer(5);
123
124 // Render content:
125 $this->moduleContent();
126
127 $this->content .= $this->doc->spacer(10);
128
129 $markers['FUNC_MENU'] = t3lib_BEfunc::getFuncMenu($this->id,'SET[function]',$this->MOD_SETTINGS['function'],$this->MOD_MENU['function']);
130 } else {
131 $this->content .= $this->doc->header($LANG->getLL('title'));
132 }
133 // Setting up the buttons and markers for docheader
134 $docHeaderButtons = $this->getButtons();
135 $markers['CSH'] = $docHeaderButtons['csh'];
136 $markers['CONTENT'] = $this->content;
137
138 // Build the <body> for the module
139 $this->content = $this->doc->startPage($LANG->getLL('title'));
140 $this->content.= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
141 $this->content.= $this->doc->endPage();
142 $this->content = $this->doc->insertStylesAndJS($this->content);
143 }
144
145 /**
146 * Prints out the module HTML
147 *
148 * @return void
149 */
150 function printContent() {
151 echo $this->content;
152 }
153
154 /**
155 * Create the panel of buttons for submitting the form or otherwise perform operations.
156 *
157 * @return array all available buttons as an assoc. array
158 */
159 private function getButtons() {
160 global $TCA, $LANG, $BACK_PATH, $BE_USER;
161
162 $buttons = array(
163 'csh' => '',
164 'shortcut' => '',
165 );
166 // CSH
167 //$buttons['csh'] = t3lib_BEfunc::cshItem('_MOD_web_func', '', $GLOBALS['BACK_PATH']);
168
169 if (($this->id && is_array($this->pageinfo)) || ($BE_USER->user['admin'] && !$this->id)) {
170 // Shortcut
171 if ($BE_USER->mayMakeShortcut()) {
172 $buttons['shortcut'] = $this->doc->makeShortcutIcon('id', implode(',', array_keys($this->MOD_MENU)), $this->MCONF['name']);
173 }
174 }
175 return $buttons;
176 }
177
178 /**
179 * Generates the module content
180 *
181 * @return void
182 */
183 function moduleContent() {
184 global $BACK_PATH, $TYPO3_LOADED_EXT, $LANG;
185
186 switch ((string)$this->MOD_SETTINGS['function']) {
187 case 1:
188 $content = '<div align="left"><strong>'.$LANG->getLL('referenceExplanation').'</strong></div>';
189 $content .= '<p>'.$LANG->getLL('referenceExplanationDetailed').'</p><br />';
190 $this->content .= $this->doc->section($LANG->getLL('displayReferences'),$content,0,1);
191 $this->content .= '<a href="#" onClick="vHWin=window.open(\''.$BACK_PATH.'wizard_tsconfig.php?mode=tsref&P[formName]=editForm\',\'popUp\',\'height=500,width=780,status=0,menubar=0,scrollbars=1\');vHWin.focus();return false;"><img src="'.$BACK_PATH.'sysext/t3skin/icons/gfx/wizard_tsconfig.gif" width="22" height="27" width="22" height="27" border="0" title="TSref reference"> TSREF</a><br />';
192 $this->content .= '<a href="#" onClick="vHWin=window.open(\''.$BACK_PATH.'wizard_tsconfig.php?mode=beuser&P[formName]=editForm\',\'popUp\',\'height=500,width=780,status=0,menubar=0,scrollbars=1\');vHWin.focus();return false;"><img src="'.$BACK_PATH.'sysext/t3skin/icons/gfx/wizard_tsconfig.gif" width="22" height="27" width="22" height="27" border="0" title="TSref reference"> USER TSCONFIG</a><br />';
193 $this->content .= '<a href="#" onClick="vHWin=window.open(\''.$BACK_PATH.'wizard_tsconfig.php?mode=page&P[formName]=editForm\',\'popUp\',\'height=500,width=780,status=0,menubar=0,scrollbars=1\');vHWin.focus();return false;"><img src="'.$BACK_PATH.'sysext/t3skin/icons/gfx/wizard_tsconfig.gif" width="22" height="27" width="22" height="27" border="0" title="TSref reference"> PAGE TSCONFIG</a><br />';
194 break;
195
196 case 2:
197 if ($GLOBALS['BE_USER']->user['admin']) {
198 if ($GLOBALS['TYPO3_OS'] === 'WIN') {
199 $this->content .= '<p>'.$LANG->getLL('noRebuildOnWindows').'</p><br />';
200 } else {
201 if (t3lib_div::_GP('_rebuild')) {
202 // remove all data from the database
203 $this->purgeSQLContents();
204
205 // get all loaded extension keys
206 $extArray = $TYPO3_LOADED_EXT;
207
208 $content = '<div align="left"><strong>'.$LANG->getLL('loadedTSfrom').'</strong></div><br />';
209
210 // parse the extension names only (no need for all details from the TYPO3_LOADED_EXT table
211 foreach ($extArray as $extName => $dummy) {
212 // check that the extension is really loaded (which should always be the case)
213 if (t3lib_extMgm::isLoaded($extName)) {
214 // extract the content.xml from the manual.sxw ZIP file
215 $manual = $this->getZIPFileContents(t3lib_extMgm::extPath($extName).'doc/manual.sxw', 'content.xml');
216
217 // check if the manual file actually exists and if the content.xml could be loaded
218 if ($manual != '') {
219 // if the manual file exists, proceed with the load into the SQL database
220 $content .= '<p>Extension '.$extName.'...';
221
222 // run the extraction processing and import the data into SQL. Return the number of TS tables found in the open office document
223 $number = $this->loadExtensionManual($extName, $manual);
224
225 // print a status message with a link to the openoffice manual
226 $content .= $number.' '.$LANG->getLL('sections').' (<a href="'.t3lib_div::getIndpEnv('TYPO3_SITE_URL').TYPO3_mainDir.t3lib_extMgm::extRelPath($extName).'doc/manual.sxw">manual</a>)</p>';
227 }
228 } else {
229 // this should never happen!
230 die ("Fatal error : loaded extension not actually loaded? Please file a bug report at http://bugs.typo3.org!");
231 }
232 }
233
234 $this->content .= $this->doc->section($LANG->getLL('rebuildTS'),$content.'<br />',0,1);
235
236 // Issue warnings about duplicate or empty obj_strings, if any
237 // An obj_string should be unique. It should appear in only one extension manual and then only once
238 // If the sum of all occurrences of a given obj_string is more than one, issue a list of duplicate entries as a warning
239 $duplicateWarnings = '';
240 $emptyWarnings = '';
241 foreach ($this->objStringsPerExtension as $obj_string => $extensions) {
242 if (empty($obj_string)) {
243 $emptyWarnings = '<p class="typo3-red">'.$LANG->getLL('warning_manualsWithoutMarkers');
244 foreach ($extensions as $extensionKey => $counter) {
245 $emptyWarnings .= ' '.$extensionKey.' ('.$counter.')<br />';
246 }
247 $emptyWarnings .= '</p><br />';
248 } else {
249 if (array_sum($extensions) > 1) {
250 $duplicateWarnings .= $obj_string.':';
251 foreach ($extensions as $extensionKey => $counter) {
252 $duplicateWarnings .= ' '.$extensionKey.' ('.$counter.')';
253 }
254 $duplicateWarnings .= '<br />';
255 }
256 }
257 }
258 $warnings = $emptyWarnings;
259 if (!empty($duplicateWarnings)) {
260 $warnings .= '<p class="typo3-red">'.$LANG->getLL('warning_duplicateMarkers').'<br />'.$duplicateWarnings.'</p>';
261 }
262 if (!empty($warnings)) {
263 $this->content .= $this->doc->section($LANG->getLL('updateWarnings'),'<div>'.$warnings.'</div>',0,1);
264 }
265 }
266
267 $content = '<p>'.$LANG->getLL('rebuildExplanation').'</p><br />';
268 $content .= $LANG->getLL('rebuild').' <input type="submit" name="_rebuild" value="Rebuild" /><br />';
269 $this->content .= $this->doc->section($LANG->getLL('rebuildTS'),$content,0,1);
270 }
271 } else {
272 $this->content .= '<p>'.$LANG->getLL('adminAccessOnly').'</p><br />';
273 }
274
275
276 break;
277 }
278 }
279
280 /**
281 * Returns the contents of a specific file within the ZIP
282 *
283 * @return string contents
284 */
285 function getZIPFileContents($ZIPfile, $filename) {
286 if (@file_exists($ZIPfile)) {
287 // Unzipping SXW file, getting filelist:
288 $tempPath = PATH_site.'typo3temp/tx_tsconfighelp_ziptemp/';
289 t3lib_div::mkdir($tempPath);
290
291 $this->unzip($ZIPfile, $tempPath);
292 $output = t3lib_div::getURL($tempPath.$filename);
293
294 $cmd = 'rm -r "'.$tempPath.'"';
295 exec($cmd);
296
297 return $output;
298 }
299 }
300
301 /**
302 * Unzips a zip file in the given path.
303 * Uses the Extension Manager unzip functions.
304 *
305 *
306 * @param string $file Full path to zip file
307 * @param string $path Path to change to before extracting
308 * @return boolean True on success, false in failure
309 */
310 function unzip($file, $path) {
311 // we use the unzip class of the Extension Manager here
312 $className = t3lib_div::makeInstanceClassName('em_unzip');
313 $unzip = new $className($file);
314 $ret = $unzip->extract(array('add_path'=>$path));
315 return (is_array($ret));
316 }
317
318 /**
319 * Parses the whole XML file in order to understand the Styles structure. This function is mostly looking at the styles
320 * that create bold or italic characters in the document, as these will later on need to be translated to <i> and <b> tags
321 * This function takes into account the hierarchy of the styles, as created by OpenOffice. This means that if a style has
322 * a parant, this function will make it inherit the styles of the parent. Therefore bold and italic styles are propagated
323 * to children as well.
324 *
325 * This function assumes the STYLE definitions are not nested. If they are then, then "close" type will need to be used
326 * more carefully, and a depth counter will need to be implemented.
327 *
328 * @param array The XML values array. The XML index is not necessary in this function.
329 * @return array Array that contains the different styles with their parent (required to recognise "Table Contents"-type styles), and their style (bold/italic)
330 */
331 function parseStyles($vals) {
332 $currentStyleName = '';
333 $style = array ();
334
335 foreach ($vals as $node) {
336 switch ($node['type']) {
337 case 'open':
338 switch ($node['tag']) {
339 case 'STYLE:STYLE':
340 $currentStyleName = $node['attributes']['STYLE:NAME'];
341
342 if (array_key_exists('STYLE:PARENT-STYLE-NAME',$node['attributes'])) {
343 $parentStyleName = $node['attributes']['STYLE:PARENT-STYLE-NAME'];
344 $style[$currentStyleName]['parents'][] = $parentStyleName; // keep trace of parents in the style array
345 } else {
346 $parentStyleName = ''; // this style has no parent, therefore clean the variable to avoid side effects with next use of that variable
347 }
348
349 if (array_key_exists($parentStyleName, $style)) { // the style parent is already documented in the array
350 $style[$currentStyleName] = $style[$parentStyleName]; // inherit parent style
351 }
352 break;
353 }
354 break;
355
356 case 'complete':
357 switch ($node['tag']) {
358 case 'STYLE:PROPERTIES':
359 if (is_array($node['attributes']) && array_key_exists('FO:FONT-WEIGHT',$node['attributes'])) {
360 $style[$currentStyleName]['font-weight'] = $node['attributes']['FO:FONT-WEIGHT']; // bold for example
361 }
362 if (is_array($node['attributes']) && array_key_exists('FO:FONT-STYLE',$node['attributes'])) {
363 $style[$currentStyleName]['font-style'] = $node['attributes']['FO:FONT-STYLE']; // italic for example
364 }
365 break;
366 }
367 break;
368
369 case 'close':
370 switch ($node['tag']) {
371 case 'STYLE:STYLE':
372 $currentStyleName = '';
373 break;
374 case 'STYLE:PROPERTIES':
375 break;
376 }
377 break;
378 }
379 }
380
381 return $style;
382 }
383
384
385 /**
386 * Checks if the style is a child of a specified parent. This is useful for example to check if a specific style that has
387 * a generic name ("P8" for example) is a child of the "Table Contents" style. It would not only inherit its style (bold/
388 * italic) but also its properties like being part of a Table.
389 *
390 * This function references the global $Styles variables which must have been created previously with parseStyles()
391 *
392 * @param string Name of the child style that we want to get properties for
393 * @param string Name of the parent style that we want to compare the child against
394 * @return boolean true if the child and parent are linked together. false otherwise.
395 */
396 function isStyleChildOf($child, $parent) {
397 global $Styles;
398
399 if (!strcmp($child, $parent)) { // the child is actually the same as the parent. They are obviously linked together
400 return TRUE;
401 }
402
403 if (is_array($Styles[$child]) // the child is a documented style
404 && array_key_exists('parents',$Styles[$child]) // it has some parents
405 && (array_search($parent, $Styles[$child]['parents']) !== FALSE)) { // and the parent appears amongst its ancestors
406 return TRUE;
407 }
408 return FALSE;
409 }
410
411 /**
412 * Find the table description that we want, then find a TABLE:TABLE close, immediately followed by a TEXT:P which has a
413 * style which is a child of a "Table Contents", then look up the index to find where the TABLE begins, and start browsing
414 * from there (returns these start and end indexes).
415 *
416 * This function only finds the next TS definition table. In order to find all TS definition tables from the document, the
417 * function needs to be called several times, starting where it left off last time. The third parameter is the index that
418 * is used to indicate where to start, and which is modified when the function returns to indicate where we left off.
419 *
420 * This function uses the unusual index XML array in addition to the values, this is necessary to find where in the XML
421 * tree a TABLE starts once we found where it ends.
422 *
423 * @param array The XML values array
424 * @param array The XML index array
425 * @param integer This is a reference to the index in the array where we should be starting the search
426 * @return array Array of the table start index and table end index where TS is defined. table start is FALSE if there are no more TS entries in the document (consider it similar to an EOF reached status).
427 */
428 function nextTSDefinitionTable($vals, $index, &$id) {
429 // browse the table where we left off last time
430 while ($id < count ($vals)) {
431 $node = $vals[$id];
432 if (!strcmp($node['type'], 'close') && !strcmp($node['tag'], 'TABLE:TABLE')) { // check if next entry is a candidate
433 $nextNode = $vals[$id+1];
434 if (!strcmp($nextNode['tag'], 'TEXT:P') && $this->isStyleChildOf($nextNode['attributes']['TEXT:STYLE-NAME'], 'Table Contents')) {
435 // we found a good entry
436 $closeIndex = array_search($id, $index['TABLE:TABLE']); // find the ID in the list of table items
437
438 $tableStart = $index['TABLE:TABLE'][$closeIndex-1]; // find the matching start of the table in the $vals array
439
440 return array($tableStart, $id++);
441 }
442 }
443 $id = $id+1;
444 }
445 return array(FALSE, 0); // marks the end of the input, no more table to find. WARNING: needs to be tested with === FALSE
446 }
447
448 /**
449 * Converts an Open Office like style (font-weight:bold for example) into an HTML style (b is for bold). This function uses the global
450 * $Styles defined through the parseStyles function
451 *
452 * @param array an array containing the [attributes][style] items in the OO format
453 * @return array an array where the items are all the HTML styles to apply to closely match the input OO-like styles
454 */
455 function styleTags($node) {
456 global $Styles;
457
458 $styleName = $node['attributes']['TEXT:STYLE-NAME'];
459 switch ($Styles[$styleName]['font-weight']) {
460 case 'bold':
461 $styleTags[] = 'b';
462 break;
463 }
464 switch ($Styles[$styleName]['font-style']) {
465 case 'italic':
466 $styleTags[] = 'i';
467 break;
468 }
469 if (!strcmp($styleName,'Table Contents/PRE')) {
470 //$styleTags[]='pre'; // unused yet, but could be <pre> in the future - this is for inline code in the manuals
471 }
472 return $styleTags;
473 }
474
475 /**
476 * Converts an array containing style strings (for example ['b','i']) into their HTML equivalents
477 *
478 * @param array an array containing all the style tags
479 * @param string either '' or '/' depending on whether the style definition is to open or close the style
480 * @return string the sequence of tags to open or close the style, for example <b><i>
481 */
482 function styleHTML($style, $char) {
483 $string = '';
484 if (count ($style) > 0) {
485 foreach ($style as $tag) {
486 $string .= '<'.$char.$tag.'>';
487 }
488 }
489 return $string;
490 }
491
492 /**
493 * This function does a little more than just HSC'ing the text passed to it. It does a general cleaning of the input:
494 * htmlspecialchars() : general cleaning for the HTML display, including single quotes transformation
495 * stripslashes() : otherwise the backslashes will cause an issue with a future unserialize of the data
496 * &nbsp if empty : if the input is empty, we return a &nbsp; string so that in the HTML output something will be displayed
497 * utf8 to entities cleaning : in some SXW docs we can find UTF8 characters that need to be converted to be displayed on screen
498 *
499 * @param string Text that will need to be transformed according to the HSC and other rules
500 * @return string Transformed text that can now be freely serialized or exported to HTML
501 */
502 function HSCtext($text) {
503 global $LANG;
504
505 if (strcmp($text,'')) { // there is some content in the text field
506 $cleantext = stripslashes(htmlspecialchars($text, ENT_QUOTES)); // stripslashes required as it could confuse unserialize
507 return $LANG->csConvObj->utf8_to_entities($cleantext, $LANG->charSet);
508 } else { // there is no text, it's empty
509 return '&nbsp;';
510 }
511 }
512
513 /**
514 * This function parses a Table from an Open Office document, in an XML format, and extracts the information. It will therefore crawl the
515 * XML tree and aggregate all the accepted contents into an array with the table contents.
516 *
517 * This function needs to extract the following information from the TABLE:
518 * property => (column 1)
519 * datatype => (column 2)
520 * description => (column 3)
521 * default => (column 4)
522 * column_count => number of columns found in table. Usually 4, but for spanned columns, it would be less (1 for example)
523 * is_propertyTable => ??? (almost always equal to 1)
524 *
525 * @param array This is the input XML data that is to be parsed
526 * @param integer The starting ID in the XML array to parse the data from
527 * @param integer The ending ID in the XML array to stop parsing data
528 * @return array An array with the contents of the different columns extracted from the input data
529 */
530 function parseTable($vals, $start, $end) {
531 $sectionHeader = 0;
532 $sectionRow = 0;
533 $sectionCell = 0;
534 $sectionP = 0;
535
536 $newLineRequired = ''; // this variable will either be empty (no newline required) or '\n' (newline required)
537 $textStyle = array (); // this will be the list of tag styles to apply to the text
538
539 $currentRow = 0;
540 $currentCell = 0;
541
542 $rowID = 0;
543 $cellID = 0; // also gets reset at every top-level row
544
545 $table = array(); // will contain the results of the function
546
547 $id = $start;
548 while ($id < $end) {
549 $node = $vals[$id];
550
551 // sanity check
552 if ($sectionHeader < 0) die ('Malformed XML (header-rows)'."\n");
553 if ($sectionRow < 0) die ('Malformed XML (row)'."\n");
554 if ($sectionCell < 0) die ('Malformed XML (cell)'."\n");
555 if ($sectionP < 0) die ('Malformed XML (P)'."\n");
556
557 switch ($node['type']) {
558 case 'open':
559 switch ($node['tag']) {
560 case 'TABLE:TABLE-HEADER-ROWS':
561 $sectionHeader++;
562 break;
563
564 case 'TABLE:TABLE-ROW':
565 if (!$sectionHeader) { // skip section header, we only look at the *contents* of the table
566 $sectionRow++;
567 if ($sectionRow == 1) { // make sure we are within a top-level row
568 $rowID++;
569 $cellID = 0;
570 }
571 }
572 break;
573
574 case 'TABLE:TABLE-CELL':
575 if (!$sectionHeader) { // skip section header, we only look at the *contents* of the table
576 $sectionCell++;
577 if ($sectionCell == 1) { // make sure we are within a top-level cell
578 $cellID++;
579 $newLineRequired = ''; // no newline required after this
580 }
581 }
582 break;
583
584 case 'TEXT:P':
585 if ($sectionCell) { // make sure we are in a cell
586 $sectionP++;
587 $table[$rowID-1][$cellID-1] .= $this->styleHTML($this->styleTags($node),'') . $newLineRequired.$this->HSCtext($node['value']);
588 $newLineRequired = ''; // no newline required after this
589 $latestTEXTPopen = $node;
590 }
591 break;
592 }
593 break;
594
595 case 'complete':
596 switch ($node['tag']) {
597 case 'TEXT:P':
598 if ($sectionCell) { // make sure we are in a cell
599 $table[$rowID-1][$cellID-1] .= $this->styleHTML($this->styleTags($node),'') . $newLineRequired.$this->HSCtext($node['value']).$this->styleHTML($this->styleTags($node),'/');
600 $newLineRequired = '<br>'; // after a paragraph, require a new-line
601 }
602 break;
603
604 case 'TEXT:SPAN':
605 if ($sectionCell) { // make sure we are in a cell
606 $table[$rowID-1][$cellID-1] .= $this->styleHTML($this->styleTags($node),'').$newLineRequired.$this->HSCtext($node['value']).$this->styleHTML($this->styleTags($node),'/');
607 $newLineRequired = ''; // no newline required after this
608 }
609 break;
610
611 case 'TEXT:S':
612 if ($sectionCell) { // make sure we are in a cell
613 for ($i=0; $i<$node['attributes']['TEXT:C']; $i++) {
614 $table[$rowID-1][$cellID-1] .= '&nbsp;';
615 }
616 $newLineRequired = ''; // no newline required after this
617 }
618 break;
619 }
620 break;
621
622 case 'cdata':
623 switch ($node['tag']) {
624 case 'TEXT:P':
625 if ($sectionCell) { // make sure we are in a cell
626 $table[$rowID-1][$cellID-1] .= $this->styleHTML($this->styleTags($node),'') . $newLineRequired.$this->HSCtext($node['value']).$this->styleHTML($this->styleTags($node),'/');
627 $newLineRequired = ''; // no newline required after this
628 }
629 break;
630 }
631 break;
632
633 case 'close':
634 switch ($node['tag']) {
635 case 'TABLE:TABLE-HEADER-ROWS':
636 $sectionHeader--;
637 break;
638
639 case 'TABLE:TABLE-ROW':
640 if (!$sectionHeader) { // skip section header, we only look at the *contents* of the table
641 $sectionRow--;
642 }
643 break;
644
645 case 'TABLE:TABLE-CELL':
646 if (!$sectionHeader) { // skip section header, we only look at the *contents* of the table
647 $sectionCell--;
648 }
649 break;
650
651 case 'TEXT:P':
652 $sectionP--;
653 $newLineRequired = '<br>'; // after a paragraph, require a new-line
654 $table[$rowID-1][$cellID-1] .= $this->styleHTML($this->styleTags($latestTEXTPopen),'/');
655 break;
656 }
657 break;
658 }
659 $id = $id+1;
660 }
661 return $table;
662 }
663
664 /**
665 * Load the contents of the table into the SQL database
666 *
667 * @param string Name of the extension to load the documentation for. This is used to make the unique hash in the database
668 * @param array Contents of the documentation table
669 * @param string Name of the table from the source document (name at the bottom of the table in OpenOffice)
670 * @return boolean TRUE on success and FALSE on failure from the INSERT database query
671 */
672 function dumpIntoSQL($extension, $table, $tableName) {
673 global $uid;
674
675 foreach ($table as $row) {
676 $tempArray = array();
677 $tempArray['property'] = $row[0];
678
679 $tempArray['datatype'] = count($row)==2 ? '&nbsp;':$row[1]; // in the case there are only 2 columns, the second one is the description !
680 $tempArray['description'] = count($row)==2 ? $row[1]:$row[2]; // in the case there are only 2 columns, the second one is the description !
681 $tempArray['default'] = $row[3];
682 $tempArray['column_count'] = count($row);
683 $tempArray['is_propertyTable'] = 1;
684 $tsHelpArray['rows'][] = $tempArray;
685 }
686 $appdata = serialize($tsHelpArray);
687 $obj_string = trim($tableName, '[]');
688
689 if (isset($this->objStringsPerExtension[$obj_string])) {
690 if (isset($this->objStringsPerExtension[$obj_string][$extension])) {
691 $this->objStringsPerExtension[$obj_string][$extension]++;
692 } else {
693 $this->objStringsPerExtension[$obj_string][$extension] = 1;
694 }
695 } else {
696 $this->objStringsPerExtension[$obj_string] = array();
697 $this->objStringsPerExtension[$obj_string][$extension] = 1;
698 }
699
700 // If the obj_string was already encountered increase its counter. If not initialise it as 0
701 // The counter (when bigger than 0) is appended to the obj_string to make it unique
702 // This way the tables do not overwrite each other in the online help
703 if (isset($this->allObjStrings[$obj_string])) {
704 $this->allObjStrings[$obj_string]++;
705 $obj_string .= ' ('.$this->allObjStrings[$obj_string].')';
706 } else {
707 $this->allObjStrings[$obj_string] = 0;
708 }
709 $md5hash = md5($obj_string);
710 $description = ''; // unused
711 $guide = hexdec(substr(md5($extension),6,6)); // try to find a way to uniquely identify the source extension and place the identified into the "guide" column
712 $title = ''; // unused
713
714 $insertFields = array(
715 'guide' => $guide,
716 'md5hash' => $md5hash,
717 'description' => $description,
718 'obj_string' => $obj_string,
719 'appdata' => $appdata,
720 'title' => $title
721 );
722
723 return $GLOBALS['TYPO3_DB']->exec_INSERTquery('static_tsconfig_help', $insertFields);
724 }
725
726 /**
727 * Purges the existing contents for TypoScript help in the database. This ensures that several runs of the import process will not push
728 * duplicate information in the database, but that we clean it first before adding new contents.
729 *
730 * @param string Name of the extension for which to delete all the data in the database. If empty, all database will be cleaned
731 * @return void
732 */
733 function purgeSQLContents($extension='') {
734 $guide = hexdec(substr(md5($extension), 6, 6));
735 if ($extension != '') {
736 $GLOBALS['TYPO3_DB']->exec_DELETEquery('static_tsconfig_help', 'guide='.$guide);
737 } else {
738 $GLOBALS['TYPO3_DB']->exec_DELETEquery('static_tsconfig_help', '');
739 }
740 }
741
742 /**
743 * This is the main function of the loading process. It will first parse the input data and load it into an XML array. It will then find all
744 * the styles associated with the contents so that later on we can distinguish bold and italic characters for example. It then parses the XML
745 * array to find all the TS-like description tables and parses them before loading them into the SQL database.
746 *
747 * @param string Name of the extension to load manual from
748 * @param string Input data from the manual.sxw in a string form. One large string with the whole OO manual document.
749 * @return integer Number of individual tables found in the document and loaded into the SQL database
750 */
751 function loadExtensionManual($extension, $contents) {
752 global $Styles;
753
754 // read the contents into an XML array
755 $parser = xml_parser_create();
756 xml_parse_into_struct($parser, $contents, $vals, $index);
757
758 xml_parser_free($parser);
759
760 // parse styles from the manual for future rendering
761 $Styles = $this->parseStyles($vals);
762
763 $id = 0;
764 $tableNumber = 0;
765 do {
766 list($tableStart, $tableEnd) = $this->nextTSDefinitionTable($vals, $index, $id);
767 if ($tableStart !== FALSE) {
768 // The title of the table can either be self-contained in a single complete entry
769 if (!strcmp($vals[$id]['type'], 'complete')) {
770 $title = $vals[$id]['value'];
771 } else { // or it can be spread across a number of spans or similar
772 $watchTag = $vals[$id]['tag'];
773 $title = '';
774 while (strcmp($vals[$id]['tag'], $watchTag) || strcmp($vals[$id]['type'], 'close')) {
775 $title .= $vals[$id++]['value'];
776 }
777 }
778 $tableContents = $this->parseTable($vals, $tableStart, $tableEnd);
779 $this->dumpIntoSQL($extension, $tableContents, $title);
780 $tableNumber++;
781 }
782 } while ($tableStart !== FALSE);
783 return $tableNumber;
784 }
785 }
786
787
788 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/tsconfig_help/mod1/index.php']) {
789 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/tsconfig_help/mod1/index.php']);
790 }
791
792
793
794
795 // Make instance:
796 $SOBE = t3lib_div::makeInstance('tx_tsconfighelp_module1');
797 $SOBE->init();
798
799 // Include files?
800 foreach ($SOBE->include_once as $INC_FILE) include_once($INC_FILE);
801
802 $SOBE->main();
803 $SOBE->printContent();
804
805 ?>