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:

    //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:

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

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

Latest WebKit Build.

I’ve just downloaded the latest WebKit build of Safari, from the Surfin’ Safari weblog, and great news! Finally, Safari/WebKit supports finding the selection in a TextArea. I can now use Safari in the WordPress Dash, and use the quicktags. I don’t need to code my JavaScript for comments to ignore Safari… Yay! This post posted using Safari, and all tags put in by the Quicktags.

Review: Bombshells.

Caroline O’Connor is magnificent in Bombshells, playing at the Adelaide Festival Centre this week. It helps that she has been given a fairly solid play to work with, but her brilliance at bringing the various characters to life is stunning.

The play is a series of apparently seperate stories, but in reality they are all linked, in some way, and we see shades of Six Degrees of Kevin Bacon in finding the links between them.

The story starts with Meryl Davenport, a busy mother - a bad mother, perhaps, who is more worried about what other people will think of her than anything else. Her day is full, and she never gets time to do everything she needs to do.

Jaq assures me that this is what life is like.

This first act is frenetic, and seemed to me like it went on forever. It was my least favourite part of the play, but it was still alright. We see a fleeting glimpse of a neighbour, who grows cactii. And who’s husband has just left her…

…and she is the star of the second act. Tiggy Entwhistle: a disgruntled wife who has found solace in her succulents, and wishes her husband loved her half as much as the cactii do.

The contrast between these two characters is strong. The busy, yuppie mum who doesn’t have time to have a coffee, to the brooding, emotional cactus-lover. Who even looks like a cactus with her furry green outfit. We learn a lot more about this character than the shallow yuppie mother. We learn how her husband has been flirting it up with a floozy. And we taste the bitterness as she finds out about it, via the ‘door-opening’ episode as a Mary O’Donnell was putting up posters for the talent show…

…who we get to know very well in the next act. This character is a bouncy, vibrant (primary school?) girl, who is about to perform in said talent show. We are treated to a lovely performance of Shaugnessy the Cat as Mary prepares her entry. Again, we learn about this character, and her arch-nemesis, who has ‘huge boobs’, and is performing just before her. Of course, said rival does the same song, and our new hero has to find a new song to perform on the spot. Nothing beats Shaft, especially as the cat’s tail becomes a long, black penis. Fun stuff indeed.

We didn’t get out of the seats during the interval. Already we were discussing the play, although I don’t think I had cottoned onto the fact all of the characters were related, as yet. That was all to change in the fourth act, as the bride preparing for her wedding was none other than the sister of the arch-rival from the previous act, Theresa McTerry.

A bride who is more interested in wearing the dress - apparently it’s all about wearing the dress - than marrying the man she is. As it turns out, she prefers the best man, and has shagged him in the past. If only he weren’t so tall…

I missed the connection to the next character, but this one was my favourite. A widow, all she does is hang around with “the widows”. O’Connors characterisation is truly magnificent, and you really believe it is a sixty-something woman up on stage. The sadness, the depth of feeling, and the excitement as something interesting finally happens to Winsome Webster, other than just going out with “the widows”…

…who happened to go to a show at “Star City” and see a washed-up American singer Zoë Struthers making a comeback. O’Connor slides easily into this character, and we again get a glimpse at another life, as she staggers about on stage - a ‘reformed’ alcoholic who can’t get her legs to do what she wants. Still talented as a singer, and even moving down into the audience, where a conveniently empty chair is the prop for a spectacular fall.

The finale was excellent.

As I say, I only missed the one connection. Meryl → (neighbour of) Tiggy → (husband seen by) Mary → (hates sister of) Theresa → (?) Winsome →(went to see) Zoë.

If anyone knows what it is, I’d love to know. None of the reviews I’ve found on the internet seem to have any mention of the connections. They were to me a key part of the cleverness of the play.

So, was there anything I didn’t like about Bombshells? I loved the connection between the characters, but I disliked the need to pretend it was all happening in Adelaide. From the half-dozen mentions of Golden Grove by Tiggy, to the Star City reference by Winsome, each of them implied - or in some cases stated outright - that these events were happening in the local town. With Zoë, part of the mention of Adelaide was a joke (“Nice to be here in… [looks at hand] …Adelaide again.”) But there were a couple of flaws.

Winsome went to read for a blind man, who lived in the inner city suburbs near the University. To put it blunty, there’s nowhere in Adelaide like that. The closest thing would be North Adelaide. But you wouldn’t call North Adelaide the inner city suburbs, you’d just call it North Adelaide. The parklands mean there’s no other suburbs really near the university. Maybe I’m just being pedantic, but I would rather they just didn’t mention any place names, and don’t try hard to make the audience feel warm and fuzzy that all of this stuff is going on in their home town.

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.

    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.

    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.

    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.

    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:

    <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:
    <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:

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

Safari Rendering 0em Text.

Safari spits the dummy when it comes across a text-size:0em; clause in a CSS file. Which is kind of annoying, as it was nice to have zero-sized text, which naturally doesn’t appear, and replace it with an image, which does appear. Saves having to do a node.style.display = "block"; Oh well.

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:

    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.

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:

    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.

    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:

    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:

    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.