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