Tags: Javascript
Ok/Cancel buttons with jqModal
2008/09/22 @ 00:12I recently quit using gwt and started using jQuery for a personal project of mine and I wanted to be able to show some modal dialog boxes using jQuery. As it turns out there is an easy to use plugin that does exactly this called jqModal. jqModal makes it simple to create modal dialogs by simply setting a css class on the tag you want to open the dialog and on the tag in the dialog that you want to close it.
| <a href="#" class="jqModal">view</a> | |
| ... | |
| <div class="jqmWindow" id="dialog"> | |
| <p>This is my dialog.</p> | |
| <a href="#" class="jqmClose">Close</a> | |
| </div> |
| <pre><code> | |
| $().ready(function() { | |
| $('#dialog').jqm(); | |
| }); | |
| </code></pre> |
That's easy but gives you a pretty minimalistic popup dialog. Any tag with the jqmClose class will simply close the dialog. What if you want to do something with OK and Cancel options? What if you want to do some fancy fade in/fade out no matter what happens? This tripped me up for a but much luckily only took about a few minutes to straiten out and test.
| <a href="#" class="jqModal">Update</a> | |
| ... | |
| <div class="jqmWindow" id="dialog"> | |
| <p>I'm going to update. Is that ok?</p> | |
| <a href="#" class="dialogok">OK</a> <a href="#" class="jqmClose">Cancel</a> | |
| </div> |
| $("#dialog #dialogok").bind("click", | |
| function() { | |
| /* Do your update logic here. */ | |
| $('#dialog').jqmHide(); | |
| } | |
| ); | |
| | |
| var newFieldHide = function(hash) { | |
| hash.w.fadeOut('2000',function() { hash.o.remove(); }); | |
| }; | |
| var newFieldShow = function(hash) { | |
| hash.w.fadeIn("2000"); | |
| }; | |
| $("#dialog").jqm({onHide:newFieldHide, onShow:newFieldShow}); |
So I'm basically closing the dialog manually in the OK case and closing it automatically using the jqmClose class in the Cancel case. In both cases the onHide trigger is called and fades out the dialog.
Javascript Interpreter
2008/07/08 @ 19:45I wanted a convenient way to test out some javascript by running it in a browser and being able to play with it via an interpreter like python has. As it turns out the almighty Bob created a nice interpreter for playing around with Mochikit but I wanted something a bit more generic that would allow me to import any kind of javascript and play with it. It turns out this is really easy so I added one simple function to the interpreter.js file called importjs.
You just call importjs like so
| importjs(url) |
This will import a javascript file from the url given. It's a very simple function that just adds a script tag to the document wrapped in div tag. You can load up the interpreter and type "importjs" to see the code.
| function (jssource) { | |
| importdiv = DIV(); | |
| importdiv.innerHTML = "Importing " + jssource + " <script type='text/javascript' src='" + jssource + "'></script>"; | |
| writeln(importdiv); | |
| } |
Check out the slightly modified interpreter here
Twitter Page Code
2008/06/19 @ 19:14
I took a look at twitter.com/" title="Twitter">Twitter's code as an example of a site that gets lots of traffic and noticed a couple things.
- They use Amazon S3 to store images
- They split the javascript, favicons, and css up across 3 or 4 subdomains (assets0.twitter.com, assets2.twitter.com, etc.)
- They include prototype and a version of jQuery as well as a version of script.aculo.us.
<script src="http://assets3.twitter.com/javascripts/prototype.js?1213829093" type="text/javascript"></script>
<script src="http://assets1.twitter.com/javascripts/effects.js?1213829093" type="text/javascript"></script>
<script src="http://assets0.twitter.com/javascripts/application.js?1213829093" type="text/javascript"></script>
<script src="http://assets0.twitter.com/javascripts/jquery-1.2.3.min.js?1213829093" type="text/javascript"></script>
It kind of surprised me that they include a version of prototype AND jQuery AND script.aculo.us since they aren't really light javascript files. Prototype comes in at 123kb, jQuery is 53kb, and script.aculo.us is 38kb. Seems to me that even with caching and all they could significantly reduce download traffic by sticking to one javascript library. I'm sure there is some wierd reason they do it though.
Google Developer Day Japan 2008 is being held on June 10th at Google's offices in Shibuya and I've registered to attend this year. There were a number of sessions that people could take part in but I decided to register for a Google appengine hackathon. I'm pretty curious about appengine since I've been working at becoming more familiar with really newly evolving technologies and not necessarily ones that have been around a while. Newly evolving technologies is something I've always felt I've had to catch up on since starting programming in high school. Going to high school with folks like Bob Ippolito (Mochikit, simplejson) and Konrad Rokicki who started coding stuff when they were in early middle school didn't help my self esteem.
Anyway, in the spirit of learning about Appengine I took a dive into the documentation and learned a few of appengines silly limitations but I came up with a simple application that utilizes the simple python library I created for prefix back in college. I put it up in my mercurial repository under prefix-appengine if you care to take a look.
The main work is done in two handlers which are essentially the controller part of the MVC pattern. One simply renders the page as a template, which is really simple since there isn't any template code, and the other implements a simple rest API that I use for an AJAX call to evaluate an expression given by the user. Using JSON seemed like a waste since there was only one returned value.
| class PrefixHandler(webapp.RequestHandler): | |
| def get(self): | |
| self.response.out.write(template.render("main.tpl", {})) | |
| | |
| # def post(self): | |
| # self.redirect('/') | |
| class EvalHandler(webapp.RequestHandler): | |
| def get(self): | |
| expression = self.request.get("exp") | |
| values = {} | |
| try: | |
| output = prefix.parser.parse(expression).evaluate() | |
| values = { | |
| "value": output | |
| } | |
| except ValueError, arg: | |
| output = "ERROR: " + str(arg) | |
| values = { | |
| "error": output | |
| } | |
| self.response.out.write(simplejson.dumps(values)) |
The rest of the code is in the javascript which I just wrote strait into the template file because I was lazy. The javascript uses jquery to do an AJAX call when the button is pressed and update the HTML DOM.
| var lastvalue = ""; | |
| $(document).ready(function() { | |
| $("#eval").click(function() { | |
| expression = $("#exp").val(); | |
| $("#output").html("Loading.."); | |
| uri = "eval?exp="; | |
| uri += encodeURIComponent(expression.replace("Ans", lastvalue)); | |
| uri = uri.replace(/%20/g|>, '+'); | |
| $.getJSON(uri, | |
| // Callback | |
| function (data) { | |
| output = "<font color='#FF0000'>ERROR: Invalid response from server</font>"; | |
| if (data.value != null) { | |
| output = expression + " = <font color='#00FF00'>" + data.value + "</font>"; | |
| lastvalue = data.value; | |
| } else { | |
| if (data.error && data.error.length>0) { | |
| output = "<font color='#FF0000'>"+ data.error +"</font>"; | |
| } | |
| } | |
| $("#output").html(output); | |
| } | |
| ); | |
| }); | |
| }); |
Google Analytics for Mobile Sites
2008/05/23 @ 20:13I implemented tracking using Google Analytics for my company's mobile sites using a technique described by Peter van der Graff on his site. The technique involves performing a GET to to an image on Google's server and passing it a bunch of options. Incidentally this is because Javascript can perform gets of images but not gets for any other kinds of content (as an aside, this kind of protection seems usless since the server could return any kind of content in wants to the javascript even though the GET has an image in the url. Maybe someone could enlighten me).
Peter originally came up with the idea because he wanted to track hits to a RSS xml url (which also seemed strange to me since the rss aggregator could read it as many times as it wants and doesn't give much insight into the number of readers, but I digress), or to another type of file download (image, pdf, etc) which wouldn't trigger the javascript that Google uses for Analytics.
One important difference between his motives and mine were that I'm tracking hits to a mobile site. Doing analytics on the server side are important since most phones (in Japan at least) don't support javascript. I also, because of the differences in what I was doing, needed to make some changes to how his script worked. Since I'm not tracking downloads or rss hits, I care about things like sessions, language, and user agent (why Peter didn't also care about this I'm not sure).
So I modified his code as follows. I forward the language and user agent of the client to Google Analytics so that I can track these things properly. I also pass my own cookie number so that Google Analytics can aggregate page hits from the same user into a session. I also make use of the user var to track hits to different customer's web pages. The example is in PHP but it could be easily translated into another language.
Note that, because of the use of stream contexts, this code will require a version of PHP >= 4.3.0.
| $var_utmac=MOBILE_GOOGLE_ANALYTICS_CODE; //enter the new urchin code | |
| $var_utmhn=WEB_DOMAIN; //enter your domain | |
| $var_utmn=rand(1000000000,9999999999);//random request number | |
| $var_cookie=$session; //cookie number | |
| $var_random=rand(1000000000,2147483647); //number under 2147483647 | |
| $var_today=time(); //today | |
| $var_referer=$_SERVER['HTTP_REFERER']; //referer url | |
| $var_uservar=$storeinfo['storeid']; //enter your own user defined variable | |
| $var_utmp=$_SERVER['REQUEST_URI']; // request uri | |
| $urchinUrl='http://www.google-analytics.com/__utm.gif?utmwv=1&utmn='.$var_utmn.'&utmsr=-&utmsc=-&utmul=-&utmje=0&utmfl=-&utmdt=-&utmhn='.$var_utmhn.'&utmr='.$var_referer.'&utmp='.$var_utmp.'&utmac='.$var_utmac.'&utmcc=__utma%3D'.$var_cookie.'.'.$var_random.'.'.$var_today.'.'.$var_today.'.'.$var_today.'.2%3B%2B__utmb%3D'.$var_cookie.'%3B%2B__utmc%3D'.$var_cookie.'%3B%2B__utmz%3D'.$var_cookie.'.'.$var_today.'.2.2.utmccn%3D(direct)%7Cutmcsr%3D(direct)%7Cutmcmd%3D(none)%3B%2B__utmv%3D'.$var_cookie.'.'.$var_uservar.'%3B'; | |
| $header = ''; | |
| //Set the language to that of the client so analytics can track it. | |
| if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { | |
| $header = 'Accept-language: '.$_SERVER['HTTP_ACCEPT_LANGUAGE'].'\r\n'; | |
| } | |
| //Set the user agent to that of the client so analytics can track it. | |
| if (!empty($_SERVER['HTTP_USER_AGENT'])) { | |
| $header = 'User-Agent: '.$_SERVER['HTTP_USER_AGENT'].'\r\n'; | |
| } | |
| $opts = array( | |
| 'http'=>array( | |
| 'method'=>'GET', | |
| 'header'=>$header | |
| ) | |
| ); | |
| $handle = fopen($urchinUrl, 'r', false, stream_context_create($opts)); | |
| $test = fgets($handle); | |
| fclose($handle); |
MochiKit does makes java suck less
2007/12/21 @ 22:58So the last few days I've been playing around with MochiKit and working with Javascript. Until now I have done some Javascript here and there but not too much. MochiKit seems to make it a lot easier by providing you with lots of useful functions for things you do often. In fact it's so popular that I have a hard time explaining to myself why I hadn't tried to use it up until now. I'm certainly not on the bleeding edge here.
Anyway, like I said, MochiKit makes JavaScript less painful. I have a little mockup for a page that defers going to the server until the user has stopped entering data for 3 seconds. That cuts down on a lot of back and forth between the server and client. It's easy in MochiKit. Just use the callLater function.
| update: function() { | |
| if (this.deferred) { | |
| this.deferred.cancel(); | |
| log('Previous deferred cancelled.'); | |
| } | |
| | |
| if (this.request) { | |
| this.request.cancel(); | |
| log('Previous request cancelled.'); | |
| } | |
| | |
| log('updated'); | |
| this.deferred = callLater(3.0, bind(this.deferredupdate, this)); | |
| } |
In this example the callLater is used to call another function, deferredupdate, after 3 seconds. However, if the user enters data a second time before the three seconds are up then the deferred object will be cancelled and a new deferred object will be created. This has the effect of not calling the update function until a user is really done entering data.
The request object is created in the deferredupdate function.
| deferredupdate: function() { | |
| log('Loading document'); | |
| this.deferred = null; | |
| | |
| this.request = loadJSONDoc('domains.json'); | |
| this.request.addCallback(bind(this.pageupdate, this)); | |
| } |
The deferredupdate function calls loadJSONDoc which creates a deferred object as well however this deferred object doesn't wait for any time it simply does it's work in a separate thread and executes a callback when it's done. In this case I set the callback to be the pageupdate function. The pageupdate function does the work of putting the resulting data into a table and adding that table to the html DOM.
If you are wondering what the bind function does, it always ensures that the 'this' reference works. I'll leave the full explanation for another post.
Most people who program in JavaScript already know about MochiKit but if you are interested in it check out the screencast at http://www.mochikit.com/
Bob Ippolito
2007/12/17 @ 14:49I found out today that the principle author of a popular Javascript/AJAX library Mochikit is my former highschool classmate Bob Ippolito. I remember him being pretty smart. I supposed he would make a name for himself in some CS circles and it looks like he has. He is also apparently a co-founder of Mochi Media, a company that makes products for content creators. Mochibot can be used to track usage of Adobe Flash content. It looks like they are moving into some advertising space by creating an advertising system for casual online games.
Interesting that Bob has moved into this area. Mochikit looks like it's had some extensive work done on it in the past few years so it looks like it's matured well but I imagined a bit more technical, low level path like kernel or low level API development for Bob rather than the relatively high level application/library development in javascript/web applications. I guess everyone follows the buck in the end to some extent and the money is in web dev.










