├── .gitignore
├── README.md
├── app
├── index.js
└── templates
│ ├── Gruntfile.js
│ ├── _bower.json
│ ├── _package.json
│ ├── app
│ ├── 404.html
│ ├── application.js
│ ├── communicator.js
│ ├── favicon.ico
│ ├── htaccess
│ ├── index.html
│ ├── init.js
│ ├── main.js
│ ├── regionManager.js
│ ├── robots.txt
│ └── welcome.hbs
│ ├── bootstrap.js
│ ├── bowerrc
│ ├── editorconfig
│ ├── gitattributes
│ ├── gitignore
│ ├── jshintrc
│ └── server
│ └── app.js
├── collection
└── index.js
├── collectionview
└── index.js
├── compositeview
└── index.js
├── controller
└── index.js
├── helpers
└── validateDirectory.js
├── itemview
└── index.js
├── layout
└── index.js
├── model
└── index.js
├── package.json
├── region
└── index.js
├── router
└── index.js
├── templates
└── javascript
│ ├── collection.js
│ ├── collectionview.js
│ ├── compositeview.js
│ ├── controller.js
│ ├── itemview.js
│ ├── layout.js
│ ├── model.js
│ ├── region.js
│ ├── router.js
│ ├── tmpl.js
│ └── view.js
├── test
└── tests.js
├── tmpl
└── index.js
└── view
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | temp/
3 | npm-debug.log
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | generator-marionette
2 | ======================
3 |
4 | Yeoman generator for Express, Marionette and Backbone with AMD
5 |
6 | Stack
7 | -------
8 | - Server:
9 | * Node: http://nodejs.org/
10 | * Express: http://expressjs.com/
11 | * Socket IO: http://socket.io/
12 | - DB: Mongo: http://www.mongodb.org/
13 | - ODM: Mongoose: http://mongoosejs.com
14 | - Client:
15 | * Backbone: http://backbonejs.org/
16 | * Marionette: https://github.com/marionettejs/backbone.marionette
17 | * jQuery: http://jquery.com/
18 | * Require: http://requirejs.org/
19 | * Handlebars:
20 | - http://handlebarsjs.com/
21 | - https://github.com/SlexAxton/require-handlebars-plugin
22 | * SASS-Bootstrap:
23 | - http://twitter.github.io/bootstrap
24 | - https://github.com/thomas-mcdonald/bootstrap-sass
25 | - Tooling:
26 | * Yeoman: http://yeoman.io/
27 | * Bower: http://bower.io/
28 | * Grunt: http://gruntjs.com/
29 | - Testing:
30 | * phantomJS http://phantomjs.org/
31 | * Mocha http://mochajs.org/
32 | * Chai http://chaijs.com/
33 | * Sinon http://sinonjs.org/
34 |
35 |
36 | Directory structure
37 | -------
38 | - app/ --> client side files
39 | * /bower_components --> bower installs
40 | * /images
41 | * /scripts
42 | - /vendor --> 3rd party scripts
43 | - /models
44 | - /collections
45 | - /controllers
46 | - /routers
47 | - /regions
48 | - /views
49 | * /item
50 | * /collection
51 | * /composite
52 | * /layout
53 | - init.js --> require configuration
54 | - main.js --> application starting point
55 | - application.js --> application file
56 |
57 | * /styles --> scss files
58 | * /templates --> handlebar templates
59 |
60 | - server/ --> node server files
61 | - test/ --> unittesting
62 | * /spec --> individual spec files
63 |
64 |
65 | Install
66 | -------
67 | First make sure you have MongoDB, Node, Npm, Yeoman, Bower and Grunt installed.
68 |
69 | Install mongoDB with:
70 |
71 | $ brew install mongodb
72 |
73 | Or visit http://www.mongodb.org/
74 |
75 | Visit nodejs.org to install node and NPM
76 |
77 |
78 | Install phantomJS with:
79 |
80 | $ brew install phantomjs
81 |
82 | Or visit http://phantomjs.org/
83 |
84 |
85 | To install Yeoman, Bower and Grunt run:
86 |
87 | $ npm install -g yo grunt-cli bower
88 |
89 |
90 | Install mocha-phantomjs:
91 |
92 | $ npm install -g mocha-phantomjs
93 |
94 |
95 | Install mocha generator:
96 |
97 | $ npm install (-g) generator-mocha-amd
98 |
99 |
100 | Install marionette generator
101 |
102 | $ npm install (-g) generator-marionette
103 |
104 |
105 |
106 | Bootstrap project
107 | -----------------
108 | To bootstrap a new project simply run:
109 |
110 | $ yo marionette
111 |
112 | You have option to include the full express server OR just the marionette generators with a minimal server to develop and run test. No SASS/CSS in the latter.
113 |
114 |
115 | To start the app run:
116 |
117 | $ grunt
118 |
119 |
120 | Unit testing generation
121 | -----------------
122 | The biggest change in this release is the automatic unit test generation as part of the marionette-generator. The Marionette generator calls upon the mocha-amd generator. The default grunt task will automatically run all unit test files via phantom JS. You can also use the browser at localhost:1234/test. Test file generation looks something like the following:
123 |
124 | - yo marionette:collection sizes --model size --create-all // run collection generator
125 | - create app/scripts/collections/sizes.js
126 | - invoke marionette:model
127 | - create app/scripts/models/size.js
128 | - invoke mocha-amd:unitTest
129 | - create test/spec/models/size.js // unit test for size model
130 | - force test/spec/testSuite.js
131 | - invoke mocha-amd:unitTest
132 | - create test/spec/collections/sizes.js // unit test for sizes collection
133 | - force test/spec/testSuite.js // testSuite file which lists all test to run
134 |
135 |
136 |
137 | Recommends
138 | -----------------
139 | The generator is most useful using the --create-all flag. In the example:
140 |
141 | $ yo marionette:compositeview peopleview --itemview personview --create-all
142 |
143 | You will get the following files:
144 | * create **app/scripts/views/composite/people.js**
145 | * invoke marionette:itemview
146 | * create **app/scripts/views/item/person.js**
147 | * invoke marionette:tmpl
148 | * create **app/templates/item/person_tmpl.hbs**
149 | * invoke marionette:tmpl
150 | * create **app/templates/composite/people_tmpl.hbs**
151 |
152 |
153 | Create routers
154 | --------------
155 | You can generate routers too with
156 |
157 | $ yo marionette:router router-name
158 |
159 |
160 |
161 | Create model
162 | ------------
163 | To add a Backbone model to the project use the model generator like this
164 |
165 | $ yo marionette:model model-name
166 |
167 | Or to inherit from an existing model
168 |
169 | $ yo marionette:model model-name --inherit model-name
170 |
171 |
172 |
173 | Create collection
174 | -----------------
175 | To add a Backbone collection to the project use collection generator
176 |
177 | $ yo marionette:collection collection-name
178 |
179 | You can link the collection with an existent model
180 |
181 | $ yo marionette:collection collection-name model-name
182 |
183 | Or may be you want to create both, model and collection on one step
184 |
185 | $ yo marionette:collection collection-name --model model-name --create-all
186 |
187 | Or you may want to inherit from another collection
188 |
189 | $ yo marionette:collection collection-name --model model-name --inherit collection-name --create-all
190 |
191 |
192 |
193 |
194 | Create views
195 | ------------
196 | Backbone works with view definitions, to create one use this command. It is recommended to use Marionette views instead of the standard Backbone view
197 |
198 | $ yo marionette:view view-name
199 |
200 |
201 |
202 |
203 | Create item views
204 | ------------
205 | Create a Marionette ItemView and link to an existing template at location templates/[template-location]
206 |
207 | $ yo marionette:itemview view-name
208 |
209 | You may want to inherit from another itemview
210 |
211 | $ yo marionette:itemview view-name --inherit view-name
212 |
213 | Or maybe you want to create both, itemView and template on one step
214 |
215 | $ yo marionette:itemview view-name --create-all
216 |
217 |
218 |
219 | Create collection views
220 | ------------
221 | Create a Marionette CollectionView that is associated to an existing itemview
222 |
223 | $ yo marionette:collectionview view-name --itemview itemview-name
224 |
225 | Or inherit from another collectionview
226 |
227 | $ yo marionette:collectionview view-name --itemview itemview-name --inherit view-name
228 |
229 | Or maybe you want to create both, itemview (with template) and collectionview.
230 |
231 | $ yo marionette:collectionview view-name --itemview itemview-name --create-all
232 |
233 |
234 |
235 |
236 | Create composite views
237 | ------------
238 | Create a Marionette CompositeView
239 |
240 | $ yo marionette:compositeview view-name --itemview itemview-name
241 |
242 | Or inherit from another CompositeView
243 |
244 | $ yo marionette:compositeview view-name --itemview itemview-name --inherit view-name
245 |
246 | Or maybe you want to create all, itemview and compositeview and both templates.
247 |
248 | $ yo marionette:compositeview view-name --itemview itemview-name --create-all
249 |
250 |
251 |
252 |
253 | Create regions
254 | ------------
255 | Create a Marionette Region
256 |
257 | $ yo marionette:region region-name
258 |
259 | Or inherit from another Region
260 |
261 | $ yo marionette:region region-name --inherit region-name
262 |
263 |
264 |
265 |
266 | Create layouts
267 | ------------
268 | Create a Marionette Layout and link to an existing template at location templates/[template-location]
269 |
270 | $ yo marionette:layout layout-name
271 |
272 | Or inherit from another layout
273 |
274 | $ yo marionette:layout layout-name --inherit layout-name
275 |
276 | Or maybe you want to create both, Layout and template on one step
277 |
278 | $ yo marionette:layout layout-name --create-all
279 |
280 |
281 |
282 | Create controller
283 | ------------
284 | Create a Marionette Controller
285 |
286 | $ yo marionette:controller controller-name
287 |
288 | Or inherit from another Controller
289 |
290 | $ yo marionette:controller controller-name --inherit controller-name
291 |
292 |
293 | Create templates
294 | ------------
295 | Create a handle bars tmpl
296 |
297 | $ yo marionette:tmpl tmpl-name --tmplLocation tmpl-location
298 |
299 |
300 |
301 |
302 |
303 |
--------------------------------------------------------------------------------
/app/index.js:
--------------------------------------------------------------------------------
1 | var util = require('util');
2 | var path = require('path');
3 | var yeoman = require('yeoman-generator');
4 | var chalk = require('chalk');
5 |
6 | module.exports = Generator;
7 |
8 | function Generator(args, options, config) {
9 | yeoman.generators.Base.apply(this, arguments);
10 |
11 | // custom mocha generator
12 | this.testFramework = 'mocha-amd';
13 |
14 | this.templateFramework = 'handlebars';
15 |
16 | this.hookFor(this.testFramework, { as: 'app' });
17 |
18 | this.on('end', function () {
19 | if (['app', 'backbone', 'marionette'].indexOf(this.generatorName) >= 0) {
20 | this.installDependencies({ skipInstall: this.options['skip-install'] });
21 | }
22 | });
23 | }
24 |
25 | util.inherits(Generator, yeoman.generators.Base);
26 |
27 | Generator.prototype.askFor = function askFor() {
28 | var cb = this.async();
29 |
30 | // welcome message
31 | var welcome =
32 | '\n _-----_' +
33 | '\n | |' +
34 | '\n |' + chalk.red('--(o)--') + '| .--------------------------.' +
35 | '\n `---------´ | ' + chalk.yellow.bold('Welcome to Yeoman') + ', |' +
36 | '\n ' + chalk.yellow('(') + ' _' + chalk.yellow('´U`') + '_ ' + chalk.yellow(')') + ' | ' + chalk.yellow.bold('ladies and gentlemen!') + ' |' +
37 | '\n /___A___\\ \'__________________________\'' +
38 | '\n ' + chalk.yellow('| ~ |') +
39 | '\n __' + chalk.yellow('\'.___.\'') + '__' +
40 | '\n ´ ' + chalk.red('` |') + '° ' + chalk.red('´ Y') + ' `\n';
41 |
42 | console.log(welcome);
43 | console.log('Out of the box I include HTML5 Boilerplate, jQuery, Backbone.js, Marionette, Handlebars, Require and Modernizr.');
44 |
45 |
46 | var prompts = [{
47 | type: 'confirm',
48 | name: 'isFullApp',
49 | message: 'Would you like to install the full express app or simply the marionette generators?'
50 | },
51 | {
52 | type: 'confirm',
53 | name: 'useMongoose',
54 | message: 'Would you like to include MongoDB for storage?'
55 | },
56 | {
57 | type: 'confirm',
58 | name: 'useSocketIO',
59 | message: 'Would you like to include Socket IO for real time communication?'
60 | },
61 | {
62 | type: 'confirm',
63 | name: 'useBaucis',
64 | message: 'Would you like to include Baucis for REST?'
65 | },
66 | {
67 | type: 'string',
68 | name: 'bowerDirectory',
69 | message: 'Where do you want the Bower components installed?',
70 | default: 'bower_components'
71 | }];
72 |
73 | this.prompt(prompts, function (props) {
74 | // manually deal with the response, get back and store the results.
75 | // we change a bit this way of doing to automatically do this in the self.prompt() method.
76 | this.isFullApp = props.isFullApp;
77 | this.useMongoose = props.useMongoose;
78 | this.useSocketIO = props.useSocketIO;
79 | this.useBaucis = props.useBaucis;
80 | this.bowerDirectory = props.bowerDirectory;
81 |
82 | //dummy vars for legacy
83 | this.compassBootstrap = true;
84 | this.includeRequireJS = true;
85 |
86 | cb();
87 | }.bind(this));
88 | };
89 |
90 | Generator.prototype.git = function git() {
91 | if( this.isFullApp ) {
92 | this.template('gitignore', '.gitignore');
93 | this.copy('gitattributes', '.gitattributes');
94 | }
95 | };
96 |
97 | Generator.prototype.bower = function bower() {
98 | this.template('bowerrc', '.bowerrc');
99 | this.copy('_bower.json', 'bower.json');
100 | };
101 |
102 | Generator.prototype.jshint = function jshint() {
103 | if( this.isFullApp ) {
104 | this.copy('jshintrc', '.jshintrc');
105 | }
106 | };
107 |
108 | Generator.prototype.editorConfig = function editorConfig() {
109 | if( this.isFullApp ) {
110 | this.copy('editorconfig', '.editorconfig');
111 | }
112 | };
113 |
114 | Generator.prototype.gruntfile = function gruntfile() {
115 | this.template('Gruntfile.js');
116 | };
117 |
118 | Generator.prototype.packageJSON = function packageJSON() {
119 | this.template('_package.json', 'package.json');
120 | };
121 |
122 | Generator.prototype.mainStylesheet = function mainStylesheet() {
123 | if( this.isFullApp ) {
124 | if (this.compassBootstrap) {
125 | this.write('app/styles/main.scss', '@import \'sass-bootstrap/lib/bootstrap\';\n\n.hero-unit {\n margin: 50px auto 0 auto;\n width: 400px;\n}');
126 | } else {
127 | this.write('app/styles/main.css', 'body {\n background: #fafafa;\n}\n\n.hero-unit {\n margin: 50px auto 0 auto;\n width: 300px;\n}');
128 | }
129 | }
130 | };
131 |
132 |
133 | Generator.prototype.bootstrapJs = function bootstrapJs() {
134 | var _rootDir = this.isFullApp ? 'app/' : '';
135 |
136 | if (this.includeRequireJS && this.compassBootstrap) {
137 | this.copy('bootstrap.js', _rootDir + 'scripts/vendor/bootstrap.js');
138 | }
139 | };
140 |
141 | Generator.prototype.setupEnv = function setupEnv() {
142 | var _rootDir = this.isFullApp ? 'app/' : '';
143 |
144 | // templates
145 | this.mkdir( _rootDir + 'templates' );
146 | this.copy( 'app/welcome.hbs', _rootDir + 'templates/welcome.hbs');
147 |
148 | // server
149 | if( this.isFullApp ) {
150 | this.mkdir('server');
151 | this.template('server/app.js', 'server/app.js');
152 | }
153 |
154 | //html
155 | this.template( 'app/index.html', _rootDir + 'index.html' );
156 |
157 | // js
158 | this.mkdir( _rootDir + 'scripts' );
159 | this.copy( 'app/main.js', _rootDir + 'scripts/main.js' );
160 | this.template( 'app/init.js', _rootDir + 'scripts/init.js' );
161 | this.copy( 'app/regionManager.js', _rootDir + 'scripts/regionManager.js' );
162 | this.copy( 'app/application.js', _rootDir + 'scripts/application.js' );
163 | this.copy( 'app/communicator.js', _rootDir + 'scripts/communicator.js' );
164 |
165 | // other
166 | if( this.isFullApp ) {
167 | this.mkdir('app/styles');
168 | this.mkdir('app/images');
169 | this.template('app/404.html');
170 | this.template('app/favicon.ico');
171 | this.template('app/robots.txt');
172 | this.copy('app/htaccess', 'app/.htaccess');
173 | }
174 |
175 | };
176 |
177 |
--------------------------------------------------------------------------------
/app/templates/Gruntfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;
3 | var mountFolder = function (connect, dir) {
4 | return connect.static(require('path').resolve(dir));
5 | };
6 |
7 | // # Globbing
8 | // for performance reasons we're only matching one level down:
9 | // 'test/spec/{,*/}*.js'
10 | // use this if you want to match all subfolders:
11 | // 'test/spec/**/*.js'
12 | // templateFramework: '<%= templateFramework %>'
13 |
14 | module.exports = function (grunt) {
15 | // load all grunt tasks
16 | require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
17 | // show elapsed time at the end
18 | require('time-grunt')(grunt);
19 |
20 | // configurable paths
21 | var yeomanConfig = {
22 | app: <% if(isFullApp){ %>'app'<%}else{%>''<%}%>,
23 | dist: 'dist'
24 | };
25 |
26 | grunt.initConfig({
27 | yeoman: yeomanConfig,
28 |
29 | // watch list
30 | watch: {
31 | <% if(isFullApp){ %>
32 | compass: {
33 | files: ['<%%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
34 | tasks: ['compass']
35 | },
36 | <%}%>
37 | livereload: {
38 | files: [
39 | <% if(isFullApp){ %>
40 | '<%%= yeoman.app %>/*.html',
41 | '{.tmp,<%%= yeoman.app %>}/styles/{,**/}*.css',
42 | '{.tmp,<%%= yeoman.app %>}/scripts/{,**/}*.js',
43 | '{.tmp,<%%= yeoman.app %>}/templates/{,**/}*.hbs',
44 | '<%%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp}',
45 | <%}else{%>
46 | 'scripts/{,**/}*.js',
47 | 'templates/{,**/}*.hbs',
48 | <%}%>
49 | 'test/spec/{,**/}*.js'
50 | ],
51 | tasks: ['exec'],
52 | options: {
53 | livereload: true
54 | }
55 | }
56 | /* not used at the moment
57 | handlebars: {
58 | files: [
59 | '<%%= yeoman.app %>/templates/*.hbs'
60 | ],
61 | tasks: ['handlebars']
62 | }*/
63 | },
64 |
65 | // testing server
66 | connect: {
67 | testserver: {
68 | options: {
69 | port: 1234,
70 | base: '.'
71 | }
72 | }
73 | },
74 |
75 | // mocha command
76 | exec: {
77 | mocha: {
78 | command: 'mocha-phantomjs http://localhost:<%%= connect.testserver.options.port %>/test',
79 | stdout: true
80 | }
81 | },
82 |
83 | <% if(isFullApp){ %>
84 | // express app
85 | express: {
86 | options: {
87 | // Override defaults here
88 | port: '9000'
89 | },
90 | dev: {
91 | options: {
92 | script: 'server/app.js'
93 | }
94 | },
95 | prod: {
96 | options: {
97 | script: 'server/app.js'
98 | }
99 | },
100 | test: {
101 | options: {
102 | script: 'server/app.js'
103 | }
104 | }
105 | },
106 | <%}%>
107 |
108 | // open app and test page
109 | open: {
110 | server: {
111 | path: <% if(isFullApp){ %>'http://localhost:<%%= express.options.port %>'<%} else {%>'http://localhost:<%%= connect.testserver.options.port %>'<%}%>
112 | }
113 | },
114 |
115 | clean: {
116 | dist: ['.tmp', '<%%= yeoman.dist %>/*'],
117 | server: '.tmp'
118 | },
119 |
120 | // linting
121 | jshint: {
122 | options: {
123 | jshintrc: '.jshintrc',
124 | reporter: require('jshint-stylish')
125 | },
126 | all: [
127 | 'Gruntfile.js',
128 | '<%%= yeoman.app %>/scripts/{,*/}*.js',
129 | '!<%%= yeoman.app %>/scripts/vendor/*',
130 | 'test/spec/{,*/}*.js'
131 | ]
132 | },
133 |
134 | <% if(isFullApp){ %>
135 | // compass
136 | compass: {
137 | options: {
138 | sassDir: '<%%= yeoman.app %>/styles',
139 | cssDir: '.tmp/styles',
140 | imagesDir: '<%%= yeoman.app %>/images',
141 | javascriptsDir: '<%%= yeoman.app %>/scripts',
142 | fontsDir: '<%%= yeoman.app %>/styles/fonts',
143 | importPath: 'app/<%= bowerDirectory %>',
144 | relativeAssets: true
145 | },
146 | dist: {},
147 | server: {
148 | options: {
149 | debugInfo: true
150 | }
151 | }
152 | },
153 | <%}%>
154 |
155 | // require
156 | requirejs: {
157 | dist: {
158 | // Options: https://github.com/jrburke/r.js/blob/master/build/example.build.js
159 | options: {
160 | // `name` and `out` is set by grunt-usemin
161 | baseUrl: 'app/scripts',
162 | optimize: 'none',
163 | paths: {
164 | 'templates': '../../.tmp/scripts/templates'
165 | },
166 | // TODO: Figure out how to make sourcemaps work with grunt-usemin
167 | // https://github.com/yeoman/grunt-usemin/issues/30
168 | //generateSourceMaps: true,
169 | // required to support SourceMaps
170 | // http://requirejs.org/docs/errors.html#sourcemapcomments
171 | preserveLicenseComments: false,
172 | useStrict: true,
173 | wrap: true,
174 | //uglify2: {} // https://github.com/mishoo/UglifyJS2
175 | pragmasOnSave: {
176 | //removes Handlebars.Parser code (used to compile template strings) set
177 | //it to `false` if you need to parse template strings even after build
178 | excludeHbsParser : true,
179 | // kills the entire plugin set once it's built.
180 | excludeHbs: true,
181 | // removes i18n precompiler, handlebars and json2
182 | excludeAfterBuild: true
183 | }
184 | }
185 | }
186 | },
187 |
188 | useminPrepare: {
189 | html: '<%%= yeoman.app %>/index.html',
190 | options: {
191 | dest: '<%%= yeoman.dist %>'
192 | }
193 | },
194 |
195 | usemin: {
196 | html: ['<%%= yeoman.dist %>/{,*/}*.html'],
197 | css: ['<%%= yeoman.dist %>/styles/{,*/}*.css'],
198 | options: {
199 | dirs: ['<%%= yeoman.dist %>']
200 | }
201 | },
202 |
203 | imagemin: {
204 | dist: {
205 | files: [{
206 | expand: true,
207 | cwd: '<%%= yeoman.app %>/images',
208 | src: '{,*/}*.{png,jpg,jpeg}',
209 | dest: '<%%= yeoman.dist %>/images'
210 | }]
211 | }
212 | },
213 |
214 | cssmin: {
215 | dist: {
216 | files: {
217 | '<%%= yeoman.dist %>/styles/main.css': [
218 | '.tmp/styles/{,*/}*.css',
219 | '<%%= yeoman.app %>/styles/{,*/}*.css'
220 | ]
221 | }
222 | }
223 | },
224 |
225 | htmlmin: {
226 | dist: {
227 | options: {
228 | /*removeCommentsFromCDATA: true,
229 | // https://github.com/yeoman/grunt-usemin/issues/44
230 | //collapseWhitespace: true,
231 | collapseBooleanAttributes: true,
232 | removeAttributeQuotes: true,
233 | removeRedundantAttributes: true,
234 | useShortDoctype: true,
235 | removeEmptyAttributes: true,
236 | removeOptionalTags: true*/
237 | },
238 | files: [{
239 | expand: true,
240 | cwd: '<%%= yeoman.app %>',
241 | src: '*.html',
242 | dest: '<%%= yeoman.dist %>'
243 | }]
244 | }
245 | },
246 |
247 | copy: {
248 | dist: {
249 | files: [{
250 | expand: true,
251 | dot: true,
252 | cwd: '<%%= yeoman.app %>',
253 | dest: '<%%= yeoman.dist %>',
254 | src: [
255 | '*.{ico,txt}',
256 | '.htaccess',
257 | 'images/{,*/}*.{webp,gif}',
258 | '<%= bowerDirectory %>/requirejs/require.js'
259 | ]
260 | }]
261 | }
262 | },
263 |
264 | bower: {
265 | all: {
266 | rjsConfig: '<%%= yeoman.app %>/scripts/main.js'
267 | }
268 | },
269 |
270 | // handlebars
271 | handlebars: {
272 | compile: {
273 | options: {
274 | namespace: 'JST',
275 | amd: true
276 | },
277 | files: {
278 | '.tmp/scripts/templates.js': ['<%= yeoman.app %>templates/**/*.hbs']
279 | }
280 | }
281 | }
282 | });
283 |
284 | grunt.registerTask('createDefaultTemplate', function () {
285 | grunt.file.write('.tmp/scripts/templates.js', 'this.JST = this.JST || {};');
286 | });
287 |
288 | // starts express server with live testing via testserver
289 | grunt.registerTask('default', function (target) {
290 |
291 | // what is this??
292 | if (target === 'dist') {
293 | return grunt.task.run(['build', 'open', 'connect:dist:keepalive']);
294 | }
295 |
296 | grunt.option('force', true);
297 |
298 | grunt.task.run([
299 | 'clean:server',
300 | <% if(isFullApp){ %>'compass:server',<%}%>
301 | 'connect:testserver',
302 | <% if(isFullApp){ %>'express:dev',<%}%>
303 | 'exec',
304 | 'open',
305 | 'watch'
306 | ]);
307 | });
308 |
309 | // todo fix these
310 | grunt.registerTask('test', [
311 | 'clean:server',
312 | 'createDefaultTemplate',
313 | 'handlebars',
314 | 'compass',
315 | 'connect:testserver',
316 | 'exec:mocha'
317 | ]);
318 |
319 | grunt.registerTask('build', [
320 | 'createDefaultTemplate',
321 | 'handlebars',
322 | 'compass:dist',
323 | 'useminPrepare',
324 | 'requirejs',
325 | 'imagemin',
326 | 'htmlmin',
327 | 'concat',
328 | 'cssmin',
329 | 'uglify',
330 | 'copy',
331 | 'usemin'
332 | ]);
333 |
334 | };
335 |
--------------------------------------------------------------------------------
/app/templates/_bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "<%= _.slugify(appname) %>",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "sass-bootstrap": "~2.3.0",
6 | "jquery": "~1.9.0",
7 | "requirejs": "~2.1.5",
8 | "requirejs-text": "~2.0.5",
9 | "backbone-amd": "~1.0.0",
10 | "underscore-amd": "~1.4.4",
11 | "modernizr": "~2.6.2",
12 | "backbone.marionette": "~1.0.2",
13 | "backbone.wreqr": "~0.2.0",
14 | "backbone.babysitter": "~0.0.6",
15 | "require-handlebars-plugin": "~0.4.0",
16 | "mocha": "~1.12.0",
17 | "chai": "~1.7.2",
18 | "sinon": "~1.7.3"
19 | },
20 | "devDependencies": {},
21 | "directory": "<%= bowerDirectory %>"
22 | }
23 |
--------------------------------------------------------------------------------
/app/templates/_package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "<%= _.slugify(appname) %>",
3 | "version": "0.0.1",
4 | <% if(isFullApp){ %>
5 | "dependencies": {
6 | "express": "~3.2.4",
7 | "request": "~2.21.0",
8 | "async": "~0.2.8",<% if(useMongoose){ %>
9 | "mongodb": "~1.3.6",
10 | "mongoose": "~3.6.11",<% } %><% if(useSocketIO){ %>
11 | "socket.io": "~0.9.14",<% } %><% if(useBaucis){ %>
12 | "baucis": "~0.4.6",<% } %>
13 | "express-hbs": "~0.2.0",
14 | "underscore": "~1.4.4"
15 | },
16 | <% } %>
17 | "devDependencies": {
18 | "grunt": "~0.4.1",
19 | "grunt-contrib-copy": "~0.4.0",
20 | "grunt-contrib-concat": "~0.2.0",
21 | "grunt-contrib-coffee": "~0.6.6",
22 | "grunt-contrib-handlebars": "~0.5.8",
23 | "grunt-contrib-uglify": "~0.2.0",
24 | "grunt-contrib-compass": "~0.2.0",
25 | "grunt-contrib-jshint": "~0.4.3",
26 | "grunt-contrib-cssmin": "~0.6.0",
27 | "grunt-contrib-connect": "0.3.0",
28 | "grunt-contrib-clean": "0.4.0",
29 | "grunt-contrib-htmlmin": "0.1.3",
30 | "grunt-contrib-imagemin": "0.1.4",
31 | "grunt-contrib-livereload": "0.1.2",
32 | "grunt-mocha": "~0.3.1",
33 | "grunt-bower-requirejs": "~0.4.1",
34 | "grunt-usemin": "~0.1.10",
35 | "grunt-requirejs": "~0.4.0",
36 | "grunt-open": "~0.2.0",
37 | "grunt-express-server": "~0.4.1",
38 | "matchdep": "~0.1.2",
39 | "mocha-phantomjs": "~3.1.0",
40 | "jshint-stylish": "~0.1.3",
41 | "grunt-exec": "~0.4.2",
42 | "grunt-contrib-watch": "~0.4.4",
43 | "time-grunt": "~0.1.1"
44 | },
45 | "engines": {
46 | "node": ">=0.8.0"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/templates/app/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Page Not Found :(
6 |
141 |
142 |
143 |
144 |
Not found :(
145 |
Sorry, but the page you were trying to view does not exist.
146 |
It looks like this was the result of either:
147 |
148 | - a mistyped address
149 | - an out-of-date link
150 |
151 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/app/templates/app/application.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone',
3 | 'communicator',
4 | 'hbs!tmpl/welcome'
5 | ],
6 |
7 | function( Backbone, Communicator, Welcome_tmpl ) {
8 | 'use strict';
9 |
10 | var welcomeTmpl = Welcome_tmpl;
11 |
12 | var App = new Backbone.Marionette.Application();
13 |
14 | /* Add application regions here */
15 | App.addRegions({});
16 |
17 | /* Add initializers here */
18 | App.addInitializer( function () {
19 | document.body.innerHTML = welcomeTmpl({ success: "CONGRATS!" });
20 | Communicator.mediator.trigger("APP:START");
21 | });
22 |
23 | return App;
24 | });
25 |
--------------------------------------------------------------------------------
/app/templates/app/communicator.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone',
3 | 'backbone.marionette'
4 | ],
5 | function( Backbone ) {
6 | 'use strict';
7 |
8 | var Communicator = Backbone.Marionette.Controller.extend({
9 | initialize: function( options ) {
10 | console.log("initialize a Communicator");
11 |
12 | // create a pub sub
13 | this.mediator = new Backbone.Wreqr.EventAggregator();
14 |
15 | //create a req/res
16 | this.reqres = new Backbone.Wreqr.RequestResponse();
17 |
18 | // create commands
19 | this.command = new Backbone.Wreqr.Commands();
20 | }
21 | });
22 |
23 | return new Communicator();
24 | });
25 |
--------------------------------------------------------------------------------
/app/templates/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrichard/generator-marionette/890c71c5d89ce25b631fe83693a76a6b46b4cad2/app/templates/app/favicon.ico
--------------------------------------------------------------------------------
/app/templates/app/htaccess:
--------------------------------------------------------------------------------
1 | # Apache configuration file
2 | # httpd.apache.org/docs/2.2/mod/quickreference.html
3 |
4 | # Note .htaccess files are an overhead, this logic should be in your Apache
5 | # config if possible: httpd.apache.org/docs/2.2/howto/htaccess.html
6 |
7 | # Techniques in here adapted from all over, including:
8 | # Kroc Camen: camendesign.com/.htaccess
9 | # perishablepress.com/press/2006/01/10/stupid-htaccess-tricks/
10 | # Sample .htaccess file of CMS MODx: modxcms.com
11 |
12 |
13 | # ----------------------------------------------------------------------
14 | # Better website experience for IE users
15 | # ----------------------------------------------------------------------
16 |
17 | # Force the latest IE version, in various cases when it may fall back to IE7 mode
18 | # github.com/rails/rails/commit/123eb25#commitcomment-118920
19 | # Use ChromeFrame if it's installed for a better experience for the poor IE folk
20 |
21 |
22 | Header set X-UA-Compatible "IE=Edge,chrome=1"
23 | # mod_headers can't match by content-type, but we don't want to send this header on *everything*...
24 |
25 | Header unset X-UA-Compatible
26 |
27 |
28 |
29 |
30 | # ----------------------------------------------------------------------
31 | # Cross-domain AJAX requests
32 | # ----------------------------------------------------------------------
33 |
34 | # Serve cross-domain Ajax requests, disabled by default.
35 | # enable-cors.org
36 | # code.google.com/p/html5security/wiki/CrossOriginRequestSecurity
37 |
38 | #
39 | # Header set Access-Control-Allow-Origin "*"
40 | #
41 |
42 |
43 | # ----------------------------------------------------------------------
44 | # CORS-enabled images (@crossorigin)
45 | # ----------------------------------------------------------------------
46 |
47 | # Send CORS headers if browsers request them; enabled by default for images.
48 | # developer.mozilla.org/en/CORS_Enabled_Image
49 | # blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html
50 | # hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/
51 | # wiki.mozilla.org/Security/Reviews/crossoriginAttribute
52 |
53 |
54 |
55 | # mod_headers, y u no match by Content-Type?!
56 |
57 | SetEnvIf Origin ":" IS_CORS
58 | Header set Access-Control-Allow-Origin "*" env=IS_CORS
59 |
60 |
61 |
62 |
63 |
64 | # ----------------------------------------------------------------------
65 | # Webfont access
66 | # ----------------------------------------------------------------------
67 |
68 | # Allow access from all domains for webfonts.
69 | # Alternatively you could only whitelist your
70 | # subdomains like "subdomain.example.com".
71 |
72 |
73 |
74 | Header set Access-Control-Allow-Origin "*"
75 |
76 |
77 |
78 |
79 | # ----------------------------------------------------------------------
80 | # Proper MIME type for all files
81 | # ----------------------------------------------------------------------
82 |
83 | # JavaScript
84 | # Normalize to standard type (it's sniffed in IE anyways)
85 | # tools.ietf.org/html/rfc4329#section-7.2
86 | AddType application/javascript js jsonp
87 | AddType application/json json
88 |
89 | # Audio
90 | AddType audio/ogg oga ogg
91 | AddType audio/mp4 m4a f4a f4b
92 |
93 | # Video
94 | AddType video/ogg ogv
95 | AddType video/mp4 mp4 m4v f4v f4p
96 | AddType video/webm webm
97 | AddType video/x-flv flv
98 |
99 | # SVG
100 | # Required for svg webfonts on iPad
101 | # twitter.com/FontSquirrel/status/14855840545
102 | AddType image/svg+xml svg svgz
103 | AddEncoding gzip svgz
104 |
105 | # Webfonts
106 | AddType application/vnd.ms-fontobject eot
107 | AddType application/x-font-ttf ttf ttc
108 | AddType font/opentype otf
109 | AddType application/x-font-woff woff
110 |
111 | # Assorted types
112 | AddType image/x-icon ico
113 | AddType image/webp webp
114 | AddType text/cache-manifest appcache manifest
115 | AddType text/x-component htc
116 | AddType application/xml rss atom xml rdf
117 | AddType application/x-chrome-extension crx
118 | AddType application/x-opera-extension oex
119 | AddType application/x-xpinstall xpi
120 | AddType application/octet-stream safariextz
121 | AddType application/x-web-app-manifest+json webapp
122 | AddType text/x-vcard vcf
123 | AddType application/x-shockwave-flash swf
124 | AddType text/vtt vtt
125 |
126 |
127 | # ----------------------------------------------------------------------
128 | # Allow concatenation from within specific js and css files
129 | # ----------------------------------------------------------------------
130 |
131 | # e.g. Inside of script.combined.js you could have
132 | #
133 | #
134 | # and they would be included into this single file.
135 |
136 | # This is not in use in the boilerplate as it stands. You may
137 | # choose to use this technique if you do not have a build process.
138 |
139 | #
140 | # Options +Includes
141 | # AddOutputFilterByType INCLUDES application/javascript application/json
142 | # SetOutputFilter INCLUDES
143 | #
144 |
145 | #
146 | # Options +Includes
147 | # AddOutputFilterByType INCLUDES text/css
148 | # SetOutputFilter INCLUDES
149 | #
150 |
151 |
152 | # ----------------------------------------------------------------------
153 | # Gzip compression
154 | # ----------------------------------------------------------------------
155 |
156 |
157 |
158 | # Force deflate for mangled headers developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping/
159 |
160 |
161 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
162 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
163 |
164 |
165 |
166 | # HTML, TXT, CSS, JavaScript, JSON, XML, HTC:
167 |
168 | FilterDeclare COMPRESS
169 | FilterProvider COMPRESS DEFLATE resp=Content-Type $text/html
170 | FilterProvider COMPRESS DEFLATE resp=Content-Type $text/css
171 | FilterProvider COMPRESS DEFLATE resp=Content-Type $text/plain
172 | FilterProvider COMPRESS DEFLATE resp=Content-Type $text/xml
173 | FilterProvider COMPRESS DEFLATE resp=Content-Type $text/x-component
174 | FilterProvider COMPRESS DEFLATE resp=Content-Type $application/javascript
175 | FilterProvider COMPRESS DEFLATE resp=Content-Type $application/json
176 | FilterProvider COMPRESS DEFLATE resp=Content-Type $application/xml
177 | FilterProvider COMPRESS DEFLATE resp=Content-Type $application/xhtml+xml
178 | FilterProvider COMPRESS DEFLATE resp=Content-Type $application/rss+xml
179 | FilterProvider COMPRESS DEFLATE resp=Content-Type $application/atom+xml
180 | FilterProvider COMPRESS DEFLATE resp=Content-Type $application/vnd.ms-fontobject
181 | FilterProvider COMPRESS DEFLATE resp=Content-Type $image/svg+xml
182 | FilterProvider COMPRESS DEFLATE resp=Content-Type $image/x-icon
183 | FilterProvider COMPRESS DEFLATE resp=Content-Type $application/x-font-ttf
184 | FilterProvider COMPRESS DEFLATE resp=Content-Type $font/opentype
185 | FilterChain COMPRESS
186 | FilterProtocol COMPRESS DEFLATE change=yes;byteranges=no
187 |
188 |
189 |
190 | # Legacy versions of Apache
191 | AddOutputFilterByType DEFLATE text/html text/plain text/css application/json
192 | AddOutputFilterByType DEFLATE application/javascript
193 | AddOutputFilterByType DEFLATE text/xml application/xml text/x-component
194 | AddOutputFilterByType DEFLATE application/xhtml+xml application/rss+xml application/atom+xml
195 | AddOutputFilterByType DEFLATE image/x-icon image/svg+xml application/vnd.ms-fontobject application/x-font-ttf font/opentype
196 |
197 |
198 |
199 |
200 |
201 | # ----------------------------------------------------------------------
202 | # Expires headers (for better cache control)
203 | # ----------------------------------------------------------------------
204 |
205 | # These are pretty far-future expires headers.
206 | # They assume you control versioning with filename-based cache busting
207 | # Additionally, consider that outdated proxies may miscache
208 | # www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/
209 |
210 | # If you don't use filenames to version, lower the CSS and JS to something like
211 | # "access plus 1 week".
212 |
213 |
214 | ExpiresActive on
215 |
216 | # Perhaps better to whitelist expires rules? Perhaps.
217 | ExpiresDefault "access plus 1 month"
218 |
219 | # cache.appcache needs re-requests in FF 3.6 (thanks Remy ~Introducing HTML5)
220 | ExpiresByType text/cache-manifest "access plus 0 seconds"
221 |
222 | # Your document html
223 | ExpiresByType text/html "access plus 0 seconds"
224 |
225 | # Data
226 | ExpiresByType text/xml "access plus 0 seconds"
227 | ExpiresByType application/xml "access plus 0 seconds"
228 | ExpiresByType application/json "access plus 0 seconds"
229 |
230 | # Feed
231 | ExpiresByType application/rss+xml "access plus 1 hour"
232 | ExpiresByType application/atom+xml "access plus 1 hour"
233 |
234 | # Favicon (cannot be renamed)
235 | ExpiresByType image/x-icon "access plus 1 week"
236 |
237 | # Media: images, video, audio
238 | ExpiresByType image/gif "access plus 1 month"
239 | ExpiresByType image/png "access plus 1 month"
240 | ExpiresByType image/jpeg "access plus 1 month"
241 | ExpiresByType video/ogg "access plus 1 month"
242 | ExpiresByType audio/ogg "access plus 1 month"
243 | ExpiresByType video/mp4 "access plus 1 month"
244 | ExpiresByType video/webm "access plus 1 month"
245 |
246 | # HTC files (css3pie)
247 | ExpiresByType text/x-component "access plus 1 month"
248 |
249 | # Webfonts
250 | ExpiresByType application/x-font-ttf "access plus 1 month"
251 | ExpiresByType font/opentype "access plus 1 month"
252 | ExpiresByType application/x-font-woff "access plus 1 month"
253 | ExpiresByType image/svg+xml "access plus 1 month"
254 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
255 |
256 | # CSS and JavaScript
257 | ExpiresByType text/css "access plus 1 year"
258 | ExpiresByType application/javascript "access plus 1 year"
259 |
260 |
261 |
262 |
263 | # ----------------------------------------------------------------------
264 | # Prevent mobile network providers from modifying your site
265 | # ----------------------------------------------------------------------
266 |
267 | # The following header prevents modification of your code over 3G on some
268 | # European providers.
269 | # This is the official 'bypass' suggested by O2 in the UK.
270 |
271 | #
272 | # Header set Cache-Control "no-transform"
273 | #
274 |
275 |
276 | # ----------------------------------------------------------------------
277 | # ETag removal
278 | # ----------------------------------------------------------------------
279 |
280 | # FileETag None is not enough for every server.
281 |
282 | Header unset ETag
283 |
284 |
285 | # Since we're sending far-future expires, we don't need ETags for
286 | # static content.
287 | # developer.yahoo.com/performance/rules.html#etags
288 | FileETag None
289 |
290 |
291 | # ----------------------------------------------------------------------
292 | # Stop screen flicker in IE on CSS rollovers
293 | # ----------------------------------------------------------------------
294 |
295 | # The following directives stop screen flicker in IE on CSS rollovers - in
296 | # combination with the "ExpiresByType" rules for images (see above).
297 |
298 | # BrowserMatch "MSIE" brokenvary=1
299 | # BrowserMatch "Mozilla/4.[0-9]{2}" brokenvary=1
300 | # BrowserMatch "Opera" !brokenvary
301 | # SetEnvIf brokenvary 1 force-no-vary
302 |
303 |
304 | # ----------------------------------------------------------------------
305 | # Set Keep-Alive Header
306 | # ----------------------------------------------------------------------
307 |
308 | # Keep-Alive allows the server to send multiple requests through one
309 | # TCP-connection. Be aware of possible disadvantages of this setting. Turn on
310 | # if you serve a lot of static content.
311 |
312 | #
313 | # Header set Connection Keep-Alive
314 | #
315 |
316 |
317 | # ----------------------------------------------------------------------
318 | # Cookie setting from iframes
319 | # ----------------------------------------------------------------------
320 |
321 | # Allow cookies to be set from iframes (for IE only)
322 | # If needed, specify a path or regex in the Location directive.
323 |
324 | #
325 | # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\""
326 | #
327 |
328 |
329 | # ----------------------------------------------------------------------
330 | # Start rewrite engine
331 | # ----------------------------------------------------------------------
332 |
333 | # Turning on the rewrite engine is necessary for the following rules and
334 | # features. FollowSymLinks must be enabled for this to work.
335 |
336 | # Some cloud hosting services require RewriteBase to be set: goo.gl/HOcPN
337 | # If using the h5bp in a subdirectory, use `RewriteBase /foo` instead where
338 | # 'foo' is your directory.
339 |
340 | # If your web host doesn't allow the FollowSymlinks option, you may need to
341 | # comment it out and use `Options +SymLinksOfOwnerMatch`, but be aware of the
342 | # performance impact: http://goo.gl/Mluzd
343 |
344 |
345 | Options +FollowSymlinks
346 | # Options +SymLinksIfOwnerMatch
347 | Options +FollowSymlinks
348 | RewriteEngine On
349 | # RewriteBase /
350 |
351 |
352 |
353 | # ----------------------------------------------------------------------
354 | # Suppress or force the "www." at the beginning of URLs
355 | # ----------------------------------------------------------------------
356 |
357 | # The same content should never be available under two different URLs -
358 | # especially not with and without "www." at the beginning, since this can cause
359 | # SEO problems (duplicate content). That's why you should choose one of the
360 | # alternatives and redirect the other one.
361 |
362 | # By default option 1 (no "www.") is activated.
363 | # no-www.org/faq.php?q=class_b
364 |
365 | # If you'd prefer to use option 2, just comment out all option 1 lines
366 | # and uncomment option 2.
367 |
368 | # IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME!
369 |
370 | # ----------------------------------------------------------------------
371 |
372 | # Option 1:
373 | # Rewrite "www.example.com -> example.com".
374 |
375 |
376 | RewriteCond %{HTTPS} !=on
377 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
378 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
379 |
380 |
381 | # ----------------------------------------------------------------------
382 |
383 | # Option 2:
384 | # Rewrite "example.com -> www.example.com".
385 | # Be aware that the following rule might not be a good idea if you use "real"
386 | # subdomains for certain parts of your website.
387 |
388 | #
389 | # RewriteCond %{HTTPS} !=on
390 | # RewriteCond %{HTTP_HOST} !^www\..+$ [NC]
391 | # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
392 | #
393 |
394 |
395 | # ----------------------------------------------------------------------
396 | # Built-in filename-based cache busting
397 | # ----------------------------------------------------------------------
398 |
399 | # If you're not using the build script to manage your filename version revving,
400 | # you might want to consider enabling this, which will route requests for
401 | # /css/style.20110203.css to /css/style.css
402 |
403 | # To understand why this is important and a better idea than all.css?v1231,
404 | # read: github.com/h5bp/html5-boilerplate/wiki/cachebusting
405 |
406 | #
407 | # RewriteCond %{REQUEST_FILENAME} !-f
408 | # RewriteCond %{REQUEST_FILENAME} !-d
409 | # RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L]
410 | #
411 |
412 |
413 | # ----------------------------------------------------------------------
414 | # Prevent SSL cert warnings
415 | # ----------------------------------------------------------------------
416 |
417 | # Rewrite secure requests properly to prevent SSL cert warnings, e.g. prevent
418 | # https://www.example.com when your cert only allows https://secure.example.com
419 |
420 | #
421 | # RewriteCond %{SERVER_PORT} !^443
422 | # RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L]
423 | #
424 |
425 |
426 | # ----------------------------------------------------------------------
427 | # Prevent 404 errors for non-existing redirected folders
428 | # ----------------------------------------------------------------------
429 |
430 | # without -MultiViews, Apache will give a 404 for a rewrite if a folder of the
431 | # same name does not exist.
432 | # webmasterworld.com/apache/3808792.htm
433 |
434 | Options -MultiViews
435 |
436 |
437 | # ----------------------------------------------------------------------
438 | # Custom 404 page
439 | # ----------------------------------------------------------------------
440 |
441 | # You can add custom pages to handle 500 or 403 pretty easily, if you like.
442 | # If you are hosting your site in subdirectory, adjust this accordingly
443 | # e.g. ErrorDocument 404 /subdir/404.html
444 | ErrorDocument 404 /404.html
445 |
446 |
447 | # ----------------------------------------------------------------------
448 | # UTF-8 encoding
449 | # ----------------------------------------------------------------------
450 |
451 | # Use UTF-8 encoding for anything served text/plain or text/html
452 | AddDefaultCharset utf-8
453 |
454 | # Force UTF-8 for a number of file formats
455 | AddCharset utf-8 .atom .css .js .json .rss .vtt .xml
456 |
457 |
458 | # ----------------------------------------------------------------------
459 | # A little more security
460 | # ----------------------------------------------------------------------
461 |
462 | # To avoid displaying the exact version number of Apache being used, add the
463 | # following to httpd.conf (it will not work in .htaccess):
464 | # ServerTokens Prod
465 |
466 | # "-Indexes" will have Apache block users from browsing folders without a
467 | # default document Usually you should leave this activated, because you
468 | # shouldn't allow everybody to surf through every folder on your server (which
469 | # includes rather private places like CMS system folders).
470 |
471 | Options -Indexes
472 |
473 |
474 | # Block access to "hidden" directories or files whose names begin with a
475 | # period. This includes directories used by version control systems such as
476 | # Subversion or Git.
477 |
478 | RewriteCond %{SCRIPT_FILENAME} -d [OR]
479 | RewriteCond %{SCRIPT_FILENAME} -f
480 | RewriteRule "(^|/)\." - [F]
481 |
482 |
483 | # Block access to backup and source files. These files may be left by some
484 | # text/html editors and pose a great security danger, when anyone can access
485 | # them.
486 |
487 | Order allow,deny
488 | Deny from all
489 | Satisfy All
490 |
491 |
492 | # If your server is not already configured as such, the following directive
493 | # should be uncommented in order to set PHP's register_globals option to OFF.
494 | # This closes a major security hole that is abused by most XSS (cross-site
495 | # scripting) attacks. For more information: http://php.net/register_globals
496 | #
497 | # IF REGISTER_GLOBALS DIRECTIVE CAUSES 500 INTERNAL SERVER ERRORS:
498 | #
499 | # Your server does not allow PHP directives to be set via .htaccess. In that
500 | # case you must make this change in your php.ini file instead. If you are
501 | # using a commercial web host, contact the administrators for assistance in
502 | # doing this. Not all servers allow local php.ini files, and they should
503 | # include all PHP configurations (not just this one), or you will effectively
504 | # reset everything to PHP defaults. Consult www.php.net for more detailed
505 | # information about setting PHP directives.
506 |
507 | # php_flag register_globals Off
508 |
509 | # Rename session cookie to something else, than PHPSESSID
510 | # php_value session.name sid
511 |
512 | # Disable magic quotes (This feature has been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 5.4.0.)
513 | # php_flag magic_quotes_gpc Off
514 |
515 | # Do not show you are using PHP
516 | # Note: Move this line to php.ini since it won't work in .htaccess
517 | # php_flag expose_php Off
518 |
519 | # Level of log detail - log all errors
520 | # php_value error_reporting -1
521 |
522 | # Write errors to log file
523 | # php_flag log_errors On
524 |
525 | # Do not display errors in browser (production - Off, development - On)
526 | # php_flag display_errors Off
527 |
528 | # Do not display startup errors (production - Off, development - On)
529 | # php_flag display_startup_errors Off
530 |
531 | # Format errors in plain text
532 | # Note: Leave this setting 'On' for xdebug's var_dump() output
533 | # php_flag html_errors Off
534 |
535 | # Show multiple occurrence of error
536 | # php_flag ignore_repeated_errors Off
537 |
538 | # Show same errors from different sources
539 | # php_flag ignore_repeated_source Off
540 |
541 | # Size limit for error messages
542 | # php_value log_errors_max_len 1024
543 |
544 | # Don't precede error with string (doesn't accept empty string, use whitespace if you need)
545 | # php_value error_prepend_string " "
546 |
547 | # Don't prepend to error (doesn't accept empty string, use whitespace if you need)
548 | # php_value error_append_string " "
549 |
550 | # Increase cookie security
551 |
552 | php_value session.cookie_httponly true
553 |
554 |
--------------------------------------------------------------------------------
/app/templates/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | <% if(!isFullApp){ %>TEST HTML PAGE - YOUR JS WORKS!<%}%>
12 |
13 |
14 |
15 |
16 |
17 | <% if(isFullApp){ %>
18 |
19 | <% } %>
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/templates/app/init.js:
--------------------------------------------------------------------------------
1 | require.config({
2 |
3 | <% if(isFullApp){ %>baseUrl: "/scripts",<%}%>
4 |
5 | /* starting point for application */
6 | deps: ['backbone.marionette', 'bootstrap', 'main'],
7 |
8 |
9 | shim: {
10 | backbone: {
11 | deps: [
12 | 'underscore',
13 | 'jquery'
14 | ],
15 | exports: 'Backbone'
16 | },
17 | bootstrap: {
18 | deps: ['jquery'],
19 | exports: 'jquery'
20 | }
21 | },
22 |
23 | paths: {
24 | jquery: '../<%= bowerDirectory %>/jquery/jquery',
25 | backbone: '../<%= bowerDirectory %>/backbone-amd/backbone',
26 | underscore: '../<%= bowerDirectory %>/underscore-amd/underscore',
27 |
28 | /* alias all marionette libs */
29 | 'backbone.marionette': '../<%= bowerDirectory %>/backbone.marionette/lib/core/amd/backbone.marionette',
30 | 'backbone.wreqr': '../<%= bowerDirectory %>/backbone.wreqr/lib/amd/backbone.wreqr',
31 | 'backbone.babysitter': '../<%= bowerDirectory %>/backbone.babysitter/lib/amd/backbone.babysitter',
32 |
33 | /* alias the bootstrap js lib */
34 | bootstrap: 'vendor/bootstrap',
35 |
36 | /* Alias text.js for template loading and shortcut the templates dir to tmpl */
37 | text: '../<%= bowerDirectory %>/requirejs-text/text',
38 | tmpl: "../templates",
39 |
40 | /* handlebars from the require handlerbars plugin below */
41 | handlebars: '../<%= bowerDirectory %>/require-handlebars-plugin/Handlebars',
42 |
43 | /* require handlebars plugin - Alex Sexton */
44 | i18nprecompile: '../<%= bowerDirectory %>/require-handlebars-plugin/hbs/i18nprecompile',
45 | json2: '../<%= bowerDirectory %>/require-handlebars-plugin/hbs/json2',
46 | hbs: '../<%= bowerDirectory %>/require-handlebars-plugin/hbs'
47 | },
48 |
49 | hbs: {
50 | disableI18n: true
51 | }
52 | });
53 |
--------------------------------------------------------------------------------
/app/templates/app/main.js:
--------------------------------------------------------------------------------
1 | require([
2 | 'backbone',
3 | 'application',
4 | 'regionManager'
5 | ],
6 | function ( Backbone, App ) {
7 | 'use strict';
8 |
9 | App.start();
10 | });
11 |
--------------------------------------------------------------------------------
/app/templates/app/regionManager.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone',
3 | 'communicator'
4 | ],
5 | function( Backbone, Communicator ) {
6 | 'use strict';
7 |
8 | var RegionManager = Backbone.Marionette.Controller.extend({
9 |
10 | initialize: function( options ) {
11 | console.log("Initialize a Region Manager");
12 |
13 | /* internal region manager */
14 | this._regionManager = new Backbone.Marionette.RegionManager();
15 |
16 | /* event API */
17 | Communicator.reqres.setHandler("RM:addRegion", this.addRegion, this);
18 | Communicator.reqres.setHandler("RM:removeRegion", this.removeRegion, this);
19 | Communicator.reqres.setHandler("RM:getRegion", this.getRegion, this);
20 | },
21 |
22 | /* add region facade */
23 | addRegion: function( regionName, regionId ) {
24 | var region = this.getRegion( regionName );
25 |
26 | if( region ) {
27 | console.log("REGION ALREADY CREATED TO JUST RETURN REF");
28 | return region;
29 | }
30 |
31 | return this._regionManager.addRegion( regionName, regionId );
32 | },
33 |
34 | /* remove region facade */
35 | removeRegion: function( regionName ) {
36 | this._regionManager.removeRegion( regionName );
37 | },
38 |
39 | /* get region facade */
40 | getRegion: function( regionName ) {
41 | return this._regionManager.get( regionName );
42 | }
43 | });
44 |
45 | return new RegionManager();
46 | });
47 |
--------------------------------------------------------------------------------
/app/templates/app/robots.txt:
--------------------------------------------------------------------------------
1 | # robotstxt.org
2 |
3 | User-agent: *
4 |
--------------------------------------------------------------------------------
/app/templates/app/welcome.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{success}}
4 |
You now have
5 |
6 | - HTML5 Boilerplate
7 | - jQuery
8 | - Backbone.js
9 | - Marionette.js
10 | - Underscore.js
11 | - Handlebars.js
12 | - RequireJS
13 | - Twitter Bootstrap
14 | - Express
15 |
16 |
17 |
installed.
18 |
Enjoy coding!
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/templates/bootstrap.js:
--------------------------------------------------------------------------------
1 | /* ===================================================
2 | * bootstrap-transition.js v2.3.0
3 | * http://twitter.github.com/bootstrap/javascript.html#transitions
4 | * ===================================================
5 | * Copyright 2012 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * ========================================================== */
19 |
20 |
21 | !function ($) {
22 |
23 | "use strict"; // jshint ;_;
24 |
25 |
26 | /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
27 | * ======================================================= */
28 |
29 | $(function () {
30 |
31 | $.support.transition = (function () {
32 |
33 | var transitionEnd = (function () {
34 |
35 | var el = document.createElement('bootstrap')
36 | , transEndEventNames = {
37 | 'WebkitTransition' : 'webkitTransitionEnd'
38 | , 'MozTransition' : 'transitionend'
39 | , 'OTransition' : 'oTransitionEnd otransitionend'
40 | , 'transition' : 'transitionend'
41 | }
42 | , name
43 |
44 | for (name in transEndEventNames){
45 | if (el.style[name] !== undefined) {
46 | return transEndEventNames[name]
47 | }
48 | }
49 |
50 | }())
51 |
52 | return transitionEnd && {
53 | end: transitionEnd
54 | }
55 |
56 | })()
57 |
58 | })
59 |
60 | }(window.jQuery);/* ==========================================================
61 | * bootstrap-alert.js v2.3.0
62 | * http://twitter.github.com/bootstrap/javascript.html#alerts
63 | * ==========================================================
64 | * Copyright 2012 Twitter, Inc.
65 | *
66 | * Licensed under the Apache License, Version 2.0 (the "License");
67 | * you may not use this file except in compliance with the License.
68 | * You may obtain a copy of the License at
69 | *
70 | * http://www.apache.org/licenses/LICENSE-2.0
71 | *
72 | * Unless required by applicable law or agreed to in writing, software
73 | * distributed under the License is distributed on an "AS IS" BASIS,
74 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
75 | * See the License for the specific language governing permissions and
76 | * limitations under the License.
77 | * ========================================================== */
78 |
79 |
80 | !function ($) {
81 |
82 | "use strict"; // jshint ;_;
83 |
84 |
85 | /* ALERT CLASS DEFINITION
86 | * ====================== */
87 |
88 | var dismiss = '[data-dismiss="alert"]'
89 | , Alert = function (el) {
90 | $(el).on('click', dismiss, this.close)
91 | }
92 |
93 | Alert.prototype.close = function (e) {
94 | var $this = $(this)
95 | , selector = $this.attr('data-target')
96 | , $parent
97 |
98 | if (!selector) {
99 | selector = $this.attr('href')
100 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
101 | }
102 |
103 | $parent = $(selector)
104 |
105 | e && e.preventDefault()
106 |
107 | $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
108 |
109 | $parent.trigger(e = $.Event('close'))
110 |
111 | if (e.isDefaultPrevented()) return
112 |
113 | $parent.removeClass('in')
114 |
115 | function removeElement() {
116 | $parent
117 | .trigger('closed')
118 | .remove()
119 | }
120 |
121 | $.support.transition && $parent.hasClass('fade') ?
122 | $parent.on($.support.transition.end, removeElement) :
123 | removeElement()
124 | }
125 |
126 |
127 | /* ALERT PLUGIN DEFINITION
128 | * ======================= */
129 |
130 | var old = $.fn.alert
131 |
132 | $.fn.alert = function (option) {
133 | return this.each(function () {
134 | var $this = $(this)
135 | , data = $this.data('alert')
136 | if (!data) $this.data('alert', (data = new Alert(this)))
137 | if (typeof option == 'string') data[option].call($this)
138 | })
139 | }
140 |
141 | $.fn.alert.Constructor = Alert
142 |
143 |
144 | /* ALERT NO CONFLICT
145 | * ================= */
146 |
147 | $.fn.alert.noConflict = function () {
148 | $.fn.alert = old
149 | return this
150 | }
151 |
152 |
153 | /* ALERT DATA-API
154 | * ============== */
155 |
156 | $(document).on('click.alert.data-api', dismiss, Alert.prototype.close)
157 |
158 | }(window.jQuery);/* ============================================================
159 | * bootstrap-button.js v2.3.0
160 | * http://twitter.github.com/bootstrap/javascript.html#buttons
161 | * ============================================================
162 | * Copyright 2012 Twitter, Inc.
163 | *
164 | * Licensed under the Apache License, Version 2.0 (the "License");
165 | * you may not use this file except in compliance with the License.
166 | * You may obtain a copy of the License at
167 | *
168 | * http://www.apache.org/licenses/LICENSE-2.0
169 | *
170 | * Unless required by applicable law or agreed to in writing, software
171 | * distributed under the License is distributed on an "AS IS" BASIS,
172 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
173 | * See the License for the specific language governing permissions and
174 | * limitations under the License.
175 | * ============================================================ */
176 |
177 |
178 | !function ($) {
179 |
180 | "use strict"; // jshint ;_;
181 |
182 |
183 | /* BUTTON PUBLIC CLASS DEFINITION
184 | * ============================== */
185 |
186 | var Button = function (element, options) {
187 | this.$element = $(element)
188 | this.options = $.extend({}, $.fn.button.defaults, options)
189 | }
190 |
191 | Button.prototype.setState = function (state) {
192 | var d = 'disabled'
193 | , $el = this.$element
194 | , data = $el.data()
195 | , val = $el.is('input') ? 'val' : 'html'
196 |
197 | state = state + 'Text'
198 | data.resetText || $el.data('resetText', $el[val]())
199 |
200 | $el[val](data[state] || this.options[state])
201 |
202 | // push to event loop to allow forms to submit
203 | setTimeout(function () {
204 | state == 'loadingText' ?
205 | $el.addClass(d).attr(d, d) :
206 | $el.removeClass(d).removeAttr(d)
207 | }, 0)
208 | }
209 |
210 | Button.prototype.toggle = function () {
211 | var $parent = this.$element.closest('[data-toggle="buttons-radio"]')
212 |
213 | $parent && $parent
214 | .find('.active')
215 | .removeClass('active')
216 |
217 | this.$element.toggleClass('active')
218 | }
219 |
220 |
221 | /* BUTTON PLUGIN DEFINITION
222 | * ======================== */
223 |
224 | var old = $.fn.button
225 |
226 | $.fn.button = function (option) {
227 | return this.each(function () {
228 | var $this = $(this)
229 | , data = $this.data('button')
230 | , options = typeof option == 'object' && option
231 | if (!data) $this.data('button', (data = new Button(this, options)))
232 | if (option == 'toggle') data.toggle()
233 | else if (option) data.setState(option)
234 | })
235 | }
236 |
237 | $.fn.button.defaults = {
238 | loadingText: 'loading...'
239 | }
240 |
241 | $.fn.button.Constructor = Button
242 |
243 |
244 | /* BUTTON NO CONFLICT
245 | * ================== */
246 |
247 | $.fn.button.noConflict = function () {
248 | $.fn.button = old
249 | return this
250 | }
251 |
252 |
253 | /* BUTTON DATA-API
254 | * =============== */
255 |
256 | $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) {
257 | var $btn = $(e.target)
258 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
259 | $btn.button('toggle')
260 | })
261 |
262 | }(window.jQuery);/* ==========================================================
263 | * bootstrap-carousel.js v2.3.0
264 | * http://twitter.github.com/bootstrap/javascript.html#carousel
265 | * ==========================================================
266 | * Copyright 2012 Twitter, Inc.
267 | *
268 | * Licensed under the Apache License, Version 2.0 (the "License");
269 | * you may not use this file except in compliance with the License.
270 | * You may obtain a copy of the License at
271 | *
272 | * http://www.apache.org/licenses/LICENSE-2.0
273 | *
274 | * Unless required by applicable law or agreed to in writing, software
275 | * distributed under the License is distributed on an "AS IS" BASIS,
276 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
277 | * See the License for the specific language governing permissions and
278 | * limitations under the License.
279 | * ========================================================== */
280 |
281 |
282 | !function ($) {
283 |
284 | "use strict"; // jshint ;_;
285 |
286 |
287 | /* CAROUSEL CLASS DEFINITION
288 | * ========================= */
289 |
290 | var Carousel = function (element, options) {
291 | this.$element = $(element)
292 | this.$indicators = this.$element.find('.carousel-indicators')
293 | this.options = options
294 | this.options.pause == 'hover' && this.$element
295 | .on('mouseenter', $.proxy(this.pause, this))
296 | .on('mouseleave', $.proxy(this.cycle, this))
297 | }
298 |
299 | Carousel.prototype = {
300 |
301 | cycle: function (e) {
302 | if (!e) this.paused = false
303 | if (this.interval) clearInterval(this.interval);
304 | this.options.interval
305 | && !this.paused
306 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
307 | return this
308 | }
309 |
310 | , getActiveIndex: function () {
311 | this.$active = this.$element.find('.item.active')
312 | this.$items = this.$active.parent().children()
313 | return this.$items.index(this.$active)
314 | }
315 |
316 | , to: function (pos) {
317 | var activeIndex = this.getActiveIndex()
318 | , that = this
319 |
320 | if (pos > (this.$items.length - 1) || pos < 0) return
321 |
322 | if (this.sliding) {
323 | return this.$element.one('slid', function () {
324 | that.to(pos)
325 | })
326 | }
327 |
328 | if (activeIndex == pos) {
329 | return this.pause().cycle()
330 | }
331 |
332 | return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
333 | }
334 |
335 | , pause: function (e) {
336 | if (!e) this.paused = true
337 | if (this.$element.find('.next, .prev').length && $.support.transition.end) {
338 | this.$element.trigger($.support.transition.end)
339 | this.cycle()
340 | }
341 | clearInterval(this.interval)
342 | this.interval = null
343 | return this
344 | }
345 |
346 | , next: function () {
347 | if (this.sliding) return
348 | return this.slide('next')
349 | }
350 |
351 | , prev: function () {
352 | if (this.sliding) return
353 | return this.slide('prev')
354 | }
355 |
356 | , slide: function (type, next) {
357 | var $active = this.$element.find('.item.active')
358 | , $next = next || $active[type]()
359 | , isCycling = this.interval
360 | , direction = type == 'next' ? 'left' : 'right'
361 | , fallback = type == 'next' ? 'first' : 'last'
362 | , that = this
363 | , e
364 |
365 | this.sliding = true
366 |
367 | isCycling && this.pause()
368 |
369 | $next = $next.length ? $next : this.$element.find('.item')[fallback]()
370 |
371 | e = $.Event('slide', {
372 | relatedTarget: $next[0]
373 | , direction: direction
374 | })
375 |
376 | if ($next.hasClass('active')) return
377 |
378 | if (this.$indicators.length) {
379 | this.$indicators.find('.active').removeClass('active')
380 | this.$element.one('slid', function () {
381 | var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
382 | $nextIndicator && $nextIndicator.addClass('active')
383 | })
384 | }
385 |
386 | if ($.support.transition && this.$element.hasClass('slide')) {
387 | this.$element.trigger(e)
388 | if (e.isDefaultPrevented()) return
389 | $next.addClass(type)
390 | $next[0].offsetWidth // force reflow
391 | $active.addClass(direction)
392 | $next.addClass(direction)
393 | this.$element.one($.support.transition.end, function () {
394 | $next.removeClass([type, direction].join(' ')).addClass('active')
395 | $active.removeClass(['active', direction].join(' '))
396 | that.sliding = false
397 | setTimeout(function () { that.$element.trigger('slid') }, 0)
398 | })
399 | } else {
400 | this.$element.trigger(e)
401 | if (e.isDefaultPrevented()) return
402 | $active.removeClass('active')
403 | $next.addClass('active')
404 | this.sliding = false
405 | this.$element.trigger('slid')
406 | }
407 |
408 | isCycling && this.cycle()
409 |
410 | return this
411 | }
412 |
413 | }
414 |
415 |
416 | /* CAROUSEL PLUGIN DEFINITION
417 | * ========================== */
418 |
419 | var old = $.fn.carousel
420 |
421 | $.fn.carousel = function (option) {
422 | return this.each(function () {
423 | var $this = $(this)
424 | , data = $this.data('carousel')
425 | , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
426 | , action = typeof option == 'string' ? option : options.slide
427 | if (!data) $this.data('carousel', (data = new Carousel(this, options)))
428 | if (typeof option == 'number') data.to(option)
429 | else if (action) data[action]()
430 | else if (options.interval) data.pause().cycle()
431 | })
432 | }
433 |
434 | $.fn.carousel.defaults = {
435 | interval: 5000
436 | , pause: 'hover'
437 | }
438 |
439 | $.fn.carousel.Constructor = Carousel
440 |
441 |
442 | /* CAROUSEL NO CONFLICT
443 | * ==================== */
444 |
445 | $.fn.carousel.noConflict = function () {
446 | $.fn.carousel = old
447 | return this
448 | }
449 |
450 | /* CAROUSEL DATA-API
451 | * ================= */
452 |
453 | $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
454 | var $this = $(this), href
455 | , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
456 | , options = $.extend({}, $target.data(), $this.data())
457 | , slideIndex
458 |
459 | $target.carousel(options)
460 |
461 | if (slideIndex = $this.attr('data-slide-to')) {
462 | $target.data('carousel').pause().to(slideIndex).cycle()
463 | }
464 |
465 | e.preventDefault()
466 | })
467 |
468 | }(window.jQuery);/* =============================================================
469 | * bootstrap-collapse.js v2.3.0
470 | * http://twitter.github.com/bootstrap/javascript.html#collapse
471 | * =============================================================
472 | * Copyright 2012 Twitter, Inc.
473 | *
474 | * Licensed under the Apache License, Version 2.0 (the "License");
475 | * you may not use this file except in compliance with the License.
476 | * You may obtain a copy of the License at
477 | *
478 | * http://www.apache.org/licenses/LICENSE-2.0
479 | *
480 | * Unless required by applicable law or agreed to in writing, software
481 | * distributed under the License is distributed on an "AS IS" BASIS,
482 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
483 | * See the License for the specific language governing permissions and
484 | * limitations under the License.
485 | * ============================================================ */
486 |
487 |
488 | !function ($) {
489 |
490 | "use strict"; // jshint ;_;
491 |
492 |
493 | /* COLLAPSE PUBLIC CLASS DEFINITION
494 | * ================================ */
495 |
496 | var Collapse = function (element, options) {
497 | this.$element = $(element)
498 | this.options = $.extend({}, $.fn.collapse.defaults, options)
499 |
500 | if (this.options.parent) {
501 | this.$parent = $(this.options.parent)
502 | }
503 |
504 | this.options.toggle && this.toggle()
505 | }
506 |
507 | Collapse.prototype = {
508 |
509 | constructor: Collapse
510 |
511 | , dimension: function () {
512 | var hasWidth = this.$element.hasClass('width')
513 | return hasWidth ? 'width' : 'height'
514 | }
515 |
516 | , show: function () {
517 | var dimension
518 | , scroll
519 | , actives
520 | , hasData
521 |
522 | if (this.transitioning || this.$element.hasClass('in')) return
523 |
524 | dimension = this.dimension()
525 | scroll = $.camelCase(['scroll', dimension].join('-'))
526 | actives = this.$parent && this.$parent.find('> .accordion-group > .in')
527 |
528 | if (actives && actives.length) {
529 | hasData = actives.data('collapse')
530 | if (hasData && hasData.transitioning) return
531 | actives.collapse('hide')
532 | hasData || actives.data('collapse', null)
533 | }
534 |
535 | this.$element[dimension](0)
536 | this.transition('addClass', $.Event('show'), 'shown')
537 | $.support.transition && this.$element[dimension](this.$element[0][scroll])
538 | }
539 |
540 | , hide: function () {
541 | var dimension
542 | if (this.transitioning || !this.$element.hasClass('in')) return
543 | dimension = this.dimension()
544 | this.reset(this.$element[dimension]())
545 | this.transition('removeClass', $.Event('hide'), 'hidden')
546 | this.$element[dimension](0)
547 | }
548 |
549 | , reset: function (size) {
550 | var dimension = this.dimension()
551 |
552 | this.$element
553 | .removeClass('collapse')
554 | [dimension](size || 'auto')
555 | [0].offsetWidth
556 |
557 | this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
558 |
559 | return this
560 | }
561 |
562 | , transition: function (method, startEvent, completeEvent) {
563 | var that = this
564 | , complete = function () {
565 | if (startEvent.type == 'show') that.reset()
566 | that.transitioning = 0
567 | that.$element.trigger(completeEvent)
568 | }
569 |
570 | this.$element.trigger(startEvent)
571 |
572 | if (startEvent.isDefaultPrevented()) return
573 |
574 | this.transitioning = 1
575 |
576 | this.$element[method]('in')
577 |
578 | $.support.transition && this.$element.hasClass('collapse') ?
579 | this.$element.one($.support.transition.end, complete) :
580 | complete()
581 | }
582 |
583 | , toggle: function () {
584 | this[this.$element.hasClass('in') ? 'hide' : 'show']()
585 | }
586 |
587 | }
588 |
589 |
590 | /* COLLAPSE PLUGIN DEFINITION
591 | * ========================== */
592 |
593 | var old = $.fn.collapse
594 |
595 | $.fn.collapse = function (option) {
596 | return this.each(function () {
597 | var $this = $(this)
598 | , data = $this.data('collapse')
599 | , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option)
600 | if (!data) $this.data('collapse', (data = new Collapse(this, options)))
601 | if (typeof option == 'string') data[option]()
602 | })
603 | }
604 |
605 | $.fn.collapse.defaults = {
606 | toggle: true
607 | }
608 |
609 | $.fn.collapse.Constructor = Collapse
610 |
611 |
612 | /* COLLAPSE NO CONFLICT
613 | * ==================== */
614 |
615 | $.fn.collapse.noConflict = function () {
616 | $.fn.collapse = old
617 | return this
618 | }
619 |
620 |
621 | /* COLLAPSE DATA-API
622 | * ================= */
623 |
624 | $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
625 | var $this = $(this), href
626 | , target = $this.attr('data-target')
627 | || e.preventDefault()
628 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
629 | , option = $(target).data('collapse') ? 'toggle' : $this.data()
630 | $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
631 | $(target).collapse(option)
632 | })
633 |
634 | }(window.jQuery);/* ============================================================
635 | * bootstrap-dropdown.js v2.3.0
636 | * http://twitter.github.com/bootstrap/javascript.html#dropdowns
637 | * ============================================================
638 | * Copyright 2012 Twitter, Inc.
639 | *
640 | * Licensed under the Apache License, Version 2.0 (the "License");
641 | * you may not use this file except in compliance with the License.
642 | * You may obtain a copy of the License at
643 | *
644 | * http://www.apache.org/licenses/LICENSE-2.0
645 | *
646 | * Unless required by applicable law or agreed to in writing, software
647 | * distributed under the License is distributed on an "AS IS" BASIS,
648 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
649 | * See the License for the specific language governing permissions and
650 | * limitations under the License.
651 | * ============================================================ */
652 |
653 |
654 | !function ($) {
655 |
656 | "use strict"; // jshint ;_;
657 |
658 |
659 | /* DROPDOWN CLASS DEFINITION
660 | * ========================= */
661 |
662 | var toggle = '[data-toggle=dropdown]'
663 | , Dropdown = function (element) {
664 | var $el = $(element).on('click.dropdown.data-api', this.toggle)
665 | $('html').on('click.dropdown.data-api', function () {
666 | $el.parent().removeClass('open')
667 | })
668 | }
669 |
670 | Dropdown.prototype = {
671 |
672 | constructor: Dropdown
673 |
674 | , toggle: function (e) {
675 | var $this = $(this)
676 | , $parent
677 | , isActive
678 |
679 | if ($this.is('.disabled, :disabled')) return
680 |
681 | $parent = getParent($this)
682 |
683 | isActive = $parent.hasClass('open')
684 |
685 | clearMenus()
686 |
687 | if (!isActive) {
688 | $parent.toggleClass('open')
689 | }
690 |
691 | $this.focus()
692 |
693 | return false
694 | }
695 |
696 | , keydown: function (e) {
697 | var $this
698 | , $items
699 | , $active
700 | , $parent
701 | , isActive
702 | , index
703 |
704 | if (!/(38|40|27)/.test(e.keyCode)) return
705 |
706 | $this = $(this)
707 |
708 | e.preventDefault()
709 | e.stopPropagation()
710 |
711 | if ($this.is('.disabled, :disabled')) return
712 |
713 | $parent = getParent($this)
714 |
715 | isActive = $parent.hasClass('open')
716 |
717 | if (!isActive || (isActive && e.keyCode == 27)) {
718 | if (e.which == 27) $parent.find(toggle).focus()
719 | return $this.click()
720 | }
721 |
722 | $items = $('[role=menu] li:not(.divider):visible a', $parent)
723 |
724 | if (!$items.length) return
725 |
726 | index = $items.index($items.filter(':focus'))
727 |
728 | if (e.keyCode == 38 && index > 0) index-- // up
729 | if (e.keyCode == 40 && index < $items.length - 1) index++ // down
730 | if (!~index) index = 0
731 |
732 | $items
733 | .eq(index)
734 | .focus()
735 | }
736 |
737 | }
738 |
739 | function clearMenus() {
740 | $(toggle).each(function () {
741 | getParent($(this)).removeClass('open')
742 | })
743 | }
744 |
745 | function getParent($this) {
746 | var selector = $this.attr('data-target')
747 | , $parent
748 |
749 | if (!selector) {
750 | selector = $this.attr('href')
751 | selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
752 | }
753 |
754 | $parent = selector && $(selector)
755 |
756 | if (!$parent || !$parent.length) $parent = $this.parent()
757 |
758 | return $parent
759 | }
760 |
761 |
762 | /* DROPDOWN PLUGIN DEFINITION
763 | * ========================== */
764 |
765 | var old = $.fn.dropdown
766 |
767 | $.fn.dropdown = function (option) {
768 | return this.each(function () {
769 | var $this = $(this)
770 | , data = $this.data('dropdown')
771 | if (!data) $this.data('dropdown', (data = new Dropdown(this)))
772 | if (typeof option == 'string') data[option].call($this)
773 | })
774 | }
775 |
776 | $.fn.dropdown.Constructor = Dropdown
777 |
778 |
779 | /* DROPDOWN NO CONFLICT
780 | * ==================== */
781 |
782 | $.fn.dropdown.noConflict = function () {
783 | $.fn.dropdown = old
784 | return this
785 | }
786 |
787 |
788 | /* APPLY TO STANDARD DROPDOWN ELEMENTS
789 | * =================================== */
790 |
791 | $(document)
792 | .on('click.dropdown.data-api', clearMenus)
793 | .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
794 | .on('.dropdown-menu', function (e) { e.stopPropagation() })
795 | .on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
796 | .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
797 |
798 | }(window.jQuery);
799 | /* =========================================================
800 | * bootstrap-modal.js v2.3.0
801 | * http://twitter.github.com/bootstrap/javascript.html#modals
802 | * =========================================================
803 | * Copyright 2012 Twitter, Inc.
804 | *
805 | * Licensed under the Apache License, Version 2.0 (the "License");
806 | * you may not use this file except in compliance with the License.
807 | * You may obtain a copy of the License at
808 | *
809 | * http://www.apache.org/licenses/LICENSE-2.0
810 | *
811 | * Unless required by applicable law or agreed to in writing, software
812 | * distributed under the License is distributed on an "AS IS" BASIS,
813 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
814 | * See the License for the specific language governing permissions and
815 | * limitations under the License.
816 | * ========================================================= */
817 |
818 |
819 | !function ($) {
820 |
821 | "use strict"; // jshint ;_;
822 |
823 |
824 | /* MODAL CLASS DEFINITION
825 | * ====================== */
826 |
827 | var Modal = function (element, options) {
828 | this.options = options
829 | this.$element = $(element)
830 | .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
831 | this.options.remote && this.$element.find('.modal-body').load(this.options.remote)
832 | }
833 |
834 | Modal.prototype = {
835 |
836 | constructor: Modal
837 |
838 | , toggle: function () {
839 | return this[!this.isShown ? 'show' : 'hide']()
840 | }
841 |
842 | , show: function () {
843 | var that = this
844 | , e = $.Event('show')
845 |
846 | this.$element.trigger(e)
847 |
848 | if (this.isShown || e.isDefaultPrevented()) return
849 |
850 | this.isShown = true
851 |
852 | this.escape()
853 |
854 | this.backdrop(function () {
855 | var transition = $.support.transition && that.$element.hasClass('fade')
856 |
857 | if (!that.$element.parent().length) {
858 | that.$element.appendTo(document.body) //don't move modals dom position
859 | }
860 |
861 | that.$element.show()
862 |
863 | if (transition) {
864 | that.$element[0].offsetWidth // force reflow
865 | }
866 |
867 | that.$element
868 | .addClass('in')
869 | .attr('aria-hidden', false)
870 |
871 | that.enforceFocus()
872 |
873 | transition ?
874 | that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) :
875 | that.$element.focus().trigger('shown')
876 |
877 | })
878 | }
879 |
880 | , hide: function (e) {
881 | e && e.preventDefault()
882 |
883 | var that = this
884 |
885 | e = $.Event('hide')
886 |
887 | this.$element.trigger(e)
888 |
889 | if (!this.isShown || e.isDefaultPrevented()) return
890 |
891 | this.isShown = false
892 |
893 | this.escape()
894 |
895 | $(document).off('focusin.modal')
896 |
897 | this.$element
898 | .removeClass('in')
899 | .attr('aria-hidden', true)
900 |
901 | $.support.transition && this.$element.hasClass('fade') ?
902 | this.hideWithTransition() :
903 | this.hideModal()
904 | }
905 |
906 | , enforceFocus: function () {
907 | var that = this
908 | $(document).on('focusin.modal', function (e) {
909 | if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
910 | that.$element.focus()
911 | }
912 | })
913 | }
914 |
915 | , escape: function () {
916 | var that = this
917 | if (this.isShown && this.options.keyboard) {
918 | this.$element.on('keyup.dismiss.modal', function ( e ) {
919 | e.which == 27 && that.hide()
920 | })
921 | } else if (!this.isShown) {
922 | this.$element.off('keyup.dismiss.modal')
923 | }
924 | }
925 |
926 | , hideWithTransition: function () {
927 | var that = this
928 | , timeout = setTimeout(function () {
929 | that.$element.off($.support.transition.end)
930 | that.hideModal()
931 | }, 500)
932 |
933 | this.$element.one($.support.transition.end, function () {
934 | clearTimeout(timeout)
935 | that.hideModal()
936 | })
937 | }
938 |
939 | , hideModal: function () {
940 | var that = this
941 | this.$element.hide()
942 | this.backdrop(function () {
943 | that.removeBackdrop()
944 | that.$element.trigger('hidden')
945 | })
946 | }
947 |
948 | , removeBackdrop: function () {
949 | this.$backdrop.remove()
950 | this.$backdrop = null
951 | }
952 |
953 | , backdrop: function (callback) {
954 | var that = this
955 | , animate = this.$element.hasClass('fade') ? 'fade' : ''
956 |
957 | if (this.isShown && this.options.backdrop) {
958 | var doAnimate = $.support.transition && animate
959 |
960 | this.$backdrop = $('')
961 | .appendTo(document.body)
962 |
963 | this.$backdrop.click(
964 | this.options.backdrop == 'static' ?
965 | $.proxy(this.$element[0].focus, this.$element[0])
966 | : $.proxy(this.hide, this)
967 | )
968 |
969 | if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
970 |
971 | this.$backdrop.addClass('in')
972 |
973 | if (!callback) return
974 |
975 | doAnimate ?
976 | this.$backdrop.one($.support.transition.end, callback) :
977 | callback()
978 |
979 | } else if (!this.isShown && this.$backdrop) {
980 | this.$backdrop.removeClass('in')
981 |
982 | $.support.transition && this.$element.hasClass('fade')?
983 | this.$backdrop.one($.support.transition.end, callback) :
984 | callback()
985 |
986 | } else if (callback) {
987 | callback()
988 | }
989 | }
990 | }
991 |
992 |
993 | /* MODAL PLUGIN DEFINITION
994 | * ======================= */
995 |
996 | var old = $.fn.modal
997 |
998 | $.fn.modal = function (option) {
999 | return this.each(function () {
1000 | var $this = $(this)
1001 | , data = $this.data('modal')
1002 | , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
1003 | if (!data) $this.data('modal', (data = new Modal(this, options)))
1004 | if (typeof option == 'string') data[option]()
1005 | else if (options.show) data.show()
1006 | })
1007 | }
1008 |
1009 | $.fn.modal.defaults = {
1010 | backdrop: true
1011 | , keyboard: true
1012 | , show: true
1013 | }
1014 |
1015 | $.fn.modal.Constructor = Modal
1016 |
1017 |
1018 | /* MODAL NO CONFLICT
1019 | * ================= */
1020 |
1021 | $.fn.modal.noConflict = function () {
1022 | $.fn.modal = old
1023 | return this
1024 | }
1025 |
1026 |
1027 | /* MODAL DATA-API
1028 | * ============== */
1029 |
1030 | $(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
1031 | var $this = $(this)
1032 | , href = $this.attr('href')
1033 | , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
1034 | , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())
1035 |
1036 | e.preventDefault()
1037 |
1038 | $target
1039 | .modal(option)
1040 | .one('hide', function () {
1041 | $this.focus()
1042 | })
1043 | })
1044 |
1045 | }(window.jQuery);
1046 | /* ===========================================================
1047 | * bootstrap-tooltip.js v2.3.0
1048 | * http://twitter.github.com/bootstrap/javascript.html#tooltips
1049 | * Inspired by the original jQuery.tipsy by Jason Frame
1050 | * ===========================================================
1051 | * Copyright 2012 Twitter, Inc.
1052 | *
1053 | * Licensed under the Apache License, Version 2.0 (the "License");
1054 | * you may not use this file except in compliance with the License.
1055 | * You may obtain a copy of the License at
1056 | *
1057 | * http://www.apache.org/licenses/LICENSE-2.0
1058 | *
1059 | * Unless required by applicable law or agreed to in writing, software
1060 | * distributed under the License is distributed on an "AS IS" BASIS,
1061 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1062 | * See the License for the specific language governing permissions and
1063 | * limitations under the License.
1064 | * ========================================================== */
1065 |
1066 |
1067 | !function ($) {
1068 |
1069 | "use strict"; // jshint ;_;
1070 |
1071 |
1072 | /* TOOLTIP PUBLIC CLASS DEFINITION
1073 | * =============================== */
1074 |
1075 | var Tooltip = function (element, options) {
1076 | this.init('tooltip', element, options)
1077 | }
1078 |
1079 | Tooltip.prototype = {
1080 |
1081 | constructor: Tooltip
1082 |
1083 | , init: function (type, element, options) {
1084 | var eventIn
1085 | , eventOut
1086 | , triggers
1087 | , trigger
1088 | , i
1089 |
1090 | this.type = type
1091 | this.$element = $(element)
1092 | this.options = this.getOptions(options)
1093 | this.enabled = true
1094 |
1095 | triggers = this.options.trigger.split(' ')
1096 |
1097 | for (i = triggers.length; i--;) {
1098 | trigger = triggers[i]
1099 | if (trigger == 'click') {
1100 | this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
1101 | } else if (trigger != 'manual') {
1102 | eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
1103 | eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
1104 | this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
1105 | this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
1106 | }
1107 | }
1108 |
1109 | this.options.selector ?
1110 | (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
1111 | this.fixTitle()
1112 | }
1113 |
1114 | , getOptions: function (options) {
1115 | options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)
1116 |
1117 | if (options.delay && typeof options.delay == 'number') {
1118 | options.delay = {
1119 | show: options.delay
1120 | , hide: options.delay
1121 | }
1122 | }
1123 |
1124 | return options
1125 | }
1126 |
1127 | , enter: function (e) {
1128 | var self = $(e.currentTarget)[this.type](this._options).data(this.type)
1129 |
1130 | if (!self.options.delay || !self.options.delay.show) return self.show()
1131 |
1132 | clearTimeout(this.timeout)
1133 | self.hoverState = 'in'
1134 | this.timeout = setTimeout(function() {
1135 | if (self.hoverState == 'in') self.show()
1136 | }, self.options.delay.show)
1137 | }
1138 |
1139 | , leave: function (e) {
1140 | var self = $(e.currentTarget)[this.type](this._options).data(this.type)
1141 |
1142 | if (this.timeout) clearTimeout(this.timeout)
1143 | if (!self.options.delay || !self.options.delay.hide) return self.hide()
1144 |
1145 | self.hoverState = 'out'
1146 | this.timeout = setTimeout(function() {
1147 | if (self.hoverState == 'out') self.hide()
1148 | }, self.options.delay.hide)
1149 | }
1150 |
1151 | , show: function () {
1152 | var $tip
1153 | , pos
1154 | , actualWidth
1155 | , actualHeight
1156 | , placement
1157 | , tp
1158 | , e = $.Event('show')
1159 |
1160 | if (this.hasContent() && this.enabled) {
1161 | this.$element.trigger(e)
1162 | if (e.isDefaultPrevented()) return
1163 | $tip = this.tip()
1164 | this.setContent()
1165 |
1166 | if (this.options.animation) {
1167 | $tip.addClass('fade')
1168 | }
1169 |
1170 | placement = typeof this.options.placement == 'function' ?
1171 | this.options.placement.call(this, $tip[0], this.$element[0]) :
1172 | this.options.placement
1173 |
1174 | $tip
1175 | .detach()
1176 | .css({ top: 0, left: 0, display: 'block' })
1177 |
1178 | this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
1179 |
1180 | pos = this.getPosition()
1181 |
1182 | actualWidth = $tip[0].offsetWidth
1183 | actualHeight = $tip[0].offsetHeight
1184 |
1185 | switch (placement) {
1186 | case 'bottom':
1187 | tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
1188 | break
1189 | case 'top':
1190 | tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
1191 | break
1192 | case 'left':
1193 | tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
1194 | break
1195 | case 'right':
1196 | tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
1197 | break
1198 | }
1199 |
1200 | this.applyPlacement(tp, placement)
1201 | this.$element.trigger('shown')
1202 | }
1203 | }
1204 |
1205 | , applyPlacement: function(offset, placement){
1206 | var $tip = this.tip()
1207 | , width = $tip[0].offsetWidth
1208 | , height = $tip[0].offsetHeight
1209 | , actualWidth
1210 | , actualHeight
1211 | , delta
1212 | , replace
1213 |
1214 | $tip
1215 | .offset(offset)
1216 | .addClass(placement)
1217 | .addClass('in')
1218 |
1219 | actualWidth = $tip[0].offsetWidth
1220 | actualHeight = $tip[0].offsetHeight
1221 |
1222 | if (placement == 'top' && actualHeight != height) {
1223 | offset.top = offset.top + height - actualHeight
1224 | replace = true
1225 | }
1226 |
1227 | if (placement == 'bottom' || placement == 'top') {
1228 | delta = 0
1229 |
1230 | if (offset.left < 0){
1231 | delta = offset.left * -2
1232 | offset.left = 0
1233 | $tip.offset(offset)
1234 | actualWidth = $tip[0].offsetWidth
1235 | actualHeight = $tip[0].offsetHeight
1236 | }
1237 |
1238 | this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
1239 | } else {
1240 | this.replaceArrow(actualHeight - height, actualHeight, 'top')
1241 | }
1242 |
1243 | if (replace) $tip.offset(offset)
1244 | }
1245 |
1246 | , replaceArrow: function(delta, dimension, position){
1247 | this
1248 | .arrow()
1249 | .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
1250 | }
1251 |
1252 | , setContent: function () {
1253 | var $tip = this.tip()
1254 | , title = this.getTitle()
1255 |
1256 | $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
1257 | $tip.removeClass('fade in top bottom left right')
1258 | }
1259 |
1260 | , hide: function () {
1261 | var that = this
1262 | , $tip = this.tip()
1263 | , e = $.Event('hide')
1264 |
1265 | this.$element.trigger(e)
1266 | if (e.isDefaultPrevented()) return
1267 |
1268 | $tip.removeClass('in')
1269 |
1270 | function removeWithAnimation() {
1271 | var timeout = setTimeout(function () {
1272 | $tip.off($.support.transition.end).detach()
1273 | }, 500)
1274 |
1275 | $tip.one($.support.transition.end, function () {
1276 | clearTimeout(timeout)
1277 | $tip.detach()
1278 | })
1279 | }
1280 |
1281 | $.support.transition && this.$tip.hasClass('fade') ?
1282 | removeWithAnimation() :
1283 | $tip.detach()
1284 |
1285 | this.$element.trigger('hidden')
1286 |
1287 | return this
1288 | }
1289 |
1290 | , fixTitle: function () {
1291 | var $e = this.$element
1292 | if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
1293 | $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
1294 | }
1295 | }
1296 |
1297 | , hasContent: function () {
1298 | return this.getTitle()
1299 | }
1300 |
1301 | , getPosition: function () {
1302 | var el = this.$element[0]
1303 | return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
1304 | width: el.offsetWidth
1305 | , height: el.offsetHeight
1306 | }, this.$element.offset())
1307 | }
1308 |
1309 | , getTitle: function () {
1310 | var title
1311 | , $e = this.$element
1312 | , o = this.options
1313 |
1314 | title = $e.attr('data-original-title')
1315 | || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
1316 |
1317 | return title
1318 | }
1319 |
1320 | , tip: function () {
1321 | return this.$tip = this.$tip || $(this.options.template)
1322 | }
1323 |
1324 | , arrow: function(){
1325 | return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
1326 | }
1327 |
1328 | , validate: function () {
1329 | if (!this.$element[0].parentNode) {
1330 | this.hide()
1331 | this.$element = null
1332 | this.options = null
1333 | }
1334 | }
1335 |
1336 | , enable: function () {
1337 | this.enabled = true
1338 | }
1339 |
1340 | , disable: function () {
1341 | this.enabled = false
1342 | }
1343 |
1344 | , toggleEnabled: function () {
1345 | this.enabled = !this.enabled
1346 | }
1347 |
1348 | , toggle: function (e) {
1349 | var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
1350 | self.tip().hasClass('in') ? self.hide() : self.show()
1351 | }
1352 |
1353 | , destroy: function () {
1354 | this.hide().$element.off('.' + this.type).removeData(this.type)
1355 | }
1356 |
1357 | }
1358 |
1359 |
1360 | /* TOOLTIP PLUGIN DEFINITION
1361 | * ========================= */
1362 |
1363 | var old = $.fn.tooltip
1364 |
1365 | $.fn.tooltip = function ( option ) {
1366 | return this.each(function () {
1367 | var $this = $(this)
1368 | , data = $this.data('tooltip')
1369 | , options = typeof option == 'object' && option
1370 | if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
1371 | if (typeof option == 'string') data[option]()
1372 | })
1373 | }
1374 |
1375 | $.fn.tooltip.Constructor = Tooltip
1376 |
1377 | $.fn.tooltip.defaults = {
1378 | animation: true
1379 | , placement: 'top'
1380 | , selector: false
1381 | , template: ''
1382 | , trigger: 'hover focus'
1383 | , title: ''
1384 | , delay: 0
1385 | , html: false
1386 | , container: false
1387 | }
1388 |
1389 |
1390 | /* TOOLTIP NO CONFLICT
1391 | * =================== */
1392 |
1393 | $.fn.tooltip.noConflict = function () {
1394 | $.fn.tooltip = old
1395 | return this
1396 | }
1397 |
1398 | }(window.jQuery);
1399 | /* ===========================================================
1400 | * bootstrap-popover.js v2.3.0
1401 | * http://twitter.github.com/bootstrap/javascript.html#popovers
1402 | * ===========================================================
1403 | * Copyright 2012 Twitter, Inc.
1404 | *
1405 | * Licensed under the Apache License, Version 2.0 (the "License");
1406 | * you may not use this file except in compliance with the License.
1407 | * You may obtain a copy of the License at
1408 | *
1409 | * http://www.apache.org/licenses/LICENSE-2.0
1410 | *
1411 | * Unless required by applicable law or agreed to in writing, software
1412 | * distributed under the License is distributed on an "AS IS" BASIS,
1413 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1414 | * See the License for the specific language governing permissions and
1415 | * limitations under the License.
1416 | * =========================================================== */
1417 |
1418 |
1419 | !function ($) {
1420 |
1421 | "use strict"; // jshint ;_;
1422 |
1423 |
1424 | /* POPOVER PUBLIC CLASS DEFINITION
1425 | * =============================== */
1426 |
1427 | var Popover = function (element, options) {
1428 | this.init('popover', element, options)
1429 | }
1430 |
1431 |
1432 | /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
1433 | ========================================== */
1434 |
1435 | Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
1436 |
1437 | constructor: Popover
1438 |
1439 | , setContent: function () {
1440 | var $tip = this.tip()
1441 | , title = this.getTitle()
1442 | , content = this.getContent()
1443 |
1444 | $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
1445 | $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)
1446 |
1447 | $tip.removeClass('fade top bottom left right in')
1448 | }
1449 |
1450 | , hasContent: function () {
1451 | return this.getTitle() || this.getContent()
1452 | }
1453 |
1454 | , getContent: function () {
1455 | var content
1456 | , $e = this.$element
1457 | , o = this.options
1458 |
1459 | content = (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
1460 | || $e.attr('data-content')
1461 |
1462 | return content
1463 | }
1464 |
1465 | , tip: function () {
1466 | if (!this.$tip) {
1467 | this.$tip = $(this.options.template)
1468 | }
1469 | return this.$tip
1470 | }
1471 |
1472 | , destroy: function () {
1473 | this.hide().$element.off('.' + this.type).removeData(this.type)
1474 | }
1475 |
1476 | })
1477 |
1478 |
1479 | /* POPOVER PLUGIN DEFINITION
1480 | * ======================= */
1481 |
1482 | var old = $.fn.popover
1483 |
1484 | $.fn.popover = function (option) {
1485 | return this.each(function () {
1486 | var $this = $(this)
1487 | , data = $this.data('popover')
1488 | , options = typeof option == 'object' && option
1489 | if (!data) $this.data('popover', (data = new Popover(this, options)))
1490 | if (typeof option == 'string') data[option]()
1491 | })
1492 | }
1493 |
1494 | $.fn.popover.Constructor = Popover
1495 |
1496 | $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
1497 | placement: 'right'
1498 | , trigger: 'click'
1499 | , content: ''
1500 | , template: ''
1501 | })
1502 |
1503 |
1504 | /* POPOVER NO CONFLICT
1505 | * =================== */
1506 |
1507 | $.fn.popover.noConflict = function () {
1508 | $.fn.popover = old
1509 | return this
1510 | }
1511 |
1512 | }(window.jQuery);
1513 | /* =============================================================
1514 | * bootstrap-scrollspy.js v2.3.0
1515 | * http://twitter.github.com/bootstrap/javascript.html#scrollspy
1516 | * =============================================================
1517 | * Copyright 2012 Twitter, Inc.
1518 | *
1519 | * Licensed under the Apache License, Version 2.0 (the "License");
1520 | * you may not use this file except in compliance with the License.
1521 | * You may obtain a copy of the License at
1522 | *
1523 | * http://www.apache.org/licenses/LICENSE-2.0
1524 | *
1525 | * Unless required by applicable law or agreed to in writing, software
1526 | * distributed under the License is distributed on an "AS IS" BASIS,
1527 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1528 | * See the License for the specific language governing permissions and
1529 | * limitations under the License.
1530 | * ============================================================== */
1531 |
1532 |
1533 | !function ($) {
1534 |
1535 | "use strict"; // jshint ;_;
1536 |
1537 |
1538 | /* SCROLLSPY CLASS DEFINITION
1539 | * ========================== */
1540 |
1541 | function ScrollSpy(element, options) {
1542 | var process = $.proxy(this.process, this)
1543 | , $element = $(element).is('body') ? $(window) : $(element)
1544 | , href
1545 | this.options = $.extend({}, $.fn.scrollspy.defaults, options)
1546 | this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)
1547 | this.selector = (this.options.target
1548 | || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
1549 | || '') + ' .nav li > a'
1550 | this.$body = $('body')
1551 | this.refresh()
1552 | this.process()
1553 | }
1554 |
1555 | ScrollSpy.prototype = {
1556 |
1557 | constructor: ScrollSpy
1558 |
1559 | , refresh: function () {
1560 | var self = this
1561 | , $targets
1562 |
1563 | this.offsets = $([])
1564 | this.targets = $([])
1565 |
1566 | $targets = this.$body
1567 | .find(this.selector)
1568 | .map(function () {
1569 | var $el = $(this)
1570 | , href = $el.data('target') || $el.attr('href')
1571 | , $href = /^#\w/.test(href) && $(href)
1572 | return ( $href
1573 | && $href.length
1574 | && [[ $href.position().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]] ) || null
1575 | })
1576 | .sort(function (a, b) { return a[0] - b[0] })
1577 | .each(function () {
1578 | self.offsets.push(this[0])
1579 | self.targets.push(this[1])
1580 | })
1581 | }
1582 |
1583 | , process: function () {
1584 | var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
1585 | , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
1586 | , maxScroll = scrollHeight - this.$scrollElement.height()
1587 | , offsets = this.offsets
1588 | , targets = this.targets
1589 | , activeTarget = this.activeTarget
1590 | , i
1591 |
1592 | if (scrollTop >= maxScroll) {
1593 | return activeTarget != (i = targets.last()[0])
1594 | && this.activate ( i )
1595 | }
1596 |
1597 | for (i = offsets.length; i--;) {
1598 | activeTarget != targets[i]
1599 | && scrollTop >= offsets[i]
1600 | && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
1601 | && this.activate( targets[i] )
1602 | }
1603 | }
1604 |
1605 | , activate: function (target) {
1606 | var active
1607 | , selector
1608 |
1609 | this.activeTarget = target
1610 |
1611 | $(this.selector)
1612 | .parent('.active')
1613 | .removeClass('active')
1614 |
1615 | selector = this.selector
1616 | + '[data-target="' + target + '"],'
1617 | + this.selector + '[href="' + target + '"]'
1618 |
1619 | active = $(selector)
1620 | .parent('li')
1621 | .addClass('active')
1622 |
1623 | if (active.parent('.dropdown-menu').length) {
1624 | active = active.closest('li.dropdown').addClass('active')
1625 | }
1626 |
1627 | active.trigger('activate')
1628 | }
1629 |
1630 | }
1631 |
1632 |
1633 | /* SCROLLSPY PLUGIN DEFINITION
1634 | * =========================== */
1635 |
1636 | var old = $.fn.scrollspy
1637 |
1638 | $.fn.scrollspy = function (option) {
1639 | return this.each(function () {
1640 | var $this = $(this)
1641 | , data = $this.data('scrollspy')
1642 | , options = typeof option == 'object' && option
1643 | if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
1644 | if (typeof option == 'string') data[option]()
1645 | })
1646 | }
1647 |
1648 | $.fn.scrollspy.Constructor = ScrollSpy
1649 |
1650 | $.fn.scrollspy.defaults = {
1651 | offset: 10
1652 | }
1653 |
1654 |
1655 | /* SCROLLSPY NO CONFLICT
1656 | * ===================== */
1657 |
1658 | $.fn.scrollspy.noConflict = function () {
1659 | $.fn.scrollspy = old
1660 | return this
1661 | }
1662 |
1663 |
1664 | /* SCROLLSPY DATA-API
1665 | * ================== */
1666 |
1667 | $(window).on('load', function () {
1668 | $('[data-spy="scroll"]').each(function () {
1669 | var $spy = $(this)
1670 | $spy.scrollspy($spy.data())
1671 | })
1672 | })
1673 |
1674 | }(window.jQuery);/* ========================================================
1675 | * bootstrap-tab.js v2.3.0
1676 | * http://twitter.github.com/bootstrap/javascript.html#tabs
1677 | * ========================================================
1678 | * Copyright 2012 Twitter, Inc.
1679 | *
1680 | * Licensed under the Apache License, Version 2.0 (the "License");
1681 | * you may not use this file except in compliance with the License.
1682 | * You may obtain a copy of the License at
1683 | *
1684 | * http://www.apache.org/licenses/LICENSE-2.0
1685 | *
1686 | * Unless required by applicable law or agreed to in writing, software
1687 | * distributed under the License is distributed on an "AS IS" BASIS,
1688 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1689 | * See the License for the specific language governing permissions and
1690 | * limitations under the License.
1691 | * ======================================================== */
1692 |
1693 |
1694 | !function ($) {
1695 |
1696 | "use strict"; // jshint ;_;
1697 |
1698 |
1699 | /* TAB CLASS DEFINITION
1700 | * ==================== */
1701 |
1702 | var Tab = function (element) {
1703 | this.element = $(element)
1704 | }
1705 |
1706 | Tab.prototype = {
1707 |
1708 | constructor: Tab
1709 |
1710 | , show: function () {
1711 | var $this = this.element
1712 | , $ul = $this.closest('ul:not(.dropdown-menu)')
1713 | , selector = $this.attr('data-target')
1714 | , previous
1715 | , $target
1716 | , e
1717 |
1718 | if (!selector) {
1719 | selector = $this.attr('href')
1720 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
1721 | }
1722 |
1723 | if ( $this.parent('li').hasClass('active') ) return
1724 |
1725 | previous = $ul.find('.active:last a')[0]
1726 |
1727 | e = $.Event('show', {
1728 | relatedTarget: previous
1729 | })
1730 |
1731 | $this.trigger(e)
1732 |
1733 | if (e.isDefaultPrevented()) return
1734 |
1735 | $target = $(selector)
1736 |
1737 | this.activate($this.parent('li'), $ul)
1738 | this.activate($target, $target.parent(), function () {
1739 | $this.trigger({
1740 | type: 'shown'
1741 | , relatedTarget: previous
1742 | })
1743 | })
1744 | }
1745 |
1746 | , activate: function ( element, container, callback) {
1747 | var $active = container.find('> .active')
1748 | , transition = callback
1749 | && $.support.transition
1750 | && $active.hasClass('fade')
1751 |
1752 | function next() {
1753 | $active
1754 | .removeClass('active')
1755 | .find('> .dropdown-menu > .active')
1756 | .removeClass('active')
1757 |
1758 | element.addClass('active')
1759 |
1760 | if (transition) {
1761 | element[0].offsetWidth // reflow for transition
1762 | element.addClass('in')
1763 | } else {
1764 | element.removeClass('fade')
1765 | }
1766 |
1767 | if ( element.parent('.dropdown-menu') ) {
1768 | element.closest('li.dropdown').addClass('active')
1769 | }
1770 |
1771 | callback && callback()
1772 | }
1773 |
1774 | transition ?
1775 | $active.one($.support.transition.end, next) :
1776 | next()
1777 |
1778 | $active.removeClass('in')
1779 | }
1780 | }
1781 |
1782 |
1783 | /* TAB PLUGIN DEFINITION
1784 | * ===================== */
1785 |
1786 | var old = $.fn.tab
1787 |
1788 | $.fn.tab = function ( option ) {
1789 | return this.each(function () {
1790 | var $this = $(this)
1791 | , data = $this.data('tab')
1792 | if (!data) $this.data('tab', (data = new Tab(this)))
1793 | if (typeof option == 'string') data[option]()
1794 | })
1795 | }
1796 |
1797 | $.fn.tab.Constructor = Tab
1798 |
1799 |
1800 | /* TAB NO CONFLICT
1801 | * =============== */
1802 |
1803 | $.fn.tab.noConflict = function () {
1804 | $.fn.tab = old
1805 | return this
1806 | }
1807 |
1808 |
1809 | /* TAB DATA-API
1810 | * ============ */
1811 |
1812 | $(document).on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
1813 | e.preventDefault()
1814 | $(this).tab('show')
1815 | })
1816 |
1817 | }(window.jQuery);/* =============================================================
1818 | * bootstrap-typeahead.js v2.3.0
1819 | * http://twitter.github.com/bootstrap/javascript.html#typeahead
1820 | * =============================================================
1821 | * Copyright 2012 Twitter, Inc.
1822 | *
1823 | * Licensed under the Apache License, Version 2.0 (the "License");
1824 | * you may not use this file except in compliance with the License.
1825 | * You may obtain a copy of the License at
1826 | *
1827 | * http://www.apache.org/licenses/LICENSE-2.0
1828 | *
1829 | * Unless required by applicable law or agreed to in writing, software
1830 | * distributed under the License is distributed on an "AS IS" BASIS,
1831 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1832 | * See the License for the specific language governing permissions and
1833 | * limitations under the License.
1834 | * ============================================================ */
1835 |
1836 |
1837 | !function($){
1838 |
1839 | "use strict"; // jshint ;_;
1840 |
1841 |
1842 | /* TYPEAHEAD PUBLIC CLASS DEFINITION
1843 | * ================================= */
1844 |
1845 | var Typeahead = function (element, options) {
1846 | this.$element = $(element)
1847 | this.options = $.extend({}, $.fn.typeahead.defaults, options)
1848 | this.matcher = this.options.matcher || this.matcher
1849 | this.sorter = this.options.sorter || this.sorter
1850 | this.highlighter = this.options.highlighter || this.highlighter
1851 | this.updater = this.options.updater || this.updater
1852 | this.source = this.options.source
1853 | this.$menu = $(this.options.menu)
1854 | this.shown = false
1855 | this.listen()
1856 | }
1857 |
1858 | Typeahead.prototype = {
1859 |
1860 | constructor: Typeahead
1861 |
1862 | , select: function () {
1863 | var val = this.$menu.find('.active').attr('data-value')
1864 | this.$element
1865 | .val(this.updater(val))
1866 | .change()
1867 | return this.hide()
1868 | }
1869 |
1870 | , updater: function (item) {
1871 | return item
1872 | }
1873 |
1874 | , show: function () {
1875 | var pos = $.extend({}, this.$element.position(), {
1876 | height: this.$element[0].offsetHeight
1877 | })
1878 |
1879 | this.$menu
1880 | .insertAfter(this.$element)
1881 | .css({
1882 | top: pos.top + pos.height
1883 | , left: pos.left
1884 | })
1885 | .show()
1886 |
1887 | this.shown = true
1888 | return this
1889 | }
1890 |
1891 | , hide: function () {
1892 | this.$menu.hide()
1893 | this.shown = false
1894 | return this
1895 | }
1896 |
1897 | , lookup: function (event) {
1898 | var items
1899 |
1900 | this.query = this.$element.val()
1901 |
1902 | if (!this.query || this.query.length < this.options.minLength) {
1903 | return this.shown ? this.hide() : this
1904 | }
1905 |
1906 | items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
1907 |
1908 | return items ? this.process(items) : this
1909 | }
1910 |
1911 | , process: function (items) {
1912 | var that = this
1913 |
1914 | items = $.grep(items, function (item) {
1915 | return that.matcher(item)
1916 | })
1917 |
1918 | items = this.sorter(items)
1919 |
1920 | if (!items.length) {
1921 | return this.shown ? this.hide() : this
1922 | }
1923 |
1924 | return this.render(items.slice(0, this.options.items)).show()
1925 | }
1926 |
1927 | , matcher: function (item) {
1928 | return ~item.toLowerCase().indexOf(this.query.toLowerCase())
1929 | }
1930 |
1931 | , sorter: function (items) {
1932 | var beginswith = []
1933 | , caseSensitive = []
1934 | , caseInsensitive = []
1935 | , item
1936 |
1937 | while (item = items.shift()) {
1938 | if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
1939 | else if (~item.indexOf(this.query)) caseSensitive.push(item)
1940 | else caseInsensitive.push(item)
1941 | }
1942 |
1943 | return beginswith.concat(caseSensitive, caseInsensitive)
1944 | }
1945 |
1946 | , highlighter: function (item) {
1947 | var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
1948 | return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
1949 | return '' + match + ''
1950 | })
1951 | }
1952 |
1953 | , render: function (items) {
1954 | var that = this
1955 |
1956 | items = $(items).map(function (i, item) {
1957 | i = $(that.options.item).attr('data-value', item)
1958 | i.find('a').html(that.highlighter(item))
1959 | return i[0]
1960 | })
1961 |
1962 | items.first().addClass('active')
1963 | this.$menu.html(items)
1964 | return this
1965 | }
1966 |
1967 | , next: function (event) {
1968 | var active = this.$menu.find('.active').removeClass('active')
1969 | , next = active.next()
1970 |
1971 | if (!next.length) {
1972 | next = $(this.$menu.find('li')[0])
1973 | }
1974 |
1975 | next.addClass('active')
1976 | }
1977 |
1978 | , prev: function (event) {
1979 | var active = this.$menu.find('.active').removeClass('active')
1980 | , prev = active.prev()
1981 |
1982 | if (!prev.length) {
1983 | prev = this.$menu.find('li').last()
1984 | }
1985 |
1986 | prev.addClass('active')
1987 | }
1988 |
1989 | , listen: function () {
1990 | this.$element
1991 | .on('focus', $.proxy(this.focus, this))
1992 | .on('blur', $.proxy(this.blur, this))
1993 | .on('keypress', $.proxy(this.keypress, this))
1994 | .on('keyup', $.proxy(this.keyup, this))
1995 |
1996 | if (this.eventSupported('keydown')) {
1997 | this.$element.on('keydown', $.proxy(this.keydown, this))
1998 | }
1999 |
2000 | this.$menu
2001 | .on('click', $.proxy(this.click, this))
2002 | .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
2003 | .on('mouseleave', 'li', $.proxy(this.mouseleave, this))
2004 | }
2005 |
2006 | , eventSupported: function(eventName) {
2007 | var isSupported = eventName in this.$element
2008 | if (!isSupported) {
2009 | this.$element.setAttribute(eventName, 'return;')
2010 | isSupported = typeof this.$element[eventName] === 'function'
2011 | }
2012 | return isSupported
2013 | }
2014 |
2015 | , move: function (e) {
2016 | if (!this.shown) return
2017 |
2018 | switch(e.keyCode) {
2019 | case 9: // tab
2020 | case 13: // enter
2021 | case 27: // escape
2022 | e.preventDefault()
2023 | break
2024 |
2025 | case 38: // up arrow
2026 | e.preventDefault()
2027 | this.prev()
2028 | break
2029 |
2030 | case 40: // down arrow
2031 | e.preventDefault()
2032 | this.next()
2033 | break
2034 | }
2035 |
2036 | e.stopPropagation()
2037 | }
2038 |
2039 | , keydown: function (e) {
2040 | this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27])
2041 | this.move(e)
2042 | }
2043 |
2044 | , keypress: function (e) {
2045 | if (this.suppressKeyPressRepeat) return
2046 | this.move(e)
2047 | }
2048 |
2049 | , keyup: function (e) {
2050 | switch(e.keyCode) {
2051 | case 40: // down arrow
2052 | case 38: // up arrow
2053 | case 16: // shift
2054 | case 17: // ctrl
2055 | case 18: // alt
2056 | break
2057 |
2058 | case 9: // tab
2059 | case 13: // enter
2060 | if (!this.shown) return
2061 | this.select()
2062 | break
2063 |
2064 | case 27: // escape
2065 | if (!this.shown) return
2066 | this.hide()
2067 | break
2068 |
2069 | default:
2070 | this.lookup()
2071 | }
2072 |
2073 | e.stopPropagation()
2074 | e.preventDefault()
2075 | }
2076 |
2077 | , focus: function (e) {
2078 | this.focused = true
2079 | }
2080 |
2081 | , blur: function (e) {
2082 | this.focused = false
2083 | if (!this.mousedover && this.shown) this.hide()
2084 | }
2085 |
2086 | , click: function (e) {
2087 | e.stopPropagation()
2088 | e.preventDefault()
2089 | this.select()
2090 | this.$element.focus()
2091 | }
2092 |
2093 | , mouseenter: function (e) {
2094 | this.mousedover = true
2095 | this.$menu.find('.active').removeClass('active')
2096 | $(e.currentTarget).addClass('active')
2097 | }
2098 |
2099 | , mouseleave: function (e) {
2100 | this.mousedover = false
2101 | if (!this.focused && this.shown) this.hide()
2102 | }
2103 |
2104 | }
2105 |
2106 |
2107 | /* TYPEAHEAD PLUGIN DEFINITION
2108 | * =========================== */
2109 |
2110 | var old = $.fn.typeahead
2111 |
2112 | $.fn.typeahead = function (option) {
2113 | return this.each(function () {
2114 | var $this = $(this)
2115 | , data = $this.data('typeahead')
2116 | , options = typeof option == 'object' && option
2117 | if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
2118 | if (typeof option == 'string') data[option]()
2119 | })
2120 | }
2121 |
2122 | $.fn.typeahead.defaults = {
2123 | source: []
2124 | , items: 8
2125 | , menu: ''
2126 | , item: ''
2127 | , minLength: 1
2128 | }
2129 |
2130 | $.fn.typeahead.Constructor = Typeahead
2131 |
2132 |
2133 | /* TYPEAHEAD NO CONFLICT
2134 | * =================== */
2135 |
2136 | $.fn.typeahead.noConflict = function () {
2137 | $.fn.typeahead = old
2138 | return this
2139 | }
2140 |
2141 |
2142 | /* TYPEAHEAD DATA-API
2143 | * ================== */
2144 |
2145 | $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
2146 | var $this = $(this)
2147 | if ($this.data('typeahead')) return
2148 | $this.typeahead($this.data())
2149 | })
2150 |
2151 | }(window.jQuery);
2152 | /* ==========================================================
2153 | * bootstrap-affix.js v2.3.0
2154 | * http://twitter.github.com/bootstrap/javascript.html#affix
2155 | * ==========================================================
2156 | * Copyright 2012 Twitter, Inc.
2157 | *
2158 | * Licensed under the Apache License, Version 2.0 (the "License");
2159 | * you may not use this file except in compliance with the License.
2160 | * You may obtain a copy of the License at
2161 | *
2162 | * http://www.apache.org/licenses/LICENSE-2.0
2163 | *
2164 | * Unless required by applicable law or agreed to in writing, software
2165 | * distributed under the License is distributed on an "AS IS" BASIS,
2166 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2167 | * See the License for the specific language governing permissions and
2168 | * limitations under the License.
2169 | * ========================================================== */
2170 |
2171 |
2172 | !function ($) {
2173 |
2174 | "use strict"; // jshint ;_;
2175 |
2176 |
2177 | /* AFFIX CLASS DEFINITION
2178 | * ====================== */
2179 |
2180 | var Affix = function (element, options) {
2181 | this.options = $.extend({}, $.fn.affix.defaults, options)
2182 | this.$window = $(window)
2183 | .on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
2184 | .on('click.affix.data-api', $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this))
2185 | this.$element = $(element)
2186 | this.checkPosition()
2187 | }
2188 |
2189 | Affix.prototype.checkPosition = function () {
2190 | if (!this.$element.is(':visible')) return
2191 |
2192 | var scrollHeight = $(document).height()
2193 | , scrollTop = this.$window.scrollTop()
2194 | , position = this.$element.offset()
2195 | , offset = this.options.offset
2196 | , offsetBottom = offset.bottom
2197 | , offsetTop = offset.top
2198 | , reset = 'affix affix-top affix-bottom'
2199 | , affix
2200 |
2201 | if (typeof offset != 'object') offsetBottom = offsetTop = offset
2202 | if (typeof offsetTop == 'function') offsetTop = offset.top()
2203 | if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
2204 |
2205 | affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
2206 | false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
2207 | 'bottom' : offsetTop != null && scrollTop <= offsetTop ?
2208 | 'top' : false
2209 |
2210 | if (this.affixed === affix) return
2211 |
2212 | this.affixed = affix
2213 | this.unpin = affix == 'bottom' ? position.top - scrollTop : null
2214 |
2215 | this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
2216 | }
2217 |
2218 |
2219 | /* AFFIX PLUGIN DEFINITION
2220 | * ======================= */
2221 |
2222 | var old = $.fn.affix
2223 |
2224 | $.fn.affix = function (option) {
2225 | return this.each(function () {
2226 | var $this = $(this)
2227 | , data = $this.data('affix')
2228 | , options = typeof option == 'object' && option
2229 | if (!data) $this.data('affix', (data = new Affix(this, options)))
2230 | if (typeof option == 'string') data[option]()
2231 | })
2232 | }
2233 |
2234 | $.fn.affix.Constructor = Affix
2235 |
2236 | $.fn.affix.defaults = {
2237 | offset: 0
2238 | }
2239 |
2240 |
2241 | /* AFFIX NO CONFLICT
2242 | * ================= */
2243 |
2244 | $.fn.affix.noConflict = function () {
2245 | $.fn.affix = old
2246 | return this
2247 | }
2248 |
2249 |
2250 | /* AFFIX DATA-API
2251 | * ============== */
2252 |
2253 | $(window).on('load', function () {
2254 | $('[data-spy="affix"]').each(function () {
2255 | var $spy = $(this)
2256 | , data = $spy.data()
2257 |
2258 | data.offset = data.offset || {}
2259 |
2260 | data.offsetBottom && (data.offset.bottom = data.offsetBottom)
2261 | data.offsetTop && (data.offset.top = data.offsetTop)
2262 |
2263 | $spy.affix(data)
2264 | })
2265 | })
2266 |
2267 |
2268 | }(window.jQuery);
--------------------------------------------------------------------------------
/app/templates/bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "<% if(isFullApp){ %>app/<%}%><%= bowerDirectory %>"
3 | }
4 |
--------------------------------------------------------------------------------
/app/templates/editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = tab
12 | indent_size = 4
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/app/templates/gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
--------------------------------------------------------------------------------
/app/templates/gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | temp
3 | dist
4 | .sass-cache
5 | app/<%= bowerDirectory %>
6 | .tmp/
7 |
--------------------------------------------------------------------------------
/app/templates/jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "es5": true,
5 | "esnext": true,
6 | "bitwise": true,
7 | "camelcase": true,
8 | "curly": true,
9 | "eqeqeq": true,
10 | "immed": true,
11 | "indent": 4,
12 | "latedef": true,
13 | "newcap": true,
14 | "noarg": true,
15 | "quotmark": "single",
16 | "regexp": true,
17 | "undef": true,
18 | "unused": true,
19 | "strict": true,
20 | "trailing": true,
21 | "smarttabs": true
22 | }
23 |
--------------------------------------------------------------------------------
/app/templates/server/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var express = require('express');
4 | var http = require('http');
5 | var path = require('path');
6 | var async = require('async');
7 | var hbs = require('express-hbs');
8 | <% if(useBaucis){ %>var baucis = require('baucis');<% } %>
9 | <% if(useSocketIO){ %>var socketIO = require('socket.io');<% } %>
10 | <% if(useMongoose){ %>var mongoose = require('mongoose');
11 |
12 |
13 | // start mongoose
14 | mongoose.connect('mongodb://localhost/sit');
15 | var db = mongoose.connection;
16 |
17 | db.on('error', console.error.bind(console, 'connection error:'));
18 | db.once('open', function callback () {
19 |
20 | /* test schema */
21 | var testSchema = new mongoose.Schema({
22 | test: String
23 | });
24 |
25 | var Test = mongoose.model( 'test', testSchema );
26 |
27 | /* set Baucis */
28 | baucis.rest({
29 | singular: 'test'
30 | });
31 |
32 | var app = express();
33 |
34 | app.configure(function(){
35 | app.set('port', 9000);
36 |
37 | app.set('view engine', 'handlebars');
38 | app.set('views', __dirname + '../app/scripts/views');
39 | });
40 |
41 | app.use('/api/v1', baucis());
42 |
43 | // simple log
44 | app.use(function(req, res, next){
45 | console.log('%s %s', req.method, req.url);
46 | next();
47 | });
48 |
49 | // mount static
50 | app.use(express.static( path.join( __dirname, '../app') ));
51 | app.use(express.static( path.join( __dirname, '../.tmp') ));
52 |
53 |
54 | // route index.html
55 | app.get('/', function(req, res){
56 | res.sendfile( path.join( __dirname, '../app/index.html' ) );
57 | });
58 |
59 | // start server
60 | http.createServer(app).listen(app.get('port'), function(){
61 | console.log('Express App started!');
62 | });
63 | });
64 | <% } else { %>
65 |
66 | // init express
67 | var app = express();
68 |
69 | app.configure(function(){
70 | app.set('port', process.env.PORT || 3000);
71 |
72 | app.set('view engine', 'handlebars');
73 | app.set('views', __dirname + '../app/scripts/views');
74 | });
75 |
76 | // set logging
77 | app.use(function(req, res, next){
78 | console.log('%s %s', req.method, req.url);
79 | next();
80 | });
81 |
82 | // mount static
83 | app.use(express.static( path.join( __dirname, '../app') ));
84 | app.use(express.static( path.join( __dirname, '../.tmp') ));
85 |
86 |
87 | // route index.html
88 | app.get('/', function(req, res){
89 | res.sendfile( path.join( __dirname, '../app/index.html' ) );
90 | });
91 |
92 | // start server
93 | http.createServer(app).listen(app.get('port'), function(){
94 | console.log('Express App started!');
95 | });
96 |
97 | <% } %>
98 |
99 |
--------------------------------------------------------------------------------
/collection/index.js:
--------------------------------------------------------------------------------
1 | /*jshint latedef:false */
2 | var generator = require('yeoman-generator');
3 | var util = require('util');
4 | var path = require('path');
5 | var validDir = require('../helpers/validateDirectory');
6 |
7 | module.exports = Generator;
8 |
9 | function Generator() {
10 | generator.NamedBase.apply(this, arguments);
11 | var dirPath = '../templates/javascript';
12 | this.sourceRoot(path.join(__dirname, dirPath));
13 |
14 | this.argument('model', { type: String, required: false });
15 | this.argument('inherit', { type: String, required: false });
16 |
17 | this.option('create-all', { desc: 'Create a new model for this collection' });
18 |
19 | if (this.model && this.options['create-all']) {
20 | this.hookFor('marionette', { as: 'model', args: [this.model, this.inherit], options: this.options });
21 | }
22 |
23 | // invoke mocha
24 | this.hookFor('mocha-amd', {
25 | as: 'unitTest',
26 | args: [this.name, 'collection', 'collections']
27 | });
28 | }
29 |
30 | util.inherits(Generator, generator.NamedBase);
31 |
32 | Generator.prototype.createViewFiles = function createViewFiles() {
33 | var ext = 'js';
34 | var baseDir = validDir.getValidatedFolder( 'app/' );
35 |
36 | this.template('collection.' + ext, path.join(baseDir + 'scripts/collections', this.name + '.' + ext));
37 | };
38 |
--------------------------------------------------------------------------------
/collectionview/index.js:
--------------------------------------------------------------------------------
1 | /*jshint latedef:false */
2 | var generator = require('yeoman-generator');
3 | var util = require('util');
4 | var path = require('path');
5 | var validDir = require('../helpers/validateDirectory');
6 |
7 |
8 | module.exports = Generator;
9 |
10 | function Generator() {
11 | generator.NamedBase.apply(this, arguments);
12 | var dirPath = '../templates/javascript';
13 | this.sourceRoot(path.join(__dirname, dirPath));
14 |
15 | this.argument('itemview', { type: String, required: false });
16 | this.argument('inherit', { type: String, required: false });
17 |
18 | this.option('create-all', { desc: 'Create a new model for this collection' });
19 |
20 |
21 | if ( this.itemview && this.options['create-all'] ) {
22 | this.hookFor('marionette', { as: 'itemview', args: [this.itemview], options: { options: this.options } });
23 | }
24 |
25 | // invoke mocha
26 | this.hookFor('mocha-amd', {
27 | as: 'unitTest',
28 | args: [this.name, 'collectionview', 'views/collection']
29 | });
30 |
31 | }
32 |
33 | util.inherits(Generator, generator.NamedBase);
34 |
35 | Generator.prototype.createCollectionViewFiles = function createCollectionViewFiles() {
36 | var ext = 'js';
37 | var baseDir = validDir.getValidatedFolder( 'app/' );
38 |
39 | this.template('collectionview.' + ext, path.join(baseDir + 'scripts/views/collection', this.name + '.' + ext));
40 | };
41 |
--------------------------------------------------------------------------------
/compositeview/index.js:
--------------------------------------------------------------------------------
1 | /*jshint latedef:false */
2 | var generator = require('yeoman-generator');
3 | var util = require('util');
4 | var path = require('path');
5 | var validDir = require('../helpers/validateDirectory');
6 |
7 |
8 | module.exports = Generator;
9 |
10 | function Generator() {
11 | generator.NamedBase.apply(this, arguments);
12 | var dirPath = '../templates/javascript';
13 | this.sourceRoot(path.join(__dirname, dirPath));
14 |
15 | this.argument('itemview', { type: String, required: false });
16 | this.argument('inherit', { type: String, required: false });
17 |
18 | this.option('create-all', { desc: 'Create a new model for this collection' });
19 |
20 |
21 | /* set the template name which is auto created */
22 | this.tmplOrig = this.name;
23 | this.compTmpl = this.name + '_tmpl';
24 | this.compTmplLocation = 'composite';
25 |
26 |
27 | if ( this.itemview && this.options['create-all'] ) {
28 | this.hookFor('marionette', { as: 'itemview', args: [this.itemview], options: { options: this.options } });
29 | this.hookFor('marionette', { as: 'tmpl', args: [this.tmplOrig, this.compTmplLocation], options: this.options });
30 | }
31 |
32 | // invoke mocha
33 | this.hookFor('mocha-amd', {
34 | as: 'unitTest',
35 | args: [this.name, 'compositeview', 'views/composite']
36 | });
37 | }
38 |
39 | util.inherits(Generator, generator.NamedBase);
40 |
41 | Generator.prototype.createCompositeViewFiles = function createCompositeViewFiles() {
42 | var ext = 'js';
43 | var baseDir = validDir.getValidatedFolder( 'app/' );
44 |
45 | this.template('compositeview.' + ext, path.join(baseDir + 'scripts/views/composite', this.name + '.' + ext));
46 | };
--------------------------------------------------------------------------------
/controller/index.js:
--------------------------------------------------------------------------------
1 | /*jshint latedef:false */
2 | var generator = require('yeoman-generator');
3 | var util = require('util');
4 | var path = require('path');
5 | var validDir = require('../helpers/validateDirectory');
6 |
7 |
8 | module.exports = Generator;
9 |
10 | function Generator() {
11 | generator.NamedBase.apply(this, arguments);
12 | var dirPath = '../templates/javascript';
13 | this.sourceRoot(path.join(__dirname, dirPath));
14 |
15 | this.argument('inherit', { type: String, required: false });
16 |
17 | // invoke mocha
18 | this.hookFor('mocha-amd', {
19 | as: 'unitTest',
20 | args: [this.name, 'controller', 'controllers']
21 | });
22 | }
23 |
24 | util.inherits(Generator, generator.NamedBase);
25 |
26 | Generator.prototype.createControllerFiles = function createControllerFiles() {
27 | var ext = 'js';
28 | var baseDir = validDir.getValidatedFolder( 'app/' );
29 |
30 | this.template('controller.' + ext, path.join(baseDir + 'scripts/controllers', this.name + '.' + ext));
31 | };
32 |
--------------------------------------------------------------------------------
/helpers/validateDirectory.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 |
3 |
4 | module.exports = {
5 | getValidatedFolder: function( path ){
6 | try {
7 | var fsStat = fs.statSync( path );
8 | if ( fsStat.isDirectory() ) {
9 | return path;
10 | }
11 | else {
12 | return '';
13 | }
14 | } catch (e) {
15 | return '';
16 | }
17 | }
18 | };
--------------------------------------------------------------------------------
/itemview/index.js:
--------------------------------------------------------------------------------
1 | /*jshint latedef:false */
2 | var generator = require('yeoman-generator');
3 | var util = require('util');
4 | var path = require('path');
5 | var validDir = require('../helpers/validateDirectory');
6 |
7 | module.exports = Generator;
8 |
9 | function Generator() {
10 | generator.NamedBase.apply(this, arguments);
11 | var dirPath = '../templates/javascript';
12 | this.sourceRoot(path.join(__dirname, dirPath));
13 |
14 | this.argument('inherit', { type: String, required: false });
15 |
16 | this.option('create-all', { desc: 'Create a new model for this collection' });
17 |
18 |
19 | /* set the template name which is auto created */
20 | this.tmplOrig = this.name;
21 | this.tmpl = this.name + '_tmpl';
22 | this.tmplLocation = 'item';
23 |
24 | if ( this.tmplOrig && this.options['create-all'] ) {
25 | this.hookFor('marionette', { as: 'tmpl', args: [this.tmplOrig, this.tmplLocation], options: this.options });
26 | }
27 |
28 | // invoke mocha
29 | this.hookFor('mocha-amd', {
30 | as: 'unitTest',
31 | args: [this.name, 'itemview', 'views/item']
32 | });
33 | }
34 |
35 | util.inherits(Generator, generator.NamedBase);
36 |
37 | Generator.prototype.createItemViewFiles = function createItemViewFiles() {
38 | var ext = 'js';
39 | var baseDir = validDir.getValidatedFolder( 'app/' );
40 |
41 | this.template('itemview.' + ext, path.join(baseDir + 'scripts/views/item', this.name + '.' + ext));
42 | };
43 |
--------------------------------------------------------------------------------
/layout/index.js:
--------------------------------------------------------------------------------
1 | /*jshint latedef:false */
2 | var generator = require('yeoman-generator');
3 | var util = require('util');
4 | var path = require('path');
5 | var validDir = require('../helpers/validateDirectory');
6 |
7 | module.exports = Generator;
8 |
9 | function Generator() {
10 | generator.NamedBase.apply(this, arguments);
11 | var dirPath = '../templates/javascript';
12 | this.sourceRoot(path.join(__dirname, dirPath));
13 |
14 | this.argument('inherit', { type: String, required: false });
15 |
16 | this.option('create-all', { desc: 'Create a new model for this collection' });
17 |
18 |
19 | /* set the template name which is auto created */
20 | this.tmplOrig = this.name;
21 | this.tmpl = this.name + '_tmpl';
22 | this.tmplLocation = 'layout';
23 |
24 | if ( this.tmplOrig && this.options['create-all'] ) {
25 | this.hookFor('marionette', { as: 'tmpl', args: [this.tmplOrig, this.tmplLocation], options: this.options });
26 | }
27 |
28 | // invoke mocha
29 | this.hookFor('mocha-amd', {
30 | as: 'unitTest',
31 | args: [this.name, 'layout', 'views/layout']
32 | });
33 | }
34 |
35 | util.inherits(Generator, generator.NamedBase);
36 |
37 | Generator.prototype.createLayoutFiles = function createLayoutFiles() {
38 | var ext = 'js';
39 | var baseDir = validDir.getValidatedFolder( 'app/' );
40 |
41 | this.template('layout.' + ext, path.join(baseDir + 'scripts/views/layout', this.name + '.' + ext));
42 | };
43 |
--------------------------------------------------------------------------------
/model/index.js:
--------------------------------------------------------------------------------
1 | /*jshint latedef:false */
2 | var generator = require('yeoman-generator');
3 | var util = require('util');
4 | var path = require('path');
5 | var validDir = require('../helpers/validateDirectory');
6 |
7 |
8 | module.exports = Generator;
9 |
10 | function Generator() {
11 | generator.NamedBase.apply(this, arguments);
12 | var dirPath = '../templates/javascript';
13 | this.sourceRoot(path.join(__dirname, dirPath));
14 |
15 | this.argument( 'model', { type: String, required: false });
16 | this.argument('inherit', { type: String, required: false });
17 |
18 | // invoke mocha
19 | this.hookFor('mocha-amd', {
20 | as: 'unitTest',
21 | args: [this.name, 'model', 'models']
22 | });
23 |
24 | }
25 |
26 | util.inherits(Generator, generator.NamedBase);
27 |
28 | Generator.prototype.createModelFiles = function createModelFiles() {
29 | var ext = 'js';
30 | var baseDir = validDir.getValidatedFolder( 'app/' );
31 |
32 | this.template('model.' + ext, path.join(baseDir + 'scripts/models', this.name + '.' + ext));
33 | };
34 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "generator-marionette",
3 | "description": "Yeoman generator for Express, Marionette and Backbone with AMD",
4 | "version" : "0.1.6",
5 | "keywords": [
6 | "yeoman-generator",
7 | "yeoman",
8 | "generator",
9 | "marionette",
10 | "backbone",
11 | "framework",
12 | "mvc"
13 | ],
14 | "homepage": "https://github.com/mrichard/generator-marionette",
15 | "bugs": "https://github.com/mrichard/generator-marionette/issues",
16 | "author": "Michel Richard (clone of backbone amd generator)",
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/mrichard/generator-marionette.git"
20 | },
21 | "dependencies": {
22 | "yeoman-generator": "git://github.com/mrichard/generator.git",
23 | "underscore.string": "~2.3.1",
24 | "generator-buster": "~0.0.1",
25 | "chalk": "~0.2.0"
26 | },
27 | "devDependencies": {
28 | "mocha": "~1.8.1"
29 | },
30 | "engines": {
31 | "node": ">=0.8.0"
32 | },
33 | "licenses": [
34 | {
35 | "type": "BSD"
36 | }
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/region/index.js:
--------------------------------------------------------------------------------
1 | /*jshint latedef:false */
2 | var generator = require('yeoman-generator');
3 | var util = require('util');
4 | var path = require('path');
5 | var validDir = require('../helpers/validateDirectory');
6 |
7 |
8 | module.exports = Generator;
9 |
10 | function Generator() {
11 | generator.NamedBase.apply(this, arguments);
12 | var dirPath = '../templates/javascript';
13 | this.sourceRoot(path.join(__dirname, dirPath));
14 |
15 | this.argument('inherit', { type: String, required: false });
16 |
17 | // invoke mocha
18 | this.hookFor('mocha-amd', {
19 | as: 'unitTest',
20 | args: [this.name, 'region', 'regions']
21 | });
22 | }
23 |
24 | util.inherits(Generator, generator.NamedBase);
25 |
26 | Generator.prototype.createRegionFiles = function createRegionFiles() {
27 | var ext = 'js';
28 | var baseDir = validDir.getValidatedFolder( 'app/' );
29 |
30 | this.template('region.' + ext, path.join(baseDir + 'scripts/regions', this.name + '.' + ext));
31 | };
32 |
--------------------------------------------------------------------------------
/router/index.js:
--------------------------------------------------------------------------------
1 | /*jshint latedef:false */
2 | var generator = require('yeoman-generator');
3 | var util = require('util');
4 | var path = require('path');
5 | var validDir = require('../helpers/validateDirectory');
6 |
7 |
8 | module.exports = Generator;
9 |
10 | function Generator() {
11 | generator.NamedBase.apply(this, arguments);
12 | var dirPath = '../templates/javascript';
13 | this.sourceRoot(path.join(__dirname, dirPath));
14 |
15 | // invoke mocha
16 | this.hookFor('mocha-amd', {
17 | as: 'unitTest',
18 | args: [this.name, 'router', 'routers']
19 | });
20 |
21 | }
22 |
23 | util.inherits(Generator, generator.NamedBase);
24 |
25 | Generator.prototype.createRouterFiles = function createRouterFiles() {
26 | var ext = 'js';
27 | var baseDir = validDir.getValidatedFolder( 'app/' );
28 |
29 | this.template('router.' + ext, path.join(baseDir + 'scripts/routers', this.name + '.' + ext));
30 | };
31 |
--------------------------------------------------------------------------------
/templates/javascript/collection.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone'<% if (!_.isEmpty(model)) { %>,
3 | 'models/<%= model %>'<% } %><% if (!_.isEmpty(inherit)) { %>,
4 | 'collections/<%= inherit %>'<% } %>
5 | ],
6 | function( <%=_.classify('backbone')%><% if (!_.isEmpty(model)) { %>, <%=_.classify(model)%><% } %><% if (!_.isEmpty(inherit)) { %>, <%=_.classify(inherit)%><% } %> ) {
7 | 'use strict';
8 |
9 | /* Return a collection class definition */
10 | return <% if (!_.isEmpty(inherit)) { %><%=_.classify(inherit)%>.extend <% } else { %>Backbone.Collection.extend<% } %>({
11 | initialize: function() {
12 | console.log('initialize a <%= _.classify(name) %> collection');
13 | }<% if (!_.isEmpty(model)) { %>,
14 |
15 | model: <%= _.classify(model) %>
16 | <% } %>
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/templates/javascript/collectionview.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone'<% if (!_.isEmpty(itemview)) { %>,
3 | 'views/item/<%=itemview%>'<% } %><% if (!_.isEmpty(inherit)) { %>,
4 | 'views/collection/<%= inherit %>'<% } %>
5 | ],
6 | function( <%=_.classify('backbone')%><% if (!_.isEmpty(itemview)) { %>, <%=_.classify(itemview)%> <% } %><% if (!_.isEmpty(inherit)) { %>, <%=_.classify(inherit)%><% } %> ) {
7 | 'use strict';
8 |
9 | /* Return a ItemView class definition */
10 | return <% if (!_.isEmpty(inherit)) { %><%=_.classify(inherit)%>.extend <% } else { %>Backbone.Marionette.CollectionView.extend<% } %>({
11 |
12 | initialize: function() {
13 | console.log('initialize a <%= _.classify(name) %> CollectionView');
14 | },
15 | <% if (!_.isEmpty(itemview)) { %>
16 | itemView: <%= _.classify(itemview) %>,
17 | <% } %>
18 |
19 | /* ui selector cache */
20 | ui: {},
21 |
22 | /* Ui events hash */
23 | events: {},
24 |
25 | /* on render callback */
26 | onRender: function() {}
27 | });
28 |
29 | });
30 |
--------------------------------------------------------------------------------
/templates/javascript/compositeview.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone'<% if (!_.isEmpty(itemview)) { %>,
3 | 'views/item/<%=itemview%>'<% } %><% if (!_.isEmpty(compTmpl)) { %>,
4 | 'hbs!tmpl/<% if (!_.isEmpty(compTmplLocation)) { %><%= compTmplLocation%>/<% } %><%= compTmpl %>'<% } %><% if (!_.isEmpty(inherit)) { %>,
5 | 'views/composite/<%= inherit %>'<% } %>
6 | ],
7 | function( <%= _.classify('backbone')%><% if (!_.isEmpty(itemview)) { %>, <%=_.classify(itemview)%><% } %><% if (!_.isEmpty(compTmpl)) { %>, <%= _.classify(compTmpl)%> <% } %><% if (!_.isEmpty(inherit)) { %>, <%=_.classify(inherit)%><% } %> ) {
8 | 'use strict';
9 |
10 | /* Return a CompositeView class definition */
11 | return <% if (!_.isEmpty(inherit)) { %><%=_.classify(inherit)%>.extend <% } else { %>Backbone.Marionette.CompositeView.extend<% } %>({
12 |
13 | initialize: function() {
14 | console.log('initialize a <%= _.classify(name) %> CompositeView');
15 | },
16 | <% if (!_.isEmpty(itemview)) { %>
17 | itemView: <%= _.classify(itemview) %>,<% } %>
18 | <% if (!_.isEmpty(compTmpl)) { %>
19 | template: <%= _.classify(compTmpl) %>,
20 | <% } %>
21 |
22 | /* ui selector cache */
23 | ui: {},
24 |
25 | /* where are we appending the items views */
26 | itemViewContainer: '',
27 |
28 | /* Ui events hash */
29 | events: {},
30 |
31 | /* on render callback */
32 | onRender: function() {}
33 | });
34 |
35 | });
36 |
--------------------------------------------------------------------------------
/templates/javascript/controller.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone'<% if (!_.isEmpty(inherit)) { %>,
3 | 'controllers/<%= inherit %>'<% } %>
4 | ],
5 | function( <%= _.classify('backbone') %><% if (!_.isEmpty(inherit)) { %>, <%=_.classify(inherit)%><% } %> ) {
6 | 'use strict';
7 |
8 | return <% if (!_.isEmpty(inherit)) { %><%=_.classify(inherit)%>.extend <% } else { %>Backbone.Marionette.Controller.extend<% } %>({
9 |
10 | initialize: function( options ) {
11 | console.log('initialize a <%= _.classify(name) %> Controller');
12 | }
13 | });
14 |
15 | });
16 |
--------------------------------------------------------------------------------
/templates/javascript/itemview.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone'<% if (!_.isEmpty(tmpl)) { %>,
3 | 'hbs!tmpl/<% if (!_.isEmpty(tmplLocation)) { %><%= tmplLocation%>/<% } %><%= tmpl %>'<% } %><% if (!_.isEmpty(inherit)) { %>,
4 | 'views/item/<%= inherit %>'<% } %>
5 | ],
6 | function( <%= _.classify('backbone') %><% if (!_.isEmpty(tmpl)) { %>, <%= _.classify(tmpl) %> <% } %><% if (!_.isEmpty(inherit)) { %>, <%=_.classify(inherit)%><% } %> ) {
7 | 'use strict';
8 |
9 | /* Return a ItemView class definition */
10 | return <% if (!_.isEmpty(inherit)) { %><%=_.classify(inherit)%>.extend <% } else { %>Backbone.Marionette.ItemView.extend<% } %>({
11 |
12 | initialize: function() {
13 | console.log('initialize a <%= _.classify(name) %> ItemView');
14 | },
15 | <% if (!_.isEmpty(tmpl)) { %>
16 | template: <%= _.classify(tmpl) %>,
17 | <% } %>
18 |
19 | /* ui selector cache */
20 | ui: {},
21 |
22 | /* Ui events hash */
23 | events: {},
24 |
25 | /* on render callback */
26 | onRender: function() {}
27 | });
28 |
29 | });
30 |
--------------------------------------------------------------------------------
/templates/javascript/layout.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone'<% if (!_.isEmpty(tmpl)) { %>,
3 | 'hbs!tmpl/<% if (!_.isEmpty(tmplLocation)) { %><%= tmplLocation%>/<% } %><%= tmpl %>'<% } %><% if (!_.isEmpty(inherit)) { %>,
4 | 'views/layout/<%= inherit %>'<% } %>
5 | ],
6 | function( <%= _.classify('backbone') %><% if (!_.isEmpty(tmpl)) { %>, <%= _.classify(tmpl) %> <% } %><% if (!_.isEmpty(inherit)) { %>, <%=_.classify(inherit)%><% } %> ) {
7 | 'use strict';
8 |
9 | /* Return a Layout class definition */
10 | return <% if (!_.isEmpty(inherit)) { %><%=_.classify(inherit)%>.extend <% } else { %>Backbone.Marionette.Layout.extend<% } %>({
11 |
12 | initialize: function() {
13 | console.log('initialize a <%= _.classify(name) %> Layout');
14 | },
15 | <% if (!_.isEmpty(tmpl)) { %>
16 | template: <%= _.classify(tmpl) %>,
17 | <% } %>
18 |
19 | /* Layout sub regions */
20 | regions: {},
21 |
22 | /* ui selector cache */
23 | ui: {},
24 |
25 | /* Ui events hash */
26 | events: {},
27 |
28 | /* on render callback */
29 | onRender: function() {}
30 | });
31 |
32 | });
33 |
--------------------------------------------------------------------------------
/templates/javascript/model.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone'<% if (!_.isEmpty(inherit)) { %>,
3 | 'models/<%= inherit %>'<% } %>
4 | ],
5 | function( <%= _.classify('backbone') %><% if (!_.isEmpty(inherit)) { %>, <%=_.classify(inherit)%><% } %> ) {
6 | 'use strict';
7 |
8 | /* Return a model class definition */
9 | return <% if (!_.isEmpty(inherit)) { %><%=_.classify(inherit)%>.extend <% } else { %>Backbone.Model.extend<% } %>({
10 | initialize: function() {
11 | console.log('initialize a <%= _.classify(name) %> model');
12 | },
13 |
14 | defaults: {},
15 |
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/templates/javascript/region.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone'<% if (!_.isEmpty(inherit)) { %>,
3 | 'regions/<%= inherit %>'<% } %>
4 | ],
5 | function( <%= _.classify('backbone') %><% if (!_.isEmpty(inherit)) { %>, <%=_.classify(inherit)%><% } %> ) {
6 | 'use strict';
7 |
8 | /* Return a Region class definition */
9 | return <% if (!_.isEmpty(inherit)) { %><%=_.classify(inherit)%>.extend <% } else { %>Backbone.Marionette.Region.extend<% } %>({
10 |
11 | initialize: function() {
12 | console.log('initialize a <%= _.classify(name) %> Region');
13 | }
14 | });
15 |
16 | });
17 |
--------------------------------------------------------------------------------
/templates/javascript/router.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone'
3 | ],
4 | function(<%= _.classify('backbone') %>){
5 | 'use strict';
6 |
7 | return Backbone.Router.extend({
8 | /* Backbone routes hash */
9 | routes: {}
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/templates/javascript/tmpl.js:
--------------------------------------------------------------------------------
1 | {{!empty <%= _.classify(name) %> template}}
--------------------------------------------------------------------------------
/templates/javascript/view.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'backbone'
3 | ],
4 | function(<%= _.classify('backbone') %>){
5 | 'use strict';
6 |
7 | return Backbone.View.extend({
8 | initialize: function() {
9 | console.log('initialize a <%= _.classify(name) %> View');
10 | }
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/test/tests.js:
--------------------------------------------------------------------------------
1 | /*global describe beforeEach it*/
2 |
3 | var path = require('path');
4 | var generator = require('yeoman-generator');
5 | var util = require('util')
6 | var helpers = require('yeoman-generator').test;
7 | var assert = require('assert');
8 |
9 | describe('Backbone AMD generator test', function () {
10 | var backbone;
11 |
12 | beforeEach(function (done) {
13 | var deps = [
14 | '../../app',
15 | '../../model',
16 | '../../collection',
17 | '../../view',
18 | '../../router', [
19 | helpers.createDummyGenerator(),
20 | 'buster:app'
21 | ]
22 | ];
23 | helpers.testDirectory(path.join(__dirname, 'temp'), function (err) {
24 | if (err) {
25 | return done(err);
26 | }
27 | backbone = helpers.createGenerator('backbone-amd:app', deps);
28 | done();
29 | });
30 | });
31 |
32 | it('creates expected files', function(done) {
33 | var expected = [
34 | ['component.json', /"name": "temp"/],
35 | ['package.json', /"name": "temp"/],
36 | 'Gruntfile.js',
37 | 'app/404.html',
38 | 'app/favicon.ico',
39 | 'app/robots.txt',
40 | 'app/index.html',
41 | 'app/.htaccess',
42 | '.gitignore',
43 | '.gitattributes',
44 | ['.bowerrc', /"directory": "app\/components"/],
45 | ['component.json', /"name":\s+"temp"/],
46 | '.jshintrc',
47 | '.editorconfig',
48 | 'Gruntfile.js',
49 | 'package.json',
50 | ['app/scripts/main.js', /'temp',\s+'jquery',\s+/],
51 | ['app/scripts/temp.js', /Temp\s+=\s+[\w\W\s]+Views[\w\W\s]+Models[\w\W\s]+Collections[\w\W\s]+Routers/]
52 | ];
53 |
54 | helpers.mockPrompt(backbone, {
55 | 'compassBootstrap': 'Y',
56 | 'includeRequireJS': 'N'
57 | });
58 |
59 | backbone.run({}, function () {
60 | helpers.assertFiles(expected);
61 | done();
62 | });
63 | });
64 |
65 | it('include requirejs', function(done) {
66 | var expected = [
67 | ['component.json', /"requirejs"/],
68 | ['package.json', /"name": "temp"/],
69 | 'Gruntfile.js',
70 | 'app/404.html',
71 | 'app/favicon.ico',
72 | 'app/robots.txt',
73 | ['app/index.html', /