[TASK] Remove last XCLASS statements
[Packages/TYPO3.CMS.git] / typo3 / sysext / cms / tslib / media / scripts / wapversionLib.inc
1 <?php
2 /***************************************************************
3 *  Copyright notice
4 *
5 *  (c) 1999-2009 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 /**
29  * Class for creating WAP pages for TYPO3
30  *
31  * Class that creates the current page and content element records as an WML structure using the library "t3lib_xml"
32  * It is demonstrated in use in the testsite package on page "59"
33  * The static template "plugin.alt.wap" is used to trigger this WML creation as well. That template contains this set of TypoScript lines which triggers the WML creation and disables all regular HTML headers
34  *
35  * ## Set up page/type:
36  * alt_wap >
37  * alt_wap = PAGE
38  * alt_wap {
39  *   typeNum=97
40  *   config.disableAllHeaderCode = 1
41  *   config.additionalHeaders = Content-type: text/vnd.wap.wml
42  *
43  *   ## Includes the newsLib:
44  *   includeLibs.alt_wap = media/scripts/wapversionLib.inc
45  *
46  *   ## Inserting the USER cObject for WAP/XML rendering
47  *   10 = USER
48  *   10 {
49  *     userFunc = user_wapversion->main_wapversion
50  *     debug=0
51  *     preTitle = T3WAP
52  *     navLabels.prev = Prev
53  *     navLabels.next = Next
54  *     navLabels.up = Up
55  *   }
56  * }
57  *
58  * NOTICE:
59  *
60  * In the static template "plugin.alt.wap" there is a part in the end looking like this:
61  *
62  * ## If the browser is a WAP-device,
63  * [device=wap]
64  * alt_wap.typeNum=0
65  * [global]
66  *
67  * This means that IF the device coming to the URL is a WAP device they will get wap content even if they don't specify "&type=97" since the typeNum is changed to zero here!
68  * In fact they CANNOT get any wap-content at "&type=97" anymore! This has been a source of error and confusion for many people
69  *
70  * @package TYPO3
71  * @subpackage tslib
72  * @author Kasper Skårhøj <kasperYYYY@typo3.com>
73  */
74 class user_wapversion {
75                 // The backReference to the mother cObj object set at call time
76         var $cObj;
77
78         var $idx = 0;
79
80         /**
81          * Main function, called from TypoScript
82          *
83          * @param string $content Empty, ignore.
84          * @param array $conf TypoScript properties for this content object/function call
85          * @return string WML content
86          */
87         function main_wapversion($content, $conf) {
88                 $GLOBALS['TSFE']->set_no_cache();
89
90                 $xmlObj = t3lib_div::makeInstance('t3lib_xml', 'wml');
91                 $xmlObj->XMLdebug=$conf['debug'];
92
93                         // Creating top level object
94                 $xmlObj->WAPHeader();
95
96                         // Creating back button:
97                 $xmlObj->WAPback();
98
99                 $pageRec = $GLOBALS['TSFE']->page;
100                 if ($GLOBALS['TSFE']->idParts[1]) {
101                                 // Creating content card:
102                         $xmlObj->newLevel('card', 1, array(
103                                 'id' => 'content',
104                                 'title' => ($conf['preTitle']?$conf['preTitle'].': ':'').$pageRec['title']
105                         ));
106
107                         $cParts = $this->contentAll();
108                         $pointer = t3lib_utility_Math::forceIntegerInRange($GLOBALS['TSFE']->idParts[1], 1, 10000);
109
110                         $msg = '';
111                         if ($pointer - 1)       {
112                                 $msg .= $this->navLink(htmlspecialchars($conf['navLabels.']['prev']), $pointer - 1) . ' ';
113                         }
114                         $msg .= $this->navLink(htmlspecialchars($conf['navLabels.']['up']), 0).' ';
115                         if ($pointer < count($cParts)) {
116                                 $msg .= $this->navLink(htmlspecialchars($conf['navLabels.']['next']), $pointer + 1) . ' ';
117                         }
118                         $msg .= '['.$pointer.'/'.count($cParts).']<br/>';
119
120                         $xmlObj->lines[] = $this->paragraph($msg);
121                         $xmlObj->lines[] = $this->paragraph($cParts[$pointer-1]);
122                         $xmlObj->lines[] = $this->paragraph('<br/>'.$msg);
123
124                         $xmlObj->newLevel('card', 0);
125                 } else {
126                                 // Creating menu card:
127                         $xmlObj->newLevel('card', 1, array(
128                                 'id' => 'menu',
129                                 'title' => ($conf['preTitle']?$conf['preTitle'].': ':'').$pageRec['title']
130                         ));
131                         $xmlObj->lines[] = $this->contentAbstract();
132                         $xmlObj->lines[] = '<p><br/>'.$this->bold('Menu:').'</p>';
133                         $xmlObj->lines[] = $this->menuCurrentLevel($xmlObj->Icode);
134                         $xmlObj->newLevel('card', 0);
135                 }
136
137                         // Footer
138                 $xmlObj->renderFooter();
139                 return $xmlObj->getResult();
140         }
141
142         /**
143          * Getting abstract of the first content elements header and bodytext for the menu
144          *
145          * @return string WML string
146          */
147         function contentAbstract() {
148                 $res = $this->getContentResult('tt_content');
149                 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
150                 $out = $this->bold(t3lib_div::fixed_lgd_cs(htmlspecialchars($row['header']), 20)) . '<br/>' .
151                         t3lib_div::fixed_lgd_cs(htmlspecialchars($row['bodytext']), 50);
152                 $out = '<p>' . $out . ' <a href="' . htmlspecialchars('?id=' . $GLOBALS['TSFE']->id . ',1.' . $GLOBALS['TSFE']->type) . '">[more]</a></p>';
153                 return $out;
154         }
155
156         /**
157          * Returns all page content, but in an array where the content is divided into chunks or a max length (for WAP clients with limited memory capabilities)
158          * Content is then displayed using the pointer value found in $GLOBALS['TSFE']->idParts[1], see main_wapversion()
159          *
160          * @param integer $chunkLgd Max length of each content chunk
161          * @return array Array with the page content divided into chucks WML code (default length equals $chunkLgd; 850)
162          * @see main_wapversion()
163          */
164         function contentAll($chunkLgd = 850) {
165                 $res = $this->getContentResult('tt_content');
166                 $overlap = 5;
167                 $idx = 0;
168                 $out = array();
169                 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
170                                 // Header:
171                         $get = '<br/>'.$this->cHeader($row['header']).'<br/>';
172                         if (strlen($out[$idx].$get)>$chunkLgd) {
173                                 $idx++;
174                         }
175                         $out[$idx] .= $get;
176
177                         switch($row['CType']) {
178                                 case 'text':
179                                 case 'bullets':
180                                 case 'table':
181                                         $bodyText = $row['bodytext'];
182                                 break;
183                                 case 'textpic':
184                                 case 'image':
185                                         if ($row['CType']!='image')             {$bodyText = $row['bodytext'];}
186                                         $bodyText .= chr(10) . '[' . count(explode(',', $row['image'])) . 'images, caption: ' . $row['imagecaption'] . ']';
187                                 break;
188                                 case 'header':
189                                         $bodyText=$row['subheader'];
190                                 break;
191                                 default:
192                                         $bodyText = '[Un-rendered element, '.$row['CType'].']';
193                                 break;
194                         }
195
196                                 // Bodytext:
197                         $get = $this->cBodytext($bodyText).'<br/>';
198                         $diff = $chunkLgd - strlen($out[$idx]);
199
200                         if ($diff>strlen($get)) {
201                                 $out[$idx] .= $get;
202                         } else {
203                                 $out[$idx] .= $this->cBodytext($bodyText, 0, $diff + $overlap) . '<br/>';
204
205                                 $safe = 0;
206                                 do {
207                                         $idx++;
208                                         $out[$idx] .= $this->cBodytext($bodyText, $diff + ($safe * $chunkLgd) - $overlap, $chunkLgd + $overlap) . '<br/>';
209                                         $safe++;
210                                         if ($safe>100) break;
211                                 } while (strlen($out[$idx])>$chunkLgd);
212                         }
213                 }
214                 return $out;
215         }
216
217         /**
218          * Formats the header for a content element
219          *
220          * @param string $str Header value to format
221          * @return string Returns the formatted version, stripped from tags and htmlspecialchar()'ed
222          * @see contentAll()
223          */
224         function cHeader($str) {
225                 $out = $this->bold(htmlspecialchars(strip_tags($str)));
226                 return $out;
227         }
228
229         /**
230          * Formats the bodytext for a content element
231          *
232          * @param string $str The bodytext content
233          * @param integer $start Position where to start in the bodytext stream. If larger than zero a prefix, "...", is prepended.
234          * @param integer $max Max length
235          * @return string Prepared content
236          * @see contentAll()
237          */
238         function cBodytext($str, $start = 0, $max = 0) {
239                 $out = t3lib_div::fixed_lgd_cs(($start ? '...' : '') . substr($this->nl2br(htmlspecialchars(strip_tags($str))), $start), ($max ? $max : 100000));
240                         // No & in WAP docs??? --> or maybe just htmlspecialchar() things as the LAST thing instead!)
241                 $out = str_replace('&', '', $out);
242                 return $out;
243         }
244
245         /**
246          * Local version of ml2br(). Replaces linebreaks with <br/> tags.
247          *
248          * @param string $str The input string to process
249          * @return string The processed value returned.
250          */
251         function nl2br($str) {
252                 return str_replace(chr(10), '<br/>', $str);
253         }
254
255         /**
256          * Selects all records from $table having the current page id as PID (records belonging to that page)
257          * Used to select content elements from "tt_content"
258          *
259          * @param string $table A tablename found in $GLOBALS['TCA']
260          * @return pointer A database resource pointer
261          */
262         function getContentResult($table) {
263                 if ($GLOBALS['TCA'][$table]) {
264                         $orderBy = ($GLOBALS['TCA'][$table]['ctrl']['sortby']
265                                 ? 'ORDER BY '.$GLOBALS['TCA'][$table]['ctrl']['sortby']
266                                 : $GLOBALS['TCA'][$table]['ctrl']['default_sortby']);
267                         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'pid='.intval($GLOBALS['TSFE']->id).$this->cObj->enableFields($table), '', $GLOBALS['TYPO3_DB']->stripOrderBy($orderBy));
268                         return $res;
269                 }
270         }
271
272         /**
273          * Simulates bold type - basically setting it in uppercase
274          *
275          * @param string $str The string for format in "bold" (uppercase)
276          * @return string Processed output.
277          */
278         function bold($str) {
279                 return strtoupper($str);
280         }
281
282         /**
283          * Wraps a string in <p>...</p> tags
284          *
285          * @param string $str The input string
286          * @return string The wrapped string
287          */
288         function paragraph($str) {
289                 return '<p>' . $str . '</p>';
290         }
291
292         /**
293          * Adds a linebreak character to the end of $str
294          *
295          * @param string $str The string/line
296          * @return string The input string with '<br/>' prepended
297          */
298         function line($str) {
299                 return $str . '<br/>';
300         }
301
302         /**
303          * Creates a navigation link to the next part of the page content!
304          *
305          * @param string $str The link text
306          * @param integer $pointer The pointer value
307          * @return string The input string, linked with the pointer value to the current page.
308          */
309         function navLink($str, $pointer) {
310                 return '<a href="'.htmlspecialchars('?id='.$GLOBALS['TSFE']->id.','.$pointer.'.'.$GLOBALS['TSFE']->type).'">'.$str.'</a>';
311         }
312
313         /**
314          * Creates a menu for the current pagelevel. Navigation is both a path-menu (rootline) and a menu of current page subpages.
315          *
316          * @param string $indent Indentation prefix string per menu item.
317          * @return string A paragraph with the menu items inside.
318          */
319         function menuCurrentLevel($indent) {
320                 $rL = $GLOBALS['TSFE']->config['rootLine'];
321                 $preSpace='';
322                 $out=array();
323                         // Hierarchy menu
324                 foreach ($rL as $level => $data) {
325                         $preSign = count($rL)-1 > $level ? '-' : '>';
326                         $menuItem = htmlspecialchars($preSign.' '.$data['title']);
327                         $menuItem = $this->link($preSpace . $menuItem, $data['uid']);
328                         $out[] = $indent.$this->line($menuItem);
329                         $preSpace .= '..';
330                 }
331                         // Current page menu:
332                 $menu = $this->cleanMenuArray($GLOBALS['TSFE']->sys_page->getMenu($GLOBALS['TSFE']->id));
333                 foreach ($menu as $data) {
334                         $preSign = count($this->cleanMenuArray($GLOBALS['TSFE']->sys_page->getMenu($data['uid']))) ? '+' : '*';
335                         $menuItem = htmlspecialchars($preSign.' '.$data['title']);
336                         $menuItem = $this->link($preSpace . $menuItem, $data['uid']);
337                         $out[] = $indent.$this->line($menuItem);
338                 }
339                 return $this->paragraph(implode(chr(10), $out));
340         }
341
342         /**
343          * Creates a link around the input string to another page/deck
344          * Used to create menus
345          *
346          * @param string $str The string to be wrapped in <a> tags
347          * @param integer $id The page id to link to
348          * @param string $deck The deck name, if any
349          * @return string String wrapped in <a> tags
350          * @see menuCurrentLevel()
351          */
352         function link($str, $id, $deck = '') {
353                 if ($GLOBALS['TSFE']->id==$id && $deck) {
354                         $out = '<a href="#'.$deck.'">'.$str.'</a>';
355                 } else {
356                         $type = $GLOBALS['TSFE']->type;
357                         $out = '<a href="'.htmlspecialchars('?id='.$id.','.($GLOBALS['TSFE']->id==$id?1:$this->idx).'.'.$type).'">'.$str.'</a>';
358                 }
359                 return $out;
360         }
361
362         /**
363          * Cleaning up the menu array returned from sys_page->getMenu().
364          * Removing pages having "not in menu" set.
365          *
366          * @param array $menu Menu item array
367          * @return array New menu item array with "not in menu" elements removed.
368          */
369         function cleanMenuArray($menu) {
370                 reset($menu);
371                 $newMenu=array();
372                 while (list(, $data) = each($menu)) {
373                         if (!$data['nav_hide']) {
374                                 $newMenu[] = $data;
375                         }
376                 }
377                 return $newMenu;
378         }
379 }
380 ?>