Building WeTweetApp, part 1
Simulfy allows you to add real-time collaboration to your website or app, using our new JavaScript platform released earlier this month. In the early days of Simulfy, about a year ago, we built WeTweetApp allowing you to prepare and write a Tweet together and post it to Twitter. But while rewriting Simulfy over the past year, WeTweetApp wasn’t updated and it got broken… Since the new Simulfy Client API (the client) is released, we decided to bring WeTweetApp back to life.
In the next couple of weeks, I will post a series of blogposts about how I created WeTweetApp.
In this first blogpost I will describe the base app structure, starting a Simulfy session using the client, creating the files and how to create the collaborative Tweet editor.
First off, the app is written in CoffeeScript, a language that compiles into JavaScript, and built on node.js.
I plan to annotate the source of WeTweetApp in the next couple of weeks, but the CoffeeScript source is already available at http://docs.simulfy.com/sources/wetweetapp/app.html.
Secondly, to post the collaborated text to Twitter, I’ve used Twitter’s Web Intents. Using web intents, it’s easy to hook Twitter’s API into WeTweetApp.
To create the WeTweetApp, I’ve created an HTML page containing the layout of the app and a CSS stylesheet. Then I added the client, Simulfy widgets library and the wetweetapp JavaScript via the script tag in the head. I then initiate the app by requiring the WetWeetApp JavaScript code. The require method is provided by the client.
<script src="http://simulfy.github.io/simulfy-libs/client/current/simulfy.min.js"></script> <script src="http://simulfy.github.io/simulfy-libs/client/current/simulfy-widgets.min.js"></script> <script src="/javascripts/wetweetapp.js"></script> <script> WeTweetApp = require('./app/js/app'); $(function() { window.app = new WeTweetApp(); }); </script>
WeTweetApp is a Coffeescript class containing all the app logic. With the client I can easily initiate a Simulfy session, by calling the startSimulfy method in the class constructor. The onConnect callback does all the specific app magic.
#app.coffee #require provided by nodejs extensionMap = require ‘./extensionmap’ simWidgets = require ‘simulfy-widgets’ class App #allows you to call ‘new App()’ constructor: () -> @start() start: () => startSimulfy onConnect: @onConnect extensionMap: extensionMap onConnect: () => #do WeTweetApp stuff
As you can see in the screenshot above, at the left there’s the Tweet text, at the right is a comment thread. For Simulfy this translates to two files. For the Tweet I created the file index.tweet, for the comments the file index.comments. Both files are public by default, allowing everyone who has access to the web url, can be added to the files. So, in the onConnect method I open these two files.
#app.coffee onConnect: () => #simletId is provided by the client, bound to window and grabbed from the hash in the browser url... @tweetFile = simulfy.openFile(simletId, 'index.tweet') @commentsFile = simulfy.openFile(simletId, 'index.comments')
Because the files are public, I can add the current user to the files without permission. In a next blogpost I’ll describe how I obtained the current user.
#app.coffee, onConnect #@address = '[email protected]' @tweetFile.participants.add(@address)
The tweetFile is just a piece of text, so I can create a tweet scope on the file content in the extensionMap, create it with an empty string and pass it to the Simulfy textarea widget.
#extensionMap.coffee class TweetFile extends SimOp autoCreate: true structure: (key) -> switch key when 'tweet' then Tweet else SimOp default: -> tweet: '' initialize: -> @tweet = @scope 'tweet'
#app.coffee, onConnect tweet = @tweetFile.content.tweet #jquery ($) provided by the client... @tweetArea = $('#tweet-area') simWidgets.textarea.bind @tweetArea, tweet
As Twitter allows 140 characters per Tweet, I’ve added a simple characters left counter. Using the live method on the tweet scope, I can simply calculate the characters left.
#app.coffee, onConnect tweet.live (str) => @tweetCounter = $('#tweet-counter') @tweetCounter.html 140 - str.length
If there are no characters left, I bounce the change by not sending it to the server, using the simOp’s isAllowed method in the extensionmap.
#extensionMap.coffee class Tweet extends SimOp #override simulfy isAllowed api method, use for content validation not permission checking isAllowed: (method, val, cb) -> if val.length <= 140 cb(true) else cb(false)
Finally, I use Twitter’s Web Intents to post the composed Tweet text to Twitter. Off course the Twitter API is in the HTML.
@tweetButton = $('#tweet-button') @tweetButton.on 'click', (event) => text = @tweetArea.val() #change the text string of the Twitter iFrame, the click propagates and triggers the Twitter popup to be opened... @tweetButton.attr('href',"https://twitter.com/intent/tweet?text=#{encodeURIComponent(text)}")
So, that’s it for this first blogpost. Next up is how I obtain the username, how to invite users and authentication.
Off course, don’t forget to check out WeTweetApp now!
Richard













