Comparing version 1.1.7-8 to 1.1.7-9
@@ -40,2 +40,5 @@ #!/usr/bin/env node | ||
if (cmd === command || (c && c.help && c.help.shortcut === command)) { | ||
if (cmd !== 'server' && cmd !== 's') { | ||
compound.app.enable('tools'); | ||
} | ||
exitAfterAction = c(compound, args); | ||
@@ -42,0 +45,0 @@ found = true; |
@@ -185,3 +185,3 @@ var fs = require('fs'), | ||
fs.readdirSync(dir).forEach(function(file) { | ||
if (file.match(/^(environment|routes|autoload)\.(js|coffee|json|yml|yaml)$/)) { | ||
if (file.match(/^(Roco|environment|routes|autoload)\.(js|coffee|json|yml|yaml)$/)) { | ||
return; | ||
@@ -188,0 +188,0 @@ } |
@@ -264,2 +264,4 @@ var fs = require('fs'); | ||
compound.emit('controller instance', ctl); | ||
if (compound.app.disabled('quiet') || compound.app.get('quiet') === 'all') { | ||
@@ -329,4 +331,5 @@ var $ = compound.utils.stylize.$; | ||
}); | ||
logger.on('render', function(file, layout) { | ||
log('Rendering ' + $(file).grey + ' using layout ' + $(layout).grey); | ||
logger.on('render', function(file, layout, duration) { | ||
log('Rendered ' + $(file).grey + ' using layout ' + $(layout).grey + | ||
' in ' + duration + 'ms'); | ||
}); | ||
@@ -333,0 +336,0 @@ } |
@@ -39,2 +39,3 @@ var fs = require('fs'), | ||
Controller.prototype.render = function render(view, params, callback) { | ||
var start = Date.now(); | ||
var self = this; | ||
@@ -68,6 +69,2 @@ var compound = self.compound; | ||
if (this.logger) { | ||
this.logger.emit('render', file, layout); | ||
} | ||
layout = layout ? 'layouts/' + layout : false; | ||
@@ -90,2 +87,6 @@ | ||
self.renderView(layout); | ||
if (self.logger) { | ||
self.logger.emit('render', file, layout, Date.now() - start); | ||
} | ||
}); | ||
@@ -92,0 +93,0 @@ |
@@ -9,2 +9,3 @@ /** | ||
utils = require('./utils'), | ||
FormForResource = require('./form-for-resource.js'), | ||
_url = require('url'); | ||
@@ -395,258 +396,8 @@ | ||
*/ | ||
HelperSet.prototype.fieldsFor = function (resource, formParams, block) { | ||
resource = resource || {}; | ||
var self = this; | ||
var resourceName = resource && resource.constructor && resource.constructor.modelName || false; | ||
var complexNames = (this.controller.app.set('view options') || {}).complexNames; | ||
if (typeof complexNames === 'undefined') { | ||
complexNames = true; | ||
} | ||
HelperSet.prototype.fieldsFor = function (resource, formParams) { | ||
return new FormForResource(resource || {}, formParams, null, this); | ||
}; | ||
/** | ||
* Generates a name | ||
* | ||
* @requires resourceName | ||
* @param {String} name Name of the element | ||
* @returns {String} returns the generated name | ||
*/ | ||
function makeName(name) { | ||
return complexNames && resourceName ? (resourceName + name.replace(/^([^\[]+)/, '[$1]')) : name; | ||
} | ||
/** | ||
* Generates an id field | ||
* | ||
* @requires resourceName | ||
* @param {String} name Name of the element | ||
* @returns {String} returns the generated id name | ||
*/ | ||
function makeId(name) { | ||
return complexNames && resourceName ? (resourceName + '_' + name.replace(/[\[\]]/g, '_').replace(/_$/, '')) : name; | ||
} | ||
var blockHelper = { | ||
/** | ||
* Opening form tag | ||
* | ||
* For formFor() calls without passing a block | ||
*/ | ||
begin: function () { | ||
return HelperSet.prototype.formTagBegin.call(self, formParams); | ||
}, | ||
/** | ||
* Closing form tag | ||
* | ||
* For formFor() calls without passing a block | ||
*/ | ||
end: function () { | ||
return HelperSet.prototype.formTagEnd(); | ||
}, | ||
/** | ||
* Input tag helper | ||
* | ||
* Example in ejs: | ||
* | ||
* <%- form.input("test") %> | ||
* | ||
* This returns: | ||
* | ||
* <input name="test"/> | ||
* | ||
* @param {String} name Name of the element | ||
* @param {Object} params Additional parameters | ||
*/ | ||
input: function (name, params) { | ||
params = params || {}; | ||
if (params.type === undef) { | ||
params.type = 'text'; | ||
} | ||
if (params.value === undef && params.type.toLowerCase() !== 'password') { | ||
params.value = typeof resource[name] !== 'undefined' ? resource[name] : ''; | ||
} | ||
return HelperSet.prototype.inputTag({ | ||
name: makeName(name), | ||
id: makeId(name) | ||
}, params); | ||
}, | ||
checkbox: function (name, params) { | ||
params = params || {}; | ||
if (params.value === undef) { | ||
params.value = resource[name] || 1; | ||
} | ||
if (params.checked === undef) { | ||
if(resource[name]) { | ||
params.checked = 'checked'; | ||
} | ||
} else if (params.checked === false) { | ||
delete params.checked; | ||
} | ||
return HelperSet.prototype.inputTag({ | ||
name: makeName(name), | ||
id: makeId(name), | ||
type: 'checkbox' | ||
}, params); | ||
}, | ||
file: function (name, params) { | ||
return HelperSet.prototype.inputTag({ | ||
name: makeName(name), | ||
id: makeId(name), | ||
type: 'file' | ||
}, params); | ||
}, | ||
/* | ||
* Label helper | ||
* | ||
* Example in ejs: | ||
* | ||
* <%- form.label("test", false, {class: "control-label"}) %> | ||
* | ||
* This returns: | ||
* | ||
* <label for="test" class="control-label">Test</label> | ||
* | ||
* @param {String} name Name of the element | ||
* @param {String} caption Optional different caption of the elemt | ||
* @param {Object} params Additional parameters | ||
*/ | ||
label: function (name, caption, params) { | ||
if (typeof caption !== 'string') { | ||
if (!params) { | ||
params = caption; | ||
} | ||
var description = ''; | ||
var model = resource.constructor.modelName; | ||
var ctl = self.controller; | ||
var shortPath = 'models.' + model + '.fields.' + name; | ||
var long = ctl.t(shortPath + '.label', ''); | ||
if (long) { | ||
caption = long; | ||
} else { | ||
caption = ctl.t(shortPath, humanize(name)); | ||
} | ||
description = ctl.t(shortPath + '.description', description); | ||
if (description) { | ||
caption += self.icon('info-sign', { | ||
rel: 'popover', | ||
title: 'Help', | ||
'data-content': description | ||
}); | ||
} | ||
} | ||
return HelperSet.prototype.labelTag( | ||
caption, | ||
{for: makeId(name) }, | ||
params); | ||
}, | ||
submit: function (name, params) { | ||
return self.tag('button', name || 'Commit', {type: 'submit'}, params); | ||
}, | ||
button: function (name, params) { | ||
return self.tag('button', name, params); | ||
}, | ||
textarea: function (name, params) { | ||
var value = params && 'value' in params ? params.value : resource[name] || ''; | ||
return HelperSet.prototype.textareaTag(sanitizeHTML(value), {name: makeName(name), id: makeId(name)}, params); | ||
}, | ||
/* | ||
* Provides a select tag | ||
* | ||
* In ejs: | ||
* | ||
* <%- form.select("state", states, {fieldname: 'name', fieldvalue: '_id'}) %> | ||
* | ||
* Possible params: | ||
* * blank: {STRING} Blank value to be added at the beginning of the list | ||
* * fieldname: {STRING} Sets the name of the field in "options" field where the displayed values can be found. Default: "value" | ||
* * fieldvalue: {STRING} Sets the name of the field in "options" field where the submitted values can be found. Default = fieldname | ||
* * multiple: Can be set to false if size >1 to only select one value. | ||
* * select: Select a value. If fieldname and fieldvalue are different, the value is compared with fieldvalue otherwise with fieldname. | ||
* * size: Sets the displayed size of the select field | ||
* | ||
* @author [Uli Wolf](https://github.com/SirUli) | ||
* @param {String} name Name of the select tag | ||
* @param {Object} options Array of possible options | ||
* @param {Object} params Additional parameters | ||
*/ | ||
select: function (name, options, params) { | ||
options = options || []; | ||
params = params || {}; | ||
// optional: Holds the displayed fieldname where the data can be found in 'options' | ||
var optionFieldname = params.fieldname || 'value'; | ||
delete params.fieldname; | ||
// optional: Holds the submittable fieldvalue where the data can be found in 'options' | ||
var optionFieldvalue = params.fieldvalue || optionFieldname; | ||
delete params.fieldvalue; | ||
// optional: Holds the number of entries that can be seen at once | ||
// If size > 1, multiple values can be selected (can be switched off via multiple:false) | ||
// If size = 1, only one value is selectable (Drop-Down) | ||
if (params.size === undef) { | ||
params.size = 1; | ||
} else { | ||
if (params.size > 1) { | ||
if (params.multiple === undef || params.multiple === true) { | ||
params.multiple = 'multiple'; | ||
} else { | ||
delete params.multiple; | ||
} | ||
} | ||
} | ||
// optional: Preselect an entry | ||
if (params.select === undef) { | ||
params.select = resource[name] || ''; | ||
} | ||
var optionSelected = params.select; | ||
delete params.select; | ||
// Render the options | ||
var innerOptions = ''; | ||
// optional: Add a blank field at the beginning | ||
if (params.blank !== undef) { | ||
innerOptions += HelperSet.prototype.optionTag(sanitizeHTML(params.blank), {value: ''}) | ||
} | ||
for (var optionsNr in options) { | ||
var option = options[optionsNr]; | ||
var optionParameters = {}; | ||
// Is the value in a seperate field? | ||
if (option[optionFieldvalue] != option[optionFieldname]) { | ||
optionParameters.value = option[optionFieldvalue]; | ||
} | ||
var actualValue, displayValue; | ||
if (typeof option === 'object') { | ||
actualValue = optionFieldname in option ? option[optionFieldvalue] : option; | ||
displayValue = optionFieldname in option ? option[optionFieldname] : option; | ||
} else { | ||
displayValue = actualValue = option + ''; | ||
} | ||
if (activeValue(actualValue, optionSelected, options.matcher)) { | ||
optionParameters.selected = 'selected'; | ||
} | ||
// Generate the option Tags | ||
innerOptions += HelperSet.prototype.optionTag(sanitizeHTML(displayValue), optionParameters) | ||
} | ||
// Render the select | ||
return HelperSet.prototype.selectTag(innerOptions, {name: makeName(name), id: makeId(name)}, params); | ||
} | ||
}; | ||
if (block) { | ||
block(blockHelper); | ||
} else { | ||
return blockHelper; | ||
} | ||
}; | ||
/** | ||
@@ -653,0 +404,0 @@ * Form for resource helper |
@@ -26,2 +26,3 @@ var Compound = require('../compound'); | ||
req.locals = req.locals || {}; | ||
app.compound.emit('request', req, res); | ||
next(); | ||
@@ -28,0 +29,0 @@ }); |
@@ -45,3 +45,3 @@ /** | ||
AppGenerator.prototype.perform = function (args) { | ||
BaseGenerator.prototype.perform.apply(this, arguments); | ||
BaseGenerator.prototype.perform.apply(this, [].slice.call(arguments)); | ||
@@ -68,3 +68,2 @@ if (this.options.appName) { | ||
'app/controllers/', | ||
'app/observers/', | ||
'app/helpers/', | ||
@@ -108,3 +107,4 @@ 'app/views/', | ||
'SUFFIX': this.isEvalAllowed() ? '_controller' : '', | ||
'EVAL': this.isEvalAllowed() ? '_eval' : '' | ||
'EVAL': this.isEvalAllowed() ? '_eval' : '', | ||
'DBDEPENDENCY': this.getDatabaseDependency() | ||
}; | ||
@@ -111,0 +111,0 @@ |
@@ -202,3 +202,3 @@ /** | ||
if (this.options.appName) { | ||
displayFileName = path.join(this.options.appName, displayFileName); | ||
displayFileName = path.join(this.options.appName, displayFileName); | ||
} | ||
@@ -213,3 +213,3 @@ | ||
if(!this.hasBinaryExtension(fileName)) { | ||
contents = this.replaceVariables(contents.toString(), variables); | ||
contents = this.replaceVariables(contents.toString(), variables); | ||
} | ||
@@ -280,3 +280,3 @@ | ||
for(key in variables) { | ||
for (key in variables) { | ||
value = variables[key]; | ||
@@ -422,2 +422,11 @@ | ||
GeneratorUtilities.prototype.getDatabaseDependency = function() { | ||
var driver = this.getDatabaseDriver(); | ||
if (driver === 'memory') { | ||
return ''; | ||
} else { | ||
return ', "jugglingdb-' + driver + '": ">= 0"'; | ||
} | ||
}; | ||
GeneratorUtilities.prototype.isEvalAllowed = function () { | ||
@@ -424,0 +433,0 @@ return !('noeval' in this.options); |
@@ -128,5 +128,11 @@ var path = require('path'), | ||
ctx.app = compound.app; | ||
ctx.compound = compound; | ||
for (var model in compound.models) { | ||
ctx[model] = compound.models[model]; | ||
} | ||
if (args[0]) { | ||
eval('with(ctx) { ' + args[0] + ' }'); | ||
} | ||
}; | ||
@@ -142,3 +148,3 @@ | ||
ctx['_' + i] = arguments[i]; | ||
message += '_' + i + ' = ' + arguments[i] + '\n'; | ||
message += 'var _' + i + ' = ' + arguments[i] + '\n'; | ||
} else { | ||
@@ -145,0 +151,0 @@ if (ctx.hasOwnProperty('_' + i)) { |
@@ -1,2 +0,2 @@ | ||
var undef, sys = require('util'), | ||
var undef, util = require('util'), | ||
path = require('path'), | ||
@@ -178,1 +178,10 @@ fs = require('fs'), | ||
exports.ensureDirectoryExists = ensureDirectoryExists; | ||
exports.inherits = function(constructor, superConstructor, includeClassMethods) { | ||
util.inherits(constructor, superConstructor); | ||
if (includeClassMethods) { | ||
Object.keys(superConstructor).forEach(function(key) { | ||
constructor[key] = superConstructor[key]; | ||
}); | ||
} | ||
}; |
{ | ||
"name": "compound", | ||
"version": "1.1.7-8", | ||
"version": "1.1.7-9", | ||
"author": "Anatoliy Chakkaev", | ||
@@ -5,0 +5,0 @@ "contributors": [ |
492
README.md
@@ -17,7 +17,11 @@ About [<img src="https://secure.travis-ci.org/1602/compound.png" />](http://travis-ci.org/#!/1602/compound) | ||
$ sudo npm install compound -g | ||
```sh | ||
sudo npm install compound -g | ||
``` | ||
Option 2: GitHub | ||
$ sudo npm install 1602/compound | ||
```sh | ||
sudo npm install 1602/compound | ||
``` | ||
@@ -27,14 +31,16 @@ Usage | ||
# initialize app | ||
$ compound init blog && cd blog | ||
$ npm install | ||
```sh | ||
# initialize app | ||
compound init blog && cd blog | ||
npm install | ||
# generate scaffold | ||
$ compound generate crud post title content published:boolean | ||
# generate scaffold | ||
compound generate crud post title content published:boolean | ||
# run server on port 3000 | ||
$ compound s 3000 | ||
# run server on port 3000 | ||
compound s 3000 | ||
# visit app | ||
$ open http://localhost:3000/posts | ||
# visit app | ||
open http://localhost:3000/posts | ||
``` | ||
@@ -47,33 +53,47 @@ Short functionality review | ||
Usage: compound command [argument(s)] | ||
``` | ||
$ compound help | ||
Usage: compound command [argument(s)] | ||
Commands: | ||
h, help Display usage information | ||
i, init Initialize compound app | ||
g, generate [smth] Generate something awesome | ||
r, routes [filter] Display application routes | ||
c, console Debug console | ||
s, server [port] Run compound server | ||
install [module] Installs a compound module and patches the autoload file | ||
Commands: | ||
h, help Display usage information | ||
i, init Initialize compound app | ||
g, generate [smth] Generate something awesome | ||
r, routes [filter] Display application routes | ||
c, console Debug console | ||
s, server [port] Run compound server | ||
install [module] Installs a compound module and patches the autoload file | ||
``` | ||
#### compound init <strong>[appname][ key(s)]</strong> | ||
keys: | ||
--coffee # Default: no coffee by default | ||
--tpl jade|ejs # Default: ejs | ||
--css sass|less|stylus # Default: stylus | ||
--db redis|mongodb|nano|mysql|sqlite3|postgres | ||
# Default: memory | ||
#### compound init [appname][ option(s)] | ||
#### compound generate smth - smth = generator name (controller, model, scaffold, ...can be extended via plugins) | ||
``` | ||
options: | ||
--coffee # Default: no coffee by default | ||
--tpl jade|ejs # Default: ejs | ||
--css sass|less|stylus # Default: stylus | ||
--db redis|mongodb|nano|mysql|sqlite3|postgres | ||
# Default: memory | ||
``` | ||
#### compound generate smth | ||
smth = generator name (controller, model, scaffold, ...can be extended via plugins) | ||
more information about generators available here: | ||
http://compoundjs.github.com/generators | ||
#### compound server 8000 or **PORT=8000 node server** - run server on port `8000` | ||
#### compound server 8000 | ||
#### compound console - run debugging console (see details below) | ||
equals to `PORT=8000 node server` - run server on port `8000` | ||
#### compound routes - print routes map (see details below) | ||
#### compound console | ||
run debugging console (see details below) | ||
#### compound routes | ||
print routes map (see details below) | ||
Directory structure | ||
@@ -84,42 +104,44 @@ ------------------- | ||
. | ||
|-- app | ||
| |-- assets | ||
| | |-- coffeescripts | ||
| | | `-- application.coffee | ||
| | `-- stylesheets | ||
| | `-- application.styl | ||
| |-- controllers | ||
| | |-- admin | ||
| | | |-- categories_controller.js | ||
| | | |-- posts_controller.js | ||
| | | `-- tags_controller.js | ||
| | |-- comments_controller.js | ||
| | `-- posts_controller.js | ||
| |-- models | ||
| | |-- category.js | ||
| | |-- post.js | ||
| | `-- tag.js | ||
| |-- views | ||
| | |-- admin | ||
| | | `-- posts | ||
| | | |-- edit.ejs | ||
| | | |-- index.ejs | ||
| | | |-- new.ejs | ||
| | |-- layouts | ||
| | | `-- application_layout.ejs | ||
| | |-- partials | ||
| | `-- posts | ||
| | |-- index.ejs | ||
| | `-- show.ejs | ||
| `-- helpers | ||
| |-- admin | ||
| | |-- posts_helper.js | ||
| | `-- tags_helper.js | ||
| `-- posts_helper.js | ||
`-- config | ||
|-- database.json | ||
|-- routes.js | ||
|-- tls.cert | ||
`-- tls.key | ||
``` | ||
. | ||
|-- app | ||
| |-- assets | ||
| | |-- coffeescripts | ||
| | | `-- application.coffee | ||
| | `-- stylesheets | ||
| | `-- application.styl | ||
| |-- controllers | ||
| | |-- admin | ||
| | | |-- categories_controller.js | ||
| | | |-- posts_controller.js | ||
| | | `-- tags_controller.js | ||
| | |-- comments_controller.js | ||
| | `-- posts_controller.js | ||
| |-- models | ||
| | |-- category.js | ||
| | |-- post.js | ||
| | `-- tag.js | ||
| |-- views | ||
| | |-- admin | ||
| | | `-- posts | ||
| | | |-- edit.ejs | ||
| | | |-- index.ejs | ||
| | | |-- new.ejs | ||
| | |-- layouts | ||
| | | `-- application_layout.ejs | ||
| | |-- partials | ||
| | `-- posts | ||
| | |-- index.ejs | ||
| | `-- show.ejs | ||
| `-- helpers | ||
| |-- admin | ||
| | |-- posts_helper.js | ||
| | `-- tags_helper.js | ||
| `-- posts_helper.js | ||
`-- config | ||
|-- database.json | ||
|-- routes.js | ||
|-- tls.cert | ||
`-- tls.key | ||
``` | ||
@@ -133,13 +155,17 @@ HTTPS Support | ||
require('compound').createServer({ | ||
key: fs.readFileSync('/tmp/tls.key').toString(), | ||
cert: fs.readFileSync('/tmp/tls.key').toString() | ||
}); | ||
```js | ||
require('compound').createServer({ | ||
key: fs.readFileSync('/tmp/tls.key').toString(), | ||
cert: fs.readFileSync('/tmp/tls.cert').toString() | ||
}); | ||
``` | ||
Few helpful commands: | ||
# generate private key | ||
openssl genrsa -out /tmp/tls.key | ||
# generate cert | ||
openssl req -new -x509 -key /tmp/tls.key -out /tmp/tls.cert -days 1095 -batch | ||
```sh | ||
# generate private key | ||
openssl genrsa -out /tmp/tls.key | ||
# generate cert | ||
openssl req -new -x509 -key /tmp/tls.key -out /tmp/tls.cert -days 1095 -batch | ||
``` | ||
@@ -151,86 +177,102 @@ Routing | ||
exports.routes = function (map) { | ||
map.resources('posts', function (post) { | ||
post.resources('comments'); | ||
}); | ||
}; | ||
```js | ||
exports.routes = function (map) { | ||
map.resources('posts', function (post) { | ||
post.resources('comments'); | ||
}); | ||
}; | ||
``` | ||
instead of: | ||
var ctl = require('./lib/posts_controller.js'); | ||
app.get('/posts/new.:format?', ctl.new); | ||
app.get('/posts.:format?', ctl.index); | ||
app.post('/posts.:format?', ctl.create); | ||
app.get('/posts/:id.:format?', ctl.show); | ||
app.put('/posts/:id.:format?', ctl.update); | ||
app.delete('/posts/:id.:format?', ctl.destroy); | ||
app.get('/posts/:id/edit.:format?', ctl.edit); | ||
```js | ||
var ctl = require('./lib/posts_controller.js'); | ||
app.get('/posts/new.:format?', ctl.new); | ||
app.get('/posts.:format?', ctl.index); | ||
app.post('/posts.:format?', ctl.create); | ||
app.get('/posts/:id.:format?', ctl.show); | ||
app.put('/posts/:id.:format?', ctl.update); | ||
app.delete('/posts/:id.:format?', ctl.destroy); | ||
app.get('/posts/:id/edit.:format?', ctl.edit); | ||
var com_ctl = require('./lib/comments_controller.js'); | ||
app.get('/posts/:post_id/comments/new.:format?', com_ctl.new); | ||
app.get('/posts/:post_id/comments.:format?', com_ctl.index); | ||
app.post('/posts/:post_id/comments.:format?', com_ctl.create); | ||
app.get('/posts/:post_id/comments/:id.:format?', com_ctl.show); | ||
app.put('/posts/:post_id/comments/:id.:format?', com_ctl.update); | ||
app.delete('/posts/:post_id/comments/:id.:format?', com_ctl.destroy); | ||
app.get('/posts/:post_id/comments/:id/edit.:format?', com_ctl.edit); | ||
var com_ctl = require('./lib/comments_controller.js'); | ||
app.get('/posts/:post_id/comments/new.:format?', com_ctl.new); | ||
app.get('/posts/:post_id/comments.:format?', com_ctl.index); | ||
app.post('/posts/:post_id/comments.:format?', com_ctl.create); | ||
app.get('/posts/:post_id/comments/:id.:format?', com_ctl.show); | ||
app.put('/posts/:post_id/comments/:id.:format?', com_ctl.update); | ||
app.delete('/posts/:post_id/comments/:id.:format?', com_ctl.destroy); | ||
app.get('/posts/:post_id/comments/:id/edit.:format?', com_ctl.edit); | ||
``` | ||
and you can more finely tune the resources to specify certain actions, middleware, and other. Here example routes of [my blog][1]: | ||
exports.routes = function (map) { | ||
map.get('/', 'posts#index'); | ||
map.get(':id', 'posts#show'); | ||
map.get('sitemap.txt', 'posts#map'); | ||
```js | ||
exports.routes = function (map) { | ||
map.get('/', 'posts#index'); | ||
map.get(':id', 'posts#show'); | ||
map.get('sitemap.txt', 'posts#map'); | ||
map.namespace('admin', function (admin) { | ||
admin.resources('posts', {middleware: basic_auth, except: ['show']}, function (post) { | ||
post.resources('comments'); | ||
post.get('likes', 'posts#likes') | ||
}); | ||
map.namespace('admin', function (admin) { | ||
admin.resources('posts', {middleware: basic_auth, except: ['show']}, function (post) { | ||
post.resources('comments'); | ||
post.get('likes', 'posts#likes') | ||
}); | ||
}; | ||
}); | ||
}; | ||
``` | ||
since version 0.2.0 it is possible to use generic routes: | ||
exports.routes = function (map) { | ||
map.get(':controller/:action/:id'); | ||
map.all(':controller/:action'); | ||
}; | ||
```js | ||
exports.routes = function (map) { | ||
map.get(':controller/:action/:id'); | ||
map.all(':controller/:action'); | ||
}; | ||
``` | ||
if you have `custom_controller` with `test` action inside it you can now do: | ||
GET /custom/test | ||
POST /custom/test | ||
GET /custom/test/1 // also sets params.id to 1 | ||
``` | ||
GET /custom/test | ||
POST /custom/test | ||
GET /custom/test/1 // also sets params.id to 1 | ||
``` | ||
for debugging routes described in `config/routes.js` you can use `compound routes` command: | ||
$ compound routes | ||
GET / posts#index | ||
GET /:id posts#show | ||
sitemap.txt GET /sitemap.txt posts#map | ||
adminPosts GET /admin/posts.:format? admin/posts#index | ||
adminPosts POST /admin/posts.:format? admin/posts#create | ||
newAdminPost GET /admin/posts/new.:format? admin/posts#new | ||
editAdminPost GET /admin/posts/:id/edit.:format? admin/posts#edit | ||
adminPost DELETE /admin/posts/:id.:format? admin/posts#destroy | ||
adminPost PUT /admin/posts/:id.:format? admin/posts#update | ||
likesAdminPost PUT /admin/posts/:id/likes.:format? admin/posts#likes | ||
``` | ||
$ compound routes | ||
GET / posts#index | ||
GET /:id posts#show | ||
sitemap.txt GET /sitemap.txt posts#map | ||
adminPosts GET /admin/posts.:format? admin/posts#index | ||
adminPosts POST /admin/posts.:format? admin/posts#create | ||
newAdminPost GET /admin/posts/new.:format? admin/posts#new | ||
editAdminPost GET /admin/posts/:id/edit.:format? admin/posts#edit | ||
adminPost DELETE /admin/posts/:id.:format? admin/posts#destroy | ||
adminPost PUT /admin/posts/:id.:format? admin/posts#update | ||
likesAdminPost PUT /admin/posts/:id/likes.:format? admin/posts#likes | ||
``` | ||
Filter by method: | ||
$ compound routes GET | ||
GET / posts#index | ||
GET /:id posts#show | ||
sitemap.txt GET /sitemap.txt posts#map | ||
adminPosts GET /admin/posts.:format? admin/posts#index | ||
newAdminPost GET /admin/posts/new.:format? admin/posts#new | ||
editAdminPost GET /admin/posts/:id/edit.:format? admin/posts#edit | ||
``` | ||
$ compound routes GET | ||
GET / posts#index | ||
GET /:id posts#show | ||
sitemap.txt GET /sitemap.txt posts#map | ||
adminPosts GET /admin/posts.:format? admin/posts#index | ||
newAdminPost GET /admin/posts/new.:format? admin/posts#new | ||
editAdminPost GET /admin/posts/:id/edit.:format? admin/posts#edit | ||
``` | ||
Filter by helper name: | ||
$ compound routes Admin | ||
newAdminPost GET /admin/posts/new.:format? admin/posts#new | ||
editAdminPost GET /admin/posts/:id/edit.:format? admin/posts#edit | ||
likesAdminPost PUT /admin/posts/:id/likes.:format? admin/posts#likes | ||
``` | ||
$ compound routes Admin | ||
newAdminPost GET /admin/posts/new.:format? admin/posts#new | ||
editAdminPost GET /admin/posts/:id/edit.:format? admin/posts#edit | ||
likesAdminPost PUT /admin/posts/:id/likes.:format? admin/posts#likes | ||
``` | ||
@@ -243,9 +285,13 @@ | ||
<%- link_to("New post", newAdminPost) %> | ||
<%- link_to("New post", editAdminPost(post)) %> | ||
```html | ||
<%- link_to("New post", newAdminPost) %> | ||
<%- link_to("New post", editAdminPost(post)) %> | ||
``` | ||
generates output: | ||
<a href="/admin/posts/new">New post</a> | ||
<a href="/admin/posts/10/edit">New post</a> | ||
```html | ||
<a href="/admin/posts/new">New post</a> | ||
<a href="/admin/posts/10/edit">New post</a> | ||
``` | ||
@@ -257,37 +303,39 @@ Controllers | ||
beforeFilter(loadPost, {only: ['edit', 'update', 'destroy']}); | ||
```js | ||
beforeFilter(loadPost, {only: ['edit', 'update', 'destroy']}); | ||
action('index', function () { | ||
Post.allInstances({order: 'created_at'}, function (collection) { | ||
render({ posts: collection }); | ||
}); | ||
action('index', function () { | ||
Post.allInstances({order: 'created_at'}, function (collection) { | ||
render({ posts: collection }); | ||
}); | ||
}); | ||
action('create', function () { | ||
Post.create(req.body, function () { | ||
redirect(pathTo.adminPosts); | ||
}); | ||
action('create', function () { | ||
Post.create(req.body, function () { | ||
redirect(pathTo.adminPosts); | ||
}); | ||
}); | ||
action('new', function () { | ||
render({ post: new Post }); | ||
}); | ||
action('new', function () { | ||
render({ post: new Post }); | ||
}); | ||
action('edit', function () { | ||
render({ post: request.post }); | ||
action('edit', function () { | ||
render({ post: request.post }); | ||
}); | ||
action('update', function () { | ||
request.post.save(req.locale, req.body, function () { | ||
redirect(pathTo.adminPosts); | ||
}); | ||
}); | ||
action('update', function () { | ||
request.post.save(req.locale, req.body, function () { | ||
redirect(pathTo.adminPosts); | ||
}); | ||
function loadPost () { | ||
Post.find(req.params.id, function () { | ||
request.post = this; | ||
next(); | ||
}); | ||
} | ||
``` | ||
function loadPost () { | ||
Post.find(req.params.id, function () { | ||
request.post = this; | ||
next(); | ||
}); | ||
} | ||
## Generators ## | ||
@@ -298,21 +346,25 @@ | ||
compound generate [what] [params] | ||
```js | ||
compound generate [what] [params] | ||
``` | ||
`what` can be `model`, `controller` or `scaffold`. Example of controller generation: | ||
$ compound generate controller admin/posts index new edit update | ||
exists app/ | ||
exists app/controllers/ | ||
create app/controllers/admin/ | ||
create app/controllers/admin/posts_controller.js | ||
create app/helpers/ | ||
create app/helpers/admin/ | ||
create app/helpers/admin/posts_helper.js | ||
exists app/views/ | ||
create app/views/admin/ | ||
create app/views/admin/posts/ | ||
create app/views/admin/posts/index.ejs | ||
create app/views/admin/posts/new.ejs | ||
create app/views/admin/posts/edit.ejs | ||
create app/views/admin/posts/update.ejs | ||
``` | ||
$ compound generate controller admin/posts index new edit update | ||
exists app/ | ||
exists app/controllers/ | ||
create app/controllers/admin/ | ||
create app/controllers/admin/posts_controller.js | ||
create app/helpers/ | ||
create app/helpers/admin/ | ||
create app/helpers/admin/posts_helper.js | ||
exists app/views/ | ||
create app/views/admin/ | ||
create app/views/admin/posts/ | ||
create app/views/admin/posts/index.ejs | ||
create app/views/admin/posts/new.ejs | ||
create app/views/admin/posts/edit.ejs | ||
create app/views/admin/posts/update.ejs | ||
``` | ||
@@ -346,7 +398,11 @@ Currently it generates only `*.ejs` views | ||
compound console | ||
```sh | ||
compound console | ||
``` | ||
or it's shortcut | ||
compound c | ||
```sh | ||
compound c | ||
``` | ||
@@ -363,15 +419,17 @@ It just simple node-js console with some Compound bindings, e.g. models. Just one note | ||
compound c | ||
compound> User.find(53, c) | ||
Callback called with 2 arguments: | ||
_0 = null | ||
_1 = [object Object] | ||
compound> _1 | ||
{ email: [Getter/Setter], | ||
password: [Getter/Setter], | ||
activationCode: [Getter/Setter], | ||
activated: [Getter/Setter], | ||
forcePassChange: [Getter/Setter], | ||
isAdmin: [Getter/Setter], | ||
id: [Getter/Setter] } | ||
``` | ||
$ compound c | ||
compound> User.find(53, c) | ||
Callback called with 2 arguments: | ||
_0 = null | ||
_1 = [object Object] | ||
compound> _1 | ||
{ email: [Getter/Setter], | ||
password: [Getter/Setter], | ||
activationCode: [Getter/Setter], | ||
activated: [Getter/Setter], | ||
forcePassChange: [Getter/Setter], | ||
isAdmin: [Getter/Setter], | ||
id: [Getter/Setter] } | ||
``` | ||
@@ -393,3 +451,5 @@ Localization | ||
app.set('i18n', 'off'); | ||
```js | ||
app.set('i18n', 'off'); | ||
``` | ||
@@ -399,4 +459,6 @@ Logger | ||
app.set('quiet', true); // force logger to log into `log/#{app.settings.env}.log` | ||
compound.logger.write(msg); // to log message | ||
```js | ||
app.set('quiet', true); // force logger to log into `log/#{app.settings.env}.log` | ||
compound.logger.write(msg); // to log message | ||
``` | ||
@@ -414,4 +476,6 @@ Configuring | ||
app.disable('eval cache'); // in config/environments/development.js | ||
app.enable('eval cache'); // in config/environments/production.js | ||
```js | ||
app.disable('eval cache'); // in config/environments/development.js | ||
app.enable('eval cache'); // in config/environments/production.js | ||
``` | ||
@@ -423,3 +487,5 @@ model cache | ||
app.disable('model cache'); // in config/environments/development.js | ||
```js | ||
app.disable('model cache'); // in config/environments/development.js | ||
``` | ||
@@ -431,3 +497,5 @@ view cache | ||
app.disable('view cache'); // in config/environments/development.js | ||
```js | ||
app.disable('view cache'); // in config/environments/development.js | ||
``` | ||
@@ -439,3 +507,5 @@ quiet | ||
app.set('quiet', true); // in config/environments/test.js | ||
```js | ||
app.set('quiet', true); // in config/environments/test.js | ||
``` | ||
@@ -447,3 +517,5 @@ merge javascripts | ||
app.enable('merge javascripts'); // in config/environments/production.js | ||
```js | ||
app.enable('merge javascripts'); // in config/environments/production.js | ||
``` | ||
@@ -455,3 +527,5 @@ merge stylesheets | ||
app.enable('merge stylesheets'); // in config/environments/production.js | ||
```js | ||
app.enable('merge stylesheets'); // in config/environments/production.js | ||
``` | ||
@@ -458,0 +532,0 @@ MIT License |
@@ -7,8 +7,9 @@ var express = require('express'); | ||
app.configure('development', function () { | ||
app.enable('watch'); | ||
app.enable('log actions'); | ||
app.enable('env info'); | ||
app.enable('watch'); | ||
app.enable('force assets compilation'); | ||
app.use(require('express').errorHandler({ dumpExceptions: true, showStack: true })); | ||
app.set('translationMissing', 'display'); | ||
app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); | ||
}); | ||
}; |
@@ -0,1 +1,3 @@ | ||
var express = require('express'); | ||
module.exports = function (compound) { | ||
@@ -5,8 +7,8 @@ var app = compound.app; | ||
app.configure('production', function () { | ||
app.enable('quiet'); | ||
app.enable('merge javascripts'); | ||
app.enable('merge stylesheets'); | ||
app.disable('assets timestamps'); | ||
app.use(require('express').errorHandler()); | ||
app.settings.quiet = true; | ||
app.use(express.errorHandler()); | ||
}); | ||
}; |
@@ -6,4 +6,3 @@ var express = require('express'); | ||
app.configure('test', function(){ | ||
app.use(express.errorHandler({dumpExceptions: true, showStack: true})); | ||
app.configure('test', function () { | ||
app.enable('quiet'); | ||
@@ -13,4 +12,4 @@ app.enable('view cache'); | ||
app.enable('eval cache'); | ||
app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); | ||
}); | ||
}; |
@@ -11,2 +11,3 @@ { "name": "{{ APPNAME }}" | ||
, "jugglingdb": ">= 0.1.0" | ||
{{ DBDEPENDENCY }} | ||
, "coffee-script": ">= 1.1.1" | ||
@@ -13,0 +14,0 @@ , "{{ CSSENGINE }}": "latest" |
@@ -80,3 +80,3 @@ jQuery(function ($) { | ||
*/ | ||
$('a[data-confirm],input[data-confirm]').on('click', function (e) { | ||
$('body').on('click', 'a[data-confirm],input[data-confirm]', function (e) { | ||
var el = $(this); | ||
@@ -100,3 +100,3 @@ if (el.triggerAndReturn('confirm')) { | ||
$('a[data-remote],input[data-remote]').on('click', function (e) { | ||
$('body').on('click', 'a[data-remote],input[data-remote]', function (e) { | ||
$(this).callRemote(); | ||
@@ -106,3 +106,3 @@ e.preventDefault(); | ||
$('a[data-method]:not([data-remote])').on('click', function (e){ | ||
$('body').on('click', 'a[data-method]:not([data-remote])', function (e) { | ||
var link = $(this), | ||
@@ -109,0 +109,0 @@ href = link.attr('href'), |
@@ -50,3 +50,2 @@ | ||
'create app/controllers/', | ||
'create app/observers/', | ||
'create app/helpers/', | ||
@@ -98,2 +97,9 @@ 'create app/views/', | ||
}); | ||
it('should generate app', function () { | ||
var package = path.normalize(__dirname + '/../package.json'); | ||
delete memfs[package]; | ||
compound.generators.perform('init', ['--db', 'mongodb']); | ||
memfs[package].should.include('jugglingdb-mongodb'); | ||
}); | ||
}); | ||
@@ -100,0 +106,0 @@ |
@@ -96,3 +96,3 @@ var app, compound; | ||
it('should be able to create inputs without a block', function () { | ||
var buf = arguments.callee.buf = []; | ||
var buf = []; | ||
var res = { | ||
@@ -119,2 +119,32 @@ constructor: { | ||
}); | ||
it('should allow to override "id" attribute of tag', function() { | ||
var res = { | ||
constructor: { | ||
modelName: 'Resource' | ||
}, | ||
id: 7 | ||
}; | ||
var f = compound.helpers.formFor(res, {}); | ||
f.textarea('name').should.equal('<textarea name="Resource[name]" id="Resource_name"></textarea>'); | ||
f.textarea('name', {id: 'over'}).should.equal('<textarea name="Resource[name]" id="over"></textarea>'); | ||
}); | ||
it('should work for nested resource', function() { | ||
var res = { | ||
constructor: { | ||
modelName: 'User' | ||
}, | ||
id: 7, | ||
address: { | ||
constructor: 'Address', | ||
id: 9, | ||
street: 'Liberty st' | ||
} | ||
}; | ||
var f = compound.helpers.formFor(res, {action: '/'}); | ||
var addr = f.fieldsFor('address'); | ||
addr.input('street').should.equal('<input name="User[address][street]" id="User_address_street" type="text" value="Liberty st" />'); | ||
}); | ||
}); | ||
@@ -121,0 +151,0 @@ |
@@ -0,1 +1,2 @@ | ||
var should = require('./init.js'); | ||
var app, compound; | ||
@@ -36,3 +37,29 @@ | ||
}); | ||
describe('utils#inherits', function() { | ||
it('should inherit superclass', function() { | ||
function MyClass(){} | ||
SuperClass.classMethod = function(){}; | ||
function SuperClass(){} | ||
compound.utils.inherits(MyClass, SuperClass); | ||
var myObj = new MyClass; | ||
myObj.should.be.an.instanceOf(SuperClass); | ||
MyClass.super_.should.equal(SuperClass); | ||
should.not.exists(MyClass.classMethod); | ||
}); | ||
it('should inherit superclass with class methods', function() { | ||
function MyClass(){} | ||
SuperClass.classMethod = function(){}; | ||
function SuperClass(){} | ||
compound.utils.inherits(MyClass, SuperClass, true); | ||
var myObj = new MyClass; | ||
myObj.should.be.an.instanceOf(SuperClass); | ||
MyClass.super_.should.equal(SuperClass); | ||
should.exists(MyClass.classMethod); | ||
}); | ||
}); | ||
}); | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
598685
126
13349
538
9