[TASK] Remove last XCLASS statements
[Packages/TYPO3.CMS.git] / typo3 / sysext / statictemplates / 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  * Contains 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         var $cObj;              // The backReference to the mother cObj object set at call time
76
77         var $idx=0;
78
79         /**
80          * Main function, called from TypoScript
81          *
82          * @param       string          Empty, ignore.
83          * @param       array           TypoScript properties for this content object/function call
84          * @return      string          WML content
85          */
86         function main_wapversion($content, $conf) {
87                 $GLOBALS['TSFE']->set_no_cache();
88
89                 $xmlObj = t3lib_div::makeInstance('t3lib_xml', 'wml');
90                 $xmlObj->XMLdebug=$conf['debug'];
91
92                         // Creating top level object
93                 $xmlObj->WAPHeader();
94
95                         // Creating back button:
96                 $xmlObj->WAPback();
97
98                 $pageRec = $GLOBALS['TSFE']->page;
99                 if ($GLOBALS['TSFE']->idParts[1]) {
100                                 // Creating content card:
101                         $xmlObj->newLevel('card', 1, array(
102                                 'id' => 'content',
103                                 'title' => ($conf['preTitle'] ? $conf['preTitle'] . ': ' : '') . $pageRec['title']
104                         ));
105
106                         $cParts = $this->contentAll();
107                         $pointer = t3lib_utility_Math::forceIntegerInRange($GLOBALS['TSFE']->idParts[1], 1, 10000);
108
109                         $msg = '';
110                         if ($pointer - 1) {
111                                 $msg .= $this->navLink(htmlspecialchars($conf['navLabels.']['prev']), $pointer - 1) . ' ';
112                         }
113                         $msg .= $this->navLink(htmlspecialchars($conf['navLabels.']['up']), 0) . ' ';
114                         if ($pointer<count($cParts)) {
115                                 $msg .= $this->navLink(htmlspecialchars($conf['navLabels.']['next']), $pointer + 1) . ' ';
116                         }
117                         $msg.= '['.$pointer.'/'.count($cParts).']<br/>';
118
119                         $xmlObj->lines[] = $this->paragraph($msg);
120                         $xmlObj->lines[] = $this->paragraph($cParts[$pointer-1]);
121                         $xmlObj->lines[] = $this->paragraph('<br/>'.$msg);
122
123                         $xmlObj->newLevel('card', 0);
124                 } else {
125                                 // Creating menu card:
126                         $xmlObj->newLevel('card', 1, array(
127                                 'id' => 'menu',
128                                 'title' => ($conf['preTitle'] ? $conf['preTitle'] . ': ' : '') . $pageRec['title']
129                         ));
130                         $xmlObj->lines[] = $this->contentAbstract();
131                         $xmlObj->lines[] = '<p><br/>'.$this->bold('Menu:').'</p>';
132                         $xmlObj->lines[] = $this->menuCurrentLevel($xmlObj->Icode);
133                         $xmlObj->newLevel('card', 0);
134                 }
135
136                         // Footer
137                 $xmlObj->renderFooter();
138                 return $xmlObj->getResult();
139
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                 $out.= 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         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          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          The bodytext content
233          * @param       integer         Position where to start in the bodytext stream. If larger than zero a prefix, "...", is prepended.
234          * @param       integer         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          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          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          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          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          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          The link text
306          * @param       integer         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          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          The string to be wrapped in <a> tags
347          * @param       integer         The page id to link to
348          * @param       string          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(). Removing page types with doktype "5" (not in menu)
364          *
365          * @param       array           Menu item array
366          * @return      array           New menu item array with doktype-5 elements removed.
367          */
368         function cleanMenuArray($menu) {
369                 $newMenu=array();
370                 foreach ($menu as $data) {
371                         if (!$data['nav_hide']) {
372                                 $newMenu[]=$data;
373                         }
374                 }
375                 return $newMenu;
376         }
377 }
378 ?>