Thanks to all who attended my CoffeeScript: Good, Bold, and with Sugar session at CodeMash. As promised at the end of the talk, here are the slides and examples.
To see videos of this presentation from previous conferences go to here or here.
Showing posts with label CoffeeScript. Show all posts
Showing posts with label CoffeeScript. Show all posts
Saturday, January 12, 2013
Monday, December 31, 2012
My Top 5 Blog Posts from 2012
On this last day of 2012, I'd like to look back and share my top 5 most popular blog posts from this year.
5. On January 8, I introduced a CoffeeScript Assertion Library called ExpectThat. ExpectThat makes it easy to create expressive, self-documenting assertions in CoffeeScript with a syntax similar to that provided by FsUnit.
4. In September, an example of a Single Page Application with Backbone.js, ASP.NET Web API, and F# was provided. This was then added to the F# and C# ASP.NET MVC 4 project template.
3. At the end of January, an example was given for how to use ExpectThat with Mocha to test a jQuery plugin. This example builds on a nice post by Josh Bush entitled Testing jQuery plugins with Node.js and Jasmine and it includes examples for both browser and Node tests with Mocha and ExpectThat.
2. In March, I announced an addition to the F# and C# ASP.NET MVC 4 template that makes it easy to create modern HTTP services with ASP.NET Web API and F#.
1. And my most popular post from 2012 was an example of a Single Page Application with Knockout.js, ASP.NET Web API, and F# . This was later added as an option to the F# and C# ASP.NET MVC 4 project template.
Happy New Year!
5. On January 8, I introduced a CoffeeScript Assertion Library called ExpectThat. ExpectThat makes it easy to create expressive, self-documenting assertions in CoffeeScript with a syntax similar to that provided by FsUnit.
4. In September, an example of a Single Page Application with Backbone.js, ASP.NET Web API, and F# was provided. This was then added to the F# and C# ASP.NET MVC 4 project template.
3. At the end of January, an example was given for how to use ExpectThat with Mocha to test a jQuery plugin. This example builds on a nice post by Josh Bush entitled Testing jQuery plugins with Node.js and Jasmine and it includes examples for both browser and Node tests with Mocha and ExpectThat.
2. In March, I announced an addition to the F# and C# ASP.NET MVC 4 template that makes it easy to create modern HTTP services with ASP.NET Web API and F#.
1. And my most popular post from 2012 was an example of a Single Page Application with Knockout.js, ASP.NET Web API, and F# . This was later added as an option to the F# and C# ASP.NET MVC 4 project template.
Happy New Year!
Labels:
2012,
ASP.NET MVC 4,
ASP.NET Web API,
Backbone,
CoffeeScript,
ExpectThat,
F#,
Knockout,
Mocha
Saturday, November 10, 2012
Presentation - CoffeeScript: Good, Bold, and with Sugar
Thanks to all who came out to the Nashville .NET User Group last Thursday. If you weren't able to make it, you can view the presentation here:
Thursday, July 5, 2012
CoffeeScript Presentation Now Available on InfoQ
The presentation that I did at Code PaLOUsa entitled CoffeeScript: Good, Bold, and with Sugar is now available on InfoQ at http://www.infoq.com/presentations/CoffeeScript-Good-Bold-and-with-Sugar.
You can find an HTML version of the slides here and various examples on my GitHub.
You can find an HTML version of the slides here and various examples on my GitHub.
Saturday, June 16, 2012
CodeStock 2012 F# and CoffeeScript Presentations
Saturday, March 17, 2012
Presentation - CoffeeScript: Good, Bold, and with Sugar
Thanks to all who came out to my talk yesterday at Code PaLOUsa. As mentioned, the slides for the presentation are provided below.
You can find the slides + examples at https://github.com/dmohl/CoffeeScriptGoodBoldAndWithSugar and navigate the deck at Slides
Monday, February 20, 2012
ExpectThat with CoffeeScript, Zombie, Mocha, and Node
A few posts ago, I showed how to use ExpectThat with Mocha and Node.js. Today, I'll show a simple example of using ExpectThat with Zombie.js--a full-stack testing framework.
Zombie.js
Zombie.js is a fast, headless testing framework that provides various functionality to write tests that hit your full technology stack. While I generally prefer to write more fine-grained, isolated tests, it's important to also have a few smoke tests and/or integration tests to verify end-to-end functionality. Zombie makes these kinds of tests easy, while allowing me to still use ExpectThat and Mocha.
The Example
Here's a simple example that populates two input elements and then verifies that the values of those input fields contain the expected text.
You can find the full example here.
After a few commands such as " coffee --output lib/ specs/ " and " mocha 'lib/example.spec.js' --reporter spec ", you should see an output that looks something like this:
To learn more about ExpectThat, visit https://github.com/dmohl/expectThat.
Zombie.js
Zombie.js is a fast, headless testing framework that provides various functionality to write tests that hit your full technology stack. While I generally prefer to write more fine-grained, isolated tests, it's important to also have a few smoke tests and/or integration tests to verify end-to-end functionality. Zombie makes these kinds of tests easy, while allowing me to still use ExpectThat and Mocha.
The Example
Here's a simple example that populates two input elements and then verifies that the values of those input fields contain the expected text.
You can find the full example here.
After a few commands such as " coffee --output lib/ specs/ " and " mocha 'lib/example.spec.js' --reporter spec ", you should see an output that looks something like this:
To learn more about ExpectThat, visit https://github.com/dmohl/expectThat.
Labels:
CoffeeScript,
ExpectThat,
Mocha,
Node.js,
Zombie.js
Monday, January 30, 2012
Testing a jQuery Plugin with ExpectThat and Mocha
A couple of weeks ago, I announced a CoffeeScript/JavaScript assertion library called ExpectThat. In this post, I'll provide a more real-world example of how ExpectThat can be used. For this example, I'll be using the jQuery plugin and tests from one of Josh Bush's posts entitled "Testing jQuery Plugins with Node.js and Jasmine".
The jQuery plugin
The code that follows is a re-write (in CoffeeScript) of the simple jQuery plugin that Josh provided in his post.
This jQuery plugin provides a basic watermark type of feature for an input box.
The specs
Since Josh has already done the work of writing the specs for this jQuery plugin, all that I need to do is port this to CoffeeScript and add in ExpectThat. To mix things up a bit, I've chosen to use Mocha instead of Jasmine (though ExpectThat works just as well for Jasmine). For simplicity, I've combined the spec files from Josh's post.
Apples to apples
Here's a quick before and after comparison (with both examples in CoffeeScript):
Before ExpectThat:
An example of the result of running the specs in the browser is shown below:
Wait, what about Node?
"So", you say, "this is great, but Josh's post was all about using the same code and specs from the browser in Node.js". Ah, yes, thanks for reminding me. It's pretty simple to run these same specs in Node.
Here are the steps:
The jQuery plugin
The code that follows is a re-write (in CoffeeScript) of the simple jQuery plugin that Josh provided in his post.
This jQuery plugin provides a basic watermark type of feature for an input box.
The specs
Since Josh has already done the work of writing the specs for this jQuery plugin, all that I need to do is port this to CoffeeScript and add in ExpectThat. To mix things up a bit, I've chosen to use Mocha instead of Jasmine (though ExpectThat works just as well for Jasmine). For simplicity, I've combined the spec files from Josh's post.
Apples to apples
Here's a quick before and after comparison (with both examples in CoffeeScript):
Before ExpectThat:
describe "when calling placeholder plugin", ->
it "should show placeholder value", ->
expect(input.val()).toEqual("foo")
After ExpectThat:
describe "when calling placeholder plugin", ->
expectThat -> input.val().should equal "foo"
Josh's tests are already very readable, but by adding ExpectThat, I'm able to eliminate 1 line from every test and allow each to be self-documenting.An example of the result of running the specs in the browser is shown below:
Wait, what about Node?
"So", you say, "this is great, but Josh's post was all about using the same code and specs from the browser in Node.js". Ah, yes, thanks for reminding me. It's pretty simple to run these same specs in Node.
Here are the steps:
1. Use NPM to install mocha at a global level (i.e. npm install mocha -g) then install jsdom, jquery, and expectThat.mocha at the local level (i.e. npm install <package name>).
2. Create a file called runspecs.coffee with the code shown below and compile it however you choose (i.e. "coffee --compile --output lib/ specs/").
3. Run the tests with a command such as "mocha 'lib/runspecs.js' --reporter spec" and you should see something like the following:
In future posts, I'll show how to do similar testing with other tools such as Jasmine-Node and Zombie.js. To learn more about ExpectThat, get involved, and/or keep an eye on its progress, go to https://github.com/dmohl/expectThat.
Labels:
CoffeeScript,
ExpectThat,
jQuery,
Mocha,
Node.js
Sunday, January 8, 2012
Introducing ExpectThat: A CoffeeScript Assertion Library
I'm a big fan of automated testing. In fact, on the rare occasions that I don't write tests, I find that I can't shake the thought that something has been missed.
As with all aspects of my coding efforts, I am constantly looking for ways to improve the process, make tests more readable, and reduce room for error. With these goals in mind, I'd like to introduce ExpectThat.
What is ExpectThat?
ExpectThat is an expressive, self-documenting, assertion library for CoffeeScript, that seeks to improve testing efforts with your favorite testing framework. It does this by providing a syntax similar to FsUnit (a library for F#) that makes assertions more readable and then automatically translates that readable code into descriptive test output. This ensures that your test names always stay in sync with your tests and allows your code to speak for itself. ExpectThat currently supports Pavlov, QUnit, and Jasmine. Overtime, support for additional testing frameworks will be added.
Let's See it in Action
The following example shows how to write tests with ExpectThat for Pavlov in CoffeeScript:
Other Testing Frameworks
As I mentioned, ExpectThat currently supports QUnit and Jasmine in addition to Pavlov. The following are examples for each of these.
QUnit:
There are a couple of ways to get started with ExpectThat. First, head over to the ExpectThat GitHub site and browse through the documentation. You can then clone the repo and grab any of the examples from the example folder. If you are writing an ASP.NET app in Visual Studio, another option is to install one of the available NuGet packages.
Available Assertions
ExpectThat currently provides the following assertions:
- equal
- stictlyEqual
- false
- true
- greaterThan
- greaterThanOrEqual
- lessThan
- lessThanOrEqual
- throwException
- 'to' and 'be' can be used in most cases to make tests more readable.
In addition to the out-of-the-box assertions, ExpectThat allows for the creation of custom assertions. Examples of this for each of the supported testing frameworks are available in the example folder on GitHub.
ExpectThat in JavaScript
While the syntax of ExpectThat works best with CoffeeScript, you can certainly use it in JavaScript as well. Simply add in the missing braces, parens, semi-colons, function keywords, etc. The following provides a simple example for Pavlov:
There are a lot of things left to do for ExpectThat and I'd love to hear your thoughts on direction, enhancements, etc. as well as have any help that anyone would like to offer. If you want to get involved, fork me on GitHub.
As with all aspects of my coding efforts, I am constantly looking for ways to improve the process, make tests more readable, and reduce room for error. With these goals in mind, I'd like to introduce ExpectThat.
What is ExpectThat?
ExpectThat is an expressive, self-documenting, assertion library for CoffeeScript, that seeks to improve testing efforts with your favorite testing framework. It does this by providing a syntax similar to FsUnit (a library for F#) that makes assertions more readable and then automatically translates that readable code into descriptive test output. This ensures that your test names always stay in sync with your tests and allows your code to speak for itself. ExpectThat currently supports Pavlov, QUnit, and Jasmine. Overtime, support for additional testing frameworks will be added.
Let's See it in Action
The following example shows how to write tests with ExpectThat for Pavlov in CoffeeScript:
pavlov.specify "Example Specifications", ->
foo = "bar"
describe "When testing 'should equal'", ->
expectThat -> foo.should equal "bar"
describe "When testing 'shouldnt equal'", ->
expectThat -> foo.shouldnt equal "baz"
describe "When testing for 'true'", ->
expectThat -> (foo is "bar").should be true
expectThat -> (foo is "baz").shouldnt be true
describe "When testing for 'false'", ->
expectThat -> (foo is "baz").should be false
expectThat -> (foo is "bar").shouldnt be false
describe "When testing 'greater than'", ->
expectThat -> (9.1).should be greaterThan 9
expectThat -> (9.1).shouldnt be greaterThan 10
expectThat -> 10.shouldnt be greaterThan 10
Here's a screenshot of the result:
Other Testing Frameworks
As I mentioned, ExpectThat currently supports QUnit and Jasmine in addition to Pavlov. The following are examples for each of these.
QUnit:
module "Example QUnit Specifications" foo = "bar" module "When testing should equal" expectThat -> foo.should equal "bar" module "When testing shouldnt equal" expectThat -> foo.shouldnt equal "baz" module "When testing for true" expectThat -> (foo is "bar").should be true expectThat -> (foo is "baz").shouldnt be true module "When testing for false" expectThat -> (foo is "baz").should be false expectThat -> (foo is "bar").shouldnt be falseJasmine:
describe "Example Jasmine Specifications", ->
foo = "bar"
describe "When testing should equal", ->
expectThat -> foo.should equal "bar"
describe "When testing shouldnt equal", ->
expectThat -> foo.shouldnt equal "baz"
describe "When testing for throw", ->
expectThat -> (-> throw "test exception").should throwException
expectThat -> (-> throw "test").should throwException "test"
describe "When testing for less than", ->
expectThat -> 10.should be lessThan 11
expectThat -> (10.1).shouldnt be lessThan 10
Getting Started with ExpectThatThere are a couple of ways to get started with ExpectThat. First, head over to the ExpectThat GitHub site and browse through the documentation. You can then clone the repo and grab any of the examples from the example folder. If you are writing an ASP.NET app in Visual Studio, another option is to install one of the available NuGet packages.
Available Assertions
ExpectThat currently provides the following assertions:
- equal
- stictlyEqual
- false
- true
- greaterThan
- greaterThanOrEqual
- lessThan
- lessThanOrEqual
- throwException
- 'to' and 'be' can be used in most cases to make tests more readable.
In addition to the out-of-the-box assertions, ExpectThat allows for the creation of custom assertions. Examples of this for each of the supported testing frameworks are available in the example folder on GitHub.
ExpectThat in JavaScript
While the syntax of ExpectThat works best with CoffeeScript, you can certainly use it in JavaScript as well. Simply add in the missing braces, parens, semi-colons, function keywords, etc. The following provides a simple example for Pavlov:
pavlov.specify("expectThat Specifications", function() {
describe("When testing should equal", function() {
var foo = "bar";
expectThat(function() {
foo.should(equal("bar"));
});
expectThat(function() {
(foo + "test").should(equal("bartest"));
});
});
});
Getting InvolvedThere are a lot of things left to do for ExpectThat and I'd love to hear your thoughts on direction, enhancements, etc. as well as have any help that anyone would like to offer. If you want to get involved, fork me on GitHub.
Labels:
CoffeeScript,
ExpectThat,
Jasmine,
JavaScript,
Pavlov,
QUnit
Tuesday, November 29, 2011
Getting Setup for JavaScript Testing with Pavlov
I've talked about testing CoffeeScript with Pavlov in a previous post. Today, I'm going to talk about a couple of ways to quickly get started with Pavlov--a BDD API that sits on top of QUnit--in an ASP.NET web app.
In the past, whenever I wanted to start creating Pavlov specs, I would go out to the Pavlov GitHub site, grab the appropriate files, and add them to my web app. While this process isn't all that time consuming, there is now a better way. Now I can simply install the Pavlov NuGet package using the NuGet Visual Studio Extension. This package adds a folder named Specs under the Scripts folder that includes a barebones html file and pavlov.js.
An example of what the file structure looks like after this package is installed is shown below:
If I prefer to have a simple example to start with, I can alternatively install the Pavlov.Sample package. This adds the same files as the Pavlov package, but also includes an example.specs.js file with the code from the example on the Pavlov GitHub site.
Lastly, I've been writing a fair amount of CoffeeScript lately, so I may prefer to have the sample specs written in CoffeeScript. All that is needed for this is to make sure that Mindscape Web WorkBench Visual Studio Extension is installed (this is a onetime install) and then install the Pavlov.Coffee NuGet package. The files are then added to the project including a example.specs.coffee file that looks like this:
In the past, whenever I wanted to start creating Pavlov specs, I would go out to the Pavlov GitHub site, grab the appropriate files, and add them to my web app. While this process isn't all that time consuming, there is now a better way. Now I can simply install the Pavlov NuGet package using the NuGet Visual Studio Extension. This package adds a folder named Specs under the Scripts folder that includes a barebones html file and pavlov.js.
An example of what the file structure looks like after this package is installed is shown below:
If I prefer to have a simple example to start with, I can alternatively install the Pavlov.Sample package. This adds the same files as the Pavlov package, but also includes an example.specs.js file with the code from the example on the Pavlov GitHub site.
Lastly, I've been writing a fair amount of CoffeeScript lately, so I may prefer to have the sample specs written in CoffeeScript. All that is needed for this is to make sure that Mindscape Web WorkBench Visual Studio Extension is installed (this is a onetime install) and then install the Pavlov.Coffee NuGet package. The files are then added to the project including a example.specs.coffee file that looks like this:
Tuesday, November 15, 2011
A Pinch of CoffeeScript Sugar - Part 1
In this series, I plan to point out and provide a few examples of some cool syntactic sugar provided by CoffeeScript. In this post, I'll talk about destructuring assignment and splats.
I've shown how to write a jQuery plugin in CoffeeScript in a previous post. In the following example, I take that simple jQuery plugin and add a little more sugar.
The above example is based on the recommendations defined in the jQuery Plugins/Authoring documentation. There are a couple of interesting aspects of this code.
Line 10 (i.e. [_, args...] = arguments) is using two cool CoffeeScript features. The first is something called destructuring assignment. This feature allows you to take data from arrays or objects and place that data into something more wieldy. In this case, we are taking the JavaScript arguments object, destructuring it, and assigning all of the arguments except the first one to an array named args. This eliminates the need for me to type Array.prototype.slice.call(arguments, 1). If I had not used a splat (i.e ...), this would have assigned only the second argument to args. Note: Destructuring assignment has been added to JavaScript 1.7.
The second thing of interest on this line (which I've already briefly mentioned) is the use of the splat. The splat allows you to easily work with anything that involves a variable number of arguments. Since line 10 potentially involves more than 2 passed arguments, this is a perfect place to use a splat. As I mentioned before, the use of the splat in this case will generate JavaScript to slice the arguments array i.e. Array.prototype.slice.call(arguments, 1).
Lines 11 and 13 also use a splat, but the reasoning behind its use on these lines is slightly different. While this is still related to a varying number of arguments, it has to do with the passing of those arguments to a function rather than retrieval of the additional argument values. The splat in this case will generate JavaScript that uses the Function.apply method.
A little bit of sugar can make things much sweeter (ug...that was bad). I hope you find this post helpful and that you find lots of uses for the described features.
I've shown how to write a jQuery plugin in CoffeeScript in a previous post. In the following example, I take that simple jQuery plugin and add a little more sugar.
The above example is based on the recommendations defined in the jQuery Plugins/Authoring documentation. There are a couple of interesting aspects of this code.
Line 10 (i.e. [_, args...] = arguments) is using two cool CoffeeScript features. The first is something called destructuring assignment. This feature allows you to take data from arrays or objects and place that data into something more wieldy. In this case, we are taking the JavaScript arguments object, destructuring it, and assigning all of the arguments except the first one to an array named args. This eliminates the need for me to type Array.prototype.slice.call(arguments, 1). If I had not used a splat (i.e ...), this would have assigned only the second argument to args. Note: Destructuring assignment has been added to JavaScript 1.7.
The second thing of interest on this line (which I've already briefly mentioned) is the use of the splat. The splat allows you to easily work with anything that involves a variable number of arguments. Since line 10 potentially involves more than 2 passed arguments, this is a perfect place to use a splat. As I mentioned before, the use of the splat in this case will generate JavaScript to slice the arguments array i.e. Array.prototype.slice.call(arguments, 1).
Lines 11 and 13 also use a splat, but the reasoning behind its use on these lines is slightly different. While this is still related to a varying number of arguments, it has to do with the passing of those arguments to a function rather than retrieval of the additional argument values. The splat in this case will generate JavaScript that uses the Function.apply method.
A little bit of sugar can make things much sweeter (ug...that was bad). I hope you find this post helpful and that you find lots of uses for the described features.
Monday, November 7, 2011
A Coder Interview with Dan Mohl
A Coder Interview With Dan Mohl by Terrence Dorsey (@tpdorsey) was recently published in the articles section of The Code Project site. In it, I talk about tools, technology, and frameworks that interest me (F#, CoffeeScript, Node.js, etc.), my background, how the community has influenced my coding, and much more.
You can find the article at http://www.codeproject.com/KB/interviews/Interview-Dan-Mohl.aspx.
You can find the article at http://www.codeproject.com/KB/interviews/Interview-Dan-Mohl.aspx.
Tuesday, September 13, 2011
Advantages of CoffeeScript When Working with jQuery Templates
Working with jQuery Templates in CoffeeScript is very similar to working with them in JavaScript. However, there are a couple of CoffeeScript features that can make it even easier.
Here's a simple example (based on an example in the jQuery Template documentation):
As you can see, it's pretty similar to its JavaScript counterpart.
How can CoffeeScript make this better?
Enter Heredoc and String Interpolation...
Heredoc: Heredocs allow you to specify multi-line, formatted text. This can be useful when defining the template markup.
With heredocs, the markup from the previous example changes to this:
String Interpolation: CoffeeScript also provides Ruby style string interpolation. Here's an example of the markup after taking advantage of the string interpolation feature (Note: String interpolation only occurs within double-quoted strings and double-quoted heredocs):
Want to see it in action?
Go to http://tinkerbin.com/w0QoscT9, change the JavaScript Format drop down to CoffeeScript, then click the Run button.
Here's a simple example (based on an example in the jQuery Template documentation):
As you can see, it's pretty similar to its JavaScript counterpart.
How can CoffeeScript make this better?
Enter Heredoc and String Interpolation...
Heredoc: Heredocs allow you to specify multi-line, formatted text. This can be useful when defining the template markup.
With heredocs, the markup from the previous example changes to this:
String Interpolation: CoffeeScript also provides Ruby style string interpolation. Here's an example of the markup after taking advantage of the string interpolation feature (Note: String interpolation only occurs within double-quoted strings and double-quoted heredocs):
Want to see it in action?
Go to http://tinkerbin.com/w0QoscT9, change the JavaScript Format drop down to CoffeeScript, then click the Run button.
Thursday, September 1, 2011
Unit Testing a jQuery Plugin with CoffeeScript and Pavlov
If you search the web, you'll find a handful of good examples of jQuery plugins written in CoffeeScript, but there seems to be few examples of writing unit tests/specs in CoffeeScript. In this post, I'll show a very simple jQuery plugin with Pavlov specs.
Simple Plugin
This plugin simply wraps the jQuery UI dialog (http://jqueryui.com/demos/dialog/).
QUnit is a JavaScript testing framework (learn more about it at http://docs.jquery.com/Qunit) and Pavlov (https://github.com/mmonteleone/pavlov) extends QUnit with several features that promote Behavior-Driven Development (BDD). Here's the example:
Once we have this in place and create a simple test runner page, we end up with the standard QUnit output that looks like the following:
Simple Plugin
This plugin simply wraps the jQuery UI dialog (http://jqueryui.com/demos/dialog/).
do ($ = jQuery) ->
methods =
init: (options) ->
dialogElement = $(options.dialogSelector)
dialog = dialogElement.dialog autoOpen: false, modal: true, resizable: false
$(options.inputSelector).click -> dialog.dialog 'open'
$.fn.simple = (options) ->
settings = dialogSelector:'.dialog', inputSelector:'.input'
if options
$.extend settings, options
methods.init settings
Pavlov SpecsQUnit is a JavaScript testing framework (learn more about it at http://docs.jquery.com/Qunit) and Pavlov (https://github.com/mmonteleone/pavlov) extends QUnit with several features that promote Behavior-Driven Development (BDD). Here's the example:
pavlov.specify "Simple Plugin", ->
describe "Given default options", ->
before -> $(this).simple()
describe "when executing a click event", ->
before -> $('.input').click()
it "it should open the dialog", ->
assert($('.dialog').parents('.ui-dialog:visible').length).isTrue()
after ->
$('.dialog').dialog('close')
describe "When the click event has not been executed", ->
it "it should not have an open dialog", ->
assert($('.dialog').parents('.ui-dialog:visible').length).isFalse()
after ->
$('.dialog').dialog('close')
describe "Given all custom options", ->
before ->
$(this).simple dialogSelector:'.customDialog', inputSelector:'.customInput'
describe "when executing a click event", ->
before -> $('.customInput').click()
it "it should open the custom dialog", ->
assert($('.customDialog').parents('.ui-dialog:visible').length).isTrue()
after ->
$('.customDialog').dialog('close')
describe "Given only a custom dialogSelector", ->
before -> $(this).simple dialogSelector:'.customDialog'
describe "when executing a click event", ->
before -> $('.input').click()
it "it should open the custom dialog", ->
assert($('.customDialog').parents('.ui-dialog:visible').length).isTrue()
after ->
$('.customDialog').dialog('close')
describe "Given only a custom inputSelector", ->
before -> $(this).simple inputSelector:'.customInput'
describe "when executing a click event", ->
before -> $('.customInput').click()
it "it should open the dialog", ->
assert($('.dialog').parents('.ui-dialog:visible').length).isTrue()
after ->
$('.dialog').dialog('close')
The OutputOnce we have this in place and create a simple test runner page, we end up with the standard QUnit output that looks like the following:
Labels:
CoffeeScript,
jQuery,
jQuery Plugin,
Pavlov,
QUnit
Sunday, August 14, 2011
Another CoffeeScript and jQuery UI Example
In a previous post, I showed a few examples of jQuery UI demos ported to CoffeeScript. While I prefer the approach that was shown in that post, there is another way that I could have done it. In this post, I'll show a different jQuery UI example (one of the the Slider demos) written using the CoffeeScript class structure.
You can find the full example (F# + ASP.NET MVC + CoffeeScript + jQuery UI) on my GitHub: https://github.com/dmohl/FsCoffeeScriptjQueryUIExample.
You can find the full example (F# + ASP.NET MVC + CoffeeScript + jQuery UI) on my GitHub: https://github.com/dmohl/FsCoffeeScriptjQueryUIExample.
class Slider
constructor: ->
$('#master').slider
value: 60
orientation: "horizontal"
range: "min"
animate: true
$('#eq > span').each ->
value = parseInt $(this).text(), 10
$(this).empty().slider
value: value
range: "min"
animate: true
orientation: "vertical"
window.slider = new Slider()
Labels:
ASP.NET MVC 3,
CoffeeScript,
JavaScript,
jQuery UI
Sunday, July 31, 2011
jQuery UI Examples in CoffeeScript
Recently, I've been playing with CoffeeScript and have found it to be a lot of fun. I'm a big fan of JavaScript and CoffeeScript has only added to the enjoyment of writing client-side code by taking away a few of the "bad parts" and reducing syntactic noise. To help learn the language, I took a few of the jQuery UI examples and re-wrote them in CoffeeScript. You can find the full solution (F# + ASP.NET MVC (Razor) + CoffeeScript) at https://github.com/dmohl/FsCoffeeScriptjQueryUIExample. (Note: You will need to install the Mindscape Web Workbench Visual Studio 2010 extension to make the CoffeeScript aspects work correctly. Visit this post by Scott Hanselman for information on getting started with this extension).
Here are the before and after examples:
This simple Portlets example comes from the jQuery UI demo found at http://jqueryui.com/demos/sortable/#portlets.
The JavaScript Version:
The CoffeeScript Version:
This simple Photo Manager example comes from the jQuery UI demo found at http://jqueryui.com/demos/droppable/#photo-manager.
The JavaScript Version:
The CoffeeScript Version:
This simple User Manager example comes from the jQuery UI demo found at http://jqueryui.com/demos/dialog/#modal-form.
The JavaScript Version:
The CoffeeScript Version:
Here are the before and after examples:
This simple Portlets example comes from the jQuery UI demo found at http://jqueryui.com/demos/sortable/#portlets.
The JavaScript Version:
(function (portlets, undefined) {
portlets.init = function() {
$(".column").sortable({
connectWith: ".column"
});
$(".portlet")
.addClass("ui-widget ui-widget-content ui-helper-clearfix ui-corner-all")
.find(".portlet-header").addClass("ui-widget-header ui-corner-all")
.prepend("<span class='ui-icon ui-icon-minusthick'></span>")
.end().find(".portlet-content");
$(".portlet-header .ui-icon").click(function () {
$(this).toggleClass("ui-icon-minusthick").toggleClass("ui-icon-plusthick");
$(this).parents(".portlet:first").find(".portlet-content").toggle();
});
$(".column").disableSelection();
};
} (window.portlets = window.portlets || {}));
The CoffeeScript Version:
((portlets) ->
portlets.init = ->
$(".column").sortable(connectWith: ".column").disableSelection()
$(".portlet")
.addClass("ui-widget ui-widget-content ui-helper-clearfix ui-corner-all")
.find(".portlet-header").addClass("ui-widget-header ui-corner-all")
.prepend("<span class='ui-icon ui-icon-minusthick'></span>")
.end().find ".portlet-content"
$(".portlet-header .ui-icon").click ->
$(this).toggleClass("ui-icon-minusthick").toggleClass "ui-icon-plusthick"
$(this).parents(".portlet:first").find(".portlet-content").toggle()
) window.portlets = window.portlets or {}
This simple Photo Manager example comes from the jQuery UI demo found at http://jqueryui.com/demos/droppable/#photo-manager.
The JavaScript Version:
(function (pictureManager, undefined) {
pictureManager.init = function() {
var $gallery = $("#gallery"),
$trash = $("#trash");
$( "li", $gallery ).draggable({
cancel: "a.ui-icon",
revert: "invalid",
containment: $( "#demo-frame" ).length ? "#demo-frame" : "document",
helper: "clone",
cursor: "move"
});
$trash.droppable({
accept: "#gallery > li",
activeClass: "ui-state-highlight",
drop: function( event, ui ) {
deleteImage( ui.draggable );
}
});
$gallery.droppable({
accept: "#trash li",
activeClass: "custom-state-active",
drop: function( event, ui ) {
recycleImage( ui.draggable );
}
});
$("ul.gallery > li").click(function (event) {
var $item = $(this), $target = $(event.target);
if ($target.is("a.ui-icon-trash")) {
deleteImage($item);
} else if ($target.is("a.ui-icon-zoomin")) {
viewLargerImage($target);
} else if ($target.is("a.ui-icon-refresh")) {
recycleImage($item);
}
return false;
});
var recycle_icon = "<a href='link/to/recycle/script/when/we/have/js/off' title='Recycle this image' class='ui-icon ui-icon-refresh'>Recycle image</a>";
function deleteImage($item) {
$item.fadeOut(function () {
var $list = $("ul", $trash).length ?
$("ul", $trash) :
$("<ul class='gallery ui-helper-reset'/>").appendTo($trash);
$item.find("a.ui-icon-trash").remove();
$item.append(recycle_icon).appendTo($list).fadeIn(function () {
$item
.animate({ width: "48px" })
.find("img")
.animate({ height: "36px" });
});
});
}
var trash_icon = "<a href='link/to/trash/script/when/we/have/js/off' title='Delete this image' class='ui-icon ui-icon-trash'>Delete image</a>";
function recycleImage($item) {
$item.fadeOut(function () {
$item
.find("a.ui-icon-refresh")
.remove()
.end()
.css("width", "96px")
.append(trash_icon)
.find("img")
.css("height", "72px")
.end()
.appendTo($gallery)
.fadeIn();
});
}
function viewLargerImage($link) {
var src = $link.attr("href"),
title = $link.siblings("img").attr("alt"),
$modal = $("img[src$='" + src + "']");
if ($modal.length) {
$modal.dialog("open");
} else {
var img = $("<img alt='" + title + "' width='384' height='288' style='display: none; padding: 8px;' />")
.attr("src", src).appendTo("body");
setTimeout(function () {
img.dialog({
title: title,
width: 400,
modal: true
});
}, 1);
}
}
};
} (window.pictureManager = window.pictureManager || {}));
The CoffeeScript Version:
((pictureManager) ->
pictureManager.init = ->
$gallery = $("#gallery")
$trash = $("#trash")
recycle_icon = "<a href='link/to/recycle/script/when/we/have/js/off'
title='Recycle this image'
class='ui-icon ui-icon-refresh'>Recycle image</a>"
trash_icon = "<a href='link/to/trash/script/when/we/have/js/off'
title='Delete this image'
class='ui-icon ui-icon-trash'>Delete image</a>"
deleteImage = ($item) ->
$item.fadeOut ->
$list = if $("ul", $trash).length then $("ul", $trash) else $("<ul class='gallery ui-helper-reset'/>").appendTo $trash
$item.find("a.ui-icon-trash").remove()
$item.append(recycle_icon).appendTo($list).fadeIn ->
$item.animate(width: "48px").find("img").animate height: "36px"
recycleImage = ($item) ->
$item.fadeOut ->
$item.find("a.ui-icon-refresh").remove().end()
.css("width", "96px").append(trash_icon).find("img")
.css("height", "72px").end().appendTo($gallery).fadeIn()
viewLargerImage = ($link) ->
src = $link.attr "href"
title = $link.siblings("img").attr "alt"
$modal = $("img[src$='#{src}']")
if $modal.length
$modal.dialog "open"
else
img = $("<img alt='#{title}' width='384' height='288'
style='display: none; padding: 8px;' />")
.attr("src", src).appendTo "body"
setTimeout (->
img.dialog
title: title
width: 400
modal: true
), 1
$("li", $gallery).draggable
cancel: "a.ui-icon"
revert: "invalid"
containment: if $("#demo-frame").length then "#demo-frame" else "document"
helper: "clone"
cursor: "move"
$trash.droppable
accept: "#gallery > li"
activeClass: "ui-state-highlight"
drop: (event, ui) ->
deleteImage ui.draggable
$gallery.droppable
accept: "#trash li"
activeClass: "custom-state-active"
drop: (event, ui) ->
recycleImage ui.draggable
$("ul.gallery > li").click (event) ->
$item = $(this)
$target = $(event.target)
if $target.is "a.ui-icon-trash"
deleteImage $item
else if $target.is "a.ui-icon-zoomin"
viewLargerImage $target
else recycleImage $item if $target.is "a.ui-icon-refresh"
false
) window.pictureManager = window.pictureManager or {}
This simple User Manager example comes from the jQuery UI demo found at http://jqueryui.com/demos/dialog/#modal-form.
The JavaScript Version:
(function (userManager, undefined) {
userManager.init = function () {
$("#dialog:ui-dialog").dialog("destroy");
var name = $("#name"),
email = $("#email"),
password = $("#password"),
allFields = $([]).add(name).add(email).add(password),
tips = $(".validateTips");
function updateTips(t) {
tips
.text(t)
.addClass("ui-state-highlight");
setTimeout(function () {
tips.removeClass("ui-state-highlight", 1500);
}, 500);
}
function checkLength(o, n, min, max) {
if (o.val().length > max || o.val().length < min) {
o.addClass("ui-state-error");
updateTips("Length of " + n + " must be between " +
min + " and " + max + ".");
return false;
} else {
return true;
}
}
function checkRegexp(o, regexp, n) {
if (!(regexp.test(o.val()))) {
o.addClass("ui-state-error");
updateTips(n);
return false;
} else {
return true;
}
}
$("#dialog-form").dialog({
autoOpen: false,
height: 300,
width: 350,
modal: true,
buttons: {
"Create an account": function () {
var bValid = true;
allFields.removeClass("ui-state-error");
bValid = bValid && checkLength(name, "username", 3, 16);
bValid = bValid && checkLength(email, "email", 6, 80);
bValid = bValid && checkLength(password, "password", 5, 16);
bValid = bValid && checkRegexp(name, /^[a-z]([0-9a-z_])+$/i, "Username may consist of a-z, 0-9, underscores, begin with a letter.");
bValid = bValid && checkRegexp(email, /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i, "eg. ui@jquery.com");
bValid = bValid && checkRegexp(password, /^([0-9a-zA-Z])+$/, "Password field only allow : a-z 0-9");
if (bValid) {
$("#users tbody").append("<tr>" +
"<td>" + name.val() + "</td>" +
"<td>" + email.val() + "</td>" +
"<td>" + password.val() + "</td>" +
"</tr>");
$(this).dialog("close");
}
},
Cancel: function () {
$(this).dialog("close");
}
},
close: function () {
allFields.val("").removeClass("ui-state-error");
}
});
$("#create-user")
.button()
.click(function () {
$("#dialog-form").dialog("open");
});
};
} (window.userManager = window.userManager || {}));
The CoffeeScript Version:
((userManager) ->
userManager.init = ->
name = $("#name")
email = $("#email")
password = $("#password")
allFields = $([]).add(name).add(email).add password
tips = $(".validateTips")
updateTips = (t) ->
tips.text(t).addClass "ui-state-highlight"
setTimeout (->
tips.removeClass "ui-state-highlight", 1500
), 500
checkLength = (o, n, min, max) ->
if o.val().length > max or o.val().length < min
o.addClass "ui-state-error"
updateTips "Length of #{n} must be between #{min} and #{max}."
false
else true
checkRegexp = (o, regexp, n) ->
unless regexp.test o.val()
o.addClass "ui-state-error"
updateTips n
false
else true
$("#dialog-form").dialog
autoOpen: false
height: 300
width: 350
modal: true
buttons:
"Create an account": ->
bValid = true
allFields.removeClass "ui-state-error"
bValid = bValid and checkLength name, "username", 3, 16
bValid = bValid and checkLength email, "email", 6, 80
bValid = bValid and checkLength password, "password", 5, 16
bValid = bValid and checkRegexp name, /^[a-z]([0-9a-z_])+$/i, "Username may consist of a-z, 0-9, underscores, begin with a letter."
bValid = bValid and checkRegexp email, /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i, "eg. ui@jquery.com"
bValid = bValid and checkRegexp password, /^([0-9a-zA-Z])+$/, "Password field only allow : a-z 0-9"
if bValid
$("#users tbody").append "<tr>" + "<td>" + name.val() + "</td>" + "<td>" + email.val() + "</td>" + "<td>" + password.val() + "</td>" + "</tr>"
$(this).dialog "close"
Cancel: ->
$(this).dialog "close"
close: ->
allFields.val("").removeClass "ui-state-error"
$("#dialog:ui-dialog").dialog "destroy"
$("#create-user").button().click ->
$("#dialog-form").dialog "open"
) window.userManager = window.userManager or {}
Labels:
ASP.NET MVC 3,
CoffeeScript,
F#,
JavaScript,
jQuery UI
Subscribe to:
Posts (Atom)