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