├── .gitignore
├── .gitmodules
├── Gruntfile.js
├── build
├── changelog.ejs
├── tasks
│ ├── bannerize.js
│ ├── beautify.js
│ ├── build.js
│ ├── changelog.js
│ ├── docco.js
│ ├── testify.js
│ └── updateversion.js
└── underscore.js
├── changelog.md
├── js
├── js.bat
├── license.md
├── package.json
├── readme.md
├── scripts
├── getjmvc
└── getjmvc.bat
├── site
├── blog.html
├── builder.html
├── code.html
├── contribute.html
├── docs.html
├── docs.js
├── follow.html
├── fonts
│ ├── museo_slab_500-webfont.eot
│ ├── museo_slab_500-webfont.svg
│ ├── museo_slab_500-webfont.ttf
│ ├── museo_slab_500-webfont.woff
│ └── museoslab.css
├── images
│ ├── add_tag_example.png
│ ├── backgrounds
│ │ ├── body.png
│ │ ├── bottom.png
│ │ ├── calendar.png
│ │ ├── download
│ │ │ ├── documentjs.png
│ │ │ ├── funcunit.png
│ │ │ ├── javascriptmvc.png
│ │ │ ├── jquerymx.png
│ │ │ ├── stealjs.png
│ │ │ └── syn.png
│ │ ├── greenbox.png
│ │ ├── link_hover.png
│ │ ├── navigation.png
│ │ └── quote.png
│ ├── coverage_commandline.png
│ ├── coverage_file.png
│ ├── coverage_report.png
│ ├── crm_doc_demo_1.png
│ ├── crm_doc_demo_2.png
│ ├── follow_twitter.png
│ ├── fork.png
│ ├── funcunit.png
│ ├── funcunit_medium.png
│ ├── funcunit_small.png
│ ├── funcunitfolder.png
│ ├── funcunithtml.png
│ ├── header.png
│ ├── iepopups.png
│ ├── iesecurity.png
│ ├── logo.png
│ ├── page_type_example.png
│ ├── parent_tag_example.png
│ ├── phui.png
│ ├── plugin_tag_example.png
│ ├── return_tag_example.png
│ ├── rss.png
│ ├── tag_tag_example.png
│ ├── team
│ │ ├── brian.png
│ │ ├── joe.png
│ │ ├── justin.png
│ │ ├── lee.png
│ │ ├── matt.png
│ │ ├── max.png
│ │ ├── michael.png
│ │ └── trey.png
│ ├── test_cookbook_example.png
│ ├── test_tag_example.png
│ └── test_tag_test_example.png
├── pages
│ ├── developingjmvc.md
│ ├── developingwithgit.md
│ ├── folders.md
│ ├── help.md
│ ├── learn.js
│ └── why.js
├── scripts
│ ├── build.html
│ ├── build.js
│ ├── clean.js
│ ├── compress.js
│ ├── crawl.js
│ ├── doc.html
│ └── doc.js
├── site.js
├── static
│ └── styles
│ │ └── config.less
├── stylesheets
│ ├── application.css
│ ├── builder.css
│ ├── reset.css
│ └── site.less
├── summary.ejs
├── templates
│ └── layout.mustache
└── views
│ └── blog.ejs
├── stealconfig.js
├── test
├── run.js
├── scripts
│ ├── big_test.js
│ └── getting_started_test.js
└── test.js
└── tutorials
├── ajaxy
├── ajaxy.html
├── ajaxy.md
└── fixtures
│ ├── articles.html
│ ├── images.html
│ └── videos.html
├── cms.png
├── done.md
├── examples.md
├── examples
├── contacts.md
├── srchr.md
├── todo.html
└── todo.md
├── funcunit.md
├── getstarted
├── Cookbook.png
├── Docs.png
├── Welcome.png
├── building.md
├── creating.md
├── documenting.md
├── getstarted.md
├── selenium-run.png
└── testing.md
├── images
├── .DS_Store
├── app_organization.png
├── app_scaffold.png
├── contacts_design.png
├── contacts_preview.jpg
├── contacts_preview.png
├── contacts_widgets.jpg
├── coverage1.png
├── coverage2.png
├── diagram.gif
├── diagram.png
├── diagram_search.png
├── diagram_tabs.png
├── eoa_diagram1.jpg
├── eoa_diagram2.jpg
├── inputs_outputs.jpg
├── playermx.png
├── playermx_overview.png
├── playermx_play.png
├── playermx_position.png
├── tabs.png
├── todo_arch.png
└── todos.png
├── installing.md
├── jquerypp.md
├── mvc.md
├── organizing.md
├── rapidstart
├── rapidstart.md
├── test.html
├── todos.ejs
├── todos.html
├── todos.js
└── todos_test.js
├── rootfolder.md
├── services.md
└── tutorials.md
/.gitignore:
--------------------------------------------------------------------------------
1 | docs/*
2 | .tmp*
3 | cookbook*
4 | site/docs/*
5 | scripts/key
6 | .DS_Store
7 | html/
8 | selenium.log
9 | packages/*
10 | tmp*
11 | node_modules
12 | npm-debug.log
13 | backbone
14 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "can"]
2 | path = can
3 | url = git://github.com/bitovi/canjs.git
4 | [submodule "documentjs"]
5 | path = documentjs
6 | url = git://github.com/bitovi/documentjs.git
7 | [submodule "jquerypp"]
8 | path = jquerypp
9 | url = https://github.com/bitovi/jquerypp.git
10 | [submodule "jmvc"]
11 | path = jmvc
12 | url = git://github.com/bitovi/jmvc-generators
13 | [submodule "funcunit"]
14 | path = funcunit
15 | url = git://github.com/bitovi/legacy-funcunit.git
16 | [submodule "steal"]
17 | path = steal
18 | url = git://github.com/bitovi/legacy-steal.git
19 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 |
3 | grunt.loadNpmTasks('grunt-contrib-connect');
4 |
5 | grunt.initConfig({
6 | connect: {
7 | server: {
8 | options: {
9 | port: 8000,
10 | base: '.',
11 | keepalive: true
12 | }
13 | }
14 | }
15 | })
16 |
17 | grunt.registerTask("server", "connect:server")
18 | };
--------------------------------------------------------------------------------
/build/changelog.ejs:
--------------------------------------------------------------------------------
1 | __<%= version %>__ ( <%= date.toDateString().substring(4) %> )
2 | <% for(var i = 0; i < issues.length; i++) { %>
3 | - change: [<%= issues[i].title %>](<%= issues[i].url %>)<% } %>
4 |
5 |
--------------------------------------------------------------------------------
/build/tasks/bannerize.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | // A grunt task that writes the banner to every file
4 | module.exports = function (grunt) {
5 | grunt.registerMultiTask('bannerize', 'Adds the banner to a set of files', function () {
6 | var options = grunt.config.process(['bannerize', this.target]);
7 | var banner = this.data.banner;
8 |
9 | grunt.file.expand(this.data.files).forEach(function (file) {
10 | var outFile = options.out ? path.join(options.out, path.basename(file)) : file;
11 |
12 | grunt.log.writeln('Adding banner to ' + file);
13 | grunt.file.write(outFile, banner + grunt.file.read(file));
14 | });
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/build/tasks/beautify.js:
--------------------------------------------------------------------------------
1 | /*
2 | * grunt-beautify.git
3 | * https://github.com/pix/grunt-beautify
4 | *
5 | * Copyright (c) 2012 Camille Moncelier
6 | * Licensed under the MIT license.
7 | */
8 | var beautifier = require('js-beautify');
9 |
10 | module.exports = function (grunt) {
11 |
12 | // Please see the grunt documentation for more information regarding task and
13 | // helper creation: https://github.com/cowboy/grunt/blob/master/docs/toc.md
14 | // ==========================================================================
15 | // TASKS
16 | // ==========================================================================a
17 | var default_options = {
18 | indentSize : 2
19 | };
20 |
21 | grunt.registerMultiTask('beautify', 'Javascript beautifier', function () {
22 | var options = null;
23 | var tmp = grunt.config(['beautifier', this.target, 'options']);
24 | if (typeof tmp === 'object') {
25 | grunt.verbose.writeln('Using "' + this.target + '" beautifier options.');
26 | options = tmp;
27 | } else {
28 | tmp = grunt.config('beautifier.options');
29 | if (typeof tmp === 'object') {
30 | grunt.verbose.writeln('Using master beautifier options.');
31 | options = tmp;
32 | } else {
33 | grunt.verbose.writeln('Using beautifier default options.');
34 | options = default_options;
35 | }
36 | }
37 |
38 | // Beautify specified files.
39 | var excludes = grunt.config(['beautifier', this.target, 'exclude']);
40 |
41 | grunt.file.expand(this.filesSrc).filter(function (file) {
42 | if(/\.min\./.test(file)) {
43 | grunt.log.writeln('Not beautifying ' + file);
44 | return false;
45 | }
46 |
47 | for (var i = 0; i < excludes.length; i++) {
48 | if (excludes[i].test(file)) {
49 | grunt.log.writeln('Not beautifying ' + file);
50 | return false;
51 | }
52 | }
53 | return true;
54 | }).forEach(function (filepath) {
55 | grunt.log.writeln('Beautifying ' + filepath);
56 | var result = beautifier(grunt.file.read(filepath), options);
57 | grunt.file.write(filepath, result);
58 | });
59 |
60 | });
61 |
62 | };
--------------------------------------------------------------------------------
/build/tasks/build.js:
--------------------------------------------------------------------------------
1 | var path = require("path");
2 | var jsDir = path.join( __dirname, "../..");
3 |
4 | module.exports = function( grunt ) {
5 | grunt.registerMultiTask('build', 'Runs build files.', function() {
6 | var done = this.async();
7 | var target = this.target;
8 |
9 | var options = grunt.config.process(['build', target]);
10 | var args = [this.data.src, this.data.out || 'dist/', this.data.version || 'edge'];
11 | var libraries = Array.isArray(this.data.libraries) ? this.data.libraries : [];
12 |
13 | args.push.apply(args, libraries);
14 |
15 | grunt.verbose.writeflags(this.data, 'Options');
16 | grunt.log.writeln('Running ./js ' + args.join(' '));
17 |
18 | grunt.util.spawn({
19 | cmd : "./js",
20 | args : args,
21 | opts : {
22 | cwd: jsDir
23 | }
24 | }, function(error, result, code) {
25 | grunt.log.writeln('Done building');
26 | done();
27 | });
28 |
29 | grunt.log.write("Building " + this.data.src + " with Steal...\n");
30 | });
31 | };
32 |
--------------------------------------------------------------------------------
/build/tasks/changelog.js:
--------------------------------------------------------------------------------
1 | var https = require('https'),
2 | querystring = require('querystring'),
3 | ejs = require('ejs');
4 |
5 | module.exports = function(grunt) {
6 |
7 | grunt.registerMultiTask('changelog', 'Updates changelog.md based on GitHub milestones', function() {
8 | var done = this.async(),
9 |
10 | params = querystring.stringify({
11 | milestone: this.data.milestone,
12 | state: 'closed',
13 | per_page: 100
14 | }),
15 |
16 | path = '/repos/' + this.data.user + '/' + this.data.repo + '/issues?' + params,
17 |
18 | buffer = '',
19 | self = this;
20 |
21 | var write = function() {
22 | var issues = JSON.parse(buffer),
23 | log = '';
24 |
25 | if(grunt.file.exists('changelog.md')) {
26 | log = grunt.file.read('changelog.md');
27 | };
28 |
29 | ejs.renderFile(__dirname + '/../changelog.ejs', {
30 | version: self.data.version,
31 | date: new Date(Date.now()),
32 | issues: issues
33 | }, function(e, template) {
34 |
35 | if(e) {
36 | done(e);
37 | }
38 |
39 | grunt.file.write('changelog.md', template + log);
40 | done();
41 |
42 | });
43 | },
44 |
45 | req = https.request({
46 | hostname: 'api.github.com',
47 | path: path
48 | }, function(res) {
49 |
50 | res.on('data', function(data) {
51 | buffer += data;
52 | });
53 |
54 | res.on('end', write);
55 | });
56 |
57 | req.end();
58 |
59 | req.on('error', function(e) {
60 | done(e);
61 | });
62 |
63 | });
64 |
65 | }
--------------------------------------------------------------------------------
/build/tasks/docco.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Grunt Docco task. Based on https://github.com/DavidSouther/grunt-docco
3 | */
4 | var docco = require('docco');
5 |
6 | module.exports = function(grunt) {
7 | grunt.registerMultiTask('docco', 'Docco processor.', function() {
8 | var _ = grunt.util._;
9 | var done = this.async();
10 | var options = this.options();
11 | var src = grunt.file.expand(this.data.files).filter(function(file) {
12 | return !_.some(options.exclude, function(exclude) {
13 | return exclude.test(file);
14 | });
15 | });
16 |
17 | docco.document( _.extend({ args: src }, this.data.docco, options.docco), function(err, result, code){
18 | grunt.log.writeln("Doccoed [" + src.join(", ") + "]; " +
19 | err ? err : "(No errors)" + "\n" + result + " " + code);
20 | done();
21 | });
22 | });
23 | }
--------------------------------------------------------------------------------
/build/tasks/testify.js:
--------------------------------------------------------------------------------
1 | var ejs = require('ejs');
2 | var beautify = require('js-beautify');
3 |
4 | module.exports = function(grunt) {
5 | var _ = grunt.util._;
6 |
7 | grunt.registerMultiTask('testify', 'Generates test runners', function() {
8 | var done = this.async();
9 | var data = this.data;
10 | var template = grunt.file.read(this.data.template);
11 | var transform = this.data.transform || {};
12 | var modules = this.data.builder.modules;
13 | var configurations = this.data.builder.configurations;
14 |
15 | _.each(configurations, function(config, configurationName) {
16 | var options = {
17 | configuration: config,
18 | modules: [],
19 | tests: [],
20 | root: data.root,
21 | '_': _
22 | };
23 |
24 | _.each(modules, function(definition, key) {
25 | if(!definition.configurations || definition.configurations.indexOf(configurationName) !== -1) {
26 | var name = key.substr(key.lastIndexOf('/') + 1);
27 | var mod = transform.module ? transform.module(definition, key) : key;
28 | var test = transform.test ? transform.test(definition, key) : (key + '/' + name + '_test.js');
29 |
30 | mod && options.modules.push(mod);
31 | test && options.tests.push(test);
32 | }
33 | });
34 |
35 | _.extend(config.steal, {
36 | root: data.root
37 | });
38 |
39 | if(transform && transform.options) {
40 | _.extend(options, transform.options.call(config, configurationName));
41 | }
42 |
43 | var lib = '\n'+
44 | beautify.html(ejs.render(template, options), {
45 | "wrap_line_length": 70
46 | });
47 |
48 | grunt.log.writeln('Generating ' + data.out + configurationName + '.html');
49 | grunt.file.write(data.out + configurationName + '.html', lib);
50 | });
51 |
52 | done();
53 | });
54 | };
--------------------------------------------------------------------------------
/build/tasks/updateversion.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | // A grunt task that writes the banner to every file
4 | module.exports = function (grunt) {
5 | grunt.registerMultiTask('updateversion', 'Replaces given symbol with current version', function () {
6 | var options = grunt.config.process(['updateversion', this.target]);
7 | var version = this.data.version;
8 | var symbol = this.data.symbol;
9 |
10 | grunt.file.expand(this.data.files).forEach(function (file) {
11 | var outFile = options.out ? path.join(options.out, path.basename(file)) : file;
12 | var fileContents = grunt.file.read(file).replace(symbol, version);
13 |
14 | if(grunt.file.read(file).match(symbol)) {
15 | grunt.log.writeln('Updating version in ' + file);
16 | grunt.file.write(outFile, fileContents.replace(symbol, version));
17 | }
18 | });
19 | });
20 | }
21 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | ## 3.3
2 |
3 | CanJS is now stolen and is the prefered way of doing things. $.Class, $.Model, $.View, $.Controller, $.route, $.Observe are all
4 | now can.NAME. To maintain large amounts of backwards compatability, these things still exist. However,
5 | using can is now encouraged. Also, can has things as plugins that were included by default previously.
6 |
7 |
8 | ### Class
9 |
10 | - Removed .Class access to instance's constructor function, use .constructor instead
11 | - Removed callback, use .proxy
12 |
13 | ### Controller
14 |
15 | - `delegate` and `bind` are replaced with `on`
16 |
17 | ### Observe
18 |
19 | - $.O is removed
20 | - attrs is now just attr
21 | - sort is removed (temporarily)
22 |
23 | ### Model
24 |
25 | - model's implemented ajax methods do not take success / error, they produce methods that do
26 | - model.update(attrs, success, error) is removed, use model.attr(attrs).save(success, error)
27 | - model list does not get updated events, listen for change
28 | - error message handlers get `handler(ev, attr, errorName)`
29 | - `this` in save's success handler `save(succes, error)` is now the deferred.
30 | - There are no default fixtures for models anymore.
31 | - there is no error handler on attributes. Use an event handler.
32 | - Abstracted element helper `.models` to be applicable to `can.Observe` and renamed to `.instances`
33 |
34 | ### View
35 |
36 | - Returns a documentFragment
37 | - All types are moved into can
38 | - Helpers are removed
39 | - plugin is gone, use <%= (el)-> el.pluginName(args) %>
40 | - callback functions execute before the fragment is inserted into the DOM
41 |
42 | ### Fixture
43 |
44 | - fixture.make returns a store
45 |
46 | ## 3.2.2
47 |
48 | ### Model
49 |
50 | - Removed this.publish
51 |
52 |
53 | ## 3.2.1 (10/18/11)
54 |
55 | ### Steal
56 |
57 | - Fixed a bug in steal/html that made it unusable
58 |
59 | ### FuncUnit
60 |
61 | - Fixed a bug in PhantomJS steal.browser
62 |
63 | ## 3.2 (10/15/11)
64 |
65 | ### JavaScriptMVC
66 |
67 | - Updated Getting Started Guide
68 | - Added tutorials for FuncUnit, jQueryMX, and StealJS
69 | - Added examples for Contacts, PlayerMX, Todo, and Srchr apps.
70 | - Added Organizing your App, Searchable Ajax Apps, Migrating to 3.1, and Ajax Service Guidelines tutorial
71 |
72 | ### StealJS
73 |
74 | - js accepts `-e` to exit on error
75 | - steal works asynchronously
76 | - steal uses suffix as type (using steal.type)
77 | - removed steal.plugins, steal.less, steal.css, etc.
78 | - added steal.parse
79 | - fixed bug with steal.dev not handling nested parenthesis
80 | - added steal.html and steal.html.crawl
81 | - IE loads more than 32 styles
82 | - added steal.browser
83 | - steal.get can follow steals and install dependencies
84 | - added steal.loaded and steal.has
85 |
86 | ### jQueryMX
87 |
88 | - Better distance calculation on drag-drop
89 | - $.Range fixes for IE
90 | - Added $.Observe and $.route
91 | - fixtures handle 0 based ids
92 | - CoffeeScript generator
93 | - Moved string helpers to lang/string
94 | - Added $.Object helpers
95 | - $.fixture can intercept a request and handle templated urls.
96 | - Updated generators to insert steal requests auto-magically
97 | - FormParams leaves values as strings by default.
98 | - dimensions works when not provided an element
99 | - upgraded to jQuery 1.6.4
100 |
101 | #### View
102 |
103 | - EJS escapes content by default. Use <%== to not escape.
104 | - Bugs fixed jQuery modify helpers when not passing html.
105 | - EJS filenames show up in firebug on the filesystem.
106 |
107 |
108 | #### Controller
109 |
110 | - Removed Document Controllers
111 | - pluginName works right
112 | - Controller's can bind on constructors or other functions.
113 | - plugin helper code happens in setup
114 | - update rebinds event handlers
115 |
116 | #### Model
117 |
118 | - added beta $.Model.Store
119 | - Removed associations, added convert
120 | - removed wrap and wrapMany in favor of model and models.
121 | - Model.List creates updated events instead of update events.
122 | - Model uses static update and destroy for ajax events.
123 |
124 | ### FuncUnit
125 |
126 | - 'inherits' from jQuery via .sub()
127 | - Uses steal.browser so PhantomJS and browsers can work
128 | - Faster Page Opening
129 | - Uses latest QUnit
130 |
131 |
132 | ### Syn
133 |
134 | - rightclick works better
135 |
136 | ### DocumentJS
137 |
138 | - caches content in localStorage
139 | - better breadcumb
140 | - handles .md files
141 |
142 |
143 | ## 3.1 (5/17/2011)
144 |
145 | ### JavaScriptMVC
146 |
147 | - Added getjmvc script
148 | - Added install script for windows
149 | - Added new init page with framework overview
150 | - Added error level (-e) support to the js.bat (Windows) and ./js (Mac, Linux)
151 |
152 | ### jQueryMX
153 |
154 | - jQuery upgraded to 1.6.1
155 | - .val method supports Views. EX: $('input').val('view_name', {});
156 | - Added range plugin
157 | - Added deparam plugin - Takes a string of name value pairs and returns a Object literal that represents those params.
158 |
159 | #### Model
160 |
161 | - Deferreds and Converter Support.
162 | - Added VERB support to parameterized CRUD urls. EX: update: "POST /recipe/update/{id}.json"
163 | - Global model events. EX: Recipe.bind('update', func).
164 | - Attribute update event. EX: recipe.bind('updated.attr', func);
165 | - Model.list upgraded to handle findAll, findOne
166 | - AJAX converters are renamed: wrap -> model and wrapMany -> models
167 | - Added dataType optional param to the ajax function
168 | - Added filters to Fixtures
169 | - Models and Fixtures support create, delete, and update model encapsulation.
170 |
171 | #### Events
172 |
173 | - Added swipe, swipeleft and swiperight events
174 | - Swipe left and swipe right added to jQuery.event.special for autobinding with controller
175 | - Hover can set leave. EX: $('.elem').bind('hoverleave', func)
176 | - Hover only runs one Mouseenter / Mouseleave per selector at a time
177 | - Added support for HTML5 history API
178 | - Drag and drop allows adding drops after drag has started
179 | - Drag doesn't select text anymore
180 | - Limit and step take center param
181 | - Limit can limit center of drag
182 | - Added pause and resume for events
183 |
184 | #### Controller
185 |
186 | - Added object binding to parameterized controller events. EX: "{window} load".
187 |
188 | #### View
189 |
190 | - Deferreds support
191 | - Better warning when templates don't exist
192 |
193 | #### Funcunit
194 |
195 | - Changes to the repeat API.
196 | - Added eval.
197 | - Added examples.
198 |
199 | #### Syn
200 |
201 | - Syn adjusts scrolling for drag / move positions not in the page.
202 | - Syn loads in Rhino, and documentation can be generated.
203 | - Syn works under Env.js.
--------------------------------------------------------------------------------
/js:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This script checks for arguments, if they don't exist it opens the Rhino dialog
3 | # if arguments do exist, it loads the script in the first argument and passes the other arguments to the script
4 | # ie: ./js steal/script/controller Todo
5 |
6 | if [ $# -eq 0 ]
7 | then
8 | java -cp steal/rhino/js.jar:funcunit/java/selenium-java-client-driver.jar org.mozilla.javascript.tools.shell.Main
9 | exit 127
10 | fi
11 | CP=funcunit/java/selenium-java-client-driver.jar:steal/rhino/js.jar
12 |
13 | export ERRORLEV=0
14 | if [ $1 = "-e" ]
15 | then
16 | ERRORLEV=1
17 | shift
18 | fi
19 |
20 | if [ $1 = "-h" -o $1 = "-?" -o $1 = "--help" ]
21 | then
22 | echo Load a command line Rhino JavaScript environment or run JavaScript script files in Rhino.
23 | echo Available commands:
24 | echo -e "./js\t\t\t\tOpens a command line JavaScript environment"
25 | echo -e "./js -d\t\t\t\tOpens the Rhino debugger"
26 | echo -e "./js [FILE]\t\t\tRuns FILE in the Rhino environment"
27 | echo -e ""
28 | echo -e "JavaScriptMVC script usage:"
29 | echo -e "./js steal/generate/app [NAME]\t\tCreates a new JavaScriptMVC application"
30 | echo -e "./js steal/generate/page [APP] [PAGE]\tGenerates a page for the application"
31 | echo -e "./js steal/generate/controller [NAME]\tGenerates a Controller file"
32 | echo -e "./js steal/generate/model [TYPE] [NAME]\tGenerates a Model file"
33 | echo -e "./js apps/[NAME]/compress.js\t\tCompress your application and generate documentation"
34 | exit 127
35 | fi
36 |
37 | if [ $1 = "-d" ]
38 | then
39 | java -classpath steal/rhino/js.jar:steal/rhino/selenium-java-client-driver.jar org.mozilla.javascript.tools.debugger.Main
40 | exit 127
41 | fi
42 |
43 | ARGS=[
44 | for arg
45 | do
46 | if [ $arg != $1 ]
47 | then
48 | ARGS=$ARGS"'$arg'",
49 | fi
50 | done
51 | ARGS=$ARGS]
52 | java -Xmx512m -Xss1024k -cp $CP org.mozilla.javascript.tools.shell.Main -e _args=$ARGS -opt -1 -e 'load('"'"$1"'"')'
53 |
54 | if [ $ERRORLEV = "1" -a $? = "1" ]
55 | then
56 |
57 | exit 1
58 | fi
59 |
--------------------------------------------------------------------------------
/js.bat:
--------------------------------------------------------------------------------
1 | :: This script checks for arguments, if they don't exist it opens the Rhino dialog
2 | :: if arguments do exist, it loads the script in the first argument and passes the other arguments to the script
3 | :: ie: js jmvc\script\controller Todo
4 | @echo off
5 | SETLOCAL ENABLEDELAYEDEXPANSION
6 | if "%1"=="" (
7 | java -cp steal\rhino\js.jar org.mozilla.javascript.tools.shell.Main
8 | GOTO END
9 | )
10 | if "%1"=="-h" GOTO PRINT_HELP
11 | if "%1"=="-?" GOTO PRINT_HELP
12 | if "%1"=="--help" GOTO PRINT_HELP
13 |
14 | if "%1"=="-d" (
15 | java -classpath funcunit/java/selenium-java-client-driver.jar;steal/rhino/js.jar org.mozilla.javascript.tools.debugger.Main
16 | GOTO END
17 | )
18 | SET CP=funcunit/java/selenium-java-client-driver.jar;steal\rhino\js.jar
19 | SET ERRORLEV=0
20 | if "%1"=="-e" (
21 | SET ERRORLEV=1
22 | SHIFT /1
23 | )
24 | SET ARGS=[
25 | SET FILENAME=%1
26 | SET FILENAME=%FILENAME:\=/%
27 | ::haven't seen any way to loop through all args yet, so for now this goes through arg 2-7
28 | ::dos sucks and for some reason this structure doesn't respect the shift, so we branch
29 | if "%ERRORLEV%"=="1" (
30 | for /f "tokens=3,4,5,6,7,8 delims= " %%a in ("%*") do SET ARGS=!ARGS!'%%a','%%b','%%c','%%d','%%e','%%f'
31 | ) ELSE (
32 | for /f "tokens=2,3,4,5,6,7 delims= " %%a in ("%*") do SET ARGS=!ARGS!'%%a','%%b','%%c','%%d','%%e','%%f'
33 | )
34 | ::remove the empty args
35 | :: for %%a in (",''=") do ( call set ARGS=%%ARGS:%%~a%% )
36 | SET ARGS=%ARGS:,''=%
37 | ::remove the spaces
38 | :: for /f "tokens=1*" %%A in ("%ARGS%") do SET ARGS=%%A
39 | SET ARGS=%ARGS: =%
40 | SET ARGS=%ARGS%]
41 | set ARGS=%ARGS:\=/%
42 | java -Xmx512m -Xss1024k -cp %CP% org.mozilla.javascript.tools.shell.Main -opt -1 -e _args=%ARGS% -e load('%FILENAME%')
43 |
44 | if "%ERRORLEV%"=="1" (
45 | if errorlevel 1 exit 1
46 | )
47 |
48 | GOTO END
49 |
50 | :PRINT_HELP
51 | echo Load a command line Rhino JavaScript environment or run JavaScript script files in Rhino.
52 | echo Available commands:
53 | echo js Opens a command line JavaScript environment
54 | echo js -d Opens the Rhino debugger
55 | echo js -selenium Starts selenium server
56 | echo js [FILE] Runs FILE in the Rhino environment
57 |
58 | echo JavaScriptMVC script usage:
59 | echo js steal/generate/app [NAME] Creates a new JavaScriptMVC application
60 | echo js steal/generate/page [APP] [PAGE] Generates a page for the application
61 | echo js steal/generate/controller [NAME] Generates a Controller file
62 | echo js steal/generate/model [TYPE] [NAME] Generates a Model file
63 | echo js apps/[NAME]/compress.js Compress your application and generate documentation
64 |
65 | :END
66 |
--------------------------------------------------------------------------------
/license.md:
--------------------------------------------------------------------------------
1 | # License
2 |
3 | Copyright (C) 2012 by [Bitovi](http://bitovi.com)
4 |
5 | The MIT license:
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | THE SOFTWARE.
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "JavaScriptMVC",
3 | "description": "A full stack JavaScript application framework containing CanJS, StealJS, FuncUnit, jQuery++, and DocumentJS.",
4 | "version": "3.3.0pre",
5 | "author": {
6 | "name": "Bitovi",
7 | "email": "contact@bitovi.com",
8 | "web": "http://bitovi.com/"
9 | },
10 | "devDependencies": {
11 | "grunt": "0.4.0",
12 | "grunt-closure-tools": "0.7.7",
13 | "http-server": "0.5.1",
14 | "docco": "0.6.2",
15 | "js-beautify": "1.2.0",
16 | "github": ">= 0.1.7",
17 | "commander": "*",
18 | "tafa-misc-util": "*",
19 | "lodash" : "0.1.0",
20 | "grunt-contrib-connect": "0.1.2",
21 | "ejs": "0.8.3"
22 | },
23 | "homepage": "http://javascriptmvc.com/",
24 | "repository": {
25 | "type": "git",
26 | "url": "git@github.com:jupiterjs/javascriptmvc.git"
27 | },
28 | "licenses": [
29 | {
30 | "type": "MIT",
31 | "url": "http://opensource.org/licenses/mit-license.php"
32 | }
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | @page javascriptmvc JavaScriptMVC
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
JavaScriptMVC Documentation
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | JavaScriptMVC (JMVC) is a MIT licensed, client-side, JavaScript framework that
18 | builds maintainable, error-free, lightweight
19 | applications as quick as possible. It packs best-of-breed
20 | libraries and tools that are guaranteed to work together. It
21 | supports every browser that jQuery supports.
22 |
23 | If you are new to the framework, this page followed by
24 | the [tutorials] is the best place to start.
25 |
26 | JMVC's goodies are broken down into four sub-projects:
27 |
28 | - [canjs CanJS] - A client side MVC Framework
29 | - [jquerypp jQuery++] - A collection of useful DOM helpers and special events for jQuery
30 | - [stealjs StealJS] - JavaScript and CSS dependency management and build tools
31 | - [FuncUnit FuncUnit] - Functional and unit testing framework
32 | - [DocumentJS DocumentJS] - Documentation engine
33 |
34 | The remainder of this page highlights each sub-project. Click
35 | the the project links on the left for a more in-depth overview
36 | of the sub-project.
37 |
38 | ## CanJS
39 |
40 | [canjs CanJS] is a JavaScript framework that makes
41 | building rich web applications easy and the MVC of
42 | JavaScriptMVC. The library is extremely lightweight
43 | (at only 11k minified and compressed) and full featured.
44 |
45 | Everything you want and need to know about CanJS
46 | [http://canjs.us can be found here.]
47 |
48 | ## jQuery++
49 |
50 | [jquerypp jQuery++] is a collection of useful jQuery libraries that provide the
51 | missing functionality necessary to implement and organize large-scale
52 | jQuery applications. It provides low-level utilities for things that
53 | jQuery doesn’t support.
54 |
55 | The best way to get started is the [jQuery++ overview](http://jquerypp.com).
56 |
57 | ## StealJS
58 |
59 | [stealjs StealJS] is a "code manager" that keeps code beautiful and organized
60 | while developing and FAST for users in production. It's a collection of
61 | command-line and browser-based utilities enabling you to:
62 |
63 | - [steal load] JS, CSS, LESS, and CoffeeScript files and build them into a single production file.
64 | - [steal.generate generate] an application file/folder structure, complete with test, build and documentation scripts.
65 | - [steal.clean clean and JSLint] your code.
66 | - make your Ajax app [steal.html crawlable].
67 | - log [steal.dev messages] in development that get removed in production builds.
68 |
69 | [stealjs StealJS] is a stand-alone tool that can be used without the rest of JavaScriptMVC.
70 |
71 | ## FuncUnit
72 |
73 | [FuncUnit FuncUnit] is a web application testing framework that provides automated unit and
74 | functional testing. Tests are written and debugged in the browser with
75 | FuncUnit's short, terse, jQuery-like API. The same tests can be instantly
76 | automated, run by Envjs or Selenium.
77 |
78 | FuncUnit also supports extremely accurate [Syn event simulation] on practically every browser and
79 | system.
80 |
81 | ## DocumentJS
82 |
83 | [DocumentJS DocumentJS] provides powerful JavaScript documenting
84 | capabilities. This whole website is built with it! DocumentJS can document practically
85 | anything. It's extensible. And with Markdown support, it's easy to document your code.
86 |
--------------------------------------------------------------------------------
/scripts/getjmvc:
--------------------------------------------------------------------------------
1 | #
2 | # Use this script to install JMVC from github or your own fork. If its already installed,
3 | # it will get latest for all the submodules. Assumes your project uses git.
4 | #
5 | # Options:
6 | # -u username (default is bitovi)
7 | # -b branch (default is master)
8 | # -s source url (default is https://github.com)
9 | # -p install path (default is current directory)
10 | #
11 | # Usage:
12 | # Default usage. This will install from https://bitovi@github.com/bitovi/steal.git
13 | # ./getjmvc
14 | #
15 | # Use your own forked submodule repositories. This will install from https://github.com/mycompany/steal.git
16 | # ./getjmvc -u mycompany
17 | #
18 | # Install to your own path. You can specify the path where the submodules are installed, like to public/
19 | # ./getjmvc -p public/
20 | #
21 | # Install a different branch (used to install the 2.0 branches for steal, canjs, jquerypp, and funcunit).
22 | # ./getjmvc -b 2.0
23 | #
24 | # Install from a different repository (not github) or from ssh instead of http (if you have write access).
25 | # ./getjmvc -s git@github.com
26 | # ./getjmvc -s http://mygitrepo.com
27 | #
28 | # Update code. If you installed somewhere besides the current directory, specify a -p. This will update code in each submodule.
29 | # ./getjmvc
30 | # ./getjmvc -p public/
31 |
32 |
33 | USERNAME=bitovi
34 | BRANCH=master
35 | SRC=https://github.com
36 | INSTALLPATH=
37 |
38 | while getopts ":u:b:s:p:" opt; do
39 | case $opt in
40 | u)
41 | USERNAME=$OPTARG
42 | ;;
43 | b)
44 | BRANCH=$OPTARG
45 | ;;
46 | s)
47 | SRC=$OPTARG
48 | ;;
49 | p)
50 | INSTALLPATH=$OPTARG
51 | ;;
52 | \?)
53 | echo "Invalid option: -$OPTARG" >&2
54 | exit 1
55 | ;;
56 | esac
57 | done
58 |
59 | # if steal/steal.js exists, refresh everything
60 | if [ -f ${INSTALLPATH}steal/steal.js ]
61 | then
62 | cd ${INSTALLPATH}steal
63 | git pull origin master
64 | cd ../jquerypp
65 | git pull origin master
66 | cd ../documentjs
67 | git pull origin master
68 | cd ../funcunit
69 | git pull origin master
70 | cd syn
71 | git pull origin master
72 | exit 127
73 | fi
74 |
75 | # if its http, should look like this: https://github.com/bitovi/canjs.git
76 | if [[ $SRC =~ :// ]]; then
77 | FULLSRC=$SRC/$USERNAME
78 | # else it should look like this: git@github.com:bitovi/canjs.git
79 | else
80 | FULLSRC=$SRC:$USERNAME
81 | fi
82 |
83 | git submodule add $FULLSRC/legacy-steal.git ${INSTALLPATH}steal
84 | git submodule add $FULLSRC/canjs.git ${INSTALLPATH}can
85 | git submodule add $FULLSRC/jquerypp.git ${INSTALLPATH}jquerypp
86 | git submodule add $FULLSRC/documentjs.git ${INSTALLPATH}documentjs
87 | git submodule add $FULLSRC/legacy-funcunit.git ${INSTALLPATH}funcunit
88 | git submodule add $FULLSRC/jmvc-generators.git ${INSTALLPATH}jmvc
89 | git submodule init
90 | git submodule update
91 | cd ${INSTALLPATH}steal
92 | git checkout $BRANCH
93 | cd ../jmvc
94 | git checkout $BRANCH
95 | cd ../can
96 | git checkout $BRANCH
97 | cd ../jquerypp
98 | git checkout $BRANCH
99 | cd ../documentjs
100 | git checkout legacy
101 | cd ../funcunit
102 | git checkout $BRANCH
103 | git submodule init
104 | git submodule update
105 | cd syn
106 | git checkout $BRANCH
107 | cd ../../
108 | ./steal/js steal/make.js
109 | chmod 777 js
110 |
--------------------------------------------------------------------------------
/scripts/getjmvc.bat:
--------------------------------------------------------------------------------
1 | :: Use this script to install JMVC from github or your own fork. If its already installed,
2 | :: it will get latest for all the submodules. Assumes your project uses git.
3 | ::
4 | :: Options:
5 | :: -u username (default is bitovi)
6 | :: -b branch (default is master)
7 | :: -s source url (default is https://github.com)
8 | :: -p install path (default is current directory)
9 | ::
10 | :: Usage:
11 | :: Default usage. This will install from https://bitovi@github.com/bitovi/steal.git
12 | :: ./getjmvc
13 | ::
14 | :: Use your own forked submodule repositories. This will install from
15 | :: https://github.com/bitovi/steal.git
16 | :: ./getjmvc -u cengage
17 | ::
18 | :: Install to your own path. You can specify the path where the submodules are installed,
19 | :: like to public/
20 | :: ./getjmvc -p public/
21 | ::
22 | :: Install a different branch (used to install the 2.0 branches for steal, canjs, jquerypp, and funcunit).
23 | :: ./getjmvc -b 2.0
24 | ::
25 | :: Install from a different repository (not github) or from ssh instead of http (if you have
26 | :: write access).
27 | :: ./getjmvc -s git@github.com
28 | :: ./getjmvc -s http://mygitrepo.com
29 | ::
30 | :: Update code. If you installed somewhere besides the current directory, specify a -p.
31 | :: ./getjmvc
32 | :: ./getjmvc -p public/
33 |
34 | @echo off
35 | set USERNAME=bitovi
36 | set BRANCH=master
37 | set SRC=https://github.com
38 | set INSTALLPATH=./
39 |
40 | :GETOPTS
41 | if /I "%1"=="-u" (
42 | set USERNAME=%2
43 | shift
44 | shift
45 | goto :GETOPTS
46 | )
47 | if /I "%1"=="-b" (
48 | set BRANCH=%2
49 | shift
50 | shift
51 | goto :GETOPTS
52 | )
53 | if /I "%1"=="-s" (
54 | set SRC=%2
55 | shift
56 | shift
57 | goto :GETOPTS
58 | )
59 | if /I "%1"=="-p" (
60 | set INSTALLPATH=%2
61 | shift
62 | shift
63 | goto :GETOPTS
64 | )
65 |
66 | set USERNAME=%USERNAME: =%
67 | set BRANCH=%BRANCH: =%
68 | set SRC=%SRC: =%
69 | set INSTALLPATH=%INSTALLPATH: =%
70 |
71 | :: if steal/steal.js exists, refresh everything
72 | IF EXIST %INSTALLPATH%steal/steal.js GOTO UPDATE
73 |
74 |
75 | :: CAN'T DO REGEX IN DOS, SO USE THIS HACK INSTEAD
76 | set WITHOUTHTTP=%SRC:http=%
77 |
78 | if "%WITHOUTHTTP%"=="%SRC%" (
79 | set FULLSRC=%SRC%:%USERNAME%
80 | GOTO :INSTALL
81 | )
82 | set FULLSRC=%SRC%/%USERNAME%
83 |
84 | :INSTALL
85 | call git submodule add %FULLSRC%/legacy-steal.git %INSTALLPATH%steal
86 | call git submodule add %FULLSRC%/canjs.git %INSTALLPATH%canjs
87 | call git submodule add %FULLSRC%/jquerypp.git %INSTALLPATH%jquerypp
88 | call git submodule add %FULLSRC%/documentjs.git %INSTALLPATH%documentjs
89 | call git submodule add %FULLSRC%/legacy-funcunit.git %INSTALLPATH%funcunit
90 | call git submodule init
91 | call git submodule update
92 | cd %INSTALLPATH%steal
93 | call git checkout %BRANCH%
94 | cd ..\jquery
95 | call git checkout %BRANCH%
96 | cd ..\documentjs
97 | call git checkout legacy
98 | cd ..\funcunit
99 | call git checkout %BRANCH%
100 | call git submodule init
101 | call git submodule update
102 | cd syn
103 | call git checkout %BRANCH%
104 | cd ..\..\
105 | call steal\js steal/make.js
106 | goto :END
107 |
108 | :UPDATE
109 | cd %INSTALLPATH%steal
110 | call git pull origin master
111 | cd ..\jquery
112 | call git pull origin master
113 | cd ..\documentjs
114 | call git pull origin master
115 | cd ..\funcunit
116 | call git pull origin master
117 | cd syn
118 | call git pull origin master
119 | cd ..\..\
120 | goto :END
121 |
122 | :END
123 |
--------------------------------------------------------------------------------
/site/blog.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | JavaScriptMVC Blog
5 |
6 |
7 |
8 |
9 |
JavaScriptMVC is an open-source framework containing the best ideas in jQuery development.
It guides you to successfully completed projects by promoting best practices, maintainability, and convention over configuration.
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
What is JavaScriptMVC?
48 |
A collection of the best practices and tools for building JavaScript applications.
49 | Built on top of jQuery, it consists of the following standalone components:
50 |
51 |
StealJS - Dependency management and a stupidly easy build tool.
52 |
FuncUnit - There's no better functional testing solution available. Write tests in jQuery syntax, run them via command line or browser.
53 |
jQueryMX - These plugins are the building blocks of large jQuery applications: model, view, controller, class, fixtures, and more.
54 |
DocumentJS - A JSDoc compliant tool that turns comments into a searchable documentation app.
55 |
56 |
Why JavaScriptMVC?
57 |
It is the product of years of experience in the trenches developing medium to large JavaScript applications.
58 | It will help you build a quality application.
59 |
Who Uses JavaScriptMVC?
60 |
Our users are software craftsmen who care about doing JavaScript development the right way. They care about things like test driven development, performance, code quality, structure and maintainability.
61 |
JavaScriptMVC makes it simple to do all these things and more.
52 | Download Syn1.0 Production
53 | Syn is used to simulate user actions. It creates synthetic events and performs their default behaviors. Learn more.
54 |
55 |
56 |
57 |
Download jQueryMXCheck the libraries you want. Then Download!
58 |
jQuery MVC Extensions. Learn More
59 |
60 |
61 |
62 |
63 |
64 |
JavaScriptMVC is an open-source framework containing the best ideas in jQuery development.
It guides you to successfully completed projects by promoting best practices, maintainability, and convention over configuration.
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
What is JavaScriptMVC?
75 |
A collection of the best practices and tools for building JavaScript applications.
76 | Built on top of jQuery, it consists of the following standalone components:
77 |
78 |
StealJS - Dependency management and a stupidly easy build tool.
79 |
FuncUnit - There's no better functional testing solution available. Write tests in jQuery syntax, run them via command line or browser.
80 |
jQueryMX - These plugins are the building blocks of large jQuery applications: model, view, controller, class, fixtures, and more.
81 |
DocumentJS - A JSDoc compliant tool that turns comments into a searchable documentation app.
82 |
83 |
Why JavaScriptMVC?
84 |
It is the product of years of experience in the trenches developing medium to large JavaScript applications.
85 | It will help you build a quality application.
86 |
Who Uses JavaScriptMVC?
87 |
Our users are software craftsmen who care about doing JavaScript development the right way. They care about things like test driven development, performance, code quality, structure and maintainability.
88 |
JavaScriptMVC makes it simple to do all these things and more.
We prefer you use Git. It's a great way to share changes with us and the community.
36 |
Installing from Github
37 |
Download the JavaScriptMVC Install script for Mac
38 | or Windows.
39 |
40 |
Put this script where you want to install JavaScriptMVC's submodules (Steal, jQueryMX, FuncUnit, and DocumentJS).
41 |
42 |
Type getjmvc in a command promp (or ./getjmvc for Mac users) and it will install each submodule. This script
43 | assumes your project is using a git repository.
44 |
45 |
Run it again later to update each submodule. Script options and more details can be found here.
46 |
47 |
If you just want a certain repo, or you like doing things the hard way, here's how to get each project yourself:
48 |
49 |
50 | JavaScriptMVC
51 | git clone http://github.com/jupiterjs/javascriptmvc.git
52 | git submodule init
53 | git submodule update
54 | cd into each submodule and do git checkout master
55 |
For more information on how to develop with Git check out Developing with Git.
82 |
83 |
84 |
JavaScriptMVC is an open-source framework containing the best ideas in jQuery development.
It guides you to successfully completed projects by promoting best practices, maintainability, and convention over configuration.
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
What is JavaScriptMVC?
95 |
A collection of the best practices and tools for building JavaScript applications.
96 | Built on top of jQuery, it consists of the following standalone components:
97 |
98 |
StealJS - Dependency management and a stupidly easy build tool.
99 |
FuncUnit - There's no better functional testing solution available. Write tests in jQuery syntax, run them via command line or browser.
100 |
jQueryMX - These plugins are the building blocks of large jQuery applications: model, view, controller, class, fixtures, and more.
101 |
DocumentJS - A JSDoc compliant tool that turns comments into a searchable documentation app.
102 |
103 |
Why JavaScriptMVC?
104 |
It is the product of years of experience in the trenches developing medium to large JavaScript applications.
105 | It will help you build a quality application.
106 |
Who Uses JavaScriptMVC?
107 |
Our users are software craftsmen who care about doing JavaScript development the right way. They care about things like test driven development, performance, code quality, structure and maintainability.
108 |
JavaScriptMVC makes it simple to do all these things and more.
Justin is a founder, and lead developer of JavaScriptMVC. During the day, he is the CEO of Jupiter Consulting, a JavaScript consulting company. When not working on JavaScriptMVC, he's cheating with his other favorite framework - Ruby on Rails.
52 |
53 |
54 |
55 |
56 |
Brian Moschel
57 |
Brian is a founder of JavaScriptMVC and Jupiter Consulting in Chicago. He wrote the original version of JavaScriptMVC and does writing for the site. He also has a dog named Ajax. Attempts to teach him programming have been fruitless thus far.
58 |
59 |
60 |
61 |
62 |
Michael Mayer
63 |
Michael loves to bring order to the chaos of Web development. He is specialized in keeping deadlines and puts his life at risk to successfully complete projects. His home base is in Berlin, Germany.
Trey Kennedy has been an embedded C/C++ software engineer for over 10 years and a part-time web applications developer for the last 3 years. He is sick and tired of generating HTML and JavaScript using other languages and is ready to evangelize the world in the way of native JavaScript development - or maybe just his company.
94 |
95 |
96 |
97 |
98 |
Lee Henson
99 |
Located at the secret Music Glue skunk works in London Town, plotting the downfall of the music industry fat cats (and sharpening his ice pick).
100 |
101 |
102 |
103 |
104 |
105 |
JavaScriptMVC is an open-source framework containing the best ideas in jQuery development.
It guides you to successfully completed projects by promoting best practices, maintainability, and convention over configuration.
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
What is JavaScriptMVC?
116 |
A collection of the best practices and tools for building JavaScript applications.
117 | Built on top of jQuery, it consists of the following standalone components:
118 |
119 |
StealJS - Dependency management and a stupidly easy build tool.
120 |
FuncUnit - There's no better functional testing solution available. Write tests in jQuery syntax, run them via command line or browser.
121 |
jQueryMX - These plugins are the building blocks of large jQuery applications: model, view, controller, class, fixtures, and more.
122 |
DocumentJS - A JSDoc compliant tool that turns comments into a searchable documentation app.
123 |
124 |
Why JavaScriptMVC?
125 |
It is the product of years of experience in the trenches developing medium to large JavaScript applications.
126 | It will help you build a quality application.
127 |
Who Uses JavaScriptMVC?
128 |
Our users are software craftsmen who care about doing JavaScript development the right way. They care about things like test driven development, performance, code quality, structure and maintainability.
129 |
JavaScriptMVC makes it simple to do all these things and more.
Read JavaScriptMVC's Blog for articles, techniques and ideas on maintainable JavaScript
34 |
Community page
35 |
Visit our community page to find links, articles, plugins and examples shared by our community
36 |
Forum
37 |
Discuss ideas to make the framework better or problems you are having on JavaScriptMVC's Forum.
38 |
39 |
40 |
JavaScriptMVC is an open-source framework containing the best ideas in jQuery development.
It guides you to successfully completed projects by promoting best practices, maintainability, and convention over configuration.
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
What is JavaScriptMVC?
51 |
A collection of the best practices and tools for building JavaScript applications.
52 | Built on top of jQuery, it consists of the following standalone components:
53 |
54 |
StealJS - Dependency management and a stupidly easy build tool.
55 |
FuncUnit - There's no better functional testing solution available. Write tests in jQuery syntax, run them via command line or browser.
56 |
jQueryMX - These plugins are the building blocks of large jQuery applications: model, view, controller, class, fixtures, and more.
57 |
DocumentJS - A JSDoc compliant tool that turns comments into a searchable documentation app.
58 |
59 |
Why JavaScriptMVC?
60 |
It is the product of years of experience in the trenches developing medium to large JavaScript applications.
61 | It will help you build a quality application.
62 |
Who Uses JavaScriptMVC?
63 |
Our users are software craftsmen who care about doing JavaScript development the right way. They care about things like test driven development, performance, code quality, structure and maintainability.
64 |
JavaScriptMVC makes it simple to do all these things and more.
76 |
77 |
78 |
79 |
83 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/site/fonts/museo_slab_500-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/fonts/museo_slab_500-webfont.eot
--------------------------------------------------------------------------------
/site/fonts/museo_slab_500-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/fonts/museo_slab_500-webfont.ttf
--------------------------------------------------------------------------------
/site/fonts/museo_slab_500-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/fonts/museo_slab_500-webfont.woff
--------------------------------------------------------------------------------
/site/fonts/museoslab.css:
--------------------------------------------------------------------------------
1 | /* Generated by Font Squirrel (http://www.fontsquirrel.com) on January 4, 2011 */
2 |
3 |
4 |
5 | @font-face {
6 | font-family: 'MuseoSlab500';
7 | src: url('museo_slab_500-webfont.eot');
8 | src: local('☺'), url('museo_slab_500-webfont.woff') format('woff'), url('museo_slab_500-webfont.ttf') format('truetype'), url('museo_slab_500-webfont.svg#webfonth7ZuKjlS') format('svg');
9 | font-weight: normal;
10 | font-style: normal;
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/site/images/add_tag_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/add_tag_example.png
--------------------------------------------------------------------------------
/site/images/backgrounds/body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/body.png
--------------------------------------------------------------------------------
/site/images/backgrounds/bottom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/bottom.png
--------------------------------------------------------------------------------
/site/images/backgrounds/calendar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/calendar.png
--------------------------------------------------------------------------------
/site/images/backgrounds/download/documentjs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/download/documentjs.png
--------------------------------------------------------------------------------
/site/images/backgrounds/download/funcunit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/download/funcunit.png
--------------------------------------------------------------------------------
/site/images/backgrounds/download/javascriptmvc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/download/javascriptmvc.png
--------------------------------------------------------------------------------
/site/images/backgrounds/download/jquerymx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/download/jquerymx.png
--------------------------------------------------------------------------------
/site/images/backgrounds/download/stealjs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/download/stealjs.png
--------------------------------------------------------------------------------
/site/images/backgrounds/download/syn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/download/syn.png
--------------------------------------------------------------------------------
/site/images/backgrounds/greenbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/greenbox.png
--------------------------------------------------------------------------------
/site/images/backgrounds/link_hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/link_hover.png
--------------------------------------------------------------------------------
/site/images/backgrounds/navigation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/navigation.png
--------------------------------------------------------------------------------
/site/images/backgrounds/quote.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/backgrounds/quote.png
--------------------------------------------------------------------------------
/site/images/coverage_commandline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/coverage_commandline.png
--------------------------------------------------------------------------------
/site/images/coverage_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/coverage_file.png
--------------------------------------------------------------------------------
/site/images/coverage_report.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/coverage_report.png
--------------------------------------------------------------------------------
/site/images/crm_doc_demo_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/crm_doc_demo_1.png
--------------------------------------------------------------------------------
/site/images/crm_doc_demo_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/crm_doc_demo_2.png
--------------------------------------------------------------------------------
/site/images/follow_twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/follow_twitter.png
--------------------------------------------------------------------------------
/site/images/fork.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/fork.png
--------------------------------------------------------------------------------
/site/images/funcunit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/funcunit.png
--------------------------------------------------------------------------------
/site/images/funcunit_medium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/funcunit_medium.png
--------------------------------------------------------------------------------
/site/images/funcunit_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/funcunit_small.png
--------------------------------------------------------------------------------
/site/images/funcunitfolder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/funcunitfolder.png
--------------------------------------------------------------------------------
/site/images/funcunithtml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/funcunithtml.png
--------------------------------------------------------------------------------
/site/images/header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/header.png
--------------------------------------------------------------------------------
/site/images/iepopups.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/iepopups.png
--------------------------------------------------------------------------------
/site/images/iesecurity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/iesecurity.png
--------------------------------------------------------------------------------
/site/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/logo.png
--------------------------------------------------------------------------------
/site/images/page_type_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/page_type_example.png
--------------------------------------------------------------------------------
/site/images/parent_tag_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/parent_tag_example.png
--------------------------------------------------------------------------------
/site/images/phui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/phui.png
--------------------------------------------------------------------------------
/site/images/plugin_tag_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/plugin_tag_example.png
--------------------------------------------------------------------------------
/site/images/return_tag_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/return_tag_example.png
--------------------------------------------------------------------------------
/site/images/rss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/rss.png
--------------------------------------------------------------------------------
/site/images/tag_tag_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/tag_tag_example.png
--------------------------------------------------------------------------------
/site/images/team/brian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/team/brian.png
--------------------------------------------------------------------------------
/site/images/team/joe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/team/joe.png
--------------------------------------------------------------------------------
/site/images/team/justin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/team/justin.png
--------------------------------------------------------------------------------
/site/images/team/lee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/team/lee.png
--------------------------------------------------------------------------------
/site/images/team/matt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/team/matt.png
--------------------------------------------------------------------------------
/site/images/team/max.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/team/max.png
--------------------------------------------------------------------------------
/site/images/team/michael.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/team/michael.png
--------------------------------------------------------------------------------
/site/images/team/trey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/team/trey.png
--------------------------------------------------------------------------------
/site/images/test_cookbook_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/test_cookbook_example.png
--------------------------------------------------------------------------------
/site/images/test_tag_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/test_tag_example.png
--------------------------------------------------------------------------------
/site/images/test_tag_test_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/site/images/test_tag_test_example.png
--------------------------------------------------------------------------------
/site/pages/developingjmvc.md:
--------------------------------------------------------------------------------
1 | @page developingjmvc Developing JavaScriptMVC
2 |
3 | Awesome, you want to contribute back some code to JavaScriptMVC, or build your own
4 | download. This article
5 | explains how.
6 |
7 | JavaScriptMVC is comprised of several projects, each with
8 | it's own repository:
9 |
10 | - [http://github.com/bitovi/steal]
11 | - [http://github.com/bitovi/canjs]
12 | - [http://github.com/bitovi/jquerypp]
13 | - [http://github.com/bitovi/documentjs]
14 | - [http://github.com/bitovi/funcunit]
15 |
16 | These are collected in the javascriptmvc repository:
17 |
18 | - [http://github.com/bitovi/javascriptmvc]
19 |
20 | Read how to get, test, and build each project in JavaScriptMVC:
21 |
22 | ## 1. Get
23 |
24 | In Github, fork the repo you want to make changes to. Then clone
25 | the javascriptmvc repo and install the submodules like:
26 |
27 | @codestart
28 | git clone git@github.com:bitovi/javascriptmvc
29 | @codeend
30 |
31 | Now, open the javascriptmvc folder's .gitmodule file and change the url of the submodule(s)
32 | you have forked. For example, you might change:
33 |
34 | @codestart
35 | url = git://github.com/bitovi/canjs.git
36 | @codeend
37 | to
38 | @codestart
39 | url = git://github.com/justinbmeyer/canjs.git
40 | @codeend
41 |
42 | Now run:
43 |
44 |
45 | @codestart
46 | cd javascriptmvc
47 | git submodule init
48 | git submodule update
49 | @codeend
50 | Finally, you might need cd into each submodule and
51 | run
52 | @codestart
53 | git checkout
54 | @codeend
55 |
56 | Now make your changes!
57 |
58 | ## 2. Test
59 |
60 | To test FuncUnit, Steal, CanJS, and jQuery++ combined open
61 | javascriptmvc/test.html in
62 | every supported browser and run:
63 |
64 | @codestart
65 | ./js test/run.js
66 | @codeend
67 |
68 | To test just the invidual projects, do the following:
69 |
70 | #### StealJS
71 |
72 | Open /steal/test/qunit.html
73 | in a browser.
74 |
75 | Run:
76 |
77 | @codestart
78 | ./js steal/test/run.js
79 | @codeend
80 |
81 | #### FuncUnit
82 |
83 | Open /funcunit/funcunit.html
84 | and /funcunit/qunit.html in every browser.
85 |
86 | Run:
87 |
88 | @codestart
89 | funcunit/envjs funcunit/funcunit.html
90 | @codeend
91 |
92 | #### CanJS
93 |
94 | Open /canjs/qunit.html
95 | in every browser.
96 |
97 | Run:
98 |
99 | @codestart
100 | ./js canjs/test/run.js
101 | @codeend
102 |
103 | #### jQuery++
104 |
105 | Open /jquerypp/qunit.html
106 | in every browser.
107 |
108 | Run:
109 |
110 | @codestart
111 | ./js jquerypp/test/run.js
112 | @codeend
113 |
114 |
115 | ## 3. Build
116 |
117 | Coming soon, but most projects have a build.js and so does framework.
118 |
119 | ## 4. Building the Docs
120 |
121 | Run:
122 | @codestart
123 | js jmvc\scripts\doc.js
124 | @codeend
125 |
126 | If you have problems, you might need to create a jmvc/docs folder.
127 | Pages like this one are found in jmvc/pages/.
128 |
129 | ## 4. Deploying the Docs
130 |
131 | Run:
132 | @codestart
133 | ruby scripts\deploy.rb
134 | @codeend
135 |
136 | First you need to add our EC2 private key in the scripts folder, named key. If you want to
137 | deploy, talk to Brian to get access to this key.
138 |
--------------------------------------------------------------------------------
/site/pages/developingwithgit.md:
--------------------------------------------------------------------------------
1 | @page developwithgit Developing With Git
2 |
3 | Thank you so much for developing with git. You're making
4 | the world better for yourself and others. With GIT we can see any change
5 | you make to JavaScriptMVC and share them with other people.
6 |
7 | Before we get started, we're assuming you:
8 |
9 | - know git
10 | - have a github account setup
11 | - have a project that is already using git
12 |
13 | If you don't, you might find the following resources helpful:
14 |
15 | - [http://git.or.cz/course/svn.html Git - SVN Crash Course]
16 | - [http://github.com/ Github] - create an account here
17 | - [http://help.github.com/msysgit-key-setup/ SSH Key Setup]
18 |
19 | ## Git-ing JavaScriptMVC
20 |
21 | JavaScriptMVC is comprised of 7 sub projects:
22 |
23 | - [http://github.com/bitovi/steal]
24 | - [http://github.com/bitovi/canjs]
25 | - [http://github.com/bitovi/jquerypp]
26 | - [http://github.com/bitovi/documentjs]
27 | - [http://github.com/bitovi/funcunit]
28 | - [http://github.com/bitovi/syn]
29 | - [https://github.com/bitovi/jmvc-generators]
30 |
31 | We're going to fork each of these projects and add them as submodules to your
32 | master git project.
33 |
34 | #### Forking
35 |
36 | Assuming you have a github account set up, and are signed in,
37 | click each of the github links and click
38 | the fork button (in the upper right of the page).
39 |
40 | @image site/images/fork.png
41 |
42 | > TIP: If you're working for a company, you should create company forks and give
43 | employees access to the company forks. This will keep everyone using the
44 | same version.
45 |
46 | #### Installing with a script
47 |
48 | To make the next several steps easier, we've made scripts for [https://github.com/bitovi/javascriptmvc/raw/master/scripts/getjmvc Mac]
49 | and [https://github.com/bitovi/javascriptmvc/raw/master/scripts/getjmvc.bat Windows] users that automate adding your repos and setting them up.
50 |
51 | _Note: For the Mac script, be sure to set permissions to run locally._
52 | @codestart text
53 | chmod 755 getjmvc
54 | @codeend
55 |
56 | Use this script to install JMVC from github or your own fork. If its already installed, it will get latest for all the submodules.
57 | Assumes your project uses git.
58 |
59 | ##### Options
60 |
61 | - -u username (default is bitovi)
62 | - -b branch (default is master)
63 | - -s source url (default is https://github.com)
64 | - -p install path (default is current directory)
65 |
66 | ##### Usage
67 |
68 | Windows users can ignore the ./ in the path:
69 |
70 | Default usage. This will install from https://bitovi@github.com:bitovi/steal.git
71 | @codestart text
72 | ./getjmvc
73 | @codeend
74 |
75 | Use your own forked submodule repositories. This will install from https://github.com/mycompany/steal.git
76 | @codestart text
77 | ./getjmvc -u mycompany
78 | @codeend
79 |
80 | Install to your own path. You can specify the path where the submodules are installed, like to public/
81 | @codestart text
82 | ./getjmvc -p public/
83 | @codeend
84 |
85 | Install a different branch (used to install the 2.0 branches for steal, canjs, jquerypp, and funcunit).
86 | @codestart text
87 | ./getjmvc -b 2.0
88 | @codeend
89 |
90 | Install from a different repository (not github) or from ssh instead of http (if you have write access).
91 | @codestart text
92 | ./getjmvc -s git@github.com
93 | ./getjmvc -s http://mygitrepo.com
94 | @codeend
95 |
96 | Update code. If you installed somewhere besides the current directory, specify a -p. This will update code in each submodule.
97 | @codestart text
98 | ./getjmvc
99 | ./getjmvc -p public/
100 | @codeend
101 |
102 | Note: This script installs steal, documentjs, canjs, jquerypp, and funcunit, and it downloads syn from whatever is in funcunit/.gitmodules.
103 | If you wish to fork your own syn and use that fork, you have to change your funcunit/.gitmodules to point to the right location manually.
104 | Check it in and future installs will work fine.
105 |
106 | If you just want a certain repo, or you like doing things the hard way, here's how to get each project yourself:
107 |
108 | #### Adding a submodule
109 |
110 | Now add the first four forked repositories as submodules
111 | to your project like:
112 |
113 | @codestart text
114 | git submodule add git@github.com:_YOU_/steal.git public/steal
115 | git submodule add git@github.com:_YOU_/canjs.git public/canjs
116 | git submodule add git@github.com:_YOU_/jquerypp.git public/jquerypp
117 | git submodule add git@github.com:_YOU_/documentjs.git public/documentjs
118 | git submodule add git@github.com:_YOU_/funcunit.git public/funcunit
119 | git submodule add git@github.com:_YOU_/jmvc-generators.git public/jmvc
120 | @codeend
121 |
122 | _Note_: Learn a little more about submodules [here](http://johnleach.co.uk/words/archives/2008/10/12/323/git-submodules-in-n-easy-steps Submodules).
123 |
124 | There are 3 important things to notice:
125 |
126 | 1. Change _YOU_ with your github username.
127 |
128 | 2. Add the submodules in a public folder, where the server hosts static content.
129 |
130 | 3. Copy the javascriptmvc repository into a jquery folder.
131 |
132 | Next, you have to install and update the submodules. Run:
133 |
134 | @codestart
135 | git submodule init
136 | git submodule update
137 | @codeend
138 |
139 | You may also have to change to each directory and checkout the master branch:
140 |
141 | @codestart
142 | cd steal
143 | git checkout master
144 | @codeend
145 |
146 | #### Installing Syn
147 |
148 | Syn is a submodule of the funcunit project. To add your fork to funcunit,
149 | first you have to change the submodule to point to your fork
150 | (because it points to the bitovi fork). To do this, open funcunit/.gitmodules. You'll see:
151 |
152 | @codestart text
153 | [submodule "syn"]
154 | path = syn
155 | url = git@github.com:bitovi/syn.git
156 | update = merge
157 | @codeend
158 |
159 | Change the URL to your own fork, like:
160 |
161 | @codestart text
162 | url = git@github.com:_YOU_/syn.git
163 | @codeend
164 |
165 | Now install syn, like the other submodules:
166 |
167 | @codestart
168 | cd funcunit
169 | git submodule init
170 | git submodule update
171 | cd syn
172 | git checkout master
173 | @codeend
174 |
175 | Finally, you just have to move the 'js' commands out of steal for convienence:
176 |
177 | @codestart text
178 | [WINDOWS] > steal\js steal\make.js
179 |
180 | [Lin/Mac] > ./steal/js steal/make.js
181 | @codeend
182 |
183 | Yes, that was more annoying then just downloading it, but you're making the
184 | world a better place for yourself and for others.
185 |
186 |
--------------------------------------------------------------------------------
/site/pages/folders.md:
--------------------------------------------------------------------------------
1 | /**
2 | @page folders Folder and File Organization
3 |
4 | This hasn't been filled out yet. Ping us and we
5 | will. For now, this is a place holder.
6 |
7 | Here's what it should dicuss:
8 |
9 | - The app folder and file structure
10 | - The plugin file structure
11 | - a plugins folder
12 | - How apps and plugins should work together
13 | - Maybe sharing your plugins folder
14 |
15 | Here's some text from the old docs that
16 | might be useful.
17 |
18 |
19 |
cookbook.js
20 |
The application file,
21 | load plugins and other JavaScript files.
22 |
cookbook.html
23 |
A page that loads your application.
24 |
25 |
funcunit.html
26 |
A page that runs your functional tests.
27 |
28 |
qunit.html
29 |
A page that runs your qunit tests.
30 |
31 |
test/
32 |
A folder for your qunit and funcunit tests.
33 |
34 |
docs/
35 |
A folder for your documentation files.
36 |
37 |
scripts/
38 |
Scripts to document and compress your application.
39 |
40 |
41 |
controllers/
42 |
A folder for code that manages events.
43 |
models/
44 |
A folder code that manages Ajax requests.
45 |
view/
46 |
A folder for client side templates
47 |
resources/
48 |
A folder for 3rd party plugins and scripts.
49 |
fixtures/
50 |
A folder for simulated ajax responses (So you don't have to wait on the slow poke backenders).
51 |
52 |
53 | */
--------------------------------------------------------------------------------
/site/pages/help.md:
--------------------------------------------------------------------------------
1 | @page help Get Help
2 |
3 |
10 |
11 | [http://jupiterit.com Jupiter], the company that maintains JavaScriptMVC,
12 | provides premium [http://jupiterit.com/support.html support] and
13 | [http://jupiterit.com/training.html training]
14 | for JavaScriptMVC at affordable prices. This is the best way to rapidly progress on
15 | your project.
16 |
17 |
27 |
28 | JMVC's documentation is searchable. Type in the input on the top right.
29 |
--------------------------------------------------------------------------------
/site/pages/learn.js:
--------------------------------------------------------------------------------
1 | /*
2 | @page learn 3. Learn
3 |
4 |
5 | JavaScriptMVC contains pretty much everything
6 | you need to develop, test, and maintain a
7 | JavaScript application. Instead of learning
8 | an API, learning JavaScriptMVC is more
9 | about learning HOW to build an application.
10 |
11 | ## The Basics
12 |
13 |
14 | Watch
15 | 2.0 Video
16 | Before you do anything, watch
17 | the 2.0 Video.
18 | It's a 12 min brain dump that will highlight most of JMVC's features.
19 |
20 |
21 |
22 |
23 | You might be asking yourself a frequently asked question:
24 |
25 |
26 | #### Who should use JMVC?
27 |
28 | JMVC is designed for large, single-page JavaScript applications
29 | that require lots of custom code (something like [http://gmail.com GMail]).
30 | It fits between low-level libraries like jQuery and widget libraries like
31 | jQueryUI.
32 |
33 | If you need to organize, test, maintain, or compress a JavaScript
34 | application, JavaScriptMVC will help.
35 |
36 | #### How does JMVC fit into my project?
37 |
38 | JMVC is based around the principles of Service Oriented Architecture (SOA) and
39 | Thin Server Architecture (TSA). This means your server
40 | produces raw (preferably REST) services and never sends data in HTML.
41 |
42 | Read a [http://blog.javascriptmvc.com/?p=68 1.5 article] how it looks
43 | from within a rails application:
44 |
45 |
46 |
47 | For information on the benefits of TSA, watch [http://www.youtube.com/watch?v=XMkIZZ7dBng Practical Thin Server Architecture].
48 |
49 | #### Does JMVC work with a Java/PHP/Rails/etc backend?
50 |
51 | Yes, JMVC will will work with any backend service. It
52 | prefers to consume JSON Rest services, but it's flexible
53 | enough to work from
54 | anything.
55 |
56 | #### Do you have any example code?
57 |
58 | We are trying to get move public source available, but for now check out:
59 |
60 | - Srchr - demo app
61 | - MXUI - jQueryMX UI widgets.
62 |
63 |
64 | #### How does JMVC compare to other JS Frameworks?
65 |
66 | JMVC has the gamut of features to support the most complex JS applications.
67 | But it's most important feature, and its most unique,
68 | is its event delegation support organized
69 | via [jQuery.Controller controllers]. If you haven't used controllers to organize event handling in
70 | JavaScript, you haven't really programmed JavaScript.
71 |
72 |
73 | ## Model View Controller
74 |
75 | There are only 4 things you will ever do with JavaScript! JMVC breaks these down into the
76 | Model-View-Controller architecture.
77 |
78 |
79 | - Respond to events -> [jQuery.Controller Controller]
80 | - Get data and manipulate services (Ajax) -> [jQuery.Model Model] Static functions
81 | - Wrap service data with domain specific information -> [jQuery.Model Model] Prototype functions
82 | - Update the page -> [jQuery.Controller Controller] and [jQuery.View View]
83 |
84 |
85 | Here's how that flow looks:
86 |
87 |
88 |
89 | Think how this would work with the google auto-suggest.
90 |
91 |
92 |
93 | - Respond to typing "JavaScriptMVC" -> [jQuery.Controller Controller].
94 | - Get search suggestions -> [jQuery.Model Model] Static functions.
95 | - Wrap search data -> [jQuery.Model Model] Prototype functions. Not really important here!
96 | - Draw suggestions -> [jQuery.Controller Controller] and [jQuery.Controller View].
97 |
98 |
99 | ## Development Tools?
100 |
101 | JavaScriptMVC supplies a host of JS tools including:
102 |
103 | - [generators Code generators]
104 | - [steal Dependancy management]
105 | - [FuncUnit Testing]
106 | - [steal.build Compression]
107 | - [DocumentJS Documentation]
108 |
109 | ## How do I get help?
110 |
111 | Write on our [http://forum.javascriptmvc.com/ forum].
112 |
113 | ## How do I report errors, or contribute code?
114 |
115 | Submit patches or errors in [https://github.com/jupiterjs github].
116 |
117 | */
118 |
119 | //break
--------------------------------------------------------------------------------
/site/pages/why.js:
--------------------------------------------------------------------------------
1 | /*
2 | @page why 0. Why JavaScriptMVC
3 |
4 |
5 | So you've read through the list of features and you're still not
6 | convinced JavaScriptMVC is right for you. If you're looking for
7 | a little (extremely biased) advice, you've come to the
8 | right place.
9 |
10 | ## Who Should Use JavaScriptMVC?
11 |
12 | JavaScriptMVC is designed to enhance jQuery development
13 | for medium to large projects. You should care about
14 | code quality, performance, and maintainability.
15 |
16 | If you don't care about these things, or think jQuery is enough
17 | for any project,
18 | you don't know what you're doing, and you will
19 | embarrass the project by using it. Leave now.
20 |
21 | If you do care, here's how JavaScriptMVC helps you:
22 |
23 |
24 | JavaScriptMVC makes everything you should be doing, as easy as possible!
25 |
26 |
27 | Here's a few things you should be doing:
28 |
29 | - Testing (especially automatic and functional testing)
30 | - Documenting
31 | - Breaking up code into logically organized files
32 | - Compressing and concatenating your JavaScript files
33 | - Using and organizing client side templates
34 | - Making plugins that clean themselves up, are internally organized, and extendable.
35 | - Error reporting
36 |
37 | All of these things are hard or impossible to do right with jQuery alone.
38 |
39 | You can add your own automated testing library -
40 | QUnit isn't automated, it's difficult to write Selenium tests.
41 |
42 | You can add your own documentation engine - JSDoc, make sure you keep track of every file!
43 |
44 | You can add your own way of loading and compressing scripts - RequireJS.
45 |
46 | You can use other client side template libraries - jquery-tmpl, but you won't be able to compress them into your build or put them in external files as easily.
47 |
48 | You can be careful to structure your jQuery plugins so they can be easily removed from an element, remove all event handlers, and provide some mechanism for extending or overwriting your plugin.
49 |
50 | You can devise your own way of doing error reporting.
51 |
52 | ### OR ...
53 |
54 | You can download JavaScriptMVC and run:
55 |
56 | @codestart text
57 | js steal/generate/app APPNAME
58 | @codeend
59 |
60 | and get all of these things for free.
61 |
62 | JavaScriptMVC's greatest strength is it's integration.
63 | Everything you should be doing is available immediately.
64 |
65 | ## Ease of Adoption
66 |
67 | Despite the huge amount of features, JavaScriptMVC is
68 | easy to learn.
69 |
70 | Every component includes:
71 |
72 | - thorough documentation
73 | - demo examples
74 | - test pages
75 | - a write-up on JavaScriptMVC's blog.
76 |
77 | We are extremely active on the forums, with essentially
78 | zero unanswered questions.
79 |
80 | We've released a number of mini apps that are built the
81 | JavaScriptMVC way.
82 |
83 | Jupiter Consulting provides JavaScriptMVC training, support,
84 | and consulting services.
85 |
86 |
87 |
88 | */
89 |
90 |
91 | //break
--------------------------------------------------------------------------------
/site/scripts/build.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | site Build Page
6 |
7 |
8 |
site Build Page
9 |
This is a dummy page that loads your app so steal can
10 | get all the files.
11 |
12 |
If you built your app
13 | to depend on HTML in the page before DOMContent loaded or
14 | onload, you can add the HTML here, or you can change the
15 | build.js script to point to a better html file.
16 |
18 |
19 |
20 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/tutorials/ajaxy/ajaxy.md:
--------------------------------------------------------------------------------
1 | @page ajaxy Searchable Ajax Apps
2 | @parent tutorials 8
3 |
4 | This tutorial walks you through building a simple widget
5 | that listens for changes in the browser location hash
6 | and updates the content of the page. It demonstrates how to make
7 | a site Google crawlable and searchable.
8 |
9 | ## The App
10 |
11 | We'll make a mini app that updates the contents of page with an
12 | Ajax request when a user clicks on a navigation link. Then, we'll make this searchable
13 | with the ajaxy/scripts/crawl.js script.
14 |
15 | @demo tutorials/ajaxy/ajaxy.html 500
16 |
17 | The crawl script generates html pages that Google can use as a representation
18 | of the content of an Ajax application. Read Google's documentation on its
19 | [Ajax crawling API](https://developers.google.com/webmasters/ajax-crawling/docs/getting-started)
20 | before continuing this tutorial.
21 |
22 | ## Setup
23 |
24 | [installing Download and install] the latest version of JavaScriptMVC.
25 |
26 | After installing JavaScriptMVC, open a command line to
27 | the [steal.config.root steal.config.root] folder (where you unzipped
28 | JavaScriptMVC).
29 |
30 |
31 | We'll use the application generator to generate an application
32 | skeleton folder. Run:
33 |
34 | [WINDOWS] > js jmvc/generate/app ajaxy
35 | [Lin/Mac] > ./js jmvc/generate/app ajaxy
36 |
37 | ## The Code
38 |
39 | In the generated ajaxy folder, you'll find ajaxy.html
40 | and ajaxy.js. We'll add a content area
41 | and few links to
42 | ajaxy.html. When we click on links,
43 | we'll make ajaxy.js load content into
44 | the content area.
45 |
46 | Change ajaxy.html so it looks like:
47 |
48 | @codestart xml
49 | <!DOCTYPE HTML>
50 | <html lang="en">
51 | <head>
52 | <title>Ajaxy</title>
53 | <meta name="fragment" content="!">
54 | </head>
55 | <body>
56 | <a href='#!videos'>Videos</a>
57 | <a href='#!articles'>Articles</a>
58 | <a href='#!images'>Images</a>
59 | <div id='content'></div>
60 | <script type='text/javascript'
61 | src='../steal/steal.js?ajaxy,development'>
62 | </script>
63 | </body>
64 | </html>
65 | @codeend
66 |
67 | Notice that the page includes a <meta name="fragment" content="!">
68 | tag. This tells to Google to process ajaxy.html as having Ajax content.
69 |
70 | Next, add some content to show when these links are clicked. Put the following content
71 | in each file:
72 |
73 | __ajaxy/fixtures/articles.html__
74 |
75 | @codestart xml
76 | <h1>Articles</h1>
77 | <p>Some articles.</p>
78 | @codeend
79 |
80 | __ajaxy/fixtures/images.html__
81 |
82 | @codestart xml
83 | <h1>Images</h1>
84 | <p>Some images.</p>
85 | @codeend
86 |
87 | __ajaxy/fixtures/videos.html__
88 |
89 | @codestart xml
90 | <h1>Videos</h1>
91 | <p>Some videos.</p>
92 | @codeend
93 |
94 | Finally, change ajaxy.js to look like:
95 |
96 | steal('jquery',
97 | 'can/construct/proxy',
98 | 'can/control',
99 | 'can/route',
100 | 'steal/html',
101 | function($, can){
102 |
103 | var Ajaxy = can.Control({
104 | "{route} change" : function(route, ev){
105 | this.updateContent(route.page)
106 | },
107 | updateContent : function(hash){
108 | // postpone reading the html
109 | steal.html.wait();
110 |
111 | $.get("fixtures/" + hash + ".html", {}, this.proxy('replaceContent'), "text")
112 | },
113 | replaceContent : function(html){
114 | this.element.html(html);
115 |
116 | // indicate the html is ready to be crawled
117 | steal.html.ready();
118 | }
119 | })
120 |
121 | new Ajaxy('#content', { route: can.route(":page", { page: "videos" }) });
122 |
123 | });
124 |
125 | When a route ("{route} change") event occurs, Ajaxy
126 | uses the route.page value to make a
127 | request ($.get)
128 | for content in thefixtures folder. For more information
129 | on routing, visit [can.route].
130 |
131 | When the content is retrieved, it replaces the element's
132 | html (this.element.html(...)).
133 |
134 | Ajaxy also calls updateContent to load content when
135 | the page loads initially.
136 |
137 | ## Crawling and scraping
138 |
139 | To crawl your site and generate google-searchable html, run:
140 |
141 | @codestart none
142 | [WINDOWS] > js ajaxy\scripts\crawl.js
143 | [Lin/Mac] > ./js ajaxy/scripts/crawl.js
144 | @codeend
145 |
146 | This script peforms the following actions:
147 |
148 | 1. Opens a page in a headless browser.
149 | 2. Waits until its content is ready.
150 | 3. Scrapes its contents.
151 | 4. Writes the contents to a file.
152 | 5. Adds any links in the page that start with #! to be indexed
153 | 6. Changes the url hash to the next index-able page
154 | 7. Goto #2 and repeats until all pages have been loaded
155 |
156 |
157 | ## Pausing the html scraping.
158 |
159 | By default, the contents are scraped immediately after the page's scripts have loaded or
160 | the route has changed. The Ajax request for content
161 | happens asynchronously so we have to tell [steal.html] to wait to scrape the content.
162 |
163 | To do this, Ajaxy calls:
164 |
165 | steal.html.wait();
166 |
167 | before the Ajax request. And when the page is ready, Ajaxy calls:
168 |
169 | steal.html.ready();
170 |
171 | ## Getting Google To Crawl Your Site
172 |
173 | If you haven't already, read up on
174 | Google's [Ajax crawling API.](https://developers.google.com/webmasters/ajax-crawling/docs/getting-started)
175 |
176 | When google wants to crawl your site, it will send a
177 | request to your page with \_escaped\_fragment=.
178 |
179 | When your server sees this param, redirect google to the generated html page. For example, when the Google Spider requests http://mysite.com?\_escaped\_fragment=val, this is its attempt to crawl http://mysite.com#!val. You should redirect this request to http://mysite.com/html/val.html.
180 |
181 | Yes, it's that easy!
182 |
183 | ## Phantom for Advanced Pages
184 |
185 | By default the crawl script uses EnvJS to open your page and build a static snapshot. For some pages, EnvJS won't be powerful enough to accurately simulate everything. If your page experiences errors, you can use PhantomJS (headless Webkit) to generate snapshots instead, which may work better.
186 |
187 | To turn on Phantom:
188 |
189 | 1. Install it using the install instructions [funcunit.phantomjs here]
190 | 1. Open scripts/crawl.js and change the second parameter of steal.html.crawl to an options object with a browser option, like this:
191 |
192 | @codestart
193 | steal('steal/html', function(){
194 | steal.html.crawl("ajaxy/ajaxy.html",
195 | {
196 | out: 'ajaxy/out',
197 | browser: 'phantomjs'
198 | })
199 | })
200 | @codeend
--------------------------------------------------------------------------------
/tutorials/ajaxy/fixtures/articles.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tutorials/cms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/cms.png
--------------------------------------------------------------------------------
/tutorials/done.md:
--------------------------------------------------------------------------------
1 | @page done Upgrading to 3.3
2 | @parent tutorials 11
3 |
4 | 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.
5 |
6 | ## CanJS
7 |
8 | [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.
9 |
10 | ## Steal
11 |
12 | [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.
13 |
14 | So, as a simple example:
15 |
16 | steal('fooResource', function(foo) {});
17 |
18 | In the above example, "foo" refers to the module returned by fooResource/fooResource.js.
19 |
20 | This leads to the gotcha when defining "$" in the previous syntax. So code that used to look like:
21 |
22 | steal('jquery', 'someResource')
23 | .then('someController', function($) {});
24 |
25 | The above will not work as expected, because "$" will refer to a module returned by "someController" or undefined. In 3.3, a simple change will fix this issue for jQuery users:
26 |
27 | steal('jquery', 'someResource')
28 | .then('someController', function() {});
29 |
30 | ## $.Class.prototype.callback
31 |
32 | "callback" has been deprecated and is now "proxy" to match jQuery's API.
33 |
34 | 3.2:
35 |
36 | $.Controller('foo', {}, {
37 | init: function() {
38 | $.get('/resource', this.callback('render'));
39 | },
40 |
41 | render: function() {}
42 | });
43 |
44 | 3.3:
45 |
46 | $.Controller('foo', {}, {
47 | init: function() {
48 | $.get('/resource', this.proxy('render'));
49 | },
50 |
51 | render: function() {}
52 | });
53 |
54 | ## $.View
55 |
56 | $.View() now returns a document fragment to aid with faster rendering within your application. However, when nesting templates, you'll need the actual html string returned by $.View.render as opposed to the document fragment.
57 |
58 | Within your EJS templates in 3.2:
59 |
60 |
--------------------------------------------------------------------------------
/tutorials/examples.md:
--------------------------------------------------------------------------------
1 | @page examples Examples
2 | @parent javascriptmvc 6
3 | @description Example application to learn from.
4 |
5 | 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.
6 |
7 | ## [todo TodoMVC JavaScriptMVC] - [open application ⇗](tutorials/examples/todo.html)
8 |
9 | In this guide, we're going to be installing and walking through the simplest [JavaScriptMVC](http://javascriptmvc.com/)
10 | application imaginable — a TODO list manager.
11 |
12 | This article covers:
13 |
14 | - Separation of application logic from user interface
15 | - Using model lists to manage collection of models
16 |
17 | ## [srchr Srchr] - [open application ⇗](srchr/srchr.html)
18 |
19 | Srchr searches multiple services (like Flickr, Upcoming, and Twitter) and saves the results between page requests.
20 |
21 | This article covers:
22 |
23 | - The ideas behind JavaScriptMVC
24 | - How JavaScriptMVC enables code separation
25 | - Event oriented architecture
26 |
27 | ## [contacts Contacts] - [open application ⇗](contacts)
28 |
29 | The contacts example is a lightweight application that allows users to add and organize their friend's contact information.
30 |
31 | This article covers:
32 |
33 | - Installing and running the application
34 | - The application's structure and organization
35 | - How the application's widgets were designed
36 | - The anatomy of the application's widgets
37 | - How we glued the application's widgets together using event-oriented-architecture
38 |
--------------------------------------------------------------------------------
/tutorials/examples/contacts.md:
--------------------------------------------------------------------------------
1 | @page contacts Contacts
2 | @parent examples 3
3 |
4 | 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.
5 |
6 | This tutorial describes:
7 |
8 | - Installing and running the application
9 | - The application's structure and organization
10 | - Dividing the application into modular widgets
11 | - Tieing the widgets together
12 |
13 | @image ../tutorials/images/contacts_preview.png
14 |
15 | Let's get started!
16 |
17 | ## Setup
18 |
19 | The application source is hosted by [GitHub](https://github.com/bitovi/contacts). You can download the application on github using the following commands:
20 |
21 | $ git clone https://github.com/bitovi/contacts
22 | $ cd contacts
23 | $ git submodule update --init
24 |
25 | 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.
26 |
27 | This will run the application in development mode. If you want to build and run the application in production, in the command line run:
28 |
29 | $ ./js contacts/scripts/build.js
30 |
31 | then change the script tag in `contacts.html` to be in production mode:
32 |
33 |
34 |
35 | Additionally, the app can be found on [Github Pages](http://bitovi.github.io/contacts/) if you do not want to set it up.
36 |
37 | ## Folder Structure
38 |
39 | 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.
40 |
41 | [top-level]
42 | /can
43 | /steal
44 | /funcunit
45 | /contacts
46 | /form
47 | /scripts
48 | /test
49 | /models
50 | /fixtures
51 | /views
52 | /less
53 | funcunit.html
54 | qunit.html
55 | contacts.js
56 | ...
57 | contacts.html
58 | stealconfig.js
59 |
60 | The contacts folder contains:
61 |
62 | - `models` AJAX end-point definitions and helpers
63 | - `views` EJS/Mustache can.view templates
64 | - `fixtures` simulated AJAX response
65 | - `less` LESS stylesheet such as [Boostrap](http://twitter.github.io/bootstrap/) 3.0 and `contacts.less`
66 | - `contacts/form` child components of contacts
67 |
68 | Along with runners and scripts for building and tests.
69 |
70 | ## Division of Modules
71 |
72 | 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.
73 |
74 | The goal for dividing your application should be to create modules that are isolated.
75 |
76 | Isolated modules are:
77 |
78 | - Limited to one specific purpose, for example showing a list of data
79 | - Rarely reference other modules and never their parents
80 | - Have a simple generic API making them easy to swap out
81 |
82 | 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.
83 |
84 | ### Dividing Contacts
85 |
86 | The contacts app has 3 lists that filter the grid of contacts. You can create additional categories and contacts by clicking the 'new' icon.
87 |
88 | This application can be divided up into a few widgets:
89 |
90 | * List - accepts a generic data source and layout, renders and updates the list.
91 | * Grid - accepts a generic data source, renders a grid.
92 | * Form - create a new instance from a data source.
93 |
94 | Heres a visual representation of how this app is broken up into modules.
95 |
96 | @image ../tutorials/images/contacts_design.png
97 |
98 | ## Tying it all together
99 |
100 | `contacts/contacts.js` will be where the application starts: loading each module, initializing them, and gluing them together.
101 |
102 | In the `init` method, we initalize all the base objects and inject the base view.
103 |
104 | init: function(){
105 | // initalize the lists and objects
106 | this.categoryList = new Models.Category.List;
107 | this.locationList = new Models.Location.List;
108 | this.companyList = new Models.Company.List;
109 | this.contactsList = new Models.Contact.List;
110 | this.edited = new Observe;
111 | this.total = can.compute(0);
112 | this.isLoading = can.compute(function(loading){
113 | loading ? loadingCounter++ : loadingCounter--;
114 | return loading > 0;
115 | });
116 |
117 | // Draw the view, setup helpers and partials
118 | this.element.html(initView({ ... });
119 |
120 | // Initalize each Form category
121 | can.each(['location', 'category',
122 | 'company', 'contact'], function(formType){
123 | new Form(this.element.find('#' + formType), {
124 | edited : this.edited,
125 | model : Models[can.capitalize(formType)],
126 | list : this[formType + 'List']
127 | });
128 | }.bind(this));
129 |
130 | this.setupScroll();
131 | this.loadFilters();
132 | this.loadContacts();
133 | }
134 |
135 | From this point on, the application uses live-binding to update the lists/views based on the filter/offset.
136 |
137 | {{#contacts}}
138 | {{>contact}}
139 | {{/contacts}}
140 |
141 | As the `contacts` list changes, the view automatically updates to reflect the new list.
142 |
143 | ## Wrapup
144 |
145 | In this article, we explored:
146 |
147 | - Installing and running the application
148 | - The application's structure and organization
149 | - Dividing the application into modular widgets
150 | - Tieing the widgets together
151 |
152 | If you're interested in other examples, check out the other application examples.
--------------------------------------------------------------------------------
/tutorials/examples/srchr.md:
--------------------------------------------------------------------------------
1 | @page srchr Srchr
2 | @parent examples 0
3 |
4 | Srchr searches several data sources for content and
5 | displays it to the user. See it in
6 | action [here](http://javascriptmvc.com/srchr/srchr.html). This article
7 | covers how to install Srchr. To understand how Srchr works and many
8 | of the core concepts behind JavaScriptMVC, please watch:
9 |
10 | - [Part 1 - MVC architecture and the observer pattern](http://www.youtube.com/watch?v=NZi5Ru4KVug)
11 | - [Part 2 - Development process](http://www.youtube.com/watch?v=yFxDY5SQQp4)
12 |
13 |
14 | ## Installing Srchr
15 |
16 |
17 | Install the Srchr app by cloning the git repo:
18 |
19 | > git clone git://github.com/bitovi/srchr srchr
20 | > cd srchr
21 | > git submodule update --init --recursive
22 |
23 | Once you get the application you should have a structure similar to below
24 |
25 | /srchr [top-level directory]
26 | /can
27 | /documentjs
28 | /steal
29 | /funcunit
30 | /srchr
31 | /history
32 | /models
33 | /scripts
34 | /search
35 | /search_result
36 | /tabs
37 | /templates
38 | /test
39 | test.html
40 | srchr.less
41 | srchr.js
42 | srchr.html
43 | ...
44 |
45 | Srchr is now ready to be used. To run the Srchr application simply open _srchr/index.html_ in your browser.
46 |
47 |
--------------------------------------------------------------------------------
/tutorials/examples/todo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | CanJS • TodoMVC
7 |
8 |
9 |
10 |
11 |
16 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/tutorials/funcunit.md:
--------------------------------------------------------------------------------
1 | @page funcunit.getstarted Get Started with FuncUnit
2 | @parent tutorials 6
3 |
4 | @body
5 |
6 | In this guide, we'll use [FuncUnit] to write functional tests for the jQuery UI
7 | autocomplete widget. We'll go over:
8 |
9 | * Running a test in browser
10 | * Writing a test
11 | * Debugging a broken test
12 | * Running tests via Selenium
13 | * Running tests via PhantomJS
14 |
15 | ## Running Autocomplete Tests
16 |
17 | Open _funcunit/test/autosuggest/autosuggest.html_ in a browser. Type "J" in the input. You'll see the following:
18 |
19 | @image funcunit/pages/images/autosuggest.png
20 |
21 |
22 | This page is a simple demo app, using [jQueryUI autocomplete](http://jqueryui.com/demos/autocomplete/). It
23 | shows results when you start typing, then you can click a result (or use mouse navigation) to populate the input.
24 |
25 | There is a test already written. Open funcunit/test/autosuggest/autosuggest_test.js in your IDE:
26 |
27 | @codestart
28 | module("autosuggest",{
29 | setup: function() {
30 | S.open('autosuggest.html')
31 | }
32 | });
33 |
34 | test("results appear",function(){
35 | S('input').visible().click().type("Java")
36 |
37 | // wait until we have some results
38 | S('.ui-menu-item').visible(function(){
39 | equal( S('.ui-menu-item').size(), 2, "there are 2 results")
40 | })
41 | });
42 | @codeend
43 |
44 | As you can probably tell, the [funcunit.finding S method] is an alias for jQuery (*). This test:
45 |
46 | 1. Opens autosuggest.html
47 | 1. Grabs the input element, clicks it, and types "Java"
48 | 1. Grabs the element that is populated with results, waits for it to be visible
49 | 1. Asserts that there are 2 results shown
50 |
51 | (*) Actually its a [http://api.jquery.com/jQuery.sub/ copy] of jQuery that performs queries in
52 | the application window by default, and sometimes caches its selector to run asynchronously.
53 |
54 | To run this test, open funcunit/test/autosuggest/funcunit.html in any browser (turn off your popup blocker). The test will open and run. The results are shown in the QUnit page:
55 |
56 | @image funcunit/pages/images/qunit.png
57 |
58 |
59 | ## Writing an Autocomplete Test
60 |
61 | Next we'll add a test for selecting a result with the keyboard. FuncUnit's [apifuncunit API] consists of:
62 |
63 | * [funcunit.finding The S Method] - Perform a query in the application window
64 | * [funcunit.actions Actions] - Simulate user actions like [FuncUnit.prototype.click click], [FuncUnit.prototype.type type], [FuncUnit.prototype.drag drag]
65 | * [funcunit.waits Waits] - Wait for a condition in your page to be met. Fail the test if the condition isn't met before a timeout.
66 | * [funcunit.getters Assertions & getters] - Synchronously check a condition in your page.
67 |
68 | The setup and assertion methods are part of the [http://docs.jquery.com/Qunit QUnit] API.
69 |
70 | Our test should do the following:
71 |
72 | 1. Type "JavaS" in the input.
73 | 1. Wait for a result to be visible.
74 | 1. Select the input and press the down and enter keys to select the first item.
75 | 1. Wait for the input to show "JavaScript".
76 |
77 | Add the following under the first test:
78 |
79 | @codestart
80 | test("keyboard navigation",function(){
81 | S('input').visible().click().type("JavaS")
82 |
83 | S('.ui-menu-item').visible()
84 | S('input').type('[down][enter]')
85 | .val("JavaScript")
86 | });
87 | @codeend
88 |
89 | A few important notes about this test:
90 |
91 | 1. We have no assertions. This is ok. Most FuncUnit tests don't need them. If the wait conditions aren't met before a timeout, the test will fail. If the test completes, this feature is working.
92 | 1. The click, visible, and val methods are actually doing asynchronous things. FuncUnit lets you write tests with this linear syntax by queueing the actual methods and running them one by one. This is to prevent your tests from being an unreadable mess of nested functions like:
93 |
94 | @codestart
95 | S('.input').visible(function(){
96 | S('.input').click(function(){
97 | S('input').type("JavaS")
98 | })
99 | })
100 | @codeend
101 |
102 | Reload the funcunit.html page and see your new test run and pass.
103 |
104 | ## Debugging tests
105 |
106 | Now change .val("JavaScript") to .text("C#"). Reload the page and watch it timeout and fail.
107 |
108 | @image funcunit/pages/images/broken.png
109 |
110 |
111 | In this case, the error message shown is a good indication for why the test is broken. But often we need
112 | more visibility to debug a test.
113 |
114 | Your first debugging instinct might be "Let's add a breakpoint!". But, as noted, this
115 | code is running asynchronously. When .val() runs, its adding a method to
116 | FuncUnit.queue, not actually doing the check. When its this wait condition's turn to
117 | run, $("input").val() === "JavaScript" is checked repeatedly until its true or a timeout is reached.
118 |
119 | We can replace the string value with a checker function and use console.log to see what's going on. When
120 | previous queued methods finish, this function will run on repeat. Change that line to:
121 |
122 | @codestart
123 | .val(function(val){
124 | console.log(val, this)
125 | if(val === "C#") return true;
126 | });
127 | @codeend
128 |
129 | "this" in your wait method is the element that .text is being run against. The console will show the following:
130 |
131 | @image funcunit/pages/images/console.png
132 |
133 |
134 | Using this technique, you can inspect the state of your app at various points throughout the test. Undo
135 | this breaking change before moving on to the next part.
136 |
137 | ## Running in Selenium
138 |
139 | Next we'll run this same test via the browser automation tool Selenium. Open a
140 | command prompt to the JMVC directory and run the following:
141 |
142 | @codestart
143 | ./js funcunit/run selenium funcunit/test/autosuggest/funcunit.html
144 | @codeend
145 |
146 | On windows, just use "js" instead of ./js. This will open the test page in
147 | Firefox, run the same test, and report the results on the command line:
148 |
149 | @image funcunit/pages/images/commandline.png
150 |
151 |
152 | You can configure this step to run in any browser via the [integrations settings.js file].
153 |
154 | ## Running in PhantomJS
155 |
156 | Running in Selenium is great, but physically opening a browser can be too slow for quick
157 | regression testing. [http://www.phantomjs.org/ PhantomJS] is a headless version of WebKit, which can run the same
158 | tests from the commandline much faster without opening any visual browser windows. To run
159 | this step, first you must [funcunit.phantomjs PhantomJS]. Then run:
160 |
161 | @codestart
162 | ./js funcunit/open/phantomjs funcunit/test/autosuggest/funcunit.html
163 | @codeend
164 |
165 | Phantom opens your page, runs the same test, and reports results on the commandline.
166 | This step can be easily integrated in your build process via [funcunit.jenkins Jenkins] or [funcunit.maven Maven].
167 |
168 | ## Conclusion
169 |
170 | Hopefully, this guide illustrates how FuncUnit provides the holy grail of testing: easy, familiar syntax, in browser running for
171 | easy debugging, and simple automation.
172 |
173 | FuncUnit will transform your development lifecycle, give your developers confidence, and improve quality.
174 |
175 |
176 | That's it! If you want to learn more, read about FuncUnit's [FuncUnit API] and [funcunit.integrations integrations]
177 | or check out some [funcunit.demos demos].
--------------------------------------------------------------------------------
/tutorials/getstarted/Cookbook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/getstarted/Cookbook.png
--------------------------------------------------------------------------------
/tutorials/getstarted/Docs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/getstarted/Docs.png
--------------------------------------------------------------------------------
/tutorials/getstarted/Welcome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/getstarted/Welcome.png
--------------------------------------------------------------------------------
/tutorials/getstarted/building.md:
--------------------------------------------------------------------------------
1 | @page building.cookbook Building Cookbook
2 | @parent getstarted 2
3 |
4 | There is a large overhead associated with
5 | downloading many JavaScript and CSS files. [stealjs StealJS]
6 | can build your app into a single minified JS and CSS file
7 | for faster download.
8 |
9 |
10 | It can also break your app into cache-able minified parts
11 | for more advanced performance techniques.
12 |
13 |
14 | ## Build Script
15 |
16 | To build your application, run the following command from a console:
17 |
18 | > ./js cookbook/scripts/build.js
19 | Building to cookbook/
20 | ...
21 | Building cookbook/production.js
22 | cookbook/production.css
23 |
24 | Verify that production.js was created by checking your `cookbook` folder.
25 |
26 | ## Switch to Production Mode
27 |
28 | Switch to production mode by changing the script tag to include steal.production.js:
29 |
30 |
33 |
34 | ## Reload and verify
35 |
36 | Reload your page. Only two JavaScript files will load: steal.production.js and production.js.
37 | Not bad considering 28 files are loaded in development mode.
38 |
39 | When you're ready, learn how to [cookbook.documenting Document Cookbook]
--------------------------------------------------------------------------------
/tutorials/getstarted/documenting.md:
--------------------------------------------------------------------------------
1 | @page cookbook.documenting Documenting Cookbook
2 | @parent getstarted 3
3 |
4 | @body
5 |
6 | Documentation is a critical step in creating maintainable code.
7 | It's often burdensome on developers and
8 | becomes neglected. JavaScriptMVC's integrates [DocumentJS] to make
9 | it easy to document your code.
10 |
11 | ## Generating Documentation
12 |
13 | Create the docs by running:
14 |
15 | > ./js cookbook/scripts/docs.js
16 |
17 |
18 | ## Viewing Documentation
19 |
20 | Open __cookbook/docs/index.html__ and you'll find something like:
21 |
22 | @image ../tutorials/getstarted/Docs.png
23 |
24 | ## Writing Documentation
25 |
26 | The generated app comes with very minimal docs. But, it
27 | gives you a great place to
28 | start. Open __cookbook/cookbook.md__. This is the top level
29 | page for the cookbook application. Notice that it's markdown!
30 |
31 | The syntax for documentation is very similar to JavaDoc. However, there are some
32 | important differences. Consult the [DocumentJS DocumentJS's documentation]
33 | for more information.
34 |
35 | ## Next steps
36 |
37 | In the context of this trivial application, you've
38 | been exposed to major features of JavaScriptMVC:
39 |
40 | - code separation
41 | - testing
42 | - building
43 | - documentation
44 |
45 | This is pretty cool! Look at how simply you went from
46 | nothing to a compressed, tested, and documented application.
47 |
48 |
--------------------------------------------------------------------------------
/tutorials/getstarted/getstarted.md:
--------------------------------------------------------------------------------
1 | @page getstarted Get Started with JMVC
2 | @parent tutorials 2
3 |
4 | This guide introduces the most important aspects of JavaScriptMVC (JMVC) by
5 | creating a simple cookbook application.
6 |
7 | ## Basics
8 |
9 | Before jumping in, there are some things you should know:
10 |
11 | ### Purpose
12 |
13 | Use JavaScriptMVC to develop client-side JavaScript apps. JMVC was
14 | created by [http://bitovi.com Bitovi], a JavaScript consulting
15 | company, to create quality, maintainable apps in the shortest
16 | amount of time. Since that time, JMVC has undergone 7 primary production releases
17 | with over 100 outside contributors.
18 |
19 | Unlike most JavaScript projects, JMVC is a
20 | true __framework__. It supplies best-of-bread solutions for things like:
21 |
22 | - DOM manipulation
23 | - MVC Architecture
24 | - Testing
25 | - Dependency management
26 | - Documentation
27 |
28 | It tightly integrates these solutions so they
29 | work together seemlessly. With repeatable development
30 | patterns, JMVC provides __direction to development__ making it easy
31 | for teams to work together more
32 | effectively.
33 |
34 |
35 | ### Sub Projects
36 |
37 | JavaScriptMVC is comprised of 5 sub projects:
38 |
39 | - [canjs CanJS] - A client side MVC framework
40 | - [jquerypp jQuery++] - A collection of useful DOM helpers and special events for jQuery
41 | - [stealjs StealJS] - A code manager: dependency management, code cleaning, building, etc.
42 | - [DocumentJS DocumentJS] - A documentation engine
43 | - [FuncUnit FuncUnit] - A web testing framework
44 |
45 | ### Plugins
46 |
47 | Sub-projects are futher broken down into plugins. Just [steal] the ones you need. Plugins load
48 | their own dependencies and won't load duplicate files. It looks like:
49 |
50 | steal('can/control', function( Control ) {
51 | Control // -> the Control API
52 | ...
53 | });
54 |
55 |
56 | > _P.S. `steal('can/control')` adds `can/control/control.js` to your project._
57 |
58 |
59 | ## License
60 |
61 | JavaScriptMVC is MIT with the following exceptions:
62 |
63 | - [Rhino](http://www.mozilla.org/rhino/) - JS command line ([MPL 1.1](http://www.mozilla.org/MPL/))
64 | - [Selenium](http://seleniumhq.org/) - Browser Automation ([Apache 2](http://www.apache.org/licenses/LICENSE-2.0))
65 |
66 | These exceptions, although permissive licenses themselves, are not linked in your final production build.
67 |
68 | ## Installing JavaScriptMVC
69 |
70 | Before continuing, make sure you have [installing installed JavaScriptMVC]. Once you
71 | have installed JavaScriptMVC, continue to [cookbook.creating Creating Cookbook].
72 |
--------------------------------------------------------------------------------
/tutorials/getstarted/selenium-run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/getstarted/selenium-run.png
--------------------------------------------------------------------------------
/tutorials/getstarted/testing.md:
--------------------------------------------------------------------------------
1 | @page cookbook.testing Testing Cookbook
2 | @parent getstarted 1
3 |
4 | @body
5 |
6 | JavaScriptMVC puts a tremendous emphasis on
7 | testing. It uses [FuncUnit] to easily write
8 | tests that can be run in the browser or automated. FuncUnit
9 | integrates:
10 |
11 | - QUnit - Assertions and testing structure
12 | - Syn - Synthetic user events like clicking and typing
13 | - Selenium / PhantomJS - Browser automation
14 |
15 | When you scaffolded recipe, it created tests and test pages for you. This
16 | guide will show you how to:
17 |
18 | - Run tests.
19 | - Understand the unit tests.
20 | - Run functional tests.
21 | - Understand the functional tests.
22 | - Test isTasty functionality.
23 |
24 | ## Run Tests
25 |
26 | Open `cookbook/cookbook_test.js`. You'll notice it steals tests
27 | for the model and controls. There
28 | are also tests that verify the
29 | original "Welcome to JavaScriptMVC" text that we removed. __Remove__ the
30 | extraneous test so `cookbook_test.js` just looks like this:
31 |
32 | @codestart
33 | steal(
34 | 'funcunit',
35 | './models/recipe_test.js',
36 | 'cookbook/recipe/create/create_test.js',
37 | 'cookbook/recipe/list/list_test.js',
38 | function (S) {
39 |
40 | // this tests the assembly
41 | module("cookbook", {
42 | setup : function () {
43 | S.open("//cookbook/index.html");
44 | }
45 | });
46 |
47 | test("creating a recipes adds it to the list ", function () {
48 |
49 | S("[name=name]").type("Ice Water");
50 | S("[name=description]")
51 | .type("Pour water in a glass. Add ice cubes.");
52 |
53 | S("[type=submit]").click();
54 |
55 | S("h3:contains(Ice Water)").exists();
56 | S("p:contains(Pour water in a glass. Add ice cubes.)").exists()
57 | });
58 | });
59 | @codeend
60 |
61 | To run all of __cookbook's__ tests, open
62 | `cookbook/test.html` in a browser.
63 |
64 | To run those same tests with [funcunit.selenium Selenium], first you must set up a
65 | local server, like Apache, running at the javascriptmvc root. Make sure you can
66 | open your test page from this server, at a URL like http://localhost/javascriptmvc/cookbook/test.html.
67 |
68 | Then run:
69 |
70 | > ./js funcunit/open/selenium http://localhost/javascriptmvc/cookbook/test.html
71 |
72 | You should see something like:
73 |
74 | @image ../tutorials/getstarted/selenium-run.png
75 |
76 |
77 | If Selenium is unable to open your browsers, it's likely you have them in an
78 | unusual location. Read the Other Browsers section in [funcunit.selenium Selenium]
79 | docs for information on how to configure browsers so selenium can find them.
80 |
81 |
82 | Continue to [building.cookbook Building Cookbook] or continuen reading to learn how
83 | this code works.
84 |
85 | ## Tiered testing
86 |
87 | If an application should be built of small, isolated modules that are glued together, its tests should reflect that.
88 |
89 | 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`
90 | and it will run the tests in `cookbook/recipe/create/create_test.js`.
91 |
92 | To test the "glue", `cookbook_test.js` loads all modules' tests
93 | and provides an integration test, verifying the application as a whole works as expected.
94 |
95 | The following goes through:
96 |
97 | - cookbook/models/recipe_test.js
98 | - cookbook/recipe/create/create_test.js
99 | - cookbook/recipe/list/list_test.js
100 | - cookbook/cookbook_test.js
101 |
102 | ## recipe_test.js
103 |
104 | `cookbook/models/recipe_test.js` unit tests the
105 | `cookbook/models/recipe`, module which is aliased as Recipe. It starts
106 | by loading the `Recipe` model, QUnit, and the fixtures
107 | used to simulate the server:
108 |
109 | steal( "./recipe.js",
110 | "funcunit/qunit",
111 | "cookbook/models/fixtures",
112 | function( Recipe ){
113 |
114 | Next it specifies which module the following tests belong to:
115 |
116 | module("cookbook/models/recipe");
117 |
118 | Then, it defines a `findAll` test:
119 |
120 | test("findAll", function(){
121 | expect(4);
122 | stop();
123 | Recipe.findAll({}, function(recipes){
124 | ok(recipes)
125 | ok(recipes.length)
126 | ok(recipes[0].name)
127 | ok(recipes[0].description)
128 | start();
129 | });
130 | });
131 |
132 | The `findAll` test calls `Recipe.findAll` and
133 | attempts to verify that it returns recipes with
134 | a name and description.
135 |
136 | Because `Recipe.findAll` is asynchronous, this
137 | test calls QUnit's `stop` and `start` methods
138 | to signal when the test is complete.
139 |
140 | `recipe_test.js` goes on to test the remainder of
141 | `Recipe`'s CRUD methods: create, update, destroy.
142 |
143 | ## create_test.js
144 |
145 | `cookbook/recipe/create/create_test.js` tests
146 | the `cookbook/recipe/create` module aliased as
147 | RecipeCreate. It starts by loading funcunit, the
148 | RecipeCreate control, the Recipe model and
149 | the recipeStore fixture:
150 |
151 | steal('funcunit',
152 | './create.js',
153 | 'cookbook/models/recipe.js',
154 | 'cookbook/models/fixtures',
155 | function (S, RecipeCreate, Recipe, recipeStore ) {
156 |
157 | Next, it defines the module, with setup and teardown
158 | code that runs before and after every test:
159 |
160 | module("cookbook/recipe/create", {
161 | setup: function(){
162 | $("#qunit-test-area")
163 | .append("");
164 | new RecipeCreate("#create");
165 | },
166 | teardown: function(){
167 | $("#qunit-test-area").empty();
168 | recipeStore.reset();
169 | }
170 | });
171 |
172 | `setup` creates a _form_ element and creates a new `RecipeCreate` instance
173 |
174 | on it. `teardown` removes the element and [can.fixture.store.reset resets] the
175 | `recipeStore` to contain the original set of recipes.
176 |
177 | `create_test.js` tests that RecipeCreate can create a recipe:
178 |
179 | test("create recipes", function () {
180 | ...
181 | });
182 |
183 | We are going to create an __Ice Water__ recipe, so we
184 | listen to a recipe being created and check it's contents like:
185 |
186 | stop();
187 | Recipe.bind("created",function(ev, recipe){
188 | ok(true, "Ice Water added");
189 |
190 | equals(recipe.name,
191 | "Ice Water",
192 | "name set correctly");
193 |
194 | equals(recipe.description,
195 | "Pour water in a glass. Add ice cubes.",
196 | "description set correctly" );
197 |
198 | start();
199 | Recipe.unbind("created",arguments.callee);
200 | })
201 |
202 | As this test is asynchronous, it calls QUnit's stop and start. After
203 | listening to Recipes being created, the test creates
204 | a recipe by simulating a user filling in the recipe form and clicking submit:
205 |
206 | S("[name=name]").type("Ice Water");
207 | S("[name=description]").type("Pour water in a glass. "+
208 | "Add ice cubes.");
209 |
210 | S("[type=submit]").click();
211 |
212 | Then, it verifies the submit button's value is "Creating":
213 |
214 | S("[type=submit]").val("Creating...",
215 | "button text changed while created");
216 |
217 | Finally, when the value is changed back to "Create", the
218 | test checks that the form has been reset:
219 |
220 | S("[type=submit]").val("Create", function(){
221 | ok(true, "button text changed back after create" );
222 | equals(S("[name=name]").val(), "", "form reset");
223 | equals(S("[name=description]").val(), "", "form reset");
224 | });
225 |
226 | ## list_test.js
227 |
228 | `cookbook/recipe/list/list_test.js` tests the `cookbook/recipe/list`
229 | module aliased as RecipeList. It starts by loading funcunit, the
230 | RecipeList control, the Recipe model and
231 | the recipeStore fixture:
232 |
233 | steal('funcunit',
234 | './list.js',
235 | 'cookbook/models/recipe.js',
236 | 'cookbook/models/fixtures',
237 | function (S, RecipeCreate, Recipe, recipeStore ) {
238 |
239 | Next, it defines the module it is testing, with setup and teardown
240 | code that runs before and after every test:
241 |
242 | module("cookbook/recipe/list", {
243 | setup: function(){
244 | $("#qunit-test-area").append("");
245 | this.list = new RecipeList("#recipes");
246 | },
247 | teardown: function(){
248 | $("#qunit-test-area").empty();
249 | recipeStore.reset();
250 | }
251 | });
252 |
253 | `setup` creates a _div_ element and creates a new `RecipeList`
254 | instance. That list will be accessible within each test as `this.list`.
255 | `teardown` removes the element and [can.fixture.store.reset resets]
256 | the `recipeStore` to contain the original set of recipes.
257 |
258 | Then, `list_test.js` tests that RecipeList displays all
259 | the recipes that are loaded on the server:
260 |
261 | test("lists all recipes", function(){
262 | stop();
263 |
264 | Recipe.findAll({}, function(recipes){
265 |
266 | S(".recipe").size(recipes.length,function(){
267 | ok(true, "All recipes listed");
268 |
269 | start();
270 | })
271 | })
272 | });
273 |
274 | And it tests that created recipes are added to the list of recipes
275 | by creating a recipe and making sure a corresponding element shows
276 | up on the page:
277 |
278 | test("lists created recipes", function(){
279 |
280 | new Recipe({
281 | name: "Grilled Cheese",
282 | description: "grill cheese in bread"
283 | }).save();
284 |
285 | S('h3:contains(Grilled Cheese X)')
286 | .exists("Lists created recipe");
287 | })
288 |
289 | To test deleting a recipe, `list_test.js` creates a recipe then
290 | clicks its destroy link and makes sure the element has been removed:
291 |
292 | test("delete recipes", function(){
293 | new Recipe({
294 | name: "Ice Water",
295 | description: "mix ice and water"
296 | }).save();
297 |
298 | // wait until grilled cheese has been added
299 | S('h3:contains(Ice Water X)').exists();
300 |
301 | S.confirm(true);
302 | S('h3:last a').click();
303 |
304 | S('h3:contains(Ice Water)')
305 | .missing("Grilled Cheese Removed");
306 |
307 | });
308 |
309 | ## cookbook_test.js
310 |
311 | `cookbook/cookbook_test.js` loads all other tests
312 | and tests the `cookbook` module. It starts
313 | by loading FuncUnit and all the other tests:
314 |
315 | steal(
316 | 'funcunit',
317 | './models/recipe_test.js',
318 | 'cookbook/recipe/create/create_test.js',
319 | 'cookbook/recipe/list/list_test.js',
320 | function (S) {
321 |
322 | Next it defines which module it's testing:
323 |
324 | module("cookbook", {
325 | setup : function () {
326 | S.open("//cookbook/index.html");
327 | }
328 | });
329 |
330 | `setup` uses FuncUnit to open the application's page. Any
331 | FuncUnit commands, for example `S("h1").text()`, will
332 | operate within that page instead of the
333 | testing window. This is ideal for integration and functional tests.
334 |
335 | `cookbook_test.js` then tests if the page contains
336 | JavaScriptMVC's welcome text:
337 |
338 | test("welcome test", function () {
339 | equals( S("h1").text(),
340 | "Welcome to JavaScriptMVC!",
341 | "welcome text" );
342 | });
343 |
344 | Finally, it tests the integration between RecipeCreate and
345 | RecipeList by creating a recipe and making sure it is
346 | listed on the page:
347 |
348 | test("creating a recipes adds it to the list ", function () {
349 |
350 | S("[name=name]").type("Ice Water");
351 | S("[name=description]").type("Pour water in a glass. "+
352 | "Add ice cubes.");
353 |
354 | S("[type=submit]").click();
355 |
356 | S("h3:contains(Ice Water)").exists();
357 | S("p:contains(Pour water in a glass. Add ice cubes.)")
358 | .exists()
359 | });
360 |
361 |
362 | Continue to [building.cookbook Building Cookbook].
--------------------------------------------------------------------------------
/tutorials/images/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/.DS_Store
--------------------------------------------------------------------------------
/tutorials/images/app_organization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/app_organization.png
--------------------------------------------------------------------------------
/tutorials/images/app_scaffold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/app_scaffold.png
--------------------------------------------------------------------------------
/tutorials/images/contacts_design.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/contacts_design.png
--------------------------------------------------------------------------------
/tutorials/images/contacts_preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/contacts_preview.jpg
--------------------------------------------------------------------------------
/tutorials/images/contacts_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/contacts_preview.png
--------------------------------------------------------------------------------
/tutorials/images/contacts_widgets.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/contacts_widgets.jpg
--------------------------------------------------------------------------------
/tutorials/images/coverage1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/coverage1.png
--------------------------------------------------------------------------------
/tutorials/images/coverage2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/coverage2.png
--------------------------------------------------------------------------------
/tutorials/images/diagram.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/diagram.gif
--------------------------------------------------------------------------------
/tutorials/images/diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/diagram.png
--------------------------------------------------------------------------------
/tutorials/images/diagram_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/diagram_search.png
--------------------------------------------------------------------------------
/tutorials/images/diagram_tabs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/diagram_tabs.png
--------------------------------------------------------------------------------
/tutorials/images/eoa_diagram1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/eoa_diagram1.jpg
--------------------------------------------------------------------------------
/tutorials/images/eoa_diagram2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/eoa_diagram2.jpg
--------------------------------------------------------------------------------
/tutorials/images/inputs_outputs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/inputs_outputs.jpg
--------------------------------------------------------------------------------
/tutorials/images/playermx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/playermx.png
--------------------------------------------------------------------------------
/tutorials/images/playermx_overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/playermx_overview.png
--------------------------------------------------------------------------------
/tutorials/images/playermx_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/playermx_play.png
--------------------------------------------------------------------------------
/tutorials/images/playermx_position.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/playermx_position.png
--------------------------------------------------------------------------------
/tutorials/images/tabs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/tabs.png
--------------------------------------------------------------------------------
/tutorials/images/todo_arch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/todo_arch.png
--------------------------------------------------------------------------------
/tutorials/images/todos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitovi/javascriptmvc/c13c2eb7de8dcc6887e47d7a1ce2f117d19febf8/tutorials/images/todos.png
--------------------------------------------------------------------------------
/tutorials/installing.md:
--------------------------------------------------------------------------------
1 | @page installing Installing JavaScriptMVC
2 | @parent tutorials 0
3 |
4 | ## Requirements
5 |
6 | JavaScriptMVC requires [Java JRE 1.6](http://www.oracle.com/technetwork/java/javase/downloads/java-se-jdk-7-download-432154.html) or greater for:
7 |
8 | - Compression (Google Closure)
9 | - Running [FuncUnit](http://www.funcunit.com/) tests with [Selenium](http://seleniumhq.org/)
10 | - Easy updating
11 | - Code Generators
12 |
13 | But your backend server can be written in any language.
14 | Download the latest [Java JRE here](http://www.java.com/en/download/index.jsp).
15 |
16 | ## Getting JavaScriptMVC
17 |
18 | There are 2 ways to get JavaScriptMVC:
19 |
20 | - [Downloading](http://javascriptmvc.com/builder.html)
21 | - [developwithgit Installing JavaScriptMVC with Git]
22 |
23 | ## Downloading
24 |
25 | [Download](http://javascriptmvc.com/builder.html) the latest JavaScriptMVC.
26 | Unzip the folder on your file system or web server.
27 | If you are using this on a webserver,
28 | unzip in a public folder where the server hosts static content.
29 |
30 | > TIP: Unzip these files as
31 | high in your apps folder structure as possible (i.e. don't
32 | put them under a javascriptmvc folder in your public directory).
33 |
34 | ## Installing JavaScriptMVC with Git.
35 |
36 | JavaScriptMVC is comprised of 7 sub projects:
37 |
38 | - [https://github.com/bitovi/legacy-steal](http://github.com/bitovi/legacy-steal)
39 | - [https://github.com/bitovi/canjs](https://github.com/bitovi/canjs)
40 | - [https://github.com/bitovi/canui](https://github.com/bitovi/canui)
41 | - [https://github.com/bitovi/jquerypp](https://github.com/bitovi/jquerypp)
42 | - [https://github.com/bitovi/documentjs](http://github.com/bitovi/documentjs)
43 | - [https://github.com/bitovi/legacy-funcunit](http://github.com/bitovi/legacy-funcunit)
44 | - [https://github.com/bitovi/jmvc-generators](https://github.com/bitovi/jmvc-generators)
45 |
46 | You want to fork each project and add it as a submodule to your project
47 | in a public folder (where your server keeps static content).
48 | If these words mean nothing to you, or you'd like more
49 | explanation, you might want to read
50 | [developwithgit Developing With Git].
51 |
52 | Forking the repos looks like:
53 |
54 | @codestart text
55 | git submodule add git@github.com:_YOU_/legacy-steal.git public/steal
56 | git submodule add git@github.com:_YOU_/canjs.git public/can
57 | git submodule add git@github.com:_YOU_/canui.git public/canui
58 | git submodule add git@github.com:_YOU_/jquerypp.git public/jquerypp
59 | git submodule add git@github.com:_YOU_/documentjs.git public/documentjs
60 | git submodule add git@github.com:_YOU_/legacy-funcunit.git public/funcunit
61 | git submodule add git@github.com:_YOU_/jmvc-generators.git public/jmvc
62 | @codeend
63 |
64 | Notice that CanJS is in can folder and
65 | jQuery++ is in the jquerypp folder.
66 |
67 | After installing the repository, run:
68 |
69 | @codestart
70 | [WINDOWS] > steal\js steal\make.js
71 |
72 | [Lin/Mac] > ./steal/js steal/make.js
73 | @codeend
74 |
75 | ## Verifing the install
76 |
77 | In your public (or static) folder, you should have something that looks like:
78 |
79 | @codestart
80 | static
81 | \documentjs - DocumentJS library
82 | \funcunit - FuncUnit testing library
83 | \canjs - CanJS MVC Framework
84 | \canui - Widgets built on CanJS and jQuery++
85 | \jquery - jQuery's missing utils and special events
86 | \steal - Compression and build system
87 | \js.bat - Windows Rhino shortcut
88 | \js - Mac/Linux Rhino shortcut
89 | @codeend
90 |
91 |
92 | Open a command line to that folder and run:
93 |
94 | @codestart
95 | [WINDOWS] > js
96 |
97 | [Lin/Mac] > ./js
98 | @codeend
99 |
100 | This starts the [Rhino JS engine](http://www.mozilla.org/rhino/). Type quit() to exit.
101 |
102 |
--------------------------------------------------------------------------------
/tutorials/jquerypp.md:
--------------------------------------------------------------------------------
1 | @page tutorials.jquerypp Get Started with jQuery++
2 | @parent tutorials 4
3 |
4 | jQuery++ is a collection of useful jQuery libraries that provide the
5 | missing functionality necessary to implement and organize large-scale
6 | jQuery applications. It provides low-level utilities for things that
7 | jQuery doesn’t support.
8 |
9 | You can find out everything you need to know about jQuery++
10 | [at its site.](http://jquerypp.com) jQuery++ is included with
11 | JavaScriptMVC by default in the jquery folder in the root
12 | of your project.
--------------------------------------------------------------------------------
/tutorials/mvc.md:
--------------------------------------------------------------------------------
1 | @page mvc Get Started with CanJS
2 | @parent tutorials 3
3 |
4 | [canjs CanJS] is a JavaScript framework that makes
5 | building rich web applications easy and the MVC of
6 | JavaScriptMVC. The library is extremely lightweight
7 | (at only 8.5k minified and compressed) and full featured.
8 |
9 | Everything you want and need to know about CanJS
10 | [ can be found here.](http://canjs.us) You will find documentation
11 | on how to use CanJS, examples of CanJS in action, as well as
12 | a customizable download builder.
13 |
14 | For the purposes of JavaScript MVC, you will not need to download
15 | CanJS, as it is already included in the framework, located in the
16 | can folder in the root of your project.
--------------------------------------------------------------------------------
/tutorials/organizing.md:
--------------------------------------------------------------------------------
1 | @page organizing Organizing Your App
2 | @parent tutorials 7
3 |
4 | @body
5 |
6 | The secret to building large apps is to NEVER build
7 | large apps. Break up your applications into small
8 | pieces. Then assemble those testable, bite-sized pieces
9 | into your big application.
10 |
11 | JavaScriptMVC 3.X is built with this pattern in
12 | mind. As opposed to a single flat 'scripts' folder,
13 | JavaScriptMVC breaks up your app into
14 | manageable, isolated modules. This tutorial discusses
15 | the reasons for doing this and patterns for doing it.
16 |
17 | ## Why
18 |
19 | Traditionally JavaScript, CSS and static resources were seen as second-class
20 | citizens when compared to server code. JavaScript was put in a single
21 | flat 'scripts' folder that looked like:
22 |
23 | button.js
24 | jquery.ui.calendar.js
25 | contactmanager.js
26 | tabs.js
27 | jquery.js
28 | nav.js
29 | resizer.js
30 | \test
31 | button_test.js
32 | contactmanager.js
33 | tabs_test.js
34 | nav_test.js
35 |
36 | This was OK for a limited amount of JavaScript; however; client code
37 | increasingly represents a larger percentage of an
38 | app's codebase. What works for 10 files does not work for 100.
39 |
40 | Complicating matters, an individual JavaScript file might have dependencies on
41 | non-JavaScript resources. A menu might need
42 | a specific stylesheet, images, or [can.view client side template].
43 |
44 | Spreading these dependencies across images, styles, and template folders
45 | makes it more difficult to know what depends on what. Over the lifetime
46 | of an an application, it makes it more likely you'll be loading
47 | resources that are not needed.
48 |
49 | ### The Fix
50 |
51 | JavaScriptMVC gives each resource you author it's own folder. Typically,
52 | the folder will hold the resource, its demo page, test page,
53 | test script, and any other files specific to that resource.
54 |
55 | For example, a tabs folder might look like:
56 |
57 | \tabs
58 | tabs.js - the code for a tabs widget
59 | tabs.html - a demo page
60 | funcunit.html - a test page
61 | tabs_test.js - test code
62 | tabs.css - css for the tab
63 |
64 | The idea is that we can work on tabs.js in complete isolation.
65 |
66 | ## How
67 |
68 | Before we discuss best practices for organizing your application, a little
69 | throat clearing ...
70 |
71 | > Every app is different. Providing a single folder structure for
72 | all applications is impossible. However, there are several useful
73 | patterns that when understood can keep your
74 | application under control. JavaScriptMVC is extremely flexible so use your best judgement!
75 |
76 | This guide walks you through starting with a small-ish example app and where you would add
77 | features over time. Before the example, it's good to know some JavaScript terminology:
78 |
79 |
80 | ### App and Library Folders
81 |
82 | In general, a JavaScriptMVC application is divided into two root folders: an app folder and
83 | library folder. The app folder code typically 'steals' and configures 'library' code.
84 |
85 | #### Application Folder
86 |
87 | The application (or app) folder houses code specific to a particular
88 | application. The code in this folder is very unlikely to be
89 | used in other places. The folder name reflects the name of the application
90 | being built.
91 |
92 | Create an application folder structure with:
93 |
94 | js jmvc\generate\app cms
95 |
96 |
97 | #### Library Folders
98 |
99 | A library folder is for general code that
100 | can be reused across several applications. It is the perfect place for
101 | reusable controls like a tabs widget. Typically folder names reflect
102 | the name of the organization building the controls.
103 |
104 | ### Module Types
105 |
106 | An application is comprised of various modules. JavaScriptMVC's code generators can
107 | be used to create .
108 |
109 | __Model__ - A model represents a set of services. Typically, models exist within
110 | an application folder's `models` directory and are used to request
111 | data.
112 |
113 | Generate a model like:
114 |
115 | js jmvc\generate\model cms\models\image
116 |
117 | __Control__ - A [can.Control] can be a traditional view (a tabs widget) or
118 | a traditional controller (coordinates model and view). Reusable controls are
119 | added to library folders. Controls specific
120 | to an application should be put in a folder within an application folder.
121 |
122 | Generate a controller like:
123 |
124 | js jmvc\generate\control bitovi\tabs
125 |
126 |
127 | __Plugin__ - A plugin is a low-level reusable module such as a special event or dom extension.
128 | It does not typically have a visible component. These should be added to library folders.
129 |
130 | js jmvc\generate\plugin bitovi\range
131 |
132 |
133 | ## Example Application
134 |
135 | The example is a content management system that organizes 'videos', 'images', and
136 | 'articles' under a tabbed layout. For each content type, the user needs
137 | to be able to edit a selected item of that type.
138 |
139 | @image tutorials/cms.png
140 |
141 |
142 |
143 | If the application's name is __cms__ and it is built by __Bitovi__, a basic version's
144 | folder structure might look like:
145 |
146 |
147 | \cms
148 | \models - models for the CMS
149 | \views - views to configure the grid
150 | cms.js
151 | \bitovi
152 | \tabs - a basic tabs widget
153 | \edit - binds a form to edit a model instance
154 | \grid - a configurable grid
155 | \views
156 |
157 |
158 | This basic version assumes that we can configure the grid and edit widget
159 | enough to produces the desired functionality. In this case,
160 | cms/cms.js might look like:
161 |
162 | // load dependencies
163 | steal('bitovi/tabs',
164 | 'bitovi/grid',
165 | 'bitovi/create',
166 | './models/image.js',
167 | './models/video.js',
168 | './models/article.js',
169 | function(
170 | Tabs, Grid, Create,
171 | Image, Video, Article
172 | ){
173 |
174 | // add tabs to the page
175 | var tabs = new Tabs('#tabs');
176 |
177 | // Configure the video grid
178 | var videos = new Grid($videos, {
179 | model: Cms.Models.Video,
180 | view: "//cms/views/videos.ejs"
181 | }),
182 | videoEdit = new Edit('#videoEdit')
183 |
184 | // listen for when a video is selected
185 | videos.element.on('selected','li',
186 | function(ev, video){
187 | // update the edit form with the selected
188 | // video's attributes
189 | videoEdit.update(video);
190 | }
191 | );
192 |
193 | // Do the same for images and articles
194 | var images = new Bitovi.Grid('#images', {
195 | model: Cms.Models.Image,
196 | view: "//cms/views/images.ejs"
197 | }),
198 | imageEdit = new Edit('#imageEdit');
199 |
200 | images.element.on('selected','li',
201 | function(ev, image){
202 | imageEdit.update(video);
203 | }
204 | );
205 |
206 | var articles = new Grid('#articles', {
207 | model: Article,
208 | view: "//cms/views/article.ejs"
209 | }),
210 | articleEdit = new Edit('#articleEdit');
211 |
212 | articles.element.on('selected','li',
213 | function(ev, article){
214 | articleEdit.update(video);
215 | }
216 | );
217 |
218 | })
219 |
220 | Notice that the cms.js configures the grid and edit widgets with
221 | the cms folder's models and views. This represents an ideal separation between
222 | app specific code and reusable widgets. However, it's extremely rare that
223 | widgets are able to provide all the functionality an app needs to meet its
224 | requirements.
225 |
226 | ### More complexity
227 |
228 | Eventually, you won't be able to configure abstract widgets to satisfy
229 | the requirements of your application. For example, you might need to
230 | add specific functionality around listing and editing videos (such as a thumbnail editor).
231 |
232 | This is application specific functionality and belongs
233 | in the application folder. We'll encapsulate it in a controller [can.Control] for each type:
234 |
235 | \cms
236 | \articles - the articles tab
237 | \images - the images tab
238 | \videos - the videos tab
239 | \models
240 | \views
241 | cms.js
242 | \bitovi
243 | \thumbnail
244 | \tabs
245 | \edit
246 | \grid
247 | \views
248 |
249 | cms/cms.js now looks like:
250 |
251 | steal('cms/articles',
252 | 'cms/images',
253 | 'cms/videos',
254 | 'bitovi/tabs',
255 | function(
256 | Articles, Images, Videos, Tabs
257 | ){
258 |
259 | new Tabs('#tabs');
260 |
261 | // add the video grid
262 | new Videos('#videos');
263 |
264 | // Do the same for images and articles
265 | new Images('#images');
266 | new Articles('#articles');
267 |
268 | })
269 |
270 | cms/articles/articles.js might look like:
271 |
272 | steal('can',
273 | 'bitovi/grid',
274 | 'bitovi/edit',
275 | './init.ejs',
276 | './article.ejs',
277 | 'bitovi/models/article.js',
278 | function(can,
279 | Grid, Edit,
280 | initEJS, articleEJS,
281 | Article){
282 |
283 | return can.Control({
284 |
285 | init : function(){
286 | // draw the html for the tab
287 | this.element.html(initEJS({}));
288 |
289 | // configure the grid
290 | new Grid(this.find('.grid'), {
291 | model: Article,
292 | view: articleEJS
293 | })
294 |
295 | this.editor = new Edit(".edit")
296 | },
297 |
298 | // when the grid triggers a select event
299 | "li select" : function(el, ev, article){
300 | this.editor.update(article)
301 | }
302 | });
303 |
304 | });
305 |
306 | ### Adding leaves to the tree
307 |
308 | In the previous example, we moved most of the code in cms/cms.js into
309 | an articles, images, and videos plugin. Each of these plugins should
310 | work independently from each other, have it's own tests and demo page.
311 |
312 | Communication between these high-level
313 | controls should be configured in cms/cms.js.
314 |
315 | Essentially, as your needs become more specific, you are encouraged to
316 | nest plugins within each other.
317 |
318 | In this example, after separating out each type into it's own plugin, you might
319 | want to split the type into edit and grid controls. The resulting
320 | folder structure would look like:
321 |
322 | \cms
323 | \articles
324 | \grid
325 | \edit
326 | \images
327 | \grid
328 | \edit
329 | \videos
330 | \grid
331 | \edit
332 | \models
333 | \views
334 | cms.js
335 | \bitovi
336 | \thumbnail
337 | \tabs
338 | \edit
339 | \grid
340 |
341 |
342 | `cms/articles/articles.js` would look the same, except it would
343 | change __Grid__ and __Edit__ to point to `cms/articles/grid` and
344 | `cms/articles/edit`:
345 |
346 |
347 | steal('can',
348 | 'cms/articles/grid',
349 | 'cms/articles/edit',
350 | './init.ejs',
351 | './article.ejs',
352 | 'bitovi/models/article.js',
353 | function(can,
354 | Grid, Edit,
355 | initEJS, articleEJS,
356 | Article){
357 | ...
358 | })
359 |
360 | JavaScriptMVC encourages you to organize your application folder as a tree.
361 | The leaves of the tree are micro-controls that perform a specific task (such as
362 | allowing the editing of videos).
363 |
364 | Higher-order controls (`cms/articles/articles.js`) combine leaves and other nodes
365 | into more complex functionality. The root of the application is the application file
366 | (`cms/cms.js`). It combines and configures all high-level widgets.
367 |
368 | Communication between modules is done with the observer
369 | pattern ([can.compute] or [can.Observe]) or with events.
370 |
371 | With events, low-level controls use `$.fn.trigger` to send messages 'up' to higher-order
372 | controls. Higher-order controls typically call methods on lower-level controls
373 |
374 | The Articles control listening to a 'select' event produced by
375 | Grid and creating (or updating) the Edit control
376 | is a great example of this.
377 |
378 | The situation where this breaks down is usually when a 'state' needs to be shared and communicated
379 | across several controls. [can.compute] and [can.Observe] are useful
380 | for this situation.
381 |
382 | ## Conclusion
383 |
384 | This is an extremely abstract article, but hopefully illustrates a few
385 | important trends of JavaScriptMVC organization:
386 |
387 | - Put code specific to an app in the application folder.
388 | - Put reusable plugins, widgets, and other code into library folders.
389 | - Fill out the tree.
390 |
--------------------------------------------------------------------------------
/tutorials/rapidstart/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/tutorials/rapidstart/todos.ejs:
--------------------------------------------------------------------------------
1 | <% this.each(function(todo){ %>
2 |
6 |
7 |
9 |
10 |
--------------------------------------------------------------------------------
/tutorials/rapidstart/todos.js:
--------------------------------------------------------------------------------
1 | steal('can',
2 | './todos.ejs',
3 | 'can/util/fixture',
4 | function(can, todosEJS){
5 |
6 | Todo = can.Model({
7 | findAll : "GET /todos",
8 | findOne : "GET /todos/{id}",
9 | create : "POST /todos",
10 | update : "PUT /todos/{id}",
11 | destroy : "DELETE /todos/{id}"
12 | },
13 | {});
14 |
15 | // our list of todos
16 | var TODOS = [
17 | {id: 1, name: "wake up"},
18 | {id: 2, name: "take out trash"},
19 | {id: 3, name: "do dishes"}
20 | ];
21 | can.fixture({
22 | // findAll
23 | "GET /todos": function(){
24 | return TODOS
25 | },
26 | // findOne
27 | "GET /todos/{id}": function(orig){
28 | return TODOS[(+orig.data.id)-1];
29 | },
30 | // create
31 | "POST /todos": function(request){
32 | TODOS.push(request.data);
33 | return {id: TODOS.length}
34 | },
35 | // update
36 | "PUT /todos/{id}": function(){
37 | return {};
38 | },
39 | // destroy
40 | "DELETE /todos/{id}": function(){
41 | return {};
42 | }
43 | });
44 |
45 | // THE CONTROLLERS
46 | Todos = can.Control({
47 | init: function( element ){
48 | Todo.findAll({}, function(todos){
49 | element.html( todosEJS( todos ) );
50 | });
51 | },
52 | "li click": function(li){
53 | li.trigger('selected', li.data('todo') );
54 | },
55 | "li .destroy click": function(el, ev){
56 | // get the li element that has the model
57 | var li = el.closest('li');
58 |
59 | // get the model and destroy it
60 | li.data('todo').destroy();
61 | }
62 | })
63 |
64 | Editor = can.Control({
65 | todo: function(todo){
66 | this.options.todo = todo;
67 | this.on();
68 | this.setName();
69 | },
70 | // a helper that sets the value of the input
71 | // to the todo's name
72 | setName: function(){
73 | this.element.val(this.options.todo.name);
74 | },
75 | // listen for changes in the todo
76 | // and update the input
77 | "{todo} updated" : function(){
78 | this.setName();
79 | },
80 | // when the input changes
81 | // update the todo instance
82 | "change" : function(){
83 | var todo = this.options.todo
84 | todo.attr('name',this.element.val() )
85 | todo.save();
86 | }
87 | });
88 |
89 | Routing = can.Control({
90 | init : function(){
91 | this.editor = new Editor("#editor")
92 | new Todos("#todos");
93 | },
94 | // the index page
95 | "route" : function(){
96 | $("#editor").hide();
97 | },
98 | "todos/:id route" : function(data){
99 | $("#editor").show();
100 | Todo.findOne(data, $.proxy(function(todo){
101 | this.editor.todo(todo);
102 | }, this))
103 | },
104 | ".todo selected" : function(el, ev, todo){
105 | can.route.attr('id',todo.id);
106 | }
107 | });
108 |
109 | // create routing controller
110 | new Routing(document.body);
111 |
112 |
113 |
114 | })
--------------------------------------------------------------------------------
/tutorials/rapidstart/todos_test.js:
--------------------------------------------------------------------------------
1 | steal('funcunit', function(S){
2 |
3 | module('todos', {
4 | setup: function(){
5 | S.open("//tutorials/rapidstart/todos.html");
6 | }
7 | })
8 |
9 | test('edit first todo', function(){
10 | S(".todo:first").click();
11 | S("#editor").val("wake up", "First Todo added correctly");
12 | })
13 |
14 | })
--------------------------------------------------------------------------------
/tutorials/rootfolder.md:
--------------------------------------------------------------------------------
1 | @page rootfolder Root Folder
2 |
3 | The root folder is the folder where JavaScriptMVC is installed. This is the parent
4 | folder of the `steal`, `can`, etc folder. For example:
5 |
6 | ROOT/
7 | can/
8 | jquery/
9 | steal/
10 | documentjs/
11 |
12 | Typically, the root folder should be a public folder that serves static content. It's often named something
13 | like `static` or `public` depending on what server and system setup you have.
14 |
15 | By default, `steal(moduleId)`, references files from the root folder. The following loads
16 | `ROOT/foo/bar.js`:
17 |
18 | steal('foo/bar.js')
19 |
20 | Paths that begin with `"//"` also reference the root folder. The following
21 | loads `ROOT/views/bar.ejs
22 |
23 | $('#foo').html('//views/bar.ejs',{})
24 |
--------------------------------------------------------------------------------
/tutorials/services.md:
--------------------------------------------------------------------------------
1 | @page services Ajax Service Guidelines
2 | @parent tutorials 9
3 |
4 | JavaScriptMVC's flexibility allows it to
5 | be used with almost any service layer. However,
6 | this guide details suggests a service layer design
7 | that minimizes the amount of extra work to get JavaScriptMVC running.
8 |
9 | In general, the service layer should be as
10 | thin as possible and reflect the Database
11 | queries and results the server must make
12 | to get the data. This keeps things flexible
13 | from the client's perspective.
14 |
15 | ## JSON Rest Part 1
16 |
17 | The best over-all service layer can be described as JSON REST.
18 |
19 | JSON is used as the data received and sometimes sent to the server.
20 |
21 | [REST](http://en.wikipedia.org/wiki/Representational_state_transfer Representational State Transfer) is
22 | where there are resource urls that are
23 | modified with GET POST PUT and DELETE methods.
24 |
25 | A brief example is a service API for messages. The server might expose the
26 | following METHOD and URLS:
27 |
28 | GET /messages - gets an array of messages from the server.
29 | GET /messages/{id} - gets a single message from the server.
30 | POST /messages - creates a message from the server.
31 | PUT /messages/{id} - updates a message from the server.
32 | DELETE /messages/{id} - destroys a message from the server.
33 |
34 | ## Query String Params
35 |
36 | Before going into detail about what each
37 | METHOD URL does, it's worth
38 | quickly describing how parameters are
39 | passed to the query string. [can.Model] passes
40 | parameters to your framework of choices ajax handler
41 | and that gets converted by [can.param].
42 | For example, if we wanted
43 | all messages for a given user,
44 | sorted first by date, then by the users's name,
45 | we might call something like:
46 |
47 | $.get('/messages',{
48 | userId: 5,
49 | order: ['createdAt ASC','user.name ASC']
50 | })
51 |
52 | Which produces:
53 |
54 | @codestart text
55 | GET /messages?
56 | userId=5&
57 | order%5B%5D=createdAt+ASC&
58 | order%5B%5D=user.name+ASC
59 | @codeend
60 |
61 | Lets walk through each REST service example.
62 |
63 | ## GET /messages
64 |
65 | A request to GET /messages should return
66 | all message records visible to the
67 | requesting user. The data should look like:
68 |
69 | {
70 | "data": [
71 | {
72 | "id" : 1,
73 | "fromUserId": 921,
74 | "text": "Hello World",
75 | "createdAt" : 1024324214123
76 | },
77 | {
78 | "id" : 2,
79 | "fromUserId": 923,
80 | "text": "Goodnight World",
81 | "createdAt" : 23524365346543
82 | },
83 | ...
84 | ],
85 | "count": 100
86 | }
87 |
88 | Where:
89 |
90 | - data - has an array of objects (in this case 100),
91 | each object contains the data for a single message.
92 | - count - lists the number of items that
93 | would be returned if a limit was not used. In this
94 | case, no limit was used so count matches the number of items.
95 |
96 |
97 | GET /messages will typically take
98 | arguments passed in as name=value parameters
99 | in the query string like:
100 |
101 | > GET /messages?limit=10&offset=20&order[]=createdAt+DESC
102 |
103 | Common name / values are:
104 |
105 | - limit - the total number of items to return
106 | - offset - the position in the 'total' set to start returning items
107 | - order - an array of 'NAME SORTORDER' pairs
108 |
109 |
110 | You'll notice that these properties can effectively be sent straight away to a DB query.
111 |
112 | #### Relationships
113 |
114 | Often, you want to get all data for a particular item. For example,
115 | all messages from user 52. Instead of requesting something like:
116 |
117 | > GET /users/52/messages
118 |
119 | A request should be made to:
120 |
121 | > GET /messages?fromUserId=52
122 |
123 | The service should limit messages to only those where fromUserId = 52.
124 |
125 | ### Related Data
126 |
127 | Another common problem is when, for
128 | performance reasons, you want the 'joined'
129 | data for a particular field. For example,
130 | when getting messages, you might want to also
131 | want to get the user data from fromUserId.
132 |
133 | In this case, we encourage the use
134 | of an 'include' option which
135 | signifies including additional data like:
136 |
137 | > GET /messages?include[]=fromUser
138 |
139 | The fromUser data will be added to each message object like:
140 |
141 | {
142 | "data": [
143 | {
144 | "id" : 1,
145 | "fromUserId": 921,
146 | "text": "Hello World",
147 | "createdAt" : 1024324214123,
148 | "fromUser": {
149 | "id" : 921,
150 | "name" : "Justin Meyer"
151 | }
152 | },
153 | ...
154 | ],
155 | "count": 100
156 | }
157 |
158 | ## GET /messages/{id}
159 |
160 | Gets a single item from the server. It should return just the JSON data for the object like:
161 |
162 | ->{
163 | "id" : 1,
164 | "fromUserId": 921,
165 | "text": "Hello World",
166 | "createdAt" : 1024324214123
167 | }
168 |
169 |
170 | ## POST /messages
171 |
172 | Creates a message on the server. Typically,
173 | the body of this request is JSON data that
174 | looks exactly like the data from a GET request,
175 | but without the id property or any properties
176 | the server might add. For example, I can
177 | create a message by sending:
178 |
179 | POST /messages
180 | {
181 | "fromUserId": 921,
182 | "text": "A new message"
183 | }
184 |
185 | The server is going to add the id and createdAt property and should return those as JSON in the response:
186 |
187 | ->{
188 | "id": 22,
189 | "createdAt": 1224324214123
190 | }
191 |
192 | ## PUT /messages/{id}
193 |
194 | This updates a resource. Similar to POST,
195 | the body should be JSON that matches what
196 | the data from a GET request looks
197 | like. However, only fields that are changing
198 | are necessary to send. For example, we we
199 | want to update the text of a message:
200 |
201 | PUT /messages/22
202 | {
203 | 'text': "An updated EVIL message"
204 | }
205 |
206 | The response should have any fields that were
207 | modified or adjusted on the server. For
208 | example, the server might filter the word
209 | "EVIL" out of messages and be updating some
210 | 'updatedAt' property. It should return:
211 |
212 | ->{
213 | 'text' : "An updated message",
214 | 'updatedAt' : 123254356346241
215 | }
216 |
217 | If no filtering or modifying of other changes
218 | happened, the server can just return
219 | an empty object: {}.
220 |
221 | ## DELETE /messages/{id}
222 |
223 | Destroys a resource from the server.
224 |
225 | ## Sending Dates
226 |
227 | The best way of sending dates is an integer representing the Julian date like:
228 |
229 | createdAt: 12313123133423
230 |
231 | Where we can convert that easily to a JavaScript date like
232 |
233 | new Date(123123133423)
234 |
235 | ## CUD Multiple Items with a Single Request
236 |
237 | Often, you want to create, update, or delete items with a single request. This is
238 | most often done with [can.Model.List].
239 |
240 |
241 | ## Handling Errors
242 |
243 | When an error happens, make sure your server sends back the
244 | proper HTTP status code. The response body should be a JSON object with
245 | property names mapped to an array of errors:
246 |
247 | {
248 | email : ["Formatting is incorrect","No email is provided"]
249 | }
250 |
251 |
--------------------------------------------------------------------------------
/tutorials/tutorials.md:
--------------------------------------------------------------------------------
1 | @page tutorials Tutorials
2 | @parent javascriptmvc 5
3 |
4 | @description Tutorials on JavaScriptMVC.
5 |
6 | This is where your learning starts. Go through these tutorials to learn JavaScriptMVC basics. Also check out these [examples example apps]
7 |
8 | ### [installing Installing JavaScriptMVC]
9 |
10 | Learn how to install JavaScriptMVC. This is a prerequisite
11 | for most of the other tutorials.
12 |
13 | ### [rapidstart Rapid Start]
14 |
15 | Want to take JMVC for a test-drive? Start here.
16 |
17 | ### [getstarted Get Started with JavaScriptMVC]
18 |
19 | Build, minify, test, and document a basic recipe application. This tutorial
20 | covers the major components of JavaScriptMVC.
21 |
22 | ### [mvc Get started with CanJS]
23 |
24 | A walkthrough of the MVC parts of JavaScript MVC. This is a must read if you
25 | want to understand how they work together.
26 |
27 | ### [tutorials.jquerypp Get started with jQuery++]
28 |
29 | jQuery++ is a collection of useful jQuery libraries that provide the missing
30 | functionality necessary to implement and organize large-scale jQuery applications.
31 |
32 | ### [funcunit.getstarted Get Started with FuncUnit]
33 |
34 | Uses [FuncUnit] to write functional tests for the jQuery UI
35 | autocomplete widget.
36 |
37 | ### [organizing Organizing Your App]
38 |
39 | From a small to large projects,
40 | covers the best way of organizing a JavaScriptMVC application and
41 | scaling it to meet future needs.
42 |
43 | ### [ajaxy Searchable Ajax Apps]
44 |
45 | Build a simple widget
46 | that loads content with ajax. This walkthrough demonstrates how to make
47 | a site Google crawlable and searchable.
48 |
49 | ### [services Ajax Service Guidelines]
50 |
51 | This guide details suggests a service layer design that minimizes the amount of extra work to get JavaScriptMVC running.
52 |
53 | ### [migrate Migrating from 3.0 and 3.1]
54 |
55 | This guide outlines the things you have to look at when upgrading from version 3.0 or 3.1.
56 |
57 | ### [done Migrating from 3.2 to 3.3]
58 |
59 | This guide outlines the API changes for moving a project from version 3.2.
60 |
--------------------------------------------------------------------------------