Posts Tagged ‘PHP’

Styling the HTML5 <meter>

Sunday, July 25th, 2010

HTML5 introduced several new tags, one of my favorites being <meter>, which is used to indicate scalar measurements. However, most browsers won’t do anything fancy with a <meter>.

But for everyone using another browser, we can easily fix that with a little CSS and JavaScript. Basically, we’re going to display each <meter> as a block element, and then insert a <div> element, whose size is determined by the <meter>‘s value attribute.

  1. First, decide how you want your <meter> styled. I opted to use the CSS system colors for a native look and feel, and -webkit-gradient to give it a nice sheen in Chrome and Safari.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    meter {
        /* You can customize the following. */
        background-color: appworkspace;
        border: thin inset menu;
        height: 1em;
        width: 100%;

        /* Leave the rest alone. */
        box-sizing: border-box;
            -moz-box-sizing: border-box;
            -webkit-box-sizing: border-box;
        clear: both;
        display: block;
        overflow: hidden;
        position: relative;
    }

    /* Style the inner bar. */     
    meter > div {
        /* You can customize the following. */
        background-color: highlight;
        background-image: -webkit-gradient(linear, 0% 0%, 90% 0%,
            from(rgb(28, 155, 91)), to(rgb(108, 255, 108)));
        box-shadow: 2px 0 8px grey;
            -moz-box-shadow: 2px 0 8px grey;
            -webkit-box-shadow: 2px 0 8px grey;

        /* Okay, that's enough customizing for now. */
        box-sizing: border-box;
            -moz-box-sizing: border-box;
            -webkit-box-sizing: border-box;
        float: none !important;
        height: 100%;
        margin-left: 0 !important;
        min-width: 1px;
        position: relative;
            bottom: 0;
            left: 0;
            top: 0;
        text-overflow: none !important;
        vertical-align: inherit !important;
    }

    meter.toohigh > div, meter.toolow > div {
        background-color: red !important;
        background-image: -webkit-gradient(linear, 0% 0%, 90% 0%,
            from(rgb(155, 28, 91)), to(rgb(255,108,108)))  !important;
    }
  2. Next, we’re going to use JavaScript to create the bar inside the <meter>. I opted to use the MooTools framework, but if you’re more adept with another framework, it should be fairly simple to port or rewrite my code.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    function updateMeter(m) {
        // Does this meter already have a bar?
        // If not, make one.  Otherwise, use the existing one.
        if (m.getChildren().length == 0) {
            bar = new Element("div");
        } else {
            bar = m.getChildren()[0];
        }

        // Set the bar's width to be a percentage of the meter, based
        // on the min and max values.
        width = m.getStyle("width").replace("px","").toInt();
        if (m.get("min")) {
            width *= m.get("data-value") / (m.get("max") - m.get("min");
        } else {
            width *= m.get("data-value") / m.get("max");
        }
        bar.setStyle("width", Math.ceil(width));
       
        // If we've set the high attribute, and the meter's value is
        // greater than high, give it the class toohigh.
        if (m.get("high")
            && m.get("data-value").toInt() >= m.get("high").toInt())
        {
            m.addClass("toohigh");
        }
        // Same thing, but with the low value.
        else if (m.get("low")
            && m.get("data-value").toInt() < = m.get("low").toInt())
        {
            m.addClass("toolow");
        } else {
            m.removeClass("toolow");
            m.removeClass("toohigh");
        }
       
        // A meter should contain a description of the measurement
        // inside of it.  Move that into the tooltip.
        m.set("title", m.get("text"));
       
        // Inject the bar.
        if (m.getChildren().length == 0) {
            m.empty().grab(bar);
        }
    }
    window.addEvent("domready",function(){
        $$("meter").each(function(m){
            updateMeter(m);
        });
    });
  3. Finally, mark up your <meter> tags. Your <meter> must have at least the value and max attributes set.

    (Note that due to a strange bug in MooTools, I had to duplicate the value attribute as a data-value attribute. It’s still legal HTML5, though. If you choose not to use MooTools, you can omit the data-values.)

    1
    2
    3
    <meter min="0" max="100" low="10" value="40" data-value="40">
        This meter is set to 40%, thankfully;  10% is too low!
    </meter>

To demonstrate this, I needed a good real-world data set. What’s more real world than my own Web server? With a little bit of PHP, I was able to whip together a little server status widget that shows CPU load and memory and swap usage.

Now that’s cool. Google Chrome 6 will do this to all <meter> tags automatically, so you won’t need JavaScript; however, this trick will still work, and (as always) you can still use CSS to override Chrome 6′s stylistic choices.

Eliminating “Page has expired” warnings

Monday, November 2nd, 2009

Every programmer working with PHP session cookies has gotten “Page has expired” warnings from time to time. The most common cause is simple: a user, when a session cookie is set, clicks on the Back button. Because the pages are not being cached, the page has, in essence, expired.

As Chris Shiflett points out in his blog post (which you should read after this), the fix is simple. PHP, by default, sends a Cache-Control: nocache header. To override it, set this header in your php.ini file or with a call to ini_set():

1
session.cache_limiter = private

This will cause the server to send a Cache-Control: private header instead. Restart your Web server, and pages will be cached for three hours by default. As always, test that out and see if it causes problems.

Naming Software

Friday, August 7th, 2009

Naming software has got to be one of the most difficult steps of the software development lifecycle.

This winter, I quickly and single-handedly developed a Web-based help desk software. Clients log in to submit trouble reports, and they can track and edit them as things progress. It also allows them to track their assets. It makes great use of PHP, HTML 5, CSS 3.0, AJAX, geolocation, Google Gears, and more; it’s a balanced mix of tried-and-true and bleeding-edge technology.

The world’s only (known) installation is on my company’s Web server. However, since then, it’s grown by leaps and bounds, but still running on the same spaghetti PHP code; even though it was developed in a rush, if my old college professors could see what I did, they’d revoke my degree.

So, what I’d like to do is clean it up, document it, make it portable, and release it as a free and open-source project. Naturally, the company would sell support contracts, like Red Hat does with Linux — there’s the moneymaking portion of it, enough to please my boss.

However, I just can’t think of a good name. The best name that I came up with is Mercury, eponymous after the messenger of the Greek gods. Trouble is, while “Project Mercury” rolls off the tongue with aplomb, and what I’m calling the development process, it’s not the greatest of names for a final product.

New and returning readers, it’s discussion time. What’s in a name? How do you name software? Have any ideas?