ad3e7580ef1cf5eceb77ada442a906c010adf872
[Packages/TYPO3.CMS.git] / typo3 / sysext / cshmanual / Classes / Controller / HelpModuleController.php
1 <?php
2 namespace TYPO3\CMS\Cshmanual\Controller;
3
4 /**
5 * Script Class for rendering the Context Sensitive Help documents, either the single display in the small pop-up window or the full-table view in the larger window.
6 *
7 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
8 */
9 class HelpModuleController {
10
11 /**
12 * @todo Define visibility
13 */
14 public $allowedHTML = '<strong><em><b><i>';
15
16 // For these vars, see init()
17 // If set access to fields and tables is checked. Should be done for TRUE database tables.
18 /**
19 * @todo Define visibility
20 */
21 public $limitAccess;
22
23 // The "table" key
24 /**
25 * @todo Define visibility
26 */
27 public $table;
28
29 // The "field" key
30 /**
31 * @todo Define visibility
32 */
33 public $field;
34
35 /**
36 * Key used to point to the right CSH resource
37 * In simple cases, is equal to $table
38 *
39 * @var string
40 */
41 protected $mainKey;
42
43 // Internal, static: GPvar:
44 // Table/FIeld id.
45 /**
46 * @todo Define visibility
47 */
48 public $tfID;
49
50 // Back (previous tfID)
51 /**
52 * @todo Define visibility
53 */
54 public $back;
55
56 // If set, then in TOC mode the FULL manual will be printed as well!
57 /**
58 * @todo Define visibility
59 */
60 public $renderALL;
61
62 // Internal, dynamic:
63 // Content accumulation.
64 /**
65 * @todo Define visibility
66 */
67 public $content;
68
69 // Glossary words
70 /**
71 * @todo Define visibility
72 */
73 public $glossaryWords;
74
75 /**
76 * Initialize the class for various input etc.
77 *
78 * @return void
79 * @todo Define visibility
80 */
81 public function init() {
82 // Setting GPvars:
83 $this->tfID = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('tfID');
84 // Sanitizes the tfID using whitelisting.
85 if (!preg_match('/^[a-zA-Z0-9_\\-\\.\\*]*$/', $this->tfID)) {
86 $this->tfID = '';
87 }
88 $this->back = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('back');
89 $this->renderALL = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('renderALL');
90 // Set internal table/field to the parts of "tfID" incoming var.
91 $identifierParts = explode('.', $this->tfID);
92 // The table is the first item
93 $this->table = array_shift($identifierParts);
94 $this->mainKey = $this->table;
95 // The field is the second one
96 $this->field = array_shift($identifierParts);
97 // There may be extra parts for FlexForms
98 if (count($identifierParts) > 0) {
99 // There's at least one extra part
100 $extraIdentifierInformation = array();
101 $extraIdentifierInformation[] = array_shift($identifierParts);
102 // Load the TCA details of the table
103 \TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA($this->table);
104 // If the ds_pointerField contains a comma, it means the choice of FlexForm DS
105 // is determined by 2 parameters. In this case we have an extra identifier part
106 if (strpos($GLOBALS['TCA'][$this->table]['columns'][$this->field]['config']['ds_pointerField'], ',') !== FALSE) {
107 $extraIdentifierInformation[] = array_shift($identifierParts);
108 }
109 // The remaining parts make up the FlexForm field name itself
110 // (reassembled with dots)
111 $flexFormField = implode('.', $identifierParts);
112 // Assemble a different main key and switch field to use FlexForm field name
113 $this->mainKey .= '.' . $this->field;
114 foreach ($extraIdentifierInformation as $extraKey) {
115 $this->mainKey .= '.' . $extraKey;
116 }
117 $this->field = $flexFormField;
118 }
119 // limitAccess is checked if the $this->table really IS a table (and if the user is NOT a translator who should see all!)
120 $showAllToUser = \TYPO3\CMS\Backend\Utility\BackendUtility::isModuleSetInTBE_MODULES('txllxmltranslateM1') && $GLOBALS['BE_USER']->check('modules', 'txllxmltranslateM1');
121 $this->limitAccess = isset($GLOBALS['TCA'][$this->table]) ? !$showAllToUser : FALSE;
122 $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_view_help.xlf', 1);
123 }
124
125 /**
126 * Main function, rendering the display
127 *
128 * @return void
129 * @todo Define visibility
130 */
131 public function main() {
132 // Start HTML output accumulation:
133 $GLOBALS['TBE_TEMPLATE']->divClass = 'typo3-view-help';
134 $this->content .= $GLOBALS['TBE_TEMPLATE']->startPage($GLOBALS['LANG']->getLL('title'));
135 if ($this->field == '*') {
136 // If ALL fields is supposed to be shown:
137 $this->createGlossaryIndex();
138 $this->content .= $this->render_Table($this->mainKey);
139 } elseif ($this->tfID) {
140 // ... otherwise show only single field:
141 $this->createGlossaryIndex();
142 $this->content .= $this->render_Single($this->mainKey, $this->field);
143 } else {
144 // Render Table Of Contents if nothing else:
145 $this->content .= $this->render_TOC();
146 }
147 // End page:
148 $this->content .= '<br/>';
149 $this->content .= $GLOBALS['TBE_TEMPLATE']->endPage();
150 }
151
152 /**
153 * Outputting the accumulated content to screen
154 *
155 * @return void
156 * @todo Define visibility
157 */
158 public function printContent() {
159 echo $this->content;
160 }
161
162 /************************************
163 *
164 * Rendering main modes
165 *
166 ************************************/
167 /**
168 * Creates Table Of Contents and possibly "Full Manual" mode if selected.
169 *
170 * @return string HTML content
171 * @todo Define visibility
172 */
173 public function render_TOC() {
174 // Initialize:
175 $CSHkeys = array_flip(array_keys($GLOBALS['TCA_DESCR']));
176 $TCAkeys = array_keys($GLOBALS['TCA']);
177 $outputSections = array();
178 $tocArray = array();
179 // TYPO3 Core Features:
180 $GLOBALS['LANG']->loadSingleTableDescription('xMOD_csh_corebe');
181 $this->render_TOC_el('xMOD_csh_corebe', 'core', $outputSections, $tocArray, $CSHkeys);
182 // Backend Modules:
183 $loadModules = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Module\\ModuleLoader');
184 $loadModules->load($GLOBALS['TBE_MODULES']);
185 foreach ($loadModules->modules as $mainMod => $info) {
186 $cshKey = '_MOD_' . $mainMod;
187 if ($CSHkeys[$cshKey]) {
188 $GLOBALS['LANG']->loadSingleTableDescription($cshKey);
189 $this->render_TOC_el($cshKey, 'modules', $outputSections, $tocArray, $CSHkeys);
190 }
191 if (is_array($info['sub'])) {
192 foreach ($info['sub'] as $subMod => $subInfo) {
193 $cshKey = '_MOD_' . $mainMod . '_' . $subMod;
194 if ($CSHkeys[$cshKey]) {
195 $GLOBALS['LANG']->loadSingleTableDescription($cshKey);
196 $this->render_TOC_el($cshKey, 'modules', $outputSections, $tocArray, $CSHkeys);
197 }
198 }
199 }
200 }
201 // Database Tables:
202 foreach ($TCAkeys as $table) {
203 // Load descriptions for table $table
204 $GLOBALS['LANG']->loadSingleTableDescription($table);
205 if (is_array($GLOBALS['TCA_DESCR'][$table]['columns']) && $GLOBALS['BE_USER']->check('tables_select', $table)) {
206 $this->render_TOC_el($table, 'tables', $outputSections, $tocArray, $CSHkeys);
207 }
208 }
209 // Extensions
210 foreach ($CSHkeys as $cshKey => $value) {
211 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($cshKey, 'xEXT_') && !isset($GLOBALS['TCA'][$cshKey])) {
212 $GLOBALS['LANG']->loadSingleTableDescription($cshKey);
213 $this->render_TOC_el($cshKey, 'extensions', $outputSections, $tocArray, $CSHkeys);
214 }
215 }
216 // Glossary
217 foreach ($CSHkeys as $cshKey => $value) {
218 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($cshKey, 'xGLOSSARY_') && !isset($GLOBALS['TCA'][$cshKey])) {
219 $GLOBALS['LANG']->loadSingleTableDescription($cshKey);
220 $this->render_TOC_el($cshKey, 'glossary', $outputSections, $tocArray, $CSHkeys);
221 }
222 }
223 // Other:
224 foreach ($CSHkeys as $cshKey => $value) {
225 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($cshKey, '_MOD_') && !isset($GLOBALS['TCA'][$cshKey])) {
226 $GLOBALS['LANG']->loadSingleTableDescription($cshKey);
227 $this->render_TOC_el($cshKey, 'other', $outputSections, $tocArray, $CSHkeys);
228 }
229 }
230 // COMPILE output:
231 $output = '';
232 $output .= '
233
234 <h1>' . $GLOBALS['LANG']->getLL('manual_title', 1) . '</h1>';
235 $output .= '
236
237 <h2>' . $GLOBALS['LANG']->getLL('introduction', 1) . '</h2>
238 <p>' . $GLOBALS['LANG']->getLL('description', 1) . '</p>';
239 $output .= '
240
241 <h2>' . $GLOBALS['LANG']->getLL('TOC', 1) . '</h2>' . $this->render_TOC_makeTocList($tocArray);
242 if (!$this->renderALL) {
243 $output .= '
244 <br/>
245 <p class="c-nav"><a href="mod.php?M=help_cshmanual&renderALL=1">' . $GLOBALS['LANG']->getLL('full_manual', 1) . '</a></p>';
246 }
247 if ($this->renderALL) {
248 $output .= '
249
250 <h2>' . $GLOBALS['LANG']->getLL('full_manual_chapters', 1) . '</h2>' . implode('
251
252
253 <!-- NEW SECTION: -->
254 ', $outputSections);
255 }
256 $output .= '<hr /><p class="manual-title">' . \TYPO3\CMS\Backend\Utility\BackendUtility::TYPO3_copyRightNotice() . '</p>';
257 return $output;
258 }
259
260 /**
261 * Creates a TOC list element and renders corresponding HELP content if "renderALL" mode is set.
262 *
263 * @param string $table CSH key / Table name
264 * @param string $tocCat TOC category keyword: "core", "modules", "tables", "other
265 * @param array $outputSections Array for accumulation of rendered HELP Content (in "renderALL" mode). Passed by reference!
266 * @param array $tocArray TOC array; Here TOC index elements are created. Passed by reference!
267 * @param array $CSHkeys CSH keys array. Every item rendered will be unset in this array so finally we can see what CSH keys are not processed yet. Passed by reference!
268 * @return void
269 * @todo Define visibility
270 */
271 public function render_TOC_el($table, $tocCat, &$outputSections, &$tocArray, &$CSHkeys) {
272 // Render full manual right here!
273 if ($this->renderALL) {
274 $outputSections[$table] = $this->render_Table($table);
275 if ($outputSections[$table]) {
276 $outputSections[$table] = '
277
278 <!-- New CSHkey/Table: ' . $table . ' -->
279 <p class="c-nav"><a name="ANCHOR_' . $table . '" href="#">' . $GLOBALS['LANG']->getLL('to_top', 1) . '</a></p>
280 <h2>' . $this->getTableFieldLabel($table) . '</h2>
281
282 ' . $outputSections[$table];
283 $tocArray[$tocCat][$table] = '<a href="#ANCHOR_' . $table . '">' . $this->getTableFieldLabel($table) . '</a>';
284 } else {
285 unset($outputSections[$table]);
286 }
287 } else {
288 // Only TOC:
289 $tocArray[$tocCat][$table] = '<p><a href="mod.php?M=help_cshmanual&tfID=' . rawurlencode(($table . '.*')) . '">' . $this->getTableFieldLabel($table) . '</a></p>';
290 }
291 // Unset CSH key:
292 unset($CSHkeys[$table]);
293 }
294
295 /**
296 * Renders the TOC index as a HTML bullet list from TOC array
297 *
298 * @param array $tocArray ToC Array.
299 * @return string HTML bullet list for index.
300 * @todo Define visibility
301 */
302 public function render_TOC_makeTocList($tocArray) {
303 // The Various manual sections:
304 $keys = explode(',', 'core,modules,tables,extensions,glossary,other');
305 // Create TOC bullet list:
306 $output = '';
307 foreach ($keys as $tocKey) {
308 if (is_array($tocArray[$tocKey])) {
309 $output .= '
310 <li>' . $GLOBALS['LANG']->getLL(('TOC_' . $tocKey), 1) . '
311 <ul>
312 <li>' . implode('</li>
313 <li>', $tocArray[$tocKey]) . '</li>
314 </ul>
315 </li>';
316 }
317 }
318 // Compile TOC:
319 $output = '
320
321 <!-- TOC: -->
322 <div class="c-toc">
323 <ul>
324 ' . $output . '
325 </ul>
326 </div>';
327 return $output;
328 }
329
330 /**
331 * Render CSH for a full cshKey/table
332 *
333 * @param string $key Full CSH key (may be different from table name)
334 * @param string $table CSH key / table name
335 * @return string HTML output
336 * @todo Define visibility
337 */
338 public function render_Table($key, $table = NULL) {
339 $output = '';
340 // Take default key if not explicitly specified
341 if ($table === NULL) {
342 $table = $key;
343 }
344 // Load table TCA
345 \TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA($key);
346 // Load descriptions for table $table
347 $GLOBALS['LANG']->loadSingleTableDescription($key);
348 if (is_array($GLOBALS['TCA_DESCR'][$key]['columns']) && (!$this->limitAccess || $GLOBALS['BE_USER']->check('tables_select', $table))) {
349 // Initialize variables:
350 $parts = array();
351 // Reserved for header of table
352 $parts[0] = '';
353 // Traverse table columns as listed in TCA_DESCR
354 foreach ($GLOBALS['TCA_DESCR'][$key]['columns'] as $field => $_) {
355 $fieldValue = isset($GLOBALS['TCA'][$key]) && strcmp($field, '') ? $GLOBALS['TCA'][$key]['columns'][$field] : array();
356 if (is_array($fieldValue) && (!$this->limitAccess || !$fieldValue['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $table . ':' . $field))) {
357 if (!$field) {
358 // Header
359 $parts[0] = $this->printItem($key, '', 1);
360 } else {
361 // Field
362 $parts[] = $this->printItem($key, $field, 1);
363 }
364 }
365 }
366 if (!$parts[0]) {
367 unset($parts[0]);
368 }
369 $output .= implode('<br />', $parts);
370 }
371 // Substitute glossary words:
372 $output = $this->substituteGlossaryWords($output);
373 // TOC link:
374 if (!$this->renderALL) {
375 $tocLink = '<p class="c-nav"><a href="mod.php?M=help_cshmanual">' . $GLOBALS['LANG']->getLL('goToToc', 1) . '</a></p>';
376 $output = $tocLink . '
377 <br/>' . $output . '
378 <br />' . $tocLink;
379 }
380 return $output;
381 }
382
383 /**
384 * Renders CSH for a single field.
385 *
386 * @param string $key CSH key / table name
387 * @param string $field Sub key / field name
388 * @return string HTML output
389 * @todo Define visibility
390 */
391 public function render_Single($key, $field) {
392 $output = '';
393 // Load the description field
394 $GLOBALS['LANG']->loadSingleTableDescription($key);
395 // Render single item
396 $output .= $this->printItem($key, $field);
397 // Substitute glossary words:
398 $output = $this->substituteGlossaryWords($output);
399 // Link to Full table description and TOC:
400 $getLLKey = $this->limitAccess ? 'fullDescription' : 'fullDescription_module';
401 $output .= '<br />
402 <p class="c-nav"><a href="mod.php?M=help_cshmanual&tfID=' . rawurlencode(($key . '.*')) . '">' . $GLOBALS['LANG']->getLL($getLLKey, 1) . '</a></p>
403 <p class="c-nav"><a href="mod.php?M=help_cshmanual">' . $GLOBALS['LANG']->getLL('goToToc', 1) . '</a></p>';
404 return $output;
405 }
406
407 /************************************
408 *
409 * Rendering CSH items
410 *
411 ************************************/
412 /**
413 * Make seeAlso links from $value
414 *
415 * @param string $value See-also input codes
416 * @param string $anchorTable If $anchorTable is set to a tablename, then references to this table will be made as anchors, not URLs.
417 * @return string See-also links HTML
418 * @todo Define visibility
419 */
420 public function make_seeAlso($value, $anchorTable = '') {
421 // Split references by comma or linebreak
422 $items = preg_split('/[,' . LF . ']/', $value);
423 $lines = array();
424 foreach ($items as $val) {
425 $val = trim($val);
426 if ($val) {
427 $iP = explode(':', $val);
428 $iPUrl = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode('|', $val);
429 // URL reference:
430 if (substr($iPUrl[1], 0, 4) == 'http') {
431 $lines[] = '<a href="' . htmlspecialchars($iPUrl[1]) . '" target="_blank"><em>' . htmlspecialchars($iPUrl[0]) . '</em></a>';
432 } elseif (substr($iPUrl[1], 0, 5) == 'FILE:') {
433 $fileName = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName(substr($iPUrl[1], 5), 1, 1);
434 if ($fileName && @is_file($fileName)) {
435 $fileName = '../' . substr($fileName, strlen(PATH_site));
436 $lines[] = '<a href="' . htmlspecialchars($fileName) . '" target="_blank"><em>' . htmlspecialchars($iPUrl[0]) . '</em></a>';
437 }
438 } else {
439 // "table" reference
440 \TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA($iP[0]);
441 if (!isset($GLOBALS['TCA'][$iP[0]]) || (!$iP[1] || is_array($GLOBALS['TCA'][$iP[0]]['columns'][$iP[1]])) && (!$this->limitAccess || $GLOBALS['BE_USER']->check('tables_select', $iP[0]) && (!$iP[1] || !$GLOBALS['TCA'][$iP[0]]['columns'][$iP[1]]['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $iP[0] . ':' . $iP[1])))) {
442 // Checking read access:
443 if (isset($GLOBALS['TCA_DESCR'][$iP[0]])) {
444 // Make see-also link:
445 $href = $this->renderALL || $anchorTable && $iP[0] == $anchorTable ? '#' . implode('.', $iP) : 'mod.php?M=help_cshmanual&tfID=' . rawurlencode(implode('.', $iP)) . '&back=' . $this->tfID;
446 $label = $this->getTableFieldLabel($iP[0], $iP[1], ' / ');
447 $lines[] = '<a href="' . htmlspecialchars($href) . '">' . htmlspecialchars($label) . '</a>';
448 }
449 }
450 }
451 }
452 }
453 return implode('<br />', $lines);
454 }
455
456 /**
457 * Will return an image tag with description in italics.
458 *
459 * @param string $images Image file reference (list of)
460 * @param string $descr Description string (divided for each image by line break)
461 * @return string Image HTML codes
462 * @todo Define visibility
463 */
464 public function printImage($images, $descr) {
465 $code = '';
466 // Splitting:
467 $imgArray = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $images, 1);
468 if (count($imgArray)) {
469 $descrArray = explode(LF, $descr, count($imgArray));
470 foreach ($imgArray as $k => $image) {
471 $descr = $descrArray[$k];
472 $absImagePath = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($image, 1, 1);
473 if ($absImagePath && @is_file($absImagePath)) {
474 $imgFile = substr($absImagePath, strlen(PATH_site));
475 $imgInfo = @getimagesize($absImagePath);
476 if (is_array($imgInfo)) {
477 $imgFile = '../' . $imgFile;
478 $code .= '<br /><img src="' . $imgFile . '" ' . $imgInfo[3] . ' class="c-inlineimg" alt="" /><br />
479 ';
480 $code .= '<p><em>' . htmlspecialchars($descr) . '</em></p>
481 ';
482 } else {
483 $code .= '<div style="background-color: red; border: 1px solid black; color: white;">NOT AN IMAGE: ' . $imgFile . '</div>';
484 }
485 } else {
486 $code .= '<div style="background-color: red; border: 1px solid black; color: white;">IMAGE FILE NOT FOUND: ' . $image . '</div>';
487 }
488 }
489 }
490 return $code;
491 }
492
493 /**
494 * Returns header HTML content
495 *
496 * @param string $str Header text
497 * @param string $type Header type (1, 0)
498 * @return string The HTML for the header.
499 * @todo Define visibility
500 */
501 public function headerLine($str, $type = 0) {
502 switch ($type) {
503 case 1:
504 $str = '<h2 class="t3-row-header">' . htmlspecialchars($str) . '</h2>
505 ';
506 break;
507 case 0:
508 $str = '<h3 class="divider">' . htmlspecialchars($str) . '</h3>
509 ';
510 break;
511 }
512 return $str;
513 }
514
515 /**
516 * Returns prepared content
517 *
518 * @param string $str Content to format.
519 * @return string Formatted content.
520 * @todo Define visibility
521 */
522 public function prepareContent($str) {
523 return '<p>' . nl2br(trim(strip_tags($str, $this->allowedHTML))) . '</p>
524 ';
525 }
526
527 /**
528 * Prints a single $table/$field information piece
529 * If $anchors is set, then seeAlso references to the same table will be page-anchors, not links.
530 *
531 * @param string $key CSH key / table name
532 * @param string $field Sub key / field name
533 * @param boolean $anchors If anchors is to be shown.
534 * @return string HTML content
535 * @todo Define visibility
536 */
537 public function printItem($key, $field, $anchors = FALSE) {
538 $out = '';
539 // Load full table definition in $GLOBALS['TCA']
540 \TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA($key);
541 if ($key && (!$field || is_array($GLOBALS['TCA_DESCR'][$key]['columns'][$field]))) {
542 // Make seeAlso references.
543 $seeAlsoRes = $this->make_seeAlso($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['seeAlso'], $anchors ? $key : '');
544 // Making item:
545 $out = '<a name="' . $key . '.' . $field . '"></a>' . $this->headerLine($this->getTableFieldLabel($key, $field), 1) . $this->prepareContent($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['description']) . ($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['details'] ? $this->headerLine(($GLOBALS['LANG']->getLL('details') . ':')) . $this->prepareContent($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['details']) : '') . ($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['syntax'] ? $this->headerLine(($GLOBALS['LANG']->getLL('syntax') . ':')) . $this->prepareContent($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['syntax']) : '') . ($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['image'] ? $this->printImage($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['image'], $GLOBALS['TCA_DESCR'][$key]['columns'][$field]['image_descr']) : '') . ($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['seeAlso'] && $seeAlsoRes ? $this->headerLine(($GLOBALS['LANG']->getLL('seeAlso') . ':')) . '<p>' . $seeAlsoRes . '</p>' : '') . ($this->back ? '<br /><p><a href="' . htmlspecialchars(('mod.php?M=help_cshmanual&tfID=' . rawurlencode($this->back))) . '" class="typo3-goBack">' . htmlspecialchars($GLOBALS['LANG']->getLL('goBack')) . '</a></p>' : '') . '<br />';
546 }
547 return $out;
548 }
549
550 /**
551 * Returns labels for a given field in a given structure
552 *
553 * @param string $key CSH key / table name
554 * @param string $field Sub key / field name
555 * @return array Table and field labels in a numeric array
556 * @todo Define visibility
557 */
558 public function getTableFieldNames($key, $field) {
559 $GLOBALS['LANG']->loadSingleTableDescription($key);
560 // Define the label for the key
561 $keyName = $key;
562 if (is_array($GLOBALS['TCA_DESCR'][$key]['columns']['']) && isset($GLOBALS['TCA_DESCR'][$key]['columns']['']['alttitle'])) {
563 // If there's an alternative title, use it
564 $keyName = $GLOBALS['TCA_DESCR'][$key]['columns']['']['alttitle'];
565 } elseif (isset($GLOBALS['TCA'][$key])) {
566 // Otherwise, if it's a table, use its title
567 $keyName = $GLOBALS['TCA'][$key]['ctrl']['title'];
568 } else {
569 // If no title was found, make sure to remove any "_MOD_"
570 $keyName = preg_replace('/^_MOD_/', '', $key);
571 }
572 // Define the label for the field
573 $fieldName = $field;
574 if (is_array($GLOBALS['TCA_DESCR'][$key]['columns'][$field]) && isset($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['alttitle'])) {
575 // If there's an alternative title, use it
576 $fieldName = $GLOBALS['TCA_DESCR'][$key]['columns'][$field]['alttitle'];
577 } elseif (isset($GLOBALS['TCA'][$key]) && isset($GLOBALS['TCA'][$key]['columns'][$field])) {
578 // Otherwise, if it's a table, use its title
579 $fieldName = $GLOBALS['TCA'][$key]['columns'][$field]['label'];
580 }
581 return array($keyName, $fieldName);
582 }
583
584 /**
585 * Returns composite label for table/field
586 *
587 * @param string $key CSH key / table name
588 * @param string $field Sub key / field name
589 * @param string $mergeToken Token to merge the two strings with
590 * @return string Labels joined with merge token
591 * @see getTableFieldNames()
592 * @todo Define visibility
593 */
594 public function getTableFieldLabel($key, $field = '', $mergeToken = ': ') {
595 $tableName = '';
596 $fieldName = '';
597 // Get table / field parts:
598 list($tableName, $fieldName) = $this->getTableFieldNames($key, $field);
599 // Create label:
600 $labelString = $GLOBALS['LANG']->sL($tableName) . ($field ? $mergeToken . rtrim(trim($GLOBALS['LANG']->sL($fieldName)), ':') : '');
601 return $labelString;
602 }
603
604 /******************************
605 *
606 * Glossary related
607 *
608 ******************************/
609 /**
610 * Creates glossary index in $this->glossaryWords
611 * Glossary is cached in cache_hash cache and so will be updated only when cache is cleared.
612 *
613 * @return void
614 * @todo Define visibility
615 */
616 public function createGlossaryIndex() {
617 // Create hash string and try to retrieve glossary array:
618 $hash = md5('typo3/mod.php?M=help_cshmanual:glossary');
619 list($this->glossaryWords, $this->substWords) = unserialize(\TYPO3\CMS\Backend\Utility\BackendUtility::getHash($hash));
620 // Generate glossary words if not found:
621 if (!is_array($this->glossaryWords)) {
622 // Initialize:
623 $this->glossaryWords = array();
624 $this->substWords = array();
625 $CSHkeys = array_flip(array_keys($GLOBALS['TCA_DESCR']));
626 // Glossary
627 foreach ($CSHkeys as $cshKey => $value) {
628 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($cshKey, 'xGLOSSARY_') && !isset($GLOBALS['TCA'][$cshKey])) {
629 $GLOBALS['LANG']->loadSingleTableDescription($cshKey);
630 if (is_array($GLOBALS['TCA_DESCR'][$cshKey]['columns'])) {
631 // Traverse table columns as listed in TCA_DESCR
632 foreach ($GLOBALS['TCA_DESCR'][$cshKey]['columns'] as $field => $data) {
633 if ($field) {
634 $this->glossaryWords[$cshKey . '.' . $field] = array(
635 'title' => trim($data['alttitle'] ? $data['alttitle'] : $cshKey),
636 'description' => str_replace('%22', '%23%23%23', rawurlencode($data['description']))
637 );
638 }
639 }
640 }
641 }
642 }
643 // First, create unique list of words:
644 foreach ($this->glossaryWords as $key => $value) {
645 // Making word lowercase in order to filter out same words in different cases.
646 $word = strtolower($value['title']);
647 if ($word !== '') {
648 $this->substWords[$word] = $value;
649 $this->substWords[$word]['key'] = $key;
650 }
651 }
652 krsort($this->substWords);
653 \TYPO3\CMS\Backend\Utility\BackendUtility::storeHash($hash, serialize(array($this->glossaryWords, $this->substWords)), 'Glossary');
654 }
655 }
656
657 /**
658 * Processing of all non-HTML content in the output
659 * Will be done by a call-back to ->substituteGlossaryWords_htmlcleaner_callback()
660 *
661 * @param string $code Input HTML code
662 * @return string Output HTML code
663 * @todo Define visibility
664 */
665 public function substituteGlossaryWords($code) {
666 $htmlParser = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Core\Html\HtmlParser');
667 $htmlParser->pObj = $this;
668 $code = $htmlParser->HTMLcleaner($code, array(), 1);
669 return $code;
670 }
671
672 /**
673 * Substituting glossary words in the CSH
674 * (This is a call-back function from "class local_t3lib_parsehtml extends t3lib_parsehtml", see top of this script)
675 *
676 * @param string $code Input HTML string
677 * @return string HTML with substituted words in.
678 * @coauthor Alex Widschwendter, media.res kommunikationsloesungen
679 * @todo Define visibility
680 */
681 public function substituteGlossaryWords_htmlcleaner_callback($code) {
682 if (is_array($this->substWords) && count($this->substWords) && strlen(trim($code))) {
683 // Substitute words:
684 foreach ($this->substWords as $wordKey => $wordSet) {
685 // quoteMeta used so special chars (which should not occur though) in words will not break the regex. Seemed to work (- kasper)
686 $parts = preg_split('/( |[\\(])(' . quoteMeta($wordSet['title']) . ')([\\.\\!\\)\\?\\:\\,]+| )/i', ' ' . $code . ' ', 2, PREG_SPLIT_DELIM_CAPTURE);
687 if (count($parts) == 5) {
688 $parts[2] = '<a class="glossary-term" href="' . htmlspecialchars(('mod.php?M=help_cshmanual&tfID=' . rawurlencode($wordSet['key']) . '&back=' . $this->tfID)) . '" title="' . rawurlencode(htmlspecialchars(\TYPO3\CMS\Core\Utility\GeneralUtility::fixed_lgd_cs(rawurldecode($wordSet['description']), 80))) . '">' . htmlspecialchars($parts[2]) . '</a>';
689 $code = substr(implode('', $parts), 1, -1);
690 // Disable entry so it doesn't get used next time:
691 unset($this->substWords[$wordKey]);
692 }
693 }
694 $code = str_replace('###', '&quot;', rawurldecode($code));
695 }
696 return $code;
697 }
698
699 }
700
701
702 ?>