Skip to content

Commit

Permalink
add textarea, date, and array field support
Browse files Browse the repository at this point in the history
  • Loading branch information
hdngr committed Nov 29, 2015
2 parents e5a2dea + b6c8120 commit 64b032e
Show file tree
Hide file tree
Showing 28 changed files with 181 additions and 24 deletions.
3 changes: 3 additions & 0 deletions .bowerrc
@@ -0,0 +1,3 @@
{
"directory": "components"
}
3 changes: 2 additions & 1 deletion .gitignore
@@ -1,3 +1,4 @@
node_modules
npm-debug.log
coverage
coverage
components
42 changes: 41 additions & 1 deletion Readme.md
Expand Up @@ -39,7 +39,8 @@ Sriracha is an Express app that can be mounted as middleware to any url in your
Options can be set globally through the options object passed to the middleware.

```
app.use('/admin', admin({...}))
var options = {...};
app.use('/admin', admin(options));
```

**username**<br>
Expand Down Expand Up @@ -69,6 +70,44 @@ User: {
**\<collection\>.admin**<br>
*default*: `undefined` A setting of false will hide this field from the admin.

## Field Types
Field types are set automatically by Sriracha based on the Mongo schema type. However, they can also be customized. Using the 'adminFieldType' option. See the [setting options on a schema](#setting-options-on-a-schema) for examples of how to set custom field types.

Sriracha currently supports the following field types:

**text**<br>
*default*: String and ObjectId schema types.
A simple string input field.

![text field](_img/fields/text.png)

**textarea**<br>
*default*: none
The text area field allows easy inline editing of larger portions of text. The textarea field uses [TinyMCE](https://www.tinymce.com/) and stores it's results as HTML.

![textarea field](_img/fields/textarea.png)

**date**<br>
*default*: Date schema type.
A date picker field using the [datepicker jquery plugin](https://eonasdan.github.io/bootstrap-datetimepicker).

![date field](_img/fields/date.png)

**array**<br>
*default*: Array schema type.
An input that accepts a comma separated list of values.

![date field](_img/fields/array.png)

**checkbox**<br>
*default*: Boolean schema type.
A checkbox that setts a boolean field to `true` or `false.`

**ref**<br>
*default*: Reference to other documents.
An input of tags representing references to other documents.

![date field](_img/fields/ref.png)

## Setting Options on a Schema
All `<collection>` level options can be set on an individual schema as well. They will take precedence over the same options if they are also defined globally.
Expand Down Expand Up @@ -106,6 +145,7 @@ For example, the following schema would set the `lastName` to the search field f
...
```


## Examples
Examples can be found in the `./examples` directory. To run them:

Expand Down
Binary file added _img/fields/array.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _img/fields/date.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _img/fields/ref.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _img/fields/text.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _img/fields/textarea.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified _img/landing.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions bower.json
@@ -0,0 +1,25 @@
{
"name": "sriracha-admin",
"description": "An admin middleware for mongoose and express.",
"main": "index.js",
"authors": [
"hdngr <hstnhdngr@gmail.com>"
],
"license": "ISC",
"homepage": "https://github.com/hdngr/siracha",
"moduleType": [
"node"
],
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"components",
"test",
"tests"
],
"dependencies": {
"tinymce": "~4.3.0",
"eonasdan-bootstrap-datetimepicker": "~4.17.37"
}
}
12 changes: 10 additions & 2 deletions examples/advanced/models/Post.js
Expand Up @@ -10,11 +10,11 @@ var PostSchema = new Schema({
default: ''
// adminSearchField: true
},
date: {
createdOn: {
type: Date,
default: new Date(),
admin: false,
adminFieldType: 'foo'
adminFieldType: 'date'
},
author: {
type: Schema.Types.ObjectId,
Expand All @@ -26,6 +26,14 @@ var PostSchema = new Schema({
},
campaignHash: {
type: String
},
body: {
type: String,
adminFieldType: 'textarea'
},
tags: {
adminFieldType: 'array',
type: Array
}
});

Expand Down
3 changes: 2 additions & 1 deletion examples/advanced/models/User.js
Expand Up @@ -20,7 +20,8 @@ var UserSchema = new Schema({
},
onboarding: {
signupDate: {
type: Date
type: String,
adminFieldType: 'date'
},
hasLoggedIn: {
type: Boolean,
Expand Down
2 changes: 1 addition & 1 deletion gulpfile.js
Expand Up @@ -53,7 +53,7 @@ gulp.task('test', function() {
// gulp-mocha needs filepaths so you can't have any plugins before it
.pipe(mocha({
reporter: 'spec',
bail: true
bail: false
}))
.once('end', function() {
process.exit();
Expand Down
3 changes: 2 additions & 1 deletion index.js
Expand Up @@ -33,7 +33,8 @@ admin.use(methodOverride(function(req, res) {
}
}));

admin.use('/static', express.static(__dirname + '/lib/static'));
admin.use('/static', express.static(__dirname + '/lib/static'));
admin.use('/components', express.static(__dirname + '/components'));


module.exports = function(userDefined) {
Expand Down
14 changes: 12 additions & 2 deletions lib/controllers/main.js
Expand Up @@ -79,7 +79,12 @@ module.exports = {
break;
case "POST":
Object.keys(req.body).forEach(function(path) {
doc.set(path, req.body[path]);
var type = Collection.getPathType(path);
var val = req.body[path];
if(type === 'array') {
val = val.split(',');
}
doc.set(path, val);
});
doc.save(function(err) {
err = err || {};
Expand Down Expand Up @@ -149,7 +154,12 @@ module.exports = {
switch (req.method) {
case "POST":
Object.keys(req.body).forEach(function(path) {
doc.set(path, req.body[path]);
var type = Collection.getPathType(path);
var val = req.body[path];
if(type === 'array') {
val = val.split(',');
}
doc.set(path, val);
});
doc.save(function(err) {
if (err) {
Expand Down
14 changes: 12 additions & 2 deletions lib/models/Collection.js
Expand Up @@ -46,8 +46,18 @@ module.exports = function(MongooseModel, options) {
case 'Boolean':
return 'checkbox';
break;
case 'ObjectID': // need better logic for multiple docs
return 'ref'; // vs single documents
case 'ObjectID':
if(leaf.options.ref) {
return 'ref';
} else {
return 'text';
}
break;
case 'Array':
return 'array';
break;
case 'Date':
return 'date';
break;
default:
return 'text';
Expand Down
3 changes: 1 addition & 2 deletions lib/models/Document.js
Expand Up @@ -7,9 +7,8 @@ module.exports = function(doc, options, Collections) {
options = options || {};
var methods = {};
var Document = doc;
var paths = Document.schema.paths;
var paths = Document.schema.paths;

// so dirty...
for(var path in paths) {
// add ability to control population in options
var ref = paths[path].options.ref
Expand Down
2 changes: 1 addition & 1 deletion lib/strategy.js
Expand Up @@ -51,7 +51,7 @@ class Strategy {
delete req.session.isLoggedIn;
var message = "You've been successfully logged out!"
req.session.message.success.push(message);
res.redirect('/');
res.redirect(req.app.locals.appPath);
}
};

Expand Down
Binary file modified lib/views/.DS_Store
Binary file not shown.
1 change: 0 additions & 1 deletion lib/views/collection.jade
Expand Up @@ -5,7 +5,6 @@ block content
include ./nav
#page-wrapper
include ./messages

.container-fluid
// Page Heading
.row
Expand Down
14 changes: 14 additions & 0 deletions lib/views/doc.jade
Expand Up @@ -53,3 +53,17 @@ block content
button.btn.btn-success(type='submit') Save
li
button.btn.btn-danger(type='submit' name="_method" value='DELETE') Delete
// textarea
block append scripts
script(type='text/javascript').
// bootstrap textareas
tinymce.init({
selector: "textarea"
});

//date
block append scripts
script(type='text/javascript').
$(function () {
$('.datetimepicker').datetimepicker();
});
8 changes: 8 additions & 0 deletions lib/views/fields/array.jade
@@ -0,0 +1,8 @@
.form-group(class=typeof errors[field] === "undefined" ? "" : "has-error")
.input-group
label.input-group-addon(for=path) #{path}
input.form-control(name=path, type='text', placeholder='', autofocus='', value=doc.get(path))
p.help-block
| Array field. Supply a list of comma separated values.
if errors[path]
span.help-block.text-danger= errors[path].message
8 changes: 8 additions & 0 deletions lib/views/fields/date.jade
@@ -0,0 +1,8 @@
.form-group(class=typeof errors[field] === "undefined" ? "" : "has-error")
.input-group.datetimepicker
label.input-group-addon(for=path) #{path}
input.form-control(name=path, type='text', placeholder='', autofocus='', data-date-default-date="#{doc.get(path)}")
span.input-group-addon
span.glyphicon.glyphicon-calendar
if errors[path]
span.help-block.text-danger= errors[path].message
8 changes: 6 additions & 2 deletions lib/views/fields/fields.jade
Expand Up @@ -5,5 +5,9 @@ case Collection.getPathType(path)
include ./checkbox
when 'ref'
include ./ref
//- when 'object'
//- include ./object
when 'textarea'
include ./textarea
when 'array'
include ./array
when 'date'
include ./date
10 changes: 10 additions & 0 deletions lib/views/fields/textarea.jade
@@ -0,0 +1,10 @@
.form-group(class=typeof errors[field] === "undefined" ? "" : "has-error")
.input-group
h4
.label.label-default(for=path) #{path}
textarea.form-control(id=path name=path, type='text', placeholder='', autofocus='',)
| #{doc.get(path)}
if errors[path]
span.help-block.text-danger= errors[path].message


8 changes: 4 additions & 4 deletions lib/views/layout.jade
Expand Up @@ -28,17 +28,17 @@ html(lang='en')

block scripts
script(type="text/javascript" src='#{appPath}/static/js/jquery.js')
script(type="text/javascript" src="#{appPath}/components/tinymce/tinymce.js")
// Bootstrap Core JavaScript
script(src='#{appPath}/static/js/bootstrap.min.js')
// Search suggestions
script(src='#{appPath}/static/js/plugins/typeahead/bootstrap3-typeahead.min.js')
script(src='#{appPath}/static/js/plugins/typeahead/bloodhound.min.js')

// Morris Charts JavaScript
script(src='#{appPath}/static/js/plugins/morris/raphael.min.js')
script(src='#{appPath}/static/js/plugins/morris/morris.min.js')
script(src='#{appPath}/static/js/plugins/morris/morris-data.js')
script(type="text/javascript" src="#{appPath}/components/moment/min/moment.min.js")

script(type="text/javascript" src="#{appPath}/components/eonasdan-bootstrap-datetimepicker/src/js/bootstrap-datetimepicker.js")

script(type='text/javascript').
//- close alerts after 5 seconds
window.setTimeout(function() { $(".alert").alert('close'); }, 5000);
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "sriracha-admin",
"version": "0.0.2",
"version": "0.0.3",
"description": "An admin middleware for mongoose and express.",
"repository": {
"type": "git",
Expand Down
20 changes: 18 additions & 2 deletions tests/models/Collection.js
Expand Up @@ -43,12 +43,28 @@ describe('Collection', function() {
UserCol.getPathType('onboarding.hasLoggedIn').should.equal('checkbox');
});

it('should return "ref" for an ObjectId schema type', function() {
it('should return "ref" for an ObjectId schema type that references another collection', function() {
PostCol.getPathType('author').should.equal('ref');
});

it('should return "ref" for an ObjectId schema type that does not reference another collection', function() {
PostCol.getPathType('_id').should.equal('text');
});

it('should return "date" field type from mongoose schema if it\'s defined', function() {
PostCol.getPathType('createdOn').should.equal('date');
});

it('should return "adminFieldType" from mongoose schema if it\'s defined', function() {
PostCol.getPathType('date').should.equal('foo');
PostCol.getPathType('body').should.equal('textarea');
});

it('should return "array" field type by default from an Array schema type', function() {
UserCol.getPathType('roles').should.equal('array');
});

it('should return "date" field type if the adminFieldType is set to "date"', function() {
UserCol.getPathType('onboarding.signupDate').should.equal('date');
});

});
Expand Down

0 comments on commit 64b032e

Please sign in to comment.