From ac9021048440904f17635e741226d6ee8ad3d782 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Thu, 21 Feb 2013 07:21:54 -0700 Subject: [PATCH 01/54] Updating references --- can | 2 +- documentjs | 2 +- funcunit | 2 +- jquery | 2 +- steal | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/can b/can index f16f5f0b6..5a931b71e 160000 --- a/can +++ b/can @@ -1 +1 @@ -Subproject commit f16f5f0b6d53107340cceb1f3f044c409533e225 +Subproject commit 5a931b71eb14f647b44ce54a0e64c6aa4408a8d2 diff --git a/documentjs b/documentjs index 3d9ca968e..680ef10a0 160000 --- a/documentjs +++ b/documentjs @@ -1 +1 @@ -Subproject commit 3d9ca968edb5d1d779686ca0323f9b9a54e56cf5 +Subproject commit 680ef10a0c81beb418b6476afd49d4961bc92cbc diff --git a/funcunit b/funcunit index 9da5a5617..0797c4d7c 160000 --- a/funcunit +++ b/funcunit @@ -1 +1 @@ -Subproject commit 9da5a561758202083163e6a7747ac9ce07d3e412 +Subproject commit 0797c4d7c6706b8da3708f203f5ac991b7ca4006 diff --git a/jquery b/jquery index 071ddcc18..b04fa2c99 160000 --- a/jquery +++ b/jquery @@ -1 +1 @@ -Subproject commit 071ddcc18df8b66e83545a101fe45a8d8aecf498 +Subproject commit b04fa2c9943a4b47e9508f99e18670a9e3bca299 diff --git a/steal b/steal index 5ccd8ed0f..7db2f6caf 160000 --- a/steal +++ b/steal @@ -1 +1 @@ -Subproject commit 5ccd8ed0fbb8c66a834b355d75e3f27ee7d0a443 +Subproject commit 7db2f6caf149968aa4a781c2f4b52b146657b020 From 4e8a83c6b6cb78091f83244b40d32ad6bfdb78d8 Mon Sep 17 00:00:00 2001 From: David Schovanec Date: Tue, 26 Feb 2013 12:38:50 +0100 Subject: [PATCH 02/54] Update to grunt 4, add and config grunt-contrib-connect --- Gruntfile.js | 18 ++++++++++++++++++ package.json | 47 ++++++++++++++++++++++++----------------------- 2 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 Gruntfile.js diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 000000000..54ec9d1dd --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,18 @@ +module.exports = function (grunt) { + + grunt.loadNpmTasks('grunt-contrib-connect'); + + grunt.initConfig({ + connect: { + server: { + options: { + port: 8000, + base: '.', + keepalive: true + } + } + } + }) + + grunt.registerTask("server", "connect:server") +}; \ No newline at end of file diff --git a/package.json b/package.json index 6068345d5..0ce06db85 100644 --- a/package.json +++ b/package.json @@ -1,31 +1,32 @@ { - "name" : "JavaScriptMVC", - "description" : "A full stack JavaScript application framework containing CanJS, StealJS, FuncUnit, jQuery++, and DocumentJS.", - "version" : "3.3.0pre", - "author" : { - "name" : "Bitovi", - "email" : "contact@bitovi.com", - "web" : "http://bitovi.com/" + "name": "JavaScriptMVC", + "description": "A full stack JavaScript application framework containing CanJS, StealJS, FuncUnit, jQuery++, and DocumentJS.", + "version": "3.3.0pre", + "author": { + "name": "Bitovi", + "email": "contact@bitovi.com", + "web": "http://bitovi.com/" }, - "devDependencies" : { - "grunt" : "~0.3.11", - "grunt-closure-tools" : "~0.6.2", - "http-server" : "0.5.1", - "docco" : ">= 0.1.x", - "node-beautify" : "*", - "github" : ">= 0.1.7", - "commander" : "*", - "tafa-misc-util" : "*" + "devDependencies": { + "grunt": "~0.4.0", + "grunt-closure-tools": "~0.6.2", + "http-server": "0.5.1", + "docco": ">= 0.1.x", + "node-beautify": "*", + "github": ">= 0.1.7", + "commander": "*", + "tafa-misc-util": "*", + "grunt-contrib-connect": "~0.1.2" }, - "homepage" : "http://javascriptmvc.com/", - "repository" : { - "type" : "git", - "url" : "git@github.com:jupiterjs/javascriptmvc.git" + "homepage": "http://javascriptmvc.com/", + "repository": { + "type": "git", + "url": "git@github.com:jupiterjs/javascriptmvc.git" }, - "licenses" : [ + "licenses": [ { - "type" : "MIT", - "url" : "http://opensource.org/licenses/mit-license.php" + "type": "MIT", + "url": "http://opensource.org/licenses/mit-license.php" } ] } From d1b92203998eb933ef125ee2c2d9a81edb7466fc Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Fri, 8 Mar 2013 00:38:01 -0600 Subject: [PATCH 03/54] fixes hard coded Recipe --- jmvc/generate/templates/scaffold/create/create_test.js.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jmvc/generate/templates/scaffold/create/create_test.js.ejs b/jmvc/generate/templates/scaffold/create/create_test.js.ejs index 52ca4e5c2..668ec543a 100644 --- a/jmvc/generate/templates/scaffold/create/create_test.js.ejs +++ b/jmvc/generate/templates/scaffold/create/create_test.js.ejs @@ -25,7 +25,7 @@ steal('funcunit', "Pour water in a glass. Add ice cubes.", "description set correctly"); start(); - Recipe.unbind("created",arguments.callee); + <%=Alias%>.unbind("created",arguments.callee); }) S("[name=name]").type("Ice Water"); From f3287b0c41f51c0bd6b9c21a478459938f6ae024 Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Fri, 8 Mar 2013 00:41:15 -0600 Subject: [PATCH 04/54] updating submodules --- can | 2 +- jquery | 2 +- steal | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/can b/can index 5a931b71e..a42d77963 160000 --- a/can +++ b/can @@ -1 +1 @@ -Subproject commit 5a931b71eb14f647b44ce54a0e64c6aa4408a8d2 +Subproject commit a42d779637c0ca251415a245a064e4c49b6aec77 diff --git a/jquery b/jquery index b04fa2c99..33bc4f89c 160000 --- a/jquery +++ b/jquery @@ -1 +1 @@ -Subproject commit b04fa2c9943a4b47e9508f99e18670a9e3bca299 +Subproject commit 33bc4f89c9388ed1b985a6cf06277f37eec09424 diff --git a/steal b/steal index 7db2f6caf..8338b9329 160000 --- a/steal +++ b/steal @@ -1 +1 @@ -Subproject commit 7db2f6caf149968aa4a781c2f4b52b146657b020 +Subproject commit 8338b9329c302501ade6462b6fc5ebf1a723e3cc From bab33b2efa4e4699c65f28443fc375d0b6de657d Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Wed, 20 Mar 2013 00:31:27 -0500 Subject: [PATCH 05/54] working on docs and updating submodules --- documentjs | 2 +- steal | 2 +- tutorials/examples/srchr.md | 75 +++++++-------- tutorials/installing.md | 19 ---- tutorials/organizing.md | 178 ++++++++++++++++++------------------ 5 files changed, 124 insertions(+), 152 deletions(-) diff --git a/documentjs b/documentjs index 680ef10a0..91119826d 160000 --- a/documentjs +++ b/documentjs @@ -1 +1 @@ -Subproject commit 680ef10a0c81beb418b6476afd49d4961bc92cbc +Subproject commit 91119826df57d5c375a54b1351e04ecb5ef65439 diff --git a/steal b/steal index 8338b9329..6c6a805c2 160000 --- a/steal +++ b/steal @@ -1 +1 @@ -Subproject commit 8338b9329c302501ade6462b6fc5ebf1a723e3cc +Subproject commit 6c6a805c204208d0ffd619fe8eb6b71b1dcf8b50 diff --git a/tutorials/examples/srchr.md b/tutorials/examples/srchr.md index fecf848fb..05a1ed798 100644 --- a/tutorials/examples/srchr.md +++ b/tutorials/examples/srchr.md @@ -1,51 +1,47 @@ @page srchr Srchr @parent examples 0 -Srchr searches several data sources for content and displays it to the user. See it in action [here](http://javascriptmvc.com/srchr/srchr.html). This article covers: +Srchr searches several data sources for content and +displays it to the user. See it in +action [here](http://javascriptmvc.com/srchr/srchr.html). This article covers: - Installing Srchr - The ideas behind JavaScriptMVC (JMVC) - How JMVC enables code separation - Srchr's architecture -This article will talk about the architecture of the Srchr application, and how event oriented architecture can help you build loosely coupled, scalable applications. You will also learn how to assemble small pieces of functionality into the full blown application. +This article will talk about the +architecture of the Srchr application, and how [can.compute] +can help you build loosely coupled, scalable applications. You will +also learn how to assemble small pieces of functionality into the full blown application. ## Installing Srchr -You can install Srchr by using steal's [steal.get getjs] or via the [git repository](https://github.com/jupiterjs/srchr). -### 1. Installing with getjs +Install the Srchr app by cloning the git repo: -The simplest way to install Srchr is to use the built in getjs script: - - $ ./js steal/getjs srchr - -It will download the whole application complete with dependencies. - -### 2. Installing via git - -You can also install the Srchr app by cloning the git repo: - - $ git clone https://github.com/jupiterjs/srchr - $ cd srchr - $ git submodule update --init + > git clone git://github.com/bitovi/srchr srchr + > cd srchr + > git submodule update --init --recursive Once you get the application you should have a structure similar to below /srchr [top-level directory] - /jquery + /can + /documentjs /steal /funcunit - /scripts /srchr + /history + /models /scripts + /search + /search_result + /tabs + /templates /test - /models - /fixtures - /views - funcunit.html - qunit.html - srchr.css + test.html + srchr.less srchr.js srchr.html ... @@ -56,44 +52,37 @@ Srchr is now ready to be used. To run the Srchr application simply open _srchr/s Srchr was built the 'JavaScriptMVC' way. It has a folder/file structure where: -* Code is logically separated and tested +* Code is logically separated and tested. * Code is easily assembled into higher-order functionality. * Higher order functionality is tested. ## How to organize and separate code -Every JavaScript application implements widgets to show and manipulate data. In JavaScriptMVC every one of these widgets is built as an isolated part that can be reused and tested. These widgets communicate to each other with events, which results in a loosely coupled application. +Every JavaScript application implements widgets to +show and manipulate data. In JavaScriptMVC every one of +these widgets is built as an isolated part that can be reused and +tested. These widgets communicate to each other via a shared [can.compute], which +results in a loosely coupled application. Srchr is broken into logically separated components: -* Disabler - Listens for search messages and disables tab buttons. * History - A cookie saved list of items. * Search - Creates a search message when a search happens. * Search Result - Seaches for results and displays them. * Tabs - A basic tabs widget. - -This is the event diagram of Srchr: - -@image tutorials/images/diagram.png - - - This is the widget organization in Srchr: @image tutorials/images/app_organization.png +### User Workflow -By creating dumb, isolated widgets with a loose coupling to the rest of the application, we can easily organize code. Every widget is living in it's own directory complete with tests and resources. This allows us to test each of the widgets separately and reuse the code across projects. - -### Srchr's workflow - -Srchr's workflow can be outlined like this: +A user using Srchr might perform the following: -1. User selects (via checkboxes) services that should be searched -2. User enters search term and clicks the search button -3. On tab activation a search is performed and results are shown (since first enabled tab is active by default, these results will be shown immediately) +1. Select (via checkboxes) services that should be searched +2. Enter a search term and clicks the search button +3. Click result tabs to see their results. 4. Search params are saved to the history (via cookie) ### Search behavior diff --git a/tutorials/installing.md b/tutorials/installing.md index 555bcce2b..ab7e1a3a9 100644 --- a/tutorials/installing.md +++ b/tutorials/installing.md @@ -99,22 +99,3 @@ Open a command line to that folder and run: This starts the [http://www.mozilla.org/rhino/ Rhino JS engine]. Type quit() to exit. -## Updating JavaScriptMVC - -We are constantly improving JMVC. If you're using git, you can -just pull changes. Otherwise, to get the latest, most -error free code, in a console, type: - -@codestart text -> ./js documentjs/update -> ./js funcunit/update -> ./js jquery/update -> ./js steal/update -> ./js can/update -> ./js canui/update -@codeend -
- P.S. If you are using linux/mac you - want to use ./js and change \ - to /. -
diff --git a/tutorials/organizing.md b/tutorials/organizing.md index f4e363278..840f7860c 100644 --- a/tutorials/organizing.md +++ b/tutorials/organizing.md @@ -15,7 +15,7 @@ the reasons for doing this and patterns for doing it. ## Why Traditionally JavaScript, CSS and static resources were seen as second-class -citizens when compared to server code. JavaScript code was put in a single +citizens when compared to server code. JavaScript was put in a single flat 'scripts' folder that looked like: button.js @@ -36,12 +36,13 @@ increasingly represents a larger percentage of an app's codebase. What works for 10 files does not work for 100. Complicating matters, an individual JavaScript file might have dependencies on -non-JavaScript resources. It's easy to imagine a menu needing -a specific stylesheet, images, or [can.view client side template] to run. +non-JavaScript resources. A menu might need +a specific stylesheet, images, or [can.view client side template]. -Spreading these dependencies across images, styles, templates etc folders -leads to bad organization and potentially bad performance. For example, it can be -hard to know if a particular style rule is needed. +Spreading these dependencies across images, styles, and template folders +makes it more difficult to know what depends on what. Over the lifetime +of an an application, it makes it more likely you'll be loading +resources that are not needed. ### The Fix @@ -98,27 +99,27 @@ can be reused across several applications. It is the perfect place for reusable controls like a tabs widget. Typically folder names reflect the name of the organization building the controls. -### Resource Types +### Module Types -An application is comprised of various resources. JavaScriptMVC's code generators can -be used to create these resources. +An application is comprised of various modules. JavaScriptMVC's code generators can +be used to create . -__Model__ - A model represents a set of services. Typically, they exist within -an application folder's models directory and are used to request -data by other controls. +__Model__ - A model represents a set of services. Typically, models exist within +an application folder's `models` directory and are used to request +data. Generate a model like: js jmvc\generate\model cms\models\image - -__Controller__ - A controller is a widget or code that combines and organizes -several widgets. Reusable widgets are added to library folders. Controllers specific +__Control__ - A [can.Control] can be a traditional view (a tabs widget) or +a traditional controller (coordinates model and view). Reusable controls are +added to library folders. Controls specific to an application should be put in a folder within an application folder. Generate a controller like: - js jmvc\generate\controller bitovi\tabs + js jmvc\generate\control bitovi\tabs __Plugin__ - A plugin is a low-level reusable module such as a special event or dom extension. @@ -160,25 +161,30 @@ enough to produces the desired functionality. In this case, steal('bitovi/tabs', 'bitovi/grid', 'bitovi/create', - './models/image', - './models/video', - './models/article',function(){ + './models/image.js', + './models/video.js', + './models/article.js', + function( + Tabs, Grid, Create, + Image, Video, Article + ){ // add tabs to the page - var tabs = new Bitovi.Tabs('#tabs'); + var tabs = new Tabs('#tabs'); // Configure the video grid - var videos = new Bitovi.Grid('#videos', { + var videos = new Grid($videos, { model: Cms.Models.Video, view: "//cms/views/videos.ejs" - }) + }), + videoEdit = new Edit('#videoEdit') // listen for when a video is selected - videos.element.find('li').bind('selected', + videos.element.on('selected','li', function(ev, video){ // update the edit form with the selected // video's attributes - new Bitovi.Edit('#videoEdit', { model: video }); + videoEdit.update(video); } ); @@ -186,22 +192,24 @@ enough to produces the desired functionality. In this case, var images = new Bitovi.Grid('#images', { model: Cms.Models.Image, view: "//cms/views/images.ejs" - }); + }), + imageEdit = new Edit('#imageEdit'); - images.element.find('li').bind('selected', + images.element.on('selected','li', function(ev, image){ - new Bitovi.Edit('#imageEdit', { model: image }); + imageEdit.update(video); } ); - var articles = new Bitovi.Grid('#articles', { - model: Cms.Models.Article, + var articles = new Grid('#articles', { + model: Article, view: "//cms/views/article.ejs" - }) + }), + articleEdit = new Edit('#articleEdit'); - articles.element.find('li').bind('selected', + articles.element.on('selected','li', function(ev, article){ - new Bitovi.Edit('#articleEdit', { model: article }); + articleEdit.update(video); } ); @@ -220,7 +228,7 @@ the requirements of your application. For example, you might need to add specific functionality around listing and editing videos (such as a thumbnail editor). This is application specific functionality and belongs -in the application folder. We'll encapsulate it in a controller for each type: +in the application folder. We'll encapsulate it in a controller [can.Control] for each type: \cms \articles - the articles tab @@ -242,51 +250,52 @@ in the application folder. We'll encapsulate it in a controller for each type: 'cms/images', 'cms/videos', 'bitovi/tabs', - function(){ + function( + Articles, Images, Videos, Tabs + ){ - new Bitovi.Tabs('#tabs'); + new Tabs('#tabs'); // add the video grid - new Cms.Videos('#videos'); + new Videos('#videos'); // Do the same for images and articles - new Cms.Images('#images'); - new Cms.Articles('#articles'); + new Images('#images'); + new Articles('#articles'); }) cms/articles/articles.js might look like: - steal('bitovi/grid', + steal('can', + 'bitovi/grid', 'bitovi/edit', - 'can/control', - 'can/view/ejs', - 'bitovi/thumbnail', - function(){ + './init.ejs', + './article.ejs', + 'bitovi/models/article.js', + function(can, + Grid, Edit, + initEJS, articleEJS, + Article){ + + return can.Control({ - can.Control('Cms.Articles', - { }, - { init : function(){ // draw the html for the tab - this.element.html('//cms/articles/views/init.ejs',{}); + this.element.html(initEJS({})); // configure the grid - new Bitovi.Grid(this.find('.grid'), { - model: Cms.Models.Article, - view: "//cms/articles/views/article.ejs" + new Grid(this.find('.grid'), { + model: Article, + view: articleEJS }) - }); + + this.editor = new Edit(".edit") }, // when the grid triggers a select event - " select" : function(el, ev){ - var editor = new Bitovi.Edit({ - model: el.data('model') - }) - - // add the thumbnail editor - new Bitovi.Thumbnail(editor.find('.thumbs')); + "li select" : function(el, ev, article){ + this.editor.update(article) } }); @@ -328,51 +337,44 @@ folder structure would look like: \grid -cms/articles/articles.js might now look like: +`cms/articles/articles.js` would look the same, except it would +change __Grid__ and __Edit__ to point to `cms/articles/grid` and +`cms/articles/edit`: + - steal('cms/articles/grid', + steal('can', + 'cms/articles/grid', 'cms/articles/edit', - 'can/control', - 'can/view/ejs', - function(){ - - can.Control('Cms.Articles', - { }, - { - init : function(){ - // draw the initial html - this.element.html('//cms/articles/views/init.ejs',{}); - - // create the articles grid - new Cms.Articles.Grid(this.find('.grid')); - }, - " select" : function(el, ev, article){ - - // update the articles edit control - new Cms.Articles.Edit(this.find('.edit'), { - model: article - }); - } - }); + './init.ejs', + './article.ejs', + 'bitovi/models/article.js', + function(can, + Grid, Edit, + initEJS, articleEJS, + Article){ + ... }) JavaScriptMVC encourages you to organize your application folder as a tree. The leaves of the tree are micro-controls that perform a specific task (such as allowing the editing of videos). -Higher-order controls (cms/articles/articles.js) combine leaves and other nodes +Higher-order controls (`cms/articles/articles.js`) combine leaves and other nodes into more complex functionality. The root of the application is the application file -(cms/cms.js). It combines and configures all high-level widgets. +(`cms/cms.js`). It combines and configures all high-level widgets. + +Communication between modules is done with the observer +pattern ([can.compute] or [can.Observe]) or with events. -In general, low-level controls use can.trigger to send messages 'up' to higher-order +With events, low-level controls use `$.fn.trigger` to send messages 'up' to higher-order controls. Higher-order controls typically call methods on lower-level controls -The Cms.Articles control listening to a 'select' event produced by -Cms.Articles.Grid and creating (or updating) the Cms.Articles.Edit control +The Articles control listening to a 'select' event produced by +Grid and creating (or updating) the Edit control is a great example of this. The situation where this breaks down is usually when a 'state' needs to be shared and communicated -across several controls. [can.Observe] and client [can.Model models] are useful +across several controls. [can.Observe] and [can.Observe] are useful for this situation. ## Conclusion From 6dfc4aabb925eb9f51553aeddd117fcb58fb024d Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Wed, 20 Mar 2013 00:36:51 -0500 Subject: [PATCH 06/54] moving jquerypp submodule in jquery folder to jquerypp folder --- .gitmodules | 6 +++--- jquery => jquerypp | 0 steal | 2 +- stealconfig.js | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) rename jquery => jquerypp (100%) diff --git a/.gitmodules b/.gitmodules index e24b5d3fb..3d1d77e26 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,6 @@ [submodule "canui"] path = canui url = git://github.com/bitovi/canui.git -[submodule "jquery"] - path = jquery - url = git://github.com/bitovi/jquerypp.git [submodule "steal"] path = steal url = git://github.com/bitovi/steal.git @@ -16,3 +13,6 @@ [submodule "documentjs"] path = documentjs url = git://github.com/bitovi/documentjs.git +[submodule "jquerypp"] + path = jquerypp + url = git://github.com/bitovi/jquerypp.git diff --git a/jquery b/jquerypp similarity index 100% rename from jquery rename to jquerypp diff --git a/steal b/steal index 6c6a805c2..4cc97f31c 160000 --- a/steal +++ b/steal @@ -1 +1 @@ -Subproject commit 6c6a805c204208d0ffd619fe8eb6b71b1dcf8b50 +Subproject commit 4cc97f31c07c5b3b31aa26ff99c17fd9f4a06969 diff --git a/stealconfig.js b/stealconfig.js index 73c00c553..0707ac946 100644 --- a/stealconfig.js +++ b/stealconfig.js @@ -2,7 +2,8 @@ steal.config({ map: { "*": { "jquery/jquery.js" : "jquery", - "can/util/util.js": "can/util/jquery/jquery.js" + "can/util/util.js": "can/util/jquery/jquery.js", + "jquery/": "jquerypp/" } }, paths: { From a06833699fcc9a4e1960fafd15ddbe54ac2bfd0a Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Wed, 20 Mar 2013 00:38:49 -0500 Subject: [PATCH 07/54] pointing to jquerypp's jquerypp branch --- jquerypp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jquerypp b/jquerypp index 33bc4f89c..9fb75b3a1 160000 --- a/jquerypp +++ b/jquerypp @@ -1 +1 @@ -Subproject commit 33bc4f89c9388ed1b985a6cf06277f37eec09424 +Subproject commit 9fb75b3a19b95be73b47a124c714189f522f0b5a From 4f90582996623cb32ba6f6e9fd49ca999752b9a4 Mon Sep 17 00:00:00 2001 From: Alexis Abril Date: Fri, 22 Mar 2013 14:23:30 -0500 Subject: [PATCH 08/54] Updating build tasks & can/jquery refs. --- build/tasks/bannerize.js | 17 +-- build/tasks/beautify.js | 3 +- build/tasks/build.js | 38 +++--- build/tasks/docco.js | 4 +- build/tasks/utils.js | 244 +++++++++++++++++++-------------------- can | 2 +- jquery | 2 +- package.json | 9 +- 8 files changed, 153 insertions(+), 166 deletions(-) diff --git a/build/tasks/bannerize.js b/build/tasks/bannerize.js index d97720469..8d49da5e6 100644 --- a/build/tasks/bannerize.js +++ b/build/tasks/bannerize.js @@ -3,21 +3,14 @@ var path = require('path'); // A grunt task that strips multiline comments module.exports = function (grunt) { grunt.registerMultiTask('bannerize', 'Adds the banner to a set of files', function () { - var _ = grunt.utils._; var options = grunt.config.process(['bannerize', this.target]); - var banner = grunt.helper('banner'); - var defaults = _.extend({ exclude : [] }, grunt.config('strip')._options); - grunt.file.expandFiles(this.file.src).forEach(function (file) { - for(var i = 0; i < defaults.exclude.length; i++) { - if(defaults.exclude[i].test(file)) { - return; - } - } + var banner = this.data.banner; + + grunt.file.expand(this.data.files).forEach(function (file) { var outFile = options.out ? path.join(options.out, path.basename(file)) : file; - grunt.log.writeln('Adding banner to ' + file); - var code = grunt.helper('file_strip_banner', file, { block : true }); - grunt.file.write(outFile, banner + code); + grunt.log.writeln('Adding banner to ' + file); + grunt.file.write(outFile, banner + grunt.file.read(file)); }); }); } diff --git a/build/tasks/beautify.js b/build/tasks/beautify.js index de999530e..3728a8966 100644 --- a/build/tasks/beautify.js +++ b/build/tasks/beautify.js @@ -38,7 +38,8 @@ module.exports = function (grunt) { // Beautify specified files. var excludes = grunt.config(['beautifier', this.target, 'exclude']); - grunt.file.expandFiles(this.file.src).filter(function (file) { + + grunt.file.expand(this.filesSrc).filter(function (file) { for (var i = 0; i < excludes.length; i++) { if (excludes[i].test(file)) { grunt.log.writeln('Not beautifying ' + file); diff --git a/build/tasks/build.js b/build/tasks/build.js index 63537e8f3..69c13dbf7 100644 --- a/build/tasks/build.js +++ b/build/tasks/build.js @@ -5,35 +5,27 @@ module.exports = function( grunt ) { grunt.registerMultiTask('build', 'Runs build files.', function() { var done = this.async(); var target = this.target; - var files = Array.isArray(this.file.src) ? this.file.src : [this.file.src]; - // TODO grunt.file.expandFiles(this.file.src); - var series = files.map(function (file) { - return function(callback) { - var options = grunt.config.process(['build', target]); - var args = [file, options.out || 'dist/', options.version || 'edge']; - var libraries = Array.isArray(options.libraries) ? options.libraries : []; - args.push.apply(args, libraries); + var options = grunt.config.process(['build', target]); + var args = [this.data.src, this.data.out || 'dist/', this.data.version || 'edge']; + var libraries = Array.isArray(this.data.libraries) ? this.data.libraries : []; - grunt.verbose.writeflags(options, 'Options'); - grunt.log.writeln('Running ./js ' + args.join(' ')); + args.push.apply(args, libraries); - grunt.utils.exec({ - cmd : "./js", - args : args, - opts : { - cwd: jsDir - } - }, function(error, result, code) { - callback(error, result, code); - }); + grunt.verbose.writeflags(this.data, 'Options'); + grunt.log.writeln('Running ./js ' + args.join(' ')); - grunt.log.write("Building " + file + " with Steal...\n"); + grunt.util.spawn({ + cmd : "./js", + args : args, + opts : { + cwd: jsDir } - }); - grunt.utils.async.parallel(series, function(error, results) { + }, function(error, result, code) { grunt.log.writeln('Done building'); done(); - }) + }); + + grunt.log.write("Building " + this.data.src + " with Steal...\n"); }); }; diff --git a/build/tasks/docco.js b/build/tasks/docco.js index 8b80d8d11..183534f57 100644 --- a/build/tasks/docco.js +++ b/build/tasks/docco.js @@ -5,14 +5,14 @@ var docco = require('docco'); module.exports = function(grunt) { grunt.registerMultiTask('docco', 'Docco processor.', function() { - var _ = grunt.utils._; + var _ = grunt.util._; var options = grunt.config.process(['docco', this.target]); var defaults = _.extend({ exclude : [/\.min\./] }, grunt.config.process('docco')._options); grunt.verbose.writeflags(options, 'Options'); var done = this.async(); - var src = grunt.file.expandFiles(this.file.src).filter(function(file) { + var src = grunt.file.expand(this.data.src).filter(function(file) { for(var i = 0; i < defaults.exclude.length; i++) { if(defaults.exclude[i].test(file)) { return false; diff --git a/build/tasks/utils.js b/build/tasks/utils.js index 4f014fd54..a49c2b29e 100644 --- a/build/tasks/utils.js +++ b/build/tasks/utils.js @@ -1,137 +1,137 @@ -var spawn = require("child_process").spawn; +// var spawn = require("child_process").spawn; -// { -// // The command to execute. It should be in the system path. -// cmd: commandToExecute, -// // An array of arguments to pass to the command. -// args: arrayOfArguments, -// // Additional options for the Node.js child_process spawn method. -// opts: nodeSpawnOptions -// } +// // { +// // // The command to execute. It should be in the system path. +// // cmd: commandToExecute, +// // // An array of arguments to pass to the command. +// // args: arrayOfArguments, +// // // Additional options for the Node.js child_process spawn method. +// // opts: nodeSpawnOptions +// // } -module.exports = function (grunt) { - grunt.utils.exec = function (options, callback) { - var build = grunt.utils.spawn(options, callback); +// module.exports = function (grunt) { +// grunt.utils.exec = function (options, callback) { +// var build = grunt.util.spawn(options, callback); - build.stdout.on("data", function (buf) { - grunt.log.write("" + buf); - }); +// build.stdout.on("data", function (buf) { +// grunt.log.write("" + buf); +// }); - build.stderr.on("data", function (buf) { - grunt.log.write("" + buf); - }); +// build.stderr.on("data", function (buf) { +// grunt.log.write("" + buf); +// }); - build.on("exit", function (code) { - callback(null, code); - }); +// build.on("exit", function (code) { +// callback(null, code); +// }); - return build; - }; +// return build; +// }; - // Generated by CoffeeScript 1.3.1 - (function () { - var crypto, https, joinBuffers, postToS3, readText, signPolicy, url, _ref; +// // Generated by CoffeeScript 1.3.1 +// (function () { +// var crypto, https, joinBuffers, postToS3, readText, signPolicy, url, _ref; - url = require('url'); +// url = require('url'); - https = require('https'); +// https = require('https'); - crypto = require('crypto'); +// crypto = require('crypto'); - _ref = require('tafa-misc-util'), joinBuffers = _ref.joinBuffers, readText = _ref.readText; +// _ref = require('tafa-misc-util'), joinBuffers = _ref.joinBuffers, readText = _ref.readText; - signPolicy = function (secretKey, policy) { - var data, hmac, json, key, policy64, signature64; - json = JSON.stringify(policy); - policy64 = new Buffer(json).toString('base64'); - data = new Buffer(policy64, 'utf-8'); - key = new Buffer(secretKey, 'utf-8'); - hmac = crypto.createHmac('sha1', key); - hmac.update(data); - signature64 = hmac.digest('base64'); - return { - signature64 : signature64, - policy64 : policy64 - }; - }; +// signPolicy = function (secretKey, policy) { +// var data, hmac, json, key, policy64, signature64; +// json = JSON.stringify(policy); +// policy64 = new Buffer(json).toString('base64'); +// data = new Buffer(policy64, 'utf-8'); +// key = new Buffer(secretKey, 'utf-8'); +// hmac = crypto.createHmac('sha1', key); +// hmac.update(data); +// signature64 = hmac.digest('base64'); +// return { +// signature64 : signature64, +// policy64 : policy64 +// }; +// }; - postToS3 = function (_arg, callback) { - var AWSAccessKeyId, Filename, acl, addParam, arr, boundary, bucket, buf, ca, contentType, customUrl, data, host, hostname, key, options, policy64, port, protocol, req, req_body, signature64, success_action_status, _ref1; - AWSAccessKeyId = _arg.AWSAccessKeyId, policy64 = _arg.policy64, signature64 = _arg.signature64, bucket = _arg.bucket, key = _arg.key, data = _arg.data, boundary = _arg.boundary, customUrl = _arg.customUrl, ca = _arg.ca, acl = _arg.acl, success_action_status = _arg.success_action_status, Filename = _arg.Filename, contentType = _arg.contentType; - if (callback == null) { - callback = (function () { - }); - } - if (customUrl) { - _ref1 = url.parse(customUrl), protocol = _ref1.protocol, hostname = _ref1.hostname, port = _ref1.port; - if (protocol !== "https:") { - return callback(new Error("customUrl must be https://")); - } - host = hostname; - port || (port = 443); - } else { - host = "" + bucket + ".s3.amazonaws.com"; - port = 443; - } - boundary || (boundary = '----------R46EARkAg4SAXSjufGsb6m'); - buf = function (x) { - return new Buffer(x); - }; - arr = []; - addParam = function (k, v) { - arr.push(buf('--' + boundary + '\r\n')); - arr.push(buf('Content-Disposition: form-data; name="' + k + '"\r\n\r\n')); - return arr.push(buf(v), buf('\r\n')); - }; - addParam('key', key); - addParam('acl', acl); - addParam('success_action_status', success_action_status); - addParam('Filename', Filename); - addParam('AWSAccessKeyId', AWSAccessKeyId); - addParam('Policy', policy64); - addParam('Signature', signature64); - addParam('Content-Type', contentType); - arr.push(buf('--' + boundary + '\r\n')); - arr.push(buf('Content-Disposition: form-data; name="file"; filename="data"\r\n')); - arr.push(buf("Content-Length: " + data.length + "\r\n")); - arr.push(buf('Content-Transfer-Encoding: binary\r\n\r\n')); - arr.push(data, buf('\r\n')); - arr.push(buf('--' + boundary + '--')); - req_body = joinBuffers(arr); - options = { - host : host, - port : port, - path : '/', - method : 'POST', - headers : { - 'Host' : "" + bucket + ".s3.amazonaws.com", - 'Content-Type' : 'multipart/form-data; boundary=' + boundary, - 'Content-Length' : req_body.length - } - }; - if (ca) { - options.ca = ca; - } - req = https.request(options, function (res) { - var _ref2; - if ((200 <= (_ref2 = res.statusCode) && _ref2 < 300)) { - return callback(null); - } else { - return readText(res, function (text) { - return callback({ - responseCode : res.statusCode, - responseText : text - }); - }); - } - }); - return req.end(req_body); - }; +// postToS3 = function (_arg, callback) { +// var AWSAccessKeyId, Filename, acl, addParam, arr, boundary, bucket, buf, ca, contentType, customUrl, data, host, hostname, key, options, policy64, port, protocol, req, req_body, signature64, success_action_status, _ref1; +// AWSAccessKeyId = _arg.AWSAccessKeyId, policy64 = _arg.policy64, signature64 = _arg.signature64, bucket = _arg.bucket, key = _arg.key, data = _arg.data, boundary = _arg.boundary, customUrl = _arg.customUrl, ca = _arg.ca, acl = _arg.acl, success_action_status = _arg.success_action_status, Filename = _arg.Filename, contentType = _arg.contentType; +// if (callback == null) { +// callback = (function () { +// }); +// } +// if (customUrl) { +// _ref1 = url.parse(customUrl), protocol = _ref1.protocol, hostname = _ref1.hostname, port = _ref1.port; +// if (protocol !== "https:") { +// return callback(new Error("customUrl must be https://")); +// } +// host = hostname; +// port || (port = 443); +// } else { +// host = "" + bucket + ".s3.amazonaws.com"; +// port = 443; +// } +// boundary || (boundary = '----------R46EARkAg4SAXSjufGsb6m'); +// buf = function (x) { +// return new Buffer(x); +// }; +// arr = []; +// addParam = function (k, v) { +// arr.push(buf('--' + boundary + '\r\n')); +// arr.push(buf('Content-Disposition: form-data; name="' + k + '"\r\n\r\n')); +// return arr.push(buf(v), buf('\r\n')); +// }; +// addParam('key', key); +// addParam('acl', acl); +// addParam('success_action_status', success_action_status); +// addParam('Filename', Filename); +// addParam('AWSAccessKeyId', AWSAccessKeyId); +// addParam('Policy', policy64); +// addParam('Signature', signature64); +// addParam('Content-Type', contentType); +// arr.push(buf('--' + boundary + '\r\n')); +// arr.push(buf('Content-Disposition: form-data; name="file"; filename="data"\r\n')); +// arr.push(buf("Content-Length: " + data.length + "\r\n")); +// arr.push(buf('Content-Transfer-Encoding: binary\r\n\r\n')); +// arr.push(data, buf('\r\n')); +// arr.push(buf('--' + boundary + '--')); +// req_body = joinBuffers(arr); +// options = { +// host : host, +// port : port, +// path : '/', +// method : 'POST', +// headers : { +// 'Host' : "" + bucket + ".s3.amazonaws.com", +// 'Content-Type' : 'multipart/form-data; boundary=' + boundary, +// 'Content-Length' : req_body.length +// } +// }; +// if (ca) { +// options.ca = ca; +// } +// req = https.request(options, function (res) { +// var _ref2; +// if ((200 <= (_ref2 = res.statusCode) && _ref2 < 300)) { +// return callback(null); +// } else { +// return readText(res, function (text) { +// return callback({ +// responseCode : res.statusCode, +// responseText : text +// }); +// }); +// } +// }); +// return req.end(req_body); +// }; - grunt.utils.s3 = { - postToS3 : postToS3, - signPolicy : signPolicy - }; +// grunt.utils.s3 = { +// postToS3 : postToS3, +// signPolicy : signPolicy +// }; - }).call(this); -} \ No newline at end of file +// }).call(this); +// } \ No newline at end of file diff --git a/can b/can index a42d77963..fd4ea82ea 160000 --- a/can +++ b/can @@ -1 +1 @@ -Subproject commit a42d779637c0ca251415a245a064e4c49b6aec77 +Subproject commit fd4ea82ea8ac0184b072ead092b30c5551e80c05 diff --git a/jquery b/jquery index 33bc4f89c..dac4f7991 160000 --- a/jquery +++ b/jquery @@ -1 +1 @@ -Subproject commit 33bc4f89c9388ed1b985a6cf06277f37eec09424 +Subproject commit dac4f7991e61f556f830ed6347fbd5151128ed5c diff --git a/package.json b/package.json index 0ce06db85..a0c7cf6ba 100644 --- a/package.json +++ b/package.json @@ -8,15 +8,16 @@ "web": "http://bitovi.com/" }, "devDependencies": { - "grunt": "~0.4.0", - "grunt-closure-tools": "~0.6.2", + "grunt": "0.4.0", + "grunt-closure-tools": "0.7.7", "http-server": "0.5.1", - "docco": ">= 0.1.x", + "docco": ">= 0.5.0", "node-beautify": "*", "github": ">= 0.1.7", "commander": "*", "tafa-misc-util": "*", - "grunt-contrib-connect": "~0.1.2" + "lodash" : "0.1.0", + "grunt-contrib-connect": "0.1.2" }, "homepage": "http://javascriptmvc.com/", "repository": { From ae81f6a939e63e586dc47e1b16e89c2a87526d84 Mon Sep 17 00:00:00 2001 From: Alexis Abril Date: Fri, 22 Mar 2013 14:24:19 -0500 Subject: [PATCH 09/54] Removing shell/strip tasks --- build/tasks/shell.js | 52 -------------------------------------------- build/tasks/strip.js | 36 ------------------------------ 2 files changed, 88 deletions(-) delete mode 100644 build/tasks/shell.js delete mode 100644 build/tasks/strip.js diff --git a/build/tasks/shell.js b/build/tasks/shell.js deleted file mode 100644 index 89d28831a..000000000 --- a/build/tasks/shell.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * grunt-shell - * 0.1.2 - 2012-06-28 - * github.com/sindresorhus/grunt-shell - * - * (c) Sindre Sorhus - * sindresorhus.com - * MIT License - */ -module.exports = function (grunt) { - 'use strict'; - - var _ = grunt.utils._; - var log = grunt.log; - - grunt.registerMultiTask('shell', 'Run shell commands', function () { - var exec = require('child_process').exec; - var done = this.async(); - var data = _.extend([], grunt.config.get('shell')._options, this.data); - var dataOut = data.stdout; - var dataErr = data.stderr; - - if (_.isFunction(data.callback)) { - data.callback.call(this); - return; - } - - var command = grunt.template.process(this.file.src); - log.writeln('Running ' + command); - exec(command, data.execOptions, function (err, stdout, stderr) { - if (stdout) { - if (_.isFunction(dataOut)) { - dataOut(stdout); - } else if (dataOut === true) { - log.write(stdout); - } - } - - if (err) { - if (_.isFunction(dataErr)) { - dataErr(stderr); - } else if (data.failOnError === true) { - grunt.fatal(err); - } else if (dataErr === true) { - log.error(err); - } - } - - done(); - }); - }); -}; \ No newline at end of file diff --git a/build/tasks/strip.js b/build/tasks/strip.js deleted file mode 100644 index 31558b192..000000000 --- a/build/tasks/strip.js +++ /dev/null @@ -1,36 +0,0 @@ -var path = require('path'); - -// A grunt task that strips multiline comments -module.exports = function (grunt) { - grunt.registerMultiTask('strip', 'Remove multiline comments from files', function () { - var _ = grunt.utils._; - var options = grunt.config.process(['strip', this.target]); - var defaults = _.extend({ - exclude : [/\.min\./] - }, grunt.config('strip')._options); - grunt.file.expandFiles(this.file.src).forEach(function (file) { - for(var i = 0; i < defaults.exclude.length; i++) { - if(defaults.exclude[i].test(file)) { - return; - } - } - var outFile = options.out ? path.join(options.out, path.basename(file)) : file; - grunt.log.writeln('Stripping ' + file + ' of all multiline and empty inline comments'); - - var code = grunt.file.read(file); - - // Remove multiline comments - code = code.replace(/\/\*([\s\S]*?)\*\//gim, "") - .replace(/\/\/(\s*)\n/gim, ""); - - // Remove double semicolons from steal pluginify - code = code.replace(/;[\s]*;/gim, ";"); - code = code.replace(/(\/\/.*)\n[\s]*;/gi, "$1"); - - // Only single new lines - code = code.replace(/(\n){3,}/gim, "\n\n"); - - grunt.file.write(outFile, code); - }); - }); -} From 6d3b2334e6be45bbba4f6354e6b6107ebcc0be69 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Sun, 24 Mar 2013 13:48:50 -0600 Subject: [PATCH 10/54] Updating references and Grunt to 0.4 --- build/tasks/bannerize.js | 2 +- build/tasks/docco.js | 22 +++---- build/tasks/downloads.js | 103 ----------------------------- build/tasks/utils.js | 137 --------------------------------------- can | 2 +- grunt.js | 3 - package.json | 2 +- steal | 2 +- 8 files changed, 12 insertions(+), 261 deletions(-) delete mode 100644 build/tasks/downloads.js delete mode 100644 build/tasks/utils.js delete mode 100644 grunt.js diff --git a/build/tasks/bannerize.js b/build/tasks/bannerize.js index 8d49da5e6..2eb1540df 100644 --- a/build/tasks/bannerize.js +++ b/build/tasks/bannerize.js @@ -1,6 +1,6 @@ var path = require('path'); -// A grunt task that strips multiline comments +// A grunt task that writes the banner to every file module.exports = function (grunt) { grunt.registerMultiTask('bannerize', 'Adds the banner to a set of files', function () { var options = grunt.config.process(['bannerize', this.target]); diff --git a/build/tasks/docco.js b/build/tasks/docco.js index 183534f57..964a668c3 100644 --- a/build/tasks/docco.js +++ b/build/tasks/docco.js @@ -6,23 +6,17 @@ var docco = require('docco'); module.exports = function(grunt) { grunt.registerMultiTask('docco', 'Docco processor.', function() { var _ = grunt.util._; - var options = grunt.config.process(['docco', this.target]); - var defaults = _.extend({ - exclude : [/\.min\./] - }, grunt.config.process('docco')._options); - grunt.verbose.writeflags(options, 'Options'); var done = this.async(); - var src = grunt.file.expand(this.data.src).filter(function(file) { - for(var i = 0; i < defaults.exclude.length; i++) { - if(defaults.exclude[i].test(file)) { - return false; - } - } - return true; + var options = this.options(); + var src = grunt.file.expand(this.data.files).filter(function(file) { + return !_.some(options.exclude, function(exclude) { + return exclude.test(file); + }); }); - docco.document(src, _.extend({}, defaults.docco, options.docco) || {}, function(err, result, code){ - grunt.log.writeln("Doccoed [" + src.join(", ") + "]; " + err ? err : "(No errors)" + "\n" + result + " " + code); + docco.document( _.extend({ args: src }, this.data.docco, options.docco), function(err, result, code){ + grunt.log.writeln("Doccoed [" + src.join(", ") + "]; " + + err ? err : "(No errors)" + "\n" + result + " " + code); done(); }); }); diff --git a/build/tasks/downloads.js b/build/tasks/downloads.js deleted file mode 100644 index e2c29abe4..000000000 --- a/build/tasks/downloads.js +++ /dev/null @@ -1,103 +0,0 @@ -var program = require("commander"); -var GitHubApi = require("github"); -var authenticated = false; -var fs = require('fs'); -var github = new GitHubApi({ - version : "3.0.0" -}); -var getCredentials = function (callback) { - if(authenticated) { - return callback(); - } - - program.prompt("Github Username: ", function (name) { - var username = name; - - program.password("Github Password: ", "*", function (pass) { - var password = pass; - process.stdin.pause(); - github.authenticate({ - type : "basic", - username : username, - password : password - }); - authenticated = true; - callback(); - }); - - }); -} - -module.exports = function (grunt) { - grunt.registerMultiTask('downloads', 'Uploads generated files as GitHub downloads.', function () { - if(this.target == '_options') { - return; - } - - var _ = grunt.utils._; - var done = this.async(); - var ops = grunt.config(['downloads', this.target]); - var defaults = _.extend({}, grunt.config(['downloads', '_options'])); - var sourceFile = this.file.src; - - var desc = grunt.template.process(ops.description); - var name = grunt.template.process(ops.filename); - - grunt.log.writeln('Deploying ' + desc); - fs.readFile(sourceFile, function (err, buf) { - if (err) { - return grunt.fail.fatal(err); - } - - var createDownload = function() { - github.httpSend({ - "user" : defaults.user, - "repo" : defaults.repository, - "name" : name, - "size" : buf.length, - "description" : desc, - "content_type" : ops.content_type || "text/javascript" - }, { - "url" : "/repos/:user/:repo/downloads", - "method" : "POST", - "params" : { - "$user" : null, - "$repo" : null, - "$name" : null, - "$size" : null, - "description" : null, - "$content_type" : null - } - }, function (err, socket) { - if(err) { - return grunt.fail.fatal(err); - } - var data = JSON.parse(socket.data); - - grunt.utils.s3.postToS3({ - key : data.path, - acl : data.acl, - success_action_status : "201", - Filename : data.name, - AWSAccessKeyId : data.accesskeyid, - policy64 : data.policy, - signature64 : data.signature, - contentType : data.mime_type, - data : buf, - bucket : "github" - }, function (e) { - if(e) { - return grunt.fail.fatal(e); - } - grunt.log.writeln('Successfully created GitHub download and uploaded to S3.'); - done(); - }) - }); - } - - grunt.log.writeln('Uploading to ' + defaults.user + '/' + defaults.repository + '/' + name); - getCredentials(createDownload); - - }); - }); -} \ No newline at end of file diff --git a/build/tasks/utils.js b/build/tasks/utils.js deleted file mode 100644 index a49c2b29e..000000000 --- a/build/tasks/utils.js +++ /dev/null @@ -1,137 +0,0 @@ -// var spawn = require("child_process").spawn; - -// // { -// // // The command to execute. It should be in the system path. -// // cmd: commandToExecute, -// // // An array of arguments to pass to the command. -// // args: arrayOfArguments, -// // // Additional options for the Node.js child_process spawn method. -// // opts: nodeSpawnOptions -// // } - -// module.exports = function (grunt) { -// grunt.utils.exec = function (options, callback) { -// var build = grunt.util.spawn(options, callback); - -// build.stdout.on("data", function (buf) { -// grunt.log.write("" + buf); -// }); - -// build.stderr.on("data", function (buf) { -// grunt.log.write("" + buf); -// }); - -// build.on("exit", function (code) { -// callback(null, code); -// }); - -// return build; -// }; - -// // Generated by CoffeeScript 1.3.1 -// (function () { -// var crypto, https, joinBuffers, postToS3, readText, signPolicy, url, _ref; - -// url = require('url'); - -// https = require('https'); - -// crypto = require('crypto'); - -// _ref = require('tafa-misc-util'), joinBuffers = _ref.joinBuffers, readText = _ref.readText; - -// signPolicy = function (secretKey, policy) { -// var data, hmac, json, key, policy64, signature64; -// json = JSON.stringify(policy); -// policy64 = new Buffer(json).toString('base64'); -// data = new Buffer(policy64, 'utf-8'); -// key = new Buffer(secretKey, 'utf-8'); -// hmac = crypto.createHmac('sha1', key); -// hmac.update(data); -// signature64 = hmac.digest('base64'); -// return { -// signature64 : signature64, -// policy64 : policy64 -// }; -// }; - -// postToS3 = function (_arg, callback) { -// var AWSAccessKeyId, Filename, acl, addParam, arr, boundary, bucket, buf, ca, contentType, customUrl, data, host, hostname, key, options, policy64, port, protocol, req, req_body, signature64, success_action_status, _ref1; -// AWSAccessKeyId = _arg.AWSAccessKeyId, policy64 = _arg.policy64, signature64 = _arg.signature64, bucket = _arg.bucket, key = _arg.key, data = _arg.data, boundary = _arg.boundary, customUrl = _arg.customUrl, ca = _arg.ca, acl = _arg.acl, success_action_status = _arg.success_action_status, Filename = _arg.Filename, contentType = _arg.contentType; -// if (callback == null) { -// callback = (function () { -// }); -// } -// if (customUrl) { -// _ref1 = url.parse(customUrl), protocol = _ref1.protocol, hostname = _ref1.hostname, port = _ref1.port; -// if (protocol !== "https:") { -// return callback(new Error("customUrl must be https://")); -// } -// host = hostname; -// port || (port = 443); -// } else { -// host = "" + bucket + ".s3.amazonaws.com"; -// port = 443; -// } -// boundary || (boundary = '----------R46EARkAg4SAXSjufGsb6m'); -// buf = function (x) { -// return new Buffer(x); -// }; -// arr = []; -// addParam = function (k, v) { -// arr.push(buf('--' + boundary + '\r\n')); -// arr.push(buf('Content-Disposition: form-data; name="' + k + '"\r\n\r\n')); -// return arr.push(buf(v), buf('\r\n')); -// }; -// addParam('key', key); -// addParam('acl', acl); -// addParam('success_action_status', success_action_status); -// addParam('Filename', Filename); -// addParam('AWSAccessKeyId', AWSAccessKeyId); -// addParam('Policy', policy64); -// addParam('Signature', signature64); -// addParam('Content-Type', contentType); -// arr.push(buf('--' + boundary + '\r\n')); -// arr.push(buf('Content-Disposition: form-data; name="file"; filename="data"\r\n')); -// arr.push(buf("Content-Length: " + data.length + "\r\n")); -// arr.push(buf('Content-Transfer-Encoding: binary\r\n\r\n')); -// arr.push(data, buf('\r\n')); -// arr.push(buf('--' + boundary + '--')); -// req_body = joinBuffers(arr); -// options = { -// host : host, -// port : port, -// path : '/', -// method : 'POST', -// headers : { -// 'Host' : "" + bucket + ".s3.amazonaws.com", -// 'Content-Type' : 'multipart/form-data; boundary=' + boundary, -// 'Content-Length' : req_body.length -// } -// }; -// if (ca) { -// options.ca = ca; -// } -// req = https.request(options, function (res) { -// var _ref2; -// if ((200 <= (_ref2 = res.statusCode) && _ref2 < 300)) { -// return callback(null); -// } else { -// return readText(res, function (text) { -// return callback({ -// responseCode : res.statusCode, -// responseText : text -// }); -// }); -// } -// }); -// return req.end(req_body); -// }; - -// grunt.utils.s3 = { -// postToS3 : postToS3, -// signPolicy : signPolicy -// }; - -// }).call(this); -// } \ No newline at end of file diff --git a/can b/can index fd4ea82ea..821135973 160000 --- a/can +++ b/can @@ -1 +1 @@ -Subproject commit fd4ea82ea8ac0184b072ead092b30c5551e80c05 +Subproject commit 8211359730c66aed3e3b451f919f62427df0adde diff --git a/grunt.js b/grunt.js deleted file mode 100644 index 9d5cb6995..000000000 --- a/grunt.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = function (grunt) { - -}; \ No newline at end of file diff --git a/package.json b/package.json index a0c7cf6ba..684c3377d 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "grunt": "0.4.0", "grunt-closure-tools": "0.7.7", "http-server": "0.5.1", - "docco": ">= 0.5.0", + "docco": "0.6.2", "node-beautify": "*", "github": ">= 0.1.7", "commander": "*", diff --git a/steal b/steal index 6c6a805c2..591b8433d 160000 --- a/steal +++ b/steal @@ -1 +1 @@ -Subproject commit 6c6a805c204208d0ffd619fe8eb6b71b1dcf8b50 +Subproject commit 591b8433da136dab6e7823d5bd8201a26506d298 From 69f659e1b0463bed8cbf65a56bd5ada1c022dcf5 Mon Sep 17 00:00:00 2001 From: Alexis Abril Date: Mon, 25 Mar 2013 16:37:50 -0500 Subject: [PATCH 11/54] Fixing steal reference. Closes #41 --- steal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/steal b/steal index 591b8433d..6c6a805c2 160000 --- a/steal +++ b/steal @@ -1 +1 @@ -Subproject commit 591b8433da136dab6e7823d5bd8201a26506d298 +Subproject commit 6c6a805c204208d0ffd619fe8eb6b71b1dcf8b50 From 69c8a7d70bbf13f5c989fdac5a9e391c80c8e924 Mon Sep 17 00:00:00 2001 From: Alexis Abril Date: Mon, 25 Mar 2013 17:42:49 -0500 Subject: [PATCH 12/54] Adding changelog task. Updating can ref to 1.1.5 --- build/changelog.ejs | 4 +++ build/tasks/changelog.js | 65 ++++++++++++++++++++++++++++++++++++++++ can | 2 +- package.json | 3 +- 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 build/changelog.ejs create mode 100644 build/tasks/changelog.js diff --git a/build/changelog.ejs b/build/changelog.ejs new file mode 100644 index 000000000..4205c23e0 --- /dev/null +++ b/build/changelog.ejs @@ -0,0 +1,4 @@ +__<%= version %>__ ( <%= date.toDateString().substring(4) %> ) +<% for(var i = 0; i < issues.length; i++) { %> +- change: [<%= issues[i].title %>](<%= issues[i].url %>)<% } %> + diff --git a/build/tasks/changelog.js b/build/tasks/changelog.js new file mode 100644 index 000000000..6215b6f25 --- /dev/null +++ b/build/tasks/changelog.js @@ -0,0 +1,65 @@ +var https = require('https'), +querystring = require('querystring'), +ejs = require('ejs'); + +module.exports = function(grunt) { + + grunt.registerMultiTask('changelog', 'Updates changelog.md based on GitHub milestones', function() { + var done = this.async(), + + params = querystring.stringify({ + milestone: this.data.milestone, + state: 'closed', + per_page: 100 + }), + + path = '/repos/' + this.data.user + '/' + this.data.repo + '/issues?' + params, + + buffer = '', + self = this; + + var write = function() { + var issues = JSON.parse(buffer), + log = ''; + + if(grunt.file.exists('changelog.md')) { + log = grunt.file.read('changelog.md'); + }; + + ejs.renderFile(__dirname + '/../changelog.ejs', { + version: self.data.version, + date: new Date(Date.now()), + issues: issues + }, function(e, template) { + + if(e) { + done(e); + } + + grunt.file.write('changelog.md', template + log); + done(); + + }); + }, + + req = https.request({ + hostname: 'api.github.com', + path: path + }, function(res) { + + res.on('data', function(data) { + buffer += data; + }); + + res.on('end', write); + }); + + req.end(); + + req.on('error', function(e) { + done(e); + }); + + }); + +} \ No newline at end of file diff --git a/can b/can index 821135973..dd1a48dee 160000 --- a/can +++ b/can @@ -1 +1 @@ -Subproject commit 8211359730c66aed3e3b451f919f62427df0adde +Subproject commit dd1a48deeded0e9ac720a07ec4801668f4d24442 diff --git a/package.json b/package.json index 684c3377d..0da8c169a 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "commander": "*", "tafa-misc-util": "*", "lodash" : "0.1.0", - "grunt-contrib-connect": "0.1.2" + "grunt-contrib-connect": "0.1.2", + "ejs": "0.8.3" }, "homepage": "http://javascriptmvc.com/", "repository": { From 29855120d7a601d390f203c12ff5f4714e6cf551 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Fri, 29 Mar 2013 11:24:08 -0600 Subject: [PATCH 13/54] Changing jQuery++ submodule folder. Removing CanUI for now. --- .gitmodules | 9 +++------ build/tasks/beautify.js | 5 +++++ can | 2 +- canui | 1 - jquery | 1 - jquerypp | 1 + stealconfig.js | 1 + 7 files changed, 11 insertions(+), 9 deletions(-) delete mode 160000 canui delete mode 160000 jquery create mode 160000 jquerypp diff --git a/.gitmodules b/.gitmodules index e24b5d3fb..5b2beb71d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,6 @@ [submodule "can"] path = can url = git://github.com/bitovi/canjs.git -[submodule "canui"] - path = canui - url = git://github.com/bitovi/canui.git -[submodule "jquery"] - path = jquery - url = git://github.com/bitovi/jquerypp.git [submodule "steal"] path = steal url = git://github.com/bitovi/steal.git @@ -16,3 +10,6 @@ [submodule "documentjs"] path = documentjs url = git://github.com/bitovi/documentjs.git +[submodule "jquerypp"] + path = jquerypp + url = https://github.com/bitovi/jquerypp.git diff --git a/build/tasks/beautify.js b/build/tasks/beautify.js index 3728a8966..db44f5673 100644 --- a/build/tasks/beautify.js +++ b/build/tasks/beautify.js @@ -40,6 +40,11 @@ module.exports = function (grunt) { var excludes = grunt.config(['beautifier', this.target, 'exclude']); grunt.file.expand(this.filesSrc).filter(function (file) { + if(/\.min\./.test(file)) { + grunt.log.writeln('Not beautifying ' + file); + return false; + } + for (var i = 0; i < excludes.length; i++) { if (excludes[i].test(file)) { grunt.log.writeln('Not beautifying ' + file); diff --git a/can b/can index 821135973..1df94a726 160000 --- a/can +++ b/can @@ -1 +1 @@ -Subproject commit 8211359730c66aed3e3b451f919f62427df0adde +Subproject commit 1df94a726c4741efe8b8230527cbd663c31c9e53 diff --git a/canui b/canui deleted file mode 160000 index 538977ddc..000000000 --- a/canui +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 538977ddc99e5d2ac2c87286c05da1c87451ead5 diff --git a/jquery b/jquery deleted file mode 160000 index dac4f7991..000000000 --- a/jquery +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dac4f7991e61f556f830ed6347fbd5151128ed5c diff --git a/jquerypp b/jquerypp new file mode 160000 index 000000000..7aa8096e3 --- /dev/null +++ b/jquerypp @@ -0,0 +1 @@ +Subproject commit 7aa8096e3212caa198a9fa322855fc389b8243c1 diff --git a/stealconfig.js b/stealconfig.js index 73c00c553..12c65f143 100644 --- a/stealconfig.js +++ b/stealconfig.js @@ -6,6 +6,7 @@ steal.config({ } }, paths: { + "jquery/": "jquerypp/", "jquery": "can/lib/jquery.1.9.1.js", "mootools/mootools.js" : "can/lib/mootools-core-1.4.5.js", "dojo/dojo.js" : "can/util/dojo/dojo-1.8.1.js", From 85740e5547a109f249256fd50ee3836ce8d82f04 Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Wed, 3 Apr 2013 19:13:21 -0500 Subject: [PATCH 14/54] updating documentjs submodule --- documentjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentjs b/documentjs index 91119826d..432b7adff 160000 --- a/documentjs +++ b/documentjs @@ -1 +1 @@ -Subproject commit 91119826df57d5c375a54b1351e04ecb5ef65439 +Subproject commit 432b7adfff5315ca0a5a0a80c7c0502ca7fe919a From 1cd2b9c31b922c9253aa9ff3b9711ff193cb4327 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Mon, 8 Apr 2013 19:10:34 -0600 Subject: [PATCH 15/54] Build tasks --- build/tasks/beautify.js | 5 ++-- build/tasks/testify.js | 53 +++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 3 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 build/tasks/testify.js diff --git a/build/tasks/beautify.js b/build/tasks/beautify.js index db44f5673..df48cf113 100644 --- a/build/tasks/beautify.js +++ b/build/tasks/beautify.js @@ -5,6 +5,7 @@ * Copyright (c) 2012 Camille Moncelier * Licensed under the MIT license. */ +var beautifier = require('js-beautify'); module.exports = function (grunt) { @@ -18,8 +19,6 @@ module.exports = function (grunt) { }; grunt.registerMultiTask('beautify', 'Javascript beautifier', function () { - var beautifier = require('node-beautify'); - var options = null; var tmp = grunt.config(['beautifier', this.target, 'options']); if (typeof tmp === 'object') { @@ -54,7 +53,7 @@ module.exports = function (grunt) { return true; }).forEach(function (filepath) { grunt.log.writeln('Beautifying ' + filepath); - var result = beautifier.beautifyJs(grunt.file.read(filepath), options); + var result = beautifier(grunt.file.read(filepath), options); grunt.file.write(filepath, result); }); diff --git a/build/tasks/testify.js b/build/tasks/testify.js new file mode 100644 index 000000000..a330b4896 --- /dev/null +++ b/build/tasks/testify.js @@ -0,0 +1,53 @@ +var ejs = require('ejs'); +var beautify = require('js-beautify'); + +module.exports = function(grunt) { + var _ = grunt.util._; + + grunt.registerMultiTask('testify', 'Generates test runners', function() { + var done = this.async(); + var data = this.data; + var template = grunt.file.read(this.data.template); + var transform = this.data.transform; + var modules = this.data.builder.modules; + var configurations = this.data.builder.configurations; + + if(transform && transform.modules) { + modules = transform.modules(modules); + } + + _.each(configurations, function(config, configurationName) { + var options = { + configuration: config, + modules: [], + tests: [], + root: data.root + }; + + _.each(modules, function(definition, key) { + if(!definition.configurations || definition.configurations.indexOf(configurationName) !== -1) { + var name = key.substr(key.lastIndexOf('/') + 1); + options.modules.push(key); + options.tests.push(key + '/' + name + '_test.js'); + } + }); + + _.extend(config.steal, { + root: '../..' + }); + + if(transform && transform.options) { + _.extend(options, transform.options.call(config, configurationName)); + } + + var lib = beautify.html(ejs.render(template, options), { + "wrap_line_length": 70 + }); + + grunt.log.writeln('Generating ' + data.out + configurationName + '.html'); + grunt.file.write(data.out + configurationName + '.html', lib); + }); + + done(); + }); +}; \ No newline at end of file diff --git a/package.json b/package.json index 0da8c169a..c09924fdb 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "grunt-closure-tools": "0.7.7", "http-server": "0.5.1", "docco": "0.6.2", - "node-beautify": "*", + "js-beautify": "1.2.0", "github": ">= 0.1.7", "commander": "*", "tafa-misc-util": "*", From 02548a9349ea3addeb348097097e9761197c5415 Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Wed, 17 Apr 2013 12:44:05 -0500 Subject: [PATCH 16/54] latest greatest --- can | 2 +- jquerypp | 2 +- tutorials/examples/srchr.md | 349 +---------------------------- tutorials/installing.md | 4 +- tutorials/rapidstart/rapidstart.md | 4 +- 5 files changed, 12 insertions(+), 349 deletions(-) diff --git a/can b/can index 1df94a726..e7e335b61 160000 --- a/can +++ b/can @@ -1 +1 @@ -Subproject commit 1df94a726c4741efe8b8230527cbd663c31c9e53 +Subproject commit e7e335b615bf5ca22b25bd338a0b2fd3690706f6 diff --git a/jquerypp b/jquerypp index 7aa8096e3..02aed6a7a 160000 --- a/jquerypp +++ b/jquerypp @@ -1 +1 @@ -Subproject commit 7aa8096e3212caa198a9fa322855fc389b8243c1 +Subproject commit 02aed6a7abb43bd1cccd9259362d1d0969439871 diff --git a/tutorials/examples/srchr.md b/tutorials/examples/srchr.md index 05a1ed798..815fc37e3 100644 --- a/tutorials/examples/srchr.md +++ b/tutorials/examples/srchr.md @@ -3,17 +3,13 @@ Srchr searches several data sources for content and displays it to the user. See it in -action [here](http://javascriptmvc.com/srchr/srchr.html). This article covers: +action [here](http://javascriptmvc.com/srchr/srchr.html). This article +covers how to install Srchr. To understand how Srchr works and many +of the core concepts behind JavaScriptMVC, please watch: -- Installing Srchr -- The ideas behind JavaScriptMVC (JMVC) -- How JMVC enables code separation -- Srchr's architecture + - [Part 1 - MVC architecture and the observer pattern](http://www.youtube.com/watch?v=NZi5Ru4KVug) + - [Part 2 - Development process](http://www.youtube.com/watch?v=yFxDY5SQQp4) -This article will talk about the -architecture of the Srchr application, and how [can.compute] -can help you build loosely coupled, scalable applications. You will -also learn how to assemble small pieces of functionality into the full blown application. ## Installing Srchr @@ -46,338 +42,5 @@ Once you get the application you should have a structure similar to below srchr.html ... -Srchr is now ready to be used. To run the Srchr application simply open _srchr/srchr.html_ in your browser. We will be using [jQuery.fixture fixtures] to simulate AJAX requests so running it in a server isn't necessary ([googlefilesystem unless you're using Chrome]) - -## How Srchr was built - -Srchr was built the 'JavaScriptMVC' way. It has a folder/file structure where: - -* Code is logically separated and tested. -* Code is easily assembled into higher-order functionality. -* Higher order functionality is tested. - -## How to organize and separate code - -Every JavaScript application implements widgets to -show and manipulate data. In JavaScriptMVC every one of -these widgets is built as an isolated part that can be reused and -tested. These widgets communicate to each other via a shared [can.compute], which -results in a loosely coupled application. - -Srchr is broken into logically separated components: - -* History - A cookie saved list of items. -* Search - Creates a search message when a search happens. -* Search Result - Seaches for results and displays them. -* Tabs - A basic tabs widget. - -This is the widget organization in Srchr: - -@image tutorials/images/app_organization.png - - -### User Workflow - -A user using Srchr might perform the following: - -1. Select (via checkboxes) services that should be searched -2. Enter a search term and clicks the search button -3. Click result tabs to see their results. -4. Search params are saved to the history (via cookie) - -### Search behavior - -When the user performs a search, these are the actions that get triggered: - -1. Disabler widget listens to the search event and disables or enables tabs based on the checkboxes' states -2. Search results widget shows results for the first enabled tab -3. History widget saves the search params to the cookie - -This is the event architecture of the search: - -@image tutorials/images/diagram_search.png - - -### Tab behavior - -When the user clicks another tab it will trigger the activate event on that tab, which results in the following actions: - -1. Disabler widget listens to the activate event and checks if the tab is disabled. If it is, it will call preventDefault on the activate -2. Tabs widget listens to the activate event, and if it wasn't prevented, it will trigger the show event on the corresponding tab panel -3. Search results listens to the show event on the tab panel, and when triggered performs a search and shows results to the user - -This is the event architecture of the tabs: - -@image tutorials/images/diagram_tabs.png - - -Let's take a detailed look at the tab behavior: - -#### 1. Disabler widget - -Disabler widget has two event handlers. The first one listens to the activate event on list items: - - "{activateSelector} activate": function( el, ev ) { - if ( el.hasClass('disabled') ) { - ev.preventDefault(); - } - } - -It looks if the element has the disabled class and if it does it will preventDefault on the activate event. - -Other event handler listens to the search event. This event gets triggered by the search widget - - "{Srchr.Models.Search} search": function( el, ev, data ) { - var types = {}, - first = true; - - // Fill the list of types to check against. - $.each(data.types, function( index, type ) { - - // Model types come in as Srchr.Model.typeName, so just get the last part - types[type.split('.').pop()] = true; - }); - - this.element.find(this.options.activateSelector).each(function(){ - var el = $(this); - - // If the Model type we are iterating through is in the list, enable it. - // Otherwise, disable it. - if ( types[el.text()] ) { - el.removeClass("disabled"); - if ( first ) { - el.trigger('activate'); - first = false; - } - } else { - el.addClass("disabled"); - } - }); - } - - -The event handler checks which services are selected and adds or removes the "disabled" class from tab elements. It will also activate the first active tab. - -#### 2. Tabs widget - -Tabs widget has a simple task: listen to the "click" event on the tab, and trigger the "activate" event: - - "li click": function( el, ev ) { - ev.preventDefault(); - el.trigger("activate"); - } - -It will also handle the "activate" event if it is not prevented by the disabler widget: - - activate: function( el ) { - this.tab(this.find('.active').removeClass('active')).hide(); - this.tab(el.addClass('active')).show().trigger("show"); - } - -#### 3. Search results widget - -Search results widget listens to the show event to load search results and show them in the tab panel: - - /** - * Show the search results. - */ - "show": function(){ - this.getResults(); - }, - - /** - * Get the appropriate search results that this Search Results container is supposed to show. - */ - getResults: function(){ - // If we have a search... - if (this.currentSearch){ - - // and our search is new ... - if(this.searched != this.currentSearch){ - // put placeholder text in the panel... - this.element.html("Searching for "+this.currentSearch+""); - // and set a callback to render the results. - this.options.modelType.findAll({query: this.currentSearch}, this.callback('renderResults')); - this.searched = this.currentSearch; - } - - }else{ - // Tell the user to make a valid query - this.element.html("Enter a search term!"); - } - - } - - -## Assembling an application - -After the widgets are developed and tested in isolation, they need to be assembled into an application. Here is a quick overview of the techniques used to assemble the widgets in to the Srchr app. - -Srchr is a small application, so most of the assembling is done in the srchr.js file. When you generate a JavaScriptMVC application: - - ./js jquery/generate/app srchr - -it will create the directory and file structure that look like this: - -@image tutorials/images/app_scaffold.png - - -srchr/srchr.js file is your main JavaScript file that should load all higher order widgets and bootstrap the application. If you open the srchr.js file you will see something similar to this: - - // Load all of the plugin dependencies - steal('bunch/of/dependencies).then('srchr/srchr.less', function($){ - .... - }); - -Steal will first load all of the dependencies, and then run the function which is usually defined as a last argument. This function is where the application bootstrapping logic lives. It's responsibilities usually are: - -* render application skeleton on the page -* find elements and initialize higher order widgets - -Srchr is a small application so all bootstrapping is done in the srchr.js file. When you have a bigger application that handles multiple resources you should create resource based higher order widgets that take care of bootstrapping and assembling that part of application. You can read more about this [here](http://edge.javascriptmvc.com/jmvc/docs.html#!organizing). - -## Testing your application - -JavaScriptMVC comes with two testing frameworks built in. QUnit is used to unit test your models and FuncUnit functionally tests your whole application. - -If you open srchr/qunit.html in your browser, it will run unit tests. For functional testing open srchr/funcunit.html. Read more about [FuncUnit](http://javascriptmvc.com/docs.html#&who=FuncUnit) and [QUnit](http://docs.jquery.com/Qunit). - -In this article we already covered the separation of code, but another aspect of code separation is test isolation. In every module folder you will have a test file that should test only that widget. The usual module folder structure looks like this: - - funcunit.html - funcunit/ - tabs_test.js - funcunit.js - tabs.js - tabs.html - -Every module has a demo page that helps you develop and test that module in isolation. In the case of the tabs widget this file is called tabs.html. If you open that file you will see this code: - -

Srchr.Tabs

-

A very basic tabs widget that creates 'activate' events.

-

Demo

-

Click the different tabs.

- - -
one
-
two
-
three
- - - - - - -As you can see this page bootstraps the tabs widget. This is the minimum needed for the tabs widget to run. You should always use the demo page to develop your widgets because you can also use that page to test that widget. In the case of the tabs widget that code is in tabs/funcunit/tabs_test.js: - - module("srchr/tabs",{ - setup : function(){ - S.open('//srchr/tabs/tabs.html') - } - }); - - - test("Proper hiding and showing", function() { - S("li:eq(1)").click(); - S("div:eq(1)").visible(function() { - equals(S("div:eq(0)").css('display'), 'none', "Old tab contents are hidden"); - ok(!S("li:eq(0)").hasClass('active'), 'Old tab is not set to active'); - equals(S("div:eq(1)").css('display'), 'block', "New tab contents are visible"); - ok(S("li:eq(1)").hasClass('active'), 'New tab is set to active'); - }); - }); - - test("Clicking twice doesn't break anything", function() { - S("li:eq(2)").click(); - S("li:eq(2)").click(); - - S("div:eq(2)").visible(function() { - equals(S("div:eq(2)").css('display'), 'block', "New tab contents are visible"); - ok(S("li:eq(2)").hasClass('active'), 'New tab is set to active'); - }); - }); - -What this code does is: - -- Opens the tabs' widget demo page (tabs.html). That sets up the tabs widget -- Simulates the user interaction necessary to test the widget. - -The first test ("Proper hiding and showing") does the following: - -- Find the second list element and click on it -- Wait until the second div is visible -- Check if the first div is hidden -- Ensure that first list item doesn't have an "active" class -- Check if the second div is shown -- Ensure that second list item has an "active" class - -FuncUnit allows you to write high fidelity tests, that resemble user's interaction as close as possible. - -This is the pattern you should use when you develop your applications. Every widget should have it's own set of tests. You should also have application level tests that test how the widgets work together. You can find this file in test/funcunit/srchr_test.js. This file tests all of the higher level srchr's functionality. - -Test example from the application level test file: - - test('Search shows results in selected service', function(){ - - S('input[value=Srchr\\.Models\\.Twitter]').click(); - S('#query').click().type('Dogs\r'); - - // wait until there are 2 results - S("#twitter li").exists( function(){ - - ok(true, "We see results in twitter"); - // make sure we see dogs in the history - - var r = /Dogs\st/; - - ok(r.test(S("#history .search .text").text()), "we see dogs correctly"); - - // make sure flickr and everyone else is diabled - ok(S('#resultsTab li:eq(1)').hasClass('disabled'), "Flickr is disabled."); - ok(S('#resultsTab li:eq(2)').hasClass('disabled'), "Upcoming is disabled."); - }); - - }) - -This code tests multiple widgets at once: - -- (Search widget) It finds the input (checkbox) with the value "Srchr.Models.Twitter" and clicks it -- (Search widget) It enters "Dogs" into the search input and submits the search -- (Search result widget) Waits until results are visible -- (History widget) Checks if "Dogs" is added to the history -- (Tabs widget) Checks if Flickr and Upcoming tabs are disabled - -You can find all of the srchr tests here: - -- Disabler widget: [test code](https://github.com/jupiterjs/srchr/blob/master/srchr/disabler/funcunit/disabler_test.js), [test page](http://javascriptmvc.com/srchr/disabler/funcunit.html) -- History widget: [test code](https://github.com/jupiterjs/srchr/blob/master/srchr/history/funcunit/history_test.js), [test page](http://javascriptmvc.com/srchr/history/funcunit.html) -- Search widget: [test code](https://github.com/jupiterjs/srchr/blob/master/srchr/search/funcunit/search_test.js), [test page](http://javascriptmvc.com/srchr/search/funcunit.html) -- Search result widget: [test code](https://github.com/jupiterjs/srchr/blob/master/srchr/search_result/funcunit/search_result_test.js), [test page](http://javascriptmvc.com/srchr/search_result/funcunit.html) -- Search tabs widget: [test code](https://github.com/jupiterjs/srchr/blob/master/srchr/search_tabs/funcunit/search_tabs_test.js), [test page](http://javascriptmvc.com/srchr/search_tabs/funcunit.html) -- Tabs widget: [test code](https://github.com/jupiterjs/srchr/blob/master/srchr/tabs/funcunit/tabs_test.js), [test page](http://javascriptmvc.com/srchr/tabs/funcunit.html) -- Application tests: [test code](https://github.com/jupiterjs/srchr/blob/master/srchr/test/funcunit/srchr_test.js), [test page](http://javascriptmvc.com/srchr/funcunit.html) - - - -## Building a production version - -To build scalable and maintainable JavaScript applications, you should keep your code separated and isolated, but when you want to deploy you want as few files as possible, and you want your scripts minified. JMVC uses Steal to build a minified production version of your code. You can build your app by running the build.js script available in every JMVC project. You can build Srchr by running: - - $ ./js srchr/scripts/build.js - -This will compile and minify all of your JS code into the production.js and all of your CSS code in the production.css file. - -## Conclusion - -Successful completion of frontend applications depends on many things, but one of the most important is architecture. In this article we've seen how to use event oriented architecture to build loosely coupled and isolated modules that are assembled into an application. - -For instance, we could take out the disabler widget and rest of the app would continue working without problems. That is the power we need to build applications that are testable and maintainable. You can read more about application organization in [this article](http://edge.javascriptmvc.com/docs.html#!organizing). +Srchr is now ready to be used. To run the Srchr application simply open _srchr/index.html_ in your browser. diff --git a/tutorials/installing.md b/tutorials/installing.md index ab7e1a3a9..0a68d9c50 100644 --- a/tutorials/installing.md +++ b/tutorials/installing.md @@ -56,13 +56,13 @@ Forking the repos looks like: git submodule add git@github.com:_YOU_/steal.git public/steal git submodule add git@github.com:_YOU_/canjs.git public/can git submodule add git@github.com:_YOU_/canui.git public/canui -git submodule add git@github.com:_YOU_/jquerypp.git public/jquery +git submodule add git@github.com:_YOU_/jquerypp.git public/jquerypp git submodule add git@github.com:_YOU_/documentjs.git public/documentjs git submodule add git@github.com:_YOU_/funcunit.git public/funcunit @codeend Notice that CanJS is in can folder and -jQuery++ is in the jquery folder. +jQuery++ is in the jquerypp folder. After installing the repository, run: diff --git a/tutorials/rapidstart/rapidstart.md b/tutorials/rapidstart/rapidstart.md index 5de5cbc1b..d135561ef 100644 --- a/tutorials/rapidstart/rapidstart.md +++ b/tutorials/rapidstart/rapidstart.md @@ -14,7 +14,7 @@ Once you have JavaScriptMVC, you should have a folder with: can - lightweight MVC components documentjs - documentation engine funcunit - testing app - jquery - useful collections of jQuery plugins + jquerypp - useful collections of jQuery plugins steal - dependency management js - JS command line for Linux/Mac js.bat - JS command line for Windows @@ -26,7 +26,7 @@ Once you have JavaScriptMVC, you should have a folder with: ## Get JavaScriptMVC running. JMVC uses [steal steal/steal.js] for dependency -management. Steal loads scripts. To use JavaScriptMVC's +management. Steal loads scripts, CSS and more. To use JavaScriptMVC's features like [can.Control] and [can.view], 'steal' them like: From aa566a43bd738b4098987b2edd624ecc51529c3d Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Wed, 17 Apr 2013 15:58:42 -0500 Subject: [PATCH 17/54] removing jmvc folder and replacing it with submodule --- jmvc/generate/app | 22 ---- jmvc/generate/coffee/controller | 35 ------ .../controller/(underscore).coffee.ejs | 11 -- .../controller/(underscore).html.ejs | 24 ---- .../controller/(underscore)_test.coffee.ejs | 7 -- .../templates/controller/funcunit.html.ejs | 16 --- jmvc/generate/control | 22 ---- jmvc/generate/model | 46 -------- jmvc/generate/page | 21 ---- jmvc/generate/plugin | 17 --- jmvc/generate/scaffold | 109 ------------------ .../templates/app/(application_name).js.ejs | 6 - .../templates/app/(application_name).less.ejs | 30 ----- .../templates/app/(application_name).md.ejs | 21 ---- .../app/(application_name)_test.js.ejs | 16 --- jmvc/generate/templates/app/index.html.ejs | 28 ----- jmvc/generate/templates/app/models/.ignore | 0 .../app/models/fixtures/fixtures.js.ejs | 3 - .../templates/app/scripts/build.html.ejs | 21 ---- .../templates/app/scripts/build.js.ejs | 6 - .../templates/app/scripts/clean.js.ejs | 17 --- .../templates/app/scripts/crawl.js.ejs | 7 -- .../templates/app/scripts/docs.js.ejs | 8 -- jmvc/generate/templates/app/test.html.ejs | 6 - .../templates/control/(underscore).html.ejs | 16 --- .../templates/control/(underscore).js.ejs | 19 --- .../control/(underscore)_test.js.ejs | 18 --- jmvc/generate/templates/control/init.ejs.ejs | 1 - jmvc/generate/templates/control/test.html.ejs | 6 - jmvc/generate/templates/fixturemake.ejs | 17 --- jmvc/generate/templates/model.js | 76 ------------ .../model/models/(underscore).js.ejs | 21 ---- .../model/models/(underscore)_test.js.ejs | 53 --------- jmvc/generate/templates/page.ejs | 22 ---- .../templates/plugin/(underscore).html.ejs | 16 --- .../templates/plugin/(underscore).js.ejs | 3 - .../templates/plugin/(underscore)_test.js.ejs | 10 -- jmvc/generate/templates/plugin/test.html.ejs | 6 - .../templates/scaffold/create/create.html.ejs | 32 ----- .../templates/scaffold/create/create.js.ejs | 26 ----- .../scaffold/create/create_test.js.ejs | 44 ------- .../templates/scaffold/create/init.ejs.ejs | 9 -- .../templates/scaffold/create/test.html.ejs | 7 -- .../templates/scaffold/list/init.ejs.ejs | 6 - .../templates/scaffold/list/list.html.ejs | 34 ------ .../templates/scaffold/list/list.js.ejs | 33 ------ .../templates/scaffold/list/list_test.js.ejs | 63 ---------- .../templates/scaffold/list/test.html.ejs | 7 -- jmvc/generate/templates/scaffoldHTML.ejs | 4 - jmvc/generate/templates/scaffoldHookup.ejs | 2 - jmvc/generate/templates/scaffoldTest.ejs | 11 -- .../test/app_plugin_model_controller.js | 60 ---------- jmvc/generate/test/run.js | 3 - jmvc/generate/test/scaffold.js | 87 -------------- readme.md | 2 +- scripts/getjmvc | 8 +- 56 files changed, 6 insertions(+), 1215 deletions(-) delete mode 100644 jmvc/generate/app delete mode 100644 jmvc/generate/coffee/controller delete mode 100644 jmvc/generate/coffee/templates/controller/(underscore).coffee.ejs delete mode 100644 jmvc/generate/coffee/templates/controller/(underscore).html.ejs delete mode 100644 jmvc/generate/coffee/templates/controller/(underscore)_test.coffee.ejs delete mode 100644 jmvc/generate/coffee/templates/controller/funcunit.html.ejs delete mode 100644 jmvc/generate/control delete mode 100644 jmvc/generate/model delete mode 100644 jmvc/generate/page delete mode 100644 jmvc/generate/plugin delete mode 100644 jmvc/generate/scaffold delete mode 100644 jmvc/generate/templates/app/(application_name).js.ejs delete mode 100644 jmvc/generate/templates/app/(application_name).less.ejs delete mode 100644 jmvc/generate/templates/app/(application_name).md.ejs delete mode 100644 jmvc/generate/templates/app/(application_name)_test.js.ejs delete mode 100644 jmvc/generate/templates/app/index.html.ejs delete mode 100644 jmvc/generate/templates/app/models/.ignore delete mode 100644 jmvc/generate/templates/app/models/fixtures/fixtures.js.ejs delete mode 100644 jmvc/generate/templates/app/scripts/build.html.ejs delete mode 100644 jmvc/generate/templates/app/scripts/build.js.ejs delete mode 100644 jmvc/generate/templates/app/scripts/clean.js.ejs delete mode 100644 jmvc/generate/templates/app/scripts/crawl.js.ejs delete mode 100644 jmvc/generate/templates/app/scripts/docs.js.ejs delete mode 100644 jmvc/generate/templates/app/test.html.ejs delete mode 100644 jmvc/generate/templates/control/(underscore).html.ejs delete mode 100644 jmvc/generate/templates/control/(underscore).js.ejs delete mode 100644 jmvc/generate/templates/control/(underscore)_test.js.ejs delete mode 100644 jmvc/generate/templates/control/init.ejs.ejs delete mode 100644 jmvc/generate/templates/control/test.html.ejs delete mode 100644 jmvc/generate/templates/fixturemake.ejs delete mode 100644 jmvc/generate/templates/model.js delete mode 100644 jmvc/generate/templates/model/models/(underscore).js.ejs delete mode 100644 jmvc/generate/templates/model/models/(underscore)_test.js.ejs delete mode 100644 jmvc/generate/templates/page.ejs delete mode 100644 jmvc/generate/templates/plugin/(underscore).html.ejs delete mode 100644 jmvc/generate/templates/plugin/(underscore).js.ejs delete mode 100644 jmvc/generate/templates/plugin/(underscore)_test.js.ejs delete mode 100644 jmvc/generate/templates/plugin/test.html.ejs delete mode 100644 jmvc/generate/templates/scaffold/create/create.html.ejs delete mode 100644 jmvc/generate/templates/scaffold/create/create.js.ejs delete mode 100644 jmvc/generate/templates/scaffold/create/create_test.js.ejs delete mode 100644 jmvc/generate/templates/scaffold/create/init.ejs.ejs delete mode 100644 jmvc/generate/templates/scaffold/create/test.html.ejs delete mode 100644 jmvc/generate/templates/scaffold/list/init.ejs.ejs delete mode 100644 jmvc/generate/templates/scaffold/list/list.html.ejs delete mode 100644 jmvc/generate/templates/scaffold/list/list.js.ejs delete mode 100644 jmvc/generate/templates/scaffold/list/list_test.js.ejs delete mode 100644 jmvc/generate/templates/scaffold/list/test.html.ejs delete mode 100644 jmvc/generate/templates/scaffoldHTML.ejs delete mode 100644 jmvc/generate/templates/scaffoldHookup.ejs delete mode 100644 jmvc/generate/templates/scaffoldTest.ejs delete mode 100644 jmvc/generate/test/app_plugin_model_controller.js delete mode 100644 jmvc/generate/test/run.js delete mode 100644 jmvc/generate/test/scaffold.js diff --git a/jmvc/generate/app b/jmvc/generate/app deleted file mode 100644 index 0f6238f24..000000000 --- a/jmvc/generate/app +++ /dev/null @@ -1,22 +0,0 @@ -// _args = ['cookbook']; load('steal/generate/app') - -if (!_args[0]) { - print("Usage: steal/js steal/generate/app path"); - quit(); -} - -load('steal/rhino/rhino.js'); - -steal('steal/generate','steal/generate/system.js', function(steal) { - var moduleId = _args[0]; - var md = steal.generate.convert(moduleId), - data = steal.extend({ - path: moduleId, - application_name: md._alias, - current_path: steal.File.cwdURL(), - path_to_steal : steal.File(moduleId).pathToRoot() - }, steal.system); - - steal.generate("jmvc/generate/templates/app", moduleId, data); -}); - diff --git a/jmvc/generate/coffee/controller b/jmvc/generate/coffee/controller deleted file mode 100644 index a547f8a21..000000000 --- a/jmvc/generate/coffee/controller +++ /dev/null @@ -1,35 +0,0 @@ -if (_args.length < 1) { - print("USAGE : steal/js steal/generate/coffee/controller Company.Widget") - print("EX : steal/js steal/generate/coffee/controller Company.WidgetName"); - print(" > company/widget_name/widget_name.coffee") - print(); - quit(); -} - -load('steal/rhino/rhino.js'); - -steal( '//steal/generate/generate', - '//steal/generate/system', -function(steal){ - var upper = function(parts){ - for(var i =0; i < parts.length; i++){ - parts[i] = parts[i].charAt(0).toUpperCase()+parts[i].substr(1) - } - return parts - } - - if(_args[0].charAt(0) !== _args[0].charAt(0).toUpperCase()){ - var caps = upper( _args[0].split(/_|-/) ).join(''), - name = upper(caps.split("/")).join('.'); - - print(" Creating "+name); - _args[0] = name; - } - - var md = steal.generate.convert(_args[0]), - path = _args[0].toLowerCase().replace('.',"/"); - md.path_to_steal = new steal.File(path).pathToRoot() - steal.generate("jquery/generate/coffee/templates/controller",md.path+"/"+md.underscore,md) - -}); - diff --git a/jmvc/generate/coffee/templates/controller/(underscore).coffee.ejs b/jmvc/generate/coffee/templates/controller/(underscore).coffee.ejs deleted file mode 100644 index 61c267b76..000000000 --- a/jmvc/generate/coffee/templates/controller/(underscore).coffee.ejs +++ /dev/null @@ -1,11 +0,0 @@ -steal "jquery/controller", -($) -> - - $.Controller "<%= name %>", - { - defaults : {}, - }, - { - init : -> - @element.html "Hello World!" - } diff --git a/jmvc/generate/coffee/templates/controller/(underscore).html.ejs b/jmvc/generate/coffee/templates/controller/(underscore).html.ejs deleted file mode 100644 index 7ad7f07cc..000000000 --- a/jmvc/generate/coffee/templates/controller/(underscore).html.ejs +++ /dev/null @@ -1,24 +0,0 @@ - - - - <%= name %> - - - -

<%= name %> Demo

-
- - - - \ No newline at end of file diff --git a/jmvc/generate/coffee/templates/controller/(underscore)_test.coffee.ejs b/jmvc/generate/coffee/templates/controller/(underscore)_test.coffee.ejs deleted file mode 100644 index 7bf21374d..000000000 --- a/jmvc/generate/coffee/templates/controller/(underscore)_test.coffee.ejs +++ /dev/null @@ -1,7 +0,0 @@ -steal "funcunit", - -> - module "<%= fullName %>", setup: -> - S.open "//<%= path %>/<%=underscore%>/<%=underscore%>.html" - - test "Text Test", -> - equals S("h1").text(), "<%= fullName %> Demo", "demo text" \ No newline at end of file diff --git a/jmvc/generate/coffee/templates/controller/funcunit.html.ejs b/jmvc/generate/coffee/templates/controller/funcunit.html.ejs deleted file mode 100644 index 282c9c9a0..000000000 --- a/jmvc/generate/coffee/templates/controller/funcunit.html.ejs +++ /dev/null @@ -1,16 +0,0 @@ - - - - - <%= name %> FuncUnit Test - - - - -

<%= name %> Test Suite

-

-
-

-
    - - \ No newline at end of file diff --git a/jmvc/generate/control b/jmvc/generate/control deleted file mode 100644 index 8dca56e2e..000000000 --- a/jmvc/generate/control +++ /dev/null @@ -1,22 +0,0 @@ -if (_args.length < 1) { - print("USAGE : steal/js steal/generate/controller Company.Widget") - print("EX : steal/js steal/generate/controller Company.WidgetName"); - print(" > company/widget_name/widget_name.js") - print(); - quit(); -} - -load('steal/rhino/rhino.js'); - -steal( 'steal/generate', - 'steal/generate/system.js', -function(steal){ - - - var md = steal.generate.convert(_args[0]); - - md.path_to_steal = new steal.File(md.module).pathToRoot() - steal.generate("jmvc/generate/templates/control",md.module,md) - -}); - diff --git a/jmvc/generate/model b/jmvc/generate/model deleted file mode 100644 index f21097f7d..000000000 --- a/jmvc/generate/model +++ /dev/null @@ -1,46 +0,0 @@ -if (_args.length < 1) { - print("USAGE : js jmvc/generate/model cookbook/models/recipe") - print(); - quit(); -} - -load('steal/rhino/rhino.js'); - -steal( 'steal/generate', - 'steal/generate/system.js', - 'steal/generate/inflector.js', -function(steal){ - var md = steal.generate.convert(_args[0]); - - var folder = md.path.replace(/\/\w+$/, ""); - if(!folder){ - print("! Error: Models need to be part of an app"); - quit(); - } - if(!steal.File(folder).exists()){ - print("! Error: folder "+folder+" does not exist!"); - quit(); - } - - md.path_to_steal = new steal.File(md.path).pathToRoot(); - md.appPath = md.path.replace(/\/models$/,""); - - //check pluralization of last part - if(steal.Inflector.singularize(md.underscore) !== md.underscore){ - print("! Warning: Model names should be singular. I don't think "+md.underscore+" is singular!") - } - - - // generate the files - steal.generate("jmvc/generate/templates/model", md.appPath, md); - - // add to models/fixtures/fixtures.js - steal.generate.insertSteal(md.appPath + '/models/fixtures/fixtures.js', - md.appPath + '/models/fixtures/' + md.fullName + '.js'); - - // var text = readFile("jmvc/generate/templates/partials/fixture.js.ejs"); - // var fixturetext = new steal.EJS({ - // text: text - // }).render(md); - // steal.generate.insertCode(md.appPath+"/models/fixtures/fixtures.js", fixturetext); -}); \ No newline at end of file diff --git a/jmvc/generate/page b/jmvc/generate/page deleted file mode 100644 index 8d5f3f811..000000000 --- a/jmvc/generate/page +++ /dev/null @@ -1,21 +0,0 @@ -if (_args.length < 2) { - print("Creates an html page that loads one of your applications.\n") - print("USAGE: js steal/generate/test app_name page_location\n") - print(); - quit(); -} - -load('steal/rhino/rhino.js'); - -steal('steal/generate','steal/generate/system.js',function(steal){ - var path = _args[0].toLowerCase().replace('.',"/") - var data = steal.extend({ - path: path, - application_name: path.match(/[^\/]*$/)[0], - current_path: steal.File.cwdURL(), - path_to_steal : new steal.File(path).pathToRoot() - }, steal.system) - - var to = path+"/"+_args[1]; - steal.generate.render("jmvc/generate/templates/page.ejs", to, data) -}); \ No newline at end of file diff --git a/jmvc/generate/plugin b/jmvc/generate/plugin deleted file mode 100644 index c860ba83c..000000000 --- a/jmvc/generate/plugin +++ /dev/null @@ -1,17 +0,0 @@ -// _args = ['thing']; load('steal/generate/app') - -if (!_args[0]) { - print("Usage: steal/js steal/generate/plugin path"); - quit(); -} -load('steal/rhino/rhino.js'); - -steal('steal/generate',function(steal){ - - var md = steal.generate.convert(_args[0]); - - md.path_to_steal = new steal.File(md.module).pathToRoot(); - steal.generate("jmvc/generate/templates/plugin",md.module,md); - -})(); - diff --git a/jmvc/generate/scaffold b/jmvc/generate/scaffold deleted file mode 100644 index d865c1cc6..000000000 --- a/jmvc/generate/scaffold +++ /dev/null @@ -1,109 +0,0 @@ -if (_args.length < 1) { - print("USAGE : steal/js steal/generate/scaffold FullName Type") - print("TYPES : JsonRest\n") - print("EX : js steal/generate/scaffold Cashnet.Models.Customer"); - print(" > cashnet/models/customer.js ....") - print(); - quit(); -} - -load('steal/rhino/rhino.js'); - -steal( 'steal/generate', - 'steal/generate/system.js', - 'jmvc/generate/templates/model.js', -function(steal){ - var generate = steal.generate; - //check capitalization - generate.model(_args[0]); - - var parts = _args[0].split("/"), - last = parts[parts.length-1]; - - parts.forEach(function(part){ - if( part !== generate.downcase(part) ){ - print("! Warning: "+part+" should probably be lowercased. JavaScriptMVC likes capital namespaces and class names.") - } - }); - - // check folders - var folder = parts.slice(0, parts.length-1).join("/"); - - - if(!folder){ - print("! Error: Scaffolding needs to be part of an app"); - quit(); - } - if(!steal.File(folder).exists()){ - print("! Error: folder "+folder+" does not exist!"); - quit(); - } - //check pluralization of last part - if(steal.Inflector.singularize(last) !== last){ - print("! Warning: Model names should be singular. I don't think "+part+ - " is singular!") - } - - var md = steal.generate.convert(_args[0]); - - md.type = _args[1] - - // generate /scaffold files - steal.generate("jmvc/generate/templates/scaffold",md.appPath+"/"+md.underscore,md); - - try{ - - steal.generate.insertSteal( - md.appPath+"/"+ md.appName+"_test.js", - md.appPath+"/"+md.underscore+"/create/create_test.js"); - - steal.generate.insertSteal( - md.appPath+"/"+ md.appName+"_test.js", - md.appPath+"/"+md.underscore+"/list/list_test.js") - - steal.generate.insertSteal( - md.appPath+"/"+md.appPath+".js", - md.appPath+"/"+md.underscore+"/create", {newline: true, name: md.Alias+"Create"}) - steal.generate.insertSteal( - md.appPath+"/"+md.appPath+".js", - md.appPath+"/"+md.underscore+"/list", {newline: true, name: md.Alias+"List"}) - } catch(e) { - //quit(); - } - - var text = readFile("jmvc/generate/templates/scaffoldHookup.ejs"); - var hookup = new steal.EJS({ - text: text - }).render(md); - steal.generate.insertCode(md.appPath+"/"+md.appName+".js", hookup ); - - // insert the HTML into index - var text = readFile("jmvc/generate/templates/scaffoldHTML.ejs"); - var hookupHTML = new steal.EJS({ - text: text - }).render(md); - - var appFile = readFile( md.appPath+"/index.html" ); - - if( appFile.indexOf(text) == -1 ){ - var scriptIndex = appFile.indexOf(".less', - './models/fixtures/fixtures.js', -function(){ - -}) \ No newline at end of file diff --git a/jmvc/generate/templates/app/(application_name).less.ejs b/jmvc/generate/templates/app/(application_name).less.ejs deleted file mode 100644 index e742a3976..000000000 --- a/jmvc/generate/templates/app/(application_name).less.ejs +++ /dev/null @@ -1,30 +0,0 @@ -body { - font-family:Lucida Sans,Lucida Grande,Arial,sans-serif; - margin:0; - line-height:22px; - width:960px; - margin:0 auto; -} -h1 { - padding:30px 0 10px; - margin-top:0; - line-height:30px; -} - -ul{ - padding:0 0 0 15px; - list-style : none; -} - -a { - color:#ae3d26; - text-decoration:none; - &:hover { - text-decoration:underline; - } -} - -hr { - border:none; - border-top:1px dotted #000; -} \ No newline at end of file diff --git a/jmvc/generate/templates/app/(application_name).md.ejs b/jmvc/generate/templates/app/(application_name).md.ejs deleted file mode 100644 index a2a8b77ef..000000000 --- a/jmvc/generate/templates/app/(application_name).md.ejs +++ /dev/null @@ -1,21 +0,0 @@ -@page index <%= application_name %> - -# <%= application_name %> - -This is a placeholder for the homepage of your documentation. - -## Testing - -Open [//<%= application_name %>/test.html] - -## Building - -Run: - - > ./js <%= application_name %>/scripts/build.js - -## Documentation - -Run: - - > ./js <%= application_name %>/scripts/docs.js \ No newline at end of file diff --git a/jmvc/generate/templates/app/(application_name)_test.js.ejs b/jmvc/generate/templates/app/(application_name)_test.js.ejs deleted file mode 100644 index 746451635..000000000 --- a/jmvc/generate/templates/app/(application_name)_test.js.ejs +++ /dev/null @@ -1,16 +0,0 @@ -steal( - 'funcunit', - function (S) { - - // this tests the assembly - module("<%= application_name %>", { - setup : function () { - S.open("//<%= path %>/index.html"); - } - }); - - test("welcome test", function () { - equals(S("h1").text(), "Welcome to JavaScriptMVC!", "welcome text"); - }); - -}); diff --git a/jmvc/generate/templates/app/index.html.ejs b/jmvc/generate/templates/app/index.html.ejs deleted file mode 100644 index 6245a99ed..000000000 --- a/jmvc/generate/templates/app/index.html.ejs +++ /dev/null @@ -1,28 +0,0 @@ - - - - <%= application_name %> - - -

    Welcome to JavaScriptMVC!

    -
      -
    • Steal plugins and files in <%= path %>/<%= application_name %>.js.
    • -
    • Change to production mode by changing steal.js to steal.production.js in this file.
    • -
    -
    - Here are some links to get you started: - -
    - Join the community: - - - - \ No newline at end of file diff --git a/jmvc/generate/templates/app/models/.ignore b/jmvc/generate/templates/app/models/.ignore deleted file mode 100644 index e69de29bb..000000000 diff --git a/jmvc/generate/templates/app/models/fixtures/fixtures.js.ejs b/jmvc/generate/templates/app/models/fixtures/fixtures.js.ejs deleted file mode 100644 index 4e9c6d1e1..000000000 --- a/jmvc/generate/templates/app/models/fixtures/fixtures.js.ejs +++ /dev/null @@ -1,3 +0,0 @@ -// map fixtures for this application -steal("can/util/fixture", function(fixture) { -}); \ No newline at end of file diff --git a/jmvc/generate/templates/app/scripts/build.html.ejs b/jmvc/generate/templates/app/scripts/build.html.ejs deleted file mode 100644 index 35b326e75..000000000 --- a/jmvc/generate/templates/app/scripts/build.html.ejs +++ /dev/null @@ -1,21 +0,0 @@ - - - - <%= application_name %> Build Page - - -

    <%= application_name %> Build Page

    -

    This is a dummy page that loads your app so steal can - get all the files. -

    -

    If you built your app - to depend on HTML in the page before DOMContent loaded or - onload, you can add the HTML here, or you can change the - build.js script to point to a better html file. -

    - - - \ No newline at end of file diff --git a/jmvc/generate/templates/app/scripts/build.js.ejs b/jmvc/generate/templates/app/scripts/build.js.ejs deleted file mode 100644 index d76ebac21..000000000 --- a/jmvc/generate/templates/app/scripts/build.js.ejs +++ /dev/null @@ -1,6 +0,0 @@ -//js <%= path %>/scripts/build.js - -load("steal/rhino/rhino.js"); -steal('steal/build',function(){ - steal.build('<%= path %>/scripts/build.html',{to: '<%= path %>'}); -}); diff --git a/jmvc/generate/templates/app/scripts/clean.js.ejs b/jmvc/generate/templates/app/scripts/clean.js.ejs deleted file mode 100644 index 909c5fc37..000000000 --- a/jmvc/generate/templates/app/scripts/clean.js.ejs +++ /dev/null @@ -1,17 +0,0 @@ -//steal/js <%= path %>/scripts/compress.js - -load("steal/rhino/rhino.js"); -steal('steal/clean',function(){ - steal.clean('<%= path %>/<%= application_name %>.html',{ - indent_size: 1, - indent_char: '\t', - jslint : false, - ignore: /jquery\/jquery.js/, - predefined: { - steal: true, - jQuery: true, - $ : true, - window : true - } - }); -}); diff --git a/jmvc/generate/templates/app/scripts/crawl.js.ejs b/jmvc/generate/templates/app/scripts/crawl.js.ejs deleted file mode 100644 index 7290b5ebe..000000000 --- a/jmvc/generate/templates/app/scripts/crawl.js.ejs +++ /dev/null @@ -1,7 +0,0 @@ -// load('<%= path %>/scripts/crawl.js') - -load('steal/rhino/rhino.js') - -steal('steal/html/crawl', function(){ - steal.html.crawl("<%= path %>/<%= application_name %>.html","<%= path %>/out") -}); diff --git a/jmvc/generate/templates/app/scripts/docs.js.ejs b/jmvc/generate/templates/app/scripts/docs.js.ejs deleted file mode 100644 index 5809d9ad0..000000000 --- a/jmvc/generate/templates/app/scripts/docs.js.ejs +++ /dev/null @@ -1,8 +0,0 @@ -//js <%= path %>/scripts/doc.js - -load('steal/rhino/rhino.js'); -steal("documentjs", function(DocumentJS){ - DocumentJS('<%= path %>/index.html', { - markdown : ['<%= application_name %>', 'steal', 'jquery', 'can', 'funcunit'] - }); -}); \ No newline at end of file diff --git a/jmvc/generate/templates/app/test.html.ejs b/jmvc/generate/templates/app/test.html.ejs deleted file mode 100644 index 54f4bcf72..000000000 --- a/jmvc/generate/templates/app/test.html.ejs +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/jmvc/generate/templates/control/(underscore).html.ejs b/jmvc/generate/templates/control/(underscore).html.ejs deleted file mode 100644 index 18e40640e..000000000 --- a/jmvc/generate/templates/control/(underscore).html.ejs +++ /dev/null @@ -1,16 +0,0 @@ - - - - <%= Alias %> - - -

    <%= Alias %> Demo

    -
    - - - - \ No newline at end of file diff --git a/jmvc/generate/templates/control/(underscore).js.ejs b/jmvc/generate/templates/control/(underscore).js.ejs deleted file mode 100644 index fc31ad4ed..000000000 --- a/jmvc/generate/templates/control/(underscore).js.ejs +++ /dev/null @@ -1,19 +0,0 @@ -steal('can','./init.ejs', function(can, initView){ - /** - * @class <%= module %> - * @alias <%= Alias %> - */ - return can.Control( - /** @Static */ - { - defaults : {} - }, - /** @Prototype */ - { - init : function(){ - this.element.html(initView({ - message: "Hello World from <%= Alias %>" - })); - } - }); -}); \ No newline at end of file diff --git a/jmvc/generate/templates/control/(underscore)_test.js.ejs b/jmvc/generate/templates/control/(underscore)_test.js.ejs deleted file mode 100644 index 3a5973e73..000000000 --- a/jmvc/generate/templates/control/(underscore)_test.js.ejs +++ /dev/null @@ -1,18 +0,0 @@ -steal('<%= module %>','funcunit', function( <%=Alias%>, S ) { - - module("<%= module %>", { - setup: function(){ - S.open( window ); - $("#qunit-test-area").html("
    ") - }, - teardown: function(){ - $("#qunit-test-area").empty(); - } - }); - - test("updates the element's html", function(){ - new <%= Alias %>('#<%=underscore%>'); - ok( $('#<%=underscore%>').html() , "updated html" ); - }); - -}); \ No newline at end of file diff --git a/jmvc/generate/templates/control/init.ejs.ejs b/jmvc/generate/templates/control/init.ejs.ejs deleted file mode 100644 index 5ad93e451..000000000 --- a/jmvc/generate/templates/control/init.ejs.ejs +++ /dev/null @@ -1 +0,0 @@ -<%%= this.message %> \ No newline at end of file diff --git a/jmvc/generate/templates/control/test.html.ejs b/jmvc/generate/templates/control/test.html.ejs deleted file mode 100644 index df9bfd866..000000000 --- a/jmvc/generate/templates/control/test.html.ejs +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/jmvc/generate/templates/fixturemake.ejs b/jmvc/generate/templates/fixturemake.ejs deleted file mode 100644 index 23ec33f9b..000000000 --- a/jmvc/generate/templates/fixturemake.ejs +++ /dev/null @@ -1,17 +0,0 @@ - - var store = fixture.store(5, function(i){ - return { - name: "<%= alias %> "+i, - description: "<%= alias %> " + i - } - }); - - fixture({ - 'GET /<%= pluralAlias %>' : store.findAll, - 'GET /<%= pluralAlias %>/{id}' : store.findOne, - 'POST /<%= pluralAlias %>' : store.create, - 'PUT /<%= pluralAlias %>/{id}' : store.update, - 'DELETE /<%= pluralAlias %>/{id}' : store.destroy - }); - - return store; \ No newline at end of file diff --git a/jmvc/generate/templates/model.js b/jmvc/generate/templates/model.js deleted file mode 100644 index d35d674e4..000000000 --- a/jmvc/generate/templates/model.js +++ /dev/null @@ -1,76 +0,0 @@ -steal( 'steal/generate', - 'steal/generate/system.js', - 'steal/generate/inflector.js', - function(steal){ - - - - var upper = function(parts){ - for(var i =0; i < parts.length; i++){ - parts[i] = parts[i].charAt(0).toUpperCase()+parts[i].substr(1) - } - return parts - } - /** - * Creates a model at the location provided - */ - steal.generate.model = function(arg){ - - // make sure we have a module id - if(arg.indexOf(".") > -1){ - print("JMVC's generators use module ids. Please remove any periods (.)."); - quit(); - } - var md = steal.generate.convert(arg); - - path = arg; - - var folder = md.parentModule; - if(!folder){ - print("! Error: Models need to be part of an app"); - quit(); - } - if(!steal.File(folder).exists()){ - print("! Error: folder "+folder+" does not exist!"); - quit(); - } - - md.path_to_steal = new steal.File(path).pathToRoot(); - - //check pluralization of last part - if(md.pluralAlias === md.alias){ - print("! Warning: Model names should be singular. I don't think "+md._alias+" is singular!") - } - - // generate the files - steal.generate("jmvc/generate/templates/model", md.appPath, md) - - try{ - // steal this model in models.js - // steal.generate.insertSteal(md.appPath+"/models/models.js", "./"+md.underscore+".js"); - - // steal this model's unit test in qunit.js - steal.generate.insertSteal(md.appPath+"/"+md.appName+"_test.js", "./models/"+md._alias+"_test.js"); - } catch (e) { - if(e.type && e.type == "DUPLICATE"){ - print("! Error: This model was already created!") - quit(); - } - } - - var text = readFile("jmvc/generate/templates/fixturemake.ejs"); - var fixturetext = new steal.EJS({ - text: text - }).render(md); - - - if(readFile(md.appPath+"/models/fixtures/fixtures.js").indexOf(fixturetext) == -1){ - steal.generate.insertCode(md.appPath+"/models/fixtures/fixtures.js", fixturetext); - } - - - } - - - -}); \ No newline at end of file diff --git a/jmvc/generate/templates/model/models/(underscore).js.ejs b/jmvc/generate/templates/model/models/(underscore).js.ejs deleted file mode 100644 index af1930632..000000000 --- a/jmvc/generate/templates/model/models/(underscore).js.ejs +++ /dev/null @@ -1,21 +0,0 @@ -steal('can', function (can) { - /** - * @class <%= module %> - * @alias <%= Alias %> - * @parent index - * @inherits can.Model - * - * Wraps backend <%= underscore %> services. - */ - return can.Model( - /* @static */ - { - findAll : "GET /<%= pluralAlias %>", - findOne : "GET /<%= pluralAlias %>/{id}", - create : "POST /<%= pluralAlias %>", - update : "PUT /<%= pluralAlias %>/{id}", - destroy : "DELETE /<%= pluralAlias %>/{id}" - }, - /* @Prototype */ - {}); -}); \ No newline at end of file diff --git a/jmvc/generate/templates/model/models/(underscore)_test.js.ejs b/jmvc/generate/templates/model/models/(underscore)_test.js.ejs deleted file mode 100644 index 8afcb11a7..000000000 --- a/jmvc/generate/templates/model/models/(underscore)_test.js.ejs +++ /dev/null @@ -1,53 +0,0 @@ -steal( "./<%= underscore %>.js", - "funcunit/qunit", - "<%= appPath %>/models/fixtures", - function( <%= Alias %> ){ - - module("<%= module %>"); - - test("findAll", function(){ - expect(4); - stop(); - <%= Alias %>.findAll({}, function(<%= pluralAlias %>){ - ok(<%= pluralAlias %>, "findAll provides an object") - ok(<%= pluralAlias %>.length, "findAll provides something array-like") - ok(<%= pluralAlias %>[0].name, "findAll provides an object with a name") - ok(<%= pluralAlias %>[0].description, "findAll provides an object with a description") - start(); - }); - }); - - test("create", function(){ - expect(3) - stop(); - new <%= Alias %>({name: "dry cleaning", description: "take to street corner"}).save(function(<%= underscore %>) { - ok(<%= underscore %>, "save provides an object"); - ok(<%= underscore %>.id, "save provides and object with an id"); - equals(<%= underscore %>.name,"dry cleaning", "save provides an objec with a name") - <%= underscore %>.destroy() - start(); - }); - }); - - test("update" , function(){ - expect(2); - stop(); - new <%= Alias %>({name: "cook dinner", description: "chicken"}).save(function(<%= underscore %>) { - equals(<%= underscore %>.description,"chicken", "save creates with description"); - <%= underscore %>.attr({description: "steak"}).save(function(<%= underscore %>){ - equals(<%= underscore %>.description,"steak", "save udpates with description"); - <%= underscore %>.destroy(); - start(); - }); - }); - }); - - test("destroy", function(){ - expect(1); - stop(); - new <%= Alias %>({name: "mow grass", description: "use riding mower"}).destroy(function(<%= underscore %>) { - ok( true ,"Destroy called" ) - start(); - }); - }); -}); \ No newline at end of file diff --git a/jmvc/generate/templates/page.ejs b/jmvc/generate/templates/page.ejs deleted file mode 100644 index 660365136..000000000 --- a/jmvc/generate/templates/page.ejs +++ /dev/null @@ -1,22 +0,0 @@ - - - - <%= application_name %> - - - -

    Welcome to JavaScriptMVC!

    -
      -
    • Steal plugins and files in <%= path %>/<%= application_name %>.js.
    • -
    • Change to production mode by changing steal.js to steal.production.js in this file.
    • -
    - - - diff --git a/jmvc/generate/templates/plugin/(underscore).html.ejs b/jmvc/generate/templates/plugin/(underscore).html.ejs deleted file mode 100644 index a3178e4b6..000000000 --- a/jmvc/generate/templates/plugin/(underscore).html.ejs +++ /dev/null @@ -1,16 +0,0 @@ - - - - <%= alias %> - - -

    <%= alias %> Demo

    -

    This is a dummy page to show off your plugin

    - - - - \ No newline at end of file diff --git a/jmvc/generate/templates/plugin/(underscore).js.ejs b/jmvc/generate/templates/plugin/(underscore).js.ejs deleted file mode 100644 index a4ab7a149..000000000 --- a/jmvc/generate/templates/plugin/(underscore).js.ejs +++ /dev/null @@ -1,3 +0,0 @@ -steal('can',function(can) { - return {}; -}); \ No newline at end of file diff --git a/jmvc/generate/templates/plugin/(underscore)_test.js.ejs b/jmvc/generate/templates/plugin/(underscore)_test.js.ejs deleted file mode 100644 index 452475dfc..000000000 --- a/jmvc/generate/templates/plugin/(underscore)_test.js.ejs +++ /dev/null @@ -1,10 +0,0 @@ -steal('./<%= underscore %>','funcunit/qunit',function(<%= alias %>){ - - module("<%= module %>"); - - test("testing works", function(){ - ok(true,"an assert is run"); - }); - - -}); \ No newline at end of file diff --git a/jmvc/generate/templates/plugin/test.html.ejs b/jmvc/generate/templates/plugin/test.html.ejs deleted file mode 100644 index df9bfd866..000000000 --- a/jmvc/generate/templates/plugin/test.html.ejs +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/jmvc/generate/templates/scaffold/create/create.html.ejs b/jmvc/generate/templates/scaffold/create/create.html.ejs deleted file mode 100644 index 29e1be7d6..000000000 --- a/jmvc/generate/templates/scaffold/create/create.html.ejs +++ /dev/null @@ -1,32 +0,0 @@ - - - - <%= appPath %>/<%=underscore%>/create - - - -

    <%= appPath %>/<%=underscore%>/create Demo

    -
    -
    - - - - \ No newline at end of file diff --git a/jmvc/generate/templates/scaffold/create/create.js.ejs b/jmvc/generate/templates/scaffold/create/create.js.ejs deleted file mode 100644 index 565906e0f..000000000 --- a/jmvc/generate/templates/scaffold/create/create.js.ejs +++ /dev/null @@ -1,26 +0,0 @@ -steal('can', '<%= appPath %>/models/<%= underscore %>.js', './init.ejs', 'jquery/dom/form_params', - function (can, <%= Alias %>, initEJS) { - - /** - * @class <%= appPath %>/<%= underscore %>/create - * @alias <%=Alias%>Create - * @parent index - * @inherits jQuery.Controller - * Creates <%= plural %> - */ - return can.Control( - /** @Prototype */ - { - init: function () { - this.element.html(initEJS()); - }, - submit: function (el, ev) { - ev.preventDefault(); - el.find('[type=submit]').val('Creating...') - new <%= Alias %>(el.formParams()).save(function() { - el.find('[type=submit]').val('Create'); - el[0].reset() - }); - } - }); -}); \ No newline at end of file diff --git a/jmvc/generate/templates/scaffold/create/create_test.js.ejs b/jmvc/generate/templates/scaffold/create/create_test.js.ejs deleted file mode 100644 index 668ec543a..000000000 --- a/jmvc/generate/templates/scaffold/create/create_test.js.ejs +++ /dev/null @@ -1,44 +0,0 @@ -steal('funcunit', - './create.js', - '<%= appPath %>/models/<%= underscore %>.js', - '<%= appPath %>/models/fixtures', - function (S, <%=Alias%>Create, <%=Alias%>, <%= underscore %>Store ) { - - module("<%= appPath %>/<%=underscore%>/create", { - setup: function(){ - $("#qunit-test-area").append("
    "); - new <%=Alias%>Create("#create"); - }, - teardown: function(){ - $("#qunit-test-area").empty(); - <%= underscore %>Store.reset(); - } - }); - - test("create <%= plural %>", function () { - stop(); - - <%=Alias%>.bind("created",function(ev, <%= alias %>){ - ok(true, "Ice Water added"); - equals(<%= alias %>.name, "Ice Water", "name set correctly"); - equals(<%= alias %>.description, - "Pour water in a glass. Add ice cubes.", - "description set correctly"); - start(); - <%=Alias%>.unbind("created",arguments.callee); - }) - - S("[name=name]").type("Ice Water"); - S("[name=description]").type("Pour water in a glass. Add ice cubes."); - - S("[type=submit]").click(); - - S("[type=submit]").val("Creating...","button text changed while created"); - S("[type=submit]").val("Create", function(){ - ok(true, "button text changed back after create"); - equals(S("[name=name]").val(), "", "form reset"); - equals(S("[name=description]").val(), "", "form reset"); - }); - }); - -}); \ No newline at end of file diff --git a/jmvc/generate/templates/scaffold/create/init.ejs.ejs b/jmvc/generate/templates/scaffold/create/init.ejs.ejs deleted file mode 100644 index a4944723e..000000000 --- a/jmvc/generate/templates/scaffold/create/init.ejs.ejs +++ /dev/null @@ -1,9 +0,0 @@ -

    New <%= underscore %>

    -

    -
    - -

    -


    - -

    -

    \ No newline at end of file diff --git a/jmvc/generate/templates/scaffold/create/test.html.ejs b/jmvc/generate/templates/scaffold/create/test.html.ejs deleted file mode 100644 index a75cde2c2..000000000 --- a/jmvc/generate/templates/scaffold/create/test.html.ejs +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/jmvc/generate/templates/scaffold/list/init.ejs.ejs b/jmvc/generate/templates/scaffold/list/init.ejs.ejs deleted file mode 100644 index dbcafe1de..000000000 --- a/jmvc/generate/templates/scaffold/list/init.ejs.ejs +++ /dev/null @@ -1,6 +0,0 @@ -<%% this.each(function(current) { %> -
  1. el.data('<%= underscore %>', current) %>> -

    <%%= current.attr('name') %> X

    -

    <%%= current.attr('description') %>

    -
  2. -<%% }) %> \ No newline at end of file diff --git a/jmvc/generate/templates/scaffold/list/list.html.ejs b/jmvc/generate/templates/scaffold/list/list.html.ejs deleted file mode 100644 index 390b201d7..000000000 --- a/jmvc/generate/templates/scaffold/list/list.html.ejs +++ /dev/null @@ -1,34 +0,0 @@ - - - - <%= appPath %>/<%= underscore %>/list Demo - - - -

    <%= appPath %>/<%= underscore %>/list Demo

    -
      - Create <%= Alias %> - - - - \ No newline at end of file diff --git a/jmvc/generate/templates/scaffold/list/list.js.ejs b/jmvc/generate/templates/scaffold/list/list.js.ejs deleted file mode 100644 index 732840f60..000000000 --- a/jmvc/generate/templates/scaffold/list/list.js.ejs +++ /dev/null @@ -1,33 +0,0 @@ -steal('can','./init.ejs', '<%= appPath %>/models/<%= underscore %>.js', -function (can, initEJS, <%=Alias%>) { - /** - * @class <%= appPath %>/<%= underscore %>/list - * @alias <%=Alias%>List - * @parent index - * @inherits can.Control - * Lists <%= plural %> and lets you destroy them. - */ - return can.Control( - /** @Static */ - { - defaults : { - <%=Alias%>: <%=Alias%> - } - }, - /** @Prototype */ - { - init: function () { - this.list = new <%=Alias%>.List(); - this.element.html(initEJS(this.list)); - this.list.replace(<%=Alias%>.findAll()); - }, - '.destroy click': function (el) { - if (confirm("Are you sure you want to destroy?")) { - el.closest('.<%= underscore %>').data('<%= underscore %>').destroy(); - } - }, - "{<%=Alias%>} created": function (Model, ev, instance) { - this.list.push(instance); - } - }); -}); \ No newline at end of file diff --git a/jmvc/generate/templates/scaffold/list/list_test.js.ejs b/jmvc/generate/templates/scaffold/list/list_test.js.ejs deleted file mode 100644 index 996ebd9b2..000000000 --- a/jmvc/generate/templates/scaffold/list/list_test.js.ejs +++ /dev/null @@ -1,63 +0,0 @@ -steal( - 'funcunit', - './list.js', - '<%= appPath %>/models/<%= underscore %>.js', - '<%= appPath %>/models/fixtures', - function(S, <%=Alias%>List, <%=Alias%>, <%= underscore %>Store ){ - - module("<%= appPath %>/<%=underscore%>/list", { - setup: function(){ - $("#qunit-test-area").append("
      "); - this.list = new <%=Alias%>List("#<%=plural%>"); - }, - teardown: function(){ - $("#qunit-test-area").empty(); - <%= underscore %>Store.reset(); - } - }); - - test("lists all <%= plural %>", function(){ - stop(); - - // retrieve <%= plural %> - <%=Alias%>.findAll({}, function(<%= plural %>){ - // make sure they are listed in the page - - S(".<%= underscore %>").size(<%= plural %>.length,function(){ - ok(true, "All <%= plural %> listed"); - - start(); - }) - }) - }); - - test("lists created <%= plural %>", function(){ - - new <%=Alias%>({ - name: "Grilled Cheese", - description: "grill cheese in bread" - }).save(); - - S('h3:contains(Grilled Cheese X)').exists("Lists created <%= underscore %>"); - }) - - - test("delete <%= plural %>", function(){ - new <%=Alias%>({ - name: "Ice Water", - description: "mix ice and water" - }).save(); - - // wait until grilled cheese has been added - S('h3:contains(Ice Water X)').exists(); - - S.confirm(true); - S('h3:last a').click(); - - - S('h3:contains(Ice Water)').missing("Grilled Cheese Removed"); - - }); - - -}); \ No newline at end of file diff --git a/jmvc/generate/templates/scaffold/list/test.html.ejs b/jmvc/generate/templates/scaffold/list/test.html.ejs deleted file mode 100644 index e36256f7d..000000000 --- a/jmvc/generate/templates/scaffold/list/test.html.ejs +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/jmvc/generate/templates/scaffoldHTML.ejs b/jmvc/generate/templates/scaffoldHTML.ejs deleted file mode 100644 index 5b291accc..000000000 --- a/jmvc/generate/templates/scaffoldHTML.ejs +++ /dev/null @@ -1,4 +0,0 @@ -

      <%= Plural %>

      -
        -
        - \ No newline at end of file diff --git a/jmvc/generate/templates/scaffoldHookup.ejs b/jmvc/generate/templates/scaffoldHookup.ejs deleted file mode 100644 index 5afb059e1..000000000 --- a/jmvc/generate/templates/scaffoldHookup.ejs +++ /dev/null @@ -1,2 +0,0 @@ - new <%= Alias %>List('#<%= plural %>'); - new <%= Alias %>Create('#create'); \ No newline at end of file diff --git a/jmvc/generate/templates/scaffoldTest.ejs b/jmvc/generate/templates/scaffoldTest.ejs deleted file mode 100644 index eecd35467..000000000 --- a/jmvc/generate/templates/scaffoldTest.ejs +++ /dev/null @@ -1,11 +0,0 @@ - - test("creating a <%= plural %> adds it to the list ", function () { - - S("[name=name]").type("Ice Water"); - S("[name=description]").type("Pour water in a glass. Add ice cubes."); - - S("[type=submit]").click(); - - S("h3:contains(Ice Water)").exists(); - S("p:contains(Pour water in a glass. Add ice cubes.)").exists() - }); \ No newline at end of file diff --git a/jmvc/generate/test/app_plugin_model_controller.js b/jmvc/generate/test/app_plugin_model_controller.js deleted file mode 100644 index 9352a0722..000000000 --- a/jmvc/generate/test/app_plugin_model_controller.js +++ /dev/null @@ -1,60 +0,0 @@ -load('steal/rhino/rhino.js') -load('steal/rhino/test.js'); - -(function(rhinoSteal){ - _S = steal.test; - - - _S.module("jquery/generate") - STEALPRINT = false; - - _S.test("app" , function(t){ - _args = ['cnu']; - load('jquery/generate/app'); - _S.clear(); - _S.open('cnu/cnu.html') - t.ok(typeof steal !== 'undefined', "steal is fine") - _S.clear(); - }) - - _S.test("app 2 levels deep" , function(t){ - _args = ['cnu/widget']; - load('jquery/generate/plugin'); - _S.clear(); - _S.open('cnu/widget/widget.html') - t.ok(typeof steal !== 'undefined', "steal is fine") - _S.clear(); - }) - - /** - * Tests generating a very basic controller and model - */ - - _S.test("controller, model, and page" , function(t){ - _args = ['Cnu.Todos']; - load('jquery/generate/controller'); - _S.clear(); - - _args = ['Cnu.Models.Todo']; - load('jquery/generate/model'); - _S.clear(); - cnuContent = readFile('cnu/cnu.js') - +"\n.then('./models/todo.js')" - +"\n.then('./todos/todos.js')"; - load('steal/rhino/rhino.js') - new steal.File('cnu/cnu.js').save( cnuContent ); - - - _args = ['cnu','cnugen.html']; - load('jquery/generate/page'); - _S.clear(); - - _S.open('cnu/cnugen.html'); - - t.ok(typeof Cnu.Todos !== 'undefined',"load Cnu.Controllers.Todos") - t.ok(typeof Cnu.Models.Todo !== 'undefined', "load Cnu.Models.Todo") - - rhinoSteal.File("cnu").removeDir(); - }) - -})(steal); diff --git a/jmvc/generate/test/run.js b/jmvc/generate/test/run.js deleted file mode 100644 index 1efe5c72a..000000000 --- a/jmvc/generate/test/run.js +++ /dev/null @@ -1,3 +0,0 @@ -load("jquery/generate/test/app_plugin_model_controller.js"); - -load("jquery/generate/test/scaffold.js"); diff --git a/jmvc/generate/test/scaffold.js b/jmvc/generate/test/scaffold.js deleted file mode 100644 index ecfb9552f..000000000 --- a/jmvc/generate/test/scaffold.js +++ /dev/null @@ -1,87 +0,0 @@ - - -load('steal/rhino/rhino.js'); -load('steal/test/test.js'); - -steal('steal/test', function(s){ - - s.test.module("jquery/generate/scaffold") - - STEALPRINT = false; - - s.test.test("make app and scaffold", function(t){ - _args = ['cookbook']; - load('jquery/generate/app'); - _args = ['Cookbook.Models.Recipe']; - load('jquery/generate/scaffold'); - - - load('steal/rhino/rhino.js'); - var cookbookContent = readFile('cookbook/cookbook.js') - +"\n.then('./models/recipe.js')" - +"\n.then('./controllers/recipe_controller.js')"; - new steal.File('cookbook/cookbook.js').save( cookbookContent ); - - var qunitContent = readFile('cookbook/test/qunit/qunit.js'). - replace("cookbook_test", "recipe_test"); - new steal.File('cookbook/test/qunit/qunit.js').save( qunitContent ); - - var funcunitContent = readFile('cookbook/test/funcunit/funcunit.js'). - replace("cookbook_test", "recipe_controller_test"); - new steal.File('cookbook/test/funcunit/funcunit.js').save( funcunitContent ); - - t.clear(); - print('trying to open ...') - t.open('cookbook/cookbook.html', false) - t.ok(Cookbook.Controllers.Recipe, "Recipe Controller") - t.ok(Cookbook.Models.Recipe, "Recipe Controller") - t.clear(); - }); - - //now see if unit and functional run - -// s.test.test("scaffold unit tests", function(t){ -// -// load('steal/rhino/rhino.js'); -// load('funcunit/loader.js'); -// FuncUnit.load('cookbook/qunit.html'); -// }); -// -// s.test.test("scaffold functional tests", function(t){ -// load('steal/rhino/rhino.js'); -// load('funcunit/loader.js'); -// FuncUnit.load('cookbook/funcunit.html'); -// -// }); -// -// s.test.test("documentjs", function(t){ -// t.clear(); -// load('steal/rhino/rhino.js'); -// _args = ['cookbook/cookbook.html'] -// load("documentjs/documentjs.js"); -// DocumentJS('cookbook/cookbook.html'); -// }); - - s.test.test("compress", function(t){ - t.clear(); - load("cookbook/scripts/build.js") - - var cookbookPage = readFile('cookbook/cookbook.html'). - replace("steal.js?cookbook,development", "steal.js?cookbook,production"); - new steal.File('cookbook/cookbook.html').save( cookbookPage ); - - t.clear(); - t.open('cookbook/cookbook.html', false) - t.ok(Cookbook.Controllers.Recipe, "Recipe Controller") - t.ok(Cookbook.Models.Recipe, "Recipe Controller") - t.clear(); - }); - - - //print("-- cleanup --"); -// s.File("cookbook").removeDir(); - -}) - - - diff --git a/readme.md b/readme.md index d140d32db..b3d218b95 100644 --- a/readme.md +++ b/readme.md @@ -71,7 +71,7 @@ command-line and browser-based utilities enabling you to: ## FuncUnit -[funcunit FuncUnit] is a web application testing framework that provides automated unit and +[FuncUnit FuncUnit] is a web application testing framework that provides automated unit and functional testing. Tests are written and debugged in the browser with FuncUnit's short, terse, jQuery-like API. The same tests can be instantly automated, run by Envjs or Selenium. diff --git a/scripts/getjmvc b/scripts/getjmvc index d8ab4630c..db10cd657 100755 --- a/scripts/getjmvc +++ b/scripts/getjmvc @@ -61,7 +61,7 @@ if [ -f ${INSTALLPATH}steal/steal.js ] then cd ${INSTALLPATH}steal git pull origin master - cd ../jquery + cd ../jquerypp git pull origin master cd ../documentjs git pull origin master @@ -81,7 +81,7 @@ else fi git submodule add $FULLSRC/steal.git ${INSTALLPATH}steal -git submodule add $FULLSRC/canjs.git ${INSTALLPATH}canjs +git submodule add $FULLSRC/canjs.git ${INSTALLPATH}can git submodule add $FULLSRC/jquerypp.git ${INSTALLPATH}jquerypp git submodule add $FULLSRC/documentjs.git ${INSTALLPATH}documentjs git submodule add $FULLSRC/funcunit.git ${INSTALLPATH}funcunit @@ -89,7 +89,9 @@ git submodule init git submodule update cd ${INSTALLPATH}steal git checkout $BRANCH -cd ../jquery +cd ../can +git checkout $BRANCH +cd ../jquerypp git checkout $BRANCH cd ../documentjs git checkout master From 891e5fe141f32b56d1bf543ab0739df8ebacd044 Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Wed, 17 Apr 2013 15:59:48 -0500 Subject: [PATCH 18/54] adding generators in jmvc --- .gitmodules | 3 +++ jmvc | 1 + 2 files changed, 4 insertions(+) create mode 160000 jmvc diff --git a/.gitmodules b/.gitmodules index 5b2beb71d..de5d08310 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "jquerypp"] path = jquerypp url = https://github.com/bitovi/jquerypp.git +[submodule "jmvc"] + path = jmvc + url = git://github.com/bitovi/jmvc-generators diff --git a/jmvc b/jmvc new file mode 160000 index 000000000..bcef43f84 --- /dev/null +++ b/jmvc @@ -0,0 +1 @@ +Subproject commit bcef43f844587bc4da1bba10382e5d861bdd8bbb From 521c9f95131f8672c726c5595562bf0a2641102b Mon Sep 17 00:00:00 2001 From: ccummings Date: Sun, 21 Apr 2013 00:56:59 -0500 Subject: [PATCH 19/54] Adding grunt task for replacing @VERSION in CanJS --- build/tasks/updateversion.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 build/tasks/updateversion.js diff --git a/build/tasks/updateversion.js b/build/tasks/updateversion.js new file mode 100644 index 000000000..5febe4698 --- /dev/null +++ b/build/tasks/updateversion.js @@ -0,0 +1,20 @@ +var path = require('path'); + +// A grunt task that writes the banner to every file +module.exports = function (grunt) { + grunt.registerMultiTask('updateversion', 'Replaces given symbol with current version', function () { + var options = grunt.config.process(['updateversion', this.target]); + var version = this.data.version; + var symbol = this.data.symbol; + + grunt.file.expand(this.data.files).forEach(function (file) { + var outFile = options.out ? path.join(options.out, path.basename(file)) : file; + var fileContents = grunt.file.read(file).replace(symbol, version); + + if(grunt.file.read(file).match(symbol)) { + grunt.log.writeln('Updating version in ' + file); + grunt.file.write(outFile, fileContents.replace(symbol, version)); + } + }); + }); +} From 39824234c5da9f4715979868dce906b6235eee31 Mon Sep 17 00:00:00 2001 From: Alexis Abril Date: Mon, 22 Apr 2013 16:31:00 -0500 Subject: [PATCH 20/54] Updating refs. --- can | 2 +- steal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/can b/can index e7e335b61..9ade76a1c 160000 --- a/can +++ b/can @@ -1 +1 @@ -Subproject commit e7e335b615bf5ca22b25bd338a0b2fd3690706f6 +Subproject commit 9ade76a1c939d62ac2ee5c4cd4bf1c2420f52df4 diff --git a/steal b/steal index 6c6a805c2..ea8682d35 160000 --- a/steal +++ b/steal @@ -1 +1 @@ -Subproject commit 6c6a805c204208d0ffd619fe8eb6b71b1dcf8b50 +Subproject commit ea8682d3595f68eb97d36d9dbe26c24fe6d9842e From cf161f598f886f6af2fa0890ba159e9f6d7ad373 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Fri, 26 Apr 2013 15:59:04 -0600 Subject: [PATCH 21/54] Updating testify --- build/tasks/testify.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/build/tasks/testify.js b/build/tasks/testify.js index a330b4896..6aa1190e1 100644 --- a/build/tasks/testify.js +++ b/build/tasks/testify.js @@ -8,41 +8,42 @@ module.exports = function(grunt) { var done = this.async(); var data = this.data; var template = grunt.file.read(this.data.template); - var transform = this.data.transform; + var transform = this.data.transform || {}; var modules = this.data.builder.modules; var configurations = this.data.builder.configurations; - if(transform && transform.modules) { - modules = transform.modules(modules); - } - _.each(configurations, function(config, configurationName) { var options = { configuration: config, modules: [], tests: [], - root: data.root + root: data.root, + '_': _ }; _.each(modules, function(definition, key) { if(!definition.configurations || definition.configurations.indexOf(configurationName) !== -1) { var name = key.substr(key.lastIndexOf('/') + 1); - options.modules.push(key); - options.tests.push(key + '/' + name + '_test.js'); + var mod = transform.module ? transform.module(definition, key) : key; + var test = transform.test ? transform.test(definition, key) : (key + '/' + name + '_test.js'); + + mod && options.modules.push(mod); + test && options.tests.push(test); } }); _.extend(config.steal, { - root: '../..' + root: data.root }); if(transform && transform.options) { _.extend(options, transform.options.call(config, configurationName)); } - var lib = beautify.html(ejs.render(template, options), { - "wrap_line_length": 70 - }); + var lib = '\n'+ + beautify.html(ejs.render(template, options), { + "wrap_line_length": 70 + }); grunt.log.writeln('Generating ' + data.out + configurationName + '.html'); grunt.file.write(data.out + configurationName + '.html', lib); From 8a5d5afcf09c414e560303d8b340e1e62bda7b25 Mon Sep 17 00:00:00 2001 From: Mihael Konjevic Date: Sun, 26 May 2013 15:19:55 -0400 Subject: [PATCH 22/54] Fix failing test --- steal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/steal b/steal index ea8682d35..b6e3febf6 160000 --- a/steal +++ b/steal @@ -1 +1 @@ -Subproject commit ea8682d3595f68eb97d36d9dbe26c24fe6d9842e +Subproject commit b6e3febf645fdc5a8408c75140858db188a2870c From 0ab68253b2661d223ab154fa16486a73df99257c Mon Sep 17 00:00:00 2001 From: Mihael Konjevic Date: Sun, 26 May 2013 15:22:37 -0400 Subject: [PATCH 23/54] Revert "Fix failing test" This reverts commit 8a5d5afcf09c414e560303d8b340e1e62bda7b25. --- steal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/steal b/steal index b6e3febf6..ea8682d35 160000 --- a/steal +++ b/steal @@ -1 +1 @@ -Subproject commit b6e3febf645fdc5a8408c75140858db188a2870c +Subproject commit ea8682d3595f68eb97d36d9dbe26c24fe6d9842e From e7046060de1850561b749a6e3baf958f933dc821 Mon Sep 17 00:00:00 2001 From: Brian Moschel Date: Sun, 26 May 2013 22:27:09 -0400 Subject: [PATCH 24/54] updating getting started guide --- tutorials/getstarted/building.md | 2 +- tutorials/getstarted/creating.md | 20 +++++++++++++++++++- tutorials/getstarted/testing.md | 10 ++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/tutorials/getstarted/building.md b/tutorials/getstarted/building.md index 8941789ce..abb5dfe56 100644 --- a/tutorials/getstarted/building.md +++ b/tutorials/getstarted/building.md @@ -28,7 +28,7 @@ Verify that production.js was created by checking your `cookbook` folder. Switch to production mode by changing the script tag to include steal.production.js: ## Reload and verify diff --git a/tutorials/getstarted/creating.md b/tutorials/getstarted/creating.md index 748bb7219..1930fd1fc 100644 --- a/tutorials/getstarted/creating.md +++ b/tutorials/getstarted/creating.md @@ -153,7 +153,25 @@ and `cookbook/recipe/list` and then tries to add these widgets to the However, `#recipes` and `#create` elements did not exist! Fortunately, the generator also added their HTML to `index.html` so that it includes: - + +

        Recipes

        +
          +
          + +Remove all other generated parts of the `index.html` page so it just looks like: + + + + + cookbook + + +

          Recipes

          +
            +
            + + + ## Run Cookbook diff --git a/tutorials/getstarted/testing.md b/tutorials/getstarted/testing.md index 2d57a32ad..af4b21cdc 100644 --- a/tutorials/getstarted/testing.md +++ b/tutorials/getstarted/testing.md @@ -21,6 +21,16 @@ guide will show you how to: ## Run Tests +Open cookbook_test.js. You'll notice it steals tests for the model and controls. There +are also tests that verify the original "Welcome to JavaScriptMVC" text that we removed. Remove the +extraneous tests so `cookbook_test.js` just looks like this: + +steal( + 'funcunit', + './models/recipe_test.js', + 'cookbook/recipe/create/create_test.js', + 'cookbook/recipe/list/list_test.js'); + To run all of __cookbook's__ tests, open `cookbook/test.html` in a browser. You should see something like [//cookbook/test.html this]. From 1f77425aabafb0bc0279c3700515a776ced611dc Mon Sep 17 00:00:00 2001 From: Brian Moschel Date: Sun, 26 May 2013 22:53:38 -0400 Subject: [PATCH 25/54] updating getting started guide --- can | 2 +- documentjs | 2 +- steal | 2 +- tutorials/getstarted/testing.md | 7 +++++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/can b/can index 9ade76a1c..356916f09 160000 --- a/can +++ b/can @@ -1 +1 @@ -Subproject commit 9ade76a1c939d62ac2ee5c4cd4bf1c2420f52df4 +Subproject commit 356916f099b17aa36a7916a3b117ca63d156a106 diff --git a/documentjs b/documentjs index 432b7adff..5e3cd4b98 160000 --- a/documentjs +++ b/documentjs @@ -1 +1 @@ -Subproject commit 432b7adfff5315ca0a5a0a80c7c0502ca7fe919a +Subproject commit 5e3cd4b98d361f30b0b2b0d18b5cc1961f6aed11 diff --git a/steal b/steal index ea8682d35..6b3973189 160000 --- a/steal +++ b/steal @@ -1 +1 @@ -Subproject commit ea8682d3595f68eb97d36d9dbe26c24fe6d9842e +Subproject commit 6b397318978c604845645f27917b4560dcfc8d31 diff --git a/tutorials/getstarted/testing.md b/tutorials/getstarted/testing.md index af4b21cdc..9c2c1982a 100644 --- a/tutorials/getstarted/testing.md +++ b/tutorials/getstarted/testing.md @@ -35,10 +35,13 @@ To run all of __cookbook's__ tests, open `cookbook/test.html` in a browser. You should see something like [//cookbook/test.html this]. -To run those same tests with [funcunit.selenium Selenium], run: +To run those same tests with [funcunit.selenium Selenium], first you must set up a +local server, like Apache, running at the javascriptmvc root. Make sure you can +open your test page from this server, at a URL like http://localhost/javascriptmvc/cookbook/test.html. +Then run: - > ./js funcunit/open/selenium cookbook/test.html + > ./js funcunit/open/selenium http://localhost/javascriptmvc/cookbook/test.html You should see something like: From de668ff0f6342acdc816e8f241944a424fa1e7aa Mon Sep 17 00:00:00 2001 From: Brian Moschel Date: Tue, 28 May 2013 01:05:36 -0400 Subject: [PATCH 26/54] site/scripts/doc.js working --- site/docs.js | 1 - site/scripts/doc.js | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/site/docs.js b/site/docs.js index 00a697a63..31ecf42fc 100644 --- a/site/docs.js +++ b/site/docs.js @@ -4,7 +4,6 @@ steal('can', 'jquery/build/lib.js') steal('steal/generate', - 'steal/get', 'steal/build', 'steal/build/pluginify', 'steal/coffee', diff --git a/site/scripts/doc.js b/site/scripts/doc.js index 5ab37aa0b..df4c66002 100644 --- a/site/scripts/doc.js +++ b/site/scripts/doc.js @@ -3,6 +3,7 @@ load('steal/rhino/rhino.js'); steal("documentjs", function(DocumentJS){ DocumentJS('site/scripts/doc.html',{ markdown : [ 'readme.md', 'site', 'tutorials', 'steal', 'jquery', 'can', 'funcunit' ], - out : 'site/docs' + out : 'site/docs', + parent: 'index' }); }); From c51120141654d45242da3da3ac7b49106b7e057c Mon Sep 17 00:00:00 2001 From: Brian Moschel Date: Tue, 28 May 2013 02:26:30 -0400 Subject: [PATCH 27/54] moving docs location --- .gitignore | 1 + site/scripts/doc.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fb7b73015..fc99d1227 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +docs/* .tmp* cookbook* site/docs/* diff --git a/site/scripts/doc.js b/site/scripts/doc.js index df4c66002..c18a33963 100644 --- a/site/scripts/doc.js +++ b/site/scripts/doc.js @@ -3,7 +3,7 @@ load('steal/rhino/rhino.js'); steal("documentjs", function(DocumentJS){ DocumentJS('site/scripts/doc.html',{ markdown : [ 'readme.md', 'site', 'tutorials', 'steal', 'jquery', 'can', 'funcunit' ], - out : 'site/docs', + out : 'docs', parent: 'index' }); }); From 3e651036bfc508f1b0fb84a23c04b17c1b52090d Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Tue, 28 May 2013 09:16:51 -0500 Subject: [PATCH 28/54] updated docs --- site/scripts/doc.js | 5 +++-- tutorials/examples.md | 12 +----------- tutorials/examples/todo.html | 25 +++++++++++++++++++++++++ tutorials/examples/todo.md | 24 ++++++++++++++---------- 4 files changed, 43 insertions(+), 23 deletions(-) create mode 100644 tutorials/examples/todo.html diff --git a/site/scripts/doc.js b/site/scripts/doc.js index c18a33963..6ce2cae81 100644 --- a/site/scripts/doc.js +++ b/site/scripts/doc.js @@ -2,8 +2,9 @@ load('steal/rhino/rhino.js'); steal("documentjs", function(DocumentJS){ DocumentJS('site/scripts/doc.html',{ - markdown : [ 'readme.md', 'site', 'tutorials', 'steal', 'jquery', 'can', 'funcunit' ], + markdown : [ 'readme.md', 'site', 'tutorials', 'steal', 'jquerypp', 'can', 'funcunit' ], out : 'docs', - parent: 'index' + parent: 'index'//, + //debug: true }); }); diff --git a/tutorials/examples.md b/tutorials/examples.md index af2557cec..21f3eefe9 100644 --- a/tutorials/examples.md +++ b/tutorials/examples.md @@ -4,7 +4,7 @@ Here is the list of the example JavaScriptMVC applications. They cover specific JavaScriptMVC features and are ordered by complexity. If you need an introduction to the JavaScriptMVC framework it is best to read them in order. -## [todo Todo] - [open application ⇗](todo/todo.html) +## [todo TodoMVC JavaScriptMVC] - [open application ⇗](tutorials/examples/todo.html) In this guide, we're going to be installing and walking through the simplest [JavaScriptMVC](http://javascriptmvc.com/) application imaginable — a TODO list manager. @@ -14,16 +14,6 @@ This article covers: - Separation of application logic from user interface - Using model lists to manage collection of models -## [playermx PlayerMX] - [open application ⇗](player/player.html) - -This article walks through a simple video player application utilizing Popcorn.js. - -This article covers: - -- Installing and running the Application -- Templated Events with [jQuery.Controller $.Controller] -- How PlayerMX is built - ## [srchr Srchr] - [open application ⇗](srchr/srchr.html) Srchr searches multiple services (like Flickr, Upcoming, and Twitter) and saves the results between page requests. diff --git a/tutorials/examples/todo.html b/tutorials/examples/todo.html new file mode 100644 index 000000000..0a75a959e --- /dev/null +++ b/tutorials/examples/todo.html @@ -0,0 +1,25 @@ + + + + + + CanJS • TodoMVC + + +
            +
            +
            +

            Double-click to edit a todo

            +

            Written by Bitovi

            +

            Part of TodoMVC

            +
            + + + + \ No newline at end of file diff --git a/tutorials/examples/todo.md b/tutorials/examples/todo.md index 0d04652ea..66eb4c3ac 100644 --- a/tutorials/examples/todo.md +++ b/tutorials/examples/todo.md @@ -3,22 +3,26 @@ ## Introduction -In this article we will be learning the basics of [JavaScriptMVC](http://javascriptmvc.com/) and the [Model-View-Controller pattern](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) by installing and walking through a simple To-do list manager. The separation of the application's core logic from its user interface behavior is the hallmark of MVC. By working through this exercise you will understand how JavaScriptMVC's particular flavor of this pattern enables you to create more flexible and maintainable browser-based applications. +In this article we will be learning the basics of [JavaScriptMVC](http://javascriptmvc.com/) and +the [Model-View-Controller pattern](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) by installing +and walking through a simple Todo list manager. The separation of the +application's core logic from its user interface behavior is the hallmark of MVC. By +working through this exercise you will understand how JavaScriptMVC's particular flavor of this pattern +enables you to create more flexible and maintainable browser-based applications. Let's get started! ## Setup -First, clone the application from our [repository](http://github.com/jupiterjs/todo) at GitHub, and initialize all the necessary submodules. The following commands will get you up and running: +First, clone the application from our [repository](http://github.com/bitovi/todomvc-javascriptmvc) at GitHub, +and initialize all the necessary submodules. The following commands will get you up and running: - $ git clone https://github.com/jupiterjs/todo - $ git checkout jmvc_3.3 - $ cd todo + $ git clone http://github.com/bitovi/todomvc-javascriptmvc + $ cd todomvc-javascriptmvc $ git submodule update --init -This bundle now contains everything you need to run the application locally. Since there is no server-side dependency, you can now open the `todo/todo.html` file in your browser and see it in action. - -@image tutorials/images/todos.png +Open `todomvc-javascriptmvc/todo/index.html` in your browser. You might have to host it +under a static server. ## Structure @@ -27,7 +31,7 @@ Now let's take a look at the anatomy of our application: /todo [top-level, the GitHub repository] /can /funcunit - /jquery + /jquerypp /steal /todo /scripts @@ -36,7 +40,7 @@ Now let's take a look at the anatomy of our application: qunit.html todo.css todo.ejs - todo.html + index.html todo.js Breaking it down: From 4c89363d1bd91733c6eae02f477fdf95a3762dc0 Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Tue, 28 May 2013 15:30:43 -0500 Subject: [PATCH 29/54] updated get script site is better --- scripts/getjmvc | 5 ++++- site/docs.js | 2 +- site/scripts/doc.js | 5 ++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/getjmvc b/scripts/getjmvc index db10cd657..a1026fdab 100755 --- a/scripts/getjmvc +++ b/scripts/getjmvc @@ -85,16 +85,19 @@ git submodule add $FULLSRC/canjs.git ${INSTALLPATH}can git submodule add $FULLSRC/jquerypp.git ${INSTALLPATH}jquerypp git submodule add $FULLSRC/documentjs.git ${INSTALLPATH}documentjs git submodule add $FULLSRC/funcunit.git ${INSTALLPATH}funcunit +git submodule add $FULLSRC/jmvc-generators.git ${INSTALLPATH}jmvc git submodule init git submodule update cd ${INSTALLPATH}steal git checkout $BRANCH +cd ../jmvc +git checkout $BRANCH cd ../can git checkout $BRANCH cd ../jquerypp git checkout $BRANCH cd ../documentjs -git checkout master +git checkout $BRANCH cd ../funcunit git checkout $BRANCH git submodule init diff --git a/site/docs.js b/site/docs.js index 31ecf42fc..d34d006ee 100644 --- a/site/docs.js +++ b/site/docs.js @@ -3,7 +3,7 @@ steal('can', 'documentjs', 'jquery/build/lib.js') -steal('steal/generate', +steal('steal','steal/generate', 'steal/build', 'steal/build/pluginify', 'steal/coffee', diff --git a/site/scripts/doc.js b/site/scripts/doc.js index 6ce2cae81..f58f478d3 100644 --- a/site/scripts/doc.js +++ b/site/scripts/doc.js @@ -2,9 +2,8 @@ load('steal/rhino/rhino.js'); steal("documentjs", function(DocumentJS){ DocumentJS('site/scripts/doc.html',{ - markdown : [ 'readme.md', 'site', 'tutorials', 'steal', 'jquerypp', 'can', 'funcunit' ], + markdown : [ 'readme.md', 'site', 'tutorials', 'steal', 'jquerypp', 'can', 'funcunit'], out : 'docs', - parent: 'index'//, - //debug: true + parent: 'index' }); }); From 2b7ff421ba6cbd2df27f66e86b628aa8a013c6e4 Mon Sep 17 00:00:00 2001 From: Austin McDaniel Date: Tue, 28 May 2013 16:33:31 -0500 Subject: [PATCH 30/54] removing contacts ap --- tutorials/examples/contacts/contacts.md | 53 ----------- tutorials/examples/contacts/dc.md | 83 ----------------- tutorials/examples/contacts/designing.md | 84 ------------------ tutorials/examples/contacts/glue.md | 108 ----------------------- 4 files changed, 328 deletions(-) delete mode 100644 tutorials/examples/contacts/contacts.md delete mode 100644 tutorials/examples/contacts/dc.md delete mode 100644 tutorials/examples/contacts/designing.md delete mode 100644 tutorials/examples/contacts/glue.md diff --git a/tutorials/examples/contacts/contacts.md b/tutorials/examples/contacts/contacts.md deleted file mode 100644 index 0037a8679..000000000 --- a/tutorials/examples/contacts/contacts.md +++ /dev/null @@ -1,53 +0,0 @@ -@page contacts Contacts -@parent examples 1 -@hide - -This is a tutorial application that introduces and explains step-by-step how to architect a JavascriptMVC 3.0 style application using a contacts application. Contacts is a lightweight application that allows users to add and organize their friends' contact information. - -This tutorial describes: - -* Installing and running the application -* The application's structure and organization -* How the application's widgets were designed -* The anatomy of the application's widgets -* How we glued the application's widgets together using event-oriented-architecture - -Using techniques we will cover in this tutorial, you will learn how to build an application that is modular, testable, and scaleable. - -@image tutorials/images/contacts_preview.jpg - -## Setup - -The application source is hosted by [GitHub](https://github.com/jupiterjs/contacts). You can either download the application using [steal.get GetJS] - - ./js steal/getjs contacts - -or clone the code using the following commands: - - $ git clone https://github.com/jupiterjs/contacts - $ cd contacts - $ git submodule update --init - -Once you get the application from GitHub you should have structure similar to below. - - [top-level] - /jquery - /steal - /funcunit - /scripts - /contacts - /scripts - /test - /models - /fixtures - /views - funcunit.html - qunit.html - contacts.css - contacts.js - ... - contacts.html - -To run the application, open _contacts.html_ with your browser. We will be using [jQuery.fixture fixtures] to simulate the AJAX requests so running it from a server isn’t necessary. - -Once the application is displayed in your browser, continue to [contacts.dc Divide and Conquer] to learn how we split up the application. \ No newline at end of file diff --git a/tutorials/examples/contacts/dc.md b/tutorials/examples/contacts/dc.md deleted file mode 100644 index 66a0878c5..000000000 --- a/tutorials/examples/contacts/dc.md +++ /dev/null @@ -1,83 +0,0 @@ -@page contacts.dc Divide and Conquer -@parent contacts 0 - -The secret to building large applications is never build large applications. Understanding how to divide your application is the first step towards maintainable architecture. This section covers why and how to divide up your app and uses contacts as an example. - -## Isolation - -The goal for dividing your application should be to create modules that are isolated. - -Isolated modules are dumb, lonely, and replaceable. Dumb because they are limited to one specific purpose, for example showing a list of data. Lonely because they rarely reference other modules. Replaceable because they have a simple API, making them easy to swap out. - -Isolated modules are easily testable because they have a small, well defined scope. Each piece can be worked on in parallel because the code is divided. Reuse is easier because the modules are not coupled to each other. - -## Dividing Contacts - -The contacts app has 3 lists that filter the grid of contacts. You can create additional categories and contacts by clicking the 'new' icon. - -The application can be divided up into a few widgets: - -* List - accepts a generic data source and layout, renders and updates the list. -* Grid - accepts a generic data source, renders a grid. -* Sort - sorts the grid items. -* Create - renders a form to create a new instance from a data source. - -Heres a visual representation of how this app is broken up into modules. - -@image tutorials/images/contacts_widgets.jpg - -## Folder Structure - -The code for these widgets is divided into three top level folders: MXUI, Jupiter, and Contacts. - -### MXUI - -[https://github.com/jupiterjs/mxui MXUI] (jQueryMX User Interface) is a JavaScriptMVC widget library. The Grid and List widgets from MXUI are used in Contacts. - -### Jupiter - -Each isolated module lives in its own directory. Those directories are then grouped in a namespace, for example _Jupiter_ or the name of your company. These modules are intended to be reused across applications. - -The Jupiter folder contains: - -* create - renders a form to create a new instance from a data source. -* style - attaches jQuery UI styles to elements. -* scrollable_grid - creates a infinitely scrollable grid using the MXUI grid. - -### Contacts - -Finally, we need a widget that loads the modules and ties them together into a application. In this application, the contacts folder contains this 'application widget'. - -This widget will be where the application starts, loading each module, initializing them, and gluing them together. - - $.Controller("Contacts.Controller", { - init: function(){ - - this.params = new Mxui.Data(); - - $("#category .list_wrapper").mxui_data_list({ - model : Contacts.Models.Category, - show : "//contacts/views/categoryList", - create: "//contacts/views/categoryCreate" - }); - - $("#location .list_wrapper").mxui_data_list({ - model : Contacts.Models.Location, - show : "//contacts/views/categoryList", - create: "//contacts/views/categoryCreate" - }); - -The contacts widget listens for events using event delegation and communicates with cousin widgets. - - "#category .list_wrapper activate": function(el, ev, item){ - this.params.attr("categoryId", item.id); - }, - "#category .list_wrapper deactivate": function(el, ev, item){ - this.params.attr("categoryId", null); - } - -In the [contacts.glue Gluing Modules Together] section, we will touch more on the pattern used to facilitate this cross-widget communication. - -Additionally in the contacts folder, you will find the building blocks of any JavascriptMVC application: models for communication with the server, fixtures for simulating AJAX responses from the server, and functional tests for testing the application. - -In the next section, we will get into more detail about [contacts.designing how to design each module]. \ No newline at end of file diff --git a/tutorials/examples/contacts/designing.md b/tutorials/examples/contacts/designing.md deleted file mode 100644 index 1711361ac..000000000 --- a/tutorials/examples/contacts/designing.md +++ /dev/null @@ -1,84 +0,0 @@ -@page contacts.designing Designing Modules -@parent contacts 1 - -Widgets should be dumb to whats going on around them. They should be self contained and provide an easy to use API for developers. The first step in designing a widget is to define the input and outputs. - -## Defining Inputs and Outputs - -Inputs are anything a widget consumes from the outside world. This can include parameters passed (optional or required) or DOM events expected. For example, a grid widget consumes parameters like page offset, initial sort, and column names. - -Outputs are anything a widget visibly produces for the outside world. This can include DOM created, events triggered, callback functions executed, data changed, etc. For example, a grid widget might produce "pageChanged" or "columnSorted" events. - -Let's examine the inputs and outputs of the _MXUI.Data.Grid_ widget. - -@image tutorials/images/inputs_outputs.jpg - -## Anatomy of the List Module - -One of the reusable modules in the Contacts app is List. The List is a simple widget that takes a model, gets and lists data, and listens for updates to the items to update and/or destroy rows. - - $("#category .list_wrapper").mxui_data_list({ - model : Contacts.Models.Category, - show : "//contacts/views/categoryList", - create: "//contacts/views/categoryCreate" - }) - -In this app, the category, location, and company sections are all filters for the contacts grid. Upon clicking one of these rows, the grid is filtered with the selection. These lists are all managed using _MXUI.Data.List_. We'll walk through how this widget works to illustrate creating reusable, self contained modules. - -### Getting the List Data - -When initialized, you pass the List a [jQuery.model model] class. JavaScriptMVC models have a standard API to perform CRUD operations. Every model implements a [jQuery.Model.static.findAll findAll] method, which we can leverage to fetch data. - - this.options.model.findAll(this.options.params, this.callback('list')) - -If you look at the models in _contacts/models_, you'll notice findAll is missing. By default, models will request data using REST standards, as described in [jquery.model.encapsulate Service Encapsulation]. Every model has a findAll method, implemented in the based [jquery.model jQuery.Model] class. - -### Drawing the List - -One of List's parameters is a 'list' template. After the model has completed its _findAll_, we will take its results and draw the UI. - - this.element.html(this.options.list,{ - items : this.options.sort ? items.sort(this.options.sort) : items, - options: this.options - }); - -### Capturing Updates - -In a live application, data changes. The List should be aware of these changes and update its UI accordingly. List listens for updates for its given model and refreshes UI with the latest data. - - "{model} updated" : function(model, ev, item){ - var el = item.elements(this.element).html(this.options.show, item); - if(this.options.updated){ - this.options.updated(this.element, el, item) - } - }, - -In the [contacts.glue Gluing Modules Together] section, we will discuss using this type of observer architecture. - -### Responding to Clicks - -As items are clicked in the list, a "selected" visual state is applied to the item. - - ".item {activateEvent}" : function(el, ev){ - if(el.hasClass("activated")){ - this._deactivate(el) - } else { - var old = this.find(".activated"); - this._deactivate(old); - this._activate(el); - } - }, - _deactivate: function(el){ - el.removeClass("activated"); - el.trigger("deactivate", el.model()); - }, - _activate: function(el){ - el.addClass("activated"); - el.trigger("activate", el.model()); - } - -In the above code, we trigger an _activate_ event. This event is one of List's outputs that we listen to using [jquery.controller.listening event delegation]. As opposed to applications listening for "click" events, we use activate to provide a level of abstraction. This allows the widget to provide other ways to activate a row, such as keyboard navigation or clicking. We could even expand this widget to use touch events for mobile devices, and applications wouldn't have to change. For more information on this you can read the [mvc.controller Controller] documentation. - -The mission of this widget was simple: create a list of data that updates itself as the items change. You and I have probably written this a dozen times in our applications. This List widget provides a reusable API because it has generic and well defined inputs and outputs. - -Next up, we will discuss how to [contacts.glue glue] our isolated modules into a full application. \ No newline at end of file diff --git a/tutorials/examples/contacts/glue.md b/tutorials/examples/contacts/glue.md deleted file mode 100644 index a6480e896..000000000 --- a/tutorials/examples/contacts/glue.md +++ /dev/null @@ -1,108 +0,0 @@ -@page contacts.glue Gluing Modules Together -@parent contacts 2 - -Now that we have learned how to create dumb, lonely, replaceable widgets, we need to glue them together into a smart app. - -## Changes in State - -Events are significant changes in state, and EOA is a pattern that detects and consumes these changes in state. EOA is an elegant way to tie decoupled modules together. - -### Cons of Callback Architecture - -Traditionally widgets accept callbacks. - - $('div').modal({ - closeCallback: windowClosed, - showCallback: windowOpened - }); - -This type of architecture in not desirable for many reasons: - -* The widget should be as dumb as possible. When you pass a callback your widget becomes coupled to its parent widget because it becomes aware of the context in which its used. - -* When you pass callbacks, only one widget can provide that callback. It creates a 1-to-1 architecture, which limits the scalability of the application. - -* Callbacks clutter the API and make it difficult for new developers to learn. - -### Event Oriented Architecture - -Rather than using callbacks, the contacts application uses EOA. One good example is how the grid is filtered from a user clicking an item in a list. - -As items are clicked in the list, it triggers an "activate" event, including the selected row’s model instance in the event. - - el.trigger("activate", el.model()); - -_Pro Tip: Because we bound [jquery.fn.model instances of models using EJS] as shown below, in our controller code we can call .model() on the element that was bound to retrieve the model as shown above._ - - <% for(var i =0 ; i < items.length;i ++){ %> -
          • > - -The contacts widget then observes this state change using event delegation and updates the grid parameters. - - "#category .list_wrapper activate": function(el, ev, item){ - this.params.attr("categoryId", item.id); - } - -The contacts widget listens for events high in the DOM, so it can capture any events triggered by child widgets. - -@image tutorials/images/eoa_diagram1.jpg - - -Grid parameters are a JavaScriptMVC Model instance, used to define common data attributes like limit, offset, and count. The JavascriptMVC Model implements an observer pattern. As changes are made to attributes, widgets can listen for the _updated_ event and react accordingly. - -In the sample code above we call [jquery.model.prototype.attr attr] on this model instance to update the parameters. The grid is listening for changes in the attributes. Above, when activate is triggered, _categoryId_ is changed. The grid observes this change and executes an AJAX request to get data for the current parameter set. - - "{params} updated.attr" : function(params, ev, attr, val){ - if(attr !== 'count'){ - //want to throttle for rapid updates - clearTimeout(this.newRequestTimer,100) - this.newRequestTimer = setTimeout(this.callback('newRequest', attr, val)) - } - }, - - newRequest : function(attr, val){ - var clear = true; - if(!this.options.newPageClears && attr == "offset"){ // if offset changes and we have newPageClears false - clear = false; - } - this.options.model.findAll(this.options.params.attrs(), this.callback('list', clear)) - } - - -@image tutorials/images/eoa_diagram2.jpg - -## Changes in Data - -[jquery.model.events Model events] are events that are fired when CRUD operations (create/update/delete) occur on a model instance. Widgets can bind to these events to automatically update when data changes. - -### Cons of Custom Events - -A common widget communication pattern is triggering custom events when actions are completed. For example, when a user clicks "next page" in a pagination widget, the paginator could trigger "nextPage" and the grid could listen and reload with new data. This is also not desirable because: - -* The widget should be as dumb as possible. If a widget is listening to custom events from child widgets, you are coupling it to the parent widget. We don't want the grid widget depending on a specific "nextPage" event from the paginator, making the paginator not easily replaceable. - -* In some cases, the same state needs to be represented across multiple widgets. The grid, paginator, and possibly other widgets need to know about the current pagination data. Rather than complicate the design by adding unnecessary layers, it makes more sense to maintain this state once (in the model), and let widgets listen to changes in that state. - -### Listening to Model Events - -The List widget provides a good example of binding directly to model updates. - - "{model} updated" : function(model, ev, item){ - var el = item.elements(this.element).html(this.options.show, item); - if(this.options.updated){ - this.options.updated(this.element, el, item) - } - } - -As model changes are made, such as an update to a contact's name, we listen for these changes in the List and update the UI accordingly using [jquery.model.events model events]. - -## Wrap-up - -In this article, we explored: - -* The layers of the contacts application -* How to structure your application into modules, optimizing for widget reuse -* Designing widgets that are modular, testable, and have easy to use APIs -* How to glue your widgets together using event oriented architecture - -If you're interested in other examples, check out the other [examples application examples]. \ No newline at end of file From 4700935668e256a1923958940caa3061da536ece Mon Sep 17 00:00:00 2001 From: Eli Morris-Heft Date: Tue, 28 May 2013 18:21:04 -0400 Subject: [PATCH 31/54] Adding can.util to the docu. --- site/docs.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/site/docs.js b/site/docs.js index d34d006ee..5d6c00f52 100644 --- a/site/docs.js +++ b/site/docs.js @@ -29,4 +29,6 @@ steal('can/construct', 'can/view/modifiers', 'can/view/mustache') +steal('can/util/func.js') + // .then('canui') From a6f4a180f30c993107760c610c4f677b215d1cfc Mon Sep 17 00:00:00 2001 From: Austin McDaniel Date: Tue, 28 May 2013 17:52:12 -0500 Subject: [PATCH 32/54] Adding contacts to examples --- tutorials/examples/contacts.md | 151 ++++++++++++++++++++++++++ tutorials/images/contacts_design.png | Bin 0 -> 99201 bytes tutorials/images/contacts_preview.png | Bin 0 -> 128871 bytes 3 files changed, 151 insertions(+) create mode 100644 tutorials/examples/contacts.md create mode 100644 tutorials/images/contacts_design.png create mode 100644 tutorials/images/contacts_preview.png diff --git a/tutorials/examples/contacts.md b/tutorials/examples/contacts.md new file mode 100644 index 000000000..206fbc825 --- /dev/null +++ b/tutorials/examples/contacts.md @@ -0,0 +1,151 @@ +@page contacts Contacts +@parent examples 3 + +In this article we will walk through installing and the ins-and-outs of Contacts. Contacts is a lightweight application that allows users to add and organize their friends' contact information. + +This tutorial describes: + +- Installing and running the application +- The application's structure and organization +- Dividing the application into modular widgets +- Tieing the widgets together + +@image tutorials/images/contacts_preview.png + +Let's get started! + +## Setup + +The application source is hosted by [GitHub](https://github.com/bitovi/contacts). You can download the application on github using the following commands: + + $ git clone https://github.com/jupiterjs/contacts + $ cd contacts + $ git submodule update --init + +To run the application, open _contacts.html_ with your browser. We will be using [can.fixture fixtures] to simulate the AJAX requests so running it from a server isn’t necessary. + +This will run the application in development mode. If you want to build and run the application in production, in the command line run: + + $ ./js contacts/scripts/build.js + +then change the script tag in `contacts.html` to be in production mode: + + + +Additionally, the app can be found on [Github Pages](http://bitovi.github.io/contacts/) if you do not want to set it up. + +## Folder Structure + +The application resides in the `contacts` folder. Steal, CanJS, and CanUI folders sit perpendicular to this for reuse in other projects. The directory structure should mirror below. + + [top-level] + /can + /steal + /funcunit + /contacts + /form + /scripts + /test + /models + /fixtures + /views + /less + funcunit.html + qunit.html + contacts.js + ... + contacts.html + stealconfig.js + +The contacts folder contains: + +- `models` AJAX end-point definitions and helpers +- `views` EJS/Mustache can.view templates +- `fixtures` simulated AJAX response +- `less` LESS stylesheet such as [Boostrap](http://twitter.github.io/bootstrap/) 3.0 and `contacts.less` +- `contacts/form` child components of contacts + +Along with runners and scripts for building and tests. + +## Division of Modules + +The secret to building large applications is NEVER build large applications. Understanding how to divide and isolate modules in the application is the first step towards maintainable architecture. + +The goal for dividing your application should be to create modules that are isolated. + +Isolated modules are: + +- Limited to one specific purpose, for example showing a list of data +- Rarely reference other modules and never their parents +- Have a simple generic API making them easy to swap out + +Isolated modules are easily testable because they have a small, well defined scope. Each piece can be worked on in parallel because the code is divided. Reuse is easier because the modules are not coupled to each other. + +### Dividing Contacts + +The contacts app has 3 lists that filter the grid of contacts. You can create additional categories and contacts by clicking the 'new' icon. + +This application can be divided up into a few widgets: + +* List - accepts a generic data source and layout, renders and updates the list. +* Grid - accepts a generic data source, renders a grid. +* Form - create a new instance from a data source. + +Heres a visual representation of how this app is broken up into modules. + +@image tutorials/images/contacts_design.png + +## Tieing it all together + +`contacts/contacts.js` will be where the application starts: loading each module, initializing them, and gluing them together. + +In the `init` method, we initalize all the base objects and inject the base view. + + init: function(){ + // initalize the lists and objects + this.categoryList = new Models.Category.List; + this.locationList = new Models.Location.List; + this.companyList = new Models.Company.List; + this.contactsList = new Models.Contact.List; + this.edited = new Observe; + this.total = can.compute(0); + this.isLoading = can.compute(function(loading){ + loading ? loadingCounter++ : loadingCounter--; + return loading > 0; + }); + + // Draw the view, setup helpers and partials + this.element.html(initView({ ... }); + + // Initalize each Form category + can.each(['location', 'category', 'company', 'contact'], function(formType){ + new Form(this.element.find('#' + formType), { + edited : this.edited, + model : Models[can.capitalize(formType)], + list : this[formType + 'List'] + }); + }.bind(this)); + + this.setupScroll(); + this.loadFilters(); + this.loadContacts(); + } + +From this point on, the application uses live-binding to update the lists/views based on the filter/offset. + + {{#contacts}} + {{>contact}} + {{/contacts}} + +As the `contacts` list changes, the view automatically updates to reflect the new list. + +## Wrapup + +In this article, we explored: + +- Installing and running the application +- The application's structure and organization +- Dividing the application into modular widgets +- Tieing the widgets together + +If you're interested in other examples, check out the other application examples. \ No newline at end of file diff --git a/tutorials/images/contacts_design.png b/tutorials/images/contacts_design.png new file mode 100644 index 0000000000000000000000000000000000000000..0aa8eaa74537068dfc91573fc0fd82a14446ad52 GIT binary patch literal 99201 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

            %8Ef^{5K9CUywN;4i8TiUzSJ-C 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 literal 0 HcmV?d00001 From 76f3e5c2124383878bbf5cf6805d379d09e4d107 Mon Sep 17 00:00:00 2001 From: Josh Dean Date: Tue, 28 May 2013 19:25:27 -0400 Subject: [PATCH 33/54] More documentation updates, this time to tutorials. --- tutorials/ajaxy/ajaxy.md | 22 ++- tutorials/funcunit.md | 6 +- tutorials/getstarted/creating.md | 8 +- tutorials/getstarted/documenting.md | 2 + tutorials/getstarted/getstarted.md | 4 +- tutorials/getstarted/testing.md | 9 +- tutorials/installing.md | 24 +-- tutorials/jquerypp.md | 2 +- tutorials/migrate.md | 288 ---------------------------- tutorials/mvc.md | 2 +- tutorials/organizing.md | 4 +- tutorials/rapidstart/rapidstart.md | 22 ++- tutorials/services.md | 2 +- tutorials/steal.md | 4 +- 14 files changed, 64 insertions(+), 335 deletions(-) delete mode 100644 tutorials/migrate.md diff --git a/tutorials/ajaxy/ajaxy.md b/tutorials/ajaxy/ajaxy.md index 92cd372df..2a07d5614 100644 --- a/tutorials/ajaxy/ajaxy.md +++ b/tutorials/ajaxy/ajaxy.md @@ -16,7 +16,7 @@ with the ajaxy/scripts/crawl.js script. The crawl script generates html pages that Google can use as a representation of the content of an Ajax application. Read Google's documentation on its -[https://developers.google.com/webmasters/ajax-crawling/docs/getting-started Ajax crawling API] +[Ajax crawling API](https://developers.google.com/webmasters/ajax-crawling/docs/getting-started) before continuing this tutorial. ## Setup @@ -24,7 +24,7 @@ of the content of an Ajax application. Read Google's documentation on its [installing Download and install] the latest version of JavaScriptMVC. After installing JavaScriptMVC, open a command line to -the [steal.static.root steal.config().root] folder (where you unzipped +the [steal.config.root steal.config.root] folder (where you unzipped JavaScriptMVC). @@ -171,7 +171,7 @@ before the Ajax request. And when the page is ready, Ajaxy calls: ## Getting Google To Crawl Your Site If you haven't already, read up on -Google's [https://developers.google.com/webmasters/ajax-crawling/docs/getting-started Ajax crawling API]. +Google's [Ajax crawling API.](https://developers.google.com/webmasters/ajax-crawling/docs/getting-started) When google wants to crawl your site, it will send a request to your page with \_escaped\_fragment=. @@ -189,10 +189,12 @@ To turn on Phantom: 1. Install it using the install instructions [funcunit.phantomjs here] 1. Open scripts/crawl.js and change the second parameter of steal.html.crawl to an options object with a browser option, like this: - steal('steal/html', function(){ - steal.html.crawl("ajaxy/ajaxy.html", - { - out: 'ajaxy/out', - browser: 'phantomjs' - }) - }) \ No newline at end of file +@codestart +steal('steal/html', function(){ + steal.html.crawl("ajaxy/ajaxy.html", + { + out: 'ajaxy/out', + browser: 'phantomjs' + }) +}) +@codeend \ No newline at end of file diff --git a/tutorials/funcunit.md b/tutorials/funcunit.md index cae978d47..f91c34952 100644 --- a/tutorials/funcunit.md +++ b/tutorials/funcunit.md @@ -1,6 +1,8 @@ @page funcunit.getstarted Get Started with FuncUnit @parent tutorials 6 +@body + In this guide, we'll use [FuncUnit] to write functional tests for the jQuery UI autocomplete widget. We'll go over: @@ -17,7 +19,7 @@ Open _funcunit/test/autosuggest/autosuggest.html_ in a browser. Type "J" in the @image funcunit/pages/images/autosuggest.png -This page is a simple demo app, using jQueryUI [http://jqueryui.com/demos/autocomplete/ autocomplete]. It +This page is a simple demo app, using [jQueryUI autocomplete](http://jqueryui.com/demos/autocomplete/). It shows results when you start typing, then you can click a result (or use mouse navigation) to populate the input. There is a test already written. Open funcunit/test/autosuggest/autosuggest_test.js in your IDE: @@ -39,7 +41,7 @@ test("results appear",function(){ }); @codeend -As you can probably tell, the [s S method] is an alias for jQuery (*). This test: +As you can probably tell, the [funcunit.finding S method] is an alias for jQuery (*). This test: 1. Opens autosuggest.html 1. Grabs the input element, clicks it, and types "Java" diff --git a/tutorials/getstarted/creating.md b/tutorials/getstarted/creating.md index 1930fd1fc..0dda2ae8d 100644 --- a/tutorials/getstarted/creating.md +++ b/tutorials/getstarted/creating.md @@ -1,6 +1,8 @@ @page cookbook.creating Creating Cookbook @parent getstarted 0 +@body + We're going to create a basic cookbook application that lets us create, and delete recipes. It will look like: @@ -56,7 +58,7 @@ page followed by `?cookbook` like: src='../path/to/steal/steal.js?cookbook'> -If you open [//cookbook/index.html], you'll see a +If you open //cookbook/index.html, you'll see a JavaScriptMVC welcome screen. @image tutorials/getstarted/Welcome.png @@ -280,7 +282,7 @@ where fixtures come in. ### The Recipe Fixture -[can.fixture Fixtures] intercept Ajax requests and +[can.fixture Fixtures] intercept AJAX requests and simulate the response. They enable you to start work on the front end without a ready server. @@ -429,7 +431,7 @@ the inner html of the `controls` element: <% }) %> In the template, `this` is `this.list`. `this.list` is initially empty so -the inner html of `this.element` is empty. The [can.Observe.List::replace list.replace](items) +the inner html of `this.element` is empty. The [can.Observe.List.prototype.replace replace] method replaces the contents of the list with `items`. If `items` is a [can.deferred deferred], it replaces the contents of the list with the resolved value of the deferred. diff --git a/tutorials/getstarted/documenting.md b/tutorials/getstarted/documenting.md index c4380e3ff..e5dd98762 100644 --- a/tutorials/getstarted/documenting.md +++ b/tutorials/getstarted/documenting.md @@ -1,6 +1,8 @@ @page cookbook.documenting Documenting Cookbook @parent getstarted 3 +@body + Documentation is a critical step in creating maintainable code. It's often burdensome on developers and becomes neglected. JavaScriptMVC's integrates [DocumentJS] to make diff --git a/tutorials/getstarted/getstarted.md b/tutorials/getstarted/getstarted.md index b019d1792..5b97e775f 100644 --- a/tutorials/getstarted/getstarted.md +++ b/tutorials/getstarted/getstarted.md @@ -61,8 +61,8 @@ P.S. steal('can/control') adds can/control/control.js JavaScriptMVC is MIT with the following exceptions: - - [http://www.mozilla.org/rhino/ Rhino] - JS command line ([http://www.mozilla.org/MPL/ MPL] 1.1) - - [http://seleniumhq.org/ Selenium] - Browser Automation ([http://www.apache.org/licenses/LICENSE-2.0 Apache 2]) + - [Rhino](http://www.mozilla.org/rhino/) - JS command line ([MPL 1.1](http://www.mozilla.org/MPL/)) + - [Selenium](http://seleniumhq.org/) - Browser Automation ([Apache 2](http://www.apache.org/licenses/LICENSE-2.0)) These exceptions, although permissive licenses themselves, are not linked in your final production build. diff --git a/tutorials/getstarted/testing.md b/tutorials/getstarted/testing.md index 9c2c1982a..fc6aa2c02 100644 --- a/tutorials/getstarted/testing.md +++ b/tutorials/getstarted/testing.md @@ -1,6 +1,8 @@ @page cookbook.testing Testing Cookbook @parent getstarted 1 +@body + JavaScriptMVC puts a tremendous emphasis on testing. It uses [FuncUnit] to easily write tests that can be run in the browser or automated. FuncUnit @@ -25,15 +27,16 @@ Open cookbook_test.js. You'll notice it steals tests for the model and controls are also tests that verify the original "Welcome to JavaScriptMVC" text that we removed. Remove the extraneous tests so `cookbook_test.js` just looks like this: +@codestart steal( 'funcunit', './models/recipe_test.js', 'cookbook/recipe/create/create_test.js', 'cookbook/recipe/list/list_test.js'); +@codeend To run all of __cookbook's__ tests, open -`cookbook/test.html` in a browser. You should -see something like [//cookbook/test.html this]. +`cookbook/test.html` in a browser. To run those same tests with [funcunit.selenium Selenium], first you must set up a local server, like Apache, running at the javascriptmvc root. Make sure you can @@ -60,7 +63,7 @@ this code works. If an application should be built of small, isolated modules that are glued together, its tests should reflect that. -Cookbook's modules are each designed to be built and tested independently. For example, the `cookbook/recipe/create` module has its own tests and test page. Open [//cookbook/recipe/create/test.html cookbook/recipe/create/test.html] +Cookbook's modules are each designed to be built and tested independently. For example, the `cookbook/recipe/create` module has its own tests and test page. Open `cookbook/recipe/create/test.html` and it will run the tests in `cookbook/recipe/create/create_test.js`. To test the "glue", `cookbook_test.js` loads all modules' tests diff --git a/tutorials/installing.md b/tutorials/installing.md index 0a68d9c50..64ce8bf11 100644 --- a/tutorials/installing.md +++ b/tutorials/installing.md @@ -3,26 +3,26 @@ ## Requirements -JavaScriptMVC requires [http://www.oracle.com/technetwork/java/javase/downloads/java-se-jdk-7-download-432154.html Java JRE 1.6] or greater for: +JavaScriptMVC requires [Java JRE 1.6](http://www.oracle.com/technetwork/java/javase/downloads/java-se-jdk-7-download-432154.html) or greater for: - Compression (Google Closure) - - Running [http://www.funcunit.com/ FuncUnit] tests with [http://seleniumhq.org/ Selenium] + - Running [FuncUnit](http://www.funcunit.com/) tests with [Selenium](http://seleniumhq.org/) - Easy updating - Code Generators But your backend server can be written in any language. -Download the latest [http://www.java.com/en/download/index.jsp Java JRE here]. +Download the latest [Java JRE here](http://www.java.com/en/download/index.jsp). ## Getting JavaScriptMVC There are 2 ways to get JavaScriptMVC: - - [http://javascriptmvc.com/builder.html Downloading] + - [Downloading](http://javascriptmvc.com/builder.html) - [developwithgit Installing JavaScriptMVC with Git] ## Downloading -[http://javascriptmvc.com/builder.html Download] the latest JavaScriptMVC. +[Download](http://javascriptmvc.com/builder.html) the latest JavaScriptMVC. Unzip the folder on your file system or web server. If you are using this on a webserver, unzip in a public folder where the server hosts static content. @@ -37,12 +37,12 @@ unzip in a public folder where the server hosts static content. JavaScriptMVC is comprised of six sub projects: - - [http://github.com/bitovi/steal] - - [https://github.com/bitovi/canjs] - - [https://github.com/bitovi/canui] - - [https://github.com/bitovi/jquerypp] - - [http://github.com/bitovi/documentjs] - - [http://github.com/bitovi/funcunit] + - [http://github.com/bitovi/steal](http://github.com/bitovi/steal) + - [https://github.com/bitovi/canjs](https://github.com/bitovi/canjs) + - [https://github.com/bitovi/canui](https://github.com/bitovi/canui) + - [https://github.com/bitovi/jquerypp](https://github.com/bitovi/jquerypp) + - [http://github.com/bitovi/documentjs](http://github.com/bitovi/documentjs) + - [http://github.com/bitovi/funcunit](http://github.com/bitovi/funcunit) You want to fork each project and add it as a submodule to your project in a public folder (where your server keeps static content). @@ -97,5 +97,5 @@ Open a command line to that folder and run: [Lin/Mac] > ./js @codeend -This starts the [http://www.mozilla.org/rhino/ Rhino JS engine]. Type quit() to exit. +This starts the [Rhino JS engine](http://www.mozilla.org/rhino/). Type quit() to exit. diff --git a/tutorials/jquerypp.md b/tutorials/jquerypp.md index 84cd563aa..ac2210f54 100644 --- a/tutorials/jquerypp.md +++ b/tutorials/jquerypp.md @@ -7,6 +7,6 @@ jQuery applications. It provides low-level utilities for things that jQuery doesn’t support. You can find out everything you need to know about jQuery++ -[http://jquerypp.com at its site.] jQuery++ is included with +[at its site.](http://jquerypp.com) jQuery++ is included with JavaScriptMVC by default in the jquery folder in the root of your project. \ No newline at end of file diff --git a/tutorials/migrate.md b/tutorials/migrate.md deleted file mode 100644 index 55ec32b48..000000000 --- a/tutorials/migrate.md +++ /dev/null @@ -1,288 +0,0 @@ -@page migrate Upgrading to 3.2 -@parent tutorials 10 - -There are many new feature in JavaScriptMVC 3.2 that help you build great JavaScript applications. -Although 3.2 is not strictly backwards compatible it is possible to upgrade from -and earlier version. This guide outlines the things you have to look at when upgrading from -version 3.0 or 3.1. - -## Steal - -[stealjs | Steal] has experienced a major improvement, making it even easier to manage your dependencies. -Instead of defining what you want to steal like _steal.plugins_, _steal.controllers_ or _steal.views_ you -just steal the file and Steal will figure out what to do with it based on the extension. -So if your code used to look like this: - - steal('helper').plugins('jquery/controller', 'jquery/view/ejs', 'jquery/controller/view').views('init.ejs') - .css('style').then(function($) { - $.Controller('Test.Controller', {}, { - init : function(el, ops) - { - this.element.html(this.view()); - } - }); - }); - -The new Steal looks like this: - - steal('./helper.js', 'jquery/controller', 'jquery/view/ejs', './views/init.ejs', './style.css', function($) { - $.Controller('Test.Controller', {}, { - init : function(el, ops) - { - this.element.html(this.view()); - } - }); - }); - -The rules when stealing a file: - -* ./ refers to the path of the current file -* When stealing something without extension like _jquery/controller_ Steal will first look for the plugin -file _jquery/controller/controller.js_ and if not found _jquery/controller.js_ based on your applications -root path -* ./helper.js loads helper.js in the folder of the current file -* ./views/init.ejs loads the init.ejs [jQuery.EJS | EJS view] from views subfolder in the current folder -* ./style.css loads the style.css file in the current folder - -Note that the new Steal runs asynchronously so you might have to be more careful using _steal.then()_ -if there are dependencies that have to be loaded before another. This is also important when putting code -outside of steal. Because jQuery hasn't been loaded you can not use the jQuery object. So instead of -$(document).ready use this: - - steal.then(function() { - $('body').my_plugin(); - }); - - -## Organizing your application - -Starting with version 3.1 and fully encouraged in 3.2 JavaScriptMVC follows a new approach in organizing your application structure. -Read the complete guide on [organizing | organizing your app] to get an idea. For migrating from the old structure -the following things are important: - -* The use of the _controllers_ folder is discouraged. You still can use it but organizing each controller in -their own folder with a views subfolder is the preferred way as it is a lot more obvious how your application -is split up and easier to test. -* Models reside in their own folder as they might be application wide and not controller specific -(e.g. a recipe model will be used in a recipe\_edit and a recipe\_list controller) - - -## Document controllers - -There are no document controllers in 3.2 anymore (controllers that used have the default option _{ onDocument : true }_). -Instead initialize your controllers like any [jquery.controller.plugin | jQuery plugin] in the application file. -For document wide controllers initialize them on the document itself. -An example how your main application file may look like: - - steal('my/controller', 'my/global/controller', function($) { - $(document).ready(function($) { - $(document).global_controller(); - $('.thing').my_controlller(); - }); - }); - -Note that unlike the old document controllers a global controller will not listen to a specific id. - -## Listening to model changes - -The notifications via OpenAJAX have been dropped in favor of the [jQuery.Observe Observable] mechanism. -Check out the documentation on [jquery.model.events | Model events] for detailed information on how use it for Models. - -## Controller History - -Controller history using OpenAjax has been removed in 3.2. Use [jQuery.route] for full history and routing support. - -## Wrap Removed - -The AJAX response converter 'wrap' and 'wrapMany' have been removed in favor of a [native jQuery converter http://api.jquery.com/extending-ajax/#Converters]. - -Before, you would do a _this.callback_ on the success like: - - findAll : function(params, success, error ){ - return $.ajax({ - url: '/services/recipes.json', - type: 'get', - data: params - dataType : 'json', - success: this.callback(['wrapMany',success]) - }); - } - -now becomes: - - findAll : function(params, success, error ){ - return $.ajax({ - url: '/services/recipes.json', - type: 'get', - data: params - dataType : 'json recipe.models', - success: success - }); - } - -## Callback Renamed to Proxy - -The _this.callback_ method has been deprecated and the preferred method is now _this.proxy_. - -## steal.browser.rhino removed - -The _steal.browser.rhino_ has been removed. We are using _steal.browsers_ namespace for the browser drivers. If you were using this to have rhino skip files in the build process, you can now use: _steal.isRhino_. - -## Associations - -Associations were removed in favor of [jQuery.Model.static.attributes]. Attribute type values can also represent the name of a function which is used is for associated data now. - -## Upgrade Process and Advice - -The changes listed above require significant adaptation of your code base. - -1) The word 'controllers' is no longer good for JMVC. If you have controllers in a directory of that name, change the name to something else. JMVC has new, automatic behavior that will break your system if you don't. - -Controller names must also be changed to the new directory name. Eg, - - jQuery.Controller.extend('Appname.Controllers.Controllername') - -becomes - - jQuery.Controller.extend('Appname.NewName.Controllername') - -and, the instantiation, - - appname_controllers_controllername() - -becomes - - appname_newname_controllername() - -2) The suffix "_controller" is no longer valid. Remove it from your controller names. - -3) Steal() has changed completely. It no longer has specific methods for different kinds of files. Eg, - - steal.plugins( - 'jquery/controller', - 'jquery/controller/view' - ) - -Becomes - - steal( - 'jquery/controller', - 'jquery/controller/view' - ) - -As do all the rest of the type-specific loaders: .resources(), .models(), .controllers(), .views() & .css() - -4) The base directory steal() looks in has changed. Instead of referring to the directory containing the steal() build file, it refers to the directory containing the *call*, ie, if you have - - foo/index.html containing +steal('jquery', + 'can/construct/proxy', + 'can/control', + 'can/route', + 'steal/html', + function($, can){ + +var Ajaxy = can.Control({ + "{route} change" : function(route, ev){ + this.updateContent(route.page) + }, + updateContent : function(hash){ + // postpone reading the html + steal.html.wait(); + + $.get("fixtures/" + hash + ".html", {}, this.proxy('replaceContent'), "text") + }, + replaceContent : function(html){ + this.element.html(html); + // indicate the html is ready to be crawled + steal.html.ready(); + } +}) + +new Ajaxy('#content', { + route: can.route(":page", { page: "videos" }) }); +}); + \ No newline at end of file diff --git a/tutorials/done.md b/tutorials/done.md index 8ea3dc631..720effd94 100644 --- a/tutorials/done.md +++ b/tutorials/done.md @@ -3,9 +3,13 @@ JavaScriptMVC 3.3 introduces a lot of new features to build large and responsive applications. As such, there are a few changes from 3.2 and this guide walks through the API differences between the versions. +## CanJS + +[canjs Can] has replaced the previous MVC internals of JavaScript MVC, but provides backwards compatability to jQuery MX. jQuery MX $.Class, $.Model, and $.Controller will not be supported in future versions, and we urge you to switch to using can. + ## Steal -[stealjs | Steal] in 3.3 has support for AMD modules. Steal will still load resources as 3.2, however will also now follow the pattern for dependencies represented by a string id. +[stealjs Steal] in 3.3 has support for AMD modules. Steal will still load resources as 3.2, however will also now follow the pattern for dependencies represented by a string id. So, as a simple example: diff --git a/tutorials/examples/contacts.md b/tutorials/examples/contacts.md index 206fbc825..dfb196551 100644 --- a/tutorials/examples/contacts.md +++ b/tutorials/examples/contacts.md @@ -95,7 +95,7 @@ Heres a visual representation of how this app is broken up into modules. @image tutorials/images/contacts_design.png -## Tieing it all together +## Tying it all together `contacts/contacts.js` will be where the application starts: loading each module, initializing them, and gluing them together. @@ -118,7 +118,8 @@ In the `init` method, we initalize all the base objects and inject the base view this.element.html(initView({ ... }); // Initalize each Form category - can.each(['location', 'category', 'company', 'contact'], function(formType){ + can.each(['location', 'category', + 'company', 'contact'], function(formType){ new Form(this.element.find('#' + formType), { edited : this.edited, model : Models[can.capitalize(formType)], diff --git a/tutorials/examples/playermx.md b/tutorials/examples/playermx.md deleted file mode 100644 index d1e21bac9..000000000 --- a/tutorials/examples/playermx.md +++ /dev/null @@ -1,243 +0,0 @@ -@page playermx PlayerMX -@parent examples 1 - -This article walks through a simple video player application utilizing Popcorn.js. We'll cover: - - - Setting up the application - - Templated events with [can.Control] - - How PlayerMX is built - -## Setup - -There's two options to install PlayerMX: getjs or using git. - -### Download with getjs - -After downloading and [installing installing JavaScriptMVC], run the following command: - -`./js steal/getjs player` - -_Note: When running the getjs command, be sure to navigate to your [rootfolder JavaScriptMVC root folder]._ - -### Github - -From a directory of your choice: - -_Clone files to your local drive_ -`$ git clone https://github.com/jupiterjs/playermx.git` - -_Navigate to application directory and initialize submodules_ -`$ cd playermx -$ git submodule update --init` - -### Running - -Open player/player.html in your browser and see the application run: - -@image tutorials/images/playermx.png - -_Note: Safari and Chrome currently support the mp4 codec, however Firefox requires the h.264 Flash player to process mp4's._ - -You can see our version running here: [http://javascriptmvc.com/player/player.html](http://javascriptmvc.com/player/player.html) - -Repo: [https://github.com/jupiterjs/playermx](https://github.com/jupiterjs/playermx) - -## PopcornJS Overview - -Repo: [https://github.com/cadecairos/popcorn-js](https://github.com/cadecairos/popcorn-js) - -> _Popcorn.js is an event framework for HTML5 media. Popcorn.js utilizes the native HTMLMediaElement properties, -methods and events, normalizes them into an easy to learn API and provides a plugin system for community contributed interactions._ - -> _[Source: http://popcornjs.org/documentation](http://popcornjs.org/documentation)_ - -Popcorn.js wraps up our mp4 file into a `video` object which we can pass to our widgets. -Our widgets can then play and pause the video based on user interaction. The Popcorn.js API we'll be using is: - -* Events: - * play - triggered when video plays - * pause - triggered when a video is paused - * timeupdate - triggered continuously during video playback -* Properties: - * paused - boolean, true if the video is paused -* Methods: - * play() - begins playing video, triggers "play" event - * pause() - pauses video, triggers "pause" event - * currentTime() - gets the current playback position in milliseconds - * duration() - gets length of the video in milliseconds - -## Templated Events Overview - -PlayerMX introduces the concept of binding events to JavaScript objects other than DOM elements. -This application uses the event syntax: `{myObject} click`, where `myObject` is the object and `click` is the event we're listening to. -This is what we call templated events. - -Templated events create a simple way to bind events without concern for cleanup. -For example, binding an event to a DOM element with $.bind(), will be removed when you call $.remove() on that element. -However, if you want to listen to events on a model, templated events handle the unbinding for you. -In essence, memory concerns are reduced with templated events. - -Specifically with PlayerMX, our widgets listen to events produced by our Popcorn video element. -If that element is removed from our page, by using templated events, we don't need to worry about cleaning up bound methods. - -## PlayerMX Architecture - -Once you've downloaded the application, you'll notice 3 folders within your `playermx` directory. -A few notes on the directory structure of this application: - -* The `can` folder refers to [CanJS](https://github.com/jupiterjs/canjs). -This is the CanJS core and what we'll be building our application on. -* The `jquery` folder refers to [jQuery++](https://github.com/jupiterjs/jquerypp). -This adds useful events like [resize jQuery.event.resize] and [jQuery.event.drag drag] which will be used in the player. -* The [steal](https://github.com/jupiterjs/steal) folder is our dependency management system. -This is how we include other resources such as scripts, stylesheets, templates or other JavaScriptMVC resources and apps altogether. -* The `player` folder is where we'll place our focus as this is the main directory for our application. - -The application is broken up into one main application page, `player.html`, with a corresponding script, -`player.js` and two corresponding widgets. - -@image tutorials/images/playermx_overview.png - -### player.js - -`Player.js` is our main application script. `Steal` loads the widgets we want, and then we initialize them. -This loosely couples our widgets from our application. The variable `video` is our reference to the Popcorn.js wrapped object. -`play` and `player_position` accept this object as a parameter. - - steal('./play.js', - './position.js', - - function() { - var video = Popcorn("#trailer"); - - new Play('#play', { video: video }); - new PlayerPosition('#position', { video: video }); - }); - -The first line of `player.js` is our call to `steal`. This is going to load all our dependencies. -In this case, we load `play.js` and `position.js`, then execute a function. - -### play.js - -@image tutorials/images/playermx_play.png - - - steal('player/popcorn', - 'can/control', - - function() { - -The purpose of this widget is to control the video playback. Listening to the `play` and `pause` events on the Popcorn.js object, -we'll add a CSS class designating playback state. - -Our widget will be created using `$.Controller`. By naming our controller "play", we have now have a `jQuery.fn.play()` method. -`init` is the constructor method for our controller. Any passed parameters are accessible via `options` on the controller. - - can.Control('Play', { - init : function(){ - if( this.options.video.video.paused ) { - this.element.text("play") - } else { - this.element.text("stop") - } - }, - -Within player.js, we've passed a video object to our controller. -Using templated events, we can listen to the events directly on this object. -Templated events allow listening to events on any object, not just DOM events. -In the code below, "{video}" refers to our object and "play" is the event we'll listen for. - - "{video} play" : function() { - this.element.text("stop").addClass('stop') - }, - - "{video} pause" : function() { - this.element.text("play").removeClass('stop') - }, - -We'll listen to clicks within the parent element and call the play/pause methods, depending on current state. -The separation of the click handler and the play/pause handlers is for extensibility. -We may have multiple widgets that control the playback of our video and each widget should be able to respond accordingly. - - click : function() { - if( this.options.video.video.paused ) { - this.options.video.play() - } else { - this.options.video.pause() - } - } - }); - }); - -### position.js - -@image tutorials/images/playermx_position.png - - - steal('player/popcorn', - 'can/control', - 'jquery/dom/dimensions', - 'jquery/event/resize', - 'jquery/event/drag/limit', - -The PlayerPosition widget shows a progression bar for our video. This should not only display playback position, but be draggable as well -`this` in the following context refers to our widget instance. Our progress indicator will be accessible via the `moving` property. -A simple div will suffice for this example and we'll set some basic css properties such as position and dimensions. - - function() { - can.Control('PlayerPosition', { - init : function(){ - this.moving = $("

            ").css({ - position: 'absolute', - left: "0px" - }) - - this.element.css("position","relative") - .append(this.moving); - - this.moving.outerWidth( this.element.height() ); - this.moving.outerHeight( this.element.height() ); - - }, - -The widget listens to the Popcorn.js `timeupdate` event on our video model to recalculate our indicator position. -We've separated the event listener from the resize method to allow for any other widgets that may be listening to `timeupdate`. - - "{video} timeupdate" : function(video){ - this.resize() - }, - resize : function(){ - var video = this.options.video, - percent = video.currentTime() / video.duration(), - width = this.element.width() - this.moving.outerWidth(); - - this.moving.css("left", percent*width+"px") - }, - -_Note: `draginit` and `dragend` are a couple of events provided by [jQuery++ jquerypp]. [jQuery.Drag jQuery.Drag]_ - -The drag events are scoped to the indicator div element. -We can now call the Popcorn.js `play` and `pause` methods, trusting other widgets to respond as needed. In this app, these events will get picked up by our 'Play' widget to start/stop the playback. - - "div draginit" : function(el, ev, drag){ - this.options.video.pause() - drag.limit(this.element) - }, - "div dragend" : function(el, ev, drag){ - var video = this.options.video, - width = this.element.width() - this.moving.outerWidth() - percent = parseInt(this.moving.css("left"), 10) / width; - - video.currentTime( percent * video.duration() ); - video.play() - } - }); - }); - -## Conclusion - -The secret to building large applications is to never build large applications. - -Applications can quickly become overwhelming, complex and difficult to maintain. -The takeaway from the PlayerMX architecture is to create isolated, dumb widgets that can be tied together with events. -This article is an example of how to loosely couple your widgets, use templated events and integrate with an API (Popcorn.js). diff --git a/tutorials/examples/todo.md b/tutorials/examples/todo.md index 66eb4c3ac..63e5f02eb 100644 --- a/tutorials/examples/todo.md +++ b/tutorials/examples/todo.md @@ -62,8 +62,8 @@ The diagram below shows how we've broken our application out into model, view, a If you look at `todo.js` the first thing you'll notice is that all the code is wrapped in a call to the `steal` function: - steal('can/model', 'can/control', 'can/view/ejs', 'jquery/lang/json') - .then('./todo.css') + steal('todo/models/todo.js', 'todo/controls/todos', + './todo.less') In fact, this is true of every JavaScript file in a JavaScriptMVC application: we use `steal` to state our dependencies up-front, which tells the framework what libraries, plugins, stylesheets, etc. we need to load before we can begin. Typically, the final argument to `steal` will be a callback function, which will be executed when all the other dependencies (and _their_ dependencies, and so on...) have been loaded and executed as well. No more worrying whether you forgot any ` +

            {{staticLocation}}

            + + + + From 71989a1307653a997dfd82d3a75e1fd3bc4e13ad Mon Sep 17 00:00:00 2001 From: Eli Morris-Heft Date: Wed, 24 Jul 2013 10:37:13 -0500 Subject: [PATCH 53/54] Updating can to 1.1.7. --- can | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can b/can index 9b6c80d7e..1a46211f4 160000 --- a/can +++ b/can @@ -1 +1 @@ -Subproject commit 9b6c80d7e97f0aef1ab67f188910f26bc6e6413c +Subproject commit 1a46211f419ad39e10be11220ce723be1485112a From ce0280bb401b5d316086b4bbf3a962349bd6de04 Mon Sep 17 00:00:00 2001 From: Eli Morris-Heft Date: Wed, 24 Jul 2013 11:22:16 -0500 Subject: [PATCH 54/54] Updating jQuery++. --- jquerypp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jquerypp b/jquerypp index 7101b15ee..ad61dbb27 160000 --- a/jquerypp +++ b/jquerypp @@ -1 +1 @@ -Subproject commit 7101b15ee14944f781c8c3921710cc2dfb7b7403 +Subproject commit ad61dbb276cdc735f5a745132898deb17108059c