Skip to content


Experiment: Ruby-style function auto-calling in Javascript

I have no clue what it’s called when ruby automatically runs a function.
After not totally understanding def.js and looking at this coffee-script issue from the cappuccino github issues browser. I had a horrible idea.

Function.prototype.valueOf = function(){return this()}

What does it do?

function getValue(){
return 42
}
if(getValue == 42){
alert('fortytwo')
}else{
alert('not fortytwo')
}

Notice notably absent in the if statement are the expected parentheses ‘()’ needed to call them. It gets stranger still.

alert(getValue == 42); //true
alert(getValue() == 42); //true
alert(getValue() === 42); //true
alert(getValue === 42); //false
typeof getValue() //number
typeof getValue //function

var sample1 = getValue;
typeof(sample1) //function

var sample2 = getValue();
typeof(sample2) //number

One advantage is that it makes a super hacky/semi-working implementation of getters that should work universally (maybe). Except that it doesn’t. It’s practically useless.

Posted in Uncategorized.

Tagged with , , .


Javascript Templating Engine

Well, there are a bazillion other JS templating engines out there, and it’s pretty easy to say why: It’s really easy to make. You just take a regex string replace and stick an eval in there and hours of boredom makes something you think is unique despite being one or two bits of (non)functionality away from any other library.

This is, of course, totally un-unique or innovative in any imaginable way. I won’t bore you with concepts like “lightest and smallest ever” because it’s really not.

//this might be close .replace(/\{(.*)\}/g,function(a,b){return eval(b)}) 

However, I feel compelled to do something utterly non-innovative or useful because everyone loves the NIH (Not Invented Here) syndrome.

Code is prefixed by the @ symbol, similar to Microsoft’s WebMatrix Razor stuff. It’s not modeled after Razor, but I just felt like using the @ symbol too. Or that microsoft planted an inception.

Blocks are like this: @{+new Date}

Anything can go inside blocks pretty much, and they can be multiline. @{ var now = (new Date).getTime(); var random = Math.random() * Math.pow(10,Math.floor(Math.log(now)/Math.log(10))); var magic = random – now; for(var i = 0; i < magic; i+= 42){ magic -= Math.PI; } magic }

Take note about how amazingly awesome it is that despite being regexp powered, it can still handle the nested for-loops instead of puking it as a syntax-errored explosive somethingness.

The last non-whitespace line gets inserted into the html. You can optionally use ‘return magic’ but that doesn’t really do anything more except look more verbose. If you really just want to have code there for some reason, you can end it with ” @{ //do stuff ” }

Of course this is all boring. You can also do a shorthand notation. @name

This inserts the value of the variable “name”. There are a few rules about the shorthand notation. @name //interpreted as @{name} @name game //interpreted as @{name} game \@name blame //not interpreted at all, outputs as “@name blame” @games_are_fun //interpreted as @{games_are_fun} @name=”bob” //interpreted as @{name=”bob”} @explosive?’run’:’poke’ //interpreted as @{explosive?’run’:’poke’}

If you don’t want to end it with space, you can also end one with a semicolon;

Basically, it scans starting from an @ sign (unless the character immediately before is a \ which causes it to remove the \ and not parse the @). It includes everything until it encounters a whitespace character.

However, like any rule, there are exceptions.

@format_time(date + 2 - 5/64) //interpreted as @{format_time(date + 2 - 5/64)} @blah(234 + 2) + 45 //interpreted as @{blah(234 + 2)} + 42 @blah(234 + 2)+45 //interpreted as @{blah(234 + 2)}+42 @blah(234+2)+45 //interpreted as @{blah(234+2)}+42 

Note that the last three examples demonstrate a sort of unexpected behavior. The function call pattern takes precedence over the include-until-whitespace behavior, because I dont really feel bothered by it and don’t feel like fixing it.

And if you don’t feel like doing JS stuff, you can also do some neat things like ifs and loops

@explosive? OH NOES! <strong>RUUUNNN</strong> @else Well, i guess it's safe. <em>let's poke it!</em> @/ @if(boom) No comment. @end 

Here you can see that there are two ways to start an if. You can postfix it with a ? or you can start it with if(condition). This probably won’t ever be useful, but the latest if value gets saved to the @_ifval value.

There are also two ways of ending a block. You can @end or @/. Both are the same, but one’s shorter.

What about looping arrays and objects? It can do that too.

@each(numbers, number) @number is a magical number, presumably a real number. @/ @each(pets, name, index) Aww, look at how cute @name is! He is my @index+1;'th pet @/ @each(new Array(50)) SPAM @end @each(users, password, username) The password of @username is @password @/ 

Note that the loop terminators are the same as the if terminators. Neat isn’t it.

So now that I’ve demonstrated there’s nothing interesting about this solution, go on and leave this document before I explain to you something that’s utterly useless and that you shouldn’t use.

Probably the most distinguishing feature is something I call blocks. That’s probably a really really bad name and it probably will get people confused with other things, but as the name of this library is “templating” I can’t imagine anyone who didn’t find this expected. I haven’t even hung around the guys who make Prototype or Closure.

So. Blocks. They’re an okay-ish feature that allows for event-based updates of certain sections of the template after the initial rendering. It’s a feature that doesn’t even belong as part of the templating engine, so it sort of isn’t. It’s part of the execute() function, which doesn’t really count as the templating engine. That’s the function which takes your variables and code sticks it through templating, and evals() the result. It also handles blocks.

@time.span{{{ //har har har i love puns It is now @format_time(+new Date) }}} @{ setInterval(function(){time()},1000) '' } 

Here we see a block being created, and a piece of attached js which updates the block every second. But blocks can also have triggers that aren’t just timeouts and other boring stuff.

<a href="#update_time" onclick="@{{{ time(); }}};return false">Update the time</a> 

The way blocks work are pretty simple. It basically creates a function out of the compiled template and then it associates it with a function in the scope of the template. It wraps a

or (based on whether the block name ends with .span or .div or .bacon) and gives it an ID of a random number. This random number is stored in the scope of the template.

When the associated update function is called, it looks up the associated ID number and tries to do a document.getElementById and re-executes the template in the previous scope and then replaces the innerHTML. Basically enabling live templates.

Its all 3KB before gzip (minified). Not that bad, but still, compared to fifty four bytes in the code from the introduction, it’s huuge.

Possible changes:

  • name.el_id.interval{{{ }}} block notation for auto updating chronologically. Probably useful for the twitter/facebook style real-time relative dates.

Posted in Uncategorized.


Flash-based CamShim-based HTML5 Capture API-ish Shim

It doesn’t truly cover the entire capture api. In fact, all it covers is the first example they give on using the navigator.device.captureImage function. I can’t even figure out if that even complies with the rest of the spec because they seem to be accessing a uri property of MediaFile, which is only defined as an object that extends inherits from File with the extra “format” attribute.

https://github.com/antimatter15/CaptureShim

Posted in ShinyTouch, Touchscreens.


ShinyTouch/OpenCV

I have yet to give up entirely on ShinyTouch, my experiment into creating a touch screen input system which requires virtually no setup. For people who haven’t read my posts from last year, it works because magically things look shinier when you look at it from an angle. And so if you mount a camera at an angle (It doesn’t need to be as extreme as the screenshot above), you end up seeing a reflection on the surface of the screen (this could be aided by a transparent layer of acrylic or by having a glossy display, but as you can see, mine are matte, but they still work). The other pretty obvious idea of ShinyTouch, is that on a reflective surface, especially observed from a non-direct angle, you can see that the distance from the reflection (I guess my eighth grade science teacher would say the “virtual image”) to the apparent finger, or “real image” is twice the distance from either to the surface of the display. In other words, the reflection gets closer to you when you get closer to the mirror. A webcam usually gives a two-dimensional bitmap of data (and one non-spatial dimension of time). This gives (after a perspective transform) the X and Y positions of the finger. But an important aspect of a touchscreen and what this technology is also capable of, a “zero-touch screen”, is a Z axis: the distance of the finger and the screen. A touchscreen has a binary Z-axis: touch or no touch. Since you can measure the distance between the apparent real finger and it’s reflection, you can get the Z-axis. That’s how ShinyTouch works.

Last year someone was interested and actually contributed some code. Eventually we both agreed that my code was crap so he decided to rewrite it, this time using less PIL and pixel manipulation, and instead, opting for more OpenCV so it’s faster. The project died a bit early this year, and with nothing more to do, I decided to revive it. His code had some neat features:

  • Better perspective performs
  • Faster
  • Less Buggy
  • Simpler configuration (track bars instead of key combinations and editing JSON files)
  • Yellow square to indicate which corner to click when callibrating (actually, I wrote that feature)

It was left however, at a pretty unfinished state. It couldn’t do anything more than generate config files through a nice UI and doing a perspective transform on the raw video feed. So in the last few days, I added a few more features.

  • Convert perspective-transformed code into grayscale
  • Apply a 6×6 gaussian blur filter
  • Apply a binary threshold filter
  • Copy it over to PIL and shrink the canvas by 75% for performance reasons
  • Hack a Python flood-fill function to do blob detection (because I couldn’t compile any python bindings for the opencv blob library)
  • Filter those blobs (sort of)

Basically, it means ShinyTouch can now do multi-touch. Though the Z-axis processing, which is really what the project is all about still sucks. Like it sucks a lot. But when it does work (on a rare occasion), you get multitouch (yay). If TUIO gets ported (again), it’ll probably be able to interface with all the neat TUIO based apps.

Code here: http://github.com/antimatter15/shinytouch/ Please help, you probably don’t want to try it (yet).

Posted in ShinyTouch.

Tagged with , , , , , , , , , , , , .


Fluidizer: fixed width → fluid width bookmarklet

Yaay, fluid width!

I IZ NOM NOMMING ON HALF UR PIXELZ

This is another old one, something I made february fifteenth of this year.

One of the purely theoretical things that have always annoyed me, were fixed width themes. Because I love being a hypocrite, this blog right now is using a fixed width theme. Though I probably could make up an excuse, like to serve as a decent test case for Fluidizer in part of my grand scheme detailed via embedded steganographic messages inside all of my screenshots. Of course that’s all a lie (however much I would like otherwise).

It’s always bothered me how some web sites have these fixed-width layouts, sometimes with insanely thin boxes allocated to content. The vast majority of my screen becomes this orange blob of text. Chrome’s visual appearance motto is “Content not chrome”. That doesn’t help if the content is being obscured by the presentation of the content (gopher might have solved that problem). Less chrome just means my eyes start to drown in +/- 1,732,405 pixels of orange. Even outside the extreme case, having a fixed-width layout isn’t efficient, and using something like Readability to only show the content removes the personality of the site or author, and only works on articles.

Fluidizer automatically resizes themes semi-pseudo-intelligently, and works with a lot of themes. It has several algorithms it uses, which are sort of alchemy-like and strange. I have no clue how it works, but there’s lots of strange stuff that goes on to magically do stuff. I think it even somehow has a CSS parser that uses CORS to load css through a server-side proxy.

Only tested in Chrome: Fluidize

Posted in Design, Fluidizer.

Tagged with , , , , , , , , , , .


Multicore Javascript Pi Computing with WebWorkers

http://antimatter15.github.com/pi/partial.html

It’s not using the fastest algorithm, but the nice thing about this one is that it’s capable of digit-extraction (calculating one section without knowing the digits before it) and was nice for doing distributed computing. This also has the nice side effect of working pretty well with the MapReduce paradigm (To calculate a block, calculate primes 3 to 2*N, map it all to the magical pi algorithm and then add it all up and truncate the fractional part, however it doesn’t really use MapReduce because there aren’t enough machines/threads to make it really necessary to distribute out the reducing part). So on the time-memory tradeoff scale, this algorithm uses low memory and is slower, which makes it pretty good for the purposes of something implemented with WebWorkers as I can’t imagine it would be good to have the same data multiplied by the number of threads and having lots of data being passed with each postMessage.

Posted in Javascript Distributed Computing.

Tagged with , , , , , , , , , , , , , .


A Bright Coloured Fish: Parsing ID3v2 Tags in Javascript (and ExtensionFM)

Stolen from wikipedia

After having fun reinstalling Ubuntu, only to get extremely bored by the newfound stability and familiarity of 10.04, I upgraded to the Maverick Meerkat, where I was greeted by a friendly GRUB error. After consulting the Live CD a few times, I got into a normal desktop. Then I proceeded to install the two apps I ever use which aren’t included in Ubuntu: Chromium and Shutter (Maybe you could include git as well). After a bit of dismay as it seems Chromium didn’t sync extensions as advertised,  I proceeded to reinstall my extensions. At least the issue where I couldn’t delete bookmarks was resolved.

It was also a neat opportunity to try out some new things, one of them was Neat Bookmarks after finding out that –bookmark-menu didn’t work (I only found it ever existed when it was announced that it was removed, though), which has a far prettier icon than some other bookmarks menu addon I had previously.

Another extension I tried out was Extension.FM. I’ve heard of it a while ago, but I never actually installed it for some reason, and there was a post on Ajaxian on it recently so I decided to try it out. The interface was neat (I knew that beforehand). I have an interesting (maybe not so much), system for storing my music on a local networked server (in my basement). So I went to it’s apache URL and browsed to the file location. ExtensionFM loaded it all and stuck it into my library (as advertised), but all the cover art, song name, album name and artist information was missing! Oh noes! Obviously it was missing ID3 data.

The great thing about Chrome, Firefox and Greasemonkey extensions, is that the source code is practically open to anyone who uses it. View source or otherwise, you can always get at it and hack stuff to make things right (ignoring the legal implications that ruin innovation). Some people think that there needs to be more done to secure the author’s source code from the user’s prying eyes, but that could not be further from the case. Hopefully this will be a case for why the source code should be exposed to the user.

So, after finding the location, which wasn’t the easiest thing as Chrome gives them these folder names based on a random generated public key which gives *no* hint on what the contents are. But as I only had a few plugins, getting ~/.config/chromium/Default/Extensions/ehohhddamheegbbkabfgegbaeminghlb/1.4.9_0/js wasn’t too hard. I found sound-parser.js and looked a little into it, and lo and behold, no ID3 parsing!

That’s probably expected as ID3v2 is a binary format, and JS was never that great at handling binary. I knew that there was an ID3v1 parser. But I wasn’t aware of an ID3v2 parser at the time, it seems that there is one that a quick google search would have saved me hours yesterday. So after implementing the spec, and googling several times why Picture Type $11 is “A bright coloured fish”, I hacked it onto song-parser.js and through means detailed here, I got ID3v2 support in ExtensionFM. So yay, now what was missing: cover art, album name, song title and artist now all work :)

Anyway, the project for the ID3v2 parser (mine, the one you shouldn’t use), is on github at http://github.com/antimatter15/js-id3v2. If you want a neat little online demo, just go to the URL below. I wouldn’t suggest any browser other than the Chromium nightlies or possibly Firefox 4.0 to view it as it relies on multi-file input and FileReader. Basically, this is how you use it: Press <Browse> and multi-select all the music that you have, and automagically, it reads it and parses ID3v2 data (all locally, mind you, so your secret collection of pirated music is not going to be sent to me for forwarding to the RIAA of your jurisdiction). It’s then shown at a 5 second slideshow. Cover art (if not present in the song) is of a probably copyright-infringing image of a sad fish that google referred me to because of this interesting fish theme.

http://antimatter15.com/misc/js-id3v2/id3v2.html <– Live Demo, you probably want to click it if you tl;dr’d this whole post.

Posted in MP3 ID3v2 Parser, Multimedia Codecs.

Tagged with , , , , , , , .


Deep Integration Wave Embed API

Can you tell that the screenshot on the left is actually an embedded wave? Probably not.

First, a little overview on what this is. A lot of people are interested in using Google Wave as a commenting system, however the official embed api at the current state suffers from several shortfalls. It’s tedious to operate a wave-integrated commenting system. As an author, you have to manually create a wave for every post, copy the content over to the wave, get the wave ID, and paste it into your template. Every time you change your post, you have to yet again manually sync the page with wave. Once you’ve gotten the wave into the page, the embedded wave itself has a few issues. You can’t style it using CSS, and you can only change the background color and font. The width can’t adjust to the width of your page after the initial load. There’s no way to get rid of or change the style of the huge blue border around it. It forces it’s own scroll bar which looks nothing like anything else on the page and prevents intuitive navigation of comments using the same scrollbar as the rest of the page. Lastly, there’s no way for anonymous readers to comment on the post.

For each of these issues, the new w2_embed api offers a solution. Instead of using iframes to hack another page onto the current one, this one is built into the page, injecting elements directly onto the page’s DOM. These elements can be styled in nearly any imaginable way through CSS and HTML. The sandboxed and namespaced single-function API allows for multiple waves on one page with less than 10KB of JS overhead (Compare to about 1.4 megabytes). Instead of relying on a special Wave ID, the app uses a centralized and remotely stored database which associates any identifier you provide with functional wave IDs. That means, that instead of using a string like googlewave.com!w+Blsm0RMW_A, you have the URL of your blog, say 2010/06/wave-embed-api. Not only that, but it can automatically pull the title of your wave, the authors, the permalink and tags from the post, automatically create a wave from that with the same tags and title with the content automatically set as the root blip as well as a permalink back to the blog post. When viewed from wave, the user can follow, unfollow, search and find waves using the exact same familiar interface. On your blog, you can make the wave backend entirely seamless and subtle. Since it’s built on top of Anonybot, people can reply blips without having google wave accounts right from your blog.

It’s all part of a new embed API built upon Anony-bot (which itself is built upon microwave, which is built on wave reader, which is built upon the prototype python desktop client… Someone should make a wordpress plugin for this to make this family history even longer).

The last post noted the beginning of this project, and here is part two. The API has been cleaned up a lot. The code has been simplified. Features added and design changed.

The major change is a total decoupling of it and the mainline Anonybot codebase. There are some major implications of the change. In the original prototype of the API, it still had the iconic blip context menu inherited from microwave. That’s gone. So is the participants bar, link to real wave client, blip html, blip content, reply box, and everything. There are now no required or automatically added html/dom elements. Everything is specified through a simple HTML templating engine. Since the code isn’t shared, changes from each individual project now on probably won’t be instantly applied to both. This has advantages and disadvantages. On the plus side, is that changes to anonybot won’t break the embed api. However, bug fixes on one may not propagate to the other.  The code can be much smaller since features like search, which was previously hidden, can now be totally removed. Also, since it’s been rewritten from scratch as an embed api, it no longer exposes any extra globals and multiple embeds can be done for each page.

The biggest change is the templating engine. Before, it only worked with the blip design, but now it’s totally integral to every aspect of the interface. Lets walk through the basics of the API, starting with a minimal example.

All the content is wrapped in a huge hidden div, and inside is one element with the wavebody class. That huge wave is the scope of the templating engine. That means that if you put {{1+1}} anywhere inside the div, it’ll show up as 2. Place it anywhere outside the div, and it shows up as {{1+1}}. Simple, right? The wavebody element is where the actual blips will go. But since there aren’t any blips beforehand, wavebody is filled with the template for a single blip. The content gets multiplied several times and that makes the wave. The template scheme is really simple. Basically, you just wrap arbitrary JS code within {{ and }}. The code gets executed (in the scope of the wave) and the block gets replaced with the return value of the script. When you’re inside wavebody there are a few additional blip-specific things that you can add. Now we have to learn the magical snippets of code you can use inside the curly brackets. One of the objects exposed to the templates is wave. The nice thing is that it mirrors the wave api. So the wave object exposes the following attributes (copied from the google page).

  • creationTime denotes the Unix time at which this wavelet was created.
  • creator denotes the address of the participant who created this wavelet.
  • lastModifiedTime denotes the Unix time at which the wavelet was last modified by any participant.
  • participants contains an array of participant IDs for all participants on the wave.
  • rootBlipId contains the Blip ID of the root blip.
  • title contains the title of the wavelet, which by default consists of the first line of text up to the first carriage return.
  • version contains the version of this wavelet. Each atomic operation on a wavelet increases this version number.
  • waveId contains the Wave ID of this wavelet.
  • waveletId contains the wavelet ID of this wavelet. Note that for waves which contain only one wavelet (that don’t have private conversations, in other words), this wavelet ID is usually of the form conv+root indicating that the wavelet is identical to the conversation root, the root wave.
  • dataDocuments contains a dictionary (associated array) of the IDs and data of any data documents attached to this wavelet.

In addition, there are a few non-standard components.

  • permalink contains a link to the waveref which points to the specific wave on the real wave client
  • blips contains a js object (similar to a hash or dictionary) of blipIDs associated to blip objects
  • bliparr contains an array of blip ids in no particular order, most frequently used for getting the number of replies in a conversation in {{wave.bliparr.length-1}}

There are also some functions you can call. For example, wave.creationTime is in the form of a unix timestamp. That probably isn’t too useful to an ordinary user, so a format_time function is there to format it like “6/30 10:45am”. If you want to have some other custom datetime format, get me a script to do it in javascript in less than 500 bytes and I’ll include it in the next version.

  • format_time(int) Format a unix-style date as a human-readable “6/30 10:45am” or if you prefer “m/d h:MMtt”
  • render(blip) Render a blip and return the HTML. Most of the time, it’s unnecessary as there’s a blip.html attribute

There are a few actions that you can do. Certain strings like {{addparticipant}} can be used in onclick= attributes to trigger certain actions on various events.

Here you see a link and a button. The link has been configured to prompt the user for a participant ID to add when clicked, and the button was set to prompt the user for a tag to add when clicked. There are several such actions.

  • addparticipant Prompt the suer for a wave address to add to the wave
  • reload Reload the current wave
  • addtag Prompt the user for a tag to add
  • setname Prompt the user to set a username for posting

There is also the user list. It comes in two flavors, {{participantlist}} and {{contributorlist}}. The latter only works when inside a blip scope (the stuff inside wavebody). They’re special because they’re actually interactive. When the list is long, it shortens it and creates a link to expand.

  • participantlist A list made from wave.participants
  • contributorlist Only works when in wavebody, a simple users list made from blip.contributors

Now, is finally the stuff that goes in the blip. Like wave it extends some wave api features, so I’ll start with pasting what google has documented.

  • blipId contains the ID of blip in which the event occurred.
  • childBlipIds contains an array of blip IDs for each of the blip’s children.
  • contributors denotes participants who have contributed to the state of this blip.
  • creator denotes the participant who created this blip.
  • lastModifiedTime denotes the Unix time at which this blip was last modified by any participant.
  • content contains the textual content of this blip.
  • version contains the version of this blip. Each atomic operation on a blip increases this version number.
  • waveId contains the Wave ID associated with this blip.
  • waveletId contains the wavelet ID associated with this blip. Note that for waves which contain only one wavelet (that don’t have private conversations, in other words), this wavelet ID is usually of the form conv+root indicating that the wavelet is identical to the conversation root, the root wave.

There are a few additional methods which, again are non-standard.

  • permalink contains a link to the waveref which points to the specific blip on the real wave client
  • html contains a string of the rendered (with formatting and annotations applied) content

There are also actions, similar to the global addparticipant, reload and setname actions. They can still be used within wavebody but there are some actions which can only work in the blip template.

  • edit Add an edit box immediately below the blip, pre-populated with the text content of the blip
  • remove Remove the blip, it will first issue a confirmation prompt to the user
  • reply Add a reply box immediately below the blip. If there is already a blip below, the reply box is indented.

Below is a little example showing how to use the blip object.
Lastly is the JS part. Without it, nothing would ever show up. You need to include the currently 6.5KB JS library from http://anony-bot.appspot.com/assets/embed2.mini.js. After that, you need a separate script tag anywhere after the big hidden super element. It must be outside the super element (unimaginable evils will happen if it isn’t). Inside that script tag needs to be a function call to w2_embed. The first (and only) argument has to be a JS object with at least the element key pointing to a DOM element which contains an element with the class wavebody. There are lots of other config options, and here they are.

  • element (Required) a dom element which contains a div with the “wavebody” class
  • identifier The identifier for the wave that the server will use to generate a wave ID from, default: location.pathname
  • root_title If the identifier has not previously been associated with a wave ID, the wave will be created with the specified title. default: (no title)
  • root_content If the identifier has not previously been associated with a wave ID, the wave will be created with the specified content as the root blip. default: (no content)
  • participants The participants the wave should be created with if not previously associated with a wave ID, default: [], suggested: ['public@a.gwave.com']
  • hideroot Boolean whether or not to not render the root blip
  • edit A reference to a DOM element which can be templated into the edit box, should contain handlers for the actions {{submit}} and {{cancel}} as well as a textarea with the class “wavetext”
  • tags Set of tags to be added to the wave if the identifier has not previously been associated with a wave and must be created.
  • api_root The domain containing the server component (proxy and dictionary server). Default: anony-bot.appspot.com
  • gadgets Enable native gadgets (does not work)
  • render_state Display the user a gadget state
  • chronological Render blips chronologically (see Microwave’s “Classic Forum Layout” option)
  • json_url Location of JSON implementation to be loaded dynamically in case it’s not native to the browser default: http://anony-bot.appspot.com/assets/json2.mini.js
  • waveid Skip the identifier lookup and directly reference a wave by it’s id

 

You can see that the function call was saved to a variable named demo. That’s useful because you can use that to reference later to manipulate things. The return of a w2_embed call is a JS object with the following keys.

  • config A reference to the initial config object
  • reply(text) Create a root-level reply
  • reload() Reload the wave.

So lets try putting everything together.

 

Afterthoughts: Just a little thing to add at the end. You can can create a a div with the class waveedit as used above. It’s not strictly necessary, but it lets you customize things a bit more. You also need a CSS style for .wavethread with a padding-left (or margin-left) in order for threads to show up properly. Blips are automatically given a .waveblip class.

That screenshot on the top of the post, if you want to try it out. It’s here.

I’m not making any money off of this, so there’s no reason for me to hide the fallibilities of this solution from anyone. This, like any other solution is not perfect. There is no true wave-style real-time editing, it uses polling. It does however update every 10 seconds if it’s configured to do so using the poll_updates: true configuration option. It can’t ever really do much better, since app engine doesn’t yet support pushing out real time data to attached clients, even though they announced the neat Channel API (still waiting to use it!) at I/O. Either way, that probably won’t help too much as w2_embed uses JSONP for client/server communication across multiple domains, and it’s unlikely that the channel api will allow for that. Also, since there’s no way to fetch a single blip, the user must request the entire wave to check the tiny 32 bit version integer if it’s been incremented, and if it has, then the whole wave has to be fetched again. It’s by no means efficient, and so my server would be very very sad if the polling interval was significantly increased. It’s not very SEO friendly. Though it’s not always that people want the comments to be indexed by search engines, so some people may care less. Accessibility-wise, it shouldn’t be too horrible if the screen reader/browser supports javascript and hugely depends on the HTML being used in conjunction with the script.

As of date, this was my longest blog post ever, and I would be sad if nobody commented (ironically using my non-wave-based commenting system). And I’m not posting my source code unless someone comments, so, an incentive :P

Posted in Deep Comment Integration, Google Wave.

Tagged with , , , , , , , , .


Anony-bot

A little robot using the Robots V2 API to expose a wave to a URL. If the URL is shared, then anyone can post anonymously on the wave.

Posted in Uncategorized.


μwave

μwave is the first true third-party wave client which is compatible with Google Wave. It’s free to use at http://micro-wave.appspot.com/ and works great on mobile devices. It supports searching for waves, opening them and writing replies.

The source code for the server component is open-source and can be found on github (though it’s slightly outdated, but the important stuff is there). It’s fairly simple (It’s based on the original example code so I’m going to have the same MIT license), but one of the few python scripts which can do authentication with google and pass commands to the data api.  It relies on thePython OAuth Library.

A list of posts related to this can be found here.

 

Posted in Uncategorized.