Example Pepper: Window Width

This article is part of a series on developing Pepper for Mint introduced here.

Now that we’ve covered the basics, we’re going to walk through building a simple Pepper. This Pepper will determine the viewer’s browser window width using JavaScript. The width will be stored in a single column added to the Mint visit table. The Pepper will present its findings as percentages in a single tab of a single pane. It will offer a grouping preference. Let’s call this Pepper “Window Width.” You can grab the finished files here to better understand how this all fits together.

Window Width Pepper

Once we’ve decided on a purpose and a name we can start building our Pepper. Begin by creating a developer directory. We’ll use mine, which is /shauninman/, in this example. Next create the Pepper directory, typically the lowercase Pepper name without spaces, eg. /windowwidth/. This is where all of our Pepper files will live. Create a new PHP document named class.php and add a PHP comment identifying yourself as the developer, the Pepper name, and any terms of use.

<?php
/******************************************************************************
 Pepper

 Developer      : Shaun Inman
 Plug-in Name   : Window Width

 [shauninman.com](http://www.shauninman.com/)

 ******************************************************************************/
 if (!defined('MINT')) { header('Location:/'); }; // Prevent viewing this file directly
 ?>

Below the comment (but before the closing ?>) we need to define our Pepper class and add the class name to the $installPepper variable. (The $installPepper variable appears to be in the global space but since this file will only be included from within a method of the Mint object the variable’s scope will be limited to that method.) Pepper class names should be CamelCase prefixed with a developer token and an underscore. Using my developer token we end up with:

$installPepper = "SI_WindowWidth";

class SI_WindowWidth extends Pepper
{

}

Now we need to define some properties for our Pepper.

var $version    = 1; // Displays as 0.01
var $info       = array
(
    'pepperName'    => 'Window Width',
    'pepperUrl'     => 'http://www.haveamint.com/',
    'pepperDesc'    => 'The Window Width Pepper picks up where User Agent 007 leaves off by tracking the width of the browser window on each page load allowing you to make more informed design decisions regarding page width than you could with screen dimensions alone.',
    'developerName' => 'Shaun Inman',
    'developerUrl'  => 'http://www.shauninman.com/'
);
var $panes = array
(
    'Window Width' => array
    (
        'Refresh'
    )
);
var $prefs = array
(
    // Common resolutions widths minus worst-case browser chrome width (56)
    'widthGroups' => '584, 744, 968, 1096, 1344, 1384, 1544, 1624, 1824'
);
var $manifest = array
(
    'visit' => array
    (
        'window_width' => "TINYINT(5) NOT NULL"
    )
);

The $version and $info properties are self-explanatory. This Pepper has a single pane labeled “Window Width” with a single tab labeled “Refresh.” It also has a single widthGroups preference. The $manifest property indicates that a single column named “window_width” should be added to the Mint visit table. The Window Width Pepper doesn’t store any additional data so the $data property is omitted.

Because this is the first version of this Pepper and it doesn’t need to react to updates to Mint, we don’t need to define the onUpdate() event handler or update() method. The isCompatible() method may also be omitted but omission results in a disclaimer being added before the Pepper description in the list of uninstalled Pepper. So we’ll do a quick check to make sure that this Mint installation meets our minimum requirements.

/**************************************************************************
 isCompatible()
 **************************************************************************/
function isCompatible()
{
    if ($this->Mint->version >= 120)
    {
        return array
        (
            'isCompatible'  => true
        );
    }
    else
    {
        return array
        (
            'isCompatible'  => false,
            'explanation'   => '<p>This Pepper is only compatible with Mint 1.2 and higher.</p>'
    );
    }
}

Since PHP is a server-side technology we need to employ some JavaScript to determine the width of the browser window. The following steps are not necessary if your Pepper can do what it needs to do using information already available on the server-side.

The Mint JavaScript object provides a way to prevent collisions with local scripts and pass additional data back to the Mint PHP object. To prevent collisions with other Pepper developers and to utilize the onsave() event handler you need to create your own developer object as a property of the Mint object. If you have more than one Pepper that utilizes JavaScript you’ll need to make sure that your developer object doesn’t already exist before defining it. This is necessary because Pepper are loaded and the Mint JavaScript include is written in the order each Pepper was installed. Also, take care that your code does not interfere with any existing element event handlers (eg. the body onload event or anchor onclick events).

So now we’ll create script.js in our Pepper directory. We’ll use my developer token as the name of the developer object:

if (!Mint.SI) { Mint.SI = new Object(); }

Then we add the WindowWidth object as a property of my developer object and write the onsave() event handler for the new object. The Mint JavaScript object expects the onsave() event handler to return a query string containing &name=value pair(s) that it will then pass to the Mint PHP object.

Mint.SI.WindowWidth = 
{
    onsave  : function() 
    {
        var width = -1;
        if (window.innerWidth)
        {
            width = window.innerWidth;
        }
        else if (document.getElementsByTagName)
        {
            var html = document.getElementsByTagName('html');
            if (html[0].offsetWidth)
            {
                width = html[0].offsetWidth;
            }
        }
        return '&window_width=' + width;
    }
};

Now that we’ve written our script we need to let Mint know to include it by adding the onJavaScript() event handler. The path to our file should be relative to the Mint directory (not the Pepper class file). It should not start with a slash.

/**************************************************************************
 onJavaScript()
 **************************************************************************/
function onJavaScript() 
{
    $js = "pepper/shauninman/windowwidth/script.js";
    if (file_exists($js))
    {
        include_once($js);
    }
}

At this point Mint is aware of the data this Pepper tracks. Using the onRecord() event handler, we’ll validate the width and tell Mint where to store it.

/**************************************************************************
 onRecord()
 **************************************************************************/
function onRecord() 
{
    $windowWidth =  $this->Mint->escapeSQL($_GET['window_width']);
    return array
    (
        'window_width' => (float) $windowWidth
    );
}

The onDisplay() event handler is pretty straight forward in this Pepper. The nested switch statements are present only to comform with the structure of the onDisplay() handler of other Pepper that have multiple tabs and panes.

/**************************************************************************
 onDisplay()
 **************************************************************************/
function onDisplay($pane, $tab, $column = '', $sort = '')
{
    $html = '';
    switch($pane) 
    {
        /* Window Width ***************************************************/
        case 'Window Width': 
            switch($tab)
            {
                /* Refresh ************************************************/
                case 'Refresh':
                    $html .= $this->getHTML_WindowWidth();
                    break;
            }
            break;
    }
    return $html;
}

The getHTML_WindowWidth() function does the heavy lifting here. It is a little different from the getHTML functions of most Pepper since it performs multiple SELECT queries to gather its data. (Take a look at the Default Pepper for an example of typical getHTML functions.) However it is still useful in illustrating how to use Mint’s generateTable() method which takes a specially organized array and returns the HTML table that displays your Pepper’s data.

The array (referrerd to here as $tableData) has three indices, table, thead, and tbody, each containing an array.

$tableData['table'] has two indices, id and class. These values are mapped to the HTML table attributes of the same name. The table index may be omitted (as it is in this example) if the table doesn’t require an id or class attribute.

$tableData['thead'] = array
(
    // display name, CSS class(es) for each column
    array('value'=>'Width','class'=>''),
    array('value'=>'% of Total','class'=>'')
);

$tableData['thead'] contains an array for each column in the HTML table we’re generating. Each array should have two indices, value and class. This is used to generate the table heads. The class index is applied to the <th> and all <td>s in that column.

$tableData['tbody'][] = array
(
    "Greater than $width",
    $this->Mint->formatPercents($r['total']/$total*100)
);

$tableData['tbody'] contains an array for each row in the table. Each row is represented by an array containing an value for each column.

The generateTable() method takes this array and generates an HTML table adding in first-child, only-child, last-child and alt classes where appropriate—ensuring that the CSS has the proper hooks to style the table so a consistent presentation is maintained across all panes.

The last thing we need to worry about for this Pepper is the Preferences. Both preference event handlers are pretty straight forward so we’ll end here with a link to the completed Window Width Pepper.

And this concludes the Introduction to Pepper Development series. Questions? Visit the Mint Forum.

Previous
Pepper Event Handlers and Methods
Next
Champions of Multimedia Design
Author
Shaun Inman
Posted
October 21st, 2005 at 2:26 pm
Categories
PHP
Mint
Web