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