Programming is a wonderful mix of art and science; source code is both a poem and a math problem. It should be as simple and elegant as it is functional and fast. This blog is about that (along with whatever else I feel like writing about).

Tuesday, July 26, 2005

Dashboard Escaper

So I've done a little work on the HTML Escaper I released here a few days ago. While it might be convenient to have a web page open that lets you escape your code for the web, it would be even MORE convenient if you could just do it in a widget. So I've decided to do just that.

The Dashboard Escaper is basically the same program as the HTML Escaper, except that instead of being rendered by your web browser, it is run by Apple's Dashboard.

I decided to make a couple of other changes: there is no longer a button to force it to escape the code. It does it automatically. It escapes the code once per second, and also any time a key is pressed while the source text field is active. I think this automatic, real-time behavior is more suited to the Dashboard concept.

Making the widget was actually quite easy. I already had the web application written, and just wanted to run/display it in a new way. I used a special Dashboard IDE called Widgetarium (link), which contains an editor for your Javascript, HTML and CSS, a widget packager, a Dashboard debugging emulator, and a source level Javascript debugger. Apparently you can insert breakpoints into your JS code, but I haven't tried it yet (I haven't put any Javascript with bugs in it into the editor or debugger).

After downloading Widgetarium and running it, I started a new project. I called it Escaper and went right along.

It asked me for the size of my widget, and I gave it 300x200, as well as the color. It automatically created a PNG to use as the background of the widget.

The widget was now ready to be written. The first thing I did was open Escaper.html. I had to change the line which includes the .js file, because it was including $_NAME_.js instead of Escaper.js. Then I just had to put in my HTML where it directed me to do so ... my Escaper.html looks like this:

<html>
<head>
<!-- The style sheet should be kept in a separate file; it contains the design for the widget -->
<style type="text/css">
 @import "Escaper.css";
</style>
    <script type='text/javascript' src="/System/Library/WidgetResources/button/genericButton.js"></script>
    <script type='text/javascript' src="Escaper.js"></script>

<title>Escaper</title>
</head>
<body onload='setup();'>
    <div id="front" onmouseover='mousemove(event);' onmouseout='mouseexit(event);'>
     <img span="backgroundImage" src="Default.png">
     <textarea id="source" rows="10"></textarea>
     <textarea id="resultcode" rows="10"></textarea>
     <div id="result"></div><!-- need to make this scrollable! -->
    </div>


</body>
</html>


I executed the widget by selecting Run from the Project menu, and my widget popped up in the pseudo-Dashboard in the Widgetarium environment. Unfortunately, it was blank.

I needed to fix this, and I discovered the problem by using the IDE's DOM inspector (on the right hand side of the application). I found that the elements I had defined were off the image, and so would not be displayed. I opened the Escaper.css file and positioned my elements so they would be sure to show up on the widget. Here is my CSS file:

body {
    margin: 0;
}

.backgroundImage {
    position: absolute;
    top: 0px;
    left: 0px;
}

#widgetButton {
    font: 10px "Lucida Grande";
    font-weight: bold;
}

#source {
    position:absolute;
    left:30px;
    top:10px;
}

#resultcode {
    position:absolute;
    right:30px;
    top:10px;
}

#result {
    position:absolute;
    left:30px;
    top:150px;
}


Note that I only wrote the last two rules. The rest are generated automatically by Widgetarium.

Now running the widget shows everything properly. Now I just needed to implement the functionality. Luckily for me, I already had code to do the heavy lifting, which I quickly moved from my old Escaper program into this one.

_$, do_escape, and html_escape were easily added, and I didn't have to change them at all. But remember when I said I didn't put a button in? How is the code going to be escaped?

I wanted to do it once per second, automatically, and then whenever something changes in the source box. So I set up a timer that executes once per second and calls do_escape(). That function is:

function everySecond() {
    if (timerID) {
        clearTimeout(timerID);
    }
    
    do_escape();
    
    timerID = setTimeout("everySecond()", 1000);
}


(Note: timerID must be declared globally.) And to the function to handle keypresses:

function keyPressed(event) {
    do_escape();
}


So I have it all in place, but nothing would happen if I were to run it now. The keyPressed function has to be connected to the onkeypress event, and everySecond has to be called for the first time to start the timer.

function setup() {
    // put your setup code here...
    
    _$("source").onkeypress = keyPressed;
    
    //start checking for changes every second
    everySecond();
}


That was easy enough. I ran it in the IDE, and it worked. I went to the Finder and double clicked Escaper.wdgt, and it opened up in Dashboard and worked there, too.

And there you have it, folks. Basically anything you can do with a web application can be done in a Dashboard widget. And web applications can do most of the the things widgets can do (the difference is that widgets can make system calls that normal Javascript can't). Which you write should depend on the application in question. How do you want it displayed? Who's going to use it? Do you want quick access to it, or should it be open and running all the time? Et cetera.

To do:
  • Make it resize itself automatically, so there is no empty space at the bottom when nothing has been escaped.
  • Make a scrollbar, so that the code doesn't go off the bottom of the widget when it's displayed.

1 comment:

Roberto Iza Valdés said...
This comment has been removed by a blog administrator.