Question

My Goal: Learn CoffeeScript by porting a jquery widget to coffescript.

Following the excellent jQuery widget introduction, I have ported the example code to CoffeeScript: http://bililite.com/blog/understanding-jquery-ui-widgets-a-tutorial/

from:

var Green5  = {
    getLevel: function () { return this.options.level; },
    setLevel: function (x) {
        var greenlevels = this.options.greenlevels;
        var level = Math.floor(Math.min(greenlevels.length-1, Math.max(0,x)));
        this.options.level = level;
        this.element.css({background: greenlevels[level]});
        this._trigger('change', 0, level);
    },
    _init: function() { this.setLevel(this.getLevel()); }, // grab the default value and use it
    darker: function() { this.setLevel(this.getLevel()-1); },
    lighter: function() { this.setLevel(this.getLevel()+1); },
    off: function() {
        this.element.css({background: 'none'});
        this._trigger('done');
        this.destroy(); // use the predefined function
    },
    options: {
        level: 15,
        greenlevels: ['#000','#010','#020','#030','#040','#050','#060','#070','#080','#090','#0a0','#0b0','#0c0','#0d0','#0e0','#0f0', '#fff']
    }
};
$.widget("ui.green5", Green5);

to:

Green5 =
    getLevel: -> @options.level
    setLevel: (x) ->
        greenlevels = @options.greenlevels;
        level = Math.floor(Math.min(greenlevels.length-1, Math.max(0,x)));
        @options.level = level;
        @element.css({background: greenlevels[level]});
        @_trigger('change', 0, level);
    _init: -> @setLevel(@getLevel()) # grab the default value and use it
    darker: -> @setLevel(@getLevel()-1)
    lighter: -> @setLevel(@getLevel()+1)
    off: ->
        @element.css({background: 'none'})
        @_trigger('done')
        @destroy() # use the predefined function
    options: {
        level: 15,
        greenlevels:['#000','#010','#020','#030','#040','#050','#060','#070','#080','#090','#0a0','#0b0','#0c0','#0d0','#0e0','#0f0', '#fff']
    }

$.widget("ui.green5", Green5);

It works perfectly fine, but It was so easy to port that I´ve got the feeling I haven´t gotten CoffeeScript yet. How would you improve on that code?

update (thanks to Billy!):

Green5 =
    getLevel: -> @options.level
    setLevel: (x) ->
        greenlevels = @options.greenlevels
        level = Math.floor(Math.min(greenlevels.length-1, Math.max(0,x)));
        @options.level = level;
        @element.css
            background: greenlevels[level]
        @_trigger('change', 0, level)
    _init: -> @setLevel @getLevel() # grab the default value and use it
    darker: -> @setLevel @getLevel() - 1 
    lighter: -> @setLevel @getLevel() + 1
    off: ->
        @element.css
            background: 'none'
        @_trigger 'done'
        @destroy() # use the predefined function
    options: {
        level: 15,
        greenlevels:['#000','#010','#020','#030','#040','#050','#060','#070','#080','#090','#0a0','#0b0','#0c0','#0d0','#0e0','#0f0', '#fff']
    }

$.widget "ui.green5", Green5
Was it helpful?

Solution

You can get rid of semi-colons at the end, and also get rid of a ton of brackets and curly braces.

Green5 =
    getLevel: -> @options.level
    setLevel: (x) ->
        greenlevels = @options.greenlevels;
        level = Math.floor Math.min greenlevels.length-1, Math.max 0,x
        @options.level = level
        @element.css background: greenlevels[level]
        @_trigger 'change', 0, level
    _init: -> @setLevel this.getLevel() # grab the default value and use it
    darker: -> @setLevel this.getLevel() - 1
    lighter: -> @setLevel this.getLevel() + 1
    off: ->
        @element.css background: 'none'
        @_trigger 'done'
        @destroy() # use the predefined function
    options: level: 15, greenlevels: ['#000','#010','#020','#030','#040','#050','#060','#070','#080','#090','#0a0','#0b0','#0c0','#0d0','#0e0','#0f0', '#fff']

$.widget "ui.green5", Green5

However, the syntactic sugar is not the only benefit of CoffeeScript. A big plus is the way it re-writes certain code structures into better javascript.

For example:

yearsOld = max: 10, ida: 9, tim: 11

ages = for child, age of yearsOld
  child + " is " + age

Becomes:

var age, ages, child, yearsOld;
yearsOld = {
  max: 10,
  ida: 9,
  tim: 11
};
ages = (function() {
  var _results;
  _results = [];
  for (child in yearsOld) {
    age = yearsOld[child];
    _results.push(child + " is " + age);
  }
  return _results;
})();

Where the variables are all declared properly, and a closure is automatically added around the ages for loop which is written with good javascript technique that is honestly quite awkward to read.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top