]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - lib/action.php
Merge branch 'atompub' into 0.9.x
[quix0rs-gnu-social.git] / lib / action.php
index 98e5ec2c94e7d89bb0d7472d4d2e0d423ee075f6..17d3e2311aa9a81f945572a638c48ad0b603ad23 100644 (file)
@@ -121,7 +121,10 @@ class Action extends HTMLOutputter // lawsuit
         // XXX: attributes (profile?)
         $this->elementStart('head');
         if (Event::handle('StartShowHeadElements', array($this))) {
-            $this->showTitle();
+            if (Event::handle('StartShowHeadTitle', array($this))) {
+                $this->showTitle();
+                Event::handle('EndShowHeadTitle', array($this));
+            }
             $this->showShortcutIcon();
             $this->showStylesheets();
             $this->showOpenSearch();
@@ -172,8 +175,9 @@ class Action extends HTMLOutputter // lawsuit
             $this->element('link', array('rel' => 'shortcut icon',
                                          'href' => Theme::path('favicon.ico')));
         } else {
+            // favicon.ico should be HTTPS if the rest of the page is
             $this->element('link', array('rel' => 'shortcut icon',
-                                         'href' => common_path('favicon.ico')));
+                                         'href' => common_path('favicon.ico', StatusNet::isHTTPS())));
         }
 
         if (common_config('site', 'mobile')) {
@@ -200,7 +204,7 @@ class Action extends HTMLOutputter // lawsuit
 
             if (Event::handle('StartShowStatusNetStyles', array($this)) &&
                 Event::handle('StartShowLaconicaStyles', array($this))) {
-                $this->cssLink('css/display.css',null, 'screen, projection, tv, print');
+                $this->primaryCssLink(null, 'screen, projection, tv, print');
                 Event::handle('EndShowStatusNetStyles', array($this));
                 Event::handle('EndShowLaconicaStyles', array($this));
             }
@@ -235,7 +239,29 @@ class Action extends HTMLOutputter // lawsuit
                 Event::handle('EndShowDesign', array($this));
             }
             Event::handle('EndShowStyles', array($this));
+
+            if (common_config('custom_css', 'enabled')) {
+                $css = common_config('custom_css', 'css');
+                if (Event::handle('StartShowCustomCss', array($this, &$css))) {
+                    if (trim($css) != '') {
+                        $this->style($css);
+                    }
+                    Event::handle('EndShowCustomCss', array($this));
+                }
+            }
+        }
+    }
+
+    function primaryCssLink($mainTheme=null, $media=null)
+    {
+        // If the currently-selected theme has dependencies on other themes,
+        // we'll need to load their display.css files as well in order.
+        $theme = new Theme($mainTheme);
+        $baseThemes = $theme->getDeps();
+        foreach ($baseThemes as $baseTheme) {
+            $this->cssLink('css/display.css', $baseTheme, $media);
         }
+        $this->cssLink('css/display.css', $mainTheme, $media);
     }
 
     /**
@@ -256,9 +282,8 @@ class Action extends HTMLOutputter // lawsuit
             }
             if (Event::handle('StartShowStatusNetScripts', array($this)) &&
                 Event::handle('StartShowLaconicaScripts', array($this))) {
-                $this->script('xbImportNode.js');
                 $this->script('util.js');
-                $this->script('geometa.js');
+                $this->showScriptMessages();
                 // Frame-busting code to avoid clickjacking attacks.
                 $this->inlineScript('if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
                 Event::handle('EndShowStatusNetScripts', array($this));
@@ -268,6 +293,54 @@ class Action extends HTMLOutputter // lawsuit
         }
     }
 
+    /**
+     * Exports a map of localized text strings to JavaScript code.
+     *
+     * Plugins can add to what's exported by hooking the StartScriptMessages or EndScriptMessages
+     * events and appending to the array. Try to avoid adding strings that won't be used, as
+     * they'll be added to HTML output.
+     */
+    function showScriptMessages()
+    {
+        $messages = array();
+        if (Event::handle('StartScriptMessages', array($this, &$messages))) {
+            // Common messages needed for timeline views etc...
+
+            // TRANS: Localized tooltip for '...' expansion button on overlong remote messages.
+            $messages['showmore_tooltip'] = _m('TOOLTIP', 'Show more');
+
+            $messages = array_merge($messages, $this->getScriptMessages());
+        }
+        Event::handle('EndScriptMessages', array($this, &$messages));
+        if ($messages) {
+            $this->inlineScript('SN.messages=' . json_encode($messages));
+        }
+        return $messages;
+    }
+
+    /**
+     * If the action will need localizable text strings, export them here like so:
+     *
+     * return array('pool_deepend' => _('Deep end'),
+     *              'pool_shallow' => _('Shallow end'));
+     *
+     * The exported map will be available via SN.msg() to JS code:
+     *
+     *   $('#pool').html('<div class="deepend"></div><div class="shallow"></div>');
+     *   $('#pool .deepend').text(SN.msg('pool_deepend'));
+     *   $('#pool .shallow').text(SN.msg('pool_shallow'));
+     *
+     * Exports a map of localized text strings to JavaScript code.
+     *
+     * Plugins can add to what's exported on any action by hooking the StartScriptMessages or
+     * EndScriptMessages events and appending to the array. Try to avoid adding strings that won't
+     * be used, as they'll be added to HTML output.
+     */
+    function getScriptMessages()
+    {
+        return array();
+    }
+
     /**
      * Show OpenSearch headers
      *
@@ -291,7 +364,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return nothing
      */
-
     function showFeeds()
     {
         $feeds = $this->getFeeds();
@@ -339,9 +411,9 @@ class Action extends HTMLOutputter // lawsuit
      */
     function showBody()
     {
-        $this->elementStart('body', (common_current_user()) ? array('id' => $this->trimmed('action'),
+        $this->elementStart('body', (common_current_user()) ? array('id' => strtolower($this->trimmed('action')),
                                                                     'class' => 'user_in')
-                            : array('id' => $this->trimmed('action')));
+                            : array('id' => strtolower($this->trimmed('action'))));
         $this->elementStart('div', array('id' => 'wrap'));
         if (Event::handle('StartShowHeader', array($this))) {
             $this->showHeader();
@@ -375,7 +447,10 @@ class Action extends HTMLOutputter // lawsuit
             Event::handle('EndShowSiteNotice', array($this));
         }
         if (common_logged_in()) {
-            $this->showNoticeForm();
+            if (Event::handle('StartShowNoticeForm', array($this))) {
+                $this->showNoticeForm();
+                Event::handle('EndShowNoticeForm', array($this));
+            }
         } else {
             $this->showAnonymousMessage();
         }
@@ -393,18 +468,43 @@ class Action extends HTMLOutputter // lawsuit
                                              'class' => 'vcard'));
         if (Event::handle('StartAddressData', array($this))) {
             if (common_config('singleuser', 'enabled')) {
+                $user = User::singleUser();
                 $url = common_local_url('showstream',
-                                        array('nickname' => common_config('singleuser', 'nickname')));
+                                        array('nickname' => $user->nickname));
             } else {
                 $url = common_local_url('public');
             }
             $this->elementStart('a', array('class' => 'url home bookmark',
                                            'href' => $url));
-            if (common_config('site', 'logo') || file_exists(Theme::file('logo.png'))) {
+
+            if (StatusNet::isHTTPS()) {
+                $logoUrl = common_config('site', 'ssllogo');
+                if (empty($logoUrl)) {
+                    // if logo is an uploaded file, try to fall back to HTTPS file URL
+                    $httpUrl = common_config('site', 'logo');
+                    if (!empty($httpUrl)) {
+                        $f = File::staticGet('url', $httpUrl);
+                        if (!empty($f) && !empty($f->filename)) {
+                            // this will handle the HTTPS case
+                            $logoUrl = File::url($f->filename);
+                        }
+                    }
+                }
+            } else {
+                $logoUrl = common_config('site', 'logo');
+            }
+
+            if (empty($logoUrl) && file_exists(Theme::file('logo.png'))) {
+                // This should handle the HTTPS case internally
+                $logoUrl = Theme::path('logo.png');
+            }
+
+            if (!empty($logoUrl)) {
                 $this->element('img', array('class' => 'logo photo',
-                                            'src' => (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png'),
+                                            'src' => $logoUrl,
                                             'alt' => common_config('site', 'name')));
             }
+
             $this->text(' ');
             $this->element('span', array('class' => 'fn org'), common_config('site', 'name'));
             $this->elementEnd('a');
@@ -476,20 +576,20 @@ class Action extends HTMLOutputter // lawsuit
                 }
                 // TRANS: Tooltip for main menu option "Login"
                 $tooltip = _m('TOOLTIP', 'Login to the site');
-                // TRANS: Main menu option when not logged in to log in
                 $this->menuItem(common_local_url('login'),
+                                // TRANS: Main menu option when not logged in to log in
                                 _m('MENU', 'Login'), $tooltip, false, 'nav_login');
             }
             // TRANS: Tooltip for main menu option "Help"
             $tooltip = _m('TOOLTIP', 'Help me!');
-            // TRANS: Main menu option for help on the StatusNet site
             $this->menuItem(common_local_url('doc', array('title' => 'help')),
+                            // TRANS: Main menu option for help on the StatusNet site
                             _m('MENU', 'Help'), $tooltip, false, 'nav_help');
             if ($user || !common_config('site', 'private')) {
                 // TRANS: Tooltip for main menu option "Search"
                 $tooltip = _m('TOOLTIP', 'Search for people or text');
-                // TRANS: Main menu option when logged in or when the StatusNet instance is not private
                 $this->menuItem(common_local_url('peoplesearch'),
+                                // TRANS: Main menu option when logged in or when the StatusNet instance is not private
                                 _m('MENU', 'Search'), $tooltip, false, 'nav_search');
             }
             Event::handle('EndPrimaryNav', array($this));
@@ -606,7 +706,10 @@ class Action extends HTMLOutputter // lawsuit
     function showContentBlock()
     {
         $this->elementStart('div', array('id' => 'content'));
-        $this->showPageTitle();
+        if (Event::handle('StartShowPageTitle', array($this))) {
+            $this->showPageTitle();
+            Event::handle('EndShowPageTitle', array($this));
+        }
         $this->showPageNoticeBlock();
         $this->elementStart('div', array('id' => 'content_inner'));
         // show the actual content (forms, lists, whatever)
@@ -684,19 +787,18 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return nothing
      */
-
     function showAside()
     {
         $this->elementStart('div', array('id' => 'aside_primary',
                                          'class' => 'aside'));
-        if (Event::handle('StartShowExportData', array($this))) {
-            $this->showExportData();
-            Event::handle('EndShowExportData', array($this));
-        }
         if (Event::handle('StartShowSections', array($this))) {
             $this->showSections();
             Event::handle('EndShowSections', array($this));
         }
+        if (Event::handle('StartShowExportData', array($this))) {
+            $this->showExportData();
+            Event::handle('EndShowExportData', array($this));
+        }
         $this->elementEnd('div');
     }
 
@@ -705,7 +807,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return void
      */
-
     function showExportData()
     {
         $feeds = $this->getFeeds();
@@ -772,15 +873,17 @@ class Action extends HTMLOutputter // lawsuit
                             // TRANS: Secondary navigation menu option leading to privacy policy.
                             _('Privacy'));
             $this->menuItem(common_local_url('doc', array('title' => 'source')),
-                            // TRANS: Secondary navigation menu option.
+                            // TRANS: Secondary navigation menu option. Leads to information about StatusNet and its license.
                             _('Source'));
             $this->menuItem(common_local_url('version'),
                             // TRANS: Secondary navigation menu option leading to version information on the StatusNet site.
                             _('Version'));
             $this->menuItem(common_local_url('doc', array('title' => 'contact')),
-                            // TRANS: Secondary navigation menu option leading to contact information on the StatusNet site.
+                            // TRANS: Secondary navigation menu option leading to e-mail contact information on the
+                            // TRANS: StatusNet site, where to report bugs, ...
                             _('Contact'));
             $this->menuItem(common_local_url('doc', array('title' => 'badge')),
+                            // TRANS: Secondary navigation menu option. Leads to information about embedding a timeline widget.
                             _('Badge'));
             Event::handle('EndSecondaryNav', array($this));
         }
@@ -814,6 +917,9 @@ class Action extends HTMLOutputter // lawsuit
         $this->elementStart('dd', null);
         if (common_config('site', 'broughtby')) {
             // TRANS: First sentence of the StatusNet site license. Used if 'broughtby' is set.
+            // TRANS: Text between [] is a link description, text between () is the link itself.
+            // TRANS: Make sure there is no whitespace between "]" and "(".
+            // TRANS: "%%site.broughtby%%" is the value of the variable site.broughtby
             $instr = _('**%%site.name%%** is a microblogging service brought to you by [%%site.broughtby%%](%%site.broughtbyurl%%).');
         } else {
             // TRANS: First sentence of the StatusNet site license. Used if 'broughtby' is not set.
@@ -821,6 +927,9 @@ class Action extends HTMLOutputter // lawsuit
         }
         $instr .= ' ';
         // TRANS: Second sentence of the StatusNet site license. Mentions the StatusNet source code license.
+        // TRANS: Make sure there is no whitespace between "]" and "(".
+        // TRANS: Text between [] is a link description, text between () is the link itself.
+        // TRANS: %s is the version of StatusNet that is being used.
         $instr .= sprintf(_('It runs the [StatusNet](http://status.net/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html).'), STATUSNET_VERSION);
         $output = common_markup_to_html($instr);
         $this->raw($output);
@@ -861,13 +970,32 @@ class Action extends HTMLOutputter // lawsuit
             case 'cc': // fall through
             default:
                 $this->elementStart('p');
+
+                $image    = common_config('license', 'image');
+                $sslimage = common_config('license', 'sslimage');
+
+                if (StatusNet::isHTTPS()) {
+                    if (!empty($sslimage)) {
+                        $url = $sslimage;
+                    } else if (preg_match('#^http://i.creativecommons.org/#', $image)) {
+                        // CC support HTTPS on their images
+                        $url = preg_replace('/^http/', 'https', $image);
+                    } else {
+                        // Better to show mixed content than no content
+                        $url = $image;
+                    }
+                } else {
+                    $url = $image;
+                }
+
                 $this->element('img', array('id' => 'license_cc',
-                                            'src' => common_config('license', 'image'),
+                                            'src' => $url,
                                             'alt' => common_config('license', 'title'),
                                             'width' => '80',
                                             'height' => '15'));
                 $this->text(' ');
-                // TRANS: license message in footer. %1$s is the site name, %2$s is a link to the license URL, with a licence name set in configuration.
+                // TRANS: license message in footer.
+                // TRANS: %1$s is the site name, %2$s is a link to the license URL, with a licence name set in configuration.
                 $notice = _('All %1$s content and data are available under the %2$s license.');
                 $link = "<a class=\"license\" rel=\"external license\" href=\"" .
                         htmlspecialchars(common_config('license', 'url')) .
@@ -921,7 +1049,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return boolean is read only action?
      */
-
     function isReadOnly($args)
     {
         return false;
@@ -968,29 +1095,61 @@ class Action extends HTMLOutputter // lawsuit
     function handle($argarray=null)
     {
         header('Vary: Accept-Encoding,Cookie');
+
         $lm   = $this->lastModified();
         $etag = $this->etag();
+
         if ($etag) {
             header('ETag: ' . $etag);
         }
+
         if ($lm) {
             header('Last-Modified: ' . date(DATE_RFC1123, $lm));
-            if (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) {
-                $if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
-                $ims = strtotime($if_modified_since);
-                if ($lm <= $ims) {
-                    $if_none_match = (array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER)) ?
-                      $_SERVER['HTTP_IF_NONE_MATCH'] : null;
-                    if (!$if_none_match ||
-                        !$etag ||
-                        $this->_hasEtag($etag, $if_none_match)) {
-                        header('HTTP/1.1 304 Not Modified');
-                        // Better way to do this?
-                        exit(0);
-                    }
+            if ($this->isCacheable()) {
+                header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
+                header( "Cache-Control: private, must-revalidate, max-age=0" );
+                header( "Pragma:");
+            }
+        }
+
+        $checked = false;
+        if ($etag) {
+            $if_none_match = (array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER)) ?
+              $_SERVER['HTTP_IF_NONE_MATCH'] : null;
+            if ($if_none_match) {
+                // If this check fails, ignore the if-modified-since below.
+                $checked = true;
+                if ($this->_hasEtag($etag, $if_none_match)) {
+                    header('HTTP/1.1 304 Not Modified');
+                    // Better way to do this?
+                    exit(0);
                 }
             }
         }
+
+        if (!$checked && $lm && array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) {
+            $if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
+            $ims = strtotime($if_modified_since);
+            if ($lm <= $ims) {
+                header('HTTP/1.1 304 Not Modified');
+                // Better way to do this?
+                exit(0);
+            }
+        }
+    }
+
+    /**
+     * Is this action cacheable?
+     *
+     * If the action returns a last-modified
+     *
+     * @param array $argarray is ignored since it's now passed in in prepare()
+     *
+     * @return boolean is read only action?
+     */
+    function isCacheable()
+    {
+        return true;
     }
 
     /**
@@ -1001,7 +1160,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return boolean
      */
-
     function _hasEtag($etag, $if_none_match)
     {
         $etags = explode(',', $if_none_match);
@@ -1041,7 +1199,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return integer integer value
      */
-
     function int($key, $defValue=null, $maxValue=null, $minValue=null)
     {
         $arg = strtolower($this->trimmed($key));
@@ -1069,7 +1226,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return nothing
      */
-
     function serverError($msg, $code=500)
     {
         $action = $this->trimmed('action');
@@ -1085,7 +1241,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return nothing
      */
-
     function clientError($msg, $code=400)
     {
         $action = $this->trimmed('action');
@@ -1098,7 +1253,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return string current URL
      */
-
     function selfUrl()
     {
         list($action, $args) = $this->returnToArgs();
@@ -1110,7 +1264,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return array two elements: action, other args
      */
-
     function returnToArgs()
     {
         $action = $this->trimmed('action');
@@ -1217,7 +1370,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return array Feed object to show in head and links
      */
-
     function getFeeds()
     {
         return null;
@@ -1228,7 +1380,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return Design a design object to use
      */
-
     function getDesign()
     {
         return Design::siteDesign();
@@ -1242,7 +1393,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return void
      */
-
     // XXX: Finding this type of check with the same message about 50 times.
     //      Possible to refactor?
     function checkSessionToken()
@@ -1250,7 +1400,19 @@ class Action extends HTMLOutputter // lawsuit
         // CSRF protection
         $token = $this->trimmed('token');
         if (empty($token) || $token != common_session_token()) {
+            // TRANS: Client error text when there is a problem with the session token.
             $this->clientError(_('There was a problem with your session token.'));
         }
     }
+
+    /**
+     * Check if the current request is a POST
+     *
+     * @return boolean true if POST; otherwise false.
+     */
+
+    function isPost()
+    {
+        return ($_SERVER['REQUEST_METHOD'] == 'POST');
+    }
 }