├── .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 | 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 | 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 = $('