Archive

Archive for the ‘javascript’ Category

Yet another must have node.js module – underscore-cli

September 12, 2012 Leave a comment

If you love underscore.js and happen to be a CLI nut, you should not miss out underscore-cli, see

https://npmjs.org/package/underscore-cli

for details, or simply install via (assuming you are already using node.js)

sudo npm install -g underscore-cli

Test Drive:
curl https://api.github.com/users/midnightcodr|underscore print --color

Categories: javascript, node.js

Calling initialization function only once with this js trick

September 12, 2012 Leave a comment

There are times when an initialization function in a js object needs to be called only once. Here’s one of the solutions I came up with. When F.paint() is called, a check on the initialization tag (need_init) is performed. need_init remains undefined until init() is called for the first time.

The code:

var F=(function() {
	var self=this;

	var init=function() {
		console.log('Initialized.');
		self.need_init=false;
	}
	return {
		paint: function() {
			if(typeof self.need_init==='undefined') {
				init();
			}
			console.log('Now I am ready to paint.');
		}
	};
})();

F.paint();
F.paint();
F.paint();

Output from the above example:
Initialized.
Now I am ready to paint.
Now I am ready to paint.
Now I am ready to paint.

Enjoy coding.

Categories: javascript, Programming

backbone.js learning note [3]

May 14, 2012 Leave a comment

[ update 5/14/2012 ] This single page app is now available at http://whatsmyspeed.appspot.com/. Decided to go (back) with google app engine instead of heroku due to (initial start) performance reason.

I am definitely addicted to backbone.js and I just threw some backbone into the running speed calculator I wrote some time ago (with node.js):

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Speed Calculator</title>
	<style type="text/css">
		body { padding: 50px; font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; }
		a { color: #00B7FF; }
		label {width:100px;font-weight:bold;display:block;float:left;}
		input[type="text"] {width:120px;margin-right:5px;}
	</style>
</head>
<body>
	<div id="container">
	   <p> 
		  <label>Distance</label>
		  <input id="distance" type="text" placeholder="distance in miles">
		</p>
		<p>
		  <label>Time</label>
		  <input id="time" type="text" placeholder="ex: 24:25, 01:45:17">
		</p>
		<p>
		  <label>Speed</label>
		  <input id="speed" type="text">
		</p>
	</div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
    <script src="http://documentcloud.github.com/backbone/backbone-min.js"></script>
	<script>
		var Speed=Backbone.Model.extend({
			defaults: {
				distance:0,
				time:0
			}
		});
		var SpeedView=Backbone.View.extend({
			el:$('body'),
			events: {
				'blur input#time': 'update_model',
				'blur input#distance': 'update_model'
			},
			initialize: function() {
				_.bindAll(this, 'render');
				this.model.bind('change', this.render);
			},
			update_model: function() {
				this.model.set({
					time: $('#time').val()
					,distance: $('#distance').val()
				});	
			},
			render: function() {
				$('#speed').val('');
				var dist_str=this.model.get('distance')
					, time_str=this.model.get('time')
				if( dist_str!='' && time_str!='' && !isNaN(dist_str) ) {
					var speed=this._calc_speed(dist_str, time_str);
					if(speed!=null) {
						$('#speed').val(speed.toFixed(3));
					}
				}
				return false;
			},
			_calc_speed: function(dist_str, time_str) {
				var dist_reg=/^([0-9]+(?:\.[0-9]+)?)$/
					, dist_res=dist_reg.exec( dist_str )
					, time_reg=/^(?:(?:(2[0-3]|[0-1]?[0-9])[:])?([0-5]?[0-9])[:])?([0-5]?[0-9](?:\.[0-9]+)?)$/
					, time_res=time_reg.exec( time_str );
				if(dist_res && time_res) {
					var hours=(time_res[1]||0)*1
						, minutes=(time_res[2]||0)*1
						, seconds=(time_res[3]||0)*1
					total_seconds=hours*3600+minutes*60+seconds;
					if(total_seconds>0) {
						return 3600*dist_res[1]/total_seconds;
					} else {
						return null;
					}
				}
				return null;
			}
		});
		var speed=new Speed();
		var speedview=new SpeedView({model:speed});
	</script>
</body>
</html>
Categories: backbone.js, javascript

backbone.js study note [2]

May 13, 2012 Leave a comment

Here’s an improved and complete example to the first learning note on backbone.js

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>stock price simple demo</title>
</head>
<body>
    <div id="data"></div>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
    <script src="http://documentcloud.github.com/backbone/backbone-min.js"></script>

    <script>
        var Stock=Backbone.Model.extend({
            defaults: {
                price: 123
            }
        });

        var StockList=Backbone.Collection.extend({
            model: Stock
        });

        var ItemView=Backbone.View.extend({
            tagName: 'li',
            initialize: function() {
                _.bindAll(this, 'render');
                this.model.bind('change:price', this.render);
            },
            render: function() {
                $(this.el).html('<span>'+this.model.get('price')+'</span>');
                return this;
            }
        });

        var stock1=new Stock({price:333});
        var stock2=new Stock({price:555.667});

        var StockView=Backbone.View.extend({
            el: $('#data'),
            initialize: function() {
                _.bindAll(this, 'render');
                this.collection=new StockList();
                this.collection.add(stock1);
                this.collection.add(stock2);
                this.render();
            },
            render: function() {
                $(this.el).append('<ul></ul>');
                _(this.collection.models).each( function(item) {
                    var itemview=new ItemView({model:item});
                    $('ul', this.el).append(itemview.render().el);
                }, this);
            }
        });
        var stockview=new StockView();
    </script>
</body>
</html>

To test what it does (so far this is the most impressive feature of backbone, the rendering is actually linked directly to the change of model), open a Javascript console (in Chrome or with Firebug in Firefox), and type

stock1.set({ price: 10 })
stock2.set({ price: 999 })

, pay attention to the changes on the page.

References:
http://arturadib.com/hello-backbonejs/docs/5.html

Categories: backbone.js, javascript

How to make an Ajax form without capturing key press event on the input element

May 13, 2012 Leave a comment

OK this is a very common task: build a form, collect user input and send to server for processing (through Ajax therefore upon response the page should remain the same). One of the ways to accomplish this is to bind the ajax handling function to both the submit button (or an anchor link)’s click event and the input field’s key press event (only when Enter key is pressed):

<!DOCTYPE html> 
<html>
<head>                  
    <meta charset="utf-8">                                               
    <title>submit test using onclick and onkeydown event</title>
</head>             
<body>
    Name:   <input type="text" name="user_name" value="" id="user_name" onkeydown="kp_handler();">
    <p><input type="button" value="Continue &rarr;" onclick="handle_submit();"></p>
    <script type="text/javascript">
        function kp_handler(evt) {
                if(!evt && window.event) evt=window.event;
                if(evt.keyCode==13) {
                    handle_submit();
                }   
        }           
        function handle_submit() {                      
            // you might want to do ajax here to submit data to the server
            // as a demo I just print the data to the client's browser
            var msg='You have entered '+ document.getElementById('user_name').value;
            try {
                console.log(msg);
            } catch (e) {
                alert(msg);
            }
        }
    </script>
</body>
</html>

However, a better approach is to do it through a dummy form enclosing the text input and submit button. The benefit of of this is the Enter key event is automatically handled by form’s onsubmit attribute hence there’s no need to capture the onkeydown event on the text input element (figuring whether the Enter key is pressed is messy as you can see from the first approch):

<!DOCTYPE html> 
<html>
<head>                  
    <meta charset="utf-8">                                               
    <title>submit test using only onsubmit event</title>
</head>             
<body>
    <form id="some_form" onsubmit="javascript: handle_submit(); return false;">
        Name:   <input type="text" name="user_name" value="" id="user_name">
    <p><input type="submit" value="Continue &rarr;" ></p>
    </form>
    <script type="text/javascript">
        function handle_submit() {
            // you might want to do ajax here to submit data to the server
            // as a demo I just print the data to the client's browser
            var msg='You have entered '+ document.getElementById('user_name').value;
            try {
                console.log(msg);
            } catch (e) {
                alert(msg);
            }
        }
    </script>
</body>
</html>

It’s worth noting that the return false statement has to be put at the end of the onsubmit attribute (moving it into handle_submit will result in the form submitting to the page itself).
Comments and feedbacks are welcome.

Categories: javascript

backbone.js learning note [1]

April 5, 2012 Leave a comment

Keep track of state change example:

    Stock = Backbone.Model.extend({
        defaults: {
            price: null,
        },
        initialize: function(){
            this.bind('change:price', function() {
                var px=this.get('price');
                console.log('price changed to: '+px);
            });
        },
        price_change: function(newprice) {
            this.set({price:newprice});
        }
    });

    var stock=new Stock({price:1234.55});
    stock.price_change(456);
    // the console output from the last line:
    // price changed to: 456

References:
http://backbonetutorials.com/what-is-a-model/

Categories: backbone.js, javascript

Howto: create javascript object without the “new” keyword (quick example)

March 11, 2012 2 comments
var Apple=function(type, color) {
    this.type=type;
    this.color=color;
    this.getInfo=function() {
        return "This is a "+color+' '+type+' apple.';
    };
    this.grow=function() {
        console.log('See a '+type+' apple needs to grow too.');
    };
    return this;
};

var myapple=Apple('honeycrip', 'red'); // new Apple ... works too
console.log(myapple.getInfo());
myapple.grow();

The new keyword can be omitted due to the use of return this line (10). Happy coding.

Categories: javascript

How to write javascript codes more jslint-compliant

February 21, 2012 Leave a comment

1. The basics
If you love writing Javascript codes, you should have some kind of syntax validator installed. The one and only tool I am using is jslint, which can be installed in a number of ways, depending on the os and development toolkits available. My favorite way to is to install through npm (provided that node.js is installed, if not, try nvm):
npm install -g jslint

Once installed, you can fire it like:

$ jslint my_script.js

Most likely it’ll produce a lot of errors/warnings unless you already write code in a jslint-compliant fashion. There are some options you might want to add:

$ jslint --eqeq --white my_script.js

Where

  • –eqeq: tolerant == and !=
  • –white: doesn’t enforce strict whitespace rules, for example, doesn’t require spaces around =’s

See the jslint doc site for a complete list of options.

2. Run jslint directly from vim
If you are like me – a vim nut, you might want to integrate jslint into vim, add the following into your ~/.vimrc

command Jslint !jslint --white --eqeq %
nnoremap <leader>j :Jslint<CR>

To activate jslint while your are inside vim, simply hit \j in command mode. Special thanks to http://blog.sanctum.geek.nz/series/unix-as-ide/ for the vim integration tip.

Categories: javascript, jslint, vim

Fix for initial opening pdf in new Internet Explorer (6-8) window problem

February 9, 2012 4 comments

Problem:
In a recent project I am working on I need to allow user to open their documents (in PDF format, hosted in a different server with different domain) in a new window. This seems to be a pretty straight-forward task as all I need is window.open (url is not hard-coded in the href as user need to get authenticated with the local server and get the token that will be used to access the document) but when it comes to Internet Explorer I got stuck with a weird problem. For versions 6-8, the first click on the pdf view link since the initial launch of IE browser always results in a blank window. User needs to either press F5 on the popped-up window click the view link (same or different) again get PDF loaded. The following code works without issues in all browsers except IE6-8:

HTML:

<a href="void(0)" onclick="javascript:opendoc('abc123')">View Document</a>

JS:

function opendoc(docid) {
    // skipping code getting token via ajax call
    var url="https://remote.host.url/somepath&docid="+docid+"&token="+token;
    var win=window.open( url, 'newwindow' );
}

Through a lot of trial and errors which include the followings:

  • refresh the new popup after some time
  • close the popup then open it again after some delay
  • server-side redirect
  • pdfobject
  • using embed tag

I found a workaround that actually works. Basically the same url got opened twice (only for the initial loading after launching browser) with 5 seconds apart if client browser is IE6-8. Note: The last two methods fail as well. I think it has something to do with the document.domain setting in the parent window.

Solution:

// this variable is to store if the double loading trick has been done
var first_clicked=0;
function opendoc(docid) {
    // skipping code getting token via ajax call
    var url="https://remote.host.url/somepath?docid="+docid+"&token="+token;
    var win=window.open( url, 'newwindow' );
    // using jQuery to do browser testing, feel free to use other methods
    if(!first_clicked && $.browser.msie && $.browser.version.substr(0,1)<'9') {
        setTimeout( function() {
            win=window.open( url, 'newwindow' );
        }, 5000 );
        // adjust the time to be shorter but be sure to
        // do enough tests as I found if the value is too low (300, 500, 1000 for example) it won't work either
        // it may have something to do with the connection speed to remote server
        
        first_clicked=1; // set to 1 so sequential clicks open the link only once
    }
}

This doesn’t seem to be a perfect fix as it still requires user to wait for a few seconds before the first result can be viewed but it’s better than leaving user in the dark or asking them to press F5 in order fix the problem.

Get javascript function definition through this trick

February 7, 2012 Leave a comment

In Google Chrome javascript console or Firefox firebug console, type the following and followed by Enter key:

function_name.prototype.constructor

where function_name is the function you want to find out its definition. Learned this trick through
http://stackoverflow.com/questions/5469691/find-js-function-with-firebug.

Categories: debugging, javascript
Follow

Get every new post delivered to your Inbox.