]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/MobileProfile/MobileProfilePlugin.php
MobileProfile plugin cleanup
[quix0rs-gnu-social.git] / plugins / MobileProfile / MobileProfilePlugin.php
1 <?php
2 /**
3  * StatusNet, the distributed open-source microblogging tool
4  *
5  * XHTML Mobile Profile plugin that uses WAP 2.0 Plugin
6  *
7  * PHP version 5
8  *
9  * LICENCE: This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU Affero General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Affero General Public License for more details.
18  *
19  * You should have received a copy of the GNU Affero General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * @category  Plugin
23  * @package   StatusNet
24  * @author    Sarven Capadisli <csarven@status.net>
25  * @copyright 2009 StatusNet, Inc.
26  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
27  * @link      http://status.net/
28  */
29
30 if (!defined('GNUSOCIAL')) { exit(1); }
31
32 define('PAGE_TYPE_PREFS_MOBILEPROFILE',
33        'application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html;q=0.9');
34
35 require_once INSTALLDIR.'/plugins/Mobile/WAP20Plugin.php';
36
37 /**
38  * Superclass for plugin to output XHTML Mobile Profile
39  *
40  * @category Plugin
41  * @package  StatusNet
42  * @author   Sarven Capadisli <csarven@status.net>
43  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
44  * @link     http://status.net/
45  */
46 class MobileProfilePlugin extends WAP20Plugin
47 {
48     public $DTD            = null;
49     public $serveMobile    = false;
50     public $reallyMobile   = false;
51     public $mobileFeatures = array();
52
53     function __construct($DTD='http://www.wapforum.org/DTD/xhtml-mobile10.dtd')
54     {
55         $this->DTD = $DTD;
56
57         parent::__construct();
58     }
59
60     public function onStartShowHTML(Action $action)
61     {
62         // TODO: A lot of this should probably graduate to WAP20Plugin
63
64         $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : null;
65
66         $cp = common_accept_to_prefs($httpaccept);
67         $sp = common_accept_to_prefs(PAGE_TYPE_PREFS_MOBILEPROFILE);
68
69         $type = common_negotiate_type($cp, $sp);
70
71         if (!$type) {
72             // TRANS: Client exception thrown when requesting a not supported media type.
73             throw new ClientException(_m('This page is not available in a '.
74                                         'media type you accept.'), 406);
75         }
76
77         // If they are on the mobile site, serve them MP
78         if ((common_config('site', 'mobileserver').'/'.common_config('site', 'path').'/'
79                 == $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'])) {
80             $this->serveMobile = true;
81         } elseif (isset($_COOKIE['MobileOverride'])) {
82             // Cookie override is controlled by link at bottom.
83             $this->serveMobile = (bool)$_COOKIE['MobileOverride'];
84         } elseif (strstr('application/vnd.wap.xhtml+xml', $type) !== false) {
85             // If they like the WAP 2.0 mimetype, serve them MP
86             $this->serveMobile = true;
87         } elseif (array_key_exists('HTTP_USER_AGENT', $_SERVER)) {
88             // If they are a mobile device that supports WAP 2.0,
89             // serve them MP
90
91             // XXX: Browser sniffing sucks
92
93             // I really don't like going through this every page,
94             // perhaps use $_SESSION or cookies
95
96             // May be better to group the devices in terms of
97             // low,mid,high-end
98
99             // Or, detect the mobile devices based on their support for
100             // MP 1.0, 1.1, or 1.2 may be ideal. Possible?
101
102             $this->mobiledevices = array(
103                 'alcatel',
104                 'android',
105                 'audiovox',
106                 'au-mic,',
107                 'avantgo',
108                 'blackberry',
109                 'blazer',
110                 'cldc-',
111                 'danger',
112                 'epoc',
113                 'ericsson',
114                 'ericy',
115                 'iphone',
116                 'ipaq',
117                 'ipod',
118                 'j2me',
119                 'lg',
120                 'maemo',
121                 'midp-',
122                 'mobile',
123                 'mot',
124                 'netfront',
125                 'nitro',
126                 'nokia',
127                 'opera mini',
128                 'palm',
129                 'palmsource',
130                 'panasonic',
131                 'philips',
132                 'pocketpc',
133                 'portalmmm',
134                 'rover',
135                 'samsung',
136                 'sanyo',
137                 'series60',
138                 'sharp',
139                 'sie-',
140                 'smartphone',
141                 'sony',
142                 'symbian',
143                 'up.browser',
144                 'up.link',
145                 'up.link',
146                 'vodafone',
147                 'wap1',
148                 'wap2',
149                 'webos',
150                 'windows ce'
151             );
152
153             $blacklist = array(
154                 'ipad', // Larger screen handles the full theme fairly well.
155             );
156
157             $httpuseragent = strtolower($_SERVER['HTTP_USER_AGENT']);
158
159             foreach ($blacklist as $md) {
160                 if (strstr($httpuseragent, $md) !== false) {
161                     $this->serveMobile = false;
162                     return true;
163                 }
164             }
165
166             foreach ($this->mobiledevices as $md) {
167                 if (strstr($httpuseragent, $md) !== false) {
168                     $this->setMobileFeatures($httpuseragent);
169
170                     $this->serveMobile = true;
171                     $this->reallyMobile = true;
172                     break;
173                 }
174             }
175         }
176
177         if (!$this->serveMobile) {
178             return true;
179         }
180
181         // If they are okay with MP, and the site has a mobile server,
182         // redirect there
183         if (common_config('site', 'mobileserver') !== false &&
184                 common_config('site', 'mobileserver') != common_config('site', 'server')) {
185
186             // FIXME: Redirect to equivalent page on mobile site instead
187             common_redirect($this->_common_path(''), 302);
188         }
189
190         header('Content-Type: '.$type);
191
192         if ($this->reallyMobile) {
193            $action->setDTD('html', '-//WAPFORUM//DTD XHTML Mobile 1.0//EN', $this->DTD);
194         }
195
196         // continue
197         return true;
198     }
199
200     function setMobileFeatures($useragent)
201     {
202         $mobiledeviceInputFileType = array(
203             'nokia'
204         );
205
206         $this->mobileFeatures['inputfiletype'] = false;
207
208         foreach ($mobiledeviceInputFileType as $md) {
209             if (strstr($useragent, $md) !== false) {
210                 $this->mobileFeatures['inputfiletype'] = true;
211                 break;
212             }
213         }
214     }
215
216     public function onStartShowStylesheets(Action $action)
217     {
218         if (!$this->serveMobile) {
219             return true;
220         }
221
222         $action->primaryCssLink();
223
224         $action->cssLink($this->path('mp-screen.css'),null,'screen');
225         if (file_exists(Theme::file('css/mp-screen.css'))) {
226             $action->cssLink('css/mp-screen.css', null, 'screen');
227         }
228
229         $action->cssLink($this->path('mp-handheld.css'),null,'handheld');
230         if (file_exists(Theme::file('css/mp-handheld.css'))) {
231             $action->cssLink('css/mp-handheld.css', null, 'handheld');
232         }
233
234         // Allow other plugins to load their styles.
235         Event::handle('EndShowStylesheets', array($action));
236
237         return false;
238     }
239
240     public function onStartShowUAStyles(Action $action) {
241         if (!$this->serveMobile) {
242             return true;
243         }
244
245         return false;
246     }
247
248     public function onStartShowHeader(Action $action)
249     {
250         if (!$this->serveMobile) {
251             return true;
252         }
253
254         $action->elementStart('div', array('id' => 'header'));
255         $this->_showLogo($action);
256         $action->showPrimaryNav();
257         $action->elementEnd('div');
258
259         return false;
260     }
261
262     protected function _showLogo(Action $action)
263     {
264         $action->elementStart('address');
265         if (common_config('singleuser', 'enabled')) {
266             $user = User::singleUser();
267             $url = common_local_url('showstream', array('nickname' => $user->getNickname()));
268         } else {
269             $url = common_local_url('public');
270         }
271
272         $action->elementStart('a', array('class' => 'h-card home bookmark',
273                                          'href' => $url));
274
275         if (common_config('site', 'mobilelogo') ||
276             file_exists(Theme::file('logo.png')) ||
277             file_exists(Theme::file('mobilelogo.png'))) {
278
279             $action->element('img', array('class' => 'u-photo',
280                 'src' => (common_config('site', 'mobilelogo')) ? common_config('site', 'mobilelogo') :
281                             ((file_exists(Theme::file('mobilelogo.png'))) ? (Theme::path('mobilelogo.png')) : Theme::path('logo.png')),
282                 'alt' => common_config('site', 'name')));
283         }
284         $action->elementEnd('a');
285         $action->elementEnd('address');
286     }
287
288     public function onStartShowAside(Action $action)
289     {
290         if ($this->serveMobile) {
291             return false;
292         }
293     }
294
295     public function onStartShowLocalNavBlock(Action $action)
296     {
297         if ($this->serveMobile) {
298             // @todo FIXME: "Show Navigation" / "Hide Navigation" needs i18n
299             $action->element('a', array('href' => '#', 'id' => 'navtoggle'), 'Show Navigation');
300         }
301     }
302
303     public function onEndShowScripts(Action $action)
304     {
305         // @todo FIXME: "Show Navigation" / "Hide Navigation" needs i18n
306         $action->inlineScript('
307             $(function() {
308                 $("#mobile-toggle-disable").click(function() {
309                     $.cookie("MobileOverride", "0", {path: "/"});
310                     window.location.reload();
311                     return false;
312                 });
313                 $("#mobile-toggle-enable").click(function() {
314                     $.cookie("MobileOverride", "1", {path: "/"});
315                     window.location.reload();
316                     return false;
317                 });
318                 $("#navtoggle").click(function () {
319                           $("#site_nav_local_views").fadeToggle();
320                           var text = $("#navtoggle").text();
321                           $("#navtoggle").text(
322                           text == "Show Navigation" ? "Hide Navigation" : "Show Navigation");
323                 });
324             });'
325         );
326
327         if ($this->serveMobile) {
328             $action->inlineScript('$(function() { $(".checkbox-wrapper").unbind("click"); });');
329         }
330     }
331
332
333     public function onEndShowInsideFooter(Action $action)
334     {
335         if ($this->serveMobile) {
336             // TRANS: Link to switch site layout from mobile to desktop mode. Appears at very bottom of page.
337             $linkText = _m('Switch to desktop site layout.');
338             $key = 'mobile-toggle-disable';
339         } else {
340             // TRANS: Link to switch site layout from desktop to mobile mode. Appears at very bottom of page.
341             $linkText = _m('Switch to mobile site layout.');
342             $key = 'mobile-toggle-enable';
343         }
344         $action->elementStart('p');
345         $action->element('a', array('href' => '#', 'id' => $key), $linkText);
346         $action->elementEnd('p');
347         return true;
348     }
349
350     function _common_path($relative, $ssl=false)
351     {
352         $pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : '';
353
354         if (($ssl && (common_config('site', 'ssl') === 'sometimes'))
355             || common_config('site', 'ssl') === 'always') {
356             $proto = 'https';
357             if (is_string(common_config('site', 'sslserver')) &&
358                 mb_strlen(common_config('site', 'sslserver')) > 0) {
359                 $serverpart = common_config('site', 'sslserver');
360             } else {
361                 $serverpart = common_config('site', 'mobileserver');
362             }
363         } else {
364             $proto      = 'http';
365             $serverpart = common_config('site', 'mobileserver');
366         }
367
368         return $proto.'://'.$serverpart.'/'.$pathpart.$relative;
369     }
370
371     function onPluginVersion(&$versions)
372     {
373         $versions[] = array('name' => 'MobileProfile',
374                             'version' => GNUSOCIAL_VERSION,
375                             'author' => 'Sarven Capadisli',
376                             'homepage' => 'http://status.net/wiki/Plugin:MobileProfile',
377                             'rawdescription' =>
378                             // TRANS: Plugin description.
379                             _m('XHTML MobileProfile output for supporting user agents.'));
380         return true;
381     }
382 }