]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - lib/action.php
Move page-generation code from lib/util.php to Action class
[quix0rs-gnu-social.git] / lib / action.php
1 <?php
2 /**
3  * Laconica, the distributed open-source microblogging tool
4  *
5  * Base class for all actions (~views)
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  Action
23  * @package   Laconica
24  * @author    Evan Prodromou <evan@controlyourself.ca>
25  * @author    Sarven Capadisli <csarven@controlyourself.ca>
26  * @copyright 2008 Control Yourself, Inc.
27  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
28  * @link      http://laconi.ca/
29  */
30
31 if (!defined('LACONICA')) {
32     exit(1);
33 }
34
35 /**
36  * Base class for all actions
37  *
38  * This is the base class for all actions in the package. An action is
39  * more or less a "view" in an MVC framework.
40  *
41  * Actions are responsible for extracting and validating parameters; using
42  * model classes to read and write to the database; and doing ouput.
43  *
44  * @category Output
45  * @package  Laconica
46  * @author   Evan Prodromou <evan@controlyourself.ca>
47  * @author   Sarven Capadisli <csarven@controlyourself.ca>
48  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
49  * @link     http://laconi.ca/
50  *
51  * @see      HTMLOutputter
52  */
53
54 class Action extends HTMLOutputter // lawsuit
55 {
56     var $args;
57
58     function Action()
59     {
60     }
61
62     // For initializing members of the class
63
64     function prepare($argarray)
65     {
66         $this->args =& common_copy_args($argarray);
67         return true;
68     }
69
70     function showPage()
71     {
72         $this->startHTML();
73         $this->showHead();
74         $this->showBody();
75         $this->endHTML();
76     }
77
78     function showHead()
79     {
80         // XXX: attributes (profile?)
81         $this->startElement('head');
82         $this->showTitle();
83         $this->showStylesheets();
84         $this->showScripts();
85         $this->showOpenSearch();
86         $this->showFeeds();
87         $this->showDescription();
88         $this->extraHead();
89         $this->elementElement('head');
90     }
91
92     function showTitle()
93     {
94         $this->element('title', null,
95                        sprintf(_("%s - %s"),
96                                $this->title(),
97                                common_config('site', 'name')));
98     }
99
100     // SHOULD overload
101
102     function title()
103     {
104         return _("Untitled page");
105     }
106
107     function showStylesheets()
108     {
109         common_element('link', array('rel' => 'stylesheet',
110                                      'type' => 'text/css',
111                                      'href' => theme_path('display.css') . '?version=' . LACONICA_VERSION,
112                                      'media' => 'screen, projection, tv'));
113         foreach (array(6,7) as $ver) {
114             if (file_exists(theme_file('ie'.$ver.'.css'))) {
115                 // Yes, IE people should be put in jail.
116                 $xw->writeComment('[if lte IE '.$ver.']><link rel="stylesheet" type="text/css" '.
117                                   'href="'.theme_path('ie'.$ver.'.css').'?version='.LACONICA_VERSION.'" /><![endif]');
118             }
119         }
120     }
121
122     function showScripts()
123     {
124         common_element('script', array('type' => 'text/javascript',
125                                        'src' => common_path('js/jquery.min.js')),
126                        ' ');
127         common_element('script', array('type' => 'text/javascript',
128                                        'src' => common_path('js/jquery.form.js')),
129                        ' ');
130         common_element('script', array('type' => 'text/javascript',
131                                        'src' => common_path('js/xbImportNode.js')),
132                        ' ');
133         common_element('script', array('type' => 'text/javascript',
134                                        'src' => common_path('js/util.js?version='.LACONICA_VERSION)),
135                        ' ');
136     }
137
138     function showOpenSearch()
139     {
140         common_element('link', array('rel' => 'search', 'type' => 'application/opensearchdescription+xml',
141                                      'href' =>  common_local_url('opensearch', array('type' => 'people')),
142                                      'title' => common_config('site', 'name').' People Search'));
143
144         common_element('link', array('rel' => 'search', 'type' => 'application/opensearchdescription+xml',
145                                      'href' =>  common_local_url('opensearch', array('type' => 'notice')),
146                                      'title' => common_config('site', 'name').' Notice Search'));
147     }
148
149     // MAY overload
150
151     function showFeeds()
152     {
153         // does nothing by default
154     }
155
156     // SHOULD overload
157
158     function showDescription()
159     {
160         // does nothing by default
161     }
162
163     // MAY overload
164
165     function extraHead()
166     {
167         // does nothing by default
168     }
169
170     function showBody()
171     {
172         // output body
173         // output wrap element
174         $this->showHeader();
175         $this->showCore();
176         $this->showFooter();
177     }
178
179     function showHeader()
180     {
181         // start header div stuff
182         $this->showLogo();
183         $this->showPrimaryNav();
184         $this->showSiteNotice();
185         $this->showNoticeForm();
186         // end header div stuff
187     }
188
189     function showLogo()
190     {
191         // show the logo here
192     }
193
194     function showPrimaryNav()
195     {
196         $user = common_current_user();
197         common_element_start('ul', array('id' => 'nav'));
198         if ($user) {
199             common_menu_item(common_local_url('all', array('nickname' => $user->nickname)),
200                              _('Home'));
201         }
202         common_menu_item(common_local_url('peoplesearch'), _('Search'));
203         if ($user) {
204             common_menu_item(common_local_url('profilesettings'),
205                              _('Settings'));
206             common_menu_item(common_local_url('invite'),
207                              _('Invite'));
208             common_menu_item(common_local_url('logout'),
209                              _('Logout'));
210         } else {
211             common_menu_item(common_local_url('login'), _('Login'));
212             if (!common_config('site', 'closed')) {
213                 common_menu_item(common_local_url('register'), _('Register'));
214             }
215             common_menu_item(common_local_url('openidlogin'), _('OpenID'));
216         }
217         common_menu_item(common_local_url('doc', array('title' => 'help')),
218                          _('Help'));
219         common_element_end('ul');
220     }
221
222     function showSiteNotice()
223     {
224         // show the site notice here
225     }
226
227     // MAY overload if no notice form needed... or direct message box????
228
229     function showNoticeForm()
230     {
231         // show the notice form here
232     }
233
234     function showCore()
235     {
236         // start core div
237         $this->showLocalNav();
238         $this->showContentBlock();
239         $this->showAside();
240         // end core div
241     }
242
243     // SHOULD overload
244
245     function showLocalNav()
246     {
247     }
248
249     function showContentBlock()
250     {
251         $this->showPageTitle();
252         $this->showPageNotice();
253         $this->showContent();
254     }
255
256     function showPageTitle() {
257         $this->element('h1', NULL, $this->title());
258     }
259
260     // SHOULD overload (unless there's not a notice)
261
262     function showPageNotice()
263     {
264         // output page notice div
265     }
266
267     // MUST overload
268
269     function showContent()
270     {
271         // show the actual content (forms, lists, whatever)
272     }
273
274     function showAside()
275     {
276         $this->showExportData();
277         $this->showSections();
278     }
279
280     // MAY overload if there are feeds
281
282     function showExportData()
283     {
284         // is there structure to this?
285         // list of (visible!) feed links
286         // can we reuse list of feeds from showFeeds() ?
287     }
288
289     // SHOULD overload
290
291     function showSections() {
292         // for each section, show it
293     }
294
295     function showFooter()
296     {
297         // start footer div
298         $this->showSecondaryNav();
299         $this->showLicenses();
300     }
301
302     function showSecondaryNav()
303     {
304         common_element_start('ul', array('id' => 'nav_sub'));
305         common_menu_item(common_local_url('doc', array('title' => 'help')),
306                          _('Help'));
307         common_menu_item(common_local_url('doc', array('title' => 'about')),
308                          _('About'));
309         common_menu_item(common_local_url('doc', array('title' => 'faq')),
310                          _('FAQ'));
311         common_menu_item(common_local_url('doc', array('title' => 'privacy')),
312                          _('Privacy'));
313         common_menu_item(common_local_url('doc', array('title' => 'source')),
314                          _('Source'));
315         common_menu_item(common_local_url('doc', array('title' => 'contact')),
316                          _('Contact'));
317         common_element_end('ul');
318     }
319
320     function showLicenses()
321     {
322         // start license dl
323         $this->showLaconicaLicense();
324         $this->showContentLicense();
325         // end license dl
326     }
327
328     function showLaconicaLicense()
329     {
330         common_element_start('div', 'laconica');
331         if (common_config('site', 'broughtby')) {
332             $instr = _('**%%site.name%%** is a microblogging service brought to you by [%%site.broughtby%%](%%site.broughtbyurl%%). ');
333         } else {
334             $instr = _('**%%site.name%%** is a microblogging service. ');
335         }
336         $instr .= sprintf(_('It runs the [Laconica](http://laconi.ca/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html).'), LACONICA_VERSION);
337         $output = common_markup_to_html($instr);
338         common_raw($output);
339         common_element_end('div');
340         // do it
341     }
342
343     function showContentLicense()
344     {
345         common_element_start('div', array('id' => 'footer'));
346         common_element('img', array('id' => 'cc',
347                                     'src' => $config['license']['image'],
348                                     'alt' => $config['license']['title']));
349         common_element_start('p');
350         common_text(_('Unless otherwise specified, contents of this site are copyright by the contributors and available under the '));
351         common_element('a', array('class' => 'license',
352                                   'rel' => 'license',
353                                   'href' => $config['license']['url']),
354                        $config['license']['title']);
355         common_text(_('. Contributors should be attributed by full name or nickname.'));
356         common_element_end('p');
357         common_element_end('div');
358     }
359
360     // For comparison with If-Last-Modified
361     // If not applicable, return null
362
363     function last_modified()
364     {
365         return null;
366     }
367
368     function etag()
369     {
370         return null;
371     }
372
373     function is_readonly()
374     {
375         return false;
376     }
377
378     function arg($key, $def=null)
379     {
380         if (array_key_exists($key, $this->args)) {
381             return $this->args[$key];
382         } else {
383             return $def;
384         }
385     }
386
387     function trimmed($key, $def=null)
388     {
389         $arg = $this->arg($key, $def);
390         return (is_string($arg)) ? trim($arg) : $arg;
391     }
392
393     // Note: argarray ignored, since it's now passed in in prepare()
394
395     function handle($argarray=null)
396     {
397
398         $lm = $this->last_modified();
399         $etag = $this->etag();
400
401         if ($etag) {
402             header('ETag: ' . $etag);
403         }
404
405         if ($lm) {
406             header('Last-Modified: ' . date(DATE_RFC1123, $lm));
407             $if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
408             if ($if_modified_since) {
409                 $ims = strtotime($if_modified_since);
410                 if ($lm <= $ims) {
411                     if (!$etag ||
412                         $this->_has_etag($etag, $_SERVER['HTTP_IF_NONE_MATCH'])) {
413                         header('HTTP/1.1 304 Not Modified');
414                         // Better way to do this?
415                         exit(0);
416                     }
417                 }
418             }
419         }
420     }
421
422     function _has_etag($etag, $if_none_match)
423     {
424         return ($if_none_match) && in_array($etag, explode(',', $if_none_match));
425     }
426
427     function boolean($key, $def=false)
428     {
429         $arg = strtolower($this->trimmed($key));
430
431         if (is_null($arg)) {
432             return $def;
433         } else if (in_array($arg, array('true', 'yes', '1'))) {
434             return true;
435         } else if (in_array($arg, array('false', 'no', '0'))) {
436             return false;
437         } else {
438             return $def;
439         }
440     }
441
442     function server_error($msg, $code=500)
443     {
444         $action = $this->trimmed('action');
445         common_debug("Server error '$code' on '$action': $msg", __FILE__);
446         common_server_error($msg, $code);
447     }
448
449     function client_error($msg, $code=400)
450     {
451         $action = $this->trimmed('action');
452         common_debug("User error '$code' on '$action': $msg", __FILE__);
453         common_user_error($msg, $code);
454     }
455
456     function self_url()
457     {
458         $action = $this->trimmed('action');
459         $args = $this->args;
460         unset($args['action']);
461         foreach (array_keys($_COOKIE) as $cookie) {
462             unset($args[$cookie]);
463         }
464         return common_local_url($action, $args);
465     }
466
467     function nav_menu($menu)
468     {
469         $action = $this->trimmed('action');
470         common_element_start('ul', array('id' => 'nav_views'));
471         foreach ($menu as $menuaction => $menudesc) {
472             common_menu_item(common_local_url($menuaction,
473                                               isset($menudesc[2]) ? $menudesc[2] : null),
474                              $menudesc[0],
475                              $menudesc[1],
476                              $action == $menuaction);
477         }
478         common_element_end('ul');
479     }
480
481     function common_show_header($pagetitle, $callable=null, $data=null, $headercall=null)
482     {
483         global $config, $xw;
484         global $action; /* XXX: kind of cheating here. */
485
486         common_start_html();
487
488         common_element_start('head');
489
490         if ($callable) {
491             if ($data) {
492                 call_user_func($callable, $data);
493             } else {
494                 call_user_func($callable);
495             }
496         }
497         common_element_end('head');
498         common_element_start('body', $action);
499         common_element_start('div', array('id' => 'wrap'));
500         common_element_start('div', array('id' => 'header'));
501         common_nav_menu();
502         if ((isset($config['site']['logo']) && is_string($config['site']['logo']) && (strlen($config['site']['logo']) > 0))
503             || file_exists(theme_file('logo.png')))
504         {
505             common_element_start('a', array('href' => common_local_url('public')));
506             common_element('img', array('src' => isset($config['site']['logo']) ?
507                                         ($config['site']['logo']) : theme_path('logo.png'),
508                                         'alt' => $config['site']['name'],
509                                         'id' => 'logo'));
510             common_element_end('a');
511         } else {
512             common_element_start('p', array('id' => 'branding'));
513             common_element('a', array('href' => common_local_url('public')),
514                            $config['site']['name']);
515             common_element_end('p');
516         }
517
518         common_element('h1', 'pagetitle', $pagetitle);
519
520         if ($headercall) {
521             if ($data) {
522                 call_user_func($headercall, $data);
523             } else {
524                 call_user_func($headercall);
525             }
526         }
527         common_element_end('div');
528         common_element_start('div', array('id' => 'content'));
529     }
530
531     function common_show_footer()
532     {
533         global $xw, $config;
534         common_element_end('div'); // content div
535         common_foot_menu();
536         common_element_end('div');
537         common_element_end('body');
538         common_element_end('html');
539         common_end_xml();
540     }
541
542     function common_menu_item($url, $text, $title=null, $is_selected=false)
543     {
544         $lattrs = array();
545         if ($is_selected) {
546             $lattrs['class'] = 'current';
547         }
548         common_element_start('li', $lattrs);
549         $attrs['href'] = $url;
550         if ($title) {
551             $attrs['title'] = $title;
552         }
553         common_element('a', $attrs, $text);
554         common_element_end('li');
555     }
556 }