Preloading Images

Apparently, it’s possible to use JavaScript to preload images. checked = new Image(); checked.src = "/images/true.gif"; unchecked = new Image(); unchecked.src = "/images/false.gif"; This is better than doing the CSS trick display:none;, as this doesn’t always preload in every browser.

Connections Template

I’ve put the current contents of my template files up on this page. You’ll always be able to find the latest version of my templates there.

Changing Selection

I’ve got an interesting little challenge. I need to be able to programmatically change the document selection, as in the text that is selected, not a select box or anything like that, using JavaScript. Basically, I want to repeat the effect that appears on the Google Adsense site, where selecting in a textarea selects the contents of that text area. But I want to do it with just a random element. It’s easy with a TextArea, but I want my element to maintain it’s lovely formatting. I’m not actually sure I can do it. With IE, I can set it up to copy the text to the clipboard, but not select it.

Interactionless Catchpa

Over on this site, I read about a system that seems to be a bit like mine (only perhaps more complicated). It did give me one idea though: I could automatically populate the value into the box. Or even more simply, have the JavaScript simply fix up the action="" attribute. Then the user just needs to set the action attribute to a whitespace string, and then the JavaScript will make it possible for the reader to submit comments. I’m not sure if this would really be all is needed to prevent Spam comments. Requiring JavaScript to be on… • And trackbacking it gave me another idea: setting the action on a trackback URI to copy the URI to the clipboard. That would be cool. Or making the ‘LinkThis’ bookmarklet get the trackback URI from the page. Should be able to look for a link with rel="trackback", and use the href from this. Okay, this bit works, but again I’ve run into the problem that I’m trying access an ‘off-site’ document. And I cannot do that with JavaScript.

1
2
3
4
5
    var a = document.getElementsByTagName('a');
    var tb = '';
    for (var i=0;i<a.length;i++){
        if (a[i].rel=="trackback") 
            tb=a[i].href;};

That code fragment will get the trackback URI. But there’s no argument I can pass to the bookmarklet.php file that will insert this automatically. Something to add to the Blogsome wishlist, I guess.

Cross Browser Script Up

My script is now up and running, and cross-browser. I’ll leave the Catchpa slightly disabled for the time being so I can test it a bit more on different machines. You’ll also notice a nice little floating toolbar - this is only supposed to appear on the site when a user is logged in, but it seems to be there all of the time at the moment. The script is about 56k, which I think is too big, however I’ve had some issues with the compression utility I was using, so I’ll roll my own solution. It is all in one file again, (easier to manage updating it), and I think the browser caches it, so it should only be slow on the first load. Things I need to do:

  • Set it up so the true.gif and false.gif images are preloaded, so there is no delay on the first time a user clicks on a checkbox.
  • Have a tag in the template for enabling/disabling checkbox replacement.
  • Fix up admin toolbar.

I’m sure there’s probably other stuff I need to do…

DOMContentLoaded and Safari

Often, you will want some scripts to run when the page has loaded, even if the images on it haven’t. I wrote up some stuff about this under Best pre-onload. My full onDOMReady script looks like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
    //Main Startup Code
    
    function checkDOM(){
        if (document.getElementById("footer")
         || document.getElementById("credit")) 
            Startup();
        else
            setTimeout("checkDOM();",100);
    }
    
    if (document.addEventListener)
        document.addEventListener("DOMContentLoaded", Startup, null);
    else 
        setTimeout("checkDOM();",100);

However, Safari will not load pages that use this, since it has document.addEventListener, but does not create DOMContentLoaded events. So, I had to create a nasty little browser check rule:

1
    if (document.addEventListener && (navigator.vendor != "Apple Computer, Inc."))

I’d rather not have to do things like this. Why not?

BugMeNot Auto-Bookmarklet.

I wrote a couple of days ago about a nice little BugMeNot bookmarklet. I have spent an hour or so today coding on that is supposed to grab the data from the window it opens, and enters this into the relevant fields on the page you came from. Unfortunately, I haven’t gotten it working yet. I’ll explain why the parts I need to work don’t as I get to them. This first part is simple: it gets the location of the current page, and also finds the input tags that it needs to add the data to later. More items may need to be added to the user array.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    loc = window.location;
    user = new Array("username","login","userid");
    inputs = document.getElementsByTagName("input");
    for(i=0;i<inputs.length;i++) {
        if (inputs[i].type=="password") {
            pw=inputs[i];
            un=inputs[i-1];
        }
        for (j=0;j<user.length;j++){
            if (inputs[i].name.toLowerCase()==user[j])
                un=inputs[i];
        }
    }

The next part opens a new window with the required URL.

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

This section is the one that fails: it complains about not being able to access the other document (not enough permissions, or something like that). This is because the new document is from another domain.

1
2
    bm_accounts = bmpopup.document.getElementById("accountList");
    acc = bm_accounts.document.getElementsByTagname("dd")[0].innerHTML;

The final section closes the window, splits the data up, and puts it back into the form.

1
2
3
4
5
6
    bmpopup.close();
    
    bm_user = acc.split("<br />")[0];
    bm_pass = acc.split("<br />")[1];
    un.value = bm_user;
    pw.value = bm_user;

So, there are only two lines that do not work. Shame. I also tried using XMLHttpRequest, but that falls victim to the same problem. You cannot access one of these from another domain. It may be possible to create a new frame on the current page, and put the data into there, and then extract what I need, and then close the frame. I’ll look into this.

Updated Toolbox Script(s)

I’ve done a bit more work on the script for all of the extras I like to use on my site. Or rather, scripts, as I’ve split it into several smaller scripts, to make it easier for me to debug. I haven’t decided whether it’s faster in little scripts or one big one, just yet. Anyway, to include the mutli-script version, include the following in your head of your HTML document:

1
    <script type="text/javascript" src="http://schinckel.net/images/toolbox.js"></script>

Anyway, the preferred usage has changed, to allow support for Safari (and possibly other KHTML browsers).

Functions:

  • Gravatars: usage hasn’t changed. Insert the following into your comments.html file: {capture name=reader}{comment_author_email}{/capture} <div class="gravatar">{$smarty.capture.reader|encode:"hex"}</div>
  • Quicktags: those handy little editing buttons to allow easier entry of HTML codes. Since this isn’t supported in Safari, you can use the old method of <!--quicktags-->. I still use this, as it prevents them appearing in Safari.
  • Catchpa: not quite ready for prime-time, as it will be coupled with an edit to the form (removing the action attribute, or setting it to " “), and since these scripts don’t yet support IE, there’s little use using it. If you want to see what it looks like, and how it will stop JavaScript enabled Spammers, use <br id="catchpa" />. The old version, using the comment tag, is still supported, but not in Safari/KHTML.
  • Resizeable Comment Area: puts buttons up for the reader to extend or reduce the length of the Text Area they can comment into. Not really that useful, since they get a scrollbar anyway. But nice. Use <br id="resize" /> where you want the buttons to appear.
  • Comment Preview: my favourite feature. Can be inserted with <br id="commentpreview" /> where you want the comment preview to appear. Optionally, you can put tags in for where the Preview button(<br id="preview" />), and the Live Preview (<br id="livepreview" />) checkbox are to appear.
  • Seperate Trackbacks: if you have the code <br id="trackbacklist" /> (or any tag with this id) then any comments that are actually trackbacks will be moved to here. Each Comment class needs to have the following smarty tag inserted in it: {comment_type}. For example:
1
    <li class="{comment_type}" id="comment-{comment_ID}">

If you already have a class, just put a space between the value you already have and the smarty tag.

  • Human readable post times: if you place your Post times in a structure like the following, then the times will be changed to a phrase that describes the time of day: Posted <span class="post_time"> at: 12:34pm</span>. Note where the Posted is… all of the content inside the span tags gets eaten up.
  • Time Since: you can have your comment times as a certain time “after the fact”, by inserting the following code at the bottom of the comment:
1
    <a href="#comment-{comment_ID}"><span class="timesince" id="{the_time d='U'}-{comment_date d='U'}">on {comment_date} at {comment_time}.</span></a>

The text will all be replaced, but it’s nice to have it there incase someone has JavaScript turned off.

Righto, I think that’s it about it. Still some parts seem to fail on Internet Explorer, but I’ll work on that. Please report any bugs/issues to me, either via email or comments here, so I can try to fix them. That includes anything you notice untoward on this site too, I guess. ;)

Including Another JavaScript

Most programming languages have some sort of an include/import feature: this allows you to have code in one file and reference it from another. JavaScript doesn’t. Most people would say: “Well, just put another <script src=''> in the HTML document”. Well, that’s all well and good, but if I’m creating a framework for others to use, and I want them to have to do as little work as possible, and I’m likely to update the framework in the future, possibly including new features that reference new files, I don’t want to have to get them to do this. Especially if the script is located on my server, and they just reference it. This had kept me to working with one monolithic file: at the moment I have around 36,812 characters in that file, and it’s getting unmanageable. Just to keep SubEthaEdit’s function menu clean, I’ve been assigning anonymous functions to variables: var funcname = function () {return "Spaghetti";} But then, I came across this function:

1
2
3
4
5
6
    function include(src){
        if (typeof include[src] == "undefined") {
            include[src] = true;
            document.write("\n<script type=\"text/javascript\" src=\"" + src + "\"></script>");
        }
    }

You can then just use an include(URI); call to have the other script executed. It’s kind of a hack, but it works, and I like it. Browser independent, too.

Safari Doesn't Parse Comments

Apparently, Safari does not ‘render’ comments in HTML. That sounds silly, but it strips them out. Which means that JavaScripts that use comments as placeholders will fail. Which means I can do one of two things: not support Safari, or rewrite my handlers so they use p, div or span tags, instead of comments. This really annoys me, as it’s much nicer to be able to tell someone to put: <!--catchpa--> into their web page, rather than <p id="catchpa"></p> What other self-closing tags could I use? <br id="catchpa" /> ??? It’s going to mean a significant restructure of my code. But since I’ve learned how to import scripts, that might not be such a bad idea.