├── example ├── api │ ├── models │ │ ├── .gitkeep │ │ ├── Contact.js │ │ ├── Customer.js │ │ └── Fileuploads.js │ └── controllers │ │ ├── .gitkeep │ │ ├── CustomerController.js │ │ ├── ContactController.js │ │ ├── CustomerCrudConfig.js │ │ ├── ContactCrudConfig.js │ │ └── FileuploadsController.js └── views │ ├── contact │ ├── edit.ejs │ ├── index.ejs │ ├── new.ejs │ └── show.ejs │ └── customer │ ├── edit.ejs │ ├── new.ejs │ ├── show.ejs │ └── index.ejs ├── components ├── _crudtemplate │ ├── new.ejs │ ├── edit.ejs │ ├── index.ejs │ └── show.ejs ├── _crud │ ├── commons.ejs │ ├── details.ejs │ ├── index.ejs │ ├── edit.ejs │ ├── new.ejs │ ├── compare.ejs │ └── show.ejs ├── _crud.js ├── attachments.ejs └── FileuploadsController.js ├── package.json ├── README.md └── index.js /example/api/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/api/controllers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/_crudtemplate/new.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/new.ejs %> -------------------------------------------------------------------------------- /example/views/contact/edit.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/edit.ejs %> -------------------------------------------------------------------------------- /example/views/contact/index.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/index.ejs %> -------------------------------------------------------------------------------- /example/views/contact/new.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/new.ejs %> -------------------------------------------------------------------------------- /example/views/contact/show.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/show.ejs %> -------------------------------------------------------------------------------- /example/views/customer/edit.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/edit.ejs %> -------------------------------------------------------------------------------- /example/views/customer/new.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/new.ejs %> -------------------------------------------------------------------------------- /example/views/customer/show.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/show.ejs %> -------------------------------------------------------------------------------- /components/_crudtemplate/edit.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/edit.ejs %> -------------------------------------------------------------------------------- /components/_crudtemplate/index.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/index.ejs %> -------------------------------------------------------------------------------- /components/_crudtemplate/show.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/show.ejs %> -------------------------------------------------------------------------------- /example/views/customer/index.ejs: -------------------------------------------------------------------------------- 1 | <% include ../_crud/index.ejs %> -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sails-crudface", 3 | "version": "0.2.4", 4 | "description": "A sailsjs node module for \"systematic\" scrud interface generation", 5 | "dependencies": { 6 | }, 7 | "repository": "https://github.com/cashbit/sails-crudface.git", 8 | "author": "Cashbit" 9 | } 10 | -------------------------------------------------------------------------------- /example/api/models/Contact.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Contact 3 | * 4 | * @module :: Model 5 | * @description :: A short summary of how this model works and what it represents. 6 | * @docs :: http://sailsjs.org/#!documentation/models 7 | */ 8 | 9 | module.exports = { 10 | 11 | attributes: { 12 | 13 | /* e.g. 14 | nickname: 'string' 15 | */ 16 | 17 | } 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /example/api/models/Customer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Customer 3 | * 4 | * @module :: Model 5 | * @description :: A short summary of how this model works and what it represents. 6 | * @docs :: http://sailsjs.org/#!documentation/models 7 | */ 8 | 9 | module.exports = { 10 | 11 | attributes: { 12 | 13 | /* e.g. 14 | nickname: 'string' 15 | */ 16 | 17 | } 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /example/api/models/Fileuploads.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Fileuploads 3 | * 4 | * @module :: Model 5 | * @description :: A short summary of how this model works and what it represents. 6 | * @docs :: http://sailsjs.org/#!documentation/models 7 | */ 8 | 9 | module.exports = { 10 | 11 | attributes: { 12 | 13 | /* e.g. 14 | nickname: 'string' 15 | */ 16 | 17 | } 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /components/_crud/commons.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | function dateFormatFromLocale(inputDate,defaultValue){ 3 | var dateStringValue = defaultValue ; 4 | var inputDate = record[field.name] ; 5 | if (typeof(inputDate.getDate) === "function"){ 6 | var outputDateElements = [] ; 7 | var dateFormatPositions = locale.dateFormat.split('/') ; 8 | for (var i=0;i -------------------------------------------------------------------------------- /example/api/controllers/CustomerController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * CustomerController 3 | * 4 | * @module :: Controller 5 | * @description :: A set of functions called `actions`. 6 | * 7 | * Actions contain code telling Sails how to respond to a certain type of request. 8 | * (i.e. do stuff, then send some JSON, show an HTML page, or redirect to another URL) 9 | * 10 | * You can configure the blueprint URLs which trigger these actions (`config/controllers.js`) 11 | * and/or override them with custom routes (`config/routes.js`) 12 | * 13 | * NOTE: The code you write here supports both HTTP and Socket.io automatically. 14 | * 15 | * @docs :: http://sailsjs.org/#!documentation/controllers 16 | */ 17 | 18 | module.exports = require("sails-crudface").init(module,__dirname); -------------------------------------------------------------------------------- /example/api/controllers/ContactController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AlunnoController 3 | * 4 | * @module :: Controller 5 | * @description :: A set of functions called `actions`. 6 | * 7 | * Actions contain code telling Sails how to respond to a certain type of request. 8 | * (i.e. do stuff, then send some JSON, show an HTML page, or redirect to another URL) 9 | * 10 | * You can configure the blueprint URLs which trigger these actions (`config/controllers.js`) 11 | * and/or override them with custom routes (`config/routes.js`) 12 | * 13 | * NOTE: The code you write here supports both HTTP and Socket.io automatically. 14 | * 15 | * @docs :: http://sailsjs.org/#!documentation/controllers 16 | */ 17 | module.exports = require("sails-crudface").init(module,__dirname); 18 | 19 | module.exports.mostracustomer = function(req,res,next){ 20 | 21 | res.redirect("customer"); 22 | 23 | }; -------------------------------------------------------------------------------- /example/api/controllers/CustomerCrudConfig.js: -------------------------------------------------------------------------------- 1 | { 2 | "prettyName" : "Customer", 3 | 4 | "layout" : [ 5 | { 6 | "section": "", "rows": [ 7 | {"firstname":6, "lastname":6} 8 | ] 9 | }, 10 | { 11 | "section": "", "rows": [ 12 | {"contacts":12} 13 | ] 14 | } 15 | ], 16 | 17 | "fieldsConfig": [ 18 | {"name": "firstname", "ines": "ines", "type": "text", "inname":true}, 19 | {"name": "lastname", "ines": "ines", "type": "text"}, 20 | {"name": "contacts", "ines":"s", "type":"detail", "model":"contact", "key":"customer", "fields":[ 21 | {"name":"firstname","label":"First name"}, 22 | {"name":"lastname", "label":"Last name"} 23 | ], 24 | "destroyMethod":"delete", "destroyEnabled":true, 25 | "addEnabled": true, 26 | "addPosition": "top", 27 | "label":"Contacts" 28 | } 29 | ] 30 | 31 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sails-crudface 2 | ============== 3 | 4 | **A [sails](https://github.com/balderdashy/sails) node module for "systematic" scrud interface generation with MVC architecture.** 5 | 6 | If you want sails generate views on the fly for your models, you can use this module and create a configuration file describing the fields and the layout you need for every controller/model. 7 | 8 | Often for data entry is not needed complexity but simplicity. 9 | Also, writing the code for the view part of the MVC architecture is a repetitive task, because you may want a standard layout for toolbars, buttons, lists, and so on. 10 | 11 | sails-crudface automates the task of creating the user interface for search and entry of data. 12 | 13 | The resulting user interface is plain and responsive HTML with [jQuery](http://jquery.com/download/) and [Bootstrap](http://getbootstrap.com/getting-started/#download) 14 | 15 | Sails it's an MVC realtime framework for web application development, please visit the [official site](http://sailsjs.org/) for more. 16 | 17 | See the [wiki](../../wiki) for docs. -------------------------------------------------------------------------------- /example/api/controllers/ContactCrudConfig.js: -------------------------------------------------------------------------------- 1 | { 2 | "prettyName" : "Contact", 3 | 4 | "facets": [ 5 | {"field": "department", "option": "department", "caption":"Department"}, 6 | {"field": "customer", "option": "customer", "caption":"Customer"} 7 | ], 8 | 9 | 10 | "layout" : [ 11 | { 12 | "section": "", "rows": [ 13 | {"firstname":6, "lastname":6} 14 | ] 15 | }, 16 | { 17 | "section":"Details","rows":[ 18 | {"email":8, "phone":4}, 19 | {"birthdate":4,"department":8} 20 | ] 21 | }, 22 | { 23 | "section":"Relazione customer","rows":[ 24 | {"customer":12} 25 | ] 26 | }, 27 | { 28 | "section":"Altri dati","rows":[ 29 | {"Mostra customer":12} 30 | ] 31 | } 32 | ], 33 | 34 | "fieldsConfig": [ 35 | {"name": "firstname", "ines": "ines", "type": "text", "inname":true}, 36 | {"name": "lastname", "ines": "ines", "type": "text", "label":"last name"}, 37 | {"name": "email", "ines": "nes", "type": "text"}, 38 | {"name": "phone", "ines": "nes", "type": "text"}, 39 | {"name": "birthdate", "ines":"nes", "type": "date"}, 40 | { 41 | "name": "department", 42 | "ines":"ines", 43 | "type":"buttongroup", 44 | "options":["Admin","Development","Sales"] 45 | }, 46 | {"name": "Mostra customer","ines":"s", "type":"button", "action":"mostracustomer"}, 47 | { 48 | "name": "customer", 49 | "type": "select", 50 | "ines": "ines", 51 | "relationship": { 52 | "entity": "customer", 53 | "inname": "firstname", 54 | "filter":{} 55 | } 56 | } 57 | ] 58 | 59 | } -------------------------------------------------------------------------------- /components/_crud.js: -------------------------------------------------------------------------------- 1 | var _crud = { 2 | 3 | addedClasses: [] , 4 | 5 | 6 | sectionHide: function(section,time){ 7 | $('#sectionBtn_'+section).removeClass('glyphicon-eye-open') ; 8 | $('#sectionBtn_'+section).addClass('glyphicon-eye-close') ; 9 | $('#section_'+section).hide(time) ; 10 | }, 11 | 12 | sectionShow: function(section,time){ 13 | $('#sectionBtn_'+section).removeClass('glyphicon-eye-close') ; 14 | $('#sectionBtn_'+section).addClass('glyphicon-eye-open') ; 15 | $('#section_'+section).show(time) ; 16 | }, 17 | 18 | sectionToggle : function(section){ 19 | if($('#sectionBtn_'+section).hasClass('glyphicon-eye-open')){ 20 | this.sectionHide(section,300) ; 21 | } else { 22 | this.sectionShow(section,300) ; 23 | } 24 | }, 25 | 26 | ActivateSelectedButtonInCompare : function(pType,fieldName){ 27 | this.addedClasses.push(pType) ; 28 | for (var i=0;i div > ul').empty(); 72 | for (var i=0;i'+ data[i].value +'') ; 74 | } 75 | }); 76 | } 77 | }; 78 | 79 | $(document).ready(function(){ 80 | _crud.ScanForButtonGroups() ; 81 | _crud.ShowHiddenSelects(); 82 | _crud.SetTitle(); 83 | 84 | 85 | 86 | if (typeof(_crud_documentReady) === 'function') _crud_documentReady(); 87 | }); 88 | 89 | -------------------------------------------------------------------------------- /components/_crud/details.ejs: -------------------------------------------------------------------------------- 1 | <% if (field.type == 'detail') { %> 2 |
3 | 4 | <% if (field.label) { %> 5 |

<%= field.label %>

6 | <% } %> 7 | 8 | 9 | 10 | <% var mode = "i" ; %> 11 | <% _.each(field.fields, function(detailfield) { %> 12 | 13 | <% }) %> 14 | 15 | 16 | 22 | <% if (field.destroyEnabled){ %> 23 | 28 | <% } %> 29 | 30 | 31 | 32 | <% _.each(field.records, function(detailrecord) { %> 33 | 34 | <% var mode = "i" ; %> 35 | <% _.each(field.fields, function(detailfield) { %> 36 | <% 37 | var path = detailfield.name.split(".") ; 38 | if (detailrecord[path[0]] !== undefined){ 39 | var value = detailrecord[path[0]] ; 40 | for (var i=1;i 49 | 50 | <% }) %> 51 | 52 | 53 | 54 | <% if (field.destroyEnabled){ %> 55 | 66 | <% } %> 67 | 68 | 69 | 70 | <% }) %> 71 |
<%= detailfield.label ? detailfield.label : detailfield.name %> 17 | <% if (!field.destroyEnabled){ 18 | if (field.addEnabled) { %> 19 | Add 20 | <% }} %> 21 | 24 | <% if (field.addEnabled) { %> 25 | Add 26 | <% } %> 27 |
<%= value ? value : "" %>ShowEdit
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
72 |
73 | <% } %> -------------------------------------------------------------------------------- /components/attachments.ejs: -------------------------------------------------------------------------------- 1 |

Attachments

2 |
3 |
4 |
5 |

Drag & drop your files here or click to search

6 |
7 | 8 | 9 | <% if (attachmentIsPublic) {%><% } %> 10 | 11 |
12 |
13 |
14 |

Attached files

15 | 44 | Remove selected attachments 45 |
46 |
47 |
48 | 49 | -------------------------------------------------------------------------------- /components/FileuploadsController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FileuploadsController 3 | * 4 | * @module :: Controller 5 | * @description :: A set of functions called `actions`. 6 | * 7 | * Actions contain code telling Sails how to respond to a certain type of request. 8 | * (i.e. do stuff, then send some JSON, show an HTML page, or redirect to another URL) 9 | * 10 | * You can configure the blueprint URLs which trigger these actions (`config/controllers.js`) 11 | * and/or override them with custom routes (`config/routes.js`) 12 | * 13 | * NOTE: The code you write here supports both HTTP and Socket.io automatically. 14 | * 15 | * @docs :: http://sailsjs.org/#!documentation/controllers 16 | */ 17 | 18 | module.exports = { 19 | 20 | 21 | 22 | 23 | /** 24 | * Overrides for the settings in `config/controllers.js` 25 | * (specific to FileuploadsController) 26 | */ 27 | _config: {}, 28 | 29 | send: function(req,res,next){ 30 | var recordid ; 31 | var recordIdDefined = (req.param('recordid') != "") && (req.param('recordid') != "undefined") && (req.param('recordid') != undefined) ; 32 | if (recordIdDefined) { 33 | recordid = req.param('recordid') 34 | } 35 | var fs = require("fs") ; 36 | var classname = req.param('classname') ; 37 | var private = req.param('public') ? false : true ; 38 | fs.readFile(req.files.file.path, function (err, data) { 39 | var newPath = __dirname + "/../../.tmp/uploads/" + req.files.file.name; 40 | Fileuploads.create({ 41 | path: newPath, 42 | user: req.session.User.id, 43 | originaldata: req.files.file, 44 | classname: classname, 45 | recordid: recordid, 46 | private: private 47 | }, function(err,newFileUpload){ 48 | if (err) return next(err) ; 49 | fs.writeFile(newPath, data, function (err) { 50 | if (sails.controllers[classname].onFileUpload){ 51 | sails.controllers[classname].onFileUpload(res,req,next,newFileUpload,function(err){ 52 | if (!err) res.json({id:newFileUpload.id, filename: req.files.file.name}) ; 53 | if (err) return next(err) ; 54 | }) ; 55 | } else { 56 | res.json({id:newFileUpload.id, filename: req.files.file.name}) ; 57 | } 58 | }); 59 | }) 60 | }); 61 | }, 62 | 63 | receive: function(req,res,next){ 64 | var fs = require("fs") ; 65 | Fileuploads.findOne(req.param('id'),function(err,foundFile){ 66 | if (foundFile.private && foundFile.user != req.session.User.id){ 67 | return res.json({errcode:'Forbidden'}) 68 | } 69 | var relativepath = __dirname + "/../../.tmp/uploads/" + foundFile.originaldata.originalFilename ; 70 | var path = require("path") ; 71 | var absolutepath = path.resolve(relativepath) ; 72 | res.attachment(absolutepath) ; 73 | res.download(absolutepath,foundFile.originaldata.originalFilename) ; 74 | }) 75 | }, 76 | 77 | remove: function(req,res,next){ 78 | 79 | function removeFile(fileToRemove){ 80 | var relativepath = __dirname + "/../../.tmp/uploads/" + fileToRemove.originaldata.originalFilename ; 81 | fs.unlink(relativepath, function(err){ 82 | if (!err || err.errno == 34){ 83 | Fileuploads.destroy(fileToRemove.id,function(removeerr){ 84 | if (removeerr) return res.json(removeerr) ; 85 | res.json({ok:true}) ; 86 | }) 87 | } else { 88 | return res.json(err) ; 89 | } 90 | }) ; 91 | } 92 | 93 | var fs = require("fs") ; 94 | Fileuploads.findOne(req.param('id'),function(err,foundFile){ 95 | if (!foundFile) return ; 96 | if (foundFile.private && foundFile.user != req.session.User.id){ 97 | return res.json({errcode:'Forbidden'}) 98 | } 99 | var classname = req.param('classname') ; 100 | if (sails.controllers[classname].onFileRemove){ 101 | sails.controllers[classname].onFileRemove(res,req,next,foundFile,function(err){ 102 | if (!err) { 103 | removeFile(foundFile) ; 104 | } else { 105 | return res.json(err) ; 106 | } 107 | }) ; 108 | } else { 109 | removeFile(foundFile) ; 110 | } 111 | 112 | 113 | }) 114 | }, 115 | 116 | index: function(req,res,next){ 117 | res.view(); 118 | }, 119 | 120 | attachedFilesList: function(classname, recordid,attachedFilesListCallBack){ 121 | Fileuploads 122 | .find({classname:classname, recordid: recordid}, function(err,attachmentsFound){ 123 | if (err) attachedFilesListCallBack(err) ; 124 | if (!err) attachedFilesListCallBack(err,attachmentsFound) ; 125 | }) 126 | } 127 | }; 128 | -------------------------------------------------------------------------------- /example/api/controllers/FileuploadsController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FileuploadsController 3 | * 4 | * @module :: Controller 5 | * @description :: A set of functions called `actions`. 6 | * 7 | * Actions contain code telling Sails how to respond to a certain type of request. 8 | * (i.e. do stuff, then send some JSON, show an HTML page, or redirect to another URL) 9 | * 10 | * You can configure the blueprint URLs which trigger these actions (`config/controllers.js`) 11 | * and/or override them with custom routes (`config/routes.js`) 12 | * 13 | * NOTE: The code you write here supports both HTTP and Socket.io automatically. 14 | * 15 | * @docs :: http://sailsjs.org/#!documentation/controllers 16 | */ 17 | 18 | module.exports = { 19 | 20 | 21 | 22 | 23 | /** 24 | * Overrides for the settings in `config/controllers.js` 25 | * (specific to FileuploadsController) 26 | */ 27 | _config: {}, 28 | 29 | send: function(req,res,next){ 30 | var recordid ; 31 | var recordIdDefined = (req.param('recordid') != "") && (req.param('recordid') != "undefined") && (req.param('recordid') != undefined) ; 32 | if (recordIdDefined) { 33 | recordid = req.param('recordid') 34 | } 35 | var fs = require("fs") ; 36 | var classname = req.param('classname') ; 37 | var private = req.param('public') ? false : true ; 38 | fs.readFile(req.files.file.path, function (err, data) { 39 | var newPath = __dirname + "/../../.tmp/uploads/" + req.files.file.name; 40 | Fileuploads.create({ 41 | path: newPath, 42 | user: req.session.User.id, 43 | originaldata: req.files.file, 44 | classname: classname, 45 | recordid: recordid, 46 | private: private 47 | }, function(err,newFileUpload){ 48 | if (err) return next(err) ; 49 | fs.writeFile(newPath, data, function (err) { 50 | if (sails.controllers[classname].onFileUpload){ 51 | sails.controllers[classname].onFileUpload(res,req,next,newFileUpload,function(err){ 52 | if (!err) res.json({id:newFileUpload.id, filename: req.files.file.name}) ; 53 | if (err) return next(err) ; 54 | }) ; 55 | } else { 56 | res.json({id:newFileUpload.id, filename: req.files.file.name}) ; 57 | } 58 | }); 59 | }) 60 | }); 61 | }, 62 | 63 | receive: function(req,res,next){ 64 | var fs = require("fs") ; 65 | Fileuploads.findOne(req.param('id'),function(err,foundFile){ 66 | if (foundFile.private && foundFile.user != req.session.User.id){ 67 | return res.json({errcode:'Forbidden'}) 68 | } 69 | var relativepath = __dirname + "/../../.tmp/uploads/" + foundFile.originaldata.originalFilename ; 70 | var path = require("path") ; 71 | var absolutepath = path.resolve(relativepath) ; 72 | res.attachment(absolutepath) ; 73 | res.download(absolutepath,foundFile.originaldata.originalFilename) ; 74 | }) 75 | }, 76 | 77 | remove: function(req,res,next){ 78 | 79 | function removeFile(fileToRemove){ 80 | var relativepath = __dirname + "/../../.tmp/uploads/" + fileToRemove.originaldata.originalFilename ; 81 | fs.unlink(relativepath, function(err){ 82 | if (!err || err.errno == 34){ 83 | Fileuploads.destroy(fileToRemove.id,function(removeerr){ 84 | if (removeerr) return res.json(removeerr) ; 85 | res.json({ok:true}) ; 86 | }) 87 | } else { 88 | return res.json(err) ; 89 | } 90 | }) ; 91 | } 92 | 93 | var fs = require("fs") ; 94 | Fileuploads.findOne(req.param('id'),function(err,foundFile){ 95 | if (!foundFile) return ; 96 | if (foundFile.private && foundFile.user != req.session.User.id){ 97 | return res.json({errcode:'Forbidden'}) 98 | } 99 | var classname = req.param('classname') ; 100 | if (sails.controllers[classname].onFileRemove){ 101 | sails.controllers[classname].onFileRemove(res,req,next,foundFile,function(err){ 102 | if (!err) { 103 | removeFile(foundFile) ; 104 | } else { 105 | return res.json(err) ; 106 | } 107 | }) ; 108 | } else { 109 | removeFile(foundFile) ; 110 | } 111 | 112 | 113 | }) 114 | }, 115 | 116 | index: function(req,res,next){ 117 | res.view(); 118 | }, 119 | 120 | attachedFilesList: function(classname, recordid,attachedFilesListCallBack){ 121 | Fileuploads 122 | .find({classname:classname, recordid: recordid}, function(err,attachmentsFound){ 123 | if (err) attachedFilesListCallBack(err) ; 124 | if (!err) attachedFilesListCallBack(err,attachmentsFound) ; 125 | }) 126 | } 127 | }; 128 | -------------------------------------------------------------------------------- /components/_crud/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 |

<%= prettyName %>

8 |

9 | Add 10 |

11 |

12 | CSV 13 |

14 |
15 |
16 | 17 | 18 |
19 |
20 |
21 |
22 | 23 | 24 |
25 | 35 |
36 | 37 | 38 |
39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 | 47 | 48 |
49 | 50 |
51 |
52 | 53 |
54 | 55 | <% var width = Math.floor(12/facets.length) > 1 ? Math.floor(12/facets.length) : 2 ;%> 56 | <% _.each(facets, function(facet) { %> 57 | 58 |
59 | 60 | 69 |
70 | <% }) %> 71 |
72 |
73 |
74 | 75 | 76 | 77 | 78 | 79 | <% var mode = "i" ; %> 80 | <% _.each(fields, function(field) { %> 81 | <% if (field.ines.indexOf(mode) > -1){ %> 82 | <% 83 | var textAlign ; 84 | var r = 0 ; 85 | while (!textAlign){ 86 | if (records[r]){ 87 | if (records[r][field.name]) textAlign = records[r][field.name].textAlign ; 88 | } 89 | r++ ; 90 | if (r >= records.length) textAlign = textAlign || " " ; 91 | } 92 | %> 93 | 94 | <% } %> 95 | <% }) %> 96 | 97 | 98 | 99 | 100 | 101 | 102 | <% _.each(records, function(record) { 103 | if (!record._crudConfig){ 104 | record._crudConfig = { 105 | canShow : true, 106 | canEdit : true, 107 | canDelete : true 108 | } 109 | } 110 | %> 111 | 112 | <% var mode = "i" ; %> 113 | <% _.each(fields, function(field) { %> 114 | <% if (field.ines.indexOf(mode) > -1) { %> 115 | <% if (field.type == "link") { %> 116 | 117 | <% } else { %> 118 | 119 | <% } %> 120 | <% } %> 121 | <% }) %> 122 | 127 | 132 | 133 | 149 | 150 | 151 | <% }) %> 152 |
<%= field.label ? field.label : field.name %>
"><%= record[field.name] ? record[field.name].crudRender(field) : "" %>"><%= record[field.name] ? record[field.name].crudRender(field) : "" %> 123 | <% if (record._crudConfig.canShow){ %> 124 | Show 125 | <% } %> 126 | 128 | <% if (record._crudConfig.canEdit){ %> 129 | Edit 130 | <% } %> 131 | 134 | <% if (record._crudConfig.canDelete){ %> 135 |
136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 |
144 | <% } %> 145 | <% if (record._crudConfig.gotoUrl){ %> 146 | Goto 147 | <% } %> 148 |
153 |
154 | -------------------------------------------------------------------------------- /components/_crud/edit.ejs: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | <% var mode = "e" %> 6 | <% _.each(fieldlayout, function(section) { %> 7 | 8 | <% if (section.section) { %>

<%= section.section %>

<% } %> 9 | <% if (section.section) { %> 10 |
11 | <% } %> 12 | <% _.each(section.rows, function(row) { %> 13 |
14 |
15 | <% for (var control in row) { %> 16 | <% var width = row[control] ; %> 17 |
18 | <% for (var i=0;i 19 | 20 | <% if (field.type == 'text' || field.type == 'link') { %> 21 | 22 | "/> 23 | <% } %> 24 | 25 | 26 | <% if (field.type == 'read-only-text') { %> 27 |
28 | 29 | "/> 30 |
31 | <% } %> 32 | 33 | <% if (field.type == 'textarea') { %> 34 | 35 | 36 | <% } %> 37 | 38 | 39 | <% if (field.type == 'checkbox') { %> 40 |   41 |
42 | 46 |
47 | <% } %> 48 | 49 | <% if (field.type == 'select') { %> 50 | 51 | 57 | <% } %> 58 | 59 | <% if (field.type == 'add-select') { %> 60 | 61 | Add 62 | 68 | <% } %> 69 | 70 | <% if (field.type == 'read-only-select') { %> 71 |
72 | 73 | 79 |
80 | " /> 81 | <% } %> 82 | 83 | 84 | <% if (field.type == 'date') { %> 85 | 86 |
87 | <% } %> 88 | 89 | 90 | <% if (field.type == 'buttongroup') { %> 91 | 92 |
93 | " /> 94 | 95 | <% _.each(field.options, function(option) { %> 96 | 97 |
<%= option.id ? option.text : option %>
98 |
99 | <% }) %> 100 | 101 |
102 | <% } %> 103 | 104 | 105 |
106 | <% } %> 107 |
108 |
109 | <% }) %> 110 | <% if (section.section) { %> 111 |
112 | <% } %> 113 | <% }) %> 114 |
115 |
116 |
117 | 118 |
119 |
120 | 121 |
122 |
123 | 124 |
125 |
-------------------------------------------------------------------------------- /components/_crud/new.ejs: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | <% var mode = "n" %> 6 | <% _.each(fieldlayout, function(section) { %> 7 | <% if (section.section) { %>

<%= section.section %>

<% } %> 8 | <% if (section.section) { %> 9 |
10 | <% } %> 11 | <% _.each(section.rows, function(row) { %> 12 |
13 |
14 | <% for (var control in row) { %> 15 | <% var width = row[control] ; %> 16 |
17 | <% for (var i=0;i 18 | 19 | <% if (field.type == 'text' || field.type == 'link') { %> 20 | 21 | "/> 22 | <% } %> 23 | 24 | <% if (field.type == 'read-only-text') { %> 25 |
26 | 27 | "/> 28 |
29 | <% } %> 30 | 31 | <% if (field.type == 'textarea') { %> 32 | 33 | 34 | <% } %> 35 | 36 | 37 | <% if (field.type == 'checkbox') { %> 38 |   39 |
40 | 44 |
45 | <% } %> 46 | 47 | <% if (field.type == 'select') { %> 48 | 49 | 55 | <% } %> 56 | 57 | <% if (field.type == 'add-select') { %> 58 | 59 | Add 60 | 66 | <% } %> 67 | 68 | <% if (field.type == 'read-only-select') { %> 69 |
70 | 71 | 77 | 78 |
79 | " /> 80 | <% } %> 81 | 82 | <% if (field.type == 'select-add') { %> 83 | 84 | 85 | <% } %> 86 | 87 | 88 | <% if (field.type == 'date') { %> 89 | 90 |
91 | <% } %> 92 | 93 | 94 | <% if (field.type == 'buttongroup') { %> 95 | 96 |
97 | " /> 98 | 99 | <% _.each(field.options, function(option) { %> 100 | 101 |
<%= option.id ? option.text : option %>
102 |
103 | <% }) %> 104 | 105 |
106 | <% } %> 107 |
108 | <% } %> 109 |
110 |
111 | <% }) %> 112 | <% if (section.section) { %> 113 |
114 | <% } %> 115 | <% }) %> 116 |
117 | 118 |
119 |
120 | 121 |
122 |
123 | 124 |
125 |
126 | 127 |
128 |
-------------------------------------------------------------------------------- /components/_crud/compare.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 |

<%= prettyName %>

8 |

9 | CSV 10 |

11 |
12 |
13 | 14 | 15 |
16 |
17 |
18 |
19 | 20 | 21 |
22 | 32 |
33 | 34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 |
42 |
43 | 44 | 45 |
46 | 47 |
48 |
49 | 50 |
51 | 52 | <% var width = Math.floor(12/facets.length) > 1 ? Math.floor(12/facets.length) : 2 ;%> 53 | <% _.each(facets, function(facet) { %> 54 | 55 |
56 | 57 | 63 |
64 | <% }) %> 65 |
66 |
67 |
68 | 69 | 70 | 74 | 75 | 76 | 77 |
78 |
79 |
80 |
81 | <% _.each(compareConfig.rankingLevels, function(option) { %> 82 | 83 |
<%= option.class %>
84 |
85 | <% }) %> 86 |
87 |
88 |
89 | <% var buttonWidth = 2 ; 90 | var colsPerRow = 12 ; 91 | var col = 0 ; 92 | var rows = [] ; 93 | var row = [] ; 94 | var sortedRecords = records ; 95 | 96 | if (compareConfig.rankingFieldName){ 97 | sortedRecords = _.sortBy(records,function(a,b){ 98 | if (a[compareConfig.rankingFieldName] < b[compareConfig.rankingFieldName]) 99 | return -1; 100 | if (a[compareConfig.rankingFieldName] > b[compareConfig.rankingFieldName]) 101 | return 1; 102 | return 0; 103 | }) ; 104 | } 105 | 106 | _.each(sortedRecords, function(record) { 107 | var buttonTitle = record[compareConfig.labelFieldName].crudRender() ; 108 | var buttonHref = "/" + compareConfig.modelName + "/show/" + record[compareConfig.objectIdFieldName]; 109 | var buttonClassName = "alert-info" ; 110 | if (compareConfig.rankingFieldName){ 111 | var ranking = record[compareConfig.rankingFieldName] ; 112 | for (var rl = compareConfig.rankingLevels.length-1; rl>=0; rl--){ 113 | if (ranking <= compareConfig.rankingLevels[rl].ranking){ 114 | buttonClassName = "alert-" + compareConfig.rankingLevels[rl].class ; 115 | } 116 | } 117 | } 118 | var button = { 119 | buttonTitle : buttonTitle, 120 | buttonHref : buttonHref, 121 | buttonClassName : buttonClassName 122 | } 123 | row.push(button) ; 124 | col += buttonWidth ; 125 | if (col >= colsPerRow){ 126 | col = 0 ; 127 | rows.push(row) ; 128 | row = [] ; 129 | } 130 | }) 131 | 132 | if (row.length > 0){ 133 | rows.push(row) ; 134 | } 135 | 136 | _.each(rows,function(row){ %> 137 |
138 | <% _.each(row,function(col){ %> 139 |
140 |
141 | 146 |
147 |
148 | <% }) %> 149 |
150 | <% }) %> 151 |
152 |
153 | 154 |
155 |
156 |
157 | <% _.each(compareConfig.rankingLevels, function(option) { %> 158 | 159 |
<%= option.class %>
160 |
161 | <% }) %> 162 |
163 |
164 | 165 | 166 | <% _.each(compareConfig.summaryFields, function(field) { %> 167 | 168 | <% }) %> 169 | 170 | 171 | 172 | 173 | <% _.each(sortedRecords, function(record) { 174 | 175 | var buttonHref = "/" + compareConfig.modelName + "/show/" + record[compareConfig.objectIdFieldName] 176 | var buttonClassName = "info" ; 177 | if (compareConfig.rankingFieldName){ 178 | var ranking = record[compareConfig.rankingFieldName] ; 179 | for (var rl = compareConfig.rankingLevels.length-1; rl>=0; rl--){ 180 | if (ranking <= compareConfig.rankingLevels[rl].ranking){ 181 | buttonClassName = compareConfig.rankingLevels[rl].class ; 182 | } 183 | } 184 | } 185 | %> 186 | 187 | <% _.each(compareConfig.summaryFields, function(field) { %> 188 | 189 | <% }) %> 190 | 191 | 192 | 193 | 194 | 195 | <% }) %> 196 | 197 | 198 | <% _.each(compareConfig.summaryFields, function(field) { 199 | var value = "" ; 200 | _.each(footerFieldsConfig, function(footerField) { 201 | if (footerField.name === field.name){ 202 | value = footerField.value ? footerField.value.crudRender(footerField.format) : "" ; 203 | } 204 | }) ; %> 205 | 206 | <% }) %> 207 | 208 |
<%= field.label ? field.label : field.name %>
<%= record[field.name] ? record[field.name].crudRender(field.format) : "" %>Show
<%= value %>
209 |
210 |
211 | 212 |
213 | -------------------------------------------------------------------------------- /components/_crud/show.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 7 |
8 | Edit 9 |
10 |
11 |
12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | <% var mode = "s" ; var sectionCount = 0; %> 20 | 21 | <% _.each(fieldlayout, function(section) { sectionCount++%> 22 | <% var hidden = section.config.hidden ? "hidden" : "" ; %> 23 | <% if (section.section) { %> 24 |
25 |

<%= section.section %>

26 |
27 |
28 | <% } %> 29 | <% if (section.section) { %> 30 | 167 | <% } %> 168 | <% }) %> 169 |
170 | 171 | <% if (showAttachments) { %> 172 | 173 | 174 |
175 | <% var attachmentClassName = controller ; %> 176 | <% var attachmentIsPublic = attachmemtIsPublic ; %> 177 | <% include ../fileuploads/attachments.ejs %> 178 |
179 | 180 | 181 | <% } %> -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * sails-crudface 3 | * 4 | * @module :: sails-crudface 5 | * @description :: Automatically creates user interface for data entry 6 | * @docs :: https://www.npmjs.org/package/sails-crudface 7 | */ 8 | 9 | (function(){ 10 | 11 | 12 | if(!String.prototype.trim) { 13 | String.prototype.trim = function () { 14 | return this.replace(/^\s+|\s+$/g,''); 15 | }; 16 | } 17 | 18 | Boolean.prototype.crudRender = function(params){ 19 | if (params){ 20 | if (this.toString() === "true"){ 21 | return params.name || params.label ; 22 | } else { 23 | return "" ; 24 | } 25 | } else if (this.toString() === "true"){ 26 | return "YES" ; 27 | } else { 28 | return "NO" ; 29 | } 30 | }; 31 | 32 | String.prototype.crudRender = function(){ 33 | return this ; 34 | }; 35 | 36 | String.prototype.toDateFromLocale = function(){ 37 | var dateElements = this.split('/') ; 38 | var outputDateElements = [] ; 39 | var locale = {} ; 40 | locale.dateFormat = "d/m/y" ; 41 | var dateFormatPositions = locale.dateFormat.split('/') ; 42 | 43 | var dateFormatElements = { 44 | y: 0, 45 | m: 0, 46 | d: 0 47 | }; 48 | 49 | for (var element in dateFormatElements){ 50 | var dateFormatElementPosition = module.exports.findStringInArray(element,dateFormatPositions) ; 51 | outputDateElements.push(dateElements[dateFormatElementPosition]) ; 52 | } 53 | return new Date(outputDateElements) ; 54 | }; 55 | 56 | Number.prototype.textAlign = "text-right" ; 57 | 58 | Number.prototype.localeThousandSeparator = function(){ 59 | return "." ; 60 | } 61 | Number.prototype.localeDecimalSeparator = function(){ 62 | return "," ; 63 | } 64 | 65 | Number.prototype.localeCurrencySymbol = function(){ 66 | return "€ " ; 67 | } 68 | 69 | Number.prototype.localeCurrecyDecimals = function(){ 70 | return 2 ; 71 | } 72 | 73 | Number.prototype.crudRender = function(config){ 74 | if (!config) return this.formatNumber(); 75 | if (config.format) config = config.format ; 76 | if (config == 'percent'){ 77 | var p = this * 100 ; 78 | return p.formatNumber(2,this.localeDecimalSeparator(),this.localeThousandSeparator()) + " %" ; 79 | } 80 | if (config == 'integer') return this.formatNumber(0,this.localeDecimalSeparator(),this.localeThousandSeparator()) ; 81 | if (config == 'year') return this.formatNumber(0,this.localeDecimalSeparator(),"") ; 82 | if (config == 'float') return this.formatNumber(2,this.localeDecimalSeparator(),this.localeThousandSeparator()) ; 83 | if (config == 'currencyNoDec') return this.formatNumber( 84 | 0, 85 | this.localeDecimalSeparator(), 86 | this.localeThousandSeparator(), 87 | this.localeCurrencySymbol() 88 | ) ; 89 | if (config == 'currency') return this.formatNumber( 90 | this.localeCurrecyDecimals(), 91 | this.localeDecimalSeparator(), 92 | this.localeThousandSeparator(), 93 | this.localeCurrencySymbol() 94 | ) ; 95 | return this.formatNumber(config.c,config.d,config.t,config.m) ; 96 | }; 97 | 98 | Number.prototype.formatMoney = function(c, d, t){ 99 | var n = this, 100 | c = isNaN(c = Math.abs(c)) ? 2 : c, 101 | d = d == undefined ? "." : d, 102 | t = t == undefined ? "," : t, 103 | s = n < 0 ? "-" : "", 104 | i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", 105 | j = (j = i.length) > 3 ? j % 3 : 0; 106 | return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : ""); 107 | }; 108 | 109 | Number.prototype.formatNumber = function(c, d, t, m){ 110 | var n = this, 111 | c = isNaN(c = Math.abs(c)) ? 2 : c, 112 | d = d == undefined ? "," : d, 113 | t = t == undefined ? "." : t, 114 | s = n < 0 ? "-" : "", 115 | i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", 116 | j = (j = i.length) > 3 ? j % 3 : 0; 117 | // todo: use M to position before or after the currecy symbol... 118 | m = m == undefined ? "" : " " + m ; 119 | return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "") + m; 120 | }; 121 | 122 | Date.prototype.crudRender = function(){ 123 | return this.formatDate() ; 124 | }; 125 | 126 | Date.prototype.formatDate = function(){ 127 | var outputDateElements = [] ; 128 | // todo: get the current locale 129 | var locale = {} ; 130 | locale.dateFormat = 'd/m/y' ; 131 | var dateFormatPositions = locale.dateFormat.split('/') ; 132 | for (var i=0;i 0) output += '/' ; 150 | output += element ; 151 | } 152 | return output ; 153 | }; 154 | })(); 155 | 156 | 157 | /* 158 | Use init to initialize the controller with standard methods: 159 | - index (lists all object in model) 160 | - new (shows the view to create a new object in model) 161 | - edit (shows the view to edit an existing object in model) 162 | - show (shows an identified object in model) 163 | 164 | Example: if you have a model called "Project", these methods will be called with urls: 165 | - index: /project 166 | - new: /project/new 167 | - edit: /project/edit/ 168 | - show: /project/show/ 169 | 170 | */ 171 | 172 | module.exports.getCurrentLocale = function(){ 173 | if (!sails.config.locale){ 174 | sails.config.locale = { 175 | it: { 176 | dateFormat : 'd/m/y' 177 | }, 178 | en: { 179 | dateFormat : 'm/d/y' 180 | } 181 | }; 182 | } 183 | // todo: dinamically load from the user-agent locale 184 | return sails.config.locale.it ; 185 | } ; 186 | 187 | module.exports.addConfigurationToViewConfig = function(req,res,config){ 188 | var locale = module.exports.getCurrentLocale() ; 189 | config.locale = locale ; 190 | } ; 191 | 192 | module.exports.init = function(controller,fromPath){ 193 | this.fromPath = fromPath ; 194 | 195 | var managedController = { 196 | index : function(req,res,next){ 197 | module.exports.searchView(req,res,next,controller,{},function(viewConfig){ 198 | res.view(viewConfig); 199 | }); 200 | }, 201 | 202 | 'new' : function(req,res,next){ 203 | module.exports.createView(req,res,next,controller,function(viewConfig){ 204 | res.view(viewConfig); 205 | }); 206 | }, 207 | 208 | edit : function(req, res, next) { 209 | module.exports.updateView(req,res,next,controller,function(viewConfig){ 210 | res.view(viewConfig); 211 | }); 212 | }, 213 | 214 | show : function(req, res, next) { 215 | module.exports.readView(req,res,next,controller,function(viewConfig){ 216 | res.view(viewConfig); 217 | }); 218 | }, 219 | 220 | createAction : function(req, res, next) { 221 | module.exports.createAction(req,res,next,controller); 222 | }, 223 | 224 | updateAction : function(req, res, next) { 225 | module.exports.updateAction(req,res,next,controller) ; 226 | }, 227 | 228 | destroyAction : function(req, res, next) { 229 | module.exports.destroyAction(req,res,next,controller) ; 230 | }, 231 | 232 | subscribe : function(req, res) { 233 | module.exports.subscribe(req,res,controller) ; 234 | }, 235 | 236 | compare : function(req,res,next){ 237 | module.exports.searchView(req,res,next,controller,{},function(viewConfig){ 238 | res.view(viewConfig); 239 | }); 240 | }, 241 | 242 | config : function(req,res,next){ 243 | // sends config to client 244 | module.exports.sendConfig(req,res,next,controller,function(err,viewConfig){ 245 | if (!err){ 246 | res.header('Content-type','text/json'); 247 | res.send(viewConfig) ; 248 | } else { 249 | res.send(err) ; 250 | } 251 | 252 | }) 253 | }, 254 | 255 | csvexport: function(req,res,next){ 256 | module.exports.searchView(req,res,next,controller,{},function(viewConfig){ 257 | var fieldlist = [] ; 258 | for (var i=0;i-1) 261 | fieldlist.push(field.name) ; 262 | } 263 | var fieldSeparator = 's' ; 264 | if (req.param('CSV') == 'c' || req.param('CSV') == 's'|| req.param('CSV') == 't'){ 265 | fieldSeparator = req.param('CSV') ; 266 | } 267 | res.header('Content-type','text/csv'); 268 | res.header('Content-disposition','attachment;filename=' + controller.exports.globalId + '.csv'); 269 | res.send(module.exports.exportCSV(viewConfig.records,fieldSeparator,fieldlist)) ; 270 | }); 271 | }, 272 | 273 | findForSelect: function(req,res,next){ 274 | module.exports.searchView(req,res,next,controller,{},function(viewConfig){ 275 | var inNameFields = [] ; 276 | for (var f=0;f 5) req.session.breadCrumbs.splice(0,1) ; 315 | } ; 316 | 317 | module.exports.removeUrlFromBreadCrumbs = function(req,url){ 318 | if (!req.session.breadCrumbs) req.session.breadCrumbs = [] ; 319 | for (var i=0;i -1){ 412 | var control = {} ; 413 | control[field.name] = 12; 414 | controller.exports.layout[0].rows.push(control) ; 415 | } 416 | } 417 | } 418 | 419 | var outputLayout = [] ; 420 | for (var i=0;i -1){ 432 | newRow[afield.name] = row[fieldName] ; 433 | fieldCount++ ; 434 | } 435 | } 436 | } 437 | /* 438 | for (var f=0;f -1){ 442 | newRow[field.name] = row[field.name] ; 443 | fieldCount++ ; 444 | } 445 | } 446 | } 447 | */ 448 | if (fieldCount){ 449 | newRows.push(newRow) ; 450 | } 451 | } 452 | if (newRows.length > 0){ 453 | outputLayout.push({section:section, rows: newRows, config:controller.exports.layout[i]}) ; 454 | } 455 | } 456 | 457 | return outputLayout ; 458 | }; 459 | 460 | module.exports.createView = function(req,res,next,controller,callback){ 461 | 462 | this.loadConfig(controller) ; 463 | 464 | var layout = module.exports.autoLayout(controller,"n") ; 465 | var returnUrl = req.param('returnUrl') ; 466 | var name = controller.exports.customIdentity || controller.exports.identity ; 467 | var fields = controller.exports.fieldsConfig ; 468 | 469 | var newObj = {} ; 470 | for (var i=0;i -1) newObj[fieldName] = req.param(fieldName) ; 473 | } 474 | 475 | var viewConfig = { 476 | fields: fields, 477 | fieldlayout: layout, 478 | controller: controller.exports.identity, 479 | prettyName: controller.exports.prettyName, 480 | record : newObj, 481 | returnUrl: returnUrl 482 | } ; 483 | 484 | module.exports.addConfigurationToViewConfig(req,res,viewConfig); 485 | 486 | var relationships = [] ; 487 | for (var i=0;i=0;rr--){ 722 | var record = viewConfig.records[rr] ; 723 | var rId = record[distinctFieldName] ; 724 | if (presentIds[rId]){ 725 | viewConfig.records.splice(rr,1) ; 726 | } else { 727 | presentIds[rId] = true ; 728 | } 729 | } 730 | } 731 | 732 | function cutRecordToViewLimit(viewConfig){ 733 | if (req.param('__viewlimit') === 'all'){ 734 | viewConfig.recordcount = viewConfig.records.length ; 735 | viewConfig.pagecount = 1 ; 736 | viewConfig.viewpage = 1 ; 737 | viewConfig.viewlimit = viewlimit ; 738 | return ; 739 | } 740 | 741 | 742 | var viewpage = 1 ; 743 | var viewlimit = 100 ; 744 | 745 | if (req.param('__viewlimit') > 0){ 746 | viewlimit = req.param('__viewlimit')*1 ; 747 | } 748 | if (req.param('__viewpage') > 0){ 749 | viewpage = req.param('__viewpage')*1 ; 750 | } 751 | 752 | viewConfig.recordcount = viewConfig.records.length ; 753 | viewConfig.pagecount = Math.ceil(viewConfig.records.length/viewlimit) ; 754 | viewConfig.viewpage = viewpage ; 755 | viewConfig.viewlimit = viewlimit ; 756 | 757 | if (viewlimit == 'all') return ; 758 | 759 | 760 | if (viewConfig.records.length > viewlimit){ 761 | var offset = (viewlimit*(viewpage -1)) ; 762 | var limitRecords = [] ; 763 | for (var i=offset;i<(viewlimit + offset);i++){ 764 | limitRecords.push(viewConfig.records[i] ) ; 765 | } 766 | viewConfig.records = limitRecords ; 767 | } 768 | } 769 | 770 | function calcRankForText(text,record){ 771 | var rank = 0 ; 772 | for (var i=0;i -1) rank++ ; 777 | } 778 | } 779 | return rank/controller.exports.textSearchFields.length ; 780 | } 781 | 782 | function freeTextSearch(viewConfig){ 783 | 784 | viewConfig.freetext = "" ; 785 | 786 | if (!controller.exports.textSearchFields) { 787 | controller.exports.textSearchFields = [] ; 788 | for (var i=0;i 0){ 807 | outputrecords.push(record) ; 808 | } 809 | } 810 | viewConfig.freetext = text ; 811 | viewConfig.records = outputrecords ; 812 | } 813 | 814 | function calculateFooter(record,viewConfig){ 815 | 816 | if (!viewConfig.footerFieldsConfig) return ; 817 | 818 | for (var f=0;f -1){ 1202 | 1203 | if (field.type == 'checkbox'){ 1204 | var checkedValue = field.checkedValue === undefined ? true : field.checkedValue ; 1205 | var uncheckedValue = field.uncheckedValue === undefined ? false : field.uncheckedValue ; 1206 | if (req.param(fieldName) === undefined){ 1207 | updateObj[fieldName] = uncheckedValue ; 1208 | } else { 1209 | updateObj[fieldName] = checkedValue ; 1210 | } 1211 | } else { 1212 | var value = req.param(fieldName) ; 1213 | if (value !== undefined) { 1214 | if (field.type == 'date'){ 1215 | if (req.param(fieldName).toDateFromLocale){ 1216 | var date = req.param(fieldName).toDateFromLocale() ; 1217 | if (date.toString() !== "Invalid Date") updateObj[fieldName] = date ; 1218 | } 1219 | } else { 1220 | updateObj[fieldName] = req.param(fieldName) ; 1221 | } 1222 | } 1223 | } 1224 | } 1225 | } 1226 | if (req.session.User){ 1227 | if (!updateObj.updator) updateObj.updator = req.session.User.id ; 1228 | } 1229 | 1230 | if (controller.exports.beforeUpdate){ 1231 | sails.models[name].findOne({id:req.param('id')},function(err,foundRecord){ 1232 | if (err) { 1233 | sails.log.warn(err) ; 1234 | return res.send(404); 1235 | } 1236 | controller.exports.beforeUpdate(req,res,foundRecord,updateObj,function(err){ 1237 | if (err) { 1238 | sails.log.warn(err) ; 1239 | return res.send(501); 1240 | } else { 1241 | run() ; 1242 | } 1243 | }) ; 1244 | }) ; 1245 | } else { 1246 | run() ; 1247 | } 1248 | 1249 | function run(){ 1250 | sails.models[name].update({id:req.param('id')},updateObj, function (err, updatedObjs) { 1251 | if (err) { 1252 | console.log(err); 1253 | req.session.flash = { 1254 | err: err 1255 | }; 1256 | if (returnUrl != "undefined") return res.redirect(returnUrl) ; 1257 | res.redirect('/'+ controller.exports.identity + '/show/' + req.param('id')); 1258 | } else { 1259 | sails.models[name].publishUpdate(req.param('id'),updatedObjs[0].toJSON()); 1260 | if (returnUrl != "undefined") return res.redirect(returnUrl) ; 1261 | res.redirect('/'+ controller.exports.identity + '/show/' + req.param('id')); 1262 | } 1263 | }); 1264 | } 1265 | }, 1266 | 1267 | module.exports.destroyAction = function(req,res,next,controller){ 1268 | 1269 | console.log("ieccchime"); 1270 | this.loadConfig(controller) ; 1271 | 1272 | var returnUrl = req.param('returnUrl') ; 1273 | var method = req.param('method') ; 1274 | var name ; 1275 | 1276 | if (method == "detach"){ 1277 | name = req.param('model') ; 1278 | var key = req.param('key') ; 1279 | var updateObj = {} ; 1280 | updateObj[key] = null ; 1281 | sails.models[name].update(req.param('id'),updateObj,function(err,updatedObjs){ 1282 | if (err) return next(err); 1283 | res.redirect(req.param('returnUrl')) ; 1284 | }); 1285 | } else { 1286 | name = controller.exports.customIdentity || controller.exports.identity ; 1287 | module.exports.removeUrlFromBreadCrumbs(req, "/" + name + "/show/" + req.param('id')) ; 1288 | sails.models[name].findOne(req.param('id'), function (err, objectToDelete) { 1289 | if (err) return next(err); 1290 | if (!objectToDelete) return next(controller.exports.prettyname + ' doesn\'t exist.'); 1291 | if (controller.exports.beforeDelete){ 1292 | controller.exports.beforeDelete(req,res,objectToDelete,function(err){ 1293 | if (err) { 1294 | sails.log.warn(err) ; 1295 | return res.send(501); 1296 | } else { 1297 | run() ; 1298 | } 1299 | }) ; 1300 | } else { 1301 | run() ; 1302 | } 1303 | 1304 | function run(){ 1305 | var inname ; 1306 | sails.models[name].destroy(req.param('id'), function (err) { 1307 | if (err) return next(err); 1308 | if (typeof(objectToDelete.inName) == 'function'){ 1309 | inname = objectToDelete.inName() ; 1310 | } else { 1311 | var fields = controller.exports.fieldsConfig ; 1312 | var innamevalues = [] ; 1313 | for (var i=0;i b.text) 1349 | return 1; 1350 | return 0; 1351 | } 1352 | 1353 | var relationship = field.relationship ; 1354 | sails.models[relationship.entity] 1355 | .find(field.relationship.filter) 1356 | .exec(function(err,foundRecords){ 1357 | if (err){ 1358 | relationshipcallback(err) ; 1359 | return; 1360 | } 1361 | var options = [] ; 1362 | for (var i=0;i -1) field = '"' + field + '"' ; 1441 | outputrow.push(field) ; 1442 | fields.push(field) ; 1443 | } 1444 | } 1445 | output.push(outputrow.join(fieldSeparator)) ; 1446 | outputrow = [] ; 1447 | } 1448 | 1449 | for (var f=0;f -1) fieldValue = '"' + fieldValue + '"' ; 1458 | if (fieldValue.indexOf(rowSeparator) > -1) fieldValue = fieldValue.replace(rowSeparator,"\\"+rowSeparator) ; 1459 | } 1460 | if (typeof(fieldValue) == 'number') { 1461 | if (Math.round(fieldValue) != fieldValue){ 1462 | fieldValue = fieldValue.formatNumber() ; 1463 | } 1464 | 1465 | } 1466 | outputrow.push(fieldValue) ; 1467 | } 1468 | output.push(outputrow.join(fieldSeparator)) ; 1469 | } 1470 | return output.join(rowSeparator) ; 1471 | }, 1472 | 1473 | module.exports.populateThisRelationshipOnRecord = function(config,populateThisCallBack){ 1474 | var field = config.field ; 1475 | var record = config.record ; 1476 | var relatedRecordId = record[field.name] ; 1477 | var relatedEntity = field.entity ; 1478 | sails.models[relatedEntity].findOne(relatedRecordId,function(err,foundRecord){ 1479 | if (err){ 1480 | populateThisCallBack(err) ; 1481 | } else { 1482 | if (foundRecord){ 1483 | record[field.name] = foundRecord ; 1484 | } else { 1485 | record[field.name] = null ; 1486 | } 1487 | populateThisCallBack() ; 1488 | } 1489 | }); 1490 | }, 1491 | 1492 | module.exports.populateRelationshipsOnRecord = function(record,entityName,populateCallBack){ 1493 | 1494 | var relationships = [] ; 1495 | for (var attrname in sails.models[entityName]._attributes){ 1496 | var attr = sails.models[entityName]._attributes[attrname] ; 1497 | if (attr.model){ 1498 | relationships.push({ 1499 | field: { 1500 | name : attrname, 1501 | entity: attr.model 1502 | }, 1503 | record: record 1504 | }) ; 1505 | } 1506 | } 1507 | 1508 | async.each(relationships,module.exports.populateThisRelationshipOnRecord,function(err){ 1509 | populateCallBack() ; 1510 | }); 1511 | }, 1512 | 1513 | module.exports.populateRelationshipsOnRecordArray = function(recordArray,entityName,populateOnArrayCallBack){ 1514 | 1515 | function populate(record,callback){ 1516 | module.exports.populateRelationshipsOnRecord(record,entityName,function(err){ 1517 | callback(err); 1518 | }); 1519 | } 1520 | 1521 | async.each(recordArray,populate,function(err){ 1522 | populateOnArrayCallBack(); 1523 | }); 1524 | }, 1525 | 1526 | module.exports.attachedFilesList = function(classname, recordid, viewConfig, attachedFilesListCallBack){ 1527 | Fileuploads 1528 | .find({classname:classname, recordid: recordid}, function(err,attachmentsFound){ 1529 | viewConfig.attachedFiles = attachmentsFound ; 1530 | attachedFilesListCallBack(err) ; 1531 | }); 1532 | }, 1533 | 1534 | module.exports.findStringInArray = function(str, strArray){ 1535 | for (var j=0; j