New Script Online

Note: there is a newer post you should read instead of/as well as this one: Updated Toolbox Scripts. I’ve finished the Mozilla part of the new script: I think there’s some issues with Internet Explorer, and Safari, but I’ll work on those over the next week. You can use the script by including the following code in the head section of your main page template: <script type="text/javascript" src="http://schinckel.net/images/toolbox.jpg"></script> And then, where you want the following tags, enter them: <!--quicktags--> <!--catchpa--> <!--commentpreview--> <!--resize--> If you put the following inside your comment area, a gravatar will appear for each commenter: {capture name=reader}{comment_author_email}{/capture} <div class="gravatar">{$smarty.capture.reader|encode:"hex"}</div> There’s also the functionality to change post and comment times to a more human readable form: <span class="post_time"> Posted at: 12:34pm</span> Comment times are a bit more difficult: they require a time difference. Getting this on Blogsome is cumbersome at the moment, so I’ll write up a better way of doing it later. At the momement it uses the value obtained through a complicated {Smarty} expression. If you are really desperate, you can find this expression elsewhere on this blog, and put it into a tag as follows: <span class="timesince"><!--{$since}--></span> I’ll write it up so you can just put in <!--{the_time d="U"}-{comment_date d='U'}-->, but that won’t be for a day or so. The other feature I have added is automatic: I’ve got seperate Comments & Trackbacks, and the script will automatically hide whichever one is empty, if the other one isn’t. I will write up a way to seperate Comments & Trackbacks using DOM management, but, again, not right now. Finally, all of the stuff on this page could seriously screw with your template/browser. It is still in beta, and doesn’t work at all in some browsers. I did kill a bug that caused a hang on Firefox Mac, but there may be more of them. Make sure you have a backup of your template, and don’t do this unless you know how to fix it up…

Best pre-onload

I’ve been using domFunction() to determine whether it’s safe to do all of my DOM modification code, but with some testing, I noticed that some pages were causing Firefox to eat up huge amounts of CPU time. I tracked the error down to the domFunction call, as it uses setInterval() to run a function every n seconds. This in itself is nice to know (I was looking for a similar feature a couple of days ago), but the nice part is that it has a stopping function: clearInterval(). You are supposed to use it like this:

1
    timer = setInterval("Function();", interval);

This will then call the function Function every interval milliseconds. Neato. Except I only want a particular thing to happen once. So, as a part of my code, I was calling clearInterval(timer) inside a function called by Function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
    function Startup(){
        Gravatars();
        .
        .
        .
        HumanTimePosts();
        
        clearInterval(timer);
    }
        
    //Code for all functions in here.
        
    timer = setInterval(function(){
        if (document.getElementById(\"footer\")){
            Startup();
        }
    }, 1000);

Which should work. Except for some reason, calls to clearInterval cannot come from inside functions called by setInterval. Or something like that. My next solution was to use:

1
2
3
4
5
    function checkDOM(){
        if (getById("footer")||getById("credit")) Startup();
        else setTimeout("checkDOM();",100);
    }
    setTimeout("checkDOM();"

Which solves the problem, but it ugly. Finally, I came across this little number:

1
2
3
    if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", Startup, null);
    }

This only works with Mozilla browsers, so for the time being I’ve combined the last two.

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.

1
2
3
4
5
6
7
8
    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:

1
2
3
4
    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:

1
    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();

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).

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>

1
2
3
    <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…

Quicktags Update

Note: The seperate Quicktags toolbar is not supported. Please use the full toolbox script, or hack it any way you like. The remainder of this post remains for posterity only. • I’ve combined my two quicktags scripts into one, it now has an (optional) argument to the edToolbar(); function. If you pass it the argument of ‘Link’, then it will render the toolbar as a series of <a href="javascript:..."> links, rather than the buttons that it defaults to. You can get it from here. Or use the code <script type="text/javascript" src="http://schinckel.net/images/quicktags.jpg> </script> <script type="text/javascript">edToolbar(); </script> in your page, where you want the toolbar to appear, and <script type="text/javascript"> edCanvas = document.getElementById('comment'); </script> after the TextBox you are using to have comments in (make sure it’s id is comment, or change the second script.

Instant Preview in Mozilla Browsers

I’ve noticed that the Preview code that both the WordPress Dash, and my Comment Preview uses (okay, I stole it from there!) is really slow - read as unusable in Instant Preview mode - under Mozilla browsers (on Mac, at least). There is a noticeable lag between typing and the characters appearing on the screen, in the Text Box, let alone in the Preview Box. I wonder if it would be possible to rewrite the script so that it wasn’t onkeyup, but every 5 seconds, or something like that. Or possibly make it so it doesn’t redraw the whole lot? Perhaps the best would be that it only redraws when keys have been pressed, but not in the last 3 seconds. I’m not sure if any of these can actually be done!