Recursion

One problem I have encountered is that sometimes templates differ, and one person may have paragraph tags inside a form, with input elements inside them. Other people may have another setup, such as all input elements inside the one paragraph tag, except the comment box. Sometimes, I needed to be able to find the form element that was the parent of a particular element, and sometimes this was it’s immediate parentNode, sometimes it was the grandparent node (node.parentNode.parentNode). So I wrote this nice little function that uses recursion to find the parent that is a form. I’m fairly sure it works okay, and there’s even a little check that will return and explicit false if there is no parent form.

    function getParentForm(node){
        if (node==document) 
            return false;
        if (node.tagName!="FORM") 
            return getParentForm(node.parentNode); 
        else 
            return node;
    }

Running JavaScript Before onload.

JavaScript has a pretty neat feature. Lets say I have some functions that need to be run when the page has finished loading. Say, like replacing some encrypted email addresses with the gravatar they are associated with. Since you want all of your JavaScript to remain in the external.js file, and not have to add anything other than the one call to the file in the header of the page, you need a method of knowing when the page has finished loading. By setting up as follows, you can do this:

    window.onload = function () {
        // Put code or calls to functions in here
        SetupStuff();
    }

This has a couple of disadvantages:

  1. If another script called after yours also has an assignment to window.onload, only their code will run.
  2. Alternately, if you are running after another script, you will replace any assignments they have made to window.onload.
  3. This will only be called when the whole page has run, including any images that need to be downloaded.

Various solutions for the second problem have surfaced, including testing window.onload, and appending to it instead of replacing it, but this does not fix either of the other two problems. Another solution is to have a function call at the end of the HTML code, but this could also fail, since the DOM is not yet complete. I have found a better solution, located at brothercake. It’s not really clear how to use it on that page, but the source is straightforward. What I did was include the text of the domFunction.js file, and right at the bottom of the script, included this line:

    var myStartup = new domFunction(Startup);

Right at the top of my code, I have a function called Startup, which contains all of the function calls I want to happen, in the order they need to. Much better than waiting for all of the images to load, even if most of them are cached.

BugMeNot Bookmarklet

Had a good idea for a bookmarklet today: get a username/password for the current domain from bugmenot, and automatically add it into the fields! I’ve got one that pops up a window: [BugMeNot][1], but it would be cool if it interacted with the page.

[1]: javascript:window.open(‘http://www.bugmenot.com/view.php?url=’+window.location, ‘bmpopup’, ‘width=500,height=400,menu=no’).focus(); bmpopup.focus();

Backup Blogsome Posts

I didn’t realize this until the other day, but it’s possible to back up every post you’ve ever made using an offline client, such as the excellent ecto. I use the Mac version of this great program, and to back up every post I’ve ever made is as simple as:

  • Find out how many posts you have made.
  • Tell ecto to download this many recent posts.
  • Press the Refresh button.

The first one is easy: when you first log into your Blogsome blog, you’ll see on the dashboard a panel like:

Blog Stats There are currently 393 posts and 284 comments, contained within 19 categories.

Getting this info to your offline composer might be difficult - each one has different settings. In ecto, choose the Account in the main window (Entries & Drafts), and then go to the ecto→Preferences… menu (keyboard shortcut: Cmd-, ). In the window that appears, choose the Recent Entries tab.

I use the following settings: Store copies of published entries locally, uncheck Retrieve titles and summaries only, and insert the desired number of entries to retrieve. Then, click Save, and press Refresh in the main view. It might take some time if you have a lot of entries, but it’s nice to know you have a backup.

Oh, and if you do regular backups, you can set the value to a reasonable value, like 10 or 20, and make sure you do it every now and then before you’ve posted that many new posts. If you make any edits to old posts, they’ll only get picked up in a large backup like this one, though.

If you are using another client, the instructions will be similar, but you may have to search around for a while before you find where to change the number of entries to retrieve. Good luck: happy backup.

Spooky iTunes Coincidences

I just listen to random music most of the time. But every now and then a weird series of tracks come up. The normal thing is that tracks that we currently have in the car CD player play. But this one tops everything. The Eagles, New Kid In Town comes on, and I switch over to iTunes Rater to rate it, as I like that song. Then I notice this: The title of the previous song was “Johnny Come Lately”, words that are part of the chorus of “New Kid In Town”. Almost as spooky as the bit in Metal Gear Solid 2 where stuff starts going bunkum, and the voice says:

You’ve been playing this video game for too long. Turn the console off now.

This occurred at around 4am, so I was totally freaked. It was right, I had been playing the game for too long. Although this was actually part of the plot (trying to make Raiden(?) believe he is not real), I was convinced.

The Night Is A Blackbird • Augie MarchStrange Bird

Functions Rewrite

I’ve got a bit of JavaScript in my site: Quicktags, Comment Preview, Catchpa and Gravatars, just to name a few of the recent additions. I’ve also got some pretty hairy Smarty Code thrown in there too. Some of it would be better off to be replaced by JavaScript. The two main examples of this are the Time Since code (eg: 22 hours, 34 minutes after the fact), and the _Human Time _code (Posted late at night). I’ve actually rewritten pretty much all of this code, and packaged it all up into one JavaScript, so I can just let other people include one line of code, with some others setting up what features they want, rather than having to wade through the code and find where to add bits. At the moment, most of it is quite functional, but would still require the use of a whole bunch of inline scripting. I’m working to replace this with functions that automatically run after the page has loaded (or, perhaps even better, when the main page has loaded, but before it displays?). So, for instance, you would just have the following code in your main page, inside the <head> section: <script type="text/javascript" src="http://schinckel.net/images/blogsome.jpg"><script> And, then in the templates, include a block of text that looks like: <div class="options" style="display:none;"> gravatar preview quicktags </div> You can have different features on different templates: the one above would make sense on a comments page, but not on others, for example. There will be robust error checking as to validity of particular features and their applicability on a particular page, but only including features you actually plan to use will make the page load faster. This ultimately should make the page load faster than with all of the inline code, and calls to several external javascripts. I think browsers will cache the blogsome.jpg file (it’s really a .js file, but don’t tell anyone), so the initial load time will be reduced on successive page loads. It will also mean I can add or improve features, and fix bugs. The tricky part is turning out to be catering for different layouts: the gravatar part was easy: the only code a user needs to put into their blog is the simple {capture name=reader}{comment_author_email}{/capture} <div class="gravatar">{$smarty.capture.reader|encode:"hex"}</div> Where they want the gravatar to appear, and it will work. Setting up for the Catchpa, which is pretty simple, turned out to be a little sticky. It all depends on how people’s templates are set up: what the structure of their form looks like. It might be easier to have them insert some HTML code, and then look for that. It makes it a little more work for the user, but more reliable.

Enlarge Text Area.

Last update for tonight: <a class='button' onclick='javascript:document.getElementById("the_id").rows+=10;'> Make Text Box Bigger </a> And similar for Make Text Boxes Smaller. It’s working on my comment box as we speak. Try it out. (Thanks to Dunstan).

Posted... (human time display)

Following on from the previous post, I’ve also shamelessly poached another idea from Dunstan: human-readable timestamps. Just pop this into your post.html file, where you want the ‘time’ to appear.

    {capture name=hour}{the_time d="G"}{/capture}
    {assign var=hour value=$smarty.capture.hour}
    Posted
    {if $hour eq "00" or $hour eq "01" or $hour eq "02"}
        in the wee hours,
    {elseif $hour eq "03" or $hour eq "04" or $hour eq "05" or $hour eq "06"}
        terribly early in the morning,
    {elseif $hour eq "07" or $hour eq "08" or $hour eq "09"}
        early in the morning,
    {elseif $hour eq "10"}
        mid-morning,
    {elseif $hour eq "11"}
        late morning,
    {elseif $hour eq "12" or $hour eq "13"}
        mid-morning,
    {elseif $hour eq "14"}
        early afternoon,
    {elseif $hour eq "15" or $hour eq "16"}
        mid-afternoon,
    {elseif $hour eq "17"}
        late afternoon,
    {elseif $hour eq "18" or $hour eq "19"}
        early evening,
    {elseif $hour eq "20" or $hour eq "21"}
        evening,
    {elseif $hour eq "22"}
        late evening,
    {elseif $hour eq "23"}
        late at night,
    {/if}

Time Since (...after the fact).

I had noticed lots of blogs had a nice little Posted x hours, y minutes after the fact tag attached to Comments. I thought this was pretty cool, and had a very short attempt at this some time ago. Then, over on Binary Bonsai, Michael mentioned how the plugin was broken, and how it needs fixing. Well, I didn’t fix the PHP version, but I did write a pure Smarty version!

    {* 
    
    "Time Since" Smarty Code 
    
    Author: Matt Schinckel <matt@schinckel.net>
        http://schinckel.net
    
    Based on a WordPress Plugin "Time Since" 
        http://binarybonsai.com/wordpress/timesince
    
    Notes: Insert this whole text where you want the
    text to appear.  If keen, you could move the first
    pair of lines to a place outside of the comment loop,
    but still inside the post.  This might save some
    precious server seconds.
    
    The accuracy of the 'time since' decreases over time:
    there aren't 30.4 days in every month, for instance.
    
    *}
    
    {capture name=post_time}{the_time d="U"}{/capture}
    {assign var=post_time value=$smarty.capture.post_time}
    
    {capture name=comment_time}{comment_date d='U'}{/capture}
    {assign var=comment_time value=$smarty.capture.comment_time}
    
    
    {assign var=since value=$comment_time-$post_time}
    
    
    {if $since < 3600}
        {assign var=name1 value="minute"}{assign var=sec1 value=60}
        {assign var=name2 value="second"}{assign var=sec2 value=1}
    {elseif $since < 86400}
        {assign var=name1 value="hour"}{assign var=sec1 value=3600}
        {assign var=name2 value="minute"}{assign var=sec2 value=60}
    {elseif $since < 604800}
        {assign var=name1 value="day"}{assign var=sec1 value=86400}
        {assign var=name2 value="hour"}{assign var=sec2 value=3600}
    {elseif $since < 2626560}
        {assign var=name1 value="week"}{assign var=sec1 value=604800}
        {assign var=name2 value="day"}{assign var=sec2 value=86400}
    {elseif $since < 31536000}
        {assign var=name1 value="month"}{assign var=sec1 value=2626560}
        {assign var=name2 value="week"}{assign var=sec2 value=604800}
    {else}
        {assign var=name1 value="year"}{assign var=sec1 value=31536000}
        {assign var=name2 value="month"}{assign var=sec2 value=2626560}
    {/if}
    {math equation='floor(a/b)' a=$since b=$sec1 assign=count1}
    {math equation='floor((a-floor(a/b)*b)/c) a=$since b=$sec1 c=$sec2 assign=count2}
    Posted {$count1} {$name1}{if $count1 != 1}s{/if},
           {$count2} {$name2}{if $count2 != 1}s{/if} after the fact.

Another Gravatar Implementation

I recalled at some stage there was a Smarty Modifier called escape. I think it was when I was looking for one called rot13. Anyways, you can use this and the JavaScript function unescape() to obfuscate the email address. You’ll need this code early in your template: I stick it at the start just after <html>

    <script type="text/javascript" 
        src="http://schinckel.net/images/md5.jpg">
    </script>

This fragment will insert the Gravatar Image:

    {capture name=reader}{comment_author_email}{/capture}
    <script type="text/javascript">
    document.write('<div class="right">');
    document.write('<img src="http://www.gravatar.com/avatar.php?gravatar_id='); 
    document.write(hex_md5(unescape("{$smarty.capture.reader|escape:"hex"}"))); 
    document.write('&size=40" alt="" />');
    document.write('</div>');
    </script>

This seems to more reliably display the Gravatars, so I’d suggest you use it instead. Either that, or Gravatar just fixed up their servers…