├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── app ├── USAGE ├── index.js └── templates │ ├── 404.html │ ├── Gruntfile.js │ ├── README.txt │ ├── _bower.json │ ├── _package.json │ ├── bowerrc │ ├── editorconfig │ ├── favicon.ico │ ├── gitattributes │ ├── gitignore │ ├── htaccess │ ├── index.html │ ├── index2.html │ ├── infra.js │ ├── jshintrc │ ├── main.css │ ├── main.js │ ├── main.scss │ ├── main2.js │ └── robots.txt ├── contributing.md ├── package.json ├── readme.md └── test └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | temp/ 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": false, 5 | "curly": false, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "latedef": true, 10 | "newcap": true, 11 | "noarg": true, 12 | "undef": true, 13 | "strict": false, 14 | "trailing": true, 15 | "smarttabs": true 16 | } 17 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .npmignore 2 | .editorconfig 3 | .travis.yml 4 | .jshintrc 5 | .gitattributes 6 | contributing.md 7 | test 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | -------------------------------------------------------------------------------- /app/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new basic Django web application with front-end support. 3 | 4 | Options: 5 | Bootstrap: Include Bootstrap for Sass 6 | 7 | Example: 8 | yo django-webapp [--coffee] 9 | 10 | This will create: 11 | Gruntfile.js: Configuration for the task runner. 12 | bower.json: Front-end packages installed by bower. 13 | package.json: Development packages installed by npm. 14 | 15 | app/: Your application files. 16 | test/: Unit tests for your application. 17 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var fs = require('fs'); 3 | var util = require('util'); 4 | var path = require('path'); 5 | var spawn = require('child_process').spawn; 6 | var yeoman = require('yeoman-generator'); 7 | var chalk = require('chalk'); 8 | var _ = require('lodash'); 9 | 10 | 11 | var AppGenerator = module.exports = function Appgenerator(args, options, config) { 12 | yeoman.generators.Base.apply(this, arguments); 13 | 14 | // setup the test-framework property, Gruntfile template will need this 15 | this.testFramework = options['test-framework'] || 'mocha'; 16 | this.coffee = options.coffee; 17 | 18 | // for hooks to resolve on mocha by default 19 | options['test-framework'] = this.testFramework; 20 | 21 | // resolved to mocha by default (could be switched to jasmine for instance) 22 | this.hookFor('test-framework', { 23 | as: 'app', 24 | options: { 25 | options: { 26 | 'skip-install': options['skip-install-message'], 27 | 'skip-message': options['skip-install'] 28 | } 29 | } 30 | }); 31 | 32 | this.options = options; 33 | 34 | this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json'))); 35 | }; 36 | 37 | util.inherits(AppGenerator, yeoman.generators.Base); 38 | 39 | var fileRelative = function (from, to) { 40 | return path.join(path.relative(path.dirname(from), path.dirname(to)), path.basename(to)); 41 | }; 42 | 43 | var djangoFail = function () { 44 | // Fail for any other circumstances 45 | console.error(chalk.red('Error: Django project not found, or project name is wrong.')); 46 | console.error(chalk.red('\nYou must run me in the base directory of the project\n(e.g. the one contains `manage.py` file).')); 47 | process.exit(1); 48 | }; 49 | 50 | AppGenerator.prototype.askFor = function askFor() { 51 | var cb = this.async(); 52 | 53 | if (fs.existsSync('manage.py')) { 54 | // welcome message 55 | if (!this.options['skip-welcome-message']) { 56 | console.log(this.yeoman); 57 | console.log(chalk.magenta('Out of the box I include HTML5 Boilerplate, jQuery, and a Gruntfile.js to build your app.')); 58 | } 59 | 60 | // Try to figure out which is the Django project directory 61 | var cwd = process.cwd(); 62 | var files = fs.readdirSync(cwd); 63 | var projDir = _.find(files, function (f) { 64 | if (f[0] === '.') return; 65 | var fpath = path.join(cwd, f); 66 | if (!fs.statSync(fpath).isDirectory()) return; 67 | if (fs.existsSync(path.join(fpath, '__init__.py')) && fs.existsSync(path.join(fpath, 'settings.py'))) { 68 | return true; 69 | } 70 | }); 71 | 72 | // Ask the user, with detected directory as default if any 73 | var prompts = [{ 74 | name: 'projectName', 75 | message: 'What is your Django project name?', 76 | default: projDir, 77 | validate: function (input) { 78 | if (!input) { 79 | return 'Please enter a name.'; 80 | } 81 | return true; 82 | } 83 | }, { 84 | type: 'checkbox', 85 | name: 'features', 86 | message: 'What more would you like?', 87 | choices: [{ 88 | name: 'Bootstrap', 89 | value: 'includeBootstrap', 90 | checked: true 91 | },{ 92 | name: 'Sass with Compass', 93 | value: 'includeCompass', 94 | checked: false 95 | },{ 96 | name: 'Less', 97 | value: 'includeLess', 98 | checked: true 99 | },{ 100 | name: 'Modernizr', 101 | value: 'includeModernizr', 102 | checked: true 103 | },{ 104 | name: 'RequireJS', 105 | value: 'includeRequireJS', 106 | checked: true 107 | }] 108 | }]; 109 | 110 | this.prompt(prompts, function (answers) { 111 | this.projectName = answers.projectName; 112 | 113 | var features = answers.features; 114 | 115 | function hasFeature(feat) { return features.indexOf(feat) !== -1; } 116 | 117 | // manually deal with the response, get back and store the results. 118 | // we change a bit this way of doing to automatically do this in the self.prompt() method. 119 | this.includeCompass = hasFeature('includeCompass'); 120 | this.includeLess = hasFeature('includeLess'); 121 | this.includeBootstrap = hasFeature('includeBootstrap'); 122 | this.includeModernizr = hasFeature('includeModernizr'); 123 | this.includeRequireJS = hasFeature('includeRequireJS'); 124 | 125 | cb(); 126 | }.bind(this)); 127 | } 128 | else { 129 | djangoFail(); 130 | } 131 | }; 132 | 133 | AppGenerator.prototype.djangoCheck = function djangoCheck() { 134 | // Check again 135 | if (this.projectName && fs.existsSync(this.projectName + '/__init__.py')) { 136 | if (fs.existsSync(this.projectName + '/settings.py')) { 137 | this.hasSettings = true; 138 | } 139 | return; 140 | } 141 | djangoFail(); 142 | }; 143 | 144 | AppGenerator.prototype.djangoProjectDir = function djangoProjectDir() { 145 | // Save current working directory 146 | var cwd = process.cwd(); 147 | 148 | // my 149 | var myDir = path.join(cwd, this.projectName, 'my'); 150 | try { 151 | fs.mkdirSync(myDir); 152 | } 153 | catch (err) {} 154 | 155 | // spec 156 | var specDir = path.join(cwd, this.projectName, 'spec'); 157 | 158 | // my/requirements/ 159 | var sourceRequirementsLocal = path.join(myDir, 'requirements/local.txt'); 160 | try { 161 | fs.mkdirSync(path.dirname(sourceRequirementsLocal)); 162 | } 163 | catch (err) {} 164 | fs.writeFile( 165 | sourceRequirementsLocal, 166 | '# This file contains Python dependencies for your local development.\n# You can also put dependencies of your choice here.\n-r common.txt\n-r dev.txt', 167 | function (err) { 168 | if (err) throw err; 169 | 170 | // Make a symbolic link 171 | var target = path.join(cwd, 'requirements/local.txt'); 172 | if (fs.existsSync(target)) { 173 | fs.unlinkSync(target); 174 | } 175 | else { 176 | try { 177 | fs.mkdirSync(path.dirname(target)); 178 | } 179 | catch (e) {} 180 | } 181 | fs.symlinkSync(fileRelative(target, sourceRequirementsLocal), target); 182 | } 183 | ); 184 | 185 | // my/stage/ 186 | var sourceStageSecret = path.join(myDir, 'stage/secret.py'); 187 | try { 188 | fs.mkdirSync(path.dirname(sourceStageSecret)); 189 | } 190 | catch (err) {} 191 | fs.writeFile( 192 | sourceStageSecret, 193 | '# -*- coding: utf-8 -*-\n# Put secrets here, e.g. SECRET_KEYS, database password, etc.', 194 | function (err) { 195 | if (err) throw err; 196 | 197 | // Make a symbolic link 198 | var target = path.join(specDir, 'stage/secret.py'); 199 | if (fs.existsSync(target)) { 200 | fs.unlinkSync(target); 201 | } 202 | else { 203 | try { 204 | fs.mkdirSync(path.dirname(target)); 205 | } 206 | catch (e) {} 207 | } 208 | fs.symlinkSync(fileRelative(target, sourceStageSecret), target); 209 | } 210 | ); 211 | 212 | // my/prod 213 | var sourceProdSecret = path.join(myDir, 'prod/secret.py'); 214 | try { 215 | fs.mkdirSync(path.dirname(sourceProdSecret)); 216 | } 217 | catch (err) {} 218 | fs.writeFile( 219 | sourceProdSecret, 220 | '# -*- coding: utf-8 -*-\n# Put secrets here, e.g. SECRET_KEYS, database password, etc.', 221 | function (err) { 222 | if (err) throw err; 223 | 224 | // Make a symbolic link 225 | var target = path.join(specDir, 'prod/secret.py'); 226 | if (fs.existsSync(target)) { 227 | fs.unlinkSync(target); 228 | } 229 | else { 230 | try { 231 | fs.mkdirSync(path.dirname(target)); 232 | } 233 | catch (e) {} 234 | } 235 | fs.symlinkSync(fileRelative(target, sourceProdSecret), target); 236 | } 237 | ); 238 | 239 | // my/local 240 | var sourceLocalSettings = path.join(myDir, 'local/settings.py'); 241 | try { 242 | fs.mkdirSync(path.dirname(sourceLocalSettings)); 243 | } 244 | catch (err) {} 245 | fs.writeFile( 246 | sourceLocalSettings, 247 | this.engine('\ 248 | # -*- coding: utf-8 -*-\nfrom <%= projectName %>.settings import *\n\n\ 249 | WSGI_APPLICATION = \'<%= projectName %>.spec.local.wsgi.application\'', this), 250 | function (err) { 251 | if (err) throw err; 252 | 253 | // Make a symbolic link 254 | var target = path.join(specDir, 'local/settings.py'); 255 | if (fs.existsSync(target)) { 256 | fs.unlinkSync(target); 257 | } 258 | else { 259 | try { 260 | fs.mkdirSync(path.dirname(target)); 261 | } 262 | catch (e) {} 263 | } 264 | fs.symlinkSync(fileRelative(target, sourceLocalSettings), target); 265 | } 266 | ); 267 | 268 | var sourceLocalWsgi = path.join(myDir, 'local/wsgi.py'); 269 | try { 270 | fs.mkdirSync(path.dirname(sourceLocalWsgi)); 271 | } 272 | catch (err) {} 273 | fs.writeFile( 274 | sourceLocalWsgi, 275 | this.engine('\ 276 | # -*- coding: utf-8 -*-\n\ 277 | import os\n\ 278 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<%= projectName %>.spec.local.settings")\n\n\ 279 | from <%= projectName %>.wsgi import application', this), 280 | function (err) { 281 | if (err) throw err; 282 | 283 | // Make a symbolic link 284 | var target = path.join(specDir, 'local/wsgi.py'); 285 | if (fs.existsSync(target)) { 286 | fs.unlinkSync(target); 287 | } 288 | else { 289 | try { 290 | fs.mkdirSync(path.dirname(target)); 291 | } 292 | catch (e) {} 293 | } 294 | fs.symlinkSync(fileRelative(target, sourceLocalWsgi), target); 295 | } 296 | ); 297 | 298 | // spec/stage 299 | this.write(specDir + '/__init__.py', ''); 300 | this.write(specDir + '/stage/__init__.py', ''); 301 | 302 | this.write(specDir + '/stage/settings.py', this.engine('\ 303 | # -*- coding: utf-8 -*-\nfrom <%= projectName %>.settings import *\n\n\ 304 | WSGI_APPLICATION = \'<%= projectName %>.spec.stage.wsgi.application\'', this)); 305 | 306 | this.write(specDir + '/stage/wsgi.py', this.engine('\ 307 | # -*- coding: utf-8 -*-\n\ 308 | import os\n\ 309 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<%= projectName %>.spec.stage.settings")\n\n\ 310 | from <%= projectName %>.wsgi import application', this)); 311 | 312 | // spec/prod 313 | this.write(specDir + '/prod/__init__.py', ''); 314 | 315 | this.write(specDir + '/prod/settings.py', this.engine('\ 316 | # -*- coding: utf-8 -*-\nfrom <%= projectName %>.settings import *\n\n\ 317 | WSGI_APPLICATION = \'<%= projectName %>.spec.prod.wsgi.application\'', this)); 318 | 319 | this.write(specDir + '/prod/wsgi.py', this.engine('\ 320 | # -*- coding: utf-8 -*-\n\ 321 | import os\n\ 322 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<%= projectName %>.spec.prod.settings")\n\n\ 323 | from <%= projectName %>.wsgi import application', this)); 324 | 325 | // spec/local 326 | this.write(specDir + '/local/__init__.py', ''); 327 | 328 | // apps 329 | var appsDir = this.projectName + '/apps'; 330 | this.write(appsDir + '/__init__.py', ''); 331 | 332 | // common 333 | var commonDir = this.projectName + '/common'; 334 | this.write(commonDir + '/__init__.py', ''); 335 | this.write( 336 | commonDir + '/trans.py', 337 | '\ 338 | # -*- coding: utf-8 -*-\n\ 339 | # Put the string you want to manually translate in this file, like this:\n\ 340 | #\n\ 341 | # _(\'Something that is not translated in offcial Django distro.\')\n\ 342 | #\n\ 343 | # When you run `django-admin.py makemessage -l ` command, it will create a message file:\n\ 344 | #\n\ 345 | # locale//LC_MESSAGES/django.po\n\ 346 | #\n\ 347 | # For more information about translation, see:\n\ 348 | # https://docs.djangoproject.com/en/dev/topics/i18n/translation/\n\ 349 | from django.utils.translation import ugettext_lazy as _\n\n' 350 | ); 351 | this.write(commonDir + '/management/__init__.py', ''); 352 | this.write(commonDir + '/management/commands/__init__.py', ''); 353 | this.write(commonDir + '/templatetags/__init__.py', ''); 354 | this.write(commonDir + '/test/__init__.py', '') 355 | this.mkdir(commonDir + '/templates'); 356 | this.mkdir(commonDir + '/static'); 357 | 358 | // utils 359 | var utilsDir = this.projectName + '/utils'; 360 | this.write(utilsDir + '/__init__.py', ''); 361 | }; 362 | 363 | AppGenerator.prototype.djangoDirRequirements = function djangoDirRequirements() { 364 | this.write('requirements/common.txt', '# This file contains common Python dependencies for all circumstances.'); 365 | this.write('requirements/stage.txt', '# This file contains Python dependencies for the staging server.\n-r common.txt'); 366 | this.write('requirements/prod.txt', '# This file contains Python dependencies for the production server.\n-r common.txt'); 367 | this.write('requirements/dev.txt', '# This file contains Python dependencies for development only.'); 368 | }; 369 | 370 | AppGenerator.prototype.djangoDirFabric = function djangoDirFabric() { 371 | this.write('fabfile/__init__.py', ''); 372 | this.write('fabfile/build.py', ''); 373 | this.write('fabfile/deploy/__init__.py', ''); 374 | this.write('fabfile/deploy/stage.py', ''); 375 | this.write('fabfile/deploy/prod.py', ''); 376 | }; 377 | 378 | AppGenerator.prototype.djangoDirReferences = function djangoDirReferences() { 379 | this.mkdir('references'); 380 | this.mkdir('references/conf/stage'); 381 | this.mkdir('references/conf/stage/uwsgi'); 382 | this.mkdir('references/conf/stage/ngix'); 383 | this.mkdir('references/conf/prod'); 384 | this.mkdir('references/conf/prod/uwsgi'); 385 | this.mkdir('references/conf/prod/ngix'); 386 | this.mkdir('references/docs'); 387 | }; 388 | 389 | AppGenerator.prototype.djangoDirEtc = function djangoDirEtc() { 390 | this.mkdir('etc'); 391 | this.mkdir('etc/static'); 392 | this.mkdir('etc/static/styles'); 393 | if (this.includeLess) { 394 | this.mkdir('etc/static/less'); 395 | } 396 | this.mkdir('etc/static/scripts'); 397 | this.mkdir('etc/static/images'); 398 | this.mkdir('etc/static/fonts'); 399 | this.mkdir('etc/templates'); 400 | this.mkdir('etc/uploads'); 401 | this.mkdir('etc/test'); 402 | }; 403 | 404 | AppGenerator.prototype.djangoSettings = function djangoSettings() { 405 | if (!this.hasSettings) { 406 | console.warn(chalk.orange('Warning: `%s/settings.py` file not found. You must manually edit STATICFILES_DIRS, TEMPLATE_DIRS and MEDIA_ROOT of project settings.'), this.projectName); 407 | return; 408 | } 409 | 410 | // Modify settings.py 411 | var settings_file = this.projectName + '/settings.py'; 412 | var settings_body = this.readFileAsString(settings_file); 413 | if (settings_body.indexOf('import os') < 0) { 414 | settings_body = settings_body + '\nimport os\n'; 415 | } 416 | 417 | if (settings_body.indexOf('BASE_DIR') < 0) { 418 | settings_body = settings_body + '\nBASE_DIR = os.path.dirname(os.path.dirname(__file__))\n'; 419 | } 420 | 421 | if (settings_body.indexOf('STATIC_ROOT') < 0) { 422 | settings_body = settings_body + '\n# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-STATIC_ROOT\nSTATIC_ROOT = os.path.join(BASE_DIR, \'etc/static_collected\')\n'; 423 | } 424 | 425 | if (settings_body.indexOf('STATICFILES_DIRS') < 0) { 426 | settings_body = settings_body + '\nSTATICFILES_DIRS = (\n os.path.join(BASE_DIR, \'etc/static\'),\n)\n'; 427 | } 428 | 429 | if (settings_body.indexOf('TEMPLATE_DIRS') < 0) { 430 | settings_body = settings_body + '\nTEMPLATE_DIRS = (\n os.path.join(BASE_DIR, \'etc/templates\'),\n)\n'; 431 | } 432 | 433 | if (settings_body.indexOf('MEDIA_ROOT') < 0) { 434 | settings_body = settings_body + '\nMEDIA_ROOT = os.path.join(BASE_DIR, \'etc/uploads\')\n'; 435 | } 436 | 437 | fs.writeFile(settings_file, settings_body, function (err) { 438 | if (err) throw err; 439 | }); 440 | }; 441 | 442 | AppGenerator.prototype.git = function git() { 443 | this.copy('gitignore', '.gitignore'); 444 | this.copy('gitattributes', '.gitattributes'); 445 | }; 446 | 447 | AppGenerator.prototype.gruntfile = function gruntfile() { 448 | this.template('Gruntfile.js', 'etc/Gruntfile.js'); 449 | }; 450 | 451 | AppGenerator.prototype.packageJSON = function packageJSON() { 452 | this.template('_package.json', 'etc/package.json'); 453 | }; 454 | 455 | AppGenerator.prototype.bower = function bower() { 456 | this.copy('bowerrc', 'etc/.bowerrc'); 457 | this.copy('_bower.json', 'etc/bower.json'); 458 | }; 459 | 460 | AppGenerator.prototype.jshint = function jshint() { 461 | this.copy('jshintrc', 'etc/.jshintrc'); 462 | }; 463 | 464 | AppGenerator.prototype.editorConfig = function editorConfig() { 465 | this.copy('editorconfig', 'etc/.editorconfig'); 466 | }; 467 | 468 | AppGenerator.prototype.h5bp = function h5bp() { 469 | this.copy('404.html', 'etc/templates/404.html'); 470 | this.copy('favicon.ico', 'etc/static/favicon.ico'); 471 | this.copy('robots.txt', 'etc/static/robots.txt'); 472 | this.copy('htaccess', 'etc/static/.htaccess'); 473 | }; 474 | 475 | AppGenerator.prototype.mainStylesheet = function mainStylesheet() { 476 | var css = 'main.' + (this.includeCompass ? 's' : '') + 'css'; 477 | this.copy(css, 'etc/static/styles/' + css); 478 | }; 479 | 480 | AppGenerator.prototype.writeIndex = function writeIndex() { 481 | 482 | this.indexFile = this.readFileAsString(path.join(this.sourceRoot(), 'index.html')); 483 | this.indexFile = this.engine(this.indexFile, this); 484 | 485 | if (this.includeRequireJS) { 486 | this.copy('index2.html', 'etc/templates/index2.html'); 487 | this.copy('infra.js', 'etc/static/scripts/infra.js'); 488 | this.copy('main.js', 'etc/static/scripts/main.js'); 489 | this.copy('main2.js', 'etc/static/scripts/main2.js'); 490 | } 491 | else { 492 | // No RequireJS 493 | // wire Bootstrap plugins 494 | if (this.includeBootstrap) { 495 | var bs = '../bower_components/bootstrap' + (this.includeCompass ? '-sass-official/vendor/assets/javascripts/bootstrap/' : '/js/'); 496 | this.indexFile = this.appendScripts(this.indexFile, 'scripts/plugins.js', [ 497 | bs + 'affix.js', 498 | bs + 'alert.js', 499 | bs + 'dropdown.js', 500 | bs + 'tooltip.js', 501 | bs + 'modal.js', 502 | bs + 'transition.js', 503 | bs + 'button.js', 504 | bs + 'popover.js', 505 | bs + 'carousel.js', 506 | bs + 'scrollspy.js', 507 | bs + 'collapse.js', 508 | bs + 'tab.js' 509 | ]); 510 | } 511 | 512 | this.indexFile = this.appendFiles({ 513 | html: this.indexFile, 514 | fileType: 'js', 515 | optimizedPath: 'scripts/main.js', 516 | sourceFileList: ['{{ STATIC_URL }}scripts/main.js'], 517 | searchPath: '{app,.tmp}' 518 | }); 519 | } 520 | }; 521 | 522 | AppGenerator.prototype.app = function app() { 523 | this.write('etc/templates/index.html', this.indexFile); 524 | 525 | if (!this.includeRequireJS) { 526 | if (this.coffee) { 527 | this.write( 528 | 'etc/static/scripts/main.coffee', 529 | 'console.log "\'Allo from CoffeeScript!"' 530 | ); 531 | } 532 | else { 533 | this.write('etc/static/scripts/main.js', 'console.log(\'\\\'Allo \\\'Allo!\');'); 534 | } 535 | } 536 | }; 537 | 538 | AppGenerator.prototype.readme = function readme() { 539 | this.template('README.txt'); 540 | }; 541 | 542 | AppGenerator.prototype.chdir = function chdir() { 543 | process.chdir('etc'); 544 | }; 545 | 546 | AppGenerator.prototype.install = function () { 547 | if (this.options['skip-install']) { 548 | return; 549 | } 550 | 551 | var done = this.async(); 552 | this.installDependencies({ 553 | skipMessage: this.options['skip-install-message'], 554 | skipInstall: this.options['skip-install'], 555 | callback: done 556 | }); 557 | }; 558 | 559 | AppGenerator.prototype.notice = function () { 560 | console.log(chalk.magenta('\nNotice: Please run `cd etc`, then run `grunt` to build static assets.\n')); 561 | } 562 | -------------------------------------------------------------------------------- /app/templates/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/Gruntfile.js: -------------------------------------------------------------------------------- 1 | // Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %> 2 | 'use strict'; 3 | 4 | // # Globbing 5 | // for performance reasons we're only matching one level down: 6 | // 'test/spec/{,*/}*.js' 7 | // use this if you want to recursively match all subfolders: 8 | // 'test/spec/**/*.js' 9 | 10 | module.exports = function (grunt) { 11 | 12 | // Load grunt tasks automatically 13 | require('load-grunt-tasks')(grunt); 14 | 15 | // Time how long tasks take. Can help when optimizing build times 16 | require('time-grunt')(grunt); 17 | 18 | <% if (includeRequireJS) { %>// ReuireJS configuration sample for distribution 19 | var requirejsDistModules = [ 20 | { 21 | name: 'main', 22 | exclude: ['infra'] 23 | }, { 24 | name: 'main2', 25 | exclude: ['infra'] 26 | }, { 27 | name: 'infra' 28 | } 29 | ]; 30 | 31 | <% } %>// Define the configuration for all the tasks 32 | grunt.initConfig({ 33 | 34 | // Configurable paths 35 | config: { 36 | assets: 'static', 37 | templates: 'templates', 38 | collectedAssets: 'static_collected', 39 | collectedTemplates: 'templates_collected', 40 | dist: 'dist', 41 | distAssets: 'dist/static', 42 | distTemplates: 'dist/templates' 43 | }, 44 | 45 | <% if (includeRequireJS) { %>// Optimize RequireJS projects using r.js 46 | requirejs: { 47 | dist: { 48 | // https://github.com/jrburke/r.js/blob/master/build/example.build.js 49 | options: { 50 | baseUrl: '<%%= config.collectedAssets %>/scripts', 51 | dir: '<%%= config.distAssets %>/scripts', 52 | paths: { 53 | jquery: '../bower_components/jquery/dist/jquery', 54 | bootstrap: '../bower_components/bootstrap/dist/js/bootstrap' 55 | }, 56 | shim: { 57 | bootstrap: ['jquery'], 58 | }, 59 | modules: requirejsDistModules, 60 | optimize: 'uglify', 61 | preserveLicenseComments: false, 62 | useStrict: true, 63 | wrap: true, 64 | removeCombined: true, 65 | findNestedDependencies: true 66 | } 67 | } 68 | }, 69 | 70 | // Custom task to collect information of revved files of RequireJS modules, 71 | // then write a temporary file for inserting into html body for paths config 72 | requirejspaths: { 73 | dist: { 74 | options: { 75 | baseRoot: '<%%= config.distAssets %>/scripts', 76 | baseUrl: '{{ STATIC_URL }}scripts', 77 | modules: requirejsDistModules.map(function(m) {return m.name;}), 78 | outputFile: '.tmp/requirejspaths.html' 79 | } 80 | } 81 | }, 82 | 83 | // Process html files at build time to modify them depending on the release environment 84 | processhtml: { 85 | options: { 86 | commentMarker: 'process', 87 | includeBase: '.tmp', 88 | }, 89 | dist: { 90 | files: [{ 91 | expand: true, 92 | cwd: '<%%= config.collectedTemplates %>', 93 | src: '**/*.html', 94 | dest: '<%%= config.distTemplates %>' 95 | }] 96 | } 97 | }, 98 | 99 | <% } %>// Watches files for changes and runs tasks based on the changed files 100 | watch: { 101 | // bower: { 102 | // files: ['bower.json'], 103 | // tasks: ['bowerInstall'] 104 | // }, 105 | <% if (coffee) { %> 106 | coffee: { 107 | files: ['<%%= config.assets %>/scripts/**/*.{coffee,litcoffee,coffee.md}'], 108 | tasks: ['coffee:server'] 109 | }, 110 | coffeeTest: { 111 | files: ['test/spec/**/*.{coffee,litcoffee,coffee.md}'], 112 | tasks: ['coffee:test', 'test:watch'] 113 | },<% } else { %> 114 | js: { 115 | files: ['<%%= config.assets %>/scripts/**/*.js'], 116 | tasks: ['jshint'], 117 | options: { 118 | livereload: true 119 | } 120 | }, 121 | jstest: { 122 | files: ['test/spec/**/*.js'], 123 | tasks: ['test:watch'] 124 | },<% } %> 125 | gruntfile: { 126 | files: ['Gruntfile.js'] 127 | },<% if (includeCompass) { %> 128 | compass: { 129 | files: ['<%%= config.assets %>/styles/**/*.{scss,sass}'], 130 | tasks: ['compass:server', 'autoprefixer'] 131 | },<% } %><% if (includeLess) { %> 132 | less: { 133 | files: ['<%%= config.assets %>/less/**/*.less'], 134 | tasks: ['less:server'] 135 | },<% } %> 136 | styles: { 137 | files: ['<%%= config.assets %>/styles/**/*.css'], 138 | tasks: ['newer:copy:styles', 'autoprefixer'] 139 | }, 140 | livereload: { 141 | options: { 142 | livereload: '<%%= connect.options.livereload %>' 143 | }, 144 | files: [ 145 | '<%%= config.templates %>/**/*.html', 146 | '.tmp/styles/**/*.css',<% if (coffee) { %> 147 | '.tmp/scripts/**/*.js',<% } %> 148 | '<%%= config.assets %>/images/**/*' 149 | ] 150 | } 151 | }, 152 | 153 | // The actual grunt server settings 154 | connect: { 155 | options: { 156 | port: 9000, 157 | open: true, 158 | livereload: 35729, 159 | // Change this to '0.0.0.0' to access the server from outside 160 | hostname: 'localhost' 161 | }, 162 | livereload: { 163 | options: { 164 | base: [ 165 | '.tmp', 166 | '<%= config.assets %>', 167 | '<%= config.templates %>' 168 | ] 169 | } 170 | }, 171 | test: { 172 | options: { 173 | open: false, 174 | port: 9001, 175 | base: [ 176 | '.tmp', 177 | '<%= config.assets %>', 178 | '<%= config.templates %>' 179 | ] 180 | } 181 | }, 182 | dist: { 183 | options: { 184 | base: [ 185 | '<%%= config.distAssets %>', 186 | '<%%= config.distTemplates %>' 187 | ], 188 | livereload: false 189 | } 190 | } 191 | }, 192 | 193 | // Empties folders to start fresh 194 | clean: { 195 | dist: { 196 | files: [{ 197 | dot: true, 198 | src: [ 199 | '.tmp', 200 | '<%%= config.dist %>/*', 201 | '!<%%= config.dist %>/.git*' 202 | ] 203 | }] 204 | }, 205 | server: '.tmp'<% if (includeRequireJS) { %>, 206 | requirejs: '<%%= config.distAssets %>/scripts/build.txt'<% } %>, 207 | collected: [ 208 | '<%%= config.collectedAssets %>', 209 | '<%%= config.collectedTemplates %>' 210 | ] 211 | }, 212 | 213 | // Make sure code styles are up to par and there are no obvious mistakes 214 | jshint: { 215 | options: { 216 | jshintrc: '.jshintrc', 217 | reporter: require('jshint-stylish') 218 | }, 219 | all: [ 220 | 'Gruntfile.js', 221 | '<%%= config.assets %>/scripts/**/*.js', 222 | '!<%%= config.assets %>/scripts/vendor/*', 223 | '<%%= config.collectedAssets %>/scripts/**/*.js', 224 | '!<%%= config.collectedAssets %>/scripts/vendor/*', 225 | 'test/spec/**/*.js' 226 | ] 227 | },<% if (testFramework === 'mocha') { %> 228 | 229 | // Mocha testing framework configuration options 230 | mocha: { 231 | all: { 232 | options: { 233 | run: true, 234 | urls: ['http://<%%= connect.test.options.hostname %>:<%%= connect.test.options.port %>/index.html'] 235 | } 236 | } 237 | },<% } else if (testFramework === 'jasmine') { %> 238 | 239 | // Jasmine testing framework configuration options 240 | jasmine: { 241 | all: { 242 | options: { 243 | specs: 'test/spec/**/*.js' 244 | } 245 | } 246 | },<% } %><% if (coffee) { %> 247 | 248 | // Compiles CoffeeScript to JavaScript 249 | coffee: { 250 | server: { 251 | files: [{ 252 | expand: true, 253 | cwd: '<%%= config.assets %>/scripts', 254 | src: '**/*.{coffee,litcoffee,coffee.md}', 255 | dest: '.tmp/scripts', 256 | ext: '.js' 257 | }] 258 | }, 259 | dist: { 260 | files: [{ 261 | expand: true, 262 | cwd: '<%%= config.collectedAssets %>/scripts', 263 | src: '**/*.{coffee,litcoffee,coffee.md}', 264 | dest: '.tmp/scripts', 265 | ext: '.js' 266 | }] 267 | }, 268 | test: { 269 | files: [{ 270 | expand: true, 271 | cwd: 'test/spec', 272 | src: '**/*.{coffee,litcoffee,coffee.md}', 273 | dest: '.tmp/spec', 274 | ext: '.js' 275 | }] 276 | } 277 | },<% } %><% if (includeCompass) { %> 278 | 279 | // Compiles Sass to CSS and generates necessary files if requested 280 | compass: { 281 | options: { 282 | cssDir: '.tmp/styles', 283 | generatedImagesDir: '.tmp/images/generated', 284 | httpImagesPath: '/images', 285 | httpGeneratedImagesPath: '/images/generated', 286 | httpFontsPath: '/fonts', 287 | relativeAssets: false, 288 | assetCacheBuster: false 289 | }, 290 | dist: { 291 | options: { 292 | sassDir: '<%%= config.collectedAssets %>/styles', 293 | imagesDir: '<%%= config.collectedAssets %>/images', 294 | javascriptsDir: '<%%= config.collectedAssets %>/scripts', 295 | fontsDir: '<%%= config.collectedAssets %>/fonts', 296 | importPath: '<%%= config.collectedAssets %>/bower_components', 297 | generatedImagesDir: '<%%= config.distAssets %>/images/generated' 298 | } 299 | }, 300 | server: { 301 | options: { 302 | sassDir: '<%%= config.assets %>/styles', 303 | imagesDir: '<%%= config.assets %>/images', 304 | javascriptsDir: '<%%= config.assets %>/scripts', 305 | fontsDir: '<%%= config.assets %>/fonts', 306 | importPath: '<%%= config.assets %>/bower_components', 307 | debugInfo: true 308 | } 309 | } 310 | },<% } %><% if (includeLess) { %> 311 | 312 | // Compile LESS files to CSS. 313 | less: { 314 | dist: { 315 | options: { 316 | strictMath: true, 317 | }, 318 | files: [{ 319 | // Dynamic expansion: 320 | // http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically 321 | expand: true, 322 | cwd: '<%%= config.collectedAssets %>/less', 323 | src: ['**/*.less'], 324 | dest: '.tmp/styles', 325 | ext: '.css' 326 | }] 327 | }, 328 | server: { 329 | options: { 330 | strictMath: true, 331 | }, 332 | files: [{ 333 | // Dynamic expansion: 334 | // http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically 335 | expand: true, 336 | cwd: '<%%= config.assets %>/less', 337 | src: ['**/*.less'], 338 | dest: '.tmp/styles', 339 | ext: '.css' 340 | }] 341 | } 342 | },<% } %> 343 | 344 | // Add vendor prefixed styles 345 | autoprefixer: { 346 | options: { 347 | browsers: ['> 1%', 'last 2 versions'] 348 | }, 349 | dist: { 350 | files: [{ 351 | expand: true, 352 | cwd: '.tmp', 353 | src: '{,*/}{styles,css}/**/*.css', 354 | dest: '.tmp' 355 | }] 356 | } 357 | }, 358 | 359 | // Automatically inject Bower components into the HTML file 360 | // bowerInstall: { 361 | // app: { 362 | // src: ['<%%= config.templates %>/index.html'], 363 | // ignorePath: '<%%= config.assets %>',<% if (includeCompass) { %> 364 | // exclude: ['<%%= config.assets %>/bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap.js']<% } else { %> 365 | // exclude: ['<%%= config.assets %>/bower_components/bootstrap/dist/js/bootstrap.js']<% } %> 366 | // }<% if (includeCompass) { %>, 367 | // sass: { 368 | // src: ['<%%= config.assets %>/styles/**/*.{scss,sass}'], 369 | // ignorePath: '<%%= config.assets %>/bower_components' 370 | // }<% } %> 371 | // }, 372 | 373 | // Renames files for browser caching purposes 374 | filerev: { 375 | files: { 376 | src: [ 377 | '<%%= config.distAssets %>/{,*/}{scripts,js}/**/*.js', 378 | '<%%= config.distAssets %>/{,*/}{styles,css}/**/*.css', 379 | '<%%= config.distAssets %>/{,*/}{images,img}/**/*.*', 380 | '<%%= config.distAssets %>/{,*/}{fonts,font}/**/*.*' 381 | ] 382 | } 383 | }, 384 | 385 | // Reads HTML for usemin blocks to enable smart builds that automatically 386 | // concat, minify and revision files. Creates configurations in memory so 387 | // additional tasks can operate on them 388 | useminPrepare: { 389 | options: { 390 | root: '<%%= config.collectedAssets %>', 391 | dest: '<%%= config.distAssets %>', 392 | useDjangoFlow: true 393 | }, 394 | html: '<%%= config.collectedTemplates %>/**/*.html' 395 | }, 396 | 397 | // Performs rewrites based on rev and the useminPrepare configuration 398 | usemin: { 399 | options: { 400 | useDjangoPatterns: true 401 | }, 402 | html: { 403 | src: ['<%%= config.distTemplates %>/**/*.html'], 404 | options: { 405 | assetsDirs: ['<%%= config.distAssets %>'] 406 | } 407 | }, 408 | css: { 409 | src: ['<%%= config.distAssets %>/{,*/}{styles,css}/**/*.css'], 410 | options: { 411 | assetsDirs: [ 412 | '', // Search from directory of current file first 413 | '<%%= config.distAssets %>' 414 | ] 415 | } 416 | } 417 | }, 418 | 419 | // The following *-min tasks produce minified files in the dist folder 420 | imagemin: { 421 | dist: { 422 | files: [{ 423 | expand: true, 424 | cwd: '<%%= config.collectedAssets %>', 425 | src: '{,*/}{images,img}/**/*.{gif,jpeg,jpg,png}', 426 | dest: '<%%= config.distAssets %>' 427 | }] 428 | } 429 | }, 430 | 431 | svgmin: { 432 | dist: { 433 | files: [{ 434 | expand: true, 435 | cwd: '<%%= config.collectedAssets %>', 436 | src: '{,*/}{images,img}/**/*.svg', 437 | dest: '<%%= config.distAssets %>' 438 | }] 439 | } 440 | }, 441 | 442 | // grunt-htmlcompressor is Java-based and Django-friendly. (grunt-contrib-htmlmin crashes 443 | // sometimes when minifying Django templates.) However, it runs HORRIBLY SLOW if 444 | // mis-configured. See performance hints below. 445 | htmlcompressor: { 446 | compress: { 447 | options: { 448 | // Options can be whatever htmlcompressor accepts. 449 | // https://code.google.com/p/htmlcompressor/ 450 | type: 'html', 451 | removeSurroundingSpaces: 'max', 452 | compressCss: true, 453 | compressJs: true, 454 | jsCompressor: 'closure', 455 | 456 | // *** 10x PERFORMANCE BOOST HERE *** 457 | 458 | // Hint: Put the output directory here. DO NOT USE "dest" of a file mapping. 459 | output: '<%%= config.distTemplates %>', 460 | 461 | // Hint: Compress files inside sub-directories of the input directory. 462 | recursive: true, 463 | 464 | // Hint: This is IMPORTANT. By default, grunt-htmlcompressor grabs the 465 | // minified content from stdout of the Java process and writes it to a file 466 | // specified by "dest" (which is `undefined` in this case). By specifying 467 | // "processName" option as the following function, it will be call at 468 | // runtime and generate a "black hole" for writing, so Grunt won't crash. 469 | // This function is consumed by grunt-htmlcompressor only. 470 | processName: function() { return '/dev/null'; } 471 | }, 472 | // Hint: Put your input directory here. DO NOT specify files using globbing 473 | // or dynamic patterns. Otherwise, grunt-htmlcompressor will spawn a Java process 474 | // for EACH FILE, which is INSANE. Also, "dest" is useless. You should instead 475 | // put the output directory in the "output" option above. If you need multiple 476 | // input directories, a multi-target configuration for this task is preferred. 477 | src: '<%%= config.distTemplates %>' 478 | } 479 | }, 480 | 481 | // By default, your `index.html`'s will take care of 482 | // minification. These next options are pre-configured if you do not wish 483 | // to use the Usemin blocks. 484 | // concat: { 485 | // dist: {} 486 | // }, 487 | 488 | // Only put CSS files here which are not referenced by 489 | // e.g. Those of Django Admin app (whose templates are certainly not Usemin-aware) 490 | cssmin: { 491 | dist: { 492 | files: [{ 493 | // CSS minification for admin app 494 | expand: true, 495 | cwd: '<%%= config.collectedAssets %>', 496 | src: 'admin/css/**/*.css', 497 | dest: '<%%= config.distAssets %>' 498 | }] 499 | } 500 | }, 501 | 502 | // Only put JavaScript files here which are not referenced by 503 | // e.g. Those of Django Admin app (whose templates are certainly not Usemin-aware) 504 | uglify: { 505 | dist: { 506 | files: [{ 507 | // JavaScript uglification for admin app 508 | expand: true, 509 | cwd: '<%%= config.collectedAssets %>', 510 | src: 'admin/js/**/*.js', 511 | dest: '<%%= config.distAssets %>' 512 | }] 513 | } 514 | }, 515 | 516 | // Copies remaining files to places other tasks can use 517 | copy: { 518 | dist: { 519 | files: [{ 520 | // Static assets 521 | expand: true, 522 | dot: true, 523 | cwd: '<%%= config.collectedAssets %>', 524 | src: [ 525 | '*.{ico,png,txt}', 526 | '.htaccess', 527 | '{,*/}{images,img}/**/*.webp', 528 | '{,*/}fonts/**/*.*' 529 | ], 530 | dest: '<%%= config.distAssets %>' 531 | }, { 532 | // Template files 533 | expand: true, 534 | dot: true, 535 | cwd: '<%%= config.collectedTemplates %>', 536 | src: '**/*.html', 537 | dest: '<%%= config.distTemplates %>' 538 | }<% if (includeBootstrap) { %>, { 539 | // Bootstrap 540 | expand: true, 541 | dot: true,<% if (includeCompass) { %> 542 | cwd: '.', 543 | src: '<%%= config.collectedAssets %>/bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/*.*',<% } else { %> 544 | cwd: '<%%= config.collectedAssets %>/bower_components/bootstrap/dist', 545 | src: 'fonts/*.*',<% } %> 546 | dest: '<%%= config.distAssets %>' 547 | }<% } %>] 548 | }, 549 | // Copy all CSS files for concat task 550 | diststyles: { 551 | expand: true, 552 | dot: true, 553 | cwd: '<%%= config.collectedAssets %>', 554 | src: '{,*/}{styles,css}/**/*.css', 555 | dest: '.tmp' 556 | }, 557 | styles: { 558 | expand: true, 559 | dot: true, 560 | cwd: '<%%= config.assets %>', 561 | src: '{,*/}{styles,css}/**/*.css', 562 | dest: '.tmp' 563 | }, 564 | // Simulate the collection process 565 | simcollected: { 566 | files: [{ 567 | // Static assets 568 | expand: true, 569 | dot: true, 570 | cwd: '<%%= config.assets %>', 571 | src: '**', 572 | dest: '<%%= config.collectedAssets %>' 573 | }, { 574 | // Templates 575 | expand: true, 576 | dot: true, 577 | cwd: '<%%= config.templates %>', 578 | src: '**', 579 | dest: '<%%= config.collectedTemplates %>' 580 | }] 581 | } 582 | },<% if (includeModernizr) { %> 583 | 584 | // Generates a custom Modernizr build that includes only the tests you 585 | // reference in your app 586 | modernizr: { 587 | devFile: '<%%= config.collectedAssets %>/bower_components/modernizr/modernizr.js', 588 | outputFile: '<%%= config.distAssets %>/scripts/vendor/modernizr.js', 589 | files: [ 590 | '<%%= config.distAssets %>/{,*/}{scripts,js}/**/*.js', 591 | '<%%= config.distAssets %>/{,*/}{styles,css}/**/*.css', 592 | '!<%%= config.distAssets %>/{,*/}{scripts,js}/vendor/*' 593 | ], 594 | uglify: true 595 | },<% } %> 596 | 597 | // Run some tasks in parallel to speed up build process 598 | concurrent: { 599 | server: [<% if (includeCompass) { %> 600 | 'compass:server',<% } %><% if (includeLess) { %> 601 | 'less:server',<% } %><% if (coffee) { %> 602 | 'coffee:server',<% } %> 603 | 'copy:styles' 604 | ], 605 | test: [<% if (coffee) { %> 606 | 'coffee:test',<% } %> 607 | 'copy:styles' 608 | ], 609 | dist: [<% if (coffee) { %> 610 | 'coffee:dist',<% } %><% if (includeCompass) { %> 611 | 'compass:dist',<% } %><% if (includeLess) { %> 612 | 'less:dist',<% } %> 613 | 'copy:diststyles', 614 | 'imagemin', 615 | 'svgmin' 616 | ] 617 | } 618 | }); 619 | 620 | 621 | grunt.registerTask('serve', function (target) { 622 | if (target === 'dist') { 623 | return grunt.task.run(['build', 'connect:dist:keepalive']); 624 | } 625 | 626 | grunt.task.run([ 627 | 'clean:server', 628 | 'concurrent:server', 629 | 'autoprefixer', 630 | 'connect:livereload', 631 | 'watch' 632 | ]); 633 | }); 634 | 635 | grunt.registerTask('server', function (target) { 636 | grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.'); 637 | grunt.task.run([target ? ('serve:' + target) : 'serve']); 638 | }); 639 | 640 | grunt.registerTask('test', function (target) { 641 | if (target !== 'watch') { 642 | grunt.task.run([ 643 | 'clean:server', 644 | 'concurrent:test', 645 | 'autoprefixer' 646 | ]); 647 | } 648 | 649 | grunt.task.run([ 650 | 'connect:test',<% if (testFramework === 'mocha') { %> 651 | 'mocha'<% } else if (testFramework === 'jasmine') { %> 652 | 'jasmine'<% } %> 653 | ]); 654 | }); 655 | 656 | grunt.registerTask('checkcollected', function () { 657 | var fs = require('fs'); 658 | var config = grunt.config.get('config'); 659 | if (!fs.existsSync(config.collectedAssets) || !fs.existsSync(config.collectedTemplates)) { 660 | /*jshint multistr:true */ 661 | grunt.fail.fatal(grunt.template.process('\ 662 | Collect assets and templates into the following directories first:\n\ 663 | * <%%= config.collectedAssets %>\n\ 664 | * <%%= config.collectedTemplates %>\n\n\ 665 | Hints: You might need to run `../manage.py collectstatic` to collect \ 666 | static assets, and some custom Fabric tasks to collect templates. \n\n\ 667 | If you want to try out the `build` task, run `grunt copy:simcollected` \ 668 | to simulate the collection process, then try again.')); 669 | } 670 | }); 671 | 672 | grunt.registerTask('build', [ 673 | 'checkcollected', 674 | 'clean:dist', 675 | 'useminPrepare',<% if (includeRequireJS) { %> 676 | 'requirejs', 677 | 'clean:requirejs',<% } %> 678 | 'concurrent:dist', 679 | 'autoprefixer', 680 | 'concat', 681 | 'cssmin', 682 | 'uglify', 683 | 'copy:dist',<% if (includeModernizr) { %> 684 | 'modernizr',<% } %> 685 | 'filerev',<% if (includeRequireJS) { %> 686 | 'requirejspaths', 687 | 'processhtml',<% } %> 688 | 'usemin', 689 | 'htmlcompressor', 690 | 'clean:collected' 691 | ]); 692 | 693 | grunt.registerTask('default', [ 694 | 'newer:jshint', 695 | 'test', 696 | 'build' 697 | ]); 698 | }; 699 | -------------------------------------------------------------------------------- /app/templates/README.txt: -------------------------------------------------------------------------------- 1 | About directory structure: 2 | 3 | <%= projectName %> 4 | |= fabfile <-- Fabric runtime files 5 | |= requirements <-- Python virtualenv requirements 6 | | 7 | |= references 8 | | |= conf <-- Server related configuration files 9 | | \= docs <-- Docs about the project 10 | | 11 | |= etc <-- Mostly front-end files. 12 | | |= test <-- Javascript unit tests. 13 | | |= static <-- Project-wise static files. Contains styles, scripts, images, fonts sub-directories 14 | | |= templates <-- Project-wise Django templates 15 | | \= uploads <-- User-uploaded content (`MEDIA_ROOT`). Keep it out of Git 16 | | 17 | \= <%= projectName %> 18 | |= spec <-- Environment-specific Django settings and WSGI applications 19 | |= my <-- Custom project information. See below for details 20 | |= common <-- A special app which injects project-wise functionalities. See below for details 21 | |= apps <-- Apps created by you (Run `django-admin.py startapp ` here) 22 | \= utils <-- Utilities modules written by you 23 | 24 | 25 | 26 | Details of some directories: 27 | 28 | <%= projectName %>/<%= projectName %>/my/ 29 | 30 | This directory holds project information which should be kept out of a cooperative repo, e.g. the production SECRET_KEY, or local development settings file. However, you can version-control this directory by committing it into an independent private repo. 31 | 32 | These files are for soft-linking in other places. Also, keep the symbolic links out of Git. 33 | 34 | 35 | <%= projectName %>/<%= projectName %>/common/ 36 | 37 | This directory holds a special Django app which injects project-wise functionalities written by you. 38 | 39 | Common usage: 40 | 41 | * Management commands 42 | * Template tags 43 | * Templates for overriding other apps (such as the `admin` app) 44 | * Static contents for overriding other apps (such as the `admin` app) 45 | * Contributed translations (via a python file which contains strings to be translated, e.g. trans.py) 46 | * Project wise unit tests 47 | 48 | Put this app in the first element of INSTALLED_APPS so that it takes priority for processing, like this: 49 | 50 | INSTALLED_APPS = ( 51 | '<%= projectName %>.common', # <-- Put it here to override `admin` app's template and static files 52 | 'django.contrib.admin', 53 | 'django.contrib.auth', 54 | ... 55 | ) 56 | -------------------------------------------------------------------------------- /app/templates/_bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appname) %>", 3 | "private": true, 4 | "dependencies": {<% if (includeBootstrap) { if (includeCompass) { %> 5 | "bootstrap-sass-official": "~3.1.1",<% } else { %> 6 | "bootstrap": "~3.1.1",<% }} %><% if (includeModernizr) { %> 7 | "modernizr": "~2.6.2",<% } %><% if (includeRequireJS) {%> 8 | "requirejs": "~2.1.11",<% } %> 9 | "jquery": "~1.11.0" 10 | }, 11 | "devDependencies": {} 12 | } 13 | -------------------------------------------------------------------------------- /app/templates/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appname) %>", 3 | "version": "0.0.0", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "grunt": "~0.4.1", 7 | "grunt-contrib-copy": "~0.4.1", 8 | "grunt-contrib-concat": "~0.3.0",<% if (coffee) { %> 9 | "grunt-contrib-coffee": "~0.7.0",<% } %> 10 | "grunt-contrib-uglify": "~0.2.0",<% if (includeCompass) { %> 11 | "grunt-contrib-compass": "~0.7.0",<% } else if (includeBootstrap) { %> 12 | "grunt-contrib-less": "~0.10.0",<% } %> 13 | "grunt-contrib-jshint": "~0.7.0", 14 | "grunt-contrib-cssmin": "~0.7.0", 15 | "grunt-contrib-connect": "~0.5.0", 16 | "grunt-contrib-clean": "~0.5.0", 17 | "grunt-htmlcompressor": "~0.1.10", 18 | "grunt-bower-install": "~1.0.0", 19 | "grunt-contrib-imagemin": "~0.4.1", 20 | "grunt-contrib-watch": "~0.5.2",<% if (testFramework === 'jasmine') { %> 21 | "grunt-contrib-jasmine": "~0.4.2",<% } %> 22 | "grunt-filerev": "~0.2.1", 23 | "grunt-autoprefixer": "~0.5.0", 24 | "grunt-usemin": "git://github.com/rockallite/grunt-usemin.git#develop",<% if (testFramework === 'mocha') { %> 25 | "grunt-mocha": "~0.4.0",<% } %><% if (includeModernizr) { %> 26 | "grunt-modernizr": "~0.4.0",<% } %><% if (includeRequireJS) { %> 27 | "grunt-contrib-requirejs": "~0.4.3", 28 | "grunt-requirejspaths": "~0.1.0", 29 | "grunt-processhtml": "~0.3.0",<% } %> 30 | "grunt-newer": "~0.6.0", 31 | "grunt-svgmin": "~0.2.0", 32 | "grunt-concurrent": "~0.4.0", 33 | "load-grunt-tasks": "~0.2.0", 34 | "time-grunt": "~0.2.0", 35 | "jshint-stylish": "~0.1.3" 36 | }, 37 | "engines": { 38 | "node": ">=0.8.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/templates/bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "static/bower_components" 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 = space 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/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockallite/generator-django-webapp/b02bf18e17c50068305614ff15ab8b2d33e083c7/app/templates/favicon.ico -------------------------------------------------------------------------------- /app/templates/gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /app/templates/gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Rr]elease/ 47 | *_i.c 48 | *_p.c 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.vspscc 63 | .builds 64 | *.dotCover 65 | 66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 67 | #packages/ 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper* 82 | 83 | # Installshield output folder 84 | [Ee]xpress 85 | 86 | # DocProject is a documentation generator add-in 87 | DocProject/buildhelp/ 88 | DocProject/Help/*.HxT 89 | DocProject/Help/*.HxC 90 | DocProject/Help/*.hhc 91 | DocProject/Help/*.hhk 92 | DocProject/Help/*.hhp 93 | DocProject/Help/Html2 94 | DocProject/Help/html 95 | 96 | # Click-Once directory 97 | publish 98 | 99 | # Others 100 | [Bb]in 101 | [Oo]bj 102 | #sql 103 | TestResults 104 | *.Cache 105 | ClientBin 106 | stylecop.* 107 | ~$* 108 | *.dbmdl 109 | Generated_Code #added for RIA/Silverlight projects 110 | 111 | # Backup & report files from converting an old project file to a newer 112 | # Visual Studio version. Backup files are not needed, because we have git ;-) 113 | _UpgradeReport_Files/ 114 | Backup*/ 115 | UpgradeLog*.XML 116 | 117 | 118 | 119 | ############ 120 | ## Windows 121 | ############ 122 | 123 | # Windows image file caches 124 | Thumbs.db 125 | 126 | # Folder config file 127 | Desktop.ini 128 | 129 | 130 | ############# 131 | ## Python 132 | ############# 133 | 134 | *.py[co] 135 | 136 | # Packages 137 | *.egg 138 | *.egg-info 139 | dist 140 | build 141 | eggs 142 | parts 143 | bin 144 | var 145 | sdist 146 | develop-eggs 147 | .installed.cfg 148 | 149 | # Installer logs 150 | pip-log.txt 151 | 152 | # Unit test / coverage reports 153 | .coverage 154 | .tox 155 | 156 | #Translations 157 | *.mo 158 | 159 | #Mr Developer 160 | .mr.developer.cfg 161 | 162 | # Mac crap 163 | .DS_Store 164 | 165 | # PyCharm settings files 166 | .idea 167 | 168 | ################# 169 | ## This project only 170 | ################# 171 | .tmp/ 172 | .sass-cache/ 173 | dist/ 174 | node_modules/ 175 | bower_components/ 176 | /requirements/local.txt 177 | /etc/static_collected/ 178 | /etc/templates_collected/ 179 | /etc/uploads/ 180 | /<%= projectName %>/my/ 181 | /<%= projectName %>/spec/*/secret.py 182 | /<%= projectName %>/spec/local/ 183 | -------------------------------------------------------------------------------- /app/templates/htaccess: -------------------------------------------------------------------------------- 1 | # Apache Server Configs v2.2.0 | MIT License 2 | # https://github.com/h5bp/server-configs-apache 3 | 4 | # (!) Using `.htaccess` files slows down Apache, therefore, if you have access 5 | # to the main server config file (usually called `httpd.conf`), you should add 6 | # this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html. 7 | 8 | # ############################################################################## 9 | # # CROSS-ORIGIN RESOURCE SHARING (CORS) # 10 | # ############################################################################## 11 | 12 | # ------------------------------------------------------------------------------ 13 | # | Cross-domain AJAX requests | 14 | # ------------------------------------------------------------------------------ 15 | 16 | # Allow cross-origin AJAX requests. 17 | # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity 18 | # http://enable-cors.org/ 19 | 20 | # 21 | # Header set Access-Control-Allow-Origin "*" 22 | # 23 | 24 | # ------------------------------------------------------------------------------ 25 | # | CORS-enabled images | 26 | # ------------------------------------------------------------------------------ 27 | 28 | # Send the CORS header for images when browsers request it. 29 | # https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image 30 | # http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html 31 | # http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ 32 | 33 | 34 | 35 | 36 | SetEnvIf Origin ":" IS_CORS 37 | Header set Access-Control-Allow-Origin "*" env=IS_CORS 38 | 39 | 40 | 41 | 42 | # ------------------------------------------------------------------------------ 43 | # | Web fonts access | 44 | # ------------------------------------------------------------------------------ 45 | 46 | # Allow access to web fonts from all domains. 47 | 48 | 49 | 50 | Header set Access-Control-Allow-Origin "*" 51 | 52 | 53 | 54 | 55 | # ############################################################################## 56 | # # ERRORS # 57 | # ############################################################################## 58 | 59 | # ------------------------------------------------------------------------------ 60 | # | 404 error prevention for non-existing redirected folders | 61 | # ------------------------------------------------------------------------------ 62 | 63 | # Prevent Apache from returning a 404 error as the result of a rewrite 64 | # when the directory with the same name does not exist. 65 | # http://httpd.apache.org/docs/current/content-negotiation.html#multiviews 66 | # http://www.webmasterworld.com/apache/3808792.htm 67 | 68 | Options -MultiViews 69 | 70 | # ------------------------------------------------------------------------------ 71 | # | Custom error messages / pages | 72 | # ------------------------------------------------------------------------------ 73 | 74 | # Customize what Apache returns to the client in case of an error. 75 | # http://httpd.apache.org/docs/current/mod/core.html#errordocument 76 | 77 | ErrorDocument 404 /404.html 78 | 79 | 80 | # ############################################################################## 81 | # # INTERNET EXPLORER # 82 | # ############################################################################## 83 | 84 | # ------------------------------------------------------------------------------ 85 | # | Better website experience | 86 | # ------------------------------------------------------------------------------ 87 | 88 | # Force Internet Explorer to render pages in the highest available mode 89 | # in the various cases when it may not. 90 | # http://hsivonen.iki.fi/doctype/ie-mode.pdf 91 | 92 | 93 | Header set X-UA-Compatible "IE=edge" 94 | # `mod_headers` cannot match based on the content-type, however, this 95 | # header should be send only for HTML pages and not for the other resources 96 | 97 | Header unset X-UA-Compatible 98 | 99 | 100 | 101 | # ------------------------------------------------------------------------------ 102 | # | Cookie setting from iframes | 103 | # ------------------------------------------------------------------------------ 104 | 105 | # Allow cookies to be set from iframes in Internet Explorer. 106 | # http://msdn.microsoft.com/en-us/library/ms537343.aspx 107 | # http://www.w3.org/TR/2000/CR-P3P-20001215/ 108 | 109 | # 110 | # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" 111 | # 112 | 113 | 114 | # ############################################################################## 115 | # # MIME TYPES AND ENCODING # 116 | # ############################################################################## 117 | 118 | # ------------------------------------------------------------------------------ 119 | # | Proper MIME types for all files | 120 | # ------------------------------------------------------------------------------ 121 | 122 | 123 | 124 | # Audio 125 | AddType audio/mp4 m4a f4a f4b 126 | AddType audio/ogg oga ogg opus 127 | 128 | # Data interchange 129 | AddType application/json json map 130 | AddType application/ld+json jsonld 131 | 132 | # JavaScript 133 | # Normalize to standard type. 134 | # http://tools.ietf.org/html/rfc4329#section-7.2 135 | AddType application/javascript js 136 | 137 | # Video 138 | AddType video/mp4 f4v f4p m4v mp4 139 | AddType video/ogg ogv 140 | AddType video/webm webm 141 | AddType video/x-flv flv 142 | 143 | # Web fonts 144 | AddType application/font-woff woff 145 | AddType application/vnd.ms-fontobject eot 146 | 147 | # Browsers usually ignore the font MIME types and simply sniff the bytes 148 | # to figure out the font type. 149 | # http://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern 150 | 151 | # Chrome however, shows a warning if any other MIME types are used for 152 | # the following fonts. 153 | 154 | AddType application/x-font-ttf ttc ttf 155 | AddType font/opentype otf 156 | 157 | # Make SVGZ fonts work on the iPad. 158 | # https://twitter.com/FontSquirrel/status/14855840545 159 | AddType image/svg+xml svgz 160 | AddEncoding gzip svgz 161 | 162 | # Other 163 | AddType application/octet-stream safariextz 164 | AddType application/x-chrome-extension crx 165 | AddType application/x-opera-extension oex 166 | AddType application/x-web-app-manifest+json webapp 167 | AddType application/x-xpinstall xpi 168 | AddType application/xml atom rdf rss xml 169 | AddType image/webp webp 170 | AddType image/x-icon cur 171 | AddType text/cache-manifest appcache manifest 172 | AddType text/vtt vtt 173 | AddType text/x-component htc 174 | AddType text/x-vcard vcf 175 | 176 | 177 | 178 | # ------------------------------------------------------------------------------ 179 | # | UTF-8 encoding | 180 | # ------------------------------------------------------------------------------ 181 | 182 | # Use UTF-8 encoding for anything served as `text/html` or `text/plain`. 183 | AddDefaultCharset utf-8 184 | 185 | # Force UTF-8 for certain file formats. 186 | 187 | AddCharset utf-8 .atom .css .js .json .jsonld .rss .vtt .webapp .xml 188 | 189 | 190 | 191 | # ############################################################################## 192 | # # URL REWRITES # 193 | # ############################################################################## 194 | 195 | # ------------------------------------------------------------------------------ 196 | # | Rewrite engine | 197 | # ------------------------------------------------------------------------------ 198 | 199 | # Turn on the rewrite engine and enable the `FollowSymLinks` option (this is 200 | # necessary in order for the following directives to work). 201 | 202 | # If your web host doesn't allow the `FollowSymlinks` option, you may need to 203 | # comment it out and use `Options +SymLinksIfOwnerMatch`, but be aware of the 204 | # performance impact. 205 | # http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks 206 | 207 | # Also, some cloud hosting services require `RewriteBase` to be set. 208 | # http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site 209 | 210 | 211 | Options +FollowSymlinks 212 | # Options +SymLinksIfOwnerMatch 213 | RewriteEngine On 214 | # RewriteBase / 215 | 216 | 217 | # ------------------------------------------------------------------------------ 218 | # | Suppressing / Forcing the `www.` at the beginning of URLs | 219 | # ------------------------------------------------------------------------------ 220 | 221 | # The same content should never be available under two different URLs, 222 | # especially not with and without `www.` at the beginning. This can cause 223 | # SEO problems (duplicate content), and therefore, you should choose one 224 | # of the alternatives and redirect the other one. 225 | 226 | # By default `Option 1` (no `www.`) is activated. 227 | # http://no-www.org/faq.php?q=class_b 228 | 229 | # If you would prefer to use `Option 2`, just comment out all the lines 230 | # from `Option 1` and uncomment the ones from `Option 2`. 231 | 232 | # IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! 233 | 234 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 235 | 236 | # Option 1: rewrite www.example.com → example.com 237 | 238 | 239 | RewriteCond %{HTTPS} !=on 240 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 241 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] 242 | 243 | 244 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 245 | 246 | # Option 2: rewrite example.com → www.example.com 247 | 248 | # Be aware that the following might not be a good idea if you use "real" 249 | # subdomains for certain parts of your website. 250 | 251 | # 252 | # RewriteCond %{HTTPS} !=on 253 | # RewriteCond %{HTTP_HOST} !^www\. [NC] 254 | # RewriteCond %{SERVER_ADDR} !=127.0.0.1 255 | # RewriteCond %{SERVER_ADDR} !=::1 256 | # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] 257 | # 258 | 259 | 260 | # ############################################################################## 261 | # # SECURITY # 262 | # ############################################################################## 263 | 264 | # ------------------------------------------------------------------------------ 265 | # | Clickjacking | 266 | # ------------------------------------------------------------------------------ 267 | 268 | # Protect website against clickjacking. 269 | 270 | # The example below sends the `X-Frame-Options` response header with the value 271 | # `DENY`, informing browsers not to display the web page content in any frame. 272 | 273 | # This might not be the best setting for everyone. You should read about the 274 | # other two possible values for `X-Frame-Options`: `SAMEORIGIN` & `ALLOW-FROM`. 275 | # http://tools.ietf.org/html/rfc7034#section-2.1 276 | 277 | # Keep in mind that while you could send the `X-Frame-Options` header for all 278 | # of your site’s pages, this has the potential downside that it forbids even 279 | # non-malicious framing of your content (e.g.: when users visit your site using 280 | # a Google Image Search results page). 281 | 282 | # Nonetheless, you should ensure that you send the `X-Frame-Options` header for 283 | # all pages that allow a user to make a state changing operation (e.g: pages 284 | # that contain one-click purchase links, checkout or bank-transfer confirmation 285 | # pages, pages that make permanent configuration changes, etc.). 286 | 287 | # Sending the `X-Frame-Options` header can also protect your website against 288 | # more than just clickjacking attacks: https://cure53.de/xfo-clickjacking.pdf. 289 | 290 | # http://tools.ietf.org/html/rfc7034 291 | # http://blogs.msdn.com/b/ieinternals/archive/2010/03/30/combating-clickjacking-with-x-frame-options.aspx 292 | # https://www.owasp.org/index.php/Clickjacking 293 | 294 | # 295 | # Header set X-Frame-Options "DENY" 296 | # 297 | # Header unset X-Frame-Options 298 | # 299 | # 300 | 301 | # ------------------------------------------------------------------------------ 302 | # | Content Security Policy (CSP) | 303 | # ------------------------------------------------------------------------------ 304 | 305 | # Mitigate the risk of cross-site scripting and other content-injection attacks. 306 | 307 | # This can be done by setting a `Content Security Policy` which whitelists 308 | # trusted sources of content for your website. 309 | 310 | # The example header below allows ONLY scripts that are loaded from the current 311 | # site's origin (no inline scripts, no CDN, etc). This almost certainly won't 312 | # work as-is for your site! 313 | 314 | # For more details on how to craft a reasonable policy for your site, read: 315 | # http://html5rocks.com/en/tutorials/security/content-security-policy (or the 316 | # specification: http://w3.org/TR/CSP). Also, to make things easier, you can 317 | # use an online CSP header generator such as: http://cspisawesome.com/. 318 | 319 | # 320 | # Header set Content-Security-Policy "script-src 'self'; object-src 'self'" 321 | # 322 | # Header unset Content-Security-Policy 323 | # 324 | # 325 | 326 | # ------------------------------------------------------------------------------ 327 | # | File access | 328 | # ------------------------------------------------------------------------------ 329 | 330 | # Block access to directories without a default document. 331 | # You should leave the following uncommented, as you shouldn't allow anyone to 332 | # surf through every directory on your server (which may includes rather private 333 | # places such as the CMS's directories). 334 | 335 | 336 | Options -Indexes 337 | 338 | 339 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 340 | 341 | # Block access to hidden files and directories. 342 | # This includes directories used by version control systems such as Git and SVN. 343 | 344 | 345 | RewriteCond %{SCRIPT_FILENAME} -d [OR] 346 | RewriteCond %{SCRIPT_FILENAME} -f 347 | RewriteRule "(^|/)\." - [F] 348 | 349 | 350 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 351 | 352 | # Block access to files that can expose sensitive information. 353 | 354 | # By default, block access to backup and source files that may be left by some 355 | # text editors and can pose a security risk when anyone has access to them. 356 | # http://feross.org/cmsploit/ 357 | 358 | # IMPORTANT: Update the `` regular expression from below to include 359 | # any files that might end up on your production server and can expose sensitive 360 | # information about your website. These files may include: configuration files, 361 | # files that contain metadata about the project (e.g.: project dependencies), 362 | # build scripts, etc.. 363 | 364 | 365 | 366 | # Apache < 2.3 367 | 368 | Order allow,deny 369 | Deny from all 370 | Satisfy All 371 | 372 | 373 | # Apache ≥ 2.3 374 | 375 | Require all denied 376 | 377 | 378 | 379 | 380 | # ------------------------------------------------------------------------------ 381 | # | Reducing MIME-type security risks | 382 | # ------------------------------------------------------------------------------ 383 | 384 | # Prevent some browsers from MIME-sniffing the response. 385 | 386 | # This reduces exposure to drive-by download attacks and should be enable 387 | # especially if the web server is serving user uploaded content, content 388 | # that could potentially be treated by the browser as executable. 389 | 390 | # http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx 391 | # http://msdn.microsoft.com/en-us/library/ie/gg622941.aspx 392 | # http://mimesniff.spec.whatwg.org/ 393 | 394 | # 395 | # Header set X-Content-Type-Options "nosniff" 396 | # 397 | 398 | # ------------------------------------------------------------------------------ 399 | # | Reflected Cross-Site Scripting (XSS) attacks | 400 | # ------------------------------------------------------------------------------ 401 | 402 | # (1) Try to re-enable the Cross-Site Scripting (XSS) filter built into the 403 | # most recent web browsers. 404 | # 405 | # The filter is usually enabled by default, but in some cases it may be 406 | # disabled by the user. However, in Internet Explorer for example, it can 407 | # be re-enabled just by sending the `X-XSS-Protection` header with the 408 | # value of `1`. 409 | # 410 | # (2) Prevent web browsers from rendering the web page if a potential reflected 411 | # (a.k.a non-persistent) XSS attack is detected by the filter. 412 | # 413 | # By default, if the filter is enabled and browsers detect a reflected 414 | # XSS attack, they will attempt to block the attack by making the smallest 415 | # possible modifications to the returned web page. 416 | # 417 | # Unfortunately, in some browsers (e.g.: Internet Explorer), this default 418 | # behavior may allow the XSS filter to be exploited, thereby, it's better 419 | # to tell browsers to prevent the rendering of the page altogether, instead 420 | # of attempting to modify it. 421 | # 422 | # http://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities 423 | # 424 | # IMPORTANT: Do not rely on the XSS filter to prevent XSS attacks! Ensure that 425 | # you are taking all possible measures to prevent XSS attacks, the most obvious 426 | # being: validating and sanitizing your site's inputs. 427 | # 428 | # http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx 429 | # http://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx 430 | # https://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29 431 | 432 | # 433 | # # (1) (2) 434 | # Header set X-XSS-Protection "1; mode=block" 435 | # 436 | # Header unset X-XSS-Protection 437 | # 438 | # 439 | 440 | # ------------------------------------------------------------------------------ 441 | # | Secure Sockets Layer (SSL) | 442 | # ------------------------------------------------------------------------------ 443 | 444 | # Rewrite secure requests properly in order to prevent SSL certificate warnings. 445 | # E.g.: prevent `https://www.example.com` when your certificate only allows 446 | # `https://secure.example.com`. 447 | 448 | # 449 | # RewriteCond %{SERVER_PORT} !^443 450 | # RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] 451 | # 452 | 453 | # ------------------------------------------------------------------------------ 454 | # | HTTP Strict Transport Security (HSTS) | 455 | # ------------------------------------------------------------------------------ 456 | 457 | # Force client-side SSL redirection. 458 | 459 | # If a user types `example.com` in his browser, the above rule will redirect 460 | # him to the secure version of the site. That still leaves a window of 461 | # opportunity (the initial HTTP connection) for an attacker to downgrade or 462 | # redirect the request. 463 | 464 | # The following header ensures that browser will ONLY connect to your server 465 | # via HTTPS, regardless of what the users type in the address bar. 466 | 467 | # http://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-14#section-6.1 468 | # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ 469 | 470 | # IMPORTANT: Remove the `includeSubDomains` optional directive if the subdomains 471 | # are not using HTTPS. 472 | 473 | # 474 | # Header set Strict-Transport-Security "max-age=16070400; includeSubDomains" 475 | # 476 | 477 | # ------------------------------------------------------------------------------ 478 | # | Server software information | 479 | # ------------------------------------------------------------------------------ 480 | 481 | # Avoid displaying the exact Apache version number, the description of the 482 | # generic OS-type and the information about Apache's compiled-in modules. 483 | 484 | # ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! 485 | 486 | # ServerTokens Prod 487 | 488 | 489 | # ############################################################################## 490 | # # WEB PERFORMANCE # 491 | # ############################################################################## 492 | 493 | # ------------------------------------------------------------------------------ 494 | # | Compression | 495 | # ------------------------------------------------------------------------------ 496 | 497 | 498 | 499 | # Force compression for mangled headers. 500 | # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping 501 | 502 | 503 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding 504 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding 505 | 506 | 507 | 508 | # Compress all output labeled with one of the following MIME-types 509 | # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` 510 | # and can remove the `` and `` lines 511 | # as `AddOutputFilterByType` is still in the core directives). 512 | 513 | AddOutputFilterByType DEFLATE application/atom+xml \ 514 | application/javascript \ 515 | application/json \ 516 | application/ld+json \ 517 | application/rss+xml \ 518 | application/vnd.ms-fontobject \ 519 | application/x-font-ttf \ 520 | application/x-web-app-manifest+json \ 521 | application/xhtml+xml \ 522 | application/xml \ 523 | font/opentype \ 524 | image/svg+xml \ 525 | image/x-icon \ 526 | text/css \ 527 | text/html \ 528 | text/plain \ 529 | text/x-component \ 530 | text/xml 531 | 532 | 533 | 534 | 535 | # ------------------------------------------------------------------------------ 536 | # | Content transformations | 537 | # ------------------------------------------------------------------------------ 538 | 539 | # Prevent mobile network providers from modifying the website's content. 540 | # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. 541 | 542 | # 543 | # Header set Cache-Control "no-transform" 544 | # 545 | 546 | # ------------------------------------------------------------------------------ 547 | # | ETags | 548 | # ------------------------------------------------------------------------------ 549 | 550 | # Remove `ETags` as resources are sent with far-future expires headers. 551 | # http://developer.yahoo.com/performance/rules.html#etags. 552 | 553 | # `FileETag None` doesn't work in all cases. 554 | 555 | Header unset ETag 556 | 557 | 558 | FileETag None 559 | 560 | # ------------------------------------------------------------------------------ 561 | # | Expires headers | 562 | # ------------------------------------------------------------------------------ 563 | 564 | # The following expires headers are set pretty far in the future. If you 565 | # don't control versioning with filename-based cache busting, consider 566 | # lowering the cache time for resources such as style sheets and JavaScript 567 | # files to something like one week. 568 | 569 | 570 | 571 | ExpiresActive on 572 | ExpiresDefault "access plus 1 month" 573 | 574 | # CSS 575 | ExpiresByType text/css "access plus 1 year" 576 | 577 | # Data interchange 578 | ExpiresByType application/json "access plus 0 seconds" 579 | ExpiresByType application/ld+json "access plus 0 seconds" 580 | ExpiresByType application/xml "access plus 0 seconds" 581 | ExpiresByType text/xml "access plus 0 seconds" 582 | 583 | # Favicon (cannot be renamed!) and cursor images 584 | ExpiresByType image/x-icon "access plus 1 week" 585 | 586 | # HTML components (HTCs) 587 | ExpiresByType text/x-component "access plus 1 month" 588 | 589 | # HTML 590 | ExpiresByType text/html "access plus 0 seconds" 591 | 592 | # JavaScript 593 | ExpiresByType application/javascript "access plus 1 year" 594 | 595 | # Manifest files 596 | ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" 597 | ExpiresByType text/cache-manifest "access plus 0 seconds" 598 | 599 | # Media 600 | ExpiresByType audio/ogg "access plus 1 month" 601 | ExpiresByType image/gif "access plus 1 month" 602 | ExpiresByType image/jpeg "access plus 1 month" 603 | ExpiresByType image/png "access plus 1 month" 604 | ExpiresByType video/mp4 "access plus 1 month" 605 | ExpiresByType video/ogg "access plus 1 month" 606 | ExpiresByType video/webm "access plus 1 month" 607 | 608 | # Web feeds 609 | ExpiresByType application/atom+xml "access plus 1 hour" 610 | ExpiresByType application/rss+xml "access plus 1 hour" 611 | 612 | # Web fonts 613 | ExpiresByType application/font-woff "access plus 1 month" 614 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month" 615 | ExpiresByType application/x-font-ttf "access plus 1 month" 616 | ExpiresByType font/opentype "access plus 1 month" 617 | ExpiresByType image/svg+xml "access plus 1 month" 618 | 619 | 620 | 621 | # ------------------------------------------------------------------------------ 622 | # | Filename-based cache busting | 623 | # ------------------------------------------------------------------------------ 624 | 625 | # If you're not using a build process to manage your filename version revving, 626 | # you might want to consider enabling the following directives to route all 627 | # requests such as `/css/style.12345.css` to `/css/style.css`. 628 | 629 | # To understand why this is important and a better idea than `*.css?v231`, read: 630 | # http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring 631 | 632 | # 633 | # RewriteCond %{REQUEST_FILENAME} !-f 634 | # RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L] 635 | # 636 | 637 | # ------------------------------------------------------------------------------ 638 | # | File concatenation | 639 | # ------------------------------------------------------------------------------ 640 | 641 | # Allow concatenation from within specific style sheets and JavaScript files. 642 | 643 | # e.g.: 644 | # 645 | # If you have the following content in a file 646 | # 647 | # 648 | # 649 | # 650 | # Apache will replace it with the content from the specified files. 651 | 652 | # 653 | # 654 | # Options +Includes 655 | # AddOutputFilterByType INCLUDES application/javascript application/json 656 | # SetOutputFilter INCLUDES 657 | # 658 | # 659 | # Options +Includes 660 | # AddOutputFilterByType INCLUDES text/css 661 | # SetOutputFilter INCLUDES 662 | # 663 | # 664 | -------------------------------------------------------------------------------- /app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= appname %> 9 | 10 | 11 | 12 | 13 | 14 | <% if (includeBootstrap && !includeCompass) { %> 15 | <% } %> 16 | 17 | 18 | 19 | <% if (includeModernizr) { %> 20 | 21 | 22 | 23 | <% } %> 24 | 25 | 26 | 29 | 30 | <% if (includeBootstrap) { %> 31 |
32 |
33 | 38 |

<%= appname %>

39 |
40 | 41 |
42 |

'Allo, 'Allo!

43 |

Always a pleasure scaffolding your apps.

44 |

Splendid!

45 |
46 | 47 |
48 |
49 |

HTML5 Boilerplate

50 |

HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or sites.

51 | 52 | <% if (includeCompass) { %>

Sass with Compass

53 |

Compass is an open-source CSS Authoring Framework that uses Sass.

54 | <% } %> 55 | 56 |

Bootstrap

57 |

Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.

58 | 59 | <% if (includeModernizr) { %>

Modernizr

60 |

Modernizr is an open-source JavaScript library that helps you build the next generation of HTML5 and CSS3-powered websites.

61 | <% } %> 62 |
63 |
64 | 65 | 68 | 69 |
70 | <% } else { %> 71 |
72 |

'Allo, 'Allo!

73 |

You now have

74 |
    75 |
  • HTML5 Boilerplate
  • 76 | <% if (includeCompass) { %>
  • Sass with Compass
  • <% } %> 77 | <% if (includeModernizr) { %>
  • Modernizr
  • <% } %> 78 |
79 |
80 | <% } %> 81 | 82 | <% if (includeRequireJS) { %> 83 | 84 | 85 | 86 | 87 | 88 | 101 | 102 | 103 | 104 | 105 | 106 | 110 | <% } else { %> 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | <% } %> 119 | 120 | 121 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /app/templates/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= appname %> index2 9 | 10 | 11 | 12 | 13 | 14 | <% if (includeBootstrap && !includeCompass) { %> 15 | <% } %> 16 | 17 | 18 | 19 | <% if (includeModernizr) { %> 20 | 21 | 22 | 23 | <% } %> 24 | 25 | 26 | 29 | 30 | <% if (includeBootstrap) { %> 31 |
32 |
33 | 38 |

<%= appname %>

39 |
40 | 41 |
42 |

'Allo, 'Allo!

43 |

Always a pleasure scaffolding your apps.

44 |

Splendid!

45 |
46 | 47 |
48 |
49 |

HTML5 Boilerplate

50 |

HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or sites.

51 | 52 | <% if (includeCompass) { %>

Sass with Compass

53 |

Compass is an open-source CSS Authoring Framework that uses Sass.

54 | <% } %> 55 | 56 |

Bootstrap

57 |

Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.

58 | 59 | <% if (includeModernizr) { %>

Modernizr

60 |

Modernizr is an open-source JavaScript library that helps you build the next generation of HTML5 and CSS3-powered websites.

61 | <% } %> 62 |
63 |
64 | 65 | 68 | 69 |
70 | <% } else { %> 71 |
72 |

'Allo, 'Allo!

73 |

You now have

74 |
    75 |
  • HTML5 Boilerplate
  • 76 | <% if (includeCompass) { %>
  • Sass with Compass
  • <% } %> 77 | <% if (includeModernizr) { %>
  • Modernizr
  • <% } %> 78 |
79 |
80 | <% } %> 81 | 82 | <% if (includeRequireJS) { %> 83 | 84 | 85 | 86 | 87 | 88 | 101 | 102 | 103 | 104 | 105 | 106 | 110 | <% } else { %> 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | <% } %> 119 | 120 | 121 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /app/templates/infra.js: -------------------------------------------------------------------------------- 1 | /* globals define */ 2 | 'use strict'; 3 | 4 | define(['bootstrap'], function () {}); -------------------------------------------------------------------------------- /app/templates/jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "jquery": true<% if (includeRequireJS) { %>, 21 | "predef": [ 22 | "require", 23 | "define" 24 | ]<% } %> 25 | } 26 | -------------------------------------------------------------------------------- /app/templates/main.css: -------------------------------------------------------------------------------- 1 | <% if (includeBootstrap) { %>.browsehappy { 2 | margin: 0.2em 0; 3 | background: #ccc; 4 | color: #000; 5 | padding: 0.2em 0; 6 | } 7 | 8 | /* Space out content a bit */ 9 | body { 10 | padding-top: 20px; 11 | padding-bottom: 20px; 12 | } 13 | 14 | /* Everything but the jumbotron gets side spacing for mobile first views */ 15 | .header, 16 | .marketing, 17 | .footer { 18 | padding-left: 15px; 19 | padding-right: 15px; 20 | } 21 | 22 | /* Custom page header */ 23 | .header { 24 | border-bottom: 1px solid #e5e5e5; 25 | } 26 | 27 | /* Make the masthead heading the same height as the navigation */ 28 | .header h3 { 29 | margin-top: 0; 30 | margin-bottom: 0; 31 | line-height: 40px; 32 | padding-bottom: 19px; 33 | } 34 | 35 | /* Custom page footer */ 36 | .footer { 37 | padding-top: 19px; 38 | color: #777; 39 | border-top: 1px solid #e5e5e5; 40 | } 41 | 42 | .container-narrow > hr { 43 | margin: 30px 0; 44 | } 45 | 46 | /* Main marketing message and sign up button */ 47 | .jumbotron { 48 | text-align: center; 49 | border-bottom: 1px solid #e5e5e5; 50 | } 51 | 52 | .jumbotron .btn { 53 | font-size: 21px; 54 | padding: 14px 24px; 55 | } 56 | 57 | /* Supporting marketing content */ 58 | .marketing { 59 | margin: 40px 0; 60 | } 61 | 62 | .marketing p + h4 { 63 | margin-top: 28px; 64 | } 65 | 66 | /* Responsive: Portrait tablets and up */ 67 | @media screen and (min-width: 768px) { 68 | .container { 69 | max-width: 730px; 70 | } 71 | 72 | /* Remove the padding we set earlier */ 73 | .header, 74 | .marketing, 75 | .footer { 76 | padding-left: 0; 77 | padding-right: 0; 78 | } 79 | 80 | /* Space out the masthead */ 81 | .header { 82 | margin-bottom: 30px; 83 | } 84 | 85 | /* Remove the bottom border on the jumbotron for visual effect */ 86 | .jumbotron { 87 | border-bottom: 0; 88 | } 89 | }<% } else { %>body { 90 | background: #fafafa; 91 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 92 | color: #333; 93 | } 94 | 95 | .hero-unit { 96 | margin: 50px auto 0 auto; 97 | width: 300px; 98 | font-size: 18px; 99 | font-weight: 200; 100 | line-height: 30px; 101 | background-color: #eee; 102 | border-radius: 6px; 103 | padding: 60px; 104 | } 105 | 106 | .hero-unit h1 { 107 | font-size: 60px; 108 | line-height: 1; 109 | letter-spacing: -1px; 110 | } 111 | 112 | .browsehappy { 113 | margin: 0.2em 0; 114 | background: #ccc; 115 | color: #000; 116 | padding: 0.2em 0; 117 | }<% } %> 118 | -------------------------------------------------------------------------------- /app/templates/main.js: -------------------------------------------------------------------------------- 1 | /* globals define */ 2 | 'use strict'; 3 | 4 | define(['require', 'infra'], function (require) { 5 | var $ = require('jquery'); 6 | $(function () { 7 | console.log('\'Allo \'Allo!'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /app/templates/main.scss: -------------------------------------------------------------------------------- 1 | <% if (includeBootstrap) { %>$icon-font-path: "/bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/"; 2 | 3 | // bower:scss 4 | @import 'bootstrap-sass-official/vendor/assets/stylesheets/bootstrap.scss'; 5 | // endbower 6 | 7 | .browsehappy { 8 | margin: 0.2em 0; 9 | background: #ccc; 10 | color: #000; 11 | padding: 0.2em 0; 12 | } 13 | 14 | /* Space out content a bit */ 15 | body { 16 | padding-top: 20px; 17 | padding-bottom: 20px; 18 | } 19 | 20 | /* Everything but the jumbotron gets side spacing for mobile first views */ 21 | .header, 22 | .marketing, 23 | .footer { 24 | padding-left: 15px; 25 | padding-right: 15px; 26 | } 27 | 28 | /* Custom page header */ 29 | .header { 30 | border-bottom: 1px solid #e5e5e5; 31 | 32 | /* Make the masthead heading the same height as the navigation */ 33 | h3 { 34 | margin-top: 0; 35 | margin-bottom: 0; 36 | line-height: 40px; 37 | padding-bottom: 19px; 38 | } 39 | } 40 | 41 | /* Custom page footer */ 42 | .footer { 43 | padding-top: 19px; 44 | color: #777; 45 | border-top: 1px solid #e5e5e5; 46 | } 47 | 48 | .container-narrow > hr { 49 | margin: 30px 0; 50 | } 51 | 52 | /* Main marketing message and sign up button */ 53 | .jumbotron { 54 | text-align: center; 55 | border-bottom: 1px solid #e5e5e5; 56 | .btn { 57 | font-size: 21px; 58 | padding: 14px 24px; 59 | } 60 | } 61 | 62 | /* Supporting marketing content */ 63 | .marketing { 64 | margin: 40px 0; 65 | p + h4 { 66 | margin-top: 28px; 67 | } 68 | } 69 | 70 | /* Responsive: Portrait tablets and up */ 71 | @media screen and (min-width: 768px) { 72 | .container { 73 | max-width: 730px; 74 | } 75 | 76 | /* Remove the padding we set earlier */ 77 | .header, 78 | .marketing, 79 | .footer { 80 | padding-left: 0; 81 | padding-right: 0; 82 | } 83 | 84 | /* Space out the masthead */ 85 | .header { 86 | margin-bottom: 30px; 87 | } 88 | 89 | /* Remove the bottom border on the jumbotron for visual effect */ 90 | .jumbotron { 91 | border-bottom: 0; 92 | } 93 | }<% } else { %>// bower:scss 94 | // endbower 95 | 96 | body { 97 | background: #fafafa; 98 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 99 | color: #333; 100 | } 101 | 102 | .hero-unit { 103 | margin: 50px auto 0 auto; 104 | width: 300px; 105 | font-size: 18px; 106 | font-weight: 200; 107 | line-height: 30px; 108 | background-color: #eee; 109 | border-radius: 6px; 110 | padding: 60px; 111 | h1 { 112 | font-size: 60px; 113 | line-height: 1; 114 | letter-spacing: -1px; 115 | } 116 | } 117 | 118 | .browsehappy { 119 | margin: 0.2em 0; 120 | background: #ccc; 121 | color: #000; 122 | padding: 0.2em 0; 123 | }<% } %> 124 | -------------------------------------------------------------------------------- /app/templates/main2.js: -------------------------------------------------------------------------------- 1 | /* globals define */ 2 | 'use strict'; 3 | 4 | define(['require', 'infra'], function (require) { 5 | var $ = require('jquery'); 6 | $(function () { 7 | console.log('\'Allo \'Allo! From main2'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /app/templates/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | See the [contributing docs](https://github.com/yeoman/yeoman/blob/master/contributing.md) 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-django-webapp", 3 | "version": "0.4.8-0.1.1", 4 | "description": "Scaffold out a Django web app with front-end support", 5 | "license": "BSD", 6 | "repository": "rockallite/generator-django-webapp", 7 | "author": "Rockallite Wulf", 8 | "main": "app/index.js", 9 | "engines": { 10 | "node": ">=0.10.0", 11 | "npm": ">=1.2.10" 12 | }, 13 | "scripts": { 14 | "test": "mocha --reporter spec" 15 | }, 16 | "files": [ 17 | "app" 18 | ], 19 | "keywords": [ 20 | "yeoman-generator", 21 | "django", 22 | "web", 23 | "app", 24 | "front-end", 25 | "h5bp", 26 | "modernizr", 27 | "jquery", 28 | "requirejs", 29 | "grunt" 30 | ], 31 | "dependencies": { 32 | "yeoman-generator": "~0.16.0", 33 | "cheerio": "~0.13.0", 34 | "chalk": "~0.4.0", 35 | "lodash": "~2.4.1" 36 | }, 37 | "peerDependencies": { 38 | "yo": ">=1.0.0", 39 | "generator-mocha": ">=0.1.0" 40 | }, 41 | "devDependencies": { 42 | "mocha": "*" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Django web app generator [![Build Status](https://secure.travis-ci.org/rockallite/generator-django-webapp.png?branch=master)](http://travis-ci.org/rockallite/generator-django-webapp) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/) 2 | 3 | [Yeoman](http://yeoman.io) generator that scaffolds out a Django web app with front-end support. Derived from [generator-webapp](https://github.com/yeoman/generator-webapp/). 4 | 5 | ## Features 6 | 7 | * CSS Autoprefixing *(new)* 8 | * Built-in preview server with LiveReload 9 | * Automagically compile CoffeeScript & Compass 10 | * Automagically lint your scripts 11 | * Automagically wire up your Bower components with [bower-install](#third-party-dependencies). 12 | * Awesome Image Optimization (via OptiPNG, pngquant, jpegtran and gifsicle) 13 | * Mocha Unit Testing with PhantomJS 14 | * Optional - Bootstrap for Sass 15 | * Optional - Leaner Modernizr builds *(new)* 16 | * Auto-generated config paths of all RequireJS modules *(new)* 17 | * Automagically handle `{{ STATIC_URL }}` and `{% static %}` template tags *(new)* 18 | * Optimze HTML files and Django templates, including inline Javascript and CSS (using grunt-htmlcompressor) *(new)* 19 | 20 | `generator-django-webapp` depends on a heavily-patched version of `grunt-usemin`. For more information on what `generator-django-webapp` can do for you, take a look at the [Grunt tasks](https://github.com/rockallite/generator-django-webapp/blob/master/app/templates/Gruntfile.js). 21 | 22 | 23 | ## Getting Started 24 | 25 | - Install: `npm install -g generator-django-webapp` 26 | - Start a Django project: `django-admin.py startproject your_project_name` 27 | - Set working directory to project base: `cd your_project_name` 28 | - Run: `yo django-webapp` 29 | - Set working directory for Grunt task: `cd etc` 30 | - Run `grunt` for building static assets 31 | - If everything is OK, the built assets are in `etc/dist` directory 32 | 33 | 34 | #### Third-Party Dependencies 35 | 36 | *(HTML/CSS/JS/Images/etc)* 37 | 38 | Third-party dependencies are managed with [bower-install](https://github.com/stephenplusplus/grunt-bower-install). Add new dependencies using **Bower** and then run the **Grunt** task to load them: 39 | 40 | ```bash 41 | bower install --save jquery 42 | grunt bowerInstall 43 | ``` 44 | 45 | This works if the package author has followed the [Bower spec](https://github.com/bower/bower.json-spec). If the files are not automatically added to your index.html, check with the package's repo for support and/or file an issue with them to have it updated. 46 | 47 | To manually add dependencies, `bower install depName --save` to get the files, then add a `script` or `style` tag to your `index.html` or an other appropriate place. 48 | 49 | The components are installed in the root of the project at `/bower_components`. To reference them from the `grunt serve` web app `index.html` file, use `src="bower_components"` or `src="/bower_components"`. Treat the references as if they were a sibling to `index.html`. 50 | 51 | *Testing Note*: a project checked into source control and later checked out, needs to have `bower install` run from the `test` folder as well as from project root. 52 | 53 | 54 | #### Grunt Serve Note 55 | 56 | Note: `grunt server` was previously used for previewing in earlier versions of the project and is being deprecated in favor of `grunt serve`. 57 | 58 | 59 | ## Options 60 | 61 | * `--skip-install` 62 | 63 | Skips the automatic execution of `bower` and `npm` after scaffolding has finished. 64 | 65 | * `--test-framework=` 66 | 67 | Defaults to `mocha`. Can be switched for another supported testing framework like `jasmine`. 68 | 69 | * `--coffee` 70 | 71 | Add support for [CoffeeScript](http://coffeescript.org/). 72 | 73 | 74 | ## Contribute 75 | 76 | Main development happens in Yeoman's `generator-webapp`. See the [contributing docs](https://github.com/yeoman/yeoman/blob/master/contributing.md) 77 | 78 | `generator-django-webapp` is fork-friendly (and is also a fork of `generator-webapp`) and you can always maintain a custom version which you `npm install && npm link` to continue using via `yo django-webapp` or a name of your choosing. 79 | 80 | 81 | ## License 82 | 83 | [BSD license](http://opensource.org/licenses/bsd-license.php) 84 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 3 | var path = require('path'); 4 | var helpers = require('yeoman-generator').test; 5 | 6 | describe('Django webapp generator test', function () { 7 | // TODO: Put real tests here 8 | 9 | // beforeEach(function (done) { 10 | // helpers.testDirectory(path.join(__dirname, 'temp'), function (err) { 11 | // if (err) { 12 | // return done(err); 13 | // } 14 | 15 | // this.webapp = helpers.createGenerator('django-webapp:app', [ 16 | // '../../app', [ 17 | // helpers.createDummyGenerator(), 18 | // 'mocha:app' 19 | // ] 20 | // ]); 21 | // this.webapp.options['skip-install'] = true; 22 | 23 | // done(); 24 | // }.bind(this)); 25 | // }); 26 | 27 | // it('the generator can be required without throwing', function () { 28 | // // not testing the actual run of generators yet 29 | // this.app = require('../app'); 30 | // }); 31 | 32 | // it('creates expected files', function (done) { 33 | // var expected = [ 34 | // ['bower.json', /"name": "temp"/], 35 | // ['package.json', /"name": "temp"/], 36 | // ['Gruntfile.js', /coffee:/], 37 | // 'app/404.html', 38 | // 'app/favicon.ico', 39 | // 'app/robots.txt', 40 | // 'app/index.html', 41 | // 'app/scripts/main.coffee', 42 | // 'app/styles/main.scss' 43 | // ]; 44 | 45 | // helpers.mockPrompt(this.webapp, { 46 | // features: ['includeCompass'] 47 | // }); 48 | 49 | // this.webapp.coffee = true; 50 | // this.webapp.run({}, function () { 51 | // helpers.assertFiles(expected); 52 | // done(); 53 | // }); 54 | // }); 55 | 56 | // it('creates expected files in non-AMD non-coffee mode', function (done) { 57 | // var expected = [ 58 | // ['bower.json', /"name": "temp"/], 59 | // ['package.json', /"name": "temp"/], 60 | // 'Gruntfile.js', 61 | // 'app/404.html', 62 | // 'app/favicon.ico', 63 | // 'app/robots.txt', 64 | // 'app/index.html', 65 | // 'app/scripts/main.js', 66 | // 'app/styles/main.scss' 67 | // ]; 68 | 69 | // helpers.mockPrompt(this.webapp, { 70 | // features: ['includeCompass'] 71 | // }); 72 | 73 | // this.webapp.coffee = false; 74 | // this.webapp.run({}, function () { 75 | // helpers.assertFiles(expected); 76 | // done(); 77 | // }); 78 | // }); 79 | 80 | // it('creates expected files in AMD mode', function (done) { 81 | // var expected = [ 82 | // ['bower.json', /"name": "temp"/], 83 | // ['package.json', /"name": "temp"/], 84 | // 'Gruntfile.js', 85 | // 'app/404.html', 86 | // 'app/favicon.ico', 87 | // 'app/robots.txt', 88 | // 'app/index.html', 89 | // 'app/scripts/main.js', 90 | // 'app/styles/main.scss' 91 | // ]; 92 | 93 | // helpers.mockPrompt(this.webapp, { 94 | // features: ['includeCompass'] 95 | // }); 96 | 97 | // this.webapp.run({}, function () { 98 | // helpers.assertFiles(expected); 99 | // done(); 100 | // }); 101 | // }); 102 | }); 103 | --------------------------------------------------------------------------------