├── .gitignore ├── lib ├── hb │ ├── label.hb │ ├── boolean.hb │ ├── object.hb │ ├── hidden.hb │ ├── descend.hb │ ├── union.hb │ ├── number.hb │ ├── enum.hb │ ├── date.hb │ ├── time.hb │ ├── text.hb │ ├── ref.hb │ ├── string.hb │ ├── datetime-local.hb │ ├── dispatch.hb │ ├── form.hb │ └── array.hb ├── client │ ├── loader.gif │ ├── edit-item.html │ ├── load-indicator.html │ ├── confirm-delete-item.html │ ├── messages.html │ ├── pagination.html │ ├── user.html │ ├── couth-core.css │ ├── couth-resource-api.tmpl.js │ └── couth-client.js ├── couth.js ├── design.js ├── users.js ├── static.js ├── server.js ├── resources.js ├── couch │ └── design-utils.js ├── core.js ├── tester.js ├── deploy.js ├── forms.js └── type.js ├── example ├── static │ ├── bootstrap │ │ ├── img │ │ │ ├── glyphicons-halflings.png │ │ │ └── glyphicons-halflings-white.png │ │ ├── css │ │ │ └── bootstrap-responsive.min.css │ │ └── js │ │ │ └── bootstrap.min.js │ ├── templates │ │ ├── home.html │ │ └── books.html │ ├── core.js │ └── index.html ├── README.md └── app.js ├── package.json ├── README.md └── vendor └── jquery-ui-1.10.1.custom.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /lib/hb/label.hb: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/client/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darobin/couth/master/lib/client/loader.gif -------------------------------------------------------------------------------- /lib/client/edit-item.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/hb/boolean.hb: -------------------------------------------------------------------------------- 1 | {{> label}} 2 |
3 | 4 |
5 | -------------------------------------------------------------------------------- /lib/hb/object.hb: -------------------------------------------------------------------------------- 1 |
2 | {{#if description}}{{description}}{{/if}} 3 | {{> descend}} 4 |
5 | -------------------------------------------------------------------------------- /example/static/bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darobin/couth/master/example/static/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /lib/hb/hidden.hb: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/static/bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darobin/couth/master/example/static/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /lib/client/load-indicator.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /lib/hb/descend.hb: -------------------------------------------------------------------------------- 1 | {{#each fields}} 2 | {{#if isHidden}} 3 | {{> hidden}} 4 | {{else}} 5 |
6 | {{> dispatch}} 7 |
8 | {{/if}} 9 | {{/each}} 10 | -------------------------------------------------------------------------------- /lib/hb/union.hb: -------------------------------------------------------------------------------- 1 |
2 | {{#each fields}} 3 |
4 | 5 | {{> dispatch}} 6 |
7 | {{/each}} 8 |
9 | -------------------------------------------------------------------------------- /lib/hb/number.hb: -------------------------------------------------------------------------------- 1 | {{> label}} 2 |
3 | 5 |
6 | -------------------------------------------------------------------------------- /lib/hb/enum.hb: -------------------------------------------------------------------------------- 1 | {{> label}} 2 |
3 | 8 |
9 | -------------------------------------------------------------------------------- /lib/hb/date.hb: -------------------------------------------------------------------------------- 1 | {{> label}} 2 |
3 | 5 |
6 | -------------------------------------------------------------------------------- /lib/hb/time.hb: -------------------------------------------------------------------------------- 1 | {{> label}} 2 |
3 | 5 |
6 | -------------------------------------------------------------------------------- /lib/hb/text.hb: -------------------------------------------------------------------------------- 1 | {{> label}} 2 |
3 | 5 |
6 | -------------------------------------------------------------------------------- /example/static/templates/home.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Hello, world!

4 |

5 | This is a template that gets called for the front page. Nothing much currently happens 6 | here but you can navigate to the books (and to anything else you may have added). 7 |

8 |
9 | -------------------------------------------------------------------------------- /lib/couth.js: -------------------------------------------------------------------------------- 1 | 2 | var Couth = require("./core").Couth; 3 | require("./deploy"); 4 | require("./server"); 5 | require("./design"); 6 | require("./static"); 7 | require("./type"); 8 | require("./resources"); 9 | require("./users"); 10 | 11 | module.exports = function () { 12 | return new Couth(); 13 | }; 14 | -------------------------------------------------------------------------------- /lib/hb/ref.hb: -------------------------------------------------------------------------------- 1 | {{> label}} 2 |
3 | 4 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /lib/hb/string.hb: -------------------------------------------------------------------------------- 1 | {{> label}} 2 |
3 | 6 |
7 | -------------------------------------------------------------------------------- /lib/hb/datetime-local.hb: -------------------------------------------------------------------------------- 1 | {{> label}} 2 |
3 | 4 | 7 |
8 | -------------------------------------------------------------------------------- /lib/client/confirm-delete-item.html: -------------------------------------------------------------------------------- 1 | 3 |
4 | 5 | 6 |
7 | -------------------------------------------------------------------------------- /lib/client/messages.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

Error

5 | {{$couthError}} 6 |
7 |
8 | 9 |

Success!

10 | {{$couthSuccess}} 11 |
12 |
13 | -------------------------------------------------------------------------------- /lib/hb/dispatch.hb: -------------------------------------------------------------------------------- 1 | {{#if isHidden }}{{> hidden}}{{/if 2 | }}{{#if isString }}{{> string}}{{/if 3 | }}{{#if isText }}{{> text}}{{/if 4 | }}{{#if isNumber }}{{> number}}{{/if 5 | }}{{#if isBoolean }}{{> boolean}}{{/if 6 | }}{{#if isObject }}{{> object}}{{/if 7 | }}{{#if isUnion }}{{> union}}{{/if 8 | }}{{#if isArray }}{{> array}}{{/if 9 | }}{{#if isEnum }}{{> enum}}{{/if 10 | }}{{#if isRef }}{{> ref}}{{/if 11 | }}{{#if isDate }}{{> date}}{{/if 12 | }}{{#if isTime }}{{> time}}{{/if 13 | }}{{#if isDatetimeLocal }}{{> datetime-local}}{{/if}} 14 | -------------------------------------------------------------------------------- /lib/client/pagination.html: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "couth" 3 | , "description": "Refined Relaxation" 4 | , "version": "0.5.0" 5 | , "author": "Robin Berjon " 6 | , "dependencies": { 7 | "nopt": "2.1.1" 8 | , "underscore": "1.4.4" 9 | , "cradle": "0.6.4" 10 | , "mime": "1.2.9" 11 | , "request": "2.12.0" 12 | , "async": "0.2.5" 13 | , "web-schema": "1.1.0" 14 | , "wrench": "1.4.4" 15 | , "handlebars": "1.0.9" 16 | } 17 | , "devDependencies": { 18 | "mocha": "1.7.3" 19 | , "expect.js":"0.2.0" 20 | } 21 | , "repository": "git://github.com/darobin/couth" 22 | , "main": "lib/couth" 23 | } 24 | -------------------------------------------------------------------------------- /lib/hb/form.hb: -------------------------------------------------------------------------------- 1 |
3 |
4 | 5 | 6 |
7 |
8 | {{#if description}}{{description}}{{/if}} 9 | {{> descend}} 10 |
11 | 12 | 13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /lib/hb/array.hb: -------------------------------------------------------------------------------- 1 |
2 | {{#if description}}{{description}}{{/if}} 3 |
4 |
5 | 6 | 7 | {{#with items}}{{> dispatch}}{{/with}} 8 |
9 |
10 |
11 |
12 | 13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /lib/design.js: -------------------------------------------------------------------------------- 1 | 2 | var Couth = require("./core").Couth 3 | ; 4 | 5 | Couth.prototype.addRewrite = function (from, to, method, query) { 6 | var rew = { from: from, to: to }; 7 | if (method) rew.method = method; 8 | if (query) { 9 | rew.query = query; 10 | for (var k in rew.query) { 11 | if (typeof rew.query[k] === "boolean" || 12 | typeof rew.query[k] === "number") rew.query[k] = "" + rew.query[k]; 13 | } 14 | } 15 | this.rewrites.push(rew); 16 | return this; 17 | }; 18 | Couth.prototype.addLib = function (libName, libPath) { 19 | if (!this.design.lib) this.design.lib = {}; 20 | if (!this.design.views.lib) this.design.views.lib = {}; 21 | if (this.libCache[libName]) return; 22 | this.libCache[libName] = true; 23 | this.design.lib[libName] = this.loadContent(libPath).toString("utf8"); 24 | this.design.views.lib[libName] = this.design.lib[libName]; 25 | }; 26 | -------------------------------------------------------------------------------- /lib/users.js: -------------------------------------------------------------------------------- 1 | var Couth = require("./core").Couth 2 | ; 3 | 4 | Couth.prototype.couthUserRoutes = function () { 5 | // NOTE: this requires secure_rewrites to be set to false 6 | var sessionDB = "../../../_session"; 7 | this.addRewrite("couth/session", sessionDB, "GET"); 8 | this.addRewrite("couth/login", sessionDB, "POST"); 9 | this.addRewrite("couth/logout", sessionDB, "DELETE"); 10 | this.addRewrite("couth/signup/*", "../../../_users/*", "PUT"); 11 | 12 | // note that it's also worth checking if the client API knows how to handle 13 | // names with a hyphen -> CouthUsers 14 | if (this.conf.exposeUsers) { 15 | this.addRewrite("couth-users/*", "../../../_users/*", "GET"); 16 | this.addRewrite("couth-users/", "../../../_users/_all_docs", "GET", { 17 | startkey: "org.couchdb.user:" 18 | , endkey: "org.couchdb.userz" 19 | , include_docs: true 20 | }); 21 | // http://deploy.berjon.dev/_users/_all_docs?startkey=%22org.couchdb.user:%22&endkey=%22org.couchdb.userz%22&include_docs=true 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /example/static/templates/books.html: -------------------------------------------------------------------------------- 1 |
2 |

Books

3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 23 | 24 |
TitleAuthorsISBNActions
{{ book.title }} 14 | {{author.name}}, et al. 16 | {{ book.isbn }} 19 |
20 |
22 |
25 |
26 |
27 | -------------------------------------------------------------------------------- /example/static/core.js: -------------------------------------------------------------------------------- 1 | /*global angular */ 2 | 3 | angular.module("my-stuff", ["CouthClient", "CouthResourceAPI"]) 4 | .config(function ($routeProvider, $locationProvider) { 5 | $locationProvider.html5Mode(true); 6 | $routeProvider 7 | .when("/", { templateUrl: "/templates/home.html" }) 8 | .when("/app/books/", { controller: "BooksCtrl", templateUrl: "/templates/books.html" }) 9 | .otherwise({ redirectTo: "/" }); 10 | }) 11 | .controller("NavCtrl", function ($scope, $rootScope, $location) { 12 | $rootScope.pathActive = function (path) { 13 | return ($location.path().substr(0, path.length) === path) ? "active" : ""; 14 | }; 15 | }) 16 | .controller("BooksCtrl", function ($scope, Books, CouthSimpleCRUD) { 17 | CouthSimpleCRUD.runForType({ 18 | type: Books 19 | , name: "Book" 20 | , scope: $scope 21 | , onload: function (data) { 22 | $scope.books = data.rows; 23 | $scope.count = data.total_rows; 24 | } 25 | , pagination: { 26 | pageSize: 10 27 | , countExpr: "count" 28 | } 29 | }); 30 | }) 31 | ; 32 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## How to get this running 3 | 4 | To get this example running, you will need to have Couth installed and CouchDB running. 5 | 6 | You will also need to have the two hostnames configured `books.dev` and 7 | `deploy.books.dev` to point to where your CouchDB instance is running. They can be anything 8 | else but you will need to change the example to match. 9 | 10 | You will need to set the username and password to something real. If your CouchDB is running 11 | in Admin Party mode, then you can just delete that line. 12 | 13 | Then you run: 14 | 15 | node app.js 16 | 17 | This ought to deploy to Couch. You should then be able to get to: http://books.dev:5984/ and 18 | see the site. 19 | 20 | Obviously in a real-world setting you would likely use an HTTP proxy on port 80 in front of 21 | CouchDB. For nginx the set up would be: 22 | 23 | 24 | upstream couch { 25 | server 127.0.0.1:5984; 26 | } 27 | 28 | server { 29 | listen 80; 30 | server_name deploy.books.dev books.dev; 31 | 32 | location / { 33 | proxy_set_header X-Real-IP $remote_addr; 34 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 35 | proxy_set_header Host $http_host; 36 | proxy_set_header X-NginX-Proxy true; 37 | 38 | proxy_pass http://couch/; 39 | proxy_redirect off; 40 | } 41 | } 42 | 43 | 44 | If you do want to hack on this, you probably want to read the documentation section 45 | on "Continuous Execution" as it will make your life much nicer. 46 | -------------------------------------------------------------------------------- /example/app.js: -------------------------------------------------------------------------------- 1 | var couth = require("couth") 2 | , app = couth() 3 | ; 4 | 5 | app 6 | .deployTo("http://deploy.books.dev/") 7 | .auth({ username: "you", password: "secret" }) 8 | .vhost("books.dev") 9 | .db("mybooks") 10 | .index("/index.html") 11 | .webAppRoot("/app/") 12 | .addStaticDir("static") 13 | ; 14 | 15 | app.type("books") 16 | .schema({ 17 | type: "object" 18 | , description: "Book" 19 | , properties: { 20 | title: { 21 | type: "string" 22 | , description: "Title" 23 | , required: true 24 | } 25 | , isbn: { 26 | type: "string" 27 | , description: "ISBN" 28 | , pattern: "\\d{3}-\\d-\\d\\d-\\d{6}-\\d" 29 | } 30 | , authors: { 31 | type: "array" 32 | , description: "Authors" 33 | , items: { 34 | type: "object" 35 | , properties: { 36 | name: { type: "string", required: true } 37 | } 38 | } 39 | } 40 | , etAl: { type: "boolean", description: "Et al." } 41 | } 42 | }) 43 | .permissions({ 44 | create: "logged" 45 | , update: "logged" 46 | , del: "admin" 47 | }) 48 | .crudify({ jsonp: true }) 49 | ; 50 | 51 | // process command line options and deploy 52 | app 53 | .cli() 54 | .deploy(function (err) { 55 | console.log(err ? "BAD!" : "ALL OK!"); 56 | }) 57 | ; 58 | -------------------------------------------------------------------------------- /lib/client/user.html: -------------------------------------------------------------------------------- 1 | 47 | -------------------------------------------------------------------------------- /lib/static.js: -------------------------------------------------------------------------------- 1 | 2 | var Couth = require("./core").Couth 3 | , pth = require("path") 4 | , wrench = require("wrench") 5 | , fs = require("fs") 6 | , mime = require("mime") 7 | , _ = require("underscore") 8 | ; 9 | 10 | Couth.prototype.addStaticDir = function (path, opts) { 11 | opts = opts || { keepDotFiles: false }; 12 | var files = wrench.readdirSyncRecursive(path) 13 | , statics = [] 14 | ; 15 | for (var i = 0, n = files.length; i < n; i++) { 16 | var f = files[i] 17 | , fullPath = pth.join(path, f) 18 | , basename = pth.basename(fullPath) 19 | ; 20 | if (fs.statSync(fullPath).isDirectory()) continue; 21 | if (basename.indexOf(".") === 0 && !opts.keepDotFiles) continue; 22 | statics.push({ path: "/" + f, content: fullPath }); 23 | } 24 | return this.addStatics(statics); 25 | }; 26 | Couth.prototype.addStatics = function (statics) { 27 | if (!_.isArray(statics)) statics = [statics]; 28 | var self = this; 29 | _.each(statics, function (stat) { 30 | // the rewrite to self is actually needed 31 | self.addRewrite(stat.path, stat.path); 32 | self.addAttachment(stat.path.replace(/^\//, ""), stat.content, stat.type); 33 | }); 34 | return this; 35 | }; 36 | Couth.prototype.addAttachment = function (url, source, mediaType) { 37 | var mt = mediaType || mime.lookup(source) 38 | , showURL = _.isString(source) 39 | , body = this.loadContent(source) 40 | , self = this 41 | ; 42 | this.seenAttachment[url] = true; 43 | this.addRequest({ 44 | run: function (cradle, cb) { 45 | cradle.addAttachment(self.design, { 46 | name: url 47 | , contentType: mt 48 | , body: body 49 | }, function (err, res) { 50 | if (err) self.error(err); 51 | self.design._rev = res._rev; 52 | cb(); 53 | }); 54 | } 55 | , reason: "Uploading attachment of type " + mt + " to " + url + " from " + (showURL ? source : "[memory]") 56 | }); 57 | return this; 58 | }; 59 | -------------------------------------------------------------------------------- /example/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | My Stuff 7 | 8 | 9 | 10 | 29 | 30 | 31 | 32 | 48 | 49 |
50 |
51 | 52 |
53 | 54 |
55 | 61 |
62 | 63 | 64 |
65 | 66 |
67 |
68 |
69 | 72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /lib/server.js: -------------------------------------------------------------------------------- 1 | 2 | var Couth = require("./core").Couth 3 | , _ = require("underscore") 4 | , urlParser = require("url") 5 | , request = require("request") 6 | ; 7 | 8 | Couth.prototype.addRequest = function (req) { 9 | this.requests.push(req); 10 | }; 11 | Couth.prototype.vhostInfo = function () { 12 | var conf = this.conf 13 | , res = [] 14 | ; 15 | if (!conf.vhost) return; 16 | if (!_.isArray(conf.vhost)) conf.vhost = [conf.vhost]; 17 | _.each(conf.vhost, function (vh) { 18 | var url = urlParser.parse(conf.deployTo); 19 | delete url.host; 20 | if (conf.port) url.port = conf.port; 21 | if (conf.auth) url.auth = conf.auth.username + ":" + conf.auth.password; 22 | url.pathname = "/_config/vhosts/" + vh; 23 | res.push({ url: urlParser.format(url), body: "\"/" + conf.db + "/_design/couth/_rewrite\"", vh: vh }); 24 | }); 25 | return res; 26 | }; 27 | Couth.prototype.enforceConfig = function () { 28 | var conf = this.conf; 29 | // prepare url 30 | var url = urlParser.parse(conf.deployTo); 31 | delete url.host; 32 | if (conf.port) url.port = conf.port; 33 | if (conf.auth) url.auth = conf.auth.username + ":" + conf.auth.password; 34 | // session 35 | url.pathname = "/_config/couch_httpd_auth/timeout"; 36 | var sessURL = urlParser.format(url); 37 | this.addRequest({ 38 | run: function (cradle, cb) { 39 | request.put({ 40 | url: sessURL 41 | , body: '"' + conf.session + '"' 42 | }, cb); 43 | } 44 | , reason: "enforcing session duration to " + conf.session + " (PUT " + urlParser.format(url) + ")" 45 | }); 46 | // secure rewrites off (these aren't secure anyway) 47 | url.pathname = "/_config/httpd/secure_rewrites"; 48 | var rewURL = urlParser.format(url); 49 | this.addRequest({ 50 | run: function (cradle, cb) { 51 | request.put({ 52 | url: rewURL 53 | , body: '"false"' 54 | }, cb); 55 | } 56 | , reason: "enforcing secure rewrites to false (PUT " + urlParser.format(url) + ")" 57 | }); 58 | }; 59 | // sets up the vhost server configuration 60 | // curl -X PUT http://${user}:${pass}@${host}/_config/vhosts/${vhost} -d '"/${db}/_design/${something}/_rewrite"' 61 | Couth.prototype.prepareVHost = function () { 62 | var vhostInfo = this.vhostInfo() 63 | , self = this 64 | ; 65 | _.each(vhostInfo, function (vh) { 66 | self.addRequest({ 67 | // we roll our own request because it's rather specific for the configuration 68 | run: function (cradle, cb) { 69 | request.put({ 70 | url: vh.url 71 | , body: vh.body 72 | }, cb); 73 | } 74 | , reason: "installing virtual host " + vh.vh + " (PUT " + vh.url + " with " + vh.body + ")" 75 | }); 76 | }); 77 | }; 78 | -------------------------------------------------------------------------------- /lib/client/couth-core.css: -------------------------------------------------------------------------------- 1 | 2 | .couth-item { 3 | background: #fff; 4 | /* margin: 10px 0;*/ 5 | } 6 | 7 | .couth-placeholder { 8 | background: #eee; 9 | border: 1px dashed #ccc; 10 | border-radius: 5px; 11 | } 12 | 13 | .couth-move { 14 | float: right; 15 | margin-right: 10px; 16 | } 17 | 18 | .couth-item-delete { 19 | float: right; 20 | } 21 | 22 | /* just to make sure we're on the safe side, FOUC wise */ 23 | [ng\:cloak], [ng-cloak], .ng-cloak { 24 | display: none; 25 | } 26 | 27 | .couth-signup { 28 | margin-right: 10px; 29 | } 30 | 31 | .dropdown-menu .form-inline { 32 | margin: 10px 20px; 33 | } 34 | 35 | .couth-form-controls { 36 | margin-bottom: 10px; 37 | text-align: right; 38 | } 39 | 40 | td.couth-actions, th.couth-actions { 41 | text-align: right; 42 | white-space: nowrap 43 | } 44 | 45 | .couth-pagination { 46 | text-align: center; 47 | } 48 | 49 | .couth-inlined { 50 | display: inline-block; 51 | } 52 | 53 | .couth-success, .couth-error { 54 | left: auto; 55 | right: 0; 56 | background-clip: padding-box; 57 | border: 1px solid #000; 58 | border-radius: 6px 6px 6px 6px; 59 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 60 | min-width: 400px; 61 | margin: 0 20px 20px 0; 62 | padding: 8px 35px 14px 14px; 63 | position: fixed; 64 | z-index: 1000; 65 | opacity: 0.9; 66 | } 67 | .couth-success h4, .couth-error h4 { 68 | margin-top: 0; 69 | } 70 | 71 | .couth-success { 72 | background-color: #dff0d8; 73 | border-color: #d6e9c6; 74 | color: #468847; 75 | 76 | } 77 | .couth-error { 78 | background-color: #f2dede; 79 | border-color: #eed3d7; 80 | color: #b94a48; 81 | } 82 | 83 | .couth-close { 84 | line-height: 20px; 85 | position: relative; 86 | right: -21px; 87 | top: -2px; 88 | vertical-align: middle; 89 | background: none repeat scroll 0 0 transparent; 90 | border: 0 none; 91 | cursor: pointer; 92 | padding: 0; 93 | float: right; 94 | font-size: 20px; 95 | font-weight: bold; 96 | opacity: 0.2; 97 | text-shadow: 0 1px 0 #FFFFFF; 98 | } 99 | 100 | fieldset fieldset legend { 101 | border: none; 102 | font-size: 1em; 103 | font-weight: bold; 104 | margin: 0; 105 | text-transform: lowercase; 106 | font-variant: small-caps; 107 | padding-top: 5px; 108 | text-align: right; 109 | width: 160px; 110 | } 111 | 112 | fieldset fieldset fieldset legend { 113 | font-weight: normal; 114 | margin: 0; 115 | padding: 0; 116 | line-height: inherit; 117 | color: #999; 118 | } 119 | 120 | /*! jQuery UI - v1.10.1 - 2013-02-26 121 | * http://jqueryui.com 122 | * Includes: jquery.ui.core.css 123 | * Copyright (c) 2013 jQuery Foundation and other contributors Licensed MIT */ 124 | 125 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%} 126 | -------------------------------------------------------------------------------- /lib/resources.js: -------------------------------------------------------------------------------- 1 | var Couth = require("./core").Couth 2 | , pth = require("path") 3 | , type2form = require("./forms").generate 4 | ; 5 | 6 | Couth.prototype.couthResources = function () { 7 | if (!Object.keys(this.types).length) return; 8 | var allTypes = []; 9 | for (var t in this.types) { 10 | allTypes.push({ 11 | name: t 12 | , crudOptions: this.types[t].crudOptions 13 | }); 14 | var path = "/couth/types/" + t + ".json"; 15 | this.addRewrite(path, path); 16 | this.addAttachment(path.replace(/^\//, ""), 17 | new Buffer(JSON.stringify(this.types[t].jsonSchema)), 18 | "application/json"); 19 | var form = "/couth/forms/" + t + ".html"; 20 | this.addRewrite(form, form); 21 | this.addAttachment(form.replace(/^\//, ""), 22 | new Buffer(type2form(this.types[t].jsonSchema, t, this.types[t].hints)), 23 | "text/html"); 24 | } 25 | if (this.conf.exposeUsers) { 26 | allTypes.push({ 27 | name: "couth-users" 28 | , crudOptions: { 29 | id: "_id", 30 | paths: { 31 | list: "/couth-users", 32 | create: "/couth/signup", 33 | read: "/couth-users/:key", 34 | update: "XXX", 35 | del: "XXX" 36 | } 37 | } 38 | }); 39 | } 40 | 41 | // generate one big JS with all the dependencies 42 | var js = this.readRelFile("../vendor/jquery.min.js") + 43 | this.readRelFile("../vendor/jquery-ui-1.10.1.custom.min.js") + 44 | this.readRelFile("../vendor/angular.min.js") + 45 | this.readRelFile("client/couth-resource-api.tmpl.js") 46 | .replace('["REPLACE ME"]', JSON.stringify(allTypes, null, 4)) + 47 | this.readRelFile("client/couth-client.js"); 48 | // XXX at some point, build one big HTML file with all the HTML templates in