TWiT Army Laconica Plugin

I was recently asked by my friends over at the TWiT Army to checkout the new Laconica plugin system in version 0.7.2.1. They wanted to know if it could be used to modify the default Laconica output on the TWiT Army Canteen, a feature currently handled by Javascript after the page is loaded. Javascript was used because it saves them from having to modify core code since core changes complicate upgrades. The downside of Javascript is that users see a brief flash of the original output before the JS runs. Another problem with JS modifications is that users who disable JS won't see the page as intended. I doubt anyone besides the TWiT Army will actually use this plugin but it's a decent example of how to use the plugin system so I hope it will be helpful for someone.

What the plugin does

  • Inserts 'apple-touch-icon' link in <head>
  • Adds 'helmetlink' and 'logolink' divs
  • Adds 'toplinks' and 'toplinks2' divs and lists (Live, Leoville, ODTV etc.)
  • Adds 'watermark' and 'bugle' div
  • Replaces nav links (tabs) on some pages

Download the plugin and documentation TwitPlugin_v0.4.zip.

Installation

Save the plugin to the plugins/ directory and add the following to config.php

require_once('plugins/TwitPlugin.php');
$twit = new TwitPlugin();

Plugin source code

<?php
/**
 * Plugin to modify output for the TWiT Army Canteen
 *
 * @category Plugin
 * @package  Laconica
 * @author   Kyle Hasegawa  @kylehase (http://army.twit.tv)
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @version  TwitPlugin.php,v 0.4 2009/03/31 22:49:08
 *
 * @see      Event
 */


if (!defined('LACONICA')) {
    exit(1);
}

require_once(INSTALLDIR.'/lib/util.php');

class TwitPlugin extends Plugin
{
    var $baseURL;

    function __construct()
    {
        // determine the base URL of the site
        $protocol = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") ? "https" : "http");
        $server = common_config('site', 'server');
        $this->baseURL = $protocol . "://" . $server . '/';
        parent::__construct();
    }

    /**
    * Implementation of onEndShowScripts()
    *
    * @return nothing
    *
    * Inserts elements into the <HTML><head> section
    */

    function onEndShowScripts($action)
    {
        $action->elementStart('link', array('rel'=>'apple-touch-icon', 'href'=>$this->baseURL . 'theme/twitarmy/images/iphoneicon.png'));
        $action->elementEnd('link');
        $action->elementStart('script', array('src'=>$this->baseURL . 'theme/twitarmy/twitarmy.js', 'type'=>'text/javascript'));
        $action->elementEnd('script');
    }

    /**
    * Implementation of onEndShowHeader()
    *
    * @return nothing
    *
    * Inserts elements after the </head>. (Transparent clickable overlays)
    */

    function onEndShowHeader($action)
    {
        $action->elementStart('a', array('href'=>common_local_url('public')));
        $action->elementStart('div', array('id'=>'helmetlink'));
        $action->elementEnd('div');
        $action->elementEnd('a');
        $action->elementStart('a', array('href'=>common_local_url('public')));
        $action->elementStart('div', array('id'=>'logolink'));
        $action->elementEnd('div');
        $action->elementEnd('a');
    }

    /**
    * Implementation of onStartShowLocalNavBlock()
    *
    * @return BOOL
    *
    * Replaces LocalNavBlock on certain pages. Returning FALSE hides the default nav block
    */

    function onStartShowLocalNavBlock($action)
    {
        // These are the pages on which the plugin may alter tabs
        $nav1pages = array('public', 'groups', 'publictagcloud', 'featured', 'favorited', 'inbox', 'outbox');
        // Unused at this time
        // $nav2pages = array('all', 'replies', 'showstream', 'showfavorites');

        // "action" is the loaded page
        $current_action = trim($action->args['action']);
        $user = common_current_user();

        // Override some nav blocks for logged in users
        if($user)
        {
            $nickname = $user->nickname;
            // nav2 pages will have an action->arg array with the 'nickname' set
            $actionNickname = (isset($action->args['nickname'])) ? $action->args['nickname'] : NULL;
            // Show these tabs on nav1 pages or nav2 pages when user is viewing their own nav2 ($nickname === $actionNickname)
            if(in_array($current_action, $nav1pages) OR ($nickname === $actionNickname))
            {
                $action->elementStart('dl', array('id' => 'site_nav_local_views'));
                $action->element('dt', null, _('Local views'));
                $action->elementStart('dd');
                $action->elementStart('ul', array('class' => 'nav'));
                $action->menuItem(common_local_url('public'), _('All TWiTs'),
                    _('Public Timeline'), $current_action == 'public', 'nav_timeline_public');
                $action->menuItem(common_local_url('all', array('nickname' =>$nickname)), _('My Squad'),
                    _('My Squad'), $current_action == 'all', 'nav_timeline_personal');
                $action->menuItem(common_local_url('replies', array('nickname' =>$nickname)), _('@me'),
                    _('Replies'), $current_action == 'replies', 'nav_timeline_replies');
                $action->menuItem(common_local_url('showstream', array('nickname' =>$nickname)), _('Profile'),
                    _('Profile'), $current_action == 'showstream', 'nav_profile');
                $action->menuItem(common_local_url('showfavorites', array('nickname' =>$nickname)), _('Favorites'),
                    _('Favorites'), $current_action == 'showfavorites', 'nav_timeline_favorites');
                $action->menuItem(common_local_url('inbox', array('nickname' =>$nickname)), _('Inbox'),
                    _('Inbox'), $current_action == 'inbox', 'nav_inbox');
                $action->menuItem(common_local_url('outbox', array('nickname' =>$nickname)), _('Outbox'),
                    _('Outbox'), $current_action == 'outbox', 'nav_outbox');
                $action->elementEnd('ul');
                $action->elementEnd('dd');
                $action->elementEnd('dl');
                return FALSE;
            }
            /* // This section was to override the labels but the new lables are misleading. Use defaults.
            elseif(in_array($current_action, $nav2pages))
            {
                $action->elementStart('dl', array('id' => 'site_nav_local_views'));
                $action->element('dt', null, _('Local views'));
                $action->elementStart('dd');
                $action->elementStart('ul', array('class' => 'nav'));
                $actionNickname = $action->args['nickname']; // Nickname of the profile being viewed
                $action->menuItem(common_local_url('public'), _('All TWiTs'),
                    _('Public Timeline'), $current_action == 'public', 'nav_timeline_public');
                $action->menuItem(common_local_url('all', array('nickname' =>$actionNickname)), _('My Squad'),
                    _('My Squad'), $current_action == 'all', 'nav_timeline_personal');
                $action->menuItem(common_local_url('replies', array('nickname' =>$actionNickname)), _('@me'),
                    _('Replies'), $current_action == 'replies', 'nav_timeline_replies');
                $action->menuItem(common_local_url('showstream', array('nickname' =>$actionNickname)), _('Profile'),
                    _('Profile'), $current_action == 'showstream', 'nav_profile');
                $action->menuItem(common_local_url('showfavorites', array('nickname' =>$actionNickname)), _('Favorites'),
                    _('Favorites'), $current_action == 'showfavorites', 'nav_timeline_favorites');
                $action->elementEnd('ul');
                $action->elementEnd('dd');
                $action->elementEnd('dl');
            }
            */

        }
       
        // Override tabs for nav1 pages even if user is not logged in
        // These are actually the default tabs but with different labels.
        // If Laconica core menus change then this section needs to be updated.
        elseif(in_array($current_action, $nav1pages))
        {
            $action->elementStart('dl', array('id' => 'site_nav_local_views'));
            $action->element('dt', null, _('Local views'));
            $action->elementStart('dd');
            $action->elementStart('ul', array('class' => 'nav'));
            $action->menuItem(common_local_url('public'), _('All TWiTs'),
                _('Public Timeline'), $current_action == 'public', 'nav_timeline_public');
            $action->menuItem(common_local_url('groups'), _('Groups'),
                _('User Groups'), $current_action == 'groups', 'nav_groups');
            $action->menuItem(common_local_url('publictagcloud'), _('Recent Tags'),
                _('Recent Tags'), $current_action == 'publictagcloud', 'nav_recent-tags');
            $action->menuItem(common_local_url('featured'), _('Featured'),
                _('Featured Users'), $current_action == 'featured', 'nav_featured');
            $action->menuItem(common_local_url('favorited'), _('Popular'),
                _('Popular Notices'), $current_action == 'favorited', 'nav_timeline_favorited');
            $action->elementEnd('ul');
            $action->elementEnd('dd');
            $action->elementEnd('dl');
            return FALSE;
        }
    }

    /**
    * Implementation of onEndShowContentBlock()
    *
    * @return nothing
    *
    * Inserts right bar divs (menus)
    */

    function onEndShowContentBlock($action)
    {
        $action->elementStart('div', array('id'=>'toplinks'));
        $action->elementStart('ul');
        $toplinks = array();
        $toplinks[] = array('text'=>_('Boot Camp'), 'href'=>'http://army.twit.tv/bootcamp', 'target'=>'_blank');
        $toplinks[] = array('text'=>_('TWiT'), 'href'=>'http://www.twit.tv', 'target'=>'_blank');
        $toplinks[] = array('text'=>_('Live'), 'href'=>'http://live.twit.tv', 'target'=>'_blank');
        $toplinks[] = array('text'=>_('Wiki'), 'href'=>'http://wiki.twit.tv', 'target'=>'_blank');
        $toplinks[] = array('text'=>_('Inside TWiT'), 'href'=>'http://inside.twit.tv', 'target'=>'_blank');

        foreach($toplinks as $link)
        {
            $action->elementStart('li');
            $action->elementStart('a', array('href'=>$link['href'], 'target'=>$link['target']));
            $action->text(_($link['text'])); // Underscore function is for i18n
            $action->elementEnd('a');
            $action->elementEnd('li');
        }
        $action->elementEnd('ul');

        $action->elementStart('div', array('id'=>'toplinks2'));
        $action->elementStart('ul');
        $toplinks2 = array();
        $toplinks2[] = array('text'=>_('Leoville'), 'href'=>'http://leoville.com', 'target'=>'_blank');
        $toplinks2[] = array('text'=>_('Army Flickr'), 'href'=>'http://www.flickr.com/photos/twitarmyflickr/sets', 'target'=>'_blank');
        $toplinks2[] = array('text'=>_('TWiTMap'), 'href'=>'http://twitmap.org', 'target'=>'_blank');
        $toplinks2[] = array('text'=>_('ODTV'), 'href'=>'http://odtv.me', 'target'=>'_blank');

        foreach($toplinks2 as $link)
        {
            $action->elementStart('li');
            $action->elementStart('a', array('href'=>$link['href'], 'target'=>$link['target']));
            $action->text(_($link['text'])); // Underscore function is for i18n
            $action->elementEnd('a');
            $action->elementEnd('li');
        }
        $action->elementEnd('ul');
        $action->elementEnd('div'); // end toplinks2
        $action->elementEnd('div'); // end toplinks


        // Show globallinks section only on the following pages and only when the logged in
        // I wish there was a more systematic way to determine globallink visibility but I can't think of one
        $showGlobalLinkOn = array('newgroup', 'tag', 'doc', 'profilesettings', 'avatarsettings',
                                'passwordsettings', 'emailsettings', 'openidsettings', 'othersettings',
                                'imsettings', 'smssettings', 'twittersettings', 'public', 'groups',
                                'publictagcloud', 'featured', 'favorited', 'showgroup', 'all',
                                'replies', 'showstream', 'showfavorites');
        $current_action = trim($action->args['action']);
        $user = common_current_user();
        if($user && in_array($current_action, $showGlobalLinkOn))
        {
            $action->elementStart('div', array('id'=>'globallinks'));
            $action->elementStart('ul');
            $globallinks = array();
            $globallinks[] = array('text'=>_('Groups'), 'action'=>'groups');
            $globallinks[] = array('text'=>_('Recent Tags'), 'action'=>'publictagcloud');
            $globallinks[] = array('text'=>_('Featured'), 'action'=>'featured');
            $globallinks[] = array('text'=>_('Popular'), 'action'=>'favorited');

            foreach($globallinks as $link)
            {
                $action->elementStart('li');
                $class = ($link['action'] === $current_action) ? 'sidebarcurrent' : 'sidebutton';  // Set class if current page
                $id = 'sidebarbutton-' . $link['action'];
                $href = common_local_url($link['action']);
                $attr = array('href'=>$href, 'class'=>$class, 'id'=>$id);
                $action->elementStart('a', $attr);
                $action->text(_($link['text']));
                $action->elementEnd('a');
                $action->elementEnd('li');
            }
            $action->elementEnd('ul');
            $action->elementEnd('div'); // end globallinks
        }
    }


    /**
    * Implementation of onEndShowSections()
    *
    * @return nothing
    *
    * Adds watermark section after the right sidebar.
    */

    function onEndShowSections($action)
    {
        $action->elementStart('div', array('id'=>'watermark', 'class'=>'section'));
        // $action->text('-- WATERMARK PLACEHOLDER --');
        $action->elementEnd('div');
    }

    /**
    * Implementation of onEndShowFooter()
    *
    * @return nothing
    *
    * Adds bugle div.
    */

    function onEndShowFooter($action)
    {
        $action->elementStart('div', array('id'=>'twit-announcement'));
        $action->elementStart('div', array('id'=>'bugle_background'));
        $action->elementStart('div', array('id'=>'bugle_text'));
        $action->text(_('...Loading...'));
        $action->elementEnd('div');
        $action->elementEnd('div');
        $action->elementEnd('div');
    }

}

All code on this site is free for use at your own risk and provided as-is under the WTFPL license unless otherwise stated. Attribution is appreciated but not required.
Blog content, with the exception of externally quoted material, is licensed under the Creative Commons Attribution 3.0 license