]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - lib/action.php
pass profile down to ScopingNoticeStream in publicnoticestream
[quix0rs-gnu-social.git] / lib / action.php
index e503975147085db7200db9575dcea0da54078456..f626c04480f69112d7e7230443cca585b740d0b1 100644 (file)
@@ -83,6 +83,11 @@ class Action extends HTMLOutputter // lawsuit
     function prepare($argarray)
     {
         $this->args =& common_copy_args($argarray);
+
+        if ($this->boolean('ajax')) {
+            StatusNet::setAjax(true);
+        }
+
         return true;
     }
 
@@ -95,10 +100,12 @@ class Action extends HTMLOutputter // lawsuit
     {
         if (Event::handle('StartShowHTML', array($this))) {
             $this->startHTML();
+            $this->flush();
             Event::handle('EndShowHTML', array($this));
         }
         if (Event::handle('StartShowHead', array($this))) {
             $this->showHead();
+            $this->flush();
             Event::handle('EndShowHead', array($this));
         }
         if (Event::handle('StartShowBody', array($this))) {
@@ -111,6 +118,19 @@ class Action extends HTMLOutputter // lawsuit
         }
     }
 
+    function endHTML()
+    {
+        global $_startTime;
+
+        if (isset($_startTime)) {
+            $endTime = microtime(true);
+            $diff = round(($endTime - $_startTime) * 1000);
+            $this->raw("<!-- ${diff}ms -->");
+        }
+
+        return parent::endHTML();
+    }
+
     /**
      * Show head, a template method.
      *
@@ -145,7 +165,7 @@ class Action extends HTMLOutputter // lawsuit
     {
         $this->element('title', null,
                        // TRANS: Page title. %1$s is the title, %2$s is the site name.
-                       sprintf(_("%1\$s - %2\$s"),
+                       sprintf(_('%1$s - %2$s'),
                                $this->title(),
                                common_config('site', 'name')));
     }
@@ -161,7 +181,7 @@ class Action extends HTMLOutputter // lawsuit
     function title()
     {
         // TRANS: Page title for a page without a title set.
-        return _("Untitled page");
+        return _('Untitled page');
     }
 
     /**
@@ -175,8 +195,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')) {
@@ -208,6 +229,8 @@ class Action extends HTMLOutputter // lawsuit
                 Event::handle('EndShowLaconicaStyles', array($this));
             }
 
+            $this->cssLink(common_path('js/css/smoothness/jquery-ui.css'));
+
             if (Event::handle('StartShowUAStyles', array($this))) {
                 $this->comment('[if IE]><link rel="stylesheet" type="text/css" '.
                                'href="'.Theme::path('css/ie.css', 'base').'?version='.STATUSNET_VERSION.'" /><![endif]');
@@ -253,9 +276,16 @@ class Action extends HTMLOutputter // lawsuit
 
     function primaryCssLink($mainTheme=null, $media=null)
     {
+        $theme = new Theme($mainTheme);
+
+        // Some themes may have external stylesheets, such as using the
+        // Google Font APIs to load webfonts.
+        foreach ($theme->getExternals() as $url) {
+            $this->cssLink($url, $mainTheme, $media);
+        }
+
         // 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);
@@ -272,16 +302,36 @@ class Action extends HTMLOutputter // lawsuit
     {
         if (Event::handle('StartShowScripts', array($this))) {
             if (Event::handle('StartShowJQueryScripts', array($this))) {
-                $this->script('jquery.min.js');
-                $this->script('jquery.form.js');
-                $this->script('jquery.cookie.js');
-                $this->inlineScript('if (typeof window.JSON !== "object") { $.getScript("'.common_path('js/json2.js').'"); }');
-                $this->script('jquery.joverlay.min.js');
+                if (common_config('site', 'minify')) {
+                    $this->script('jquery.min.js');
+                    $this->script('jquery.form.min.js');
+                    $this->script('jquery-ui.min.js');
+                    $this->script('jquery.cookie.min.js');
+                    $this->inlineScript('if (typeof window.JSON !== "object") { $.getScript("'.common_path('js/json2.min.js').'"); }');
+                    $this->script('jquery.joverlay.min.js');
+                } else {
+                    $this->script('jquery.js');
+                    $this->script('jquery.form.js');
+                    $this->script('jquery-ui.min.js');
+                    $this->script('jquery.cookie.js');
+                    $this->inlineScript('if (typeof window.JSON !== "object") { $.getScript("'.common_path('js/json2.js').'"); }');
+                    $this->script('jquery.joverlay.js');
+                }
+
                 Event::handle('EndShowJQueryScripts', array($this));
             }
             if (Event::handle('StartShowStatusNetScripts', array($this)) &&
                 Event::handle('StartShowLaconicaScripts', array($this))) {
-                $this->script('util.js');
+                if (common_config('site', 'minify')) {
+                    $this->script('util.min.js');
+                } else {
+                    $this->script('util.js');
+                    $this->script('xbImportNode.js');
+                    $this->script('geometa.js');
+                }
+                $this->inlineScript('var _peopletagAC = "' .
+                    common_local_url('peopletagautocomplete') . '";');
+                $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));
@@ -291,6 +341,64 @@ 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');
+
+            // TRANS: Inline reply form submit button: submits a reply comment.
+            $messages['reply_submit'] = _m('BUTTON', 'Reply');
+
+            // TRANS: Placeholder text for inline reply form. Clicking in this box will turn it into a mini notice form.
+            $messages['reply_placeholder'] = _m('Write a reply...');
+
+            $messages = array_merge($messages, $this->getScriptMessages());
+
+           Event::handle('EndScriptMessages', array($this, &$messages));
+        }
+
+        if (!empty($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
      *
@@ -314,7 +422,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return nothing
      */
-
     function showFeeds()
     {
         $feeds = $this->getFeeds();
@@ -362,17 +469,20 @@ 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();
+            $this->flush();
             Event::handle('EndShowHeader', array($this));
         }
         $this->showCore();
+        $this->flush();
         if (Event::handle('StartShowFooter', array($this))) {
             $this->showFooter();
+            $this->flush();
             Event::handle('EndShowFooter', array($this));
         }
         $this->elementEnd('div');
@@ -397,11 +507,7 @@ class Action extends HTMLOutputter // lawsuit
 
             Event::handle('EndShowSiteNotice', array($this));
         }
-        if (common_logged_in()) {
-            $this->showNoticeForm();
-        } else {
-            $this->showAnonymousMessage();
-        }
+
         $this->elementEnd('div');
     }
 
@@ -416,21 +522,51 @@ 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 if (common_logged_in()) {
+                $cur = common_current_user();
+                $url = common_local_url('all', array('nickname' => $cur->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');
+
             Event::handle('EndAddressData', array($this));
         }
         $this->elementEnd('address');
@@ -443,83 +579,10 @@ class Action extends HTMLOutputter // lawsuit
      */
     function showPrimaryNav()
     {
-        $user = common_current_user();
-        $this->elementStart('dl', array('id' => 'site_nav_global_primary'));
-        // TRANS: DT element for primary navigation menu. String is hidden in default CSS.
-        $this->element('dt', null, _('Primary site navigation'));
-        $this->elementStart('dd');
-        $this->elementStart('ul', array('class' => 'nav'));
-        if (Event::handle('StartPrimaryNav', array($this))) {
-            if ($user) {
-                // TRANS: Tooltip for main menu option "Personal"
-                $tooltip = _m('TOOLTIP', 'Personal profile and friends timeline');
-                $this->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
-                                // TRANS: Main menu option when logged in for access to personal profile and friends timeline
-                                _m('MENU', 'Personal'), $tooltip, false, 'nav_home');
-                // TRANS: Tooltip for main menu option "Account"
-                $tooltip = _m('TOOLTIP', 'Change your email, avatar, password, profile');
-                $this->menuItem(common_local_url('profilesettings'),
-                                // TRANS: Main menu option when logged in for access to user settings
-                                _('Account'), $tooltip, false, 'nav_account');
-                // TRANS: Tooltip for main menu option "Services"
-                $tooltip = _m('TOOLTIP', 'Connect to services');
-                $this->menuItem(common_local_url('oauthconnectionssettings'),
-                                // TRANS: Main menu option when logged in and connection are possible for access to options to connect to other services
-                                _('Connect'), $tooltip, false, 'nav_connect');
-                if ($user->hasRight(Right::CONFIGURESITE)) {
-                    // TRANS: Tooltip for menu option "Admin"
-                    $tooltip = _m('TOOLTIP', 'Change site configuration');
-                    $this->menuItem(common_local_url('siteadminpanel'),
-                                    // TRANS: Main menu option when logged in and site admin for access to site configuration
-                                    _m('MENU', 'Admin'), $tooltip, false, 'nav_admin');
-                }
-                if (common_config('invite', 'enabled')) {
-                    // TRANS: Tooltip for main menu option "Invite"
-                    $tooltip = _m('TOOLTIP', 'Invite friends and colleagues to join you on %s');
-                    $this->menuItem(common_local_url('invite'),
-                                    // TRANS: Main menu option when logged in and invitations are allowed for inviting new users
-                                    _m('MENU', 'Invite'),
-                                    sprintf($tooltip,
-                                            common_config('site', 'name')),
-                                    false, 'nav_invitecontact');
-                }
-                // TRANS: Tooltip for main menu option "Logout"
-                $tooltip = _m('TOOLTIP', 'Logout from the site');
-                $this->menuItem(common_local_url('logout'),
-                                // TRANS: Main menu option when logged in to log out the current user
-                                _m('MENU', 'Logout'), $tooltip, false, 'nav_logout');
-            }
-            else {
-                if (!common_config('site', 'closed') && !common_config('site', 'inviteonly')) {
-                    // TRANS: Tooltip for main menu option "Register"
-                    $tooltip = _m('TOOLTIP', 'Create an account');
-                    $this->menuItem(common_local_url('register'),
-                                    // TRANS: Main menu option when not logged in to register a new account
-                                    _m('MENU', 'Register'), $tooltip, false, 'nav_register');
-                }
-                // 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'),
-                                _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')),
-                            _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'),
-                                _m('MENU', 'Search'), $tooltip, false, 'nav_search');
-            }
-            Event::handle('EndPrimaryNav', array($this));
-        }
-        $this->elementEnd('ul');
-        $this->elementEnd('dd');
-        $this->elementEnd('dl');
+        $this->elementStart('div', array('id' => 'site_nav_global_primary'));
+        $pn = new PrimaryNav($this);
+        $pn->show();
+        $this->elementEnd('div');
     }
 
     /**
@@ -532,14 +595,10 @@ class Action extends HTMLOutputter // lawsuit
         // Revist. Should probably do an hAtom pattern here
         $text = common_config('site', 'notice');
         if ($text) {
-            $this->elementStart('dl', array('id' => 'site_notice',
+            $this->elementStart('div', array('id' => 'site_notice',
                                             'class' => 'system_notice'));
-            // TRANS: DT element for site notice. String is hidden in default CSS.
-            $this->element('dt', null, _('Site notice'));
-            $this->elementStart('dd', null);
             $this->raw($text);
-            $this->elementEnd('dd');
-            $this->elementEnd('dl');
+            $this->elementEnd('div');
         }
     }
 
@@ -552,8 +611,72 @@ class Action extends HTMLOutputter // lawsuit
      */
     function showNoticeForm()
     {
-        $notice_form = new NoticeForm($this);
-        $notice_form->show();
+        // TRANS: Tab on the notice form.
+        $tabs = array('status' => _m('TAB','Status'));
+
+        $this->elementStart('div', 'input_forms');
+
+        if (Event::handle('StartShowEntryForms', array(&$tabs))) {
+            $this->elementStart('ul', array('class' => 'nav',
+                                            'id' => 'input_form_nav'));
+
+            foreach ($tabs as $tag => $title) {
+                $attrs = array('id' => 'input_form_nav_'.$tag,
+                               'class' => 'input_form_nav_tab');
+
+                if ($tag == 'status') {
+                    // We're actually showing the placeholder form,
+                    // but we special-case the 'Status' tab as if
+                    // it were a small version of it.
+                    $attrs['class'] .= ' current';
+                }
+                $this->elementStart('li', $attrs);
+
+                $this->element('a',
+                               array('href' => 'javascript:SN.U.switchInputFormTab("'.$tag.'")'),
+                               $title);
+                $this->elementEnd('li');
+            }
+
+            $this->elementEnd('ul');
+
+            $attrs = array('class' => 'input_form current',
+                           'id' => 'input_form_placeholder');
+            $this->elementStart('div', $attrs);
+            $form = new NoticePlaceholderForm($this);
+            $form->show();
+            $this->elementEnd('div');
+
+            foreach ($tabs as $tag => $title) {
+                $attrs = array('class' => 'input_form',
+                               'id' => 'input_form_'.$tag);
+
+                $this->elementStart('div', $attrs);
+
+                $form = null;
+
+                if (Event::handle('StartMakeEntryForm', array($tag, $this, &$form))) {
+                    if ($tag == 'status') {
+                        $options = $this->noticeFormOptions();
+                        $form = new NoticeForm($this, $options);
+                    }
+                    Event::handle('EndMakeEntryForm', array($tag, $this, $form));
+                }
+
+                if (!empty($form)) {
+                    $form->show();
+                }
+
+                $this->elementEnd('div');
+            }
+        }
+
+        $this->elementEnd('div');
+    }
+
+    function noticeFormOptions()
+    {
+        return array();
     }
 
     /**
@@ -578,19 +701,28 @@ class Action extends HTMLOutputter // lawsuit
     function showCore()
     {
         $this->elementStart('div', array('id' => 'core'));
+        $this->elementStart('div', array('id' => 'aside_primary_wrapper'));
+        $this->elementStart('div', array('id' => 'content_wrapper'));
+        $this->elementStart('div', array('id' => 'site_nav_local_views_wrapper'));
         if (Event::handle('StartShowLocalNavBlock', array($this))) {
             $this->showLocalNavBlock();
+            $this->flush();
             Event::handle('EndShowLocalNavBlock', array($this));
         }
         if (Event::handle('StartShowContentBlock', array($this))) {
             $this->showContentBlock();
+            $this->flush();
             Event::handle('EndShowContentBlock', array($this));
         }
         if (Event::handle('StartShowAside', array($this))) {
             $this->showAside();
+            $this->flush();
             Event::handle('EndShowAside', array($this));
         }
         $this->elementEnd('div');
+        $this->elementEnd('div');
+        $this->elementEnd('div');
+        $this->elementEnd('div');
     }
 
     /**
@@ -600,13 +732,25 @@ class Action extends HTMLOutputter // lawsuit
      */
     function showLocalNavBlock()
     {
-        $this->elementStart('dl', array('id' => 'site_nav_local_views'));
-        // TRANS: DT element for local views block. String is hidden in default CSS.
-        $this->element('dt', null, _('Local views'));
-        $this->elementStart('dd');
+        // Need to have this ID for CSS; I'm too lazy to add it to
+        // all menus
+        $this->elementStart('div', array('id' => 'site_nav_local_views'));
+        // Cheat cheat cheat!
         $this->showLocalNav();
-        $this->elementEnd('dd');
-        $this->elementEnd('dl');
+        $this->elementEnd('div');
+    }
+
+    /**
+     * If there's a logged-in user, show a bit of login context
+     *
+     * @return nothing
+     */
+    function showProfileBlock()
+    {
+        if (common_logged_in()) {
+            $block = new DefaultProfileBlock($this);
+            $block->show();
+        }
     }
 
     /**
@@ -618,7 +762,43 @@ class Action extends HTMLOutputter // lawsuit
      */
     function showLocalNav()
     {
-        // does nothing by default
+        $nav = new DefaultLocalNav($this);
+        $nav->show();
+    }
+
+    /**
+     * Show menu for an object (group, profile)
+     *
+     * This block will only show if a subclass has overridden
+     * the showObjectNav() method.
+     *
+     * @return nothing
+     */
+    function showObjectNavBlock()
+    {
+        $rmethod = new ReflectionMethod($this, 'showObjectNav');
+        $dclass = $rmethod->getDeclaringClass()->getName();
+
+        if ($dclass != 'Action') {
+            // Need to have this ID for CSS; I'm too lazy to add it to
+            // all menus
+            $this->elementStart('div', array('id' => 'site_nav_object',
+                                             'class' => 'section'));
+            $this->showObjectNav();
+            $this->elementEnd('div');
+        }
+    }
+
+    /**
+     * Show object navigation.
+     *
+     * If there are things to do with this object, show it here.
+     *
+     * @return nothing
+     */
+    function showObjectNav()
+    {
+        /* Nothing here. */
     }
 
     /**
@@ -629,6 +809,12 @@ class Action extends HTMLOutputter // lawsuit
     function showContentBlock()
     {
         $this->elementStart('div', array('id' => 'content'));
+        if (common_logged_in()) {
+            if (Event::handle('StartShowNoticeForm', array($this))) {
+                $this->showNoticeForm();
+                Event::handle('EndShowNoticeForm', array($this));
+            }
+        }
         if (Event::handle('StartShowPageTitle', array($this))) {
             $this->showPageTitle();
             Event::handle('EndShowPageTitle', array($this));
@@ -669,17 +855,13 @@ class Action extends HTMLOutputter // lawsuit
 
         if ($dclass != 'Action' || Event::hasHandler('StartShowPageNotice')) {
 
-            $this->elementStart('dl', array('id' => 'page_notice',
+            $this->elementStart('div', array('id' => 'page_notice',
                                             'class' => 'system_notice'));
-            // TRANS: DT element for page notice. String is hidden in default CSS.
-            $this->element('dt', null, _('Page notice'));
-            $this->elementStart('dd');
             if (Event::handle('StartShowPageNotice', array($this))) {
                 $this->showPageNotice();
                 Event::handle('EndShowPageNotice', array($this));
             }
-            $this->elementEnd('dd');
-            $this->elementEnd('dl');
+            $this->elementEnd('div');
         }
     }
 
@@ -710,19 +892,23 @@ 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));
+        $this->showProfileBlock();
+        if (Event::handle('StartShowObjectNavBlock', array($this))) {
+            $this->showObjectNavBlock();
+            Event::handle('EndShowObjectNavBlock', 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');
     }
 
@@ -731,7 +917,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return void
      */
-
     function showExportData()
     {
         $feeds = $this->getFeeds();
@@ -761,8 +946,11 @@ class Action extends HTMLOutputter // lawsuit
     function showFooter()
     {
         $this->elementStart('div', array('id' => 'footer'));
-        $this->showSecondaryNav();
-        $this->showLicenses();
+        if (Event::handle('StartShowInsideFooter', array($this))) {
+            $this->showSecondaryNav();
+            $this->showLicenses();
+            Event::handle('EndShowInsideFooter', array($this));
+        }
         $this->elementEnd('div');
     }
 
@@ -773,46 +961,8 @@ class Action extends HTMLOutputter // lawsuit
      */
     function showSecondaryNav()
     {
-        $this->elementStart('dl', array('id' => 'site_nav_global_secondary'));
-        // TRANS: DT element for secondary navigation menu. String is hidden in default CSS.
-        $this->element('dt', null, _('Secondary site navigation'));
-        $this->elementStart('dd', null);
-        $this->elementStart('ul', array('class' => 'nav'));
-        if (Event::handle('StartSecondaryNav', array($this))) {
-            $this->menuItem(common_local_url('doc', array('title' => 'help')),
-                            // TRANS: Secondary navigation menu option leading to help on StatusNet.
-                            _('Help'));
-            $this->menuItem(common_local_url('doc', array('title' => 'about')),
-                            // TRANS: Secondary navigation menu option leading to text about StatusNet site.
-                            _('About'));
-            $this->menuItem(common_local_url('doc', array('title' => 'faq')),
-                            // TRANS: Secondary navigation menu option leading to Frequently Asked Questions.
-                            _('FAQ'));
-            $bb = common_config('site', 'broughtby');
-            if (!empty($bb)) {
-                $this->menuItem(common_local_url('doc', array('title' => 'tos')),
-                                // TRANS: Secondary navigation menu option leading to Terms of Service.
-                                _('TOS'));
-            }
-            $this->menuItem(common_local_url('doc', array('title' => 'privacy')),
-                            // TRANS: Secondary navigation menu option leading to privacy policy.
-                            _('Privacy'));
-            $this->menuItem(common_local_url('doc', array('title' => 'source')),
-                            // TRANS: Secondary navigation menu option.
-                            _('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.
-                            _('Contact'));
-            $this->menuItem(common_local_url('doc', array('title' => 'badge')),
-                            _('Badge'));
-            Event::handle('EndSecondaryNav', array($this));
-        }
-        $this->elementEnd('ul');
-        $this->elementEnd('dd');
-        $this->elementEnd('dl');
+        $sn = new SecondaryNav($this);
+        $sn->show();
     }
 
     /**
@@ -822,10 +972,8 @@ class Action extends HTMLOutputter // lawsuit
      */
     function showLicenses()
     {
-        $this->elementStart('dl', array('id' => 'licenses'));
         $this->showStatusNetLicense();
         $this->showContentLicense();
-        $this->elementEnd('dl');
     }
 
     /**
@@ -835,11 +983,11 @@ class Action extends HTMLOutputter // lawsuit
      */
     function showStatusNetLicense()
     {
-        // TRANS: DT element for StatusNet software license.
-        $this->element('dt', array('id' => 'site_statusnet_license'), _('StatusNet software license'));
-        $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.
@@ -847,10 +995,12 @@ 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);
-        $this->elementEnd('dd');
         // do it
     }
 
@@ -862,10 +1012,6 @@ class Action extends HTMLOutputter // lawsuit
     function showContentLicense()
     {
         if (Event::handle('StartShowContentLicense', array($this))) {
-            // TRANS: DT element for StatusNet site content license.
-            $this->element('dt', array('id' => 'site_content_license'), _('Site content license'));
-            $this->elementStart('dd', array('id' => 'site_content_license_cc'));
-
             switch (common_config('license', 'type')) {
             case 'private':
                 // TRANS: Content license displayed when license is set to 'private'.
@@ -887,13 +1033,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')) .
@@ -907,7 +1072,6 @@ class Action extends HTMLOutputter // lawsuit
                 break;
             }
 
-            $this->elementEnd('dd');
             Event::handle('EndShowContentLicense', array($this));
         }
     }
@@ -947,7 +1111,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return boolean is read only action?
      */
-
     function isReadOnly($args)
     {
         return false;
@@ -1011,17 +1174,22 @@ class Action extends HTMLOutputter // lawsuit
             }
         }
 
+        $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 && $this->_hasEtag($etag, $if_none_match)) {
-                header('HTTP/1.1 304 Not Modified');
-                // Better way to do this?
-                exit(0);
+            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 ($lm && array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) {
+        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) {
@@ -1041,7 +1209,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return boolean is read only action?
      */
-
     function isCacheable()
     {
         return true;
@@ -1055,7 +1222,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return boolean
      */
-
     function _hasEtag($etag, $if_none_match)
     {
         $etags = explode(',', $if_none_match);
@@ -1095,7 +1261,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return integer integer value
      */
-
     function int($key, $defValue=null, $maxValue=null, $minValue=null)
     {
         $arg = strtolower($this->trimmed($key));
@@ -1123,7 +1288,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return nothing
      */
-
     function serverError($msg, $code=500)
     {
         $action = $this->trimmed('action');
@@ -1139,7 +1303,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return nothing
      */
-
     function clientError($msg, $code=400)
     {
         $action = $this->trimmed('action');
@@ -1152,7 +1315,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return string current URL
      */
-
     function selfUrl()
     {
         list($action, $args) = $this->returnToArgs();
@@ -1164,7 +1326,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return array two elements: action, other args
      */
-
     function returnToArgs()
     {
         $action = $this->trimmed('action');
@@ -1231,11 +1392,8 @@ class Action extends HTMLOutputter // lawsuit
     {
         // Does a little before-after block for next/prev page
         if ($have_before || $have_after) {
-            $this->elementStart('dl', 'pagination');
-            // TRANS: DT element for pagination (previous/next, etc.).
-            $this->element('dt', null, _('Pagination'));
-            $this->elementStart('dd', null);
-            $this->elementStart('ul', array('class' => 'nav'));
+            $this->elementStart('ul', array('class' => 'nav',
+                                            'id' => 'pagination'));
         }
         if ($have_before) {
             $pargs   = array('page' => $page-1);
@@ -1259,8 +1417,6 @@ class Action extends HTMLOutputter // lawsuit
         }
         if ($have_before || $have_after) {
             $this->elementEnd('ul');
-            $this->elementEnd('dd');
-            $this->elementEnd('dl');
         }
     }
 
@@ -1271,7 +1427,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return array Feed object to show in head and links
      */
-
     function getFeeds()
     {
         return null;
@@ -1282,7 +1437,6 @@ class Action extends HTMLOutputter // lawsuit
      *
      * @return Design a design object to use
      */
-
     function getDesign()
     {
         return Design::siteDesign();
@@ -1296,7 +1450,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()
@@ -1304,7 +1457,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');
+    }
 }