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