Getting hold of the event and context when binding a Javascript function to an HTML element

The problem

There are 2 ways of binding a Javascript function to an HTML element. One is programmatic, typically done with jQuery, such as:

$('#myElement').click(function() {
  console.log(this);
});

Doing that way correctly provides the HTML element which triggered the event as the this context. If the event object is needed, one can easily get it as it is passed as an argument to the function.

$('#myElement').click(function(event) {
  console.log(this);
  console.log(event);
});

The other way to bind a function is to simply declare it in the markup of the HTML element, such as:

<span id="myElement" onclick="doSomething()">click me</span>

The function can be defined elsewhere in Javascript:

function doSomething() {
  console.log(this);  // !!! doesn't work 
}

The problem is that, in the function, this now refers to the window and not anymore to the HTML element which triggered the event. And there is no way to get the event object.

The solution

Use apply or call to invoke the function in the HTML element and pass the arguments. So in the html we have:

<span id="myElement" onclick="doSomething.apply(this, arguments)">click me</span>

Now, not only this is defined properly, but you can also access the event object, the same way as when binding programmatically

function doSomething(event) {
  console.log(this);   // it works
  console.log(event);  // it works
}

Getting the event object can be especially useful to stop the event propagation by invoking event.stopPropagation();

 

Working with HandleBars templates in Express on Node.js

What is HandleBars

HandleBars.js is an extension to Mustache logic-less template language. Mustache is a very nice template language and HandleBars provides some necessary extensions.

Installing HandleBars on Node.js

HandleBars is maintained be Yehuda Katz and can be found on GitHub. Installation is done via npm

npm install handlebars

HandleBars needs to be built to generate the javascript file parser.js. For that you need ruby, bundler and rake and the node module jison. I ended up installing everything :

cd /usr/local/
brew install ruby
gem install bundler
npm -g install jison
cd {{your path}}/handlebars/
bundle install rake
rake release

Check that parser.js exist in the directory handlebars/lib/handlebars/compiler/.

Using HandleBars with Express

Don Park maintains a bridge between Express and HandleBars called HBS. It is a very simple module.

npm install hbs

In Node.js, the hbs has to be loaded and configured:

var hbs = require('hbs');
var app = express.createServer();
app.register('.handlebars', hdb);
app.configure(function() {
  app.set('views', __dirname + '/views');
  app.set('view engine', 'handlebars');
  app.set('view options', { layout: true });
}

Editing HandleBars tamplate in TextMate or SublimeText

There is a bundle to work with HandleBars in TextMate or Sublime Text 2:

cd ~/Library/Application\ Support/TextMate/Bundles/
git clone git://github.com/drnic/Handlebars.tmbundle.git

cd ~/Library/Application\ Support/Sublime\ Text\ 2/Packages
git clone git://github.com/drnic/Handlebars.tmbundle.git HandleBars

Installing Node.js and CoffeeScript on Mac OS X Lion

Installing Node.js with Homebrew

Using Homebrew, installing Node.js is a one liner

brew install node

Node is placed in /usr/local/Cellar/node/0.4.12/ and the 2 node executables are placed in /usr/local/bin so that they are available as command right away. Try:

>node -v
v0.4.12

to confirm it works.

Installing npm

Npm is a package manager for node. It can be installed by the following command:

curl http://npmjs.org/install.sh | sh

Using npm, all node packages can be installed directly. No need to use Homebrew for Node. Node modules are installed in a node_modules directory directly inside the directory from which the npm command is invoked. Some modules (such as CoffeeScript or Node Inspector can be better off installed globally (using the option -g). In that case they are placed in /usr/local/lib/node_modules.

Nice additions to work with js on Mac

Using TextMate or SublimeText 2 to work with JavaScript is great on the Mac but one need to add a bundle to be able to run/debug the code from the editor. javascript-tools.tmbundle is a bundle that provides validation, compaction, execution and debugging. To install it in TextMate and Sublime Text:

cd ~/Library/Application\ Support/TextMate/Bundles/
git clone git://github.com/subtleGradient/javascript-tools.tmbundle.git

cd ~/Library/Application\ Support/Sublime\ Text\ 2/Packages
git clone git://github.com/subtleGradient/javascript-tools.tmbundle.git JavaScript-Tools

This will add a menu JavaScript Tools in which all functionalities are accessible. In order to use the debugger, Node Inspector needs to be installed using npm (best is to install it globally):

npm install -g node-inspector

Working with CoffeeScript

CoffeeScript is a nice language that compiles to JavaScript. It can be used instead of JavaScript to have more readable code and increase productivity. To install it (globally):

npm install -g coffee-script

There is also a bundle to work with CoffeeScript in TextMate or Sublime Text 2:

cd ~/Library/Application\ Support/TextMate/Bundles/
git clone https://github.com/jashkenas/coffee-script-tmbundle.git CoffeeScript.tmbundle

cd ~/Library/Application\ Support/Sublime\ Text\ 2/Packages
git clone https://github.com/jashkenas/coffee-script-tmbundle.git CoffeeScript

Installing nginx-gridfs with Homebrew on MacOS X Lion

This is a follow-up of the previous post which look into the installation of the module nginx-gridfs in Nginx.

Get the nginx-gridfs source code

First create a directory to receive the source code, and get it with git:

mkdir /usr/local/src
cd /usr/local/src
git clone git://github.com/mdirolf/nginx-gridfs.git

A directory /usr/local/src/nginx-gridfs is created. As explained on the nginx-gridfs page, we then need to get the sub-module:

cd nginx-gridfs
git submodule init
git submodule update

Remake Nginx with nginx-gridfs

We need to edit the local nginx formula to add nginx-gridfs:

brew edit nginx

In your editor add the line "--add-module=/usr/local/src/nginx-gridfs/" in the arguments of the installation to obtain:

def install
    args = ["--prefix=#{prefix}",
            "--with-http_ssl_module",
            "--with-pcre",
            "--conf-path=#{etc}/nginx/nginx.conf",
            "--pid-path=#{var}/run/nginx.pid",
            "--add-module=/usr/local/src/nginx-gridfs/",
            "--lock-path=#{var}/nginx/nginx.lock"]

Then remove Nginx and reinstall.

brew rm nginx
brew install nginx

Check that it works

Let's add an image to the test database in MongoDB using mongofiles:

mongofiles -d test -l /path/to/an/image.jpg put test.jpg

Let's add the location /gridfs/ in one server already defined in nginx.conf (username and password should be set depending of mongoDB configuration):

location /gridfs/ {
  gridfs test
  field=filename
  type=string
  #user=admin
  #pass=admin
  ;
  mongo 127.0.0.1:27017;
}

In one browser, go to the right URL

http:∕/localhost:8080/gridfs/test.jpg

and you should see the image.

Installing Nginx - PHP with FPM - MongoDB on Mac OS X Lion

So far I was using MAMP for web development. It is a fine solution when used out of the box. For Localto, I needed to install MongoDB and I was able to do it within MAMP but that was a manual installation I would have to maintain with each new version of MAMP. I then decided to give Nginx a try, particularly for the Nginx-GridFS bridge to read files directly from MongoDB-GridFS.

At this point MAMP was not fit for the job anymore. I settled on installing my own stack and decided to use Homebrew the very good package manager for Mac OS X. Here is a walk down of the steps involved.

Installing Homebrew

/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"

The only thing to watch is to correct the PATH so that packages installed with Homebrew are found before the ones installed with the Mac OS X standard installation (for PHP for instance). Additionally, XCode needs to be installed together with Unix tools.

PATH=/usr/local/bin:/usr/local/sbin:$PATH

Installing Nginx

brew install nginx

After installation, we need to copy the Nginx launch agent configuration to your LaunchAgents directory for automatic startup of Nginx after computer restart.

cp /usr/local/Cellar/nginx/1.0.7/org.nginx.nginx.plist ~/Library/LaunchAgents/

You can also start Nginx manually using

launchctl load -w ~/Library/LaunchAgents/org.nginx.nginx.plist

and stop it using

launchctl unload -w ~/Library/LaunchAgents/org.nginx.nginx.plist

Installing MongoDB

Same thing as with Nginx:

brew install mongodb
cp /usr/local/Cellar/mongodb/2.0.0-x86_64/org.mongodb.mongod.plist ~/Library/LaunchAgents/

You probably want to edit the configuration file of MongoDB to make it perfect for your need:

mate /usr/local/Cellar/mongodb/2.0.0-x86_64/mongod.conf

Installing PHP with FPM

There is no standard formula for php in Homebrew, but there are plenty of third party ones. This article gives all necessary details. Here we install PHP without Apache support but with FPM and internationalization and without MySQL support.

brew install https://github.com/adamv/homebrew-alt/raw/master/duplicates/php.rb --without-apache --with-intl --with-fpm

We need to create a log directory for FPM

mkdir /usr/local/Cellar/php/5.3.8/var/log

and create and edit the configuration file for FPM

cp /usr/local/Cellar/php/5.3.8/etc/php-fpm.conf.default /usr/local/Cellar/php/5.3.8/etc/php-fpm.conf
mate /usr/local/Cellar/php/5.3.8/etc/php-fpm.conf

for enabling the setting of pm.min_spare_servers and pm.max_spare_servers.

'Fix' the default PEAR permissions and config:

chmod -R ug+w /usr/local/Cellar/php/5.3.8/lib/php
pear config-set php_ini /usr/local/etc/php.ini

LaunchAgents configuration for PHP-FPM

In order to start PHP-FPM automatically with the Mac, like Nginx and MongoDB, we need to create a configuration file and place it in ~/Library/LaunchAgents/ (replace username by your username on the mac).

MongoDB PHP extension

That is to allow PHP connect to MongoDB.

brew install mongo-php

That Mongo extension has to be added in /usr/local/etc/php.ini with the following line :

extension="/usr/local/Cellar/mongo-php/1.2.4/mongo.so"

Installing Xdebug

Note a necessary step but a very nice addition for debugging PHP code:

brew install xdebug

Xdebug has to be loaded in /usr/local/etc/php.ini with the following lines (asssuming PHP-FPM runs on port 9000 we have to choose another port than the default one which is also 9000, choosing here 9001):

zend_extension="/usr/local/Cellar/xdebug/2.1.2/xdebug.so"
xdebug.remote_enable=1
xdebug.remote_host=localhost
xdebug.remote_port=9001
xdebug.remote_autostart=1

Configuring Nginx

The configuration file for Nginx is found in /usr/local/etc/nginx/nginx.conf. You need to look in the documentation and in various examples on the web to make it the way you want. Here is a working configuration I came up with:

Fixing zooming problem with fitBounds() in Google Maps API

We came across a problem when using fitBounds() on a map with Google Map API. We have bounds predefined for regions we want to display in the map. So we called fitBounds() on the map with the predefined bounds of the chosen region.

Problem of fitBounds() is that it has a very liberal approach regarding the way it fits the map to the given bounds. Often, the given bounds represent only a small area on the map after the fitting to the point it is possible to increase the zoom level by one to get a much better fitting. So we implemented a solution that we give here. Basically when we fit the map to bounds, we add a listener that will zoom in the map is it sees the fitting was not good enough.