Search This Blog

Tuesday, July 05, 2011

Strikethrough in Gmail: At Long Last! (For Chrome and Firefox)


Gmail has come a long ways since I first started using it. However, one feature that is conspicuously absent is strikethrough text, which I often want to use because I'm proofreading someone else's writing and want to show the parts that I recommend deleting.

Now there is a way that I can have my cake and eat it too. If you're using Google Chrome, just click the Install button at Gmail Strikethrough Button. If you are using Firefox, first install the add-on Greasemonkey (if it isn't already installed), restart, then click Install.

Monday, July 04, 2011

JavaScript "Interactive Shell" (like Python) and Variable Hoisting


When I first started working at IWS, there were two teams, the front-end or "Interface" team and the back-end or "Systems" team. I was part of the Interface team writing JavaScript; the Systems team wrote Python. We have now gone to a new approach in development, the two teams merging into a single "Engineering" team. Though most of us have written at least some code in both languages, we've been knee-deep in cross-training.

As part of our cross-training, the new Engineering team has been further divided into "squadrons" of three with team members consisting of both (previous) Python and JavaScript developers working together on small projects. My team includes two Python developers who know relatively little about JavaScript, so the responsibility of catching them up to speed has fallen on my shoulders.

In working with my two teammates, I mentioned the concept of "hoisting" where variables are lifted to the top of function blocks by the interpreter. I also shared with them the PyCon video PyCon 2011: Javascript For People Who Know Python which offers a decent overview of JavaScript for the Python-minded.

The PyCon video suggested two things I want to mention: first, it suggested that JavaScript's behavior has an undeserved reputation for being unpredictable, and second, in the Q&A there was a question asked about an interactive shell for JavaScript. I'll come back to the former in a moment; regarding the latter, the video didn't mention it, but did you know Firebug provides its own interactive shell?

To use Firebug's "command editor" (as it is called), click the arrow next to the Console tab, then select Command Editor from the context menu:

The command editor offers a side window on the right; simply type or paste raw JavaScript and click Run to see the results in the console:

If you don't use Firefox, the MooTools' team has created the excellent JSFiddle, which comes with virtually all the major JS frameworks on board (not just MooTools) and which can be embedded directly in web pages and/or created examples can be saved and linked to: very cool stuff.

Okay, so now that we have an interaction shell, a large step toward understanding the "unpredictable" nature of JavaScript is to understand fully how hoisting works. I've been writing JavaScript for years now, and I'll have to say that if I was given an exam with the two examples listed at the beginning of JavaScript Scoping and Hoisting, I would have failed miserably.

The reason I would have failed is because JavaScript is normally backward to Python or PHP. Defining a private (definition scoped) variable in Python involves nothing more than declaring it in an assignment. If you want it to be global, you have to explicitly use the global keyword, exactly as you do in PHP (except in PHP, a semi-colon is mandatory).

But in JavaScript, if you want a private variable scoped to the function, you have to use the var keyword. If you omit the var keyword, the variable becomes available globally—define a variable without the var keyword anywhere in a script, and it's instantly global. (That said, if you declare a variable using the var keyword outside any functions or classes, it is also global—we might say that it is "private to the global scope" because though it was declared with the var keyword, it was nevertheless defined globally, outside a containing function or class.)

With this var / no var knowledge in place, that's why I would have failed an exam with the two examples from the article above: I did not understand exactly how hoisting worked, and this articles does an excellent job of taking another level of unpredictability out of JavaScript's run-time behavior.

So, check out JavaScript Scoping and Hoisting and put the claims to the test: fire up Firebug's command editor or try out JSFiddle and verify for yourself that the results accord with the claims made, then read the rest of the article to see why the results are counter-intuitive, and, ultimately, highly predictable once you understand what's going on under the hood.

Saturday, May 21, 2011

Balabolka: A Free Text-To-Speech (TTS) Swiss Army Knife for Windows Operating Systems


Let Your Computer Read to You

Typically when I'm home, I've set the company Mac aside and fallen back on a wide-screen Windows PC. I've gotten lazy as I've gotten older: I rather like having the computer read things to me I don't necessarily feel like reading myself. :)

Being read to is especially enjoyable when I'm either working on another task or I want to completely relax without having my eyes glued to the screen.

Enter Balabolka (Russian for "chatterer"), the free Windows text-to-speech (TTS) engine.

Balabolka is easy to use, and works with any TTS voice currently installed on your system (my current preference being "VW Kate"), and the documentation points you to additional voices you can download free of charge.

It supports a range of reading options including text-based documents of assorted types, pasted text, or the contents of the clipboard.

Balabolka has all the features you'd expect without getting carried off to bloat-land. Like most quality software, a lot of the best things about it are its most basic.

Two bread-and-butter features I needed that work especially well include the ability to save MP3s* and to "train" the dictionary to correct mispronunciations.
* In addition to MP3, Balabolka supports seven other file export formats: WAV, OGG, WMA, MP4, M4A, M4B, and AWB.

It also comes with the ability to save ID3 meta information to MP3s (though since I've been using Balabolka to record chapters in audio books, I prefer to bulk edit this info using another first-rate freeware program called Tag Scanner featured in Best Free MP3 Tag Editor).

Other useful features are the ability to have multiple documents open displayed as tabs along the top or bottom (your choice set in Options -> Settings) and the ability to use context menus while Balabolka is reading (both pictured in the screen shot shown above).

Balabolka is an all-around useful program that works well and is easy to use, and it comes in a portable version as well if you want to stick it on a USB drive and go. Just grab yourself a free copy today. Cheers! :)

Saturday, February 26, 2011

How to Minify HTML using PHP and Minify (including final HTML output of PHP files)


Full disclaimer: I did not actually implement this method in the project where I had it set up. I explain why below.

Before Doing Anything Else, Gzip Your Pages!

The first line of defense in reducing the payload of an HTML page is to gzip, or compress, your files. Make sure you have taken that step first if you haven't before doing anything else mentioned here, as that will provide the biggest pay-off.

Benchmark Your Speed, Before and After

I said I didn't implement this method on the particular project I was working on: often after your pages are gzipped, the benefits you get from further compression are either negligible or actually decrease load speed, the very thing you're hoping to improve.

Therefore, testing the speed of your pages before and after minification is advised: there are several free, online solutions available, and I happened to be using Webwait, which I liked because it is simple, does not require registration, and does not place restrictions.

In my case, results revealed that I was actually suffering a slight penalty in load time when stripping whitespace. That said, I have a writing site that has massive HTML pages, and when I have time, I will likely try it again there: I suspect that for very large files, minification by PHP before page load would provide a benefit.

Enough preamble.

Whitespace Removal: Basic Steps

There are several steps you need to take to set it up and get it working.

PHP Check:

First, is PHP already being used to render your page? If so, you're good to go as is—skip this paragraph. If not, does the page have an "htm," "html", or "shtml" file extension and does that extension matter? If the answer to the second question is no, just change your file extension to "php" and if your web service provides PHP you should be good. If the file extension does matter and you're hosted on an Apache server, take a look at Step 4 here on how to give PHP control of rendering your pages.

Note: If your extension is "shtml" and you currently make full use of server-side includes (SSI), you will need to reconfigure your pages to use PHP for the same task or else find a different solution. The beauty is, PHP can do everything Apache's support of SSI can and more.

Basic PHP Function with Associated "Gotchas" Explained:

Now we need to write a PHP function, so let's create a new file called compress_html.php that we include on all our pages we want to minify. Open the IDE or text editor of your choice and create this new file.

Now let's type a simple function.
<?php
// This function is probably too simple to use: It can bite.
function replace_tabs_newlines($content) {
    return preg_replace('(\r|\n|\t)', '', $content);
}
?>
A very simple function like this that strips newline characters and tabs might be all you'd need. The danger with this approach though happens when your site includes any inline JavaScript or CDATA that uses single-line comments (double slashes) or any pre-filled textareas that need to have newline characters for human readability. For example...
<script type="text/javascript">
// click event
myFormElement.onclick = function() {
     this.submit();
};
</script>
...our simple PHP function would cause all the JavaScript below the "click event" comment to fail, because it's just stripping newlines and tabs from the entire HTML page indiscriminately. Once the document gets parsed by the browser, as far as the interpreter is concerned, without the newlines the script tag contains nothing but a big, long comment: // click eventmyFormElement.onclick = function() {this.submit();};. That means, of course, that your click event just died a horrid death.

And if you have any textareas on your page with text already included in them, you'll also see just one big, long string. Probably not what you want.

Wrapper Function Using Minify:

My approach was to use Minify's little-documented and still-experimental HTML minifier instead. Simply download Minify, and check out this page on getting it set up and running.

Once Minify's in place, here's the new and improved, as before assumed to be saved to a file named compress_html.php; there's still nothing exotic about our now wrapper function, and if you know PHP, you could probably write a better one (and if you do, please post it here and share with the rest of us), but this one will at least get your foot through the door.
<?php
function replace_tabs_newlines($content) {
    require_once 'min/lib/Minify/HTML.php';
    require_once 'min/lib/Minify/CSS.php';
    require_once 'min/lib/JSMin.php';
    $content = Minify_HTML::minify($content, array(
        'cssMinifier' => array('Minify_CSS', 'minify'),
        'jsMinifier' => array('JSMin', 'minify')
    ));
    return $content;
}
?>
With some sort of callback method in place (such as the one above using Minify), you've now ensured that JavaScript and CSS at least should get handled correctly.

Serving Minified HTML on a Platter:

Now, simply include in the very top line of the PHP or HTML page you want to minify the following code, which includes the file that contains our replace_tabs_newlines function and calls ob_start:
<?php
// includes are relative to the including file: this example
// assumes compress_html.php lives at the same directory level
// as the file in which you'll include these lines
include('compress_html.php'); 
ob_start('replace_tabs_newlines');
?>
ob_start tells PHP to output any file contents to its internal memory buffer rather than the screen (think "o.utput b.uffering start"—you are turning on output buffering). The "replace_tabs_newlines" tells ob_start to send the raw output from the buffer through the function we just wrote and included in a separate file. Notice the quotation marks—single or double doesn't matter: ob_start expects the function reference to be a string.

Then, at the very bottom of the file after all other code and markup, include the following:
<?php
ob_end_flush();
?>
This does just what it says: it ends, or turns back off, output buffering, then flushes the contents previously held in the buffer either to the screen (if ob_start is passed no callback method) or through "replace_tabs_newlines" (or any other callback method, if one is specified).

Final Check:

View your source code, and you should see that white space and newlines * were stripped before the page was rendered.

That's it! Make sure to test your page speed before and after: Webwait or however. If you are seeing any performance increase, go for it! :)

Update on Getting a Totally Blank Output Page

I host through 1&1, and ran into a caveat when testing this on my writing site (which incidentally did improve speed performance for the large pages): I had to edit the file min/lib/Minify/CSS.php, taking out the three references to Minify in the require_once statements:
// edits made to "min/lib/Minify/CSS.php"

public static function minify($css, $options = array()) 
    {
        require_once 'CSS/Compressor.php'; // removed "Minify/" from the front
        if (isset($options['preserveComments']) 
            && !$options['preserveComments']) {
            $css = Minify_CSS_Compressor::process($css, $options);
        } else {
            require_once 'CommentPreserver.php'; // removed "Minify/" from the front
            $css = Minify_CommentPreserver::process(
                $css
                ,array('Minify_CSS_Compressor', 'process')
                ,array($options)
            );
        }
        if (! isset($options['currentDir']) && ! isset($options['prependRelativePath'])) {
            return $css;
        }
        require_once 'CSS/UriRewriter.php'; // removed "Minify/" from the front
        if (isset($options['currentDir'])) {
            return Minify_CSS_UriRewriter::rewrite(
                $css
                ,$options['currentDir']
                ,isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT']
                ,isset($options['symlinks']) ? $options['symlinks'] : array()
            );  
        } else {
            return Minify_CSS_UriRewriter::prepend(
                $css
                ,$options['prependRelativePath']
            );
        }
    }
Note that (a) I am using the Minify library a directory level deeper (/some_dir/min), and (b) I only ran into problems when including it in files that lived in directories deeper than root, not at the root level itself.

However, I suspect that even if (a) were not an issue, (b) would probably still apply, and since CSS.php physically lives in the Minify directory, there should be no reason that directory should have to be specified at the front of the require_once path anyway, as includes are relative to the including file.

I can also verify that modifying this file in this way works equally well in root as it does any number of directory levels deeper.

* Minify does not necessarily strip all newlines depending on its heuristics and your particular page. If you can be assured that stripping all newlines and tabs will have no effect on your particular setup, you can replace "return $content;" with the return found in the otherwise too-simple first example. Minify will have safely stripped all comments from the CSS and JS and you'll be stripping any whitespace it "missed," but you've still got any pre-populated textareas to consider, inputs Minify knows to leave well enough alone.

Thursday, September 30, 2010

Simple Class-Based JavaScript Fade Animation: An Object-Oriented Reworking

Simple Object-Oriented Fade Animation

Normally, I'd just use MooTools for fade animations, but a long-time client wanted a simple, one-time popup that notified her patients that her doctor's office had moved—a temporary courtesy to be removed in a few months.

To make the custom popup just a little nicer, I wanted a simple fade effect without the extra framework code. Of course, I could have just copied and pasted the methods in MooTools, but I was feeling creative and shopped around to see if any native JS solutions existed.

I found a solution I liked, though it lacks the greater flexibility of a more object-oriented approach. It also sets foreign attributes, FadeState and FadeTimeLeft, directly on the element
<div id="fadeEl" FadeState="-2" FadeTimeLeft="33">
    I am the fade element.
</div>
and passes a spliced-together variable that looks up the same element over and over again: document.getElementById(eid),
setTimeout("animateFade(" + new Date().getTime() + ",'" + eid + "')", 33);
neither of which are optimal.

The logic was there, however, and it wasn't hard to convert into an object. The nice thing about objects is that an object is just that: A flexible model of something that once modeled can be easily reused. So, I revamped the function provided there to make it less intrusive and more modular.

I'd originally posted the following re-working in the comments on that site, but this is a slightly more polished example.

Basic Object

The AnimateFade Class

// declare class so we can use the "new" keyword to create unique instances
var AnimateFade = function(elmOrElmId, duration, state) {
    this.setOptions(elmOrElmId, duration, state);
    this.animate();
};

// prototype its methods
AnimateFade.prototype = {

    setOptions: function(elmOrElmId, duration, state) {
        this.fadeDuration = duration;
        this.element = (typeof elmOrElmId == 'string') ? document.getElementById(elmOrElmId) : elmOrElmId;
        this.fadeState = (state && state == 1) ? 1 : 0;
        this.fadeTimeLeft = duration;
        this.lastTick = this.newTick();
    },

    newTick: function() {
        return (new Date).getTime();
    },

    getElapsedTicks: function() {
        return this.currentTick - this.lastTick;
    },

    animate: function() {

        this.currentTick = this.newTick();

        var self = this;
        var elapsedTicks = this.getElapsedTicks();

        // helper function, called in the timeout below,
        // recurses with correct reference to "this"
        var helper = function() {
            self.animate();
        };

        if (this.fadeTimeLeft <= elapsedTicks) {
            this.element.style.opacity = this.fadeState;
            this.element.style.filter = 'alpha(opacity = ' + (this.fadeState * 100) + ')';
            return;
        }

        this.fadeTimeLeft -= elapsedTicks;

        var newOptVal = this.fadeTimeLeft / this.fadeDuration;

        newOptVal = (this.fadeState == 1) ? (1 - newOptVal) : newOptVal;


        this.element.style.opacity = newOptVal;
        this.element.style.filter = 'alpha(opacity = ' + (newOptVal * 100) + ')';

        this.lastTick = this.currentTick;
        this.currentTick = this.newTick();

        setTimeout(helper, 24);
    }
};

// initializer function
var init = function(elmsOrElmIdArr, duration, state) {
    for (var i = 0, l = elmsOrElmIdArr.length; i < l; i++) {
        // "new" keyword creates unique instance
        new AnimateFade(elmsOrElmIdArr[i], duration, state);
    }
};

Instantiations

Single/Multiple Elements, Single Duration and Fade State

To instantiate with one or more elements that will all fade in or out for the same duration:
// pass in either string id or element reference

// Example A: fade just one element
var myOnlyElement = ['myUniqueId'];

// Example B: fade multiple elements
var myMultElms = ['myId', document.getElementsByTagName('div')[7], 'anotherId'];

// how long fade should last
var myDuration = 1000;//1,000 milliseconds, or 1 second

// start fading out
init(myMultElms, myDuration);
// or fading in
init(myMultElms, myDuration, 1);

Multiple Elements, Durations, and Fade States

Or retool the initializer function...
// initializer function capitalizing on parallel arrays
var init = function(elmsOrElmIdArr, duration, state) {
    for (var i = 0, l = elmsOrElmIdArr.length; i < l; i++) {
        // "new" keyword creates unique instance
        new AnimateFade(elmsOrElmIdArr[i], duration[i], state[i]);
    }
};
...to take full advantage of arrays, simultaneously fading multiple elements in and out for different lengths of time:
// set parallel arrays
var myElms = [elm1, elm2, elm3];
var myDurations = [1000, 2500, 300];
var myStates = [0, 1, 0];

// start effects
init(myElms, myDurations, myStates);

// elm1 fades out in 1 second
// elm2 fades in in 2-and-a-half seconds
// elm3 fades out in 3/10ths of a second
This could be useful if you wanted to fade in one set of elements while simultaneously fading out another set, perhaps a confirmation dialog and its acknowledge that the user's choice has either been implemented or canceled. Or whatever.

Friday, August 06, 2010

Make Caching Less Aggressive in Firefox on Development Machines

I have been having some issues with Firefox caching files too aggressively on my development machine at work: not good when you write client-side code.

My first attempt to resolve the issue was to disable caching entirely using the Web Developer toolbar (Disable > Disable Cache). However, that is not optimal, as every page resource gets downloaded every time you refresh the page.

So I did some reading up, and, just as I suspected, there is a Firefox configuration setting that forces a 304 request each time you refresh the page. This solution is superior to disabling the cache, as only resources that have changed are downloaded again.

If you have caching problems (or you're concerned that you might), you'll need to change a value in Firefox's "power-user" configuration settings. Here's how:
  1. Open a new tab, type about:config into your address bar, and promise Firefox you'll be careful. ;)
  2. Enter browser.cache.check_doc_frequency into the filter field.
  3. Change the value from 3 to 1, which tells Firefox to check the server for updated resources on every refresh.
Further Information: For the full reference see here, and for a list of the seven hidden pages in Firefox, see The Seven "Hidden" Pages.

Thursday, July 01, 2010

Complex CSS3 Expressions in MooTools: Reference Guide


In addition to standard CSS expressions . . . Selectors.js also allows you to select on element properties such as name, value, or href using standard CSS3 expressions (see http://www.w3.org/TR/css3-selectors/#attribute-representation).

Example:

// All the mail-to links on the page:
$$('a[href^=mailto:]');
The following expressions are supported:

= The property is equal to the value.
^= The property begins with the value.
$= The property ends with the value.
!= The property is not equal to the value.
*= The property contains the value.
~= The property is found when the value is split on spaces (so ~=foo matches “blah foo bar” but not “blahfoobar”).
|= The property is found when the value is split on dashes (so |=foo matches “blah-foo-bar” but not “blahfoobar”).

Here are a few more examples:
// All the inputs where name equals 'email'
$$('input[name=email]')
// All the images with urls that end in .gif
$$('img[src$=gif]')
// All the links without target="_blank"
$$('[target!=_blank]')
Note that these expressions can take double or single quotes when you want to search for something that has a space or other character:
$$('input[name!="user[username]"]')
$$('img[src$=".gif"]')

Source: Newton, Aaron. MooTools Essentials. Apress, 2008. 106–107.