This is a blog about Joose and my other mostly JavaScript-related projects. The official Joose homepage is located at Google Code.

Tuesday, October 13, 2009

Joose moves to GitHub

The official Joose repo has been moved to GitHub (Thanks to Nickolay for the work). Looking forward to your code!

Wednesday, September 30, 2009

A DSL for generating HTML with JS

Maybe some people find this interesting. I created a little DSL to generate HTML with JavaScript. Here is an example:
var things = [{text: "Hello"}, {text: "World"}];

with(HTML) {

var html = div({
id: "foo",
content: a({
href: "#",
content: ["test", span("bar")]
})
}) +

div({
className: "baz",
content: map(things, function (thing) {
return p(thing.text)
})
});

alert(html)

document.write(html)
}

Yes, I know, with is very evil but it is cool in this situation.

Here is the full source. I hacked it up in 30 minutes and it is in bad need for a cleanup, but otherwise it seems to work alright.

var HTML = (function () {
function encode(text) {
text = text.replace(/&/g, "&", "g");
text = text.replace(/</g, "&lt;", "g");
text = text.replace(/>/g, "&gt;", "g");
text = text.replace(/"/g, "&quot;", "g");
text = text.replace(/'/g, "&apos;", "g");
return text;
}

function renderAttr(attr) {
if(!attr) return '';
var html = '';
for(var name in attr) {
var value = attr[name];
if(name === "className") name == "class";
if(name === "content") continue;
html += ' '+name+'="'+encode(value)+'"'
}
html.encoded = true;
return html
}

function makeTag (name) {
return function (paras, content) {
if(arguments.length < 2) {
content = [];
}
if(typeof content === "string") content = [content]
var attr = {};
if(typeof paras === "string") {
content = [encode(paras)];
} else if(paras == null) {
content = [];
} else if(paras.content) {
var c = paras.content;
delete paras.content;
return arguments.callee(paras, c);
} else if(paras.length > 0) {
content = paras;
} else {
attr = paras;
}
var empty = content.length === 0 ? true : false;

var html = '<'+name+renderAttr(attr)+(empty ? '/' : '')+'>';
if(!empty) {
html += content.join("");

html += '';
}
return html;
}
}

function map(enumerable, fn) {
var result = [];
for(var i = 0, len = enumerable.length; i < len; ++i) {
result.push(fn(enumerable[i]))
}
return result;
}

var tags = ["div", "a", "p", "span"]

var HTML = {
map: map,
encode: encode
};

map(tags, function (name) {
HTML[name] = makeTag(name)
});

return HTML;
})();

Joose IRC Channel

We'd like to announce that Joose now has a dedicated IRC channel on irc.freenode.org:

#joose

I'm currently working on a large online store project that is using a platform based on server side JavaScript. We use Joose on both the server side and the client side. Very good stuff. More on that later.

Wednesday, August 26, 2009

Running the Bespin command line from the, well, the command line

I felt a little masochistic today which left two possibilities open:
  1. fix IE6 bugs in (pick any project)
  2. program in AppleScript
I chose #2.

The following script will execute it's command line arguments as commands inside bespin (if it is running in the current tab of Safari).
on run argv
tell application "Safari"

set docs to every document

set cmd to ""
repeat with c in argv
set cmd to cmd & c & " "
end repeat

set js to "(function () {if(typeof bespin != 'undefined') { return bespin.get('commandLine').executeCommand('" & cmd & "').output.replace(/]*>/g, '\\n').replace(/<[^>]*>/g, '') } else { return '' }})()"

set out to ""

repeat with doc in docs

set output to do JavaScript js in doc

set out to out & "
" & output

end repeat

out

end tell
end run


Wrap this in a little shell script:
#!/bin/bash
cp bespin.scpt bespin.work.scpt
osascript bespin.work.scpt "$@"

(Don't ask about line two (it is part of the masochism experience :))

... and now stuff like this works:
-bash-3.2$ ./bespin set | grep collab
collaborate = off

Thursday, August 13, 2009

Bringing the awesome JSConf to Europe

@janl, @hblank and @me are proud to announce that we will bring JSConf to Europe!

From the announcement:

JSConf in Washington, DC in April this year proved to be the homecoming of a JavaScript community that didn't know it existed. The conference got top marks all around for content, community and fun. With JSConf.eu, we let that spirit live on and give JavaScript a home in Europe. (why let the americans have all the fun? :)

Mark November 7th/8th in your calendar, we'll be presenting top speakers in the field and a relaxing atmosphere in Berlin, Germany's pulsing capital. Join us for a two-day, community-focussed indie conference with top technical content around your favourite language and great opportunities to meet like-minded people.

Our speakers so far include:
Amy Hoy,
Thomas Fuchs,
John Resig,
Dion Almaer &
Ben Galbraith

I'm really looking forward to the event. See you there!

Sunday, August 2, 2009

Joose 2.1 released

We are proud to announce the release of Joose 2.1

This release is a pure maintenance release with minor fixes and enhancements:
  • Fix a rare issue that occurs with Firefox 3.5 native JSON supports when using Joose.Storage
  • Fix an issue with the Google Gears detection code in Joose.Gears when Gears is installed but disabled in Firefox 3.5
  • Various performance enhancements in heavy used methods
  • Joose.Singleton's singletonInitialize methods now receives the parameters which are passed to the first call of getInstance().
If you are not using either Joose.Storage or Joose.Gears there is no immediate need to upgrade.

Wednesday, July 22, 2009

Google Chrome's Very Incomplete Web Worker Support

In bespin we use a facade that allows us running JavaScript code in Web Workers, Gears Workers and if those are not available in the main thread.

Google Chrome does not yet support Web Workers but since it has Google Gears built in it should use the appropriate fallback. Turns out it didn't with our original code.

I naively implemented object detection to check for the availability of the Worker-object like this:
if (typeof Worker == "undefined") {
For some reason the statement above is actually true in Chrome 2, even though as stated above support for the Worker API has not been implemented.

I then tried to instantiate the Worker object. All this does is to throw an exception with the message "Worker is not enabled". This looks like an unfinished implementation that was only partially removed or something in that direction.

This code handles the special case:
var noWorker = typeof Worker == "undefined" ? true : false;
if(!noWorker) {
try { new Worker("test.js") }
catch(e) {
e = e + ""
if(e.indexOf("Worker is not enabled") != -1) {
noWorker = true;
}
}
}
I'd be very interested why this fragment of the worker implementation was left in the code? Most likely it is a bug but it is questionable whether it will be fixed since the next version of Chrome will actually support the Worker API.