[BUGFIX] Fix 1-2-3(-4) wizard
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_syntaxhl.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
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 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains a class for various syntax highlighting.
29 *
30 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
31 */
32
33 /**
34 * Syntax Highlighting class.
35 *
36 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
37 * @package TYPO3
38 * @subpackage t3lib
39 */
40 class t3lib_syntaxhl {
41
42 // Internal, dynamic:
43 // Parse object.
44 var $htmlParse;
45
46 // External, static:
47 var $DS_wrapTags = array(
48 'T3DataStructure' => array('<span style="font-weight: bold;">', '</span>'),
49 'type' => array('<span style="font-weight: bold; color: #000080;">', '</span>'),
50 'section' => array('<span style="font-weight: bold; color: #000080;">', '</span>'),
51 'el' => array('<span style="font-weight: bold; color: #800000;">', '</span>'),
52 'meta' => array('<span style="font-weight: bold; color: #800080;">', '</span>'),
53 '_unknown' => array('<span style="font-style: italic; color: #666666;">', '</span>'),
54
55 '_applicationTag' => array('<span style="font-weight: bold; color: #FF6600;">', '</span>'),
56 '_applicationContents' => array('<span style="font-style: italic; color: #C29336;">', '</span>'),
57
58 'sheets' => array('<span style="font-weight: bold; color: #008000;">', '</span>'),
59 'parent:sheets' => array('<span style="color: #008000;">', '</span>'),
60
61 'ROOT' => array('<span style="font-weight: bold; color: #008080;">', '</span>'),
62 'parent:el' => array('<span style="font-weight: bold; color: #008080;">', '</span>'),
63
64 'langDisable' => array('<span style="color: #000080;">', '</span>'),
65 'langChildren' => array('<span style="color: #000080;">', '</span>'),
66 );
67
68 var $FF_wrapTags = array(
69 'T3FlexForms' => array('<span style="font-weight: bold;">', '</span>'),
70 'meta' => array('<span style="font-weight: bold; color: #800080;">', '</span>'),
71 'data' => array('<span style="font-weight: bold; color: #800080;">', '</span>'),
72 'el' => array('<span style="font-weight: bold; color: #80a000;">', '</span>'),
73 'itemType' => array('<span style="font-weight: bold; color: #804000;">', '</span>'),
74 'section' => array('<span style="font-weight: bold; color: #604080;">', '</span>'),
75 'numIndex' => array('<span style="color: #333333;">', '</span>'),
76 '_unknown' => array('<span style="font-style: italic; color: #666666;">', '</span>'),
77
78
79 'sDEF' => array('<span style="font-weight: bold; color: #008000;">', '</span>'),
80 'level:sheet' => array('<span style="font-weight: bold; color: #008000;">', '</span>'),
81
82 'lDEF' => array('<span style="font-weight: bold; color: #000080;">', '</span>'),
83 'level:language' => array('<span style="font-weight: bold; color: #000080;">', '</span>'),
84
85 'level:fieldname' => array('<span style="font-weight: bold; color: #666666;">', '</span>'),
86
87 'vDEF' => array('<span style="font-weight: bold; color: #008080;">', '</span>'),
88 'level:value' => array('<span style="font-weight: bold; color: #008080;">', '</span>'),
89
90 'currentSheetId' => array('<span style="color: #000080;">', '</span>'),
91 'currentLangId' => array('<span style="color: #000080;">', '</span>'),
92 );
93
94 /*************************************
95 *
96 * Markup of Data Structure, <T3DataStructure>
97 *
98 *************************************/
99
100 /**
101 * Makes syntax highlighting of a Data Structure, <T3DataStructure>
102 *
103 * @param string $str Data Structure XML, must be valid since it's parsed.
104 * @return string HTML code with highlighted content. Must be wrapped in <PRE> tags
105 */
106 function highLight_DS($str) {
107
108 // Parse DS to verify that it is valid:
109 $DS = t3lib_div::xml2array($str);
110 if (is_array($DS)) {
111 // Complete list of tags in DS
112 $completeTagList = array_unique($this->getAllTags($str));
113
114 // Highlighting source:
115 // Init parser object
116 $this->htmlParse = t3lib_div::makeInstance('t3lib_parsehtml');
117 // Split the XML by the found tags, recursively into LARGE array.
118 $struct = $this->splitXMLbyTags(implode(',', $completeTagList), $str);
119 // Perform color-markup on the parsed content. Markup preserves the LINE formatting of the XML.
120 $markUp = $this->highLight_DS_markUpRecursively($struct);
121
122 // Return content:
123 return $markUp;
124 } else {
125 $error = 'ERROR: The input content failed XML parsing: ' . $DS;
126 }
127 return $error;
128 }
129
130 /**
131 * Making syntax highlighting of the parsed Data Structure XML.
132 * Called recursively.
133 *
134 * @param array $struct The structure, see splitXMLbyTags()
135 * @param string $parent Parent tag.
136 * @param string $app "Application" - used to denote if we are 'inside' a section
137 * @return string HTML
138 */
139 function highLight_DS_markUpRecursively($struct, $parent = '', $app = '') {
140 $output = '';
141 foreach ($struct as $k => $v) {
142 if ($k % 2) {
143 $nextApp = $app;
144 $wrap = array('', '');
145
146 switch ($app) {
147 case 'TCEforms':
148 case 'tx_templavoila':
149 $wrap = $this->DS_wrapTags['_applicationContents'];
150 break;
151 case 'el':
152 default:
153 if ($parent == 'el') {
154 $wrap = $this->DS_wrapTags['parent:el'];
155 $nextApp = 'el';
156 } elseif ($parent == 'sheets') {
157 $wrap = $this->DS_wrapTags['parent:sheets'];
158 } else {
159 $wrap = $this->DS_wrapTags[$v['tagName']];
160 $nextApp = '';
161 }
162
163 // If no wrap defined, us "unknown" definition
164 if (!is_array($wrap)) {
165 $wrap = $this->DS_wrapTags['_unknown'];
166 }
167
168 // Check for application sections in the XML:
169 if ($app == 'el' || $parent == 'ROOT') {
170 switch ($v['tagName']) {
171 case 'TCEforms':
172 case 'tx_templavoila':
173 $nextApp = $v['tagName'];
174 $wrap = $this->DS_wrapTags['_applicationTag'];
175 break;
176 }
177 }
178 break;
179 }
180
181 $output .= $wrap[0] . htmlspecialchars($v['tag']) . $wrap[1];
182 $output .= $this->highLight_DS_markUpRecursively($v['sub'], $v['tagName'], $nextApp);
183 $output .= $wrap[0] . htmlspecialchars('</' . $v['tagName'] . '>') . $wrap[1];
184 } else {
185 $output .= htmlspecialchars($v);
186 }
187 }
188
189 return $output;
190 }
191
192 /*************************************
193 *
194 * Markup of Data Structure, <T3FlexForms>
195 *
196 *************************************/
197
198 /**
199 * Makes syntax highlighting of a FlexForm Data, <T3FlexForms>
200 *
201 * @param string $str Data Structure XML, must be valid since it's parsed.
202 * @return string HTML code with highlighted content. Must be wrapped in <PRE> tags
203 */
204 function highLight_FF($str) {
205
206 // Parse DS to verify that it is valid:
207 $DS = t3lib_div::xml2array($str);
208 if (is_array($DS)) {
209 // Complete list of tags in DS
210 $completeTagList = array_unique($this->getAllTags($str));
211
212 // Highlighting source:
213 // Init parser object
214 $this->htmlParse = t3lib_div::makeInstance('t3lib_parsehtml');
215 // Split the XML by the found tags, recursively into LARGE array.
216 $struct = $this->splitXMLbyTags(implode(',', $completeTagList), $str);
217 // Perform color-markup on the parsed content. Markup preserves the LINE formatting of the XML.
218 $markUp = $this->highLight_FF_markUpRecursively($struct);
219
220 // Return content:
221 return $markUp;
222 } else {
223 $error = 'ERROR: The input content failed XML parsing: ' . $DS;
224 }
225 return $error;
226 }
227
228 /**
229 * Making syntax highlighting of the parsed FlexForm XML.
230 * Called recursively.
231 *
232 * @param array $struct The structure, see splitXMLbyTags()
233 * @param string $parent Parent tag.
234 * @param string $app "Application" - used to denote if we are 'inside' a section
235 * @return string HTML
236 */
237 function highLight_FF_markUpRecursively($struct, $parent = '', $app = '') {
238 $output = '';
239
240 // Setting levels:
241 if ($parent == 'data') {
242 $app = 'sheet';
243 } elseif ($app == 'sheet') {
244 $app = 'language';
245 } elseif ($app == 'language') {
246 $app = 'fieldname';
247 } elseif ($app == 'fieldname') {
248 $app = 'value';
249 } elseif ($app == 'el' || $app == 'numIndex') {
250 $app = 'fieldname';
251 }
252
253 // Traverse structure:
254 foreach ($struct as $k => $v) {
255 if ($k % 2) {
256 $wrap = array('', '');
257
258 if ($v['tagName'] == 'numIndex') {
259 $app = 'numIndex';
260 }
261
262 // Default wrap:
263 $wrap = $this->FF_wrapTags[$v['tagName']];
264
265 // If no wrap defined, us "unknown" definition
266 if (!is_array($wrap)) {
267 switch ($app) {
268 case 'sheet':
269 case 'language':
270 case 'fieldname':
271 case 'value':
272 $wrap = $this->FF_wrapTags['level:' . $app];
273 break;
274 default:
275 $wrap = $this->FF_wrapTags['_unknown'];
276 break;
277 }
278 }
279
280 if ($v['tagName'] == 'el') {
281 $app = 'el';
282 }
283
284 $output .= $wrap[0] . htmlspecialchars($v['tag']) . $wrap[1];
285 $output .= $this->highLight_FF_markUpRecursively($v['sub'], $v['tagName'], $app);
286 $output .= $wrap[0] . htmlspecialchars('</' . $v['tagName'] . '>') . $wrap[1];
287 } else {
288 $output .= htmlspecialchars($v);
289 }
290 }
291
292 return $output;
293 }
294
295 /*************************************
296 *
297 * Various
298 *
299 *************************************/
300
301 /**
302 * Returning all tag names found in XML/HTML input string
303 *
304 * @param string $str HTML/XML input
305 * @return array Array with all found tags (starttags only)
306 */
307 function getAllTags($str) {
308
309 // Init:
310 $tags = array();
311 $token = md5(microtime());
312
313 // Markup all tag names with token.
314 $markUpStr = preg_replace('/<([[:alnum:]_]+)[^>]*>/', $token . '${1}' . $token, $str);
315
316 // Splitting by token:
317 $parts = explode($token, $markUpStr);
318
319 // Traversing parts:
320 foreach ($parts as $k => $v) {
321 if ($k % 2) {
322 $tags[] = $v;
323 }
324 }
325
326 // Returning tags:
327 return $tags;
328 }
329
330 /**
331 * Splitting the input source by the tags listing in $tagList.
332 * Called recursively.
333 *
334 * @param string $tagList Commalist of tags to split source by (into blocks, ALL being block-tags!)
335 * @param string $str Input string.
336 * @return array Array with the content arranged hierarchically.
337 */
338 function splitXMLbyTags($tagList, $str) {
339 $struct = $this->htmlParse->splitIntoBlock($tagList, $str);
340
341 // Traverse level:
342 foreach ($struct as $k => $v) {
343 if ($k % 2) {
344 $tag = $this->htmlParse->getFirstTag($v);
345 $tagName = $this->htmlParse->getFirstTagName($tag, TRUE);
346 $struct[$k] = array(
347 'tag' => $tag,
348 'tagName' => $tagName,
349 'sub' => $this->splitXMLbyTags($tagList, $this->htmlParse->removeFirstAndLastTag($struct[$k]))
350 );
351 }
352 }
353
354 return $struct;
355 }
356 }
357
358 ?>