WIP open file for a while
This commit is contained in:
parent
f937019e42
commit
d280fb9af3
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -10,10 +10,10 @@ npm-debug.log
|
||||||
test/data
|
test/data
|
||||||
|
|
||||||
# Ignore example data
|
# Ignore example data
|
||||||
example/node_modules
|
|
||||||
example/npm-debug.log
|
|
||||||
example/www_static/css/lib
|
example/www_static/css/lib
|
||||||
example/www_static/js/lib
|
example/www_static/js/lib
|
||||||
|
example/www_logs
|
||||||
|
example/lib_app
|
||||||
|
|
||||||
# Ignore binary files
|
# Ignore binary files
|
||||||
*.o
|
*.o
|
||||||
|
|
20
TODO.md
Normal file
20
TODO.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
TODO
|
||||||
|
=========
|
||||||
|
|
||||||
|
Small todo list
|
||||||
|
|
||||||
|
## angular
|
||||||
|
|
||||||
|
* add downloads
|
||||||
|
* (paging)
|
||||||
|
* field types
|
||||||
|
* validation
|
||||||
|
* tabs for child entities
|
||||||
|
* i18n
|
||||||
|
|
||||||
|
## server
|
||||||
|
|
||||||
|
* ldap support
|
||||||
|
* route page
|
||||||
|
* keyyed sub list
|
||||||
|
* menu
|
45
example/example-config.json
Normal file
45
example/example-config.json
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"winston": {
|
||||||
|
"console": {
|
||||||
|
"level": "debug",
|
||||||
|
"silent": false,
|
||||||
|
"colorize": true,
|
||||||
|
"timestamp": null
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"level": "debug",
|
||||||
|
"silent": false,
|
||||||
|
"colorize": false,
|
||||||
|
"timestamp": null,
|
||||||
|
"json": false,
|
||||||
|
"filename": "www_logs/server.log"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"server": {
|
||||||
|
"httpPort": 8008,
|
||||||
|
"httpTrustProxy": true,
|
||||||
|
"sessionSecret": "tcrudIDKEy",
|
||||||
|
"sessionTTL": "14 * 24 * 60 * 60"
|
||||||
|
},
|
||||||
|
"application": {
|
||||||
|
"name": "TCrud Example Server",
|
||||||
|
"index": {
|
||||||
|
"pageTitle": "TCrud Example Server",
|
||||||
|
"pageKeywords": "node,crud,api,json,xml,views"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"static": {
|
||||||
|
"maxAge": 86400000
|
||||||
|
},
|
||||||
|
"cookieParser": {
|
||||||
|
"secretKey": "test88test"
|
||||||
|
},
|
||||||
|
"rss": {
|
||||||
|
"link": "http://localhost:8008",
|
||||||
|
"author": "TCrud",
|
||||||
|
"options": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
example/example.js
Normal file
61
example/example.js
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var config = require('./example-config.json');
|
||||||
|
var favicon = require('static-favicon');
|
||||||
|
var cookieParser = require('cookie-parser')
|
||||||
|
var path = require('path');
|
||||||
|
var winston = require('winston');
|
||||||
|
winston.loggers.add('main',config.winston);
|
||||||
|
var log = winston.loggers.get('main');
|
||||||
|
var expressWinston = require('express-winston');
|
||||||
|
var tcrud = require('../lib/node-ff-tcrud');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
|
||||||
|
// PHASE_1: load extra plugins
|
||||||
|
//tcrud.setup.pluginLoad(new MyPlugin());
|
||||||
|
require('./lib/pg-moviedb').load(tcrud);
|
||||||
|
require('./lib/pg-pagila').load(tcrud);
|
||||||
|
|
||||||
|
// PHASE_2: enable plugins
|
||||||
|
tcrud.setup.pluginEnableAll();
|
||||||
|
|
||||||
|
// PHASE_3: start config
|
||||||
|
tcrud.setup.phaseConfig();
|
||||||
|
tcrud.config.getRootTEntity().tmeta.tplugin.formatXML.tslug = 'xml_is_free';
|
||||||
|
tcrud.config.getRootTEntity().tmeta.tplugin.formatCSV.tslug = 'csv4all';
|
||||||
|
var tPostgresDB = tcrud.config.createTEntityNode(tcrud.config.getRootTEntity(),'pg');
|
||||||
|
var tMongoose = tcrud.config.createTEntityNode(tcrud.config.getRootTEntity(),'mongoose');
|
||||||
|
require('./lib/pg-moviedb').setup(tcrud,tPostgresDB);
|
||||||
|
require('./lib/pg-pagila').setup(tcrud,tPostgresDB);
|
||||||
|
//require('./lib/mongoose-blog').setup(tcrud,tMongoose);
|
||||||
|
|
||||||
|
// PHASE_4: finalize config
|
||||||
|
tcrud.setup.phaseServer();
|
||||||
|
//tcrud.setup.expressSimple(); or complex;
|
||||||
|
|
||||||
|
var server = tcrud.setup.expressCreate();
|
||||||
|
server.use(expressWinston.logger({
|
||||||
|
transports: [new winston.transports.Console({json: false,colorize: true})],
|
||||||
|
meta: false,
|
||||||
|
expressFormat: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
var buildOptions = {
|
||||||
|
viewsDir: path.join(__dirname, 'www_views')
|
||||||
|
}
|
||||||
|
tcrud.setup.expressBuild(buildOptions);
|
||||||
|
|
||||||
|
server.use(favicon());
|
||||||
|
server.use(cookieParser(config.options.cookieParser.secretKey));
|
||||||
|
|
||||||
|
//server.get('/ui/thtml/*', tcrud.setup.express.renderTemplatePath('thtml/'));
|
||||||
|
|
||||||
|
server.use(expressWinston.errorLogger({
|
||||||
|
transports: [new winston.transports.Console({json: false,colorize: true})]
|
||||||
|
}));
|
||||||
|
|
||||||
|
tcrud.setup.expressListen();
|
||||||
|
|
||||||
|
//PHASE_6: post boot to from self.
|
||||||
|
tcrud.setup.phaseServerUp();
|
26
example/lib/ldapjs-example.js
Normal file
26
example/lib/ldapjs-example.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
var ldap = require('ldapjs');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
setup: setup
|
||||||
|
};
|
||||||
|
|
||||||
|
function setup(tcrud,tcrudModel) {
|
||||||
|
|
||||||
|
var client = ldap.createClient({
|
||||||
|
url: 'ldap://127.0.0.1:389'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create backend with id and uri
|
||||||
|
tcrud.plugin.backend.ldapjs.registrate('ldapjs/main',client);
|
||||||
|
|
||||||
|
// Create tcrud models
|
||||||
|
var tc = tcrud.config;
|
||||||
|
var t = tc.createTEntityNode(tcrudModel,'ldapjs');
|
||||||
|
t.tmeta.tmodel.tbackend = 'ldapjs/main';
|
||||||
|
|
||||||
|
// Define model and columns
|
||||||
|
var tUser = tc.createTEntity(t,'cn=foo, o=example','cn');
|
||||||
|
var tUserId = tc.createTField(tUser,'uid');
|
||||||
|
var tUserName = tc.createTField(tUser,'sn');
|
||||||
|
var tUserEmail = tc.createTField(tUser,'email');
|
||||||
|
}
|
153
example/lib/mongoose-blog.js
Normal file
153
example/lib/mongoose-blog.js
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
var mongoose = require('mongoose');
|
||||||
|
var log = require('winston').loggers.get('main');
|
||||||
|
var tcrud = require('../../lib/node-ff-tcrud');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
setup: setup
|
||||||
|
};
|
||||||
|
|
||||||
|
function setup(tcrud,tcrudModel) {
|
||||||
|
|
||||||
|
var mongoUrl = 'mongodb://localhost:27017/blog';
|
||||||
|
var mongoOptions = {
|
||||||
|
db: {
|
||||||
|
fsync: false,
|
||||||
|
journal: false,
|
||||||
|
native_parser: true,
|
||||||
|
forceServerObjectId: true
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
poolSize: 4,
|
||||||
|
socketOptions: {
|
||||||
|
connectTimeoutMS: 500,
|
||||||
|
keepAlive: 1,
|
||||||
|
auto_reconnect: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
log.info('Connecting to: ' + mongoUrl);
|
||||||
|
var conn = mongoose.createConnection(mongoUrl,mongoOptions);
|
||||||
|
|
||||||
|
tcrud.plugin.backend.mongoose.registrate('mongoose/blog',conn);
|
||||||
|
conn.model('blog-state', modelSchemaBlogState, 'blog_state');
|
||||||
|
|
||||||
|
var tc = tcrud.config;
|
||||||
|
var crudAdmin = tc.createTEntityNode(tcrudModel,'admin');
|
||||||
|
crudAdmin.troles.push('admin');
|
||||||
|
|
||||||
|
var crudAdminModels = tcrud.plugin.backend.mongoose.buildTEntityModels(conn,crudAdmin);
|
||||||
|
log.info('crud admin models created: '+crudAdminModels.length);
|
||||||
|
crudAdminModels.forEach(function(model) {
|
||||||
|
model.tmeta.tmodel.tbackend = 'mongoose/blog';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var modelMetaBlogState = {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
trim: true,
|
||||||
|
index: { unique: true },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
trim: true,
|
||||||
|
index: { unique: false },
|
||||||
|
tfield: {
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
trim: true,
|
||||||
|
tfield: {
|
||||||
|
xtype: 'textarea',
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
trim: true,
|
||||||
|
tfield: {
|
||||||
|
ttype: 'textarea',
|
||||||
|
tvalidate: { io: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
changed_date: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now,
|
||||||
|
tfield: {
|
||||||
|
tlist: { tenable: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created_date: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now,
|
||||||
|
tfield: {
|
||||||
|
tlist: { tenable: false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var modelSchemaBlogState = new mongoose.Schema(modelMetaBlogState);
|
||||||
|
modelSchemaBlogState.statics = tcrud.plugin.backend.mongoose.buildStaticsModelValidated(modelMetaBlogState,modelSchemaBlogState, {
|
||||||
|
findLastChangedLimit5: function (callback) {
|
||||||
|
log.debug(modelBackend+'.findLastChangedLimit5');
|
||||||
|
this.find({}).sort('-changed_date').limit(5).exec(callback);
|
||||||
|
},
|
||||||
|
findOneByName: function (name, callback) {
|
||||||
|
log.debug(modelBackend+'.findByName name='+name);
|
||||||
|
this.findOne({name:name}).exec(callback);
|
||||||
|
},
|
||||||
|
ensureExcists: function (name, type, defaultValue, description, callback) {
|
||||||
|
this.findOneByName(name, function(err, xprop) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (xprop == null) {
|
||||||
|
log.debug(modelBackend+'.getByName create name='+name+' defaultValue='+defaultValue);
|
||||||
|
var model = mongoose.model('blog-state');
|
||||||
|
xprop = new model();
|
||||||
|
xprop.name = name;
|
||||||
|
xprop.type = type;
|
||||||
|
xprop.value = defaultValue;
|
||||||
|
xprop.description = description;
|
||||||
|
xprop.save(function(err,xprop) {
|
||||||
|
if (callback) {
|
||||||
|
callback(err, xprop);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
log.debug(modelBackend+'.getByName fetched name='+name);
|
||||||
|
if (callback) {
|
||||||
|
callback(null, xprop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setByName: function (name, value, callback) {
|
||||||
|
this.findOneByName(name, function(err, xprop) {
|
||||||
|
if (err) { throw err }
|
||||||
|
log.debug(modelBackend+'.setByName name='+name+' valueNew='+value+' valueOld='+xprop.value);
|
||||||
|
xprop.value = value;
|
||||||
|
xprop.save(function(err) {
|
||||||
|
callback(err, xprop);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
incByName: function (name, callback) {
|
||||||
|
this.findOneByName(name, function(err, xprop) {
|
||||||
|
if (err) { throw err }
|
||||||
|
xprop.value++;
|
||||||
|
log.debug(modelBackend+'.incByName name='+name+' value='+xprop.value);
|
||||||
|
xprop.save(function(err) {
|
||||||
|
callback(err, xprop);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
60
example/lib/pg-moviedb.js
Normal file
60
example/lib/pg-moviedb.js
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
var pgDB = require('pg');
|
||||||
|
var pgDBNamed = require('node-postgres-named');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
setup: setup,
|
||||||
|
load: load
|
||||||
|
};
|
||||||
|
|
||||||
|
function load(tcrud) {
|
||||||
|
|
||||||
|
// Create backend with id and uri
|
||||||
|
tcrud.backend.database.loadPostgres('pg/moviedb','postgres://postgres:postgresql@localhost/moviedb',pgDB,pgDBNamed);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup(tcrud,tcrudModel) {
|
||||||
|
|
||||||
|
// Create tcrud models
|
||||||
|
var tc = tcrud.config;
|
||||||
|
var t = tc.createTEntityNode(tcrudModel,'moviedb');
|
||||||
|
t.tmeta.tmodel.tbackend = 'pg/moviedb';
|
||||||
|
|
||||||
|
// Define model and columns
|
||||||
|
var tCompany = tc.createTEntity(t,'company','company_id');
|
||||||
|
var tCompanyId = tc.createTField(tCompany,'company_id');
|
||||||
|
var tCompanyName = tc.createTField(tCompany,'name');
|
||||||
|
var tCompanyDateEst = tc.createTField(tCompany,'date_est');
|
||||||
|
var tCompanyRemarks = tc.createTField(tCompany,'remarks');
|
||||||
|
var tCompanyCountryId = tc.createTField(tCompany,'country_id');
|
||||||
|
|
||||||
|
var tCountry = tc.createTEntity(t,'country','country_id');
|
||||||
|
|
||||||
|
var tCountryCompany = tc.createTEntity(tCountry,'company','company_id');
|
||||||
|
var tCountryCompanyId = tc.createTField(tCountryCompany,'company_id');
|
||||||
|
var tCountryCompanyName = tc.createTField(tCountryCompany,'name');
|
||||||
|
var tCountryCompanyDateEst = tc.createTField(tCountryCompany,'date_est');
|
||||||
|
var tCountryCompanyRemarks = tc.createTField(tCountryCompany,'remarks');
|
||||||
|
var tCountryCompanyCountryId = tc.createTField(tCountryCompany,'country_id');
|
||||||
|
|
||||||
|
var tCountryId = tc.createTField(tCountry,'country_id');
|
||||||
|
var tCountryCode = tc.createTField(tCountry,'code');
|
||||||
|
var tCountryName = tc.createTField(tCountry,'name');
|
||||||
|
|
||||||
|
var tDirector = tc.createTEntity(t,'director','director_id');
|
||||||
|
var tDirectorId = tc.createTField(tDirector,'director_id');
|
||||||
|
var tDirectorDateBorn = tc.createTField(tDirector,'date_born');
|
||||||
|
var tDirectorDateDied = tc.createTField(tDirector,'date_died');
|
||||||
|
var tDirectorFirstName = tc.createTField(tDirector,'first_name');
|
||||||
|
var tDirectorLastName = tc.createTField(tDirector,'last_name');
|
||||||
|
|
||||||
|
var tGenre = tc.createTEntity(t,'genre','genre_id');
|
||||||
|
var tGenreId = tc.createTField(tGenre,'genre_id');
|
||||||
|
var tGenreCode = tc.createTField(tGenre,'code');
|
||||||
|
var tGenreName = tc.createTField(tGenre,'name');
|
||||||
|
|
||||||
|
tCompany.tmeta.tmenu.ticon='fa fa-building';
|
||||||
|
//tCountryCompany.tmeta.tmenu.ticon='fa fa-building';
|
||||||
|
tCountry.tmeta.tmenu.ticon='fa fa-globe';
|
||||||
|
tDirector.tmeta.tmenu.ticon='fa fa-cogs';
|
||||||
|
tGenre.tmeta.tmenu.ticon='fa fa-star';
|
||||||
|
}
|
31
example/lib/pg-pagila.js
Normal file
31
example/lib/pg-pagila.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
var pgDB = require('pg');
|
||||||
|
var pgDBNamed = require('node-postgres-named');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
load: load,
|
||||||
|
setup: setup
|
||||||
|
};
|
||||||
|
|
||||||
|
function load(tcrud) {
|
||||||
|
// Create backend with id and uri
|
||||||
|
tcrud.backend.database.loadPostgres('pg/pagila','postgres://postgres:postgresql@localhost/pagila',pgDB,pgDBNamed);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup(tcrud,tcrudModel) {
|
||||||
|
|
||||||
|
// Create tcrud models
|
||||||
|
var tc = tcrud.config;
|
||||||
|
var t = tc.createTEntityNode(tcrudModel,'pagila');
|
||||||
|
t.tmeta.tmodel.tbackend = 'pg/pagila';
|
||||||
|
|
||||||
|
// Define model and columns
|
||||||
|
var tLanguage = tc.createTEntity(t,'language','language_id');
|
||||||
|
var tLanguageId = tc.createTField(tLanguage,'language_id');
|
||||||
|
var tLanguageName = tc.createTField(tLanguage,'name');
|
||||||
|
var tLanguageLastUpdate = tc.createTField(tLanguage,'last_update');
|
||||||
|
|
||||||
|
var tCountry = tc.createTEntity(t,'country','country_id');
|
||||||
|
var tCountryId = tc.createTField(tCountry,'country_id');
|
||||||
|
var tCountryCountry = tc.createTField(tCountry,'country');
|
||||||
|
var tCountryLastUpdate = tc.createTField(tCountry,'last_update');
|
||||||
|
}
|
21
example/package.json
Normal file
21
example/package.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "node-ff-tcrud-example",
|
||||||
|
"description": "node-ff-tcrud-example",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "node example.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"cookie-parser": "^1.0.1",
|
||||||
|
"debug": "^2.2.0",
|
||||||
|
"express-winston": "0.3.1",
|
||||||
|
"static-favicon": "~1.0.0",
|
||||||
|
"winston": "~0.7.3",
|
||||||
|
"node-postgres-named": "^2.2.0",
|
||||||
|
"pg": "^4.4.0",
|
||||||
|
"mssql": "^2.1.6",
|
||||||
|
"mysql2": "^0.15.8",
|
||||||
|
"mongoose": "~3.8.13"
|
||||||
|
}
|
||||||
|
}
|
10
example/www_views/js/page-bar.ejs
Normal file
10
example/www_views/js/page-bar.ejs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
pageRouteInit.push(function ($routeProvider, $locationProvider) {
|
||||||
|
$routeProvider.when('/ui/bar', {
|
||||||
|
templateUrl: '/ui/thtml/bar',
|
||||||
|
controller: PageFoo
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function PageFoo($scope, $http) {
|
||||||
|
}
|
10
example/www_views/js/page-foo.ejs
Normal file
10
example/www_views/js/page-foo.ejs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
pageRouteInit.push(function ($routeProvider, $locationProvider) {
|
||||||
|
$routeProvider.when('/ui/foo', {
|
||||||
|
templateUrl: '/ui/thtml/foo',
|
||||||
|
controller: PageFoo
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function PageFoo($scope, $http) {
|
||||||
|
}
|
10
example/www_views/js/page-home.ejs
Normal file
10
example/www_views/js/page-home.ejs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
pageRouteInit.push(function ($routeProvider, $locationProvider) {
|
||||||
|
$routeProvider.when('/ui', {
|
||||||
|
templateUrl: '/ui/thtml/home',
|
||||||
|
controller: PageHome
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function PageHome($scope, $http) {
|
||||||
|
}
|
4
example/www_views/thtml/bar.ejs
Normal file
4
example/www_views/thtml/bar.ejs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<div>
|
||||||
|
<h2>Bar</h2>
|
||||||
|
<p>Welcome to the bar.</p>
|
||||||
|
</div>
|
4
example/www_views/thtml/foo.ejs
Normal file
4
example/www_views/thtml/foo.ejs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<div>
|
||||||
|
<h2>Foo</h2>
|
||||||
|
<p>Welcome to the foo.</p>
|
||||||
|
</div>
|
4
example/www_views/thtml/home.ejs
Normal file
4
example/www_views/thtml/home.ejs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<div>
|
||||||
|
<h2>Example UI Index</h2>
|
||||||
|
<p>Welcome make yourself at home.</p>
|
||||||
|
</div>
|
247
lib/backend/database.js
Normal file
247
lib/backend/database.js
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
var tcrudSetup = require('./../tcrud-setup');
|
||||||
|
var debug = require('debug')('ff:tcrud:backend:database');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
loadModule: function(key,dbModule) {
|
||||||
|
tcrudSetup.pluginLoad(new DatabasePlugin(key,dbModule));
|
||||||
|
},
|
||||||
|
loadPostgres: function(key,dbUri,pgDB,pgDBNamed) {
|
||||||
|
tcrudSetup.pluginLoad(new DatabasePlugin(key,new PostgresModule(dbUri,pgDB,pgDBNamed)));
|
||||||
|
},
|
||||||
|
loadMysql2: function(key,pool) {
|
||||||
|
tcrudSetup.pluginLoad(new DatabasePlugin(key,new Mysql2Module(pool)));
|
||||||
|
},
|
||||||
|
loadMssql: function(key,driver,conn) {
|
||||||
|
tcrudSetup.pluginLoad(new DatabasePlugin(key,new MssqlModule(driver,conn)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------- PostgresModule Object
|
||||||
|
|
||||||
|
function PostgresModule(dbUri,pgDB,pgDBNamed) {
|
||||||
|
this.dbUri = dbUri;
|
||||||
|
this.pgDB = pgDB;
|
||||||
|
this.pgDBNamed = pgDBNamed;
|
||||||
|
}
|
||||||
|
PostgresModule.prototype.query = function(sqlQuery,params, cb) {
|
||||||
|
var self = this;
|
||||||
|
self.pgDB.connect(self.dbUri, function(err, client, done) {
|
||||||
|
self.pgDBNamed.patch(client);
|
||||||
|
client.query(sqlQuery, params, function(err, result) {
|
||||||
|
done(); // release client from pool
|
||||||
|
cb(err,result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function Mysql2Module(pool) {
|
||||||
|
this.pool = pool;
|
||||||
|
}
|
||||||
|
Mysql2Module.prototype.query = function(sqlQuery,params, cb) {
|
||||||
|
var self = this;
|
||||||
|
self.pool.getConnection(function(err, connection) {
|
||||||
|
connection.config.namedPlaceholders = true;
|
||||||
|
connection.execute(sqlQuery,params, function(err, rows) {
|
||||||
|
connection.release();
|
||||||
|
cb(err,rows);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function MssqlModule(driver,conn) {
|
||||||
|
this.driver = driver;
|
||||||
|
this.conn = conn;
|
||||||
|
}
|
||||||
|
MssqlModule.prototype.query = function(sqlQuery,params, cb) {
|
||||||
|
var self = this;
|
||||||
|
var request = new self.driver.Request(self.conn);
|
||||||
|
request.query(sqlQuery,params,function(err, rows) {
|
||||||
|
cb(err,rows);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//------- DatabasePlugin Object
|
||||||
|
|
||||||
|
function DatabasePlugin(key,dbModule) {
|
||||||
|
this.key = key;
|
||||||
|
this.dbModule = dbModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabasePlugin.prototype.configPlugin = function (ctx) {
|
||||||
|
ctx.key='db#'+this.key;
|
||||||
|
ctx.description='Database api adapter for '+this.key;
|
||||||
|
};
|
||||||
|
|
||||||
|
DatabasePlugin.prototype.createBackend = function() {
|
||||||
|
return new DatabaseBackend(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabasePlugin.prototype.query = function(sqlQuery,params, cb) {
|
||||||
|
this.dbModule.query(sqlQuery,params,cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- DatabaseBackend
|
||||||
|
|
||||||
|
function findKeysView(tview) {
|
||||||
|
return tview.tkeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findKeysModel(tview) {
|
||||||
|
return tview.tmeta.tmodel.tkeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectField(tview,crudType) {
|
||||||
|
var result = [];
|
||||||
|
tview[crudType].tfields.forEach(function (tfieldKey) {
|
||||||
|
var tfield = tview.tmeta.tfields[tfieldKey];
|
||||||
|
result.push(tfield.tid);
|
||||||
|
});
|
||||||
|
var resultSql = '';
|
||||||
|
for (var i = 0; i < result.length; i++) {
|
||||||
|
var key = result[i];
|
||||||
|
resultSql += key;
|
||||||
|
if (i < (result.length - 1)) {
|
||||||
|
resultSql += ',';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
function whereKeys(tview) {
|
||||||
|
var resultSql = '';
|
||||||
|
for (var i = 0; i < tview.tmeta.tmodel.tkeys.length; i++) {
|
||||||
|
var key = tview.tmeta.tmodel.tkeys[i];
|
||||||
|
//resultSql += key +' = $'+(i+1);
|
||||||
|
resultSql += key +' = $'+key;
|
||||||
|
if (i < (tview.tmeta.tmodel.tkeys.length - 1)) {
|
||||||
|
resultSlug += ' AND ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateValues(tview,data) {
|
||||||
|
var resultSql = 'SET ';
|
||||||
|
var dataKeys = Object.keys(data);
|
||||||
|
for (var i = 0; i < dataKeys.length; i++) {
|
||||||
|
var key = dataKeys[i];
|
||||||
|
|
||||||
|
var skip = false;
|
||||||
|
for (var ii = 0; ii < tview.tmeta.tmodel.tkeys.length; ii++) {
|
||||||
|
var keyPK = tview.tmeta.tmodel.tkeys[ii];
|
||||||
|
if (key === keyPK) {
|
||||||
|
skip = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (skip === true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
resultSql += key +' = $'+key;
|
||||||
|
if (i < (dataKeys.length - 1)) {
|
||||||
|
resultSql += ',';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
function DatabaseBackend(plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseBackend.prototype.getKey = function() {
|
||||||
|
return this.plugin.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseBackend.prototype.findAll = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'SELECT '+selectField(tview,crudType)+' FROM '+tview.tmeta.tmodel.tid+'';
|
||||||
|
debug('findAll %s',querySql);
|
||||||
|
var query = self.plugin.query(querySql,[],function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseBackend.prototype.createNew = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseBackend.prototype.findOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'SELECT '+selectField(tview,crudType)+' FROM '+tview.tmeta.tmodel.tid+' WHERE '+whereKeys(tview)+'';
|
||||||
|
debug('findOne param %s',JSON.stringify(dataParam));
|
||||||
|
debug('findOne sql %s',querySql);
|
||||||
|
var query = self.plugin.query(querySql, dataParam, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseBackend.prototype.updateOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'UPDATE '+tview.tmeta.tmodel.tid+' '+updateValues(tview,data)+' WHERE '+whereKeys(tview);
|
||||||
|
debug('updateOne param %s',JSON.stringify(dataParam));
|
||||||
|
debug('updateOne data %s',JSON.stringify(data));
|
||||||
|
debug('updateOne sql %s',querySql);
|
||||||
|
var query = self.plugin.query(querySql, data, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseBackend.prototype.deleteOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'DELETE FROM '+tview.tmeta.tmodel.tid+' WHERE '+whereKeys(tview);
|
||||||
|
debug('deleteOne param %s',JSON.stringify(dataParam));
|
||||||
|
debug('deleteOne sql %s',querySql);
|
||||||
|
var query = self.plugin.query(querySql, dataParam, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseBackend.prototype.findAllCount = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'SELECT count(*) FROM '+tview.tmeta.tmodel.tid; //+' WHERE '+whereKeys(tview);
|
||||||
|
debug('findAllCount param %s',JSON.stringify(dataParam));
|
||||||
|
debug('findAllCount sql %s',querySql);
|
||||||
|
var query = self.plugin.query(querySql, dataParam, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
150
lib/backend/ldapjs.js
Normal file
150
lib/backend/ldapjs.js
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
var config = require('./../tcrud-config');
|
||||||
|
var debug = require('debug')('ff:tcrud:ldapjs');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
registrate: function(key,client) {
|
||||||
|
config.registratePlugin(new LdapJSPlugin(key,client));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------- LdapJSPlugin Object
|
||||||
|
|
||||||
|
function LdapJSPlugin(key,client) {
|
||||||
|
this.key = key;
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
LdapJSPlugin.prototype.configPlugin = function (ctx) {
|
||||||
|
ctx.key='ldapjs#'+this.key;
|
||||||
|
ctx.description='Adds ldap backend support.';
|
||||||
|
};
|
||||||
|
|
||||||
|
LdapJSPlugin.prototype.createBackend = function() {
|
||||||
|
return new LdapJSBackend(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- LdapJSBackend Object
|
||||||
|
|
||||||
|
function LdapJSBackend(plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
LdapJSBackend.prototype.getKey = function() {
|
||||||
|
return this.plugin.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
LdapJSBackend.prototype.findAll = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var opts = {
|
||||||
|
filter: '(&(l=Seattle)(email=*@foo.com))',
|
||||||
|
scope: 'sub'
|
||||||
|
};
|
||||||
|
debug('findAll %s',opts);
|
||||||
|
self.plugin.client.search('o=example', opts, function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//var querySql = 'SELECT '+selectField(tview,crudType)+' FROM '+tview.tmeta.tmodel.tid+'';
|
||||||
|
var result = [];
|
||||||
|
res.on('searchEntry', function(entry) {
|
||||||
|
result.push(entry);
|
||||||
|
});
|
||||||
|
res.on('end', function(result) {
|
||||||
|
cb(err,result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
LdapJSBackend.prototype.createNew = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var entry = {
|
||||||
|
cn: 'foo',
|
||||||
|
sn: 'bar',
|
||||||
|
email: ['foo@bar.com', 'foo1@bar.com'],
|
||||||
|
objectclass: 'fooPerson'
|
||||||
|
};
|
||||||
|
self.plugin.client.add('cn=foo, o=example', entry, function(err) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
LdapJSBackend.prototype.findOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'SELECT '+selectField(tview,crudType)+' FROM '+tview.tmeta.tmodel.tid+' WHERE '+whereKeys(tview)+'';
|
||||||
|
debug('findOne param %s',JSON.stringify(dataParam));
|
||||||
|
debug('findOne sql %s',querySql);
|
||||||
|
var query = self.db.query(querySql, dataParam, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
LdapJSBackend.prototype.updateOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'UPDATE '+tview.tmeta.tmodel.tid+' '+updateValues(tview,data)+' WHERE '+whereKeys(tview);
|
||||||
|
debug('updateOne param %s',JSON.stringify(dataParam));
|
||||||
|
debug('updateOne data %s',JSON.stringify(data));
|
||||||
|
debug('updateOne sql %s',querySql);
|
||||||
|
var query = self.db.query(querySql, data, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
LdapJSBackend.prototype.deleteOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'DELETE FROM '+tview.tmeta.tmodel.tid+' WHERE '+whereKeys(tview);
|
||||||
|
debug('deleteOne param %s',JSON.stringify(dataParam));
|
||||||
|
debug('deleteOne sql %s',querySql);
|
||||||
|
var query = self.db.query(querySql, dataParam, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
LdapJSBackend.prototype.findAllCount = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'SELECT count(*) FROM '+tview.tmeta.tmodel.tid+' WHERE '+whereKeys(tview);
|
||||||
|
debug('findAllCount param %s',JSON.stringify(dataParam));
|
||||||
|
debug('findAllCount sql %s',querySql);
|
||||||
|
var query = self.db.query(querySql, dataParam, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
127
lib/backend/mongo.js
Normal file
127
lib/backend/mongo.js
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
var config = require('./../tcrud-config');
|
||||||
|
var debug = require('debug')('ff:tcrud:mongo');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
registrate: function(key,server) {
|
||||||
|
config.registratePlugin(new MongoPlugin(key,server));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------- MongoPlugin Object
|
||||||
|
|
||||||
|
function MongoPlugin(key,server) {
|
||||||
|
this.key = key;
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoPlugin.prototype.configPlugin = function (ctx) {
|
||||||
|
ctx.key='mongo#'+this.key;
|
||||||
|
ctx.description='Adds mongo backend support.';
|
||||||
|
};
|
||||||
|
|
||||||
|
MongoPlugin.prototype.createBackend = function() {
|
||||||
|
return new MongoBackend(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- MongoBackend
|
||||||
|
|
||||||
|
function MongoBackend(plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoBackend.prototype.getKey = function() {
|
||||||
|
return this.plugin.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoBackend.prototype.findAll = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'SELECT '+selectField(tview,crudType)+' FROM '+tview.tmeta.tmodel.tid+'';
|
||||||
|
debug('findAll %s',querySql);
|
||||||
|
var query = self.db.query(querySql,[],function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoBackend.prototype.createNew = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoBackend.prototype.findOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'SELECT '+selectField(tview,crudType)+' FROM '+tview.tmeta.tmodel.tid+' WHERE '+whereKeys(tview)+'';
|
||||||
|
debug('findOne param %s',JSON.stringify(dataParam));
|
||||||
|
debug('findOne sql %s',querySql);
|
||||||
|
var query = self.db.query(querySql, dataParam, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoBackend.prototype.updateOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'UPDATE '+tview.tmeta.tmodel.tid+' '+updateValues(tview,data)+' WHERE '+whereKeys(tview);
|
||||||
|
debug('updateOne param %s',JSON.stringify(dataParam));
|
||||||
|
debug('updateOne data %s',JSON.stringify(data));
|
||||||
|
debug('updateOne sql %s',querySql);
|
||||||
|
var query = self.db.query(querySql, data, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoBackend.prototype.deleteOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'DELETE FROM '+tview.tmeta.tmodel.tid+' WHERE '+whereKeys(tview);
|
||||||
|
debug('deleteOne param %s',JSON.stringify(dataParam));
|
||||||
|
debug('deleteOne sql %s',querySql);
|
||||||
|
var query = self.db.query(querySql, dataParam, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoBackend.prototype.findAllCount = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
var querySql = 'SELECT count(*) FROM '+tview.tmeta.tmodel.tid+' WHERE '+whereKeys(tview);
|
||||||
|
debug('findAllCount param %s',JSON.stringify(dataParam));
|
||||||
|
debug('findAllCount sql %s',querySql);
|
||||||
|
var query = self.db.query(querySql, dataParam, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
271
lib/backend/mongoose.js
Normal file
271
lib/backend/mongoose.js
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
var config = require('./../tcrud-config');
|
||||||
|
var debug = require('debug')('ff:tcrud:mongoose');
|
||||||
|
var clone = require('clone');
|
||||||
|
var validate = require('validate.io');
|
||||||
|
|
||||||
|
// ------- MongoosePlugin Object
|
||||||
|
|
||||||
|
function MongoosePlugin(key,conn) {
|
||||||
|
this.key = key;
|
||||||
|
this.conn = conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
MongoosePlugin.prototype.configPlugin = function (ctx) {
|
||||||
|
ctx.key='mongoose#'+this.key;
|
||||||
|
ctx.description='Adds ldap backend support.';
|
||||||
|
};
|
||||||
|
|
||||||
|
MongoosePlugin.prototype.createBackend = function() {
|
||||||
|
return new MongooseBackend(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------- MongooseBackend Object
|
||||||
|
|
||||||
|
function MongooseBackend(plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
MongooseBackend.prototype.getKey = function() {
|
||||||
|
return this.plugin.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
MongooseBackend.prototype.findAll = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
debug('find all..'+tview.tmeta.tmodel.tid);
|
||||||
|
var model = self.plugin.conn.model(tview.tmeta.tmodel.tid);
|
||||||
|
model.find({},function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// cb();
|
||||||
|
// var querySql = 'SELECT '+selectField(tview,crudType)+' FROM '+tview.tmeta.tmodel.tid+'';
|
||||||
|
// debug('findAll %s',querySql);
|
||||||
|
// var query = self.db.query(querySql,[],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MongooseBackend.prototype.createNew = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MongooseBackend.prototype.findOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
debug('findOne param %s',JSON.stringify(dataParam));
|
||||||
|
//debug('findOne sql %s',querySql);
|
||||||
|
var model = self.plugin.conn.model(tview.tmeta.tmodel.tid);
|
||||||
|
model.findById(dataParam,function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// var querySql = 'SELECT '+selectField(tview,crudType)+' FROM '+tview.tmeta.tmodel.tid+' WHERE '+whereKeys(tview)+'';
|
||||||
|
//
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MongooseBackend.prototype.updateOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
debug('updateOne param %s',JSON.stringify(dataParam));
|
||||||
|
debug('updateOne data %s',JSON.stringify(data));
|
||||||
|
var model = self.plugin.conn.model(tview.tmeta.tmodel.tid);
|
||||||
|
model.save(data,function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
debug(err);
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(err,result.rows);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// var querySql = 'UPDATE '+tview.tmeta.tmodel.tid+' '+updateValues(tview,data)+' WHERE '+whereKeys(tview);
|
||||||
|
//
|
||||||
|
// debug('updateOne sql %s',querySql);
|
||||||
|
// var query = self.db.query(querySql, data, function (err, result) {
|
||||||
|
// if (err) {
|
||||||
|
// debug(err);
|
||||||
|
// cb(err);
|
||||||
|
// } else {
|
||||||
|
// cb(err,result.rows[0]);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MongooseBackend.prototype.deleteOne = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
// var querySql = 'DELETE FROM '+tview.tmeta.tmodel.tid+' WHERE '+whereKeys(tview);
|
||||||
|
// debug('deleteOne param %s',JSON.stringify(dataParam));
|
||||||
|
// debug('deleteOne sql %s',querySql);
|
||||||
|
// var query = self.db.query(querySql, dataParam, function (err, result) {
|
||||||
|
// if (err) {
|
||||||
|
// debug(err);
|
||||||
|
// cb(err);
|
||||||
|
// } else {
|
||||||
|
// cb(err,result.rows[0]);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MongooseBackend.prototype.findAllCount = function(tview,crudType) {
|
||||||
|
var self = this;
|
||||||
|
return function(data, dataParam, cb) {
|
||||||
|
// var querySql = 'SELECT count(*) FROM '+tview.tmeta.tmodel.tid+' WHERE '+whereKeys(tview);
|
||||||
|
// debug('findAllCount param %s',JSON.stringify(dataParam));
|
||||||
|
// debug('findAllCount sql %s',querySql);
|
||||||
|
// var query = self.db.query(querySql, dataParam, function (err, result) {
|
||||||
|
// if (err) {
|
||||||
|
// debug(err);
|
||||||
|
// cb(err);
|
||||||
|
// } else {
|
||||||
|
// cb(err,result.rows[0]);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function autoFieldType(fieldMeta,fieldType) {
|
||||||
|
if (!fieldMeta) {
|
||||||
|
throw new Error('no fieldMeta');
|
||||||
|
}
|
||||||
|
if (fieldType && fieldType.length != 0) {
|
||||||
|
return fieldType;
|
||||||
|
}
|
||||||
|
if (fieldMeta.type == Date) {
|
||||||
|
return 'date';
|
||||||
|
}
|
||||||
|
return 'text';
|
||||||
|
}
|
||||||
|
|
||||||
|
buildFields = function(modelMeta) {
|
||||||
|
if (!modelMeta) {
|
||||||
|
throw new Error('no modelMeta');
|
||||||
|
}
|
||||||
|
var tfields = {};
|
||||||
|
var keys = Object.keys(modelMeta);
|
||||||
|
for (i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var value = modelMeta[key];
|
||||||
|
var tfield = null;
|
||||||
|
if (key && value && value.tfield) {
|
||||||
|
debug('tfield model cloned');
|
||||||
|
tfield = clone(value.tfield);
|
||||||
|
tfield.tid = key;
|
||||||
|
tfield.tname = tfield.tname;
|
||||||
|
tfield.type = autoFieldType(value,tfield.ttype);
|
||||||
|
} else if (key && value) {
|
||||||
|
debug('tfield model auto created');
|
||||||
|
tfield = config.createTField(key);
|
||||||
|
tfield.type = autoFieldType(value);
|
||||||
|
}
|
||||||
|
if (tfield.tvalidate && tfield.tvalidate.io) {
|
||||||
|
debug('tfield validate rule: '+tfield.tvalidate.io);
|
||||||
|
}
|
||||||
|
tfields[tfield.tid] = tfield;
|
||||||
|
}
|
||||||
|
return tfields;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ss(valueRule) {
|
||||||
|
return function (value, response) {
|
||||||
|
response(validate(valueRule,value));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
createModelValidators = function (modelSchema,modelFields) {
|
||||||
|
if (!modelSchema) {
|
||||||
|
throw new Error('no modelSchema');
|
||||||
|
}
|
||||||
|
if (!modelFields) {
|
||||||
|
throw new Error('no modelFields');
|
||||||
|
}
|
||||||
|
var keys = Object.keys(modelFields);
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var tfield = modelFields[key];
|
||||||
|
if (!tfield.tvalidate) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!tfield.tvalidate.io) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
modelSchema.path(tfield.tid).validate(ss(tfield.tvalidate.io), '{PATH} validation failed: '+tfield.tvalidate.io);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildStatics = function(modelFields,modelStatics) {
|
||||||
|
if (!modelFields) {
|
||||||
|
throw new Error('no modelFields');
|
||||||
|
}
|
||||||
|
if (!modelStatics) {
|
||||||
|
modelStatics = {};
|
||||||
|
}
|
||||||
|
modelStatics['ff_tcrud_fields'] = modelFields;
|
||||||
|
return modelStatics;
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTEntityModel = function(mongoose,tcrudParent,name) {
|
||||||
|
var model = mongoose.model(name);
|
||||||
|
var tcrud = config.createTEntity(tcrudParent,name, '_id');
|
||||||
|
var tfields = model['ff_tcrud_fields'];
|
||||||
|
if (tfields) {
|
||||||
|
tcrud.tmeta.tfields = tfields;
|
||||||
|
}
|
||||||
|
tcrud.tmodel = name;
|
||||||
|
|
||||||
|
return tcrud;
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTEntityModels = function(conn,tcrudParent) {
|
||||||
|
var result = [];
|
||||||
|
var modelNames = conn.modelNames();
|
||||||
|
for (var i = 0; i < modelNames.length; i++) {
|
||||||
|
result.push(buildTEntityModel(conn,tcrudParent,modelNames[i]))
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----- wrappers
|
||||||
|
|
||||||
|
buildStaticsModel = function(modelMeta,modelStatics) {
|
||||||
|
return buildStatics(buildFields(modelMeta),modelStatics);
|
||||||
|
}
|
||||||
|
|
||||||
|
buildStaticsModelValidated = function(modelMeta,modelSchema,modelStatics) {
|
||||||
|
var modelFields = buildFields(modelMeta);
|
||||||
|
createModelValidators(modelSchema,modelFields);
|
||||||
|
return buildStatics(modelFields,modelStatics);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
buildTEntityModels: buildTEntityModels,
|
||||||
|
buildStaticsModelValidated: buildStaticsModelValidated,
|
||||||
|
buildFields: buildFields,
|
||||||
|
registrate: function(key,conn) {
|
||||||
|
config.registratePlugin(new MongoosePlugin(key,conn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
261
lib/build-server-api-tentity.js
Normal file
261
lib/build-server-api-tentity.js
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
var debug = require('debug')('ff:tcrud:build:server:api:tentity');
|
||||||
|
var fs = require('fs');
|
||||||
|
var ejs = require('ejs');
|
||||||
|
var ncrud = require('node-crud');
|
||||||
|
var configTCrud = require('./tcrud-config');
|
||||||
|
var configRegistry = require('./config-registry');
|
||||||
|
var buildServerApiUrl = require('./build-server-api-url');
|
||||||
|
var buildServerExpress = require('./build-server-express');
|
||||||
|
var _ = require('underscore');
|
||||||
|
|
||||||
|
var mod = (function () {
|
||||||
|
|
||||||
|
var renderTemplateDataRead = function(tview, exportType, contentType) {
|
||||||
|
return function(data, query, cb) {
|
||||||
|
var res = this.response;
|
||||||
|
res.set('Content-Type', contentType);
|
||||||
|
|
||||||
|
//var templateReadHeader = fs.readFileSync('www_views/node-ff-tcrud/'+exportType+'/read-header.ejs', 'utf8');
|
||||||
|
var templateReadRecord = fs.readFileSync('./../lib/www_views/node-ff-tcrud/'+exportType+'/read-record.ejs', 'utf8');
|
||||||
|
//var templateReadFooter = fs.readFileSync('www_views/node-ff-tcrud/'+exportType+'/read-footer.ejs', 'utf8');
|
||||||
|
|
||||||
|
//var result = ejs.render(templateHeader,{
|
||||||
|
// tview: tview,
|
||||||
|
//});
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
var row = data[i];
|
||||||
|
result += ejs.render(templateRecord,{
|
||||||
|
tview: tview,
|
||||||
|
record: row,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//result +=ejs.render(templateFooter,{
|
||||||
|
// tview: tview,
|
||||||
|
//});
|
||||||
|
res.write(result);
|
||||||
|
res.end();
|
||||||
|
this.close(); // end chain (cb set headers)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var renderTemplateDataList = function(tview, exportType, contentType) {
|
||||||
|
return function(data, query, cb) {
|
||||||
|
var res = this.response;
|
||||||
|
//res.set('Content-Type', contentType);
|
||||||
|
|
||||||
|
var templateHeader = fs.readFileSync('./../lib/www_views/node-ff-tcrud/'+exportType+'/list-header.ejs', 'utf8');
|
||||||
|
var templateRecord = fs.readFileSync('./../lib/www_views/node-ff-tcrud/'+exportType+'/list-record.ejs', 'utf8');
|
||||||
|
var templateFooter = fs.readFileSync('./../lib/www_views/node-ff-tcrud/'+exportType+'/list-footer.ejs', 'utf8');
|
||||||
|
|
||||||
|
var result = ejs.render(templateHeader,{
|
||||||
|
tview: tview,
|
||||||
|
});
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
var row = data[i];
|
||||||
|
result += ejs.render(templateRecord,{
|
||||||
|
tview: tview,
|
||||||
|
record: row,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
result +=ejs.render(templateFooter,{
|
||||||
|
tview: tview,
|
||||||
|
});
|
||||||
|
res.write(result);
|
||||||
|
res.end();
|
||||||
|
this.close(); // end chain (cb set headers)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var filterQueryList = function (model) {
|
||||||
|
return mcrud.parseQuery()
|
||||||
|
.defaults({ limit: '10' })
|
||||||
|
.overrides({})
|
||||||
|
.maxes({ limit: 1000 });
|
||||||
|
//.removes()
|
||||||
|
};
|
||||||
|
|
||||||
|
var filterDataUpdate = function (model) {
|
||||||
|
return mcrud.parseData()
|
||||||
|
overrides({});
|
||||||
|
//.removes('auth')
|
||||||
|
//.overrides({ updated: Date.now })
|
||||||
|
//.defaults({ 'info.gender': 'M' }))
|
||||||
|
};
|
||||||
|
|
||||||
|
function allowCrudType(tview,tcrudType) {
|
||||||
|
return tview[tcrudType].tenable; // todo add roles
|
||||||
|
};
|
||||||
|
|
||||||
|
var createMethodObject = function (entityObject,httpMethod) {
|
||||||
|
if ('GET' === httpMethod) {
|
||||||
|
return entityObject.Read();
|
||||||
|
} else if ('POST' === httpMethod) {
|
||||||
|
return entityObject.Create();
|
||||||
|
} else if ('PUT' === httpMethod) {
|
||||||
|
return entityObject.Update();
|
||||||
|
} else if ('DELETE' === httpMethod) {
|
||||||
|
return entityObject.Delete();
|
||||||
|
} else {
|
||||||
|
throw 'unknown httpMethod: '+httpMethod;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var createMethodExport = function (ctx,crudType,backendPipe,keySlug,exportMethod,exportMethodPre,exportMethodUse) {
|
||||||
|
var plugin = ctx.tplugin;
|
||||||
|
if (plugin[exportMethod] && allowCrudType(ctx.tview,crudType)) {
|
||||||
|
var apiUrl = buildServerApiUrl.createSlugApiTEntity(plugin.tmeta.key,ctx.tview,crudType) + keySlug;
|
||||||
|
var entityObject = ncrud.entity(apiUrl);
|
||||||
|
for (var ii = 0; ii < ctx.tview[crudType].tmethods.length; ii++) {
|
||||||
|
var httpMethod = ctx.tview[crudType].tmethods[ii];
|
||||||
|
var methodObject = createMethodObject(entityObject,httpMethod);
|
||||||
|
debug(plugin.tmeta.key+'.'+httpMethod+' for: '+crudType);
|
||||||
|
if (plugin[exportMethodUse]) {
|
||||||
|
methodObject.use(plugin[exportMethodUse](ctx));
|
||||||
|
}
|
||||||
|
//methodObject.pipe(filterQueryList(model))
|
||||||
|
//methodObject.pipe(filterDateUpdate(model))
|
||||||
|
if (plugin[exportMethodPre]) {
|
||||||
|
methodObject.pipe(plugin[exportMethodPre](ctx));
|
||||||
|
}
|
||||||
|
methodObject.pipe(backendPipe);
|
||||||
|
methodObject.pipe(plugin[exportMethod](ctx));
|
||||||
|
|
||||||
|
methodObject.on('close', function(event) {
|
||||||
|
debug('event close: '+event)
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.tplugin['troutes'].push({
|
||||||
|
urlPath: ctx.tview.tmeta.tserver.tslugs.tbase + '/' + apiUrl,
|
||||||
|
httpMethod: httpMethod
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var registrateMenu2 = function(menu,key) {
|
||||||
|
if (menu['items'] === undefined) {
|
||||||
|
menu['items'] = [];
|
||||||
|
}
|
||||||
|
configRegistry.getMasterConfig().rootTMenu[key] = menu; // TODO; move to reg
|
||||||
|
};
|
||||||
|
|
||||||
|
var buildCrud = function (server,tcrud) {
|
||||||
|
|
||||||
|
if (!tcrud.tenable) {
|
||||||
|
debug('skip tentity by tenable: %s',tcrud.tid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var tview = configTCrud.createTView(tcrud /*, fetchCrudRoles()*/);
|
||||||
|
|
||||||
|
if (tview.tmeta.tmenu.tenable && tview.tmeta.tmenu.tkey !== null && tview.tmeta.tmenu.titem === false) {
|
||||||
|
registrateMenu2({
|
||||||
|
name: tview.tmeta.tmenu.tname,
|
||||||
|
icon: tview.tmeta.tmenu.ticon
|
||||||
|
},tview.tmeta.tmenu.tkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tview.tmeta.tmodel.tbackend) {
|
||||||
|
debug('skip tentity no backend: %s',tcrud.tid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!tview.tmeta.tmodel.tid) {
|
||||||
|
debug('skip tentity no model: %s',tcrud.tid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var backend = configTCrud.getBackend(tview.tmeta.tmodel.tbackend);
|
||||||
|
if (!backend) {
|
||||||
|
debug('skip tentity illegal backend: %s',tcrud.tid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var keySlug = '/'+tview.tmeta.tmodel.tkey; // TODO: remove me
|
||||||
|
for (var i = 0; i < configRegistry.getMasterConfig().plugins.length; i++) {
|
||||||
|
var plugin = configRegistry.getMasterConfig().plugins[i];
|
||||||
|
var pluginKey = plugin.tmeta.key;
|
||||||
|
if (!_.contains(tview.tmeta.tserver.tformats,pluginKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctx = {
|
||||||
|
tplugin: plugin,
|
||||||
|
tview: tview,
|
||||||
|
createSlugApiTEntityBasePlugin: function(key,postfix) {
|
||||||
|
return buildServerApiUrl.createSlugApiTEntityBase(key,ctx.tview,postfix);
|
||||||
|
},
|
||||||
|
createSlugApiTEntityBase: function(postfix) {
|
||||||
|
return buildServerApiUrl.createSlugApiTEntityBase(pluginKey,ctx.tview,postfix); //createSlugApiTEntity: buildServerUrl.createSlugApiTEntity,
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTemplateDataList: function(contentType) {
|
||||||
|
return renderTemplateDataList(ctx.tview,pluginKey,contentType);
|
||||||
|
},
|
||||||
|
renderTemplateDataRead: function(contentType) {
|
||||||
|
return renderTemplateDataRead(ctx.tview,pluginKey,contentType);
|
||||||
|
},
|
||||||
|
|
||||||
|
registrateMenu: function(menu,key) {
|
||||||
|
if (menu['items'] === undefined) {
|
||||||
|
menu['items'] = [];
|
||||||
|
}
|
||||||
|
configRegistry.getMasterConfig().rootTMenu[key] = menu;
|
||||||
|
},
|
||||||
|
registrateMenuItem: function(menuItem,key) {
|
||||||
|
if (configRegistry.getMasterConfig().rootTMenu[key] === undefined) {
|
||||||
|
return; // sub tentities
|
||||||
|
}
|
||||||
|
configRegistry.getMasterConfig().rootTMenu[key].items.push(menuItem);
|
||||||
|
},
|
||||||
|
|
||||||
|
registrateClientJSResource: function(clientResource) {
|
||||||
|
configRegistry.registrateClientResource(clientResource,'js');
|
||||||
|
},
|
||||||
|
registrateClientCSSResource: function(clientResource) {
|
||||||
|
configRegistry.registrateClientResource(clientResource,'css'); // +data or rm others
|
||||||
|
},
|
||||||
|
renderFunctionJSON: buildServerExpress.renderFunctionJSON,
|
||||||
|
server: server
|
||||||
|
}
|
||||||
|
if (plugin.configApi) {
|
||||||
|
debug(pluginKey+'.configApi(tview='+tview.tid+',backend='+tview.tmeta.tmodel.tbackend+')');
|
||||||
|
plugin.configApi(ctx);
|
||||||
|
}
|
||||||
|
createMethodExport(ctx,'tlist', backend.findAll(tview, 'tlist'), '', 'configApiTListExport', 'configApiTListExportPre', 'configApiTListExportUse');
|
||||||
|
createMethodExport(ctx,'tcreate', backend.createNew(tview, 'tcreate'), '', 'configApiTCreateExport', 'configApiTCreateExportPre', 'configApiTCreateExportUse');
|
||||||
|
createMethodExport(ctx,'tread', backend.findOne(tview, 'tread'), keySlug, 'configApiTReadExport', 'configApiTReadExportPre', 'configApiTReadExportUse');
|
||||||
|
createMethodExport(ctx,'tedit', backend.updateOne(tview, 'tedit'), keySlug, 'configApiTEditExport', 'configApiTEditExportPre', 'configApiTEditExportUse');
|
||||||
|
createMethodExport(ctx,'tdelete', backend.deleteOne(tview, 'tdelete'), keySlug, 'configApiTDeleteExport', 'configApiTDeleteExportPre', 'configApiTDeleteExportUse');
|
||||||
|
createMethodExport(ctx,'tcount', backend.findAllCount(tview,'tcount'), '', 'configApiTCountExport', 'configApiTCountExportPre', 'configApiTCountExportUse');
|
||||||
|
|
||||||
|
if (allowCrudType(tview,'tverify')) {
|
||||||
|
debug('todo verift');
|
||||||
|
//ncrud.entity(buildView.createBaseApiUri(tview,'json','tverify') + '/:_id').Update()
|
||||||
|
// .pipe(mcrud.findOne(model));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function walkTEntityTree(server,tentity) {
|
||||||
|
if (tentity.tparent) { // TODO: move skip root node
|
||||||
|
buildCrud(server,tentity);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < tentity.tchilds.length; i++) {
|
||||||
|
walkTEntityTree(server,tentity.tchilds[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return function BuildServerApiTEntity() {
|
||||||
|
|
||||||
|
this.build = function(server) {
|
||||||
|
debug('buildServerApiTEntity');
|
||||||
|
configRegistry.assertPhaseServer();
|
||||||
|
var troot = configTCrud.getRootTEntity();
|
||||||
|
walkTEntityTree(server,troot);
|
||||||
|
ncrud.launch(server,{
|
||||||
|
base: troot.tmeta.tserver.tslugs.tbase,
|
||||||
|
cors: false,
|
||||||
|
timeoute: troot.tmeta.tserver.tapi.timeoute
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = new mod();
|
59
lib/build-server-api-url.js
Normal file
59
lib/build-server-api-url.js
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
var debug = require('debug')('ff:tcrud:build:server:api:url');
|
||||||
|
var configTCrud = require('./tcrud-config');
|
||||||
|
|
||||||
|
var mod = (function () {
|
||||||
|
|
||||||
|
var createSlugApi = function(pluginId,postfix,slugType) {
|
||||||
|
var troot = configTCrud.getRootTEntity();
|
||||||
|
var pluginSlug = pluginId;
|
||||||
|
if (troot.tmeta.tplugin[pluginId] !== undefined && troot.tmeta.tplugin[pluginId].tslug !== undefined) {
|
||||||
|
pluginSlug = troot.tmeta.tplugin[pluginId].tslug;
|
||||||
|
}
|
||||||
|
var result = troot.tmeta.tserver.tslugs.tbase+
|
||||||
|
'/'+troot.tmeta.tserver.tslugs[slugType]+
|
||||||
|
'/'+pluginSlug;
|
||||||
|
if (postfix) {
|
||||||
|
result +='/'+postfix;
|
||||||
|
}
|
||||||
|
debug('createSlugApi plugin: '+pluginId+' result: '+result);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
var createSlugApiTEntityAction = function(pluginId,tview, action) {
|
||||||
|
var uriEntity = tview.tmeta.tserver.tslugs.tentity;
|
||||||
|
var uriView = tview.tslug;
|
||||||
|
var uriTech = tview.tmeta.tplugin[pluginId].tslug;
|
||||||
|
var uriAction = '';
|
||||||
|
if (action) {
|
||||||
|
uriAction = '/' + tview[action].tplugin[pluginId].tslug;
|
||||||
|
}
|
||||||
|
//debug('createBaseApiUri uriTech: '+uriTech+' uriView: '+uriView+' uriAction: '+uriAction);
|
||||||
|
if (tview.tmeta.tserver.tpopfix) {
|
||||||
|
return uriEntity + '/' + uriTech + '/' + uriView + uriAction;
|
||||||
|
} else {
|
||||||
|
return uriEntity + '/' +uriView + '/' + uriTech + uriAction;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return function BuildServerApiUrl() {
|
||||||
|
|
||||||
|
this.createSlugApiServerBase = function(pluginId,postfix) {
|
||||||
|
return createSlugApi(pluginId,postfix,'tserver');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createSlugApiPluginBase = function(pluginId,postfix) {
|
||||||
|
return createSlugApi(pluginId,postfix,'tplugin');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createSlugApiTEntityBase = function(pluginId,tview,action) {
|
||||||
|
var troot = configTCrud.getRootTEntity();
|
||||||
|
return troot.tmeta.tserver.tslugs.tbase+'/'+createSlugApiTEntityAction(pluginId,tview,action);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createSlugApiTEntity = function(pluginId,tview,action) {
|
||||||
|
return createSlugApiTEntityAction(pluginId,tview,action);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = new mod();
|
253
lib/build-server-api.js
Normal file
253
lib/build-server-api.js
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
var debug = require('debug')('ff:tcrud:build:server:api');
|
||||||
|
var clone = require('clone');
|
||||||
|
var Fontmin = require('fontmin');
|
||||||
|
var fs = require('fs');
|
||||||
|
var configTCrud = require('./tcrud-config');
|
||||||
|
var configRegistry = require('./config-registry');
|
||||||
|
var buildServerApiUrl = require('./build-server-api-url');
|
||||||
|
var buildServerExpress = require('./build-server-express');
|
||||||
|
|
||||||
|
|
||||||
|
var mod = (function () {
|
||||||
|
|
||||||
|
var renderTemplate = function(pluginSlug,templateFile, contentType) {
|
||||||
|
var renderFile = 'node-ff-tcrud/'+pluginSlug+'/'+templateFile;
|
||||||
|
var troot = configTCrud.getRootTEntity();
|
||||||
|
return function (req, res, next) {
|
||||||
|
res.set('Content-Type', contentType);
|
||||||
|
res.render(renderFile,{
|
||||||
|
troot: troot,
|
||||||
|
query: req.query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var hostTemplate = function(ctx, templateFile, contentType, skipReg) {
|
||||||
|
var pluginKey = ctx.tplugin.tmeta.key;
|
||||||
|
var apiPath = buildServerApiUrl.createSlugApiPluginBase(pluginKey,templateFile);
|
||||||
|
debug('hostTemplate apiPath: '+apiPath+' templateFile: '+templateFile+' content-Type: '+contentType);
|
||||||
|
ctx.server.get(apiPath, renderTemplate(pluginKey,templateFile, contentType)); // TODO: check sluging
|
||||||
|
if (skipReg !== undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentType.indexOf('css') !== -1) {
|
||||||
|
configRegistry.registrateClientResource(apiPath,'css');
|
||||||
|
}
|
||||||
|
if (contentType.indexOf('javascript') !== -1) {
|
||||||
|
configRegistry.registrateClientResource(apiPath,'js');
|
||||||
|
}
|
||||||
|
// TODO: no (t)html resources for caching ?
|
||||||
|
}
|
||||||
|
|
||||||
|
var filterContent = function(data,regexData) {
|
||||||
|
if (regexData === undefined) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
data = ''+data;
|
||||||
|
var regexList = Object.keys(regexData);
|
||||||
|
for (var i = 0; i < regexList.length; i++) {
|
||||||
|
var regex = new RegExp(regexList[i],'gm');
|
||||||
|
var regexReplace = regexData[regexList[i]];
|
||||||
|
data = data.replace(regex,regexReplace);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
var hostFile = function (ctx,opt,basePath,optContentTypeHint) {
|
||||||
|
|
||||||
|
if (opt === undefined) {
|
||||||
|
throw new Error('No options given');
|
||||||
|
}
|
||||||
|
if (opt.file === undefined) {
|
||||||
|
throw new Error('No file option given');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optContentTypeHint !== undefined) {
|
||||||
|
if (optContentTypeHint === 'js') {
|
||||||
|
opt.contentType = 'text/javascript';
|
||||||
|
} else {
|
||||||
|
opt.contentType = 'text/css';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.fileCharset === undefined) {
|
||||||
|
opt.fileCharset = 'utf8';
|
||||||
|
}
|
||||||
|
if (opt.contentType === undefined) {
|
||||||
|
opt.contentType = 'text/html';
|
||||||
|
}
|
||||||
|
if (opt.registrate === undefined) {
|
||||||
|
opt.registrate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var file = basePath;
|
||||||
|
if (opt.path !== undefined) {
|
||||||
|
file = file + opt.path;
|
||||||
|
}
|
||||||
|
file = file + '/' + opt.file;
|
||||||
|
debug('read host file: '+file);
|
||||||
|
var fileContent = fs.readFileSync(file, opt.fileCharset);
|
||||||
|
if (opt.filterFn !== undefined) {
|
||||||
|
fileContent = opt.filterFn(fileContent);
|
||||||
|
}
|
||||||
|
var serverContent = filterContent(fileContent, opt.filterRegex);
|
||||||
|
var serverContentType = opt.contentType;
|
||||||
|
|
||||||
|
var apiPath = buildServerApiUrl.createSlugApiPluginBase(ctx.tplugin.tmeta.key,opt.file);
|
||||||
|
ctx.server.get(apiPath, function(req, res) {
|
||||||
|
res.set('Content-Type', serverContentType);
|
||||||
|
res.send(serverContent);
|
||||||
|
});
|
||||||
|
if (opt.registrate && opt.contentType === 'text/javascript') {
|
||||||
|
configRegistry.registrateClientResource(apiPath,'js');
|
||||||
|
}
|
||||||
|
if (opt.registrate && opt.contentType === 'text/css') {
|
||||||
|
configRegistry.registrateClientResource(apiPath,'css');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: a bit hacky and not compleet or ready...
|
||||||
|
var hostFileCssFont = function(ctx,opt,basePath) {
|
||||||
|
|
||||||
|
if (opt === undefined) {
|
||||||
|
throw new Error('No options given');
|
||||||
|
}
|
||||||
|
if (opt.file === undefined) {
|
||||||
|
throw new Error('No file option given');
|
||||||
|
}
|
||||||
|
|
||||||
|
var filename = basePath;
|
||||||
|
if (opt.path !== undefined) {
|
||||||
|
filename += opt.path;
|
||||||
|
}
|
||||||
|
filename += opt.file;
|
||||||
|
|
||||||
|
var fontmin = new Fontmin()
|
||||||
|
fontmin.src(fs.readFileSync(filename));
|
||||||
|
if (filename.toLowerCase().indexOf('.otf') > 0) {
|
||||||
|
fontmin.use(Fontmin.otf2ttf());
|
||||||
|
}
|
||||||
|
//.use(Fontmin.otf2ttf()).use(Fontmin.ttf2woff()); // slow...
|
||||||
|
fontmin.run(function (err, files, stream) {
|
||||||
|
|
||||||
|
var fontBuffer = files[0].contents;
|
||||||
|
debug('fond build done..'+files.length);
|
||||||
|
debug('fond build done..'+Object.keys(files[0]));
|
||||||
|
var fontStr = fontBuffer.toString('base64');
|
||||||
|
var fontWeight = '';
|
||||||
|
if (opt.fontWeight !== undefined) {
|
||||||
|
fontWeight = '\tfont-weight: '+opt.fontWeight+';\n';
|
||||||
|
}
|
||||||
|
var result = '\n'+
|
||||||
|
'@font-face {\n'+
|
||||||
|
' font-family: "'+opt.fontFamily+'";\n'+
|
||||||
|
' src: url("data:font/ttf;charset=utf-8;base64,'+fontStr+'") format("truetype");\n'+
|
||||||
|
fontWeight+
|
||||||
|
'}\n';
|
||||||
|
///' src: url("data:font/ttf;charset=utf-8;base64,'+fontStr+'") format("truetype");\n'+
|
||||||
|
//cb(result); // ' font-style: normal;\n'+ //font/opentype
|
||||||
|
//' src: url("data:application/x-font-woff;charset=utf-8;base64,'+fontData+'") format("woff");\n'+
|
||||||
|
ctx.server.get(apiPath, function(req, res) {
|
||||||
|
res.set('Content-Type', 'text/css');
|
||||||
|
res.write(result);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: async build path ?
|
||||||
|
var apiPath = ctx.createSlugApiPluginBase(opt.file);
|
||||||
|
ctx.registrateClientCSSDataResource(apiPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var buildCrudApi = function(server) {
|
||||||
|
var troot = configTCrud.getRootTEntity();
|
||||||
|
var ctx = {
|
||||||
|
server: server,
|
||||||
|
troot: troot,
|
||||||
|
|
||||||
|
registrateMenu: function(menu,key) {
|
||||||
|
if (menu['items'] === undefined) {
|
||||||
|
menu['items'] = [];
|
||||||
|
}
|
||||||
|
configRegistry.getMasterConfig().rootTMenu[key] = menu;
|
||||||
|
},
|
||||||
|
registrateMenuItem: function(menuItem,key) {
|
||||||
|
configRegistry.getMasterConfig().rootTMenu[key].items.push(menuItem);
|
||||||
|
},
|
||||||
|
|
||||||
|
registrateClientJSResource: function(clientResource) {
|
||||||
|
return configRegistry.registrateClientResource(clientResource,'js');
|
||||||
|
},
|
||||||
|
registrateClientCSSResource: function(clientResource) {
|
||||||
|
return configRegistry.registrateClientResource(clientResource,'css');
|
||||||
|
},
|
||||||
|
registrateClientCSSDataResource: function(clientResource) {
|
||||||
|
return configRegistry.registrateClientResource(clientResource,'dss');
|
||||||
|
},
|
||||||
|
|
||||||
|
createSlugApiServerBase: function(postfix) {
|
||||||
|
return buildServerApiUrl.createSlugApiServerBase(ctx.tplugin.tmeta.key,postfix);
|
||||||
|
},
|
||||||
|
createSlugApiPluginBase: function(postfix) {
|
||||||
|
return buildServerApiUrl.createSlugApiPluginBase(ctx.tplugin.tmeta.key,postfix);
|
||||||
|
},
|
||||||
|
|
||||||
|
hostFileCSSLocal: function (opt) {
|
||||||
|
hostFile(ctx,opt,ctx.tplugin.tmeta.localDir,'css');
|
||||||
|
},
|
||||||
|
hostFileJSLocal: function (opt) {
|
||||||
|
hostFile(ctx,opt,ctx.tplugin.tmeta.localDir,'js');
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
hostFileCSSFontNodeModule: function (opt) {
|
||||||
|
hostFileCssFont(ctx,opt,__dirname+'/../node_modules/');
|
||||||
|
},
|
||||||
|
hostFileCSSNodeModule: function (opt) {
|
||||||
|
hostFile(ctx,opt,__dirname+'/../node_modules/','css');
|
||||||
|
},
|
||||||
|
hostFileJSNodeModule: function (opt) {
|
||||||
|
hostFile(ctx,opt,__dirname+'/../node_modules/','js');
|
||||||
|
},
|
||||||
|
|
||||||
|
hostTemplateJS: function(templateFile, skipReg) {
|
||||||
|
hostTemplate(ctx,templateFile, 'text/javascript', skipReg);
|
||||||
|
},
|
||||||
|
hostTemplateHTML: function(templateFile, skipReg) {
|
||||||
|
hostTemplate(ctx,templateFile, 'text/html', skipReg);
|
||||||
|
},
|
||||||
|
hostTemplateCSS: function(templateFile, skipReg) {
|
||||||
|
hostTemplate(ctx,templateFile, 'text/css', skipReg);
|
||||||
|
},
|
||||||
|
|
||||||
|
renderRedirect: buildServerExpress.renderRedirect,
|
||||||
|
renderFunctionJSON: buildServerExpress.renderFunctionJSON,
|
||||||
|
renderTemplate: function (templateFile, contentType) {
|
||||||
|
return renderTemplate(ctx.tplugin.tmeta.key,templateFile, contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildServerExpress.saveRoutes(server);
|
||||||
|
configRegistry.pluginCall('configServer',ctx, function(plugin) {
|
||||||
|
buildServerExpress.saveRoutes(server);
|
||||||
|
Array.prototype.push.apply(plugin['troutes'],buildServerExpress.getRoutesDiff(server));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return function BuildServerApi() {
|
||||||
|
|
||||||
|
this.build = function(server) {
|
||||||
|
debug('buildServerApi');
|
||||||
|
configRegistry.assertPhaseServer();
|
||||||
|
|
||||||
|
var cors = require('cors');
|
||||||
|
server.use(cors({credentials: true, origin: '*'}));
|
||||||
|
//troot.tmeta.tserver.tapi.cors
|
||||||
|
|
||||||
|
buildCrudApi(server);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = new mod();
|
99
lib/build-server-express.js
Normal file
99
lib/build-server-express.js
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
var debug = require('debug')('ff:tcrud:build:server:express');
|
||||||
|
|
||||||
|
var mod = (function () {
|
||||||
|
|
||||||
|
var walkRouteTree = function(result,stack,parent_path) {
|
||||||
|
if (parent_path == null) {
|
||||||
|
parent_path = '';
|
||||||
|
}
|
||||||
|
stack.forEach(function(middleware) {
|
||||||
|
if (middleware.route){
|
||||||
|
var path = parent_path + middleware.route.path;
|
||||||
|
for (var httpMethod in middleware.route.methods) {
|
||||||
|
var data = {
|
||||||
|
uriPath: path,
|
||||||
|
httpMethod: httpMethod
|
||||||
|
};
|
||||||
|
result.push(data);
|
||||||
|
}
|
||||||
|
} else if (middleware.name === 'router') {
|
||||||
|
var pp = parent_path + middleware.handle.path;
|
||||||
|
walkRouteTree(result,middleware.handle.stack,pp);
|
||||||
|
} else {
|
||||||
|
//log.info('route err: '+JSON.stringify(middleware));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var buildRouteLine = function(routes) {
|
||||||
|
var result = [];
|
||||||
|
for (var routeIdx in routes) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var buildRouteDiff = function(obj,objOld) {
|
||||||
|
var result = [];
|
||||||
|
for (var objIdx in obj) {
|
||||||
|
var objResult = obj[objIdx];
|
||||||
|
var objAdd = true;
|
||||||
|
for (var objOldIdx in objOld) {
|
||||||
|
var objOldResult = objOld[objOldIdx];
|
||||||
|
|
||||||
|
if (objResult.uriPath === objOldResult.uriPath && objResult.httpMethod === objOldResult.httpMethod) {
|
||||||
|
objAdd = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (objAdd) {
|
||||||
|
result.push(objResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function BuildServerExpress() {
|
||||||
|
|
||||||
|
this.saveRoutes = function(server) {
|
||||||
|
if (!server) {
|
||||||
|
throw new Error('no server given');
|
||||||
|
}
|
||||||
|
var resultOld = server.get('ff_tcrud_route_list');
|
||||||
|
var result = walkRouteTree([],server._router.stack);
|
||||||
|
result.sort(function(a, b) {
|
||||||
|
return a.uriPath.localeCompare(b.uriPath);
|
||||||
|
});
|
||||||
|
server.set('ff_tcrud_route_list',result);
|
||||||
|
server.set('ff_tcrud_route_list_diff',buildRouteDiff(result,resultOld));
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getRoutes = function(server) {
|
||||||
|
return server.get('ff_tcrud_route_list');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getRoutesDiff = function(server) {
|
||||||
|
return server.get('ff_tcrud_route_list_diff');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.renderRedirect = function(location) {
|
||||||
|
if (!location) {
|
||||||
|
throw 'no location';
|
||||||
|
}
|
||||||
|
return function(req, res) {
|
||||||
|
res.redirect(location);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.renderFunctionJSON = function(fn) {
|
||||||
|
return function (req, res, next) {
|
||||||
|
res.json({
|
||||||
|
data: fn()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = new mod();
|
405
lib/config-registry.js
Normal file
405
lib/config-registry.js
Normal file
|
@ -0,0 +1,405 @@
|
||||||
|
var path = require('path');
|
||||||
|
var fs = require('fs');
|
||||||
|
var debug = require('debug')('ff:tcrud:config:registry');
|
||||||
|
var configUtil = require('./config-util');
|
||||||
|
|
||||||
|
var mod = (function () {
|
||||||
|
|
||||||
|
var phaseInit = true;
|
||||||
|
var phaseConfig = false;
|
||||||
|
var phaseServer = false;
|
||||||
|
var phaseServerUp = false;
|
||||||
|
|
||||||
|
// Master template for plugins.
|
||||||
|
this.masterTemplates = {
|
||||||
|
masterTFieldTemplate: {},
|
||||||
|
masterTFieldTHelp: {},
|
||||||
|
masterTEntityTemplate: {},
|
||||||
|
masterTEntityTHelp: {},
|
||||||
|
masterTViewTemplate: {},
|
||||||
|
masterTViewTHelp: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Master config of tcrud
|
||||||
|
this.masterConfig = {
|
||||||
|
rootTEntity: null,
|
||||||
|
rootTMenu: {},
|
||||||
|
plugins: [],
|
||||||
|
backends: {},
|
||||||
|
validators: {},
|
||||||
|
clientResources: {
|
||||||
|
js: [],
|
||||||
|
css: [],
|
||||||
|
dss: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.pluginKeysAllowed = [
|
||||||
|
'configPlugin',
|
||||||
|
'configTemplate',
|
||||||
|
'configServer',
|
||||||
|
'configApi',
|
||||||
|
'configApiTListExport',
|
||||||
|
'configApiTCreateExport',
|
||||||
|
'configApiTReadExport',
|
||||||
|
'configApiTEditExport',
|
||||||
|
'configApiTDeleteExport',
|
||||||
|
'configApiTCountExport',
|
||||||
|
'configPostBoot',
|
||||||
|
'fillTEntity',
|
||||||
|
'fillTField',
|
||||||
|
'fillTView',
|
||||||
|
'createBackend',
|
||||||
|
'key','dbModule','query','conn'];
|
||||||
|
|
||||||
|
|
||||||
|
var mergeMaster = function(objectDest,pluginKey) {
|
||||||
|
return function(objectSrc) {
|
||||||
|
//console.log('mergeMasterSrc:'+JSON.stringify(objectSrc));
|
||||||
|
//console.log('mergeMasterDst:'+JSON.stringify(objectDest));
|
||||||
|
|
||||||
|
var resPre = {keys: 0,values: 0};
|
||||||
|
configUtil.countTree(objectDest,resPre);
|
||||||
|
|
||||||
|
configUtil.copyByTemplate('',objectDest,objectSrc,objectSrc);
|
||||||
|
|
||||||
|
var resPost = {keys: 0,values: 0};
|
||||||
|
configUtil.countTree(objectDest,resPost);
|
||||||
|
|
||||||
|
// TODO: check pre+post counters so first 2 arrays grow equal !
|
||||||
|
|
||||||
|
debug('mergeMaster'
|
||||||
|
+' start: '+resPre.keys+' -> '+resPre.values
|
||||||
|
+' end: '+resPost.keys+' -> '+resPost.values
|
||||||
|
+' diff: '+(resPost.keys-resPre.keys)+' -> '+(resPost.values-resPre.values)
|
||||||
|
+' plugin: '+pluginKey);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var tentityMergeDown = function(prefix,objectDest,objectSrc) {
|
||||||
|
var keys = Object.keys(objectSrc);
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var value = objectSrc[key];
|
||||||
|
if (!value) {
|
||||||
|
//console.log(prefix+'.'+key+' src object has no value.');
|
||||||
|
continue; // no src value
|
||||||
|
}
|
||||||
|
if (!objectDest[key]) {
|
||||||
|
objectDest[key] = configUtil.clone(value);
|
||||||
|
} else if (typeof value === 'object') {
|
||||||
|
|
||||||
|
if (key === 'tchilds') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//console.log(prefix+'.'+key+' going deeper');
|
||||||
|
tentityMergeDown(prefix+'.'+key,objectDest[key],value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var tentityFillTree = function(parent) {
|
||||||
|
debug('tentityFillTree.tid: %s',parent.tid);
|
||||||
|
for (var key in parent.tmeta.tfields) {
|
||||||
|
pluginCall('fillTField',{
|
||||||
|
filterValue: function(a,b,c,d) {return configUtil.filterValue(a,b,c,d);},
|
||||||
|
tfield: parent.tmeta.tfields[key]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (var i = 0; i < parent.tchilds.length; i++) {
|
||||||
|
var child = parent.tchilds[i];
|
||||||
|
tentityMergeDown('',child,parent);
|
||||||
|
tentityFillTree(child);
|
||||||
|
}
|
||||||
|
pluginCall('fillTEntity',{
|
||||||
|
filterValue: function(a,b,c,d) {return configUtil.filterValue(a,b,c,d);},
|
||||||
|
tentity: parent
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var pluginCall = function(fnName,ctx,afterPluginCb) {
|
||||||
|
var startTime = new Date().getTime();
|
||||||
|
var callCount = 0;
|
||||||
|
var keys = Object.keys(masterConfig.plugins);
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var pluginKey = keys[i];
|
||||||
|
var plugin = masterConfig.plugins[pluginKey];
|
||||||
|
if (plugin.tenable === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ctx.tplugin = plugin;
|
||||||
|
if (plugin[fnName]) {
|
||||||
|
var result = plugin[fnName](ctx);
|
||||||
|
callCount++;
|
||||||
|
if (afterPluginCb !== undefined) {
|
||||||
|
afterPluginCb(plugin, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug('pluginCall.function: %s done %s plugins in %s ms.',fnName,callCount,(new Date().getTime()-startTime));
|
||||||
|
};
|
||||||
|
|
||||||
|
var assertPhaseInit = function() {
|
||||||
|
if (!phaseInit) {
|
||||||
|
throw Error('Not in init phase.')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var assertPhaseConfig = function() {
|
||||||
|
if (!phaseConfig) {
|
||||||
|
throw Error('Not in config phase.')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var assertPhaseServer = function() {
|
||||||
|
if (!phaseServer) {
|
||||||
|
throw Error('Not in server phase.')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var assertPhaseServerUp = function() {
|
||||||
|
if (!phaseServerUp) {
|
||||||
|
throw Error('Not in serverUp phase.')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var pluginLoad = function(plugin) {
|
||||||
|
assertPhaseInit();
|
||||||
|
if (plugin === undefined) {
|
||||||
|
throw new Error('No object given');
|
||||||
|
}
|
||||||
|
if (plugin.configPlugin === undefined) {
|
||||||
|
throw new Error('Object is not a plugin: Missing configPlugin()');
|
||||||
|
}
|
||||||
|
// run config to have key
|
||||||
|
var ctx = {
|
||||||
|
key: null,
|
||||||
|
description: null,
|
||||||
|
dependencies: [],
|
||||||
|
localDir: null,
|
||||||
|
localConfigTemplate: null
|
||||||
|
}
|
||||||
|
plugin.configPlugin(ctx);
|
||||||
|
if (ctx.key === null) {
|
||||||
|
throw new Error('Plugin does not provide pluginKey.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate plugin before injection
|
||||||
|
for (var objectKey in plugin) {
|
||||||
|
if (objectKey.charAt(0) === '_') {
|
||||||
|
continue; // tmp
|
||||||
|
}
|
||||||
|
if (pluginKeysAllowed.indexOf(objectKey) !== -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw new Error('Illegal plugin objectKey: '+objectKey+' plugin: '+plugin.tmeta.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin['tmeta'] = ctx;
|
||||||
|
plugin['troutes'] = [];
|
||||||
|
plugin['tenable'] = false;
|
||||||
|
|
||||||
|
if (ctx.localConfigTemplate) {
|
||||||
|
var pluginJsonFile = path.join(ctx.localDir,ctx.localConfigTemplate);
|
||||||
|
var pluginJsonTemplate = fs.readFileSync(pluginJsonFile, 'utf8');
|
||||||
|
plugin['configTemplateLocal'] = function (ctx) {
|
||||||
|
debug('configTemplateLocal file %s',pluginJsonFile);
|
||||||
|
ctx.mergeMaster(JSON.parse(pluginJsonTemplate));
|
||||||
|
};
|
||||||
|
debugPostfix = ' localConfigTemplate:\t'+pluginJsonFile;
|
||||||
|
}
|
||||||
|
//masterConfig.plugins[plugin.tmeta.key]=plugin;
|
||||||
|
masterConfig.plugins.push(plugin);
|
||||||
|
debug('pluginLoad %s',plugin.tmeta.key);
|
||||||
|
};
|
||||||
|
|
||||||
|
var pluginLoadTree = function (plugins) {
|
||||||
|
var keys = Object.keys(plugins);
|
||||||
|
var result = [];
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var value = plugins[key];
|
||||||
|
|
||||||
|
if (typeof value === 'function') {
|
||||||
|
pluginLoad(new value());
|
||||||
|
} else {
|
||||||
|
pluginLoadTree(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var pluginEnable = function(pluginFilter, value) {
|
||||||
|
assertPhaseInit();
|
||||||
|
if (pluginFilter === undefined) {
|
||||||
|
throw new Error('No pluginKey given');
|
||||||
|
}
|
||||||
|
if (value === undefined) {
|
||||||
|
value = true;
|
||||||
|
}
|
||||||
|
var keys = Object.keys(masterConfig.plugins);
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var pluginIdx = keys[i];
|
||||||
|
var plugin = masterConfig.plugins[pluginIdx];
|
||||||
|
var pluginKey = plugin.tmeta.key;
|
||||||
|
|
||||||
|
if (pluginKey.match(pluginFilter)) {
|
||||||
|
debug('pluginEnable plugin: '+pluginKey+' value: '+value);
|
||||||
|
plugin.tenable = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var pluginIndexOf = function(checkKey) {
|
||||||
|
var keys = Object.keys(masterConfig.plugins);
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var pluginKey = keys[i];
|
||||||
|
var plugin = masterConfig.plugins[pluginKey];
|
||||||
|
if (plugin.tmeta.key === checkKey) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pluginOrder = function() {
|
||||||
|
|
||||||
|
var keys = Object.keys(masterConfig.plugins);
|
||||||
|
for (var pluginId = 0; pluginId < keys.length; pluginId++) {
|
||||||
|
var pluginKey = keys[pluginId];
|
||||||
|
var plugin = masterConfig.plugins[pluginKey];
|
||||||
|
if (plugin.tmeta.dependencies.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (var depId in plugin.tmeta.dependencies) {
|
||||||
|
var dep = plugin.tmeta.dependencies[depId];
|
||||||
|
var depIdx = pluginIndexOf(dep);
|
||||||
|
|
||||||
|
|
||||||
|
if (depIdx === -1) {
|
||||||
|
throw new Error('Missing plugin: '+dep+' requested by: '+plugin.tmeta.key);
|
||||||
|
}
|
||||||
|
if (depIdx < pluginId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
debug('pluginOrder dependency move: '+dep+' before: '+plugin.tmeta.key);
|
||||||
|
|
||||||
|
var depMove = masterConfig.plugins[depIdx];
|
||||||
|
var oldPlugins = masterConfig.plugins;
|
||||||
|
var newPlugins = [];
|
||||||
|
|
||||||
|
newPlugins = oldPlugins.slice(0,pluginId);
|
||||||
|
newPlugins.push(depMove);
|
||||||
|
newPlugins = newPlugins.concat(oldPlugins.slice(pluginId,depIdx));
|
||||||
|
newPlugins = newPlugins.concat(oldPlugins.slice(depIdx+1));
|
||||||
|
|
||||||
|
masterConfig.plugins = newPlugins;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function ConfigRegistry() {
|
||||||
|
|
||||||
|
this.assertPhaseInit = assertPhaseInit;
|
||||||
|
this.assertPhaseConfig = assertPhaseConfig;
|
||||||
|
this.assertPhaseServer = assertPhaseServer;
|
||||||
|
this.assertPhaseServerUp = assertPhaseServerUp;
|
||||||
|
|
||||||
|
this.pluginCall = pluginCall;
|
||||||
|
this.pluginLoad = pluginLoad;
|
||||||
|
this.pluginLoadTree = pluginLoadTree;
|
||||||
|
this.pluginEnable = pluginEnable;
|
||||||
|
|
||||||
|
this.phaseNext = function() {
|
||||||
|
if (phaseInit) {
|
||||||
|
debug('phaseNext init->config');
|
||||||
|
phaseInit = false;
|
||||||
|
phaseConfig = true;
|
||||||
|
|
||||||
|
debug('pluginOrder start');
|
||||||
|
while (!pluginOrder()) {
|
||||||
|
}
|
||||||
|
debug('pluginOrder done');
|
||||||
|
|
||||||
|
var ctx = {
|
||||||
|
mergeMaster: function(template) {
|
||||||
|
mergeMaster(masterTemplates,ctx.tplugin.tmeta.key)(template);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
pluginCall('configTemplate',ctx);
|
||||||
|
pluginCall('configTemplateLocal',ctx);
|
||||||
|
pluginCall('createBackend',{},function (plugin,backend) {
|
||||||
|
masterConfig.backends[backend.getKey()]=backend;
|
||||||
|
debug('createBackend: %s',backend.getKey());
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (phaseConfig) {
|
||||||
|
debug('phaseNext config->server');
|
||||||
|
phaseConfig = false;
|
||||||
|
phaseServer = true;
|
||||||
|
|
||||||
|
tentityFillTree(masterConfig.rootTEntity);
|
||||||
|
|
||||||
|
} else if (phaseServer) {
|
||||||
|
debug('phaseNext server->serverUp');
|
||||||
|
phaseServer = false;
|
||||||
|
phaseServerUp = true;
|
||||||
|
|
||||||
|
} else if (phaseServerUp) {
|
||||||
|
debug('phaseNext serverUp->done');
|
||||||
|
phaseServerUp = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error('All phases are done.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getRootTEntity = function() {
|
||||||
|
if (masterConfig.rootTEntity === null) {
|
||||||
|
masterConfig.rootTEntity = configUtil.clone(masterTemplates.masterTEntityTemplate);
|
||||||
|
masterConfig.rootTEntity.tid = 'root';
|
||||||
|
debug('getRootTEntity.created');
|
||||||
|
}
|
||||||
|
return masterConfig.rootTEntity;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getMasterTemplates = function() {
|
||||||
|
return masterTemplates;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getMasterConfig = function() {
|
||||||
|
return masterConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.registrateClientResource = function(clientResource, resourceType) {
|
||||||
|
if (clientResource === undefined) {
|
||||||
|
throw new Error('No resource provided');
|
||||||
|
}
|
||||||
|
if (resourceType === undefined) {
|
||||||
|
throw new Error('No resource provided');
|
||||||
|
}
|
||||||
|
debug('registrateClientResource: '+clientResource+' type: '+resourceType);
|
||||||
|
masterConfig.clientResources[resourceType].push(clientResource);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createClientResourceFetchList = function() {
|
||||||
|
var fetchList = [];
|
||||||
|
for (var clientResourceIdx in masterConfig.clientResources.js) {
|
||||||
|
var url = masterConfig.clientResources.js[clientResourceIdx];
|
||||||
|
fetchList.push({url:url,type:'js'});
|
||||||
|
}
|
||||||
|
for (var clientResourceIdx in masterConfig.clientResources.css) {
|
||||||
|
var url = masterConfig.clientResources.css[clientResourceIdx];
|
||||||
|
fetchList.push({url:url,type:'css'});
|
||||||
|
}
|
||||||
|
for (var clientResourceIdx in masterConfig.clientResources.dss) {
|
||||||
|
var url = masterConfig.clientResources.dss[clientResourceIdx];
|
||||||
|
fetchList.push({url:url,type:'dss'});
|
||||||
|
}
|
||||||
|
return fetchList;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = new mod();
|
100
lib/config-util.js
Normal file
100
lib/config-util.js
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
var cloneImpl = require('clone');
|
||||||
|
var debug = require('debug')('ff:tcrud:config:util');
|
||||||
|
var configRegistry = require('./config-registry');
|
||||||
|
|
||||||
|
var mod = (function () {
|
||||||
|
|
||||||
|
var clone = function(obj) {
|
||||||
|
return cloneImpl(obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
var filterValuePart = function(value,replaceChar,splitChar,partFn) {
|
||||||
|
var result = '';
|
||||||
|
var parts = value.split(splitChar);
|
||||||
|
for (var i = 0; i < parts.length; i++) {
|
||||||
|
var part = parts[i];
|
||||||
|
if (part.length > 1) {
|
||||||
|
result += partFn(part);
|
||||||
|
} else {
|
||||||
|
result += part;
|
||||||
|
}
|
||||||
|
if (i < parts.length - 1) {
|
||||||
|
result += replaceChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
var copyByTemplate = function(prefix,objectDest,objectSrc,copyTemplate) {
|
||||||
|
var keys = Object.keys(copyTemplate);
|
||||||
|
var result = [];
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var value = objectSrc[key];
|
||||||
|
if (value === null) {
|
||||||
|
//debug('copyByTemplate '+prefix+'.'+key+' src object has null value.');
|
||||||
|
objectDest[key] = null;
|
||||||
|
continue; // no src value
|
||||||
|
}
|
||||||
|
var templateValue = copyTemplate[key];
|
||||||
|
if (templateValue === null) {
|
||||||
|
if (objectDest[key] !== null) {
|
||||||
|
//debug('copyByTemplate '+prefix+'.'+key+' has own value: '+objectDest[key]);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
//debug('copyByTemplate '+prefix+'.'+key+' copy value: '+value);
|
||||||
|
objectDest[key] = clone(value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (objectDest[key] === undefined) {
|
||||||
|
objectDest[key] = clone(templateValue);
|
||||||
|
} else {
|
||||||
|
//debug('copyByTemplate '+prefix+'.'+key+' going deeper');
|
||||||
|
copyByTemplate(prefix+'.'+key,objectDest[key],value,templateValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var countTree = function(obj,result) {
|
||||||
|
if (typeof obj === 'object') {
|
||||||
|
for (var key in obj) {
|
||||||
|
result.keys++;
|
||||||
|
countTree(obj[key],result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.values++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return function ConfigUtil() {
|
||||||
|
|
||||||
|
this.countTree = countTree;
|
||||||
|
|
||||||
|
this.copyByTemplate = copyByTemplate;
|
||||||
|
|
||||||
|
this.clone = clone;
|
||||||
|
|
||||||
|
this.filterValue = function(value,removeChars,replaceChar,partFn) {
|
||||||
|
var valueOrg = value;
|
||||||
|
for (var i = 0; i < removeChars.length; i++) {
|
||||||
|
value = filterValuePart(value,replaceChar,removeChars[i],partFn);
|
||||||
|
}
|
||||||
|
//debug('filterValue.result: %s from: %s',value,valueOrg);
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.stringHash = function (str) {
|
||||||
|
var hash = 31; // prime
|
||||||
|
for (var i = 0; i < str.length; i++) {
|
||||||
|
hash = ((hash<<5)-hash)+str.charCodeAt(i);
|
||||||
|
hash = hash & hash; // keep 32b
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = new mod();
|
28
lib/default/default-tentity.js
Normal file
28
lib/default/default-tentity.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function DefaultTEntityPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'defaultTEntity';
|
||||||
|
ctx.description = 'Adds the basic data and structure of the tentity.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'default-tentity.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTEntity = function(ctx) {
|
||||||
|
if (ctx.tentity === undefined) {
|
||||||
|
throw new Error('no tentity');
|
||||||
|
}
|
||||||
|
if (ctx.tentity.tid === undefined) {
|
||||||
|
throw new Error('no tentity.tid');
|
||||||
|
}
|
||||||
|
if (ctx.tentity.tid === null) {
|
||||||
|
throw new Error('null tentity.tid');
|
||||||
|
}
|
||||||
|
if (ctx.tentity.tid.length === 0) {
|
||||||
|
throw new Error('empty tentity.tid');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
83
lib/default/default-tentity.json
Normal file
83
lib/default/default-tentity.json
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tid": null,
|
||||||
|
"tname": null,
|
||||||
|
"tplural": null,
|
||||||
|
"tslug": null,
|
||||||
|
"tenable": null,
|
||||||
|
"tcode": null,
|
||||||
|
"tkeys": [],
|
||||||
|
"troles": [],
|
||||||
|
"tparent": null,
|
||||||
|
"tchilds": [],
|
||||||
|
"tlist": {
|
||||||
|
"tenable": null,
|
||||||
|
"ttext": "Listing of ..",
|
||||||
|
"troles": [],
|
||||||
|
"tmethods": ["GET"],
|
||||||
|
"tplugin": {}
|
||||||
|
},
|
||||||
|
"tcreate": {
|
||||||
|
"tenable": null,
|
||||||
|
"ttext": null,
|
||||||
|
"troles": [],
|
||||||
|
"tmethods": ["POST"],
|
||||||
|
"tplugin": {}
|
||||||
|
},
|
||||||
|
"tedit": {
|
||||||
|
"tenable": null,
|
||||||
|
"ttext": null,
|
||||||
|
"troles": [],
|
||||||
|
"tmethods": ["PUT","POST"],
|
||||||
|
"tplugin": {}
|
||||||
|
},
|
||||||
|
"tread": {
|
||||||
|
"tenable": null,
|
||||||
|
"ttext": null,
|
||||||
|
"troles": [],
|
||||||
|
"tslug": null,
|
||||||
|
"tmethods": ["GET"],
|
||||||
|
"tplugin": {}
|
||||||
|
},
|
||||||
|
"tdelete": {
|
||||||
|
"tenable": null,
|
||||||
|
"ttext": null,
|
||||||
|
"troles": [],
|
||||||
|
"tmethods": ["DELETE","POST"],
|
||||||
|
"tplugin": {}
|
||||||
|
},
|
||||||
|
"tcount": {
|
||||||
|
"tenable": null,
|
||||||
|
"ttext": "Count records",
|
||||||
|
"troles": [],
|
||||||
|
"tmethods": ["GET"],
|
||||||
|
"tplugin": {}
|
||||||
|
},
|
||||||
|
"tverify": {
|
||||||
|
"tenable": null,
|
||||||
|
"ttext": "Verify data",
|
||||||
|
"troles": [],
|
||||||
|
"tmethods": ["POST"],
|
||||||
|
"tplugin": {}
|
||||||
|
},
|
||||||
|
"tmeta": {
|
||||||
|
"tmodel": {
|
||||||
|
"tkey": null,
|
||||||
|
"tkeys": [],
|
||||||
|
"tid": null,
|
||||||
|
"tbackend": null
|
||||||
|
},
|
||||||
|
"tmenu": {
|
||||||
|
"tenable": null,
|
||||||
|
"tkey": null,
|
||||||
|
"tname": null,
|
||||||
|
"titem": null,
|
||||||
|
"ticon": null
|
||||||
|
},
|
||||||
|
"troles": [],
|
||||||
|
"tfields": {},
|
||||||
|
"tplugin": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {}
|
||||||
|
}
|
32
lib/default/default-tfield.js
Normal file
32
lib/default/default-tfield.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function DefaultTFieldPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'defaultTField';
|
||||||
|
ctx.description = 'Adds the basic data and structure of the tfield.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'default-tfield.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTField = function(ctx) {
|
||||||
|
if (ctx.tfield === undefined) {
|
||||||
|
throw new Error('no tfield');
|
||||||
|
}
|
||||||
|
if (ctx.tfield.tid === undefined) {
|
||||||
|
throw new Error('no tfield.tid');
|
||||||
|
}
|
||||||
|
if (ctx.tfield.tid === null) {
|
||||||
|
throw new Error('null tfield.tid');
|
||||||
|
}
|
||||||
|
if (ctx.tfield.tid.length === 0) {
|
||||||
|
throw new Error('empty tfield.tid');
|
||||||
|
}
|
||||||
|
if (ctx.tfield.ttype === null) {
|
||||||
|
ctx.tfield.ttype = 'text'; // move ?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
54
lib/default/default-tfield.json
Normal file
54
lib/default/default-tfield.json
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
"masterTFieldTemplate": {
|
||||||
|
"tid": null,
|
||||||
|
"tname": null,
|
||||||
|
"ttext": null,
|
||||||
|
"ttype": null,
|
||||||
|
"tslug": null,
|
||||||
|
"tvalidate": {
|
||||||
|
"io": null
|
||||||
|
},
|
||||||
|
"tlist": {
|
||||||
|
"tenable": true,
|
||||||
|
"troles": []
|
||||||
|
},
|
||||||
|
"tread": {
|
||||||
|
"tenable": true,
|
||||||
|
"troles": []
|
||||||
|
},
|
||||||
|
"tedit": {
|
||||||
|
"tenable": true,
|
||||||
|
"troles": []
|
||||||
|
},
|
||||||
|
"tcreate": {
|
||||||
|
"tenable": true,
|
||||||
|
"troles": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"masterTFieldTHelp": {
|
||||||
|
"tid": "The id of the field.",
|
||||||
|
"tname": "The name of the field.",
|
||||||
|
"ttext": "The description of the field.",
|
||||||
|
"ttype": "The field type",
|
||||||
|
"tslug": "The slug of the field.",
|
||||||
|
"tvalidate": {
|
||||||
|
"io": "Named validate-io rules for the field."
|
||||||
|
},
|
||||||
|
"tlist": {
|
||||||
|
"tenable": "Is field enabled in crud listing.",
|
||||||
|
"troles": "Needed roles for listing."
|
||||||
|
},
|
||||||
|
"tread": {
|
||||||
|
"tenable": "Is field enabled in crud reading.",
|
||||||
|
"troles": "Needed roles for reading."
|
||||||
|
},
|
||||||
|
"tedit": {
|
||||||
|
"tenable": "Is field enabled in crud editing.",
|
||||||
|
"troles": "Needed roles for editing."
|
||||||
|
},
|
||||||
|
"tcreate": {
|
||||||
|
"tenable": "Is field enabled in crud creating.",
|
||||||
|
"troles": "Needed roles for creating."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
lib/default/default-tserver.js
Normal file
13
lib/default/default-tserver.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function DefaultTServerPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'defaultTServer';
|
||||||
|
ctx.description = 'Adds the basic data and structure of the tserver.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'default-tserver.json';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
44
lib/default/default-tserver.json
Normal file
44
lib/default/default-tserver.json
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tlist": { "tserver": {
|
||||||
|
"tpipe": {
|
||||||
|
"query": {
|
||||||
|
"defaults": { "limit": 10 },
|
||||||
|
"maxes": { "limit": 50 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
"tmeta": { "tserver": {
|
||||||
|
"thost": "http://localhost:8080",
|
||||||
|
"tslugs": {
|
||||||
|
"tbase": "/api",
|
||||||
|
"tserver": "server",
|
||||||
|
"tentity": "tentity",
|
||||||
|
"tplugin": "plugin"
|
||||||
|
},
|
||||||
|
"tpopfix": true,
|
||||||
|
"tformats": ["formatJSON","formatXML","formatCSV","serverConfigTView","angular"],
|
||||||
|
"tapi": {
|
||||||
|
"cors": true,
|
||||||
|
"timeoute": 30000
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tmeta": { "tserver": {
|
||||||
|
"thost": "The host of the server.",
|
||||||
|
"tslugs": {
|
||||||
|
"tbase": "The base api prefix slug",
|
||||||
|
"tserver": "The server slug",
|
||||||
|
"tentity": "The tentity slug",
|
||||||
|
"tplugin": "The plugin slug"
|
||||||
|
},
|
||||||
|
"tpopfix": "Use tech or format first.",
|
||||||
|
"tformats": "list of exported formats.",
|
||||||
|
"tapi": {
|
||||||
|
"cors": "Allow cors requests on api.",
|
||||||
|
"timeoute": "Timeout of api requests."
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
38
lib/default/default-tview.js
Normal file
38
lib/default/default-tview.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var addFilteredFields = function(tview,type,tcrud) {
|
||||||
|
//debug('addFilterFields of: '+type+' from: '+tview.tid);
|
||||||
|
result = [];
|
||||||
|
var keys = Object.keys(tcrud.tmeta.tfields);
|
||||||
|
var result = [];
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var tfield = tcrud.tmeta.tfields[key];
|
||||||
|
if (tfield[type]) {
|
||||||
|
if (!tfield[type].tenable) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(key); // default is true..
|
||||||
|
}
|
||||||
|
tview[type].tfields = result;
|
||||||
|
};
|
||||||
|
|
||||||
|
return function DefaultTViewPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'defaultTView';
|
||||||
|
ctx.description = 'Add copy template for building the tview from the tentity.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'default-tview.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTView = function(ctx) {
|
||||||
|
addFilteredFields(ctx.tview,'tlist',ctx.tentity);
|
||||||
|
addFilteredFields(ctx.tview,'tread',ctx.tentity);
|
||||||
|
addFilteredFields(ctx.tview,'tedit',ctx.tentity);
|
||||||
|
addFilteredFields(ctx.tview,'tcreate',ctx.tentity);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
135
lib/default/default-tview.json
Normal file
135
lib/default/default-tview.json
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
{
|
||||||
|
"masterTViewTemplate": {
|
||||||
|
"tid": null,
|
||||||
|
"tname": null,
|
||||||
|
"tplural": null,
|
||||||
|
"tslug": null,
|
||||||
|
"tcode": null,
|
||||||
|
"tenable": null,
|
||||||
|
"troles": null,
|
||||||
|
"tkeys": [],
|
||||||
|
"tcount": {
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"troles": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tlist": {
|
||||||
|
"tfields": [],
|
||||||
|
"ttext": null,
|
||||||
|
"tlinks": null,
|
||||||
|
"tenable": null,
|
||||||
|
"troles": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tread": {
|
||||||
|
"tfields": [],
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"troles": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tedit": {
|
||||||
|
"tfields": [],
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"troles": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tcreate": {
|
||||||
|
"tfields": [],
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"troles": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tdelete": {
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"troles": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tverify": {
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"troles": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tmeta": {
|
||||||
|
"tmodel": null,
|
||||||
|
"tfields": null,
|
||||||
|
"tvalidate": null,
|
||||||
|
"tserver": null,
|
||||||
|
"tplugin": null,
|
||||||
|
"tmenu": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"masterTViewTHelp": {
|
||||||
|
"tid": "The name of the view.",
|
||||||
|
"tplural": "The plural name of the view.",
|
||||||
|
"tslug": "The slug of the view.",
|
||||||
|
"tcode": null,
|
||||||
|
"tkeys": "The primary key fields.",
|
||||||
|
"tcount": {
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tlist": {
|
||||||
|
"tfields": [],
|
||||||
|
"ttext": null,
|
||||||
|
"tlinks": null,
|
||||||
|
"tenable": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tread": {
|
||||||
|
"tfields": [],
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tedit": {
|
||||||
|
"tfields": [],
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tcreate": {
|
||||||
|
"tfields": [],
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tdelete": {
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tverify": {
|
||||||
|
"ttext": null,
|
||||||
|
"tenable": null,
|
||||||
|
"tmethods": null,
|
||||||
|
"tplugin": null
|
||||||
|
},
|
||||||
|
"tmeta": {
|
||||||
|
"tmodel": null,
|
||||||
|
"tfields": null,
|
||||||
|
"tvalidate": null,
|
||||||
|
"tserver": null,
|
||||||
|
"tplugin": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,26 @@
|
||||||
'use strict';
|
var debug = require('debug')('ff:tcrud');
|
||||||
|
var startTime = new Date().getTime();
|
||||||
|
debug('Init welcome');
|
||||||
|
|
||||||
var assets = {
|
debug('Init objects...');
|
||||||
|
var requireAll = require('require-all');
|
||||||
|
var configRegistry = require('./config-registry');
|
||||||
|
var tcrudSetup = require('./tcrud-setup');
|
||||||
|
var tcrudConfig = require('./tcrud-config');
|
||||||
|
debug('Init objects done');
|
||||||
|
|
||||||
|
debug('Init plugins...');
|
||||||
|
configRegistry.pluginLoadTree(requireAll({dirname: __dirname + '/default',filter: /^([^\.].*)\.js?$/}));
|
||||||
|
configRegistry.pluginLoadTree(requireAll({dirname: __dirname + '/plugin',filter: /^([^\.].*)\.js?$/}));
|
||||||
|
debug('Init plugins done');
|
||||||
|
|
||||||
|
debug('Init backends...');
|
||||||
|
var tcrudBackend = requireAll({dirname: __dirname + '/backend',filter: /^([^\.].*)\.js?$/});
|
||||||
|
debug('Init backends done');
|
||||||
|
debug('Init done in %s ms.',(new Date().getTime()-startTime));
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
setup: tcrudSetup,
|
||||||
|
config: tcrudConfig,
|
||||||
|
backend: tcrudBackend
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = assets;
|
|
||||||
|
|
54
lib/plugin/auto/auto-tenable.js
Normal file
54
lib/plugin/auto/auto-tenable.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var autoFieldEnable = function(tfield,type) {
|
||||||
|
if (type === undefined) {
|
||||||
|
throw new Error('no type');
|
||||||
|
}
|
||||||
|
if (tfield[type] === undefined) {
|
||||||
|
tfield[type] = {}; // todo rm this
|
||||||
|
}
|
||||||
|
if (tfield[type].tenable !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var fieldKey = tfield.tid;
|
||||||
|
var result = true;
|
||||||
|
if ('tlist' === type) {
|
||||||
|
var name = fieldKey.toLowerCase();
|
||||||
|
if (fieldKey.indexOf('description') >= 0) {
|
||||||
|
result = false;
|
||||||
|
} else if (fieldKey.indexOf('comment') >= 0) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tfield[type].tenable = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function AutoTEnablePlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='autoTEnable';
|
||||||
|
ctx.description='Auto enables to true if undefined.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTEntity = function(ctx) {
|
||||||
|
if (ctx.tentity.tenable === null || ctx.tentity.tenable === undefined) {
|
||||||
|
ctx.tentity.tenable = true;
|
||||||
|
}
|
||||||
|
autoFieldEnable(ctx.tentity,'tlist');
|
||||||
|
autoFieldEnable(ctx.tentity,'tread');
|
||||||
|
autoFieldEnable(ctx.tentity,'tedit');
|
||||||
|
autoFieldEnable(ctx.tentity,'tcreate');
|
||||||
|
autoFieldEnable(ctx.tentity,'tdelete');
|
||||||
|
autoFieldEnable(ctx.tentity,'tcount');
|
||||||
|
autoFieldEnable(ctx.tentity,'tverify');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fillTField = function(ctx) {
|
||||||
|
autoFieldEnable(ctx.tfield,'tlist');
|
||||||
|
autoFieldEnable(ctx.tfield,'tread');
|
||||||
|
autoFieldEnable(ctx.tfield,'tedit');
|
||||||
|
autoFieldEnable(ctx.tfield,'tcreate');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
45
lib/plugin/auto/auto-tmenu.js
Normal file
45
lib/plugin/auto/auto-tmenu.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function AutoTMenuPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='autoTMenu';
|
||||||
|
ctx.description='Auto enables menu items.';
|
||||||
|
ctx.dependencies.push('autoTEntityTPlural');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTEntity = function(ctx) {
|
||||||
|
if (ctx.tentity.tparent === null) {
|
||||||
|
return; // root node
|
||||||
|
}
|
||||||
|
if (ctx.tentity.tmeta.tmodel.tid === null) {
|
||||||
|
ctx.tentity.tmeta.tmenu.titem = false; // auto menu for items
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.tentity.tmeta.tmenu.tenable === null || ctx.tentity.tmeta.tmenu.tenable === undefined) {
|
||||||
|
ctx.tentity.tmeta.tmenu.tenable = true;
|
||||||
|
}
|
||||||
|
if (ctx.tentity.tmeta.tmenu.titem === null || ctx.tentity.tmeta.tmenu.titem === undefined) {
|
||||||
|
ctx.tentity.tmeta.tmenu.titem = true;
|
||||||
|
}
|
||||||
|
if (ctx.tentity.tmeta.tmenu.tname === null || ctx.tentity.tmeta.tmenu.tname === undefined) {
|
||||||
|
ctx.tentity.tmeta.tmenu.tname = ctx.tentity.tplural.substring(0,1).toUpperCase()+ctx.tentity.tplural.substring(1);
|
||||||
|
}
|
||||||
|
if (ctx.tentity.tmeta.tmenu.tkey === null || ctx.tentity.tmeta.tmenu.tkey === undefined) {
|
||||||
|
if (ctx.tentity.tmeta.tmenu.titem) {
|
||||||
|
ctx.tentity.tmeta.tmenu.tkey = ctx.tentity.tparent.tid;
|
||||||
|
} else {
|
||||||
|
ctx.tentity.tmeta.tmenu.tkey = ctx.tentity.tid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ctx.tentity.tmeta.tmenu.ticon === null || ctx.tentity.tmeta.tmenu.ticon === undefined) {
|
||||||
|
if (ctx.tentity.tmeta.tmenu.titem) {
|
||||||
|
ctx.tentity.tmeta.tmenu.ticon = 'fa fa-table';
|
||||||
|
} else {
|
||||||
|
ctx.tentity.tmeta.tmenu.ticon = 'fa fa-cubes';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
50
lib/plugin/auto/auto-tname.js
Normal file
50
lib/plugin/auto/auto-tname.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var createName = function (fieldKey,fieldName) {
|
||||||
|
if (fieldKey === undefined) {
|
||||||
|
throw new Error('no fieldKey');
|
||||||
|
}
|
||||||
|
if (fieldName && fieldName.length !== 0) {
|
||||||
|
return fieldName;
|
||||||
|
}
|
||||||
|
var result = '';
|
||||||
|
var names = fieldKey.split('_');
|
||||||
|
for (var i in names) {
|
||||||
|
var name = names[i];
|
||||||
|
if (name.length > 1) {
|
||||||
|
name = name.substring(0,1).toUpperCase() + name.substring(1);
|
||||||
|
}
|
||||||
|
result = result + ' ' + name;
|
||||||
|
}
|
||||||
|
return result.substring(1); // remove first space
|
||||||
|
};
|
||||||
|
|
||||||
|
var filterName = function(ctx,value) {
|
||||||
|
return ctx.filterValue(value,['_','-','.',','],' ', function (part) {
|
||||||
|
return part.substring(0,1).toUpperCase()+part.substring(1).toLowerCase();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return function AutoTNamePlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='autoTName';
|
||||||
|
ctx.description='Auto fills and checks the tname fields.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTField = function(ctx) {
|
||||||
|
if (ctx.tfield.tname === null) {
|
||||||
|
ctx.tfield.tname = createName(ctx.tfield.tid);
|
||||||
|
} else {
|
||||||
|
//ctx.tfield.tname = filterName(ctx,ctx.tfield.tname);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTEntity = function(ctx) {
|
||||||
|
if (ctx.tentity.tname === null) {
|
||||||
|
ctx.tentity.tname = ctx.tentity.tid;//
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
47
lib/plugin/auto/auto-tslug.js
Normal file
47
lib/plugin/auto/auto-tslug.js
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var filterSlug = function(ctx,value) {
|
||||||
|
return ctx.filterValue(value,['.',',','/','=','&','?',' '],'', function (part) {
|
||||||
|
return part; // todo use fully correct uri removeal and escaping.
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
var createTViewSlug = function(tentity) {
|
||||||
|
var uriViewSlash = '/';
|
||||||
|
var slug = uriViewSlash + tentity.tslug;
|
||||||
|
if (!tentity.tenable || !tentity.tparent) {
|
||||||
|
slug = '';
|
||||||
|
}
|
||||||
|
if (tentity.tparent) {
|
||||||
|
return createTViewSlug(tentity.tparent)+slug;
|
||||||
|
}
|
||||||
|
return slug;
|
||||||
|
};
|
||||||
|
|
||||||
|
return function AutoTSlugPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='autoTSlug';
|
||||||
|
ctx.description='Auto fills and checks the tslug fields.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTField = function(ctx) {
|
||||||
|
if (ctx.tfield.tslug === undefined || ctx.tfield.tslug === null) {
|
||||||
|
ctx.tfield.tslug = ctx.tfield.tid;
|
||||||
|
}
|
||||||
|
ctx.tfield.tslug = filterSlug(ctx,ctx.tfield.tslug);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTEntity = function(ctx) {
|
||||||
|
if (ctx.tentity.tslug === null) {
|
||||||
|
ctx.tentity.tslug = ctx.tentity.tid;
|
||||||
|
}
|
||||||
|
ctx.tentity.tslug = filterSlug(ctx,ctx.tentity.tslug);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTView = function(ctx) {
|
||||||
|
ctx.tview.tslug = createTViewSlug(ctx.tentity).substring(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
24
lib/plugin/auto/tentity/auto-tentity-tcode.js
Normal file
24
lib/plugin/auto/tentity/auto-tentity-tcode.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var filterCode = function(ctx,value) {
|
||||||
|
return ctx.filterValue(value,[' ','_','-','.',','],'',function (part) {
|
||||||
|
return part.toLowerCase();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return function AutoTEntityTCodePlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='autoTEntityTCode';
|
||||||
|
ctx.description='Fills and filters tcode to be code-safe for generating variables/functions.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTEntity = function(ctx) {
|
||||||
|
if (ctx.tentity.tcode === null || ctx.tentity.tcode === null) {
|
||||||
|
ctx.tentity.tcode = ctx.tentity.tid;
|
||||||
|
}
|
||||||
|
ctx.tentity.tcode = filterCode(ctx,ctx.tentity.tcode);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
29
lib/plugin/auto/tentity/auto-tentity-tkey.js
Normal file
29
lib/plugin/auto/tentity/auto-tentity-tkey.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var makeTKey = function(ctx) {
|
||||||
|
var keySlug = '';
|
||||||
|
for (var i = 0; i < ctx.tentity.tmeta.tmodel.tkeys.length; i++) {
|
||||||
|
var key = ctx.tentity.tmeta.tmodel.tkeys[i];
|
||||||
|
keySlug += ':'+key;
|
||||||
|
if (i < (ctx.tentity.tmeta.tmodel.tkeys.length - 1)) {
|
||||||
|
keySlug += '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keySlug;
|
||||||
|
};
|
||||||
|
|
||||||
|
return function AutoTEntityTKeyPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='autoTEntityTKey';
|
||||||
|
ctx.description='Auto creates the tmode.tkey parameter slug.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTEntity = function(ctx) {
|
||||||
|
if (ctx.tentity.tmeta.tmodel.tkey === null) {
|
||||||
|
ctx.tentity.tmeta.tmodel.tkey = makeTKey(ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
32
lib/plugin/auto/tentity/auto-tentity-tplural.js
Normal file
32
lib/plugin/auto/tentity/auto-tentity-tplural.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var makePlural = function(name) {
|
||||||
|
if (name.slice(-1) === 's') {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if (name.slice(-1) === 'y') {
|
||||||
|
name = name.slice(0,-1) + 'ie';
|
||||||
|
}
|
||||||
|
return name + 's';
|
||||||
|
}
|
||||||
|
|
||||||
|
return function AutoTEntityTPluralPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='autoTEntityTPlural';
|
||||||
|
ctx.description='Auto create tplurals from the tname/tid field.';
|
||||||
|
ctx.dependencies.push('autoTName');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTEntity = function(ctx) {
|
||||||
|
if (ctx.tentity.tplural === null) {
|
||||||
|
if (ctx.tentity.tname === null) {
|
||||||
|
ctx.tentity.tplural = makePlural(ctx.tentity.tid);
|
||||||
|
} else {
|
||||||
|
ctx.tentity.tplural = makePlural(ctx.tentity.tname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
53
lib/plugin/auto/tview/auto-tview-ftl.js
Normal file
53
lib/plugin/auto/tview/auto-tview-ftl.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
function forceLookupTFields(tview) {
|
||||||
|
var keys = Object.keys(tview.tmeta.tfields);
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var keyNew = 'FTL_' +forceLookupKeySimple() + '_' + key.substring(key.length/3,key.length/3*2); // no....its; Force template lookup
|
||||||
|
var tfield = tview.tmeta.tfields[key];
|
||||||
|
tview.tmeta.tfields[key] = undefined;
|
||||||
|
tview.tmeta.tfields[keyNew] = tfield;
|
||||||
|
|
||||||
|
var ckeys = Object.keys(tview);
|
||||||
|
for (var ii = 0; ii < ckeys.length; ii++) {
|
||||||
|
var ckey = ckeys[ii];
|
||||||
|
if (ckey === 'tmeta') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var obj = tview[ckey];
|
||||||
|
if (obj && obj.tfields) {
|
||||||
|
var tfieldsNew = [];
|
||||||
|
for (var iii = 0; iii < obj.tfields.length; iii++) {
|
||||||
|
var tkey = obj.tfields[iii];
|
||||||
|
if (tkey === key) {
|
||||||
|
tfieldsNew.push(keyNew);
|
||||||
|
} else {
|
||||||
|
tfieldsNew.push(tkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.tfields = tfieldsNew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function forceLookupKeySimple() {
|
||||||
|
var low = 100000;
|
||||||
|
var high = 999999;
|
||||||
|
return Math.floor(Math.random() * (high - low + 1) + low).toString(16).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
return function AutoTViewFTLPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='autoTViewFTL';
|
||||||
|
ctx.description='Automatic tview tfields key change to force table lookup.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fillTView = function(ctx) {
|
||||||
|
forceLookupTFields(ctx.tview);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
21
lib/plugin/format/format-csv.js
Normal file
21
lib/plugin/format/format-csv.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function FormatCsvPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'formatCSV';
|
||||||
|
ctx.description = 'Export tentity list/read api in csv format.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'format-csv.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTListExport = function (ctx) {
|
||||||
|
return ctx.renderTemplateDataList(ctx.tview.tmeta.tplugin.formatCSV.tmime);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTReadExport = function (ctx) {
|
||||||
|
return ctx.renderTemplateDataRead(ctx.tview.tmeta.tplugin.formatCSV.tmime);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
18
lib/plugin/format/format-csv.json
Normal file
18
lib/plugin/format/format-csv.json
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tlist": { "tplugin": { "formatCSV": { "tslug": "list" }}},
|
||||||
|
"tread": { "tplugin": { "formatCSV": { "tslug": "read" }}},
|
||||||
|
"tmeta": { "tplugin": { "formatCSV": {
|
||||||
|
"tslug": "csv",
|
||||||
|
"tmime": "text/csv"
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tlist": { "tplugin": { "formatCSV": { "tslug": "csv slug of api url" }}},
|
||||||
|
"tread": { "tplugin": { "formatCSV": { "tslug": "csv slug of api url" }}},
|
||||||
|
"tmeta": { "tplugin": { "formatCSV": {
|
||||||
|
"tslug": "The csv slug of api url.",
|
||||||
|
"tmime": "The csv mime type header."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
35
lib/plugin/format/format-json.js
Normal file
35
lib/plugin/format/format-json.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
|
||||||
|
// TODO: move to default-format-json.js ??
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function FormatJsonPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'formatJSON';
|
||||||
|
ctx.description = 'Export the tentity api in json format.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'format-json.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
// flag that we support these all crud types.
|
||||||
|
|
||||||
|
this.configApiTListExport = function (ctx) {
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTCreateExport = function (ctx) {
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTReadExport = function (ctx) {
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTEditExport = function (ctx) {
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTDeleteExport = function (ctx) {
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTCountExport = function (ctx) {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
22
lib/plugin/format/format-json.json
Normal file
22
lib/plugin/format/format-json.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tlist": { "tplugin": { "formatJSON": { "tslug": "list" }}},
|
||||||
|
"tcreate": { "tplugin": { "formatJSON": { "tslug": "create" }}},
|
||||||
|
"tedit": { "tplugin": { "formatJSON": { "tslug": "edit" }}},
|
||||||
|
"tread": { "tplugin": { "formatJSON": { "tslug": "read" }}},
|
||||||
|
"tdelete": { "tplugin": { "formatJSON": { "tslug": "delete" }}},
|
||||||
|
"tcount": { "tplugin": { "formatJSON": { "tslug": "list-count" }}},
|
||||||
|
"tverify": { "tplugin": { "formatJSON": { "tslug": "verify" }}},
|
||||||
|
"tmeta": { "tplugin": { "formatJSON": { "tslug": "json" }}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tlist": { "tplugin": { "formatJSON": { "tslug": "tlist json slug part api url" }}},
|
||||||
|
"tcreate": { "tplugin": { "formatJSON": { "tslug": "tcreate json slug part api url" }}},
|
||||||
|
"tedit": { "tplugin": { "formatJSON": { "tslug": "tedit json slug part api url" }}},
|
||||||
|
"tread": { "tplugin": { "formatJSON": { "tslug": "tread json slug part api url" }}},
|
||||||
|
"delete": { "tplugin": { "formatJSON": { "tslug": "tdelete json slug part api url" }}},
|
||||||
|
"tcount": { "tplugin": { "formatJSON": { "tslug": "tcount json slug part api url" }}},
|
||||||
|
"tverify": { "tplugin": { "formatJSON": { "tslug": "tverifiy json slug part api url"}}},
|
||||||
|
"tmeta": { "tplugin": { "formatJSON": { "tslug": "json group part api url" }}}
|
||||||
|
}
|
||||||
|
}
|
13
lib/plugin/format/format-rss.js
Normal file
13
lib/plugin/format/format-rss.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function FormatRssPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'formatRSS';
|
||||||
|
ctx.description = 'Export tentity list/read api in rss format.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'format-rss.json';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
17
lib/plugin/format/format-rss.json
Normal file
17
lib/plugin/format/format-rss.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tlist": { "tplugin": { "formatRSS": { "tslug": "list" }}},
|
||||||
|
"tmeta": { "tplugin": { "formatRSS": {
|
||||||
|
"tslug": "rss",
|
||||||
|
"itemTitle": "$data._id",
|
||||||
|
"itemLink": "$siteLink/ui/$modelUri/read/$[\"data._id\"]",
|
||||||
|
"itemDate": "",
|
||||||
|
"itemDescription": "",
|
||||||
|
"itemFields": ""
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tlist": { "tplugin": { "formatRSS": { "tslug": "rss slug of api url" }}},
|
||||||
|
"tmeta": { "tplugin": { "formatRSS": { "tslug": "rss slug of api url" }}}
|
||||||
|
}
|
||||||
|
}
|
75
lib/plugin/format/format-xml.js
Normal file
75
lib/plugin/format/format-xml.js
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
var xmlmapping = require('xml-mapping');
|
||||||
|
var rawbody = require('raw-body');
|
||||||
|
var typeis = require('type-is');
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
function bodyParserXml() {
|
||||||
|
return function(req, res, next) {
|
||||||
|
if (req._body) return next();
|
||||||
|
req.body = req.body || {};
|
||||||
|
|
||||||
|
if (!typeis(req, 'xml')) return next();
|
||||||
|
|
||||||
|
// flag as parsed
|
||||||
|
req._body = true;
|
||||||
|
|
||||||
|
// parse
|
||||||
|
rawbody(req, {
|
||||||
|
limit: options.limit || '100kb',
|
||||||
|
length: req.headers['content-length'],
|
||||||
|
encoding: 'utf8'
|
||||||
|
}, function (err, buf) {
|
||||||
|
if (err) return next(err);
|
||||||
|
|
||||||
|
if (0 == buf.length) {
|
||||||
|
return next(error(400, 'invalid xml, empty body'));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
req.body = xmlmapping.dump(buf/*, options.reviver*/);
|
||||||
|
} catch (err){
|
||||||
|
err.body = buf;
|
||||||
|
err.status = 400;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function FormatXmlPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'formatXML';
|
||||||
|
ctx.description = 'Export the tentity api in xml format.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'format-xml.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.server.use(bodyParserXml());
|
||||||
|
}
|
||||||
|
|
||||||
|
// flag that we support these all crud types.
|
||||||
|
|
||||||
|
this.configApiTListExport = function (ctx) {
|
||||||
|
return ctx.renderTemplateDataList(ctx.tview.tmeta.tplugin.formatXML.tmime);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTCreateExport = function (ctx) {
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTReadExport = function (ctx) {
|
||||||
|
return ctx.renderTemplateDataRead(ctx.tview.tmeta.tplugin.formatXML.tmime);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTEditExport = function (ctx) {
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTDeleteExport = function (ctx) {
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApiTCountExport = function (ctx) {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
28
lib/plugin/format/format-xml.json
Normal file
28
lib/plugin/format/format-xml.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tlist": { "tplugin": { "formatXML": { "tslug": "list" }}},
|
||||||
|
"tcreate": { "tplugin": { "formatXML": { "tslug": "create" }}},
|
||||||
|
"tedit": { "tplugin": { "formatXML": { "tslug": "edit" }}},
|
||||||
|
"tread": { "tplugin": { "formatXML": { "tslug": "read" }}},
|
||||||
|
"tdelete": { "tplugin": { "formatXML": { "tslug": "delete" }}},
|
||||||
|
"tcount": { "tplugin": { "formatXML": { "tslug": "list-count" }}},
|
||||||
|
"tverify": { "tplugin": { "formatXML": { "tslug": "verify" }}},
|
||||||
|
"tmeta": { "tplugin": { "formatXML": {
|
||||||
|
"tslug": "xml",
|
||||||
|
"tmime": "text/xml"
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tlist": { "tplugin": { "formatXML": { "tslug": "xml slug of api url" }}},
|
||||||
|
"tcreate": { "tplugin": { "formatXML": { "tslug": "xml slug of api url" }}},
|
||||||
|
"tedit": { "tplugin": { "formatXML": { "tslug": "xml slug of api url" }}},
|
||||||
|
"tread": { "tplugin": { "formatXML": { "tslug": "xml slug of api url" }}},
|
||||||
|
"tdelete": { "tplugin": { "formatXML": { "tslug": "xml slug of api url" }}},
|
||||||
|
"tcount": { "tplugin": { "formatXML": { "tslug": "xml slug of api url" }}},
|
||||||
|
"tverify": { "tplugin": { "formatXML": { "tslug": "xml slug of api url" }}},
|
||||||
|
"tmeta": { "tplugin": { "formatXML": {
|
||||||
|
"tslug": "The xml slug of api url.",
|
||||||
|
"tmime": "The xml mime type header."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
63
lib/plugin/server/config/config-resources-mobile.js
Normal file
63
lib/plugin/server/config/config-resources-mobile.js
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
var debug = require('debug')('ff:tcrud:plugin:server:config:resouces:mobile');
|
||||||
|
var configRegistry = require('./../../../config-registry');
|
||||||
|
var configUtil = require('./../../../config-util');
|
||||||
|
var fetch = require('fetch');
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var webAssets = [];
|
||||||
|
|
||||||
|
var fetchHashResource = function(fetchEntry,cb) {
|
||||||
|
fetch.fetchUrl(fetchEntry.url,function(err, meta, data) {
|
||||||
|
debug('fetched url: '+fetchEntry.url+' length: '+meta.responseHeaders['content-length']);
|
||||||
|
var assetHash = configUtil.stringHash(''+data);
|
||||||
|
webAssets.push({
|
||||||
|
url: fetchEntry.url,
|
||||||
|
type: fetchEntry.type,
|
||||||
|
hash: assetHash
|
||||||
|
});
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var fetchHashResources = function(fetchList, cb) {
|
||||||
|
var startTime = new Date().getTime();
|
||||||
|
debug('createHashResources: '+fetchList.length);
|
||||||
|
var resourceStack = fetchList;
|
||||||
|
var resourceLoader = function() {
|
||||||
|
resourceStack = resourceStack.slice(1);
|
||||||
|
if (resourceStack.length === 0) {
|
||||||
|
debug('fetchHashResources done in '+(new Date().getTime()-startTime)+' ms.');
|
||||||
|
cb();
|
||||||
|
} else {
|
||||||
|
fetchHashResource(resourceStack[0],resourceLoader);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchHashResource(resourceStack[0],resourceLoader);
|
||||||
|
};
|
||||||
|
|
||||||
|
return function ServerConfigResourcesMobilePlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'serverConfigResourcesMobile';
|
||||||
|
ctx.description = 'Exports client resources mobile.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'config-resources-mobile.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.server.get(ctx.createSlugApiServerBase(),ctx.renderFunctionJSON(function () {
|
||||||
|
return {
|
||||||
|
resources: webAssets
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configPostBoot = function(ctx) {
|
||||||
|
fetchHashResources(configRegistry.createClientResourceFetchList(), function() {
|
||||||
|
debug('Total assets build: '+webAssets.length);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
12
lib/plugin/server/config/config-resources-mobile.json
Normal file
12
lib/plugin/server/config/config-resources-mobile.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tmeta": { "tplugin": { "serverConfigResourcesMobile": {
|
||||||
|
"tslug": "config/client-resources-mobile"
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tmeta": { "tplugin": { "serverConfigResourcesMobile": {
|
||||||
|
"tslug": "The client resource for mobile slug."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
144
lib/plugin/server/config/config-resources-web.js
Normal file
144
lib/plugin/server/config/config-resources-web.js
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
var debug = require('debug')('ff:tcrud:plugin:server:config:resouces:web');
|
||||||
|
var configRegistry = require('./../../../config-registry');
|
||||||
|
var configUtil = require('./../../../config-util');
|
||||||
|
var fetch = require('fetch');
|
||||||
|
|
||||||
|
// FIXME: use type as key
|
||||||
|
var assetCss = '';
|
||||||
|
var assetCssUrl = '';
|
||||||
|
var assetCssHash = '';
|
||||||
|
var assetCssData = '';
|
||||||
|
var assetCssDataUrl = '';
|
||||||
|
var assetCssDataHash = '';
|
||||||
|
var assetJs = '';
|
||||||
|
var assetJsUrl = '';
|
||||||
|
var assetJsHash = '';
|
||||||
|
|
||||||
|
var plugin = (function () {
|
||||||
|
|
||||||
|
var webAssets = [];
|
||||||
|
|
||||||
|
var fetchResource = function(fetchEntry,cb) {
|
||||||
|
fetch.fetchUrl(fetchEntry.url,function(err, meta, data) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
debug('fetched url: '+fetchEntry.url+' length: '+meta.responseHeaders['content-length']);
|
||||||
|
//debug('meta: '+JSON.stringify(meta));
|
||||||
|
|
||||||
|
if (fetchEntry.type === 'css') {
|
||||||
|
assetCss += '\n/* FILE: '+fetchEntry.url+' */\n';
|
||||||
|
assetCss += data;
|
||||||
|
} else if (fetchEntry.type === 'js') {
|
||||||
|
assetJs += '\n/* FILE: '+fetchEntry.url+' */\n';
|
||||||
|
assetJs += data;
|
||||||
|
} else if (fetchEntry.type === 'dss') {
|
||||||
|
assetCssData += '\n/* FILE: '+fetchEntry.url+' */\n';
|
||||||
|
assetCssData += data;
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var fetchResources = function(fetchList, cb) {
|
||||||
|
var startTime = new Date().getTime();
|
||||||
|
debug('createResources: '+fetchList.length);
|
||||||
|
var resourceStack = fetchList;
|
||||||
|
var resourceLoader = function() {
|
||||||
|
resourceStack = resourceStack.slice(1);
|
||||||
|
if (resourceStack.length === 0) {
|
||||||
|
debug('fetchResources done in '+(new Date().getTime()-startTime)+' ms.');
|
||||||
|
cb();
|
||||||
|
} else {
|
||||||
|
fetchResource(resourceStack[0],resourceLoader);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchResource(resourceStack[0],resourceLoader);
|
||||||
|
};
|
||||||
|
|
||||||
|
return function ServerConfigResourcesWebPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'serverConfigResourcesWeb';
|
||||||
|
ctx.description = 'Exports client resources web.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'config-resources-web.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.server.get(ctx.createSlugApiServerBase(),ctx.renderFunctionJSON(function () {
|
||||||
|
return {
|
||||||
|
resources: webAssets
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configPostBoot = function(ctx) {
|
||||||
|
fetchResources(configRegistry.createClientResourceFetchList(), function() {
|
||||||
|
assetJsHash = configUtil.stringHash(assetJs);
|
||||||
|
assetCssHash = configUtil.stringHash(assetCss);
|
||||||
|
assetCssDataHash = configUtil.stringHash(assetCssData);
|
||||||
|
debug('Total size assets.js: '+assetJs.length+' hash: '+assetJsHash);
|
||||||
|
debug('Total size assets.css: '+assetCss.length+' hash: '+assetCssHash);
|
||||||
|
debug('Total size assets-data.css: '+assetCssData.length+' hash: '+assetCssDataHash);
|
||||||
|
// note: js first to inject href asap by loader
|
||||||
|
webAssets.push({
|
||||||
|
url: assetJsUrl,
|
||||||
|
type: 'js',
|
||||||
|
hash: assetJsHash
|
||||||
|
});
|
||||||
|
webAssets.push({
|
||||||
|
url: assetCssUrl,
|
||||||
|
type: 'css',
|
||||||
|
hash: assetCssHash
|
||||||
|
});
|
||||||
|
webAssets.push({
|
||||||
|
url: assetCssDataUrl,
|
||||||
|
type: 'dss',
|
||||||
|
hash: assetCssDataHash
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
var pluginDownload = (function () {
|
||||||
|
|
||||||
|
return function ServerConfigResourcesWebAssetPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'serverConfigResourcesWebAsset';
|
||||||
|
ctx.description = 'Exports downloaded client web resources.';
|
||||||
|
ctx.dependencies.push('serverConfigResourcesWeb');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
|
||||||
|
assetCssDataUrl = ctx.createSlugApiPluginBase('assets-data.css');
|
||||||
|
ctx.server.get(assetCssDataUrl,function (req, res, next) {
|
||||||
|
res.set('Content-Type','text/css');
|
||||||
|
res.write(assetCssData);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
assetCssUrl = ctx.createSlugApiPluginBase('assets.css');
|
||||||
|
ctx.server.get(assetCssUrl,function (req, res, next) {
|
||||||
|
res.set('Content-Type','text/css');
|
||||||
|
res.write(assetCss);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
assetJsUrl = ctx.createSlugApiPluginBase('assets.js');
|
||||||
|
ctx.server.get(assetJsUrl,function (req, res, next) {
|
||||||
|
res.set('Content-Type','application/javascript');
|
||||||
|
res.write(assetJs);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
web: plugin,
|
||||||
|
webAssets: pluginDownload
|
||||||
|
};
|
12
lib/plugin/server/config/config-resources-web.json
Normal file
12
lib/plugin/server/config/config-resources-web.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tmeta": { "tplugin": { "serverConfigResourcesWeb": {
|
||||||
|
"tslug": "config/client-resources-web"
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tmeta": { "tplugin": { "serverConfigResourcesWeb": {
|
||||||
|
"tslug": "The client resources web slug."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
68
lib/plugin/server/config/config-routes.js
Normal file
68
lib/plugin/server/config/config-routes.js
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
var buildServerExpress = require('./../../../build-server-express');
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var renderServerRoutes = function (server) {
|
||||||
|
if (!server) {
|
||||||
|
throw new Error('no server');
|
||||||
|
}
|
||||||
|
return function (req, res, next) {
|
||||||
|
var routeList = buildServerExpress.getRoutes(server);
|
||||||
|
if (!routeList) {
|
||||||
|
routeList = [];
|
||||||
|
}
|
||||||
|
var reqGroups = req.query.groups;
|
||||||
|
var groupList = [];
|
||||||
|
if (reqGroups) {
|
||||||
|
groupList = reqGroups.split(',');
|
||||||
|
}
|
||||||
|
var result = {
|
||||||
|
all: [],
|
||||||
|
};
|
||||||
|
for (var i = 0; i < groupList.length; i++) {
|
||||||
|
var groupName = groupList[i].split('/').join('_');
|
||||||
|
result[groupName] = [];
|
||||||
|
}
|
||||||
|
groupList.sort(function(a, b) {
|
||||||
|
return a.length < b.length; // longest first as we break on first hit
|
||||||
|
});
|
||||||
|
|
||||||
|
for (i = 0; i < routeList.length; i++) {
|
||||||
|
var route = routeList[i];
|
||||||
|
var added = false;
|
||||||
|
for (var ii = 0; ii < groupList.length; ii++) {
|
||||||
|
if (route.uriPath.indexOf(groupList[ii]) > 0) {
|
||||||
|
var groupName = groupList[ii].split('/').join('_');
|
||||||
|
result[groupName].push(route);
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!added) {
|
||||||
|
result.all.push(route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.json({
|
||||||
|
data: result
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return function ServerConfigRoutesPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'serverConfigRoutes';
|
||||||
|
ctx.description = 'Exports all server routes.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'config-routes.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.server.get(ctx.createSlugApiServerBase(),renderServerRoutes(ctx.server));
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configPostBoot = function(ctx) {
|
||||||
|
buildServerExpress.saveRoutes(ctx.server);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
12
lib/plugin/server/config/config-routes.json
Normal file
12
lib/plugin/server/config/config-routes.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tmeta": { "tplugin": { "serverConfigRoutes": {
|
||||||
|
"tslug": "config/routes"
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tmeta": { "tplugin": { "serverConfigRoutes": {
|
||||||
|
"tslug": "The routes slug."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
28
lib/plugin/server/config/config-tmenu.js
Normal file
28
lib/plugin/server/config/config-tmenu.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
var configRegistry = require('./../../../config-registry');
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function ServerConfigTMenuPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'serverConfigTMenu';
|
||||||
|
ctx.description = 'Exports tmenu.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'config-tmenu.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.server.get(ctx.createSlugApiServerBase(),ctx.renderFunctionJSON(function() {
|
||||||
|
var result = {};
|
||||||
|
for (var key in configRegistry.getMasterConfig().rootTMenu) {
|
||||||
|
var value = configRegistry.getMasterConfig().rootTMenu[key];
|
||||||
|
if (value.items.length > 0) {
|
||||||
|
result[key] = value; // remove empty menus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
12
lib/plugin/server/config/config-tmenu.json
Normal file
12
lib/plugin/server/config/config-tmenu.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tmeta": { "tplugin": { "serverConfigTMenu": {
|
||||||
|
"tslug": "config/menu"
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tmeta": { "tplugin": { "serverConfigTMenu": {
|
||||||
|
"tslug": "The config tmenu slug."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
23
lib/plugin/server/config/config-tview.js
Normal file
23
lib/plugin/server/config/config-tview.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
var configRegistry = require('./../../../config-registry');
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function ServerConfigTViewPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'serverConfigTView';
|
||||||
|
ctx.description = 'Exports tentity tviews.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'config-tview.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApi = function(ctx) {
|
||||||
|
ctx.server.get(ctx.createSlugApiTEntityBase(),ctx.renderFunctionJSON(function () {
|
||||||
|
return {
|
||||||
|
tview: ctx.tview
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
12
lib/plugin/server/config/config-tview.json
Normal file
12
lib/plugin/server/config/config-tview.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tmeta": { "tplugin": { "serverConfigTView": {
|
||||||
|
"tslug": "config/tview"
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tmeta": { "tplugin": { "serverConfigTView": {
|
||||||
|
"tslug": "The config tview slug."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
42
lib/plugin/server/debug.js
Normal file
42
lib/plugin/server/debug.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
var configRegistry = require('./../../config-registry');
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var masterDebug = function(ctx,modelName,modelType,model) {
|
||||||
|
ctx.server.get(
|
||||||
|
ctx.createSlugApiServerBase('master')+
|
||||||
|
'/'+modelName+
|
||||||
|
'/'+modelType
|
||||||
|
,ctx.renderFunctionJSON(function() {
|
||||||
|
var result = {};
|
||||||
|
result[modelName] = model;
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return function ServerDebugPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'serverDebug';
|
||||||
|
ctx.description = 'Exports some debug data.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'debug.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
var mt = configRegistry.getMasterTemplates();
|
||||||
|
masterDebug(ctx,'tfield', 'template', mt.masterTFieldTemplate);
|
||||||
|
masterDebug(ctx,'tfield', 'thelp', mt.masterTFieldTHelp);
|
||||||
|
masterDebug(ctx,'tentity', 'template', mt.masterTEntityTemplate);
|
||||||
|
masterDebug(ctx,'tentity', 'thelp', mt.masterTEntityTHelp);
|
||||||
|
masterDebug(ctx,'tview', 'template', mt.masterTViewTemplate);
|
||||||
|
masterDebug(ctx,'tview', 'thelp', mt.masterTViewTHelp);
|
||||||
|
|
||||||
|
// todo: TypeError: Converting circular structure to JSON
|
||||||
|
//ctx.server.get(ctx.createSlugApiServerBase('config/root-tentity'),this.renderFunction(function() {
|
||||||
|
// return configRegistry.rootTEntity;
|
||||||
|
//}));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
12
lib/plugin/server/debug.json
Normal file
12
lib/plugin/server/debug.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tmeta": { "tplugin": { "serverDebug": {
|
||||||
|
"tslug": "debug"
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tmeta": { "tplugin": { "serverDebug": {
|
||||||
|
"tslug": "The server debug slug."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
55
lib/plugin/server/info/info-plugins.js
Normal file
55
lib/plugin/server/info/info-plugins.js
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
var configRegistry = require('./../../../config-registry');
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var createPluginInfo = function() {
|
||||||
|
var result = {};
|
||||||
|
for (var pluginIdx in configRegistry.getMasterConfig().plugins) {
|
||||||
|
var plugin = configRegistry.getMasterConfig().plugins[pluginIdx];
|
||||||
|
var pluginExtensions = Object.keys(plugin).slice(0,-1);
|
||||||
|
//TODO: pluginExtensions.remove('tmeta');
|
||||||
|
var pluginData = {
|
||||||
|
extensions: pluginExtensions,
|
||||||
|
tmeta: plugin.tmeta,
|
||||||
|
troutes: plugin.troutes
|
||||||
|
};
|
||||||
|
result[plugin.tmeta.key] = pluginData;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
var createPluginKeyList = function() {
|
||||||
|
var result = [];
|
||||||
|
for (var pluginIdx in configRegistry.getMasterConfig().plugins) {
|
||||||
|
var plugin = configRegistry.getMasterConfig().plugins[pluginIdx];
|
||||||
|
result.push(plugin.tmeta.key);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
return function ServerInfoPluginsPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='serverInfoPlugins';
|
||||||
|
ctx.description='Makes the server plugins info public as json';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'info-plugins.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.server.get(ctx.createSlugApiServerBase(),ctx.renderFunctionJSON(function () {
|
||||||
|
return {
|
||||||
|
plugins: {
|
||||||
|
keys: {
|
||||||
|
registrated: createPluginKeyList(),
|
||||||
|
backends: Object.keys(configRegistry.getMasterConfig().backends),
|
||||||
|
validators: Object.keys(configRegistry.getMasterConfig().validators)
|
||||||
|
},
|
||||||
|
info: createPluginInfo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
12
lib/plugin/server/info/info-plugins.json
Normal file
12
lib/plugin/server/info/info-plugins.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tmeta": { "tplugin": { "serverInfoPlugins": {
|
||||||
|
"tslug": "info/plugins"
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tmeta": { "tplugin": { "serverInfoPlugins": {
|
||||||
|
"tslug": "The info plugins slug."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
28
lib/plugin/server/info/info-uptime.js
Normal file
28
lib/plugin/server/info/info-uptime.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var timeBoot = new Date().getTime();
|
||||||
|
|
||||||
|
return function ServerInfoUptimePlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='serverInfoUptime';
|
||||||
|
ctx.description='Makes the server uptime info public as json';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'info-uptime.json';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.server.get(ctx.createSlugApiServerBase(),ctx.renderFunctionJSON(function () {
|
||||||
|
var timeNow = new Date().getTime();
|
||||||
|
return {
|
||||||
|
serverInfoUptime: {
|
||||||
|
time_boot: timeBoot,
|
||||||
|
time_now: timeNow,
|
||||||
|
uptime: timeNow-timeBoot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
12
lib/plugin/server/info/info-uptime.json
Normal file
12
lib/plugin/server/info/info-uptime.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tmeta": { "tplugin": { "serverInfoUptime": {
|
||||||
|
"tslug": "info/uptime"
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tmeta": { "tplugin": { "serverInfoUptime": {
|
||||||
|
"tslug": "The info uptime slug."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
25
lib/plugin/ui/angular/server/ui-angular-server-plugins.js
vendored
Normal file
25
lib/plugin/ui/angular/server/ui-angular-server-plugins.js
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function UIAngularServerRoutesPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'uiAngularServerPlugins';
|
||||||
|
ctx.description = 'Adds an angular server plugins page.';
|
||||||
|
ctx.dependencies.push('angular');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.hostTemplateJS('js/server-plugins');
|
||||||
|
ctx.hostTemplateHTML('thtml/plugins',true);
|
||||||
|
|
||||||
|
ctx.registrateMenuItem({
|
||||||
|
name: 'Server Plugins',
|
||||||
|
link: ctx.troot.tmeta.tplugin.angular.tbase+'/server/plugins',
|
||||||
|
enable: true,
|
||||||
|
roles: [],
|
||||||
|
icon: 'fa fa-umbrella'
|
||||||
|
},'server');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
26
lib/plugin/ui/angular/server/ui-angular-server-routes.js
vendored
Normal file
26
lib/plugin/ui/angular/server/ui-angular-server-routes.js
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function UIAngularServerRoutesPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'uiAngularServerRoutes';
|
||||||
|
ctx.description = 'Adds an angular server routes page.';
|
||||||
|
ctx.dependencies.push('angular');
|
||||||
|
ctx.dependencies.push('serverInfoPlugins');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.hostTemplateJS('js/server-routes');
|
||||||
|
ctx.hostTemplateHTML('thtml/routes',true);
|
||||||
|
|
||||||
|
ctx.registrateMenuItem({
|
||||||
|
name: 'Server Routes',
|
||||||
|
link: ctx.troot.tmeta.tplugin.angular.tbase+'/server/routes',
|
||||||
|
enable: true,
|
||||||
|
roles: [],
|
||||||
|
icon: 'fa fa-road'
|
||||||
|
},'server');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
128
lib/plugin/ui/angular/ui-angular.js
vendored
Normal file
128
lib/plugin/ui/angular/ui-angular.js
vendored
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
var debug = require('debug')('ff:tcrud:ui:angular:boot');
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var renderCrudController = function (tview, thtmlPrefix, tapiPrefix, tapiPrefix2) {
|
||||||
|
|
||||||
|
if (tview.tmeta.tmodel.tkeys.length === 0) {
|
||||||
|
throw Error('no model keys in: '+tview.tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
var keySlug = '';
|
||||||
|
for (var i = 0; i < tview.tmeta.tmodel.tkeys.length; i++) {
|
||||||
|
var key = tview.tmeta.tmodel.tkeys[i];
|
||||||
|
keySlug += '$routeParams.'+key;
|
||||||
|
if (i < (tview.tmeta.tmodel.tkeys.length - 1)) {
|
||||||
|
keySlug += '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tviewCode = '';
|
||||||
|
var slugParts = tview.tslug.split('/');
|
||||||
|
for (var i = 0; i < slugParts.length; i++) {
|
||||||
|
var part = slugParts[i];
|
||||||
|
part = part.replace(/-/g,''); // TODO use tcode which is already cleaned ?
|
||||||
|
tviewCode += part.substring(0,1).toUpperCase()+part.substring(1);
|
||||||
|
}
|
||||||
|
//debug('tviewCode: $s',tviewCode);
|
||||||
|
|
||||||
|
return function (req, res, next) {
|
||||||
|
res.set('Content-Type', 'text/javascript');
|
||||||
|
res.render('node-ff-tcrud/angular/js/crud/controller',{
|
||||||
|
tview: tview,
|
||||||
|
tviewCode: tviewCode,
|
||||||
|
thtmlPrefix: thtmlPrefix,
|
||||||
|
tapiPrefix: tapiPrefix,
|
||||||
|
tapiPrefix2: tapiPrefix2,
|
||||||
|
ejsRouteParams: keySlug
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var renderCrudTemplate = function (tview,paction) {
|
||||||
|
|
||||||
|
var ejsKeyRow = '';
|
||||||
|
var ejsKeyData = '';
|
||||||
|
for (var i = 0; i < tview.tmeta.tmodel.tkeys.length; i++) {
|
||||||
|
var key = tview.tmeta.tmodel.tkeys[i];
|
||||||
|
ejsKeyRow += '{{row.'+key+'}}';
|
||||||
|
ejsKeyData += '{{data.'+key+'}}';
|
||||||
|
if (i < (tview.tmeta.tmodel.tkeys.length - 1)) {
|
||||||
|
ejsKeyRow += '/';
|
||||||
|
ejsKeyData += '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (req, res, next) {
|
||||||
|
res.render('node-ff-tcrud/angular/'+paction+'/'+req.params.action,{
|
||||||
|
tview: tview,
|
||||||
|
ejsKeyRow: ejsKeyRow,
|
||||||
|
ejsKeyData: ejsKeyData
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return function UIAngularCorePlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key = 'angular';
|
||||||
|
ctx.description = 'Exports angular ui data.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'ui-angular.json';
|
||||||
|
ctx.dependencies.push('uiLibAngular');
|
||||||
|
ctx.dependencies.push('uiLibFFSpaLoader');
|
||||||
|
//ctx.dependencies.push('uiLibTopcoat');
|
||||||
|
ctx.dependencies.push('serverConfigTMenu');
|
||||||
|
ctx.dependencies.push('uiLibFontFaceOnLoad');
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.hostTemplateJS('js/application');
|
||||||
|
ctx.hostTemplateJS('js/application-font');
|
||||||
|
ctx.hostTemplateJS('js/application-controller')
|
||||||
|
ctx.hostTemplateJS('js/navigation-service');
|
||||||
|
|
||||||
|
ctx.hostTemplateHTML('thtml/application-view',true);;
|
||||||
|
ctx.hostTemplateHTML('thtml/application-top',true);
|
||||||
|
ctx.hostTemplateHTML('thtml/application-top-action',true);
|
||||||
|
ctx.hostTemplateHTML('thtml/application-top-tabs',true);
|
||||||
|
|
||||||
|
var uiPath = ctx.troot.tmeta.tplugin.angular.tbase;
|
||||||
|
debug('Exported uiPath: %s',uiPath);
|
||||||
|
|
||||||
|
ctx.server.get('/', ctx.renderRedirect(uiPath));
|
||||||
|
ctx.server.get(uiPath, ctx.renderTemplate('index','text/html'));
|
||||||
|
ctx.server.get(uiPath+'/*', ctx.renderTemplate('index','text/html')); // must be last; for HTML5 history
|
||||||
|
|
||||||
|
ctx.registrateMenu({
|
||||||
|
name: 'Server',
|
||||||
|
icon: 'fa fa-server'
|
||||||
|
},'server'); // move ?
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configApi = function(ctx) {
|
||||||
|
var uriPrefix = ctx.createSlugApiTEntityBase();
|
||||||
|
var thtmlPrefix = uriPrefix + '/' + ctx.tview.tmeta.tplugin.angular.thtml;
|
||||||
|
var tapiPrefix = ctx.createSlugApiTEntityBasePlugin('formatJSON'); // TODO: move to tview ?
|
||||||
|
var tapiPrefix2 = ctx.createSlugApiTEntityBasePlugin('serverConfigTView'); // TODO: move to tview ?
|
||||||
|
|
||||||
|
|
||||||
|
ctx.server.get(uriPrefix + '/thtml/crud/:action', renderCrudTemplate(ctx.tview,'thtml/crud/'));
|
||||||
|
ctx.server.get(uriPrefix + '/crud/controller.js', renderCrudController(ctx.tview,thtmlPrefix,tapiPrefix,tapiPrefix2));
|
||||||
|
//ctx.server.get(uriPrefix + '/service.js', renderCrudService(tview))
|
||||||
|
|
||||||
|
ctx.registrateClientJSResource(uriPrefix + '/crud/controller.js');
|
||||||
|
|
||||||
|
if (ctx.tview.tmeta.tmenu.tenable && ctx.tview.tmeta.tmenu.tkey !== null && ctx.tview.tmeta.tmenu.titem) {
|
||||||
|
ctx.registrateMenuItem({
|
||||||
|
name: ctx.tview.tmeta.tmenu.tname,
|
||||||
|
link: ctx.tview.tmeta.tplugin.angular.tbase+'/'+ctx.tview.tslug+'/'+ctx.tview.tlist.tplugin.angular.tslug,
|
||||||
|
enable: ctx.tview.tlist.tenable,
|
||||||
|
roles: ctx.tview.tlist.troles,
|
||||||
|
icon: ctx.tview.tmeta.tmenu.ticon
|
||||||
|
},ctx.tview.tmeta.tmenu.tkey);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
72
lib/plugin/ui/angular/ui-angular.json
Normal file
72
lib/plugin/ui/angular/ui-angular.json
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tlist": { "tplugin": { "angular": {
|
||||||
|
"tslug": "list",
|
||||||
|
"thtml": "crud/list",
|
||||||
|
"tcontroller": {
|
||||||
|
"prefix": "tcrudAuto",
|
||||||
|
"postfix": "ListCntr",
|
||||||
|
"argu": "$scope, $http, $location, $routeParams, navigationService"
|
||||||
|
},
|
||||||
|
"tlinks": {
|
||||||
|
"DataTODO":"/ui/XNodeData/list/XNode/{{row.net_id}}/{{row.net_id}}"
|
||||||
|
}
|
||||||
|
}}},
|
||||||
|
"tcreate": { "tplugin": { "angular": {
|
||||||
|
"tslug": "create",
|
||||||
|
"thtml": "crud/create",
|
||||||
|
"tcontroller": {
|
||||||
|
"prefix": "tcrudAuto",
|
||||||
|
"postfix": "CreateCntr",
|
||||||
|
"argu": "$scope, $http, $location, $routeParams, navigationService"
|
||||||
|
}
|
||||||
|
}}},
|
||||||
|
"tedit": { "tplugin": { "angular": {
|
||||||
|
"tslug": "edit",
|
||||||
|
"thtml": "crud/edit",
|
||||||
|
"tcontroller": {
|
||||||
|
"prefix": "tcrudAuto",
|
||||||
|
"postfix": "EditCntr",
|
||||||
|
"argu": "$scope, $http, $location, $routeParams, navigationService"
|
||||||
|
}
|
||||||
|
}}},
|
||||||
|
"tread": { "tplugin": { "angular": {
|
||||||
|
"tslug": "read",
|
||||||
|
"thtml": "crud/read",
|
||||||
|
"troute": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"tcontroller": {
|
||||||
|
"prefix": "tcrudAuto",
|
||||||
|
"postfix": "ReadCntr",
|
||||||
|
"argu": "$scope, $http, $location, $routeParams, navigationService"
|
||||||
|
}
|
||||||
|
}}},
|
||||||
|
"tdelete": { "tplugin": { "angular": {
|
||||||
|
"tslug": "delete",
|
||||||
|
"thtml": "crud/delete",
|
||||||
|
"tcontroller": {
|
||||||
|
"prefix": "tcrudAuto",
|
||||||
|
"postfix": "DeleteCntr",
|
||||||
|
"argu": "$scope, $http, $location, $routeParams, navigationService"
|
||||||
|
}
|
||||||
|
}}},
|
||||||
|
"tcount": { "tplugin": { "angular": { "tslug": "list-count" }}},
|
||||||
|
"tverify": { "tplugin": { "angular": { "tslug": "verify" }}},
|
||||||
|
"tmeta": { "tplugin": { "angular": {
|
||||||
|
"tslug": "angular",
|
||||||
|
"tbase": "/ui",
|
||||||
|
"thtml": "thtml"
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tlist": { "tplugin": { "angular": { "tslug": "slug of api url" }}},
|
||||||
|
"tcreate": { "tplugin": { "angular": { "tslug": "slug of api url" }}},
|
||||||
|
"tedit": { "tplugin": { "angular": { "tslug": "slug of api url" }}},
|
||||||
|
"tread": { "tplugin": { "angular": { "tslug": "slug of api url" }}},
|
||||||
|
"tdelete": { "tplugin": { "angular": { "tslug": "slug of api url" }}},
|
||||||
|
"tcount": { "tplugin": { "angular": { "tslug": "slug of api url" }}},
|
||||||
|
"tverify": { "tplugin": { "angular": { "tslug": "slug of api url" }}},
|
||||||
|
"tmeta": { "tplugin": { "angular": { "tslug": "slug of api url" }}}
|
||||||
|
}
|
||||||
|
}
|
46
lib/plugin/ui/lib/ui-lib-angular.js
Normal file
46
lib/plugin/ui/lib/ui-lib-angular.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var incHostFileJSNodeModule = function(ctx,includeFile,namePart) {
|
||||||
|
if (includeFile) {
|
||||||
|
ctx.hostFileJSNodeModule({file: 'angular-'+namePart+'.min.js', path: 'angular-'+namePart});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return function UILibAngularPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='uiLibAngular';
|
||||||
|
ctx.description='Adds angular libs to resources.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'ui-lib-angular.json';
|
||||||
|
ctx.dependencies.push('uiLibJQuery');
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.hostFileJSNodeModule({file: 'angular.min.js', path: 'angular'});
|
||||||
|
|
||||||
|
var inc = ctx.troot.tmeta.tplugin.uiLibAngular.include;
|
||||||
|
incHostFileJSNodeModule(ctx,inc.animate,'animate');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.resource,'resource');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.route,'route');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.touch,'touch');
|
||||||
|
|
||||||
|
if (inc['ui-grid']) {
|
||||||
|
var filter = {
|
||||||
|
'(^.*url.*?;)': '', // removed all urls
|
||||||
|
'(@font-face[\\s\\S]*?})': '', // remove font-face
|
||||||
|
'(^\\s+)': '', // clean up white space
|
||||||
|
'(\\{[\\s\\/]+\\/.*)': '{', // rm comment on functions
|
||||||
|
'(^|\\s\\/\\/.*)': '', // rm comment lines
|
||||||
|
'(\\/\\*[\\s\\*\\!][\\s\\S]*?\\*\\/)': '', // rm comment blocks
|
||||||
|
};
|
||||||
|
ctx.hostFileJSNodeModule({file: 'ui-grid.min.js', path: 'angular-ui-grid'});
|
||||||
|
ctx.hostFileCSSNodeModule({file: 'ui-grid.css', path: 'angular-ui-grid', filterRegex: filter});
|
||||||
|
|
||||||
|
ctx.hostFileCSSFontNodeModule({file: 'ui-grid.ttf', path: 'angular-ui-grid/', fontFamily: 'ui-grid'});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
19
lib/plugin/ui/lib/ui-lib-angular.json
Normal file
19
lib/plugin/ui/lib/ui-lib-angular.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tmeta": { "tplugin": { "uiLibAngular": {
|
||||||
|
"tslug": "uiLibAngular",
|
||||||
|
"include": {
|
||||||
|
"animate": true,
|
||||||
|
"resource": true,
|
||||||
|
"route": true,
|
||||||
|
"touch": true,
|
||||||
|
"ui-grid": true
|
||||||
|
}
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tmeta": { "tplugin": { "uiLibAngular": {
|
||||||
|
"tslug": "The angular lib slug."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
27
lib/plugin/ui/lib/ui-lib-bootswatch.js
Normal file
27
lib/plugin/ui/lib/ui-lib-bootswatch.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function UILibBootstrapPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='uiLibBootswatch';
|
||||||
|
ctx.description='Adds and hosts bootstrap.css as client resource.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
var filter = {
|
||||||
|
'(^.*url.*?;)': '', // removed all urls
|
||||||
|
'(@font-face[\\s\\S]*?})': '', // remove font-face
|
||||||
|
//'(body[\\s\\S]*?})': '', // remove body
|
||||||
|
'(^\\s+)': '', // clean up white space
|
||||||
|
'(\\{[\\s\\/]+\\/.*)': '{', // rm comment on functions
|
||||||
|
'(^|\\s\\/\\/.*)': '', // rm comment lines
|
||||||
|
'(\\/\\*[\\s\\*\\!][\\s\\S]*?\\*\\/)': '', // rm comment blocks
|
||||||
|
};
|
||||||
|
ctx.hostFileCSSNodeModule({file: 'bootstrap.css', path: 'bootswatch/paper', filterRegex: filter});
|
||||||
|
ctx.hostFileJSNodeModule({file: 'bootstrap.js', path: 'bootstrap/dist/js'});
|
||||||
|
|
||||||
|
ctx.hostFileCSSFontNodeModule({file: 'glyphicons-halflings-regular.ttf', path: 'bootswatch/fonts/', fontFamily: 'Glyphicons Halflings'});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
20
lib/plugin/ui/lib/ui-lib-ff-spa-loader.js
Normal file
20
lib/plugin/ui/lib/ui-lib-ff-spa-loader.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function UILibSpaLoaderPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='uiLibFFSpaLoader';
|
||||||
|
ctx.description='Adds FFSpaLoader lib to resources.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.dependencies.push('serverConfigResourcesWeb');
|
||||||
|
ctx.dependencies.push('serverConfigResourcesMobile'); // TODO: is this opt ?
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
//ctx.hostFileJSNodeModule({file: 'es5-ff-spa-loader.js', path: 'es5-ff-spa-loader/dist', registrate: false});
|
||||||
|
ctx.hostFileJSNodeModule({file: 'es5-ff-spa-loader.js', path: '../../es5-ff-spa-loader', registrate: false});
|
||||||
|
ctx.hostFileCSSNodeModule({file: 'es5-ff-spa-loader.css', path: '../../es5-ff-spa-loader', registrate: false});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
39
lib/plugin/ui/lib/ui-lib-flot.js
Normal file
39
lib/plugin/ui/lib/ui-lib-flot.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var incHostFileJSNodeModule = function(ctx,includeFile,namePart) {
|
||||||
|
if (includeFile) {
|
||||||
|
ctx.hostFileJSNodeModule({file: 'jquery.flot.'+namePart+'.js',path: 'flot'});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return function UILibFlotPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='uiLibFlot';
|
||||||
|
ctx.description='Adds basic flot js libs to resources.';
|
||||||
|
ctx.localDir = __dirname;
|
||||||
|
ctx.localConfigTemplate = 'ui-lib-flot.json';
|
||||||
|
ctx.dependencies.push('uiLibJQuery');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.hostFileJSNodeModule({file: 'jquery.flot.js', path: 'flot'});
|
||||||
|
|
||||||
|
var inc = ctx.troot.tmeta.tplugin.uiLibFlot.include;
|
||||||
|
incHostFileJSNodeModule(ctx,inc.categories, 'categories');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.crosshair, 'crosshair');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.errorbars, 'errorbars');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.fillbetween, 'fillbetween');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.image, 'image');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.navigate, 'navigate');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.pie, 'pie');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.resize, 'resize');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.selection, 'selection');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.stack, 'stack');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.symbol, 'symbol');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.threshold, 'threshold');
|
||||||
|
incHostFileJSNodeModule(ctx,inc.time, 'time');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
27
lib/plugin/ui/lib/ui-lib-flot.json
Normal file
27
lib/plugin/ui/lib/ui-lib-flot.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"masterTEntityTemplate": {
|
||||||
|
"tmeta": { "tplugin": { "uiLibFlot": {
|
||||||
|
"tslug": "uiLibFlot",
|
||||||
|
"include": {
|
||||||
|
"categories": false,
|
||||||
|
"crosshair": false,
|
||||||
|
"errorbars": false,
|
||||||
|
"fillbetween": false,
|
||||||
|
"image": false,
|
||||||
|
"navigate": false,
|
||||||
|
"pie": true,
|
||||||
|
"resize": true,
|
||||||
|
"selection": false,
|
||||||
|
"stack": true,
|
||||||
|
"symbol": false,
|
||||||
|
"threshold": false,
|
||||||
|
"time": true
|
||||||
|
}
|
||||||
|
}}}
|
||||||
|
},
|
||||||
|
"masterTEntityTHelp": {
|
||||||
|
"tmeta": { "tplugin": { "uiLibFlot": {
|
||||||
|
"tslug": "The server debug slug."
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
25
lib/plugin/ui/lib/ui-lib-fontawesome.js
Normal file
25
lib/plugin/ui/lib/ui-lib-fontawesome.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function UILibBootstrapPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='uiLibFontAwesome';
|
||||||
|
ctx.description='Adds fontawesome client resources.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
var filter = {
|
||||||
|
'(^.*url.*?;)': '', // removed all urls
|
||||||
|
'(@font-face[\\s\\S]*?})': '', // remove font-face
|
||||||
|
'(^\\s+)': '', // clean up white space
|
||||||
|
'(\\{[\\s\\/]+\\/.*)': '{', // rm comment on functions
|
||||||
|
'(^|\\s\\/\\/.*)': '', // rm comment lines
|
||||||
|
'(\\/\\*[\\s\\*\\!][\\s\\S]*?\\*\\/)': '', // rm comment blocks
|
||||||
|
};
|
||||||
|
ctx.hostFileCSSNodeModule({file: 'font-awesome.css', path: 'font-awesome/css', filterRegex: filter});
|
||||||
|
|
||||||
|
ctx.hostFileCSSFontNodeModule({file: 'fontawesome-webfont.ttf', path: 'font-awesome/fonts/', fontFamily: 'FontAwesome'});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
15
lib/plugin/ui/lib/ui-lib-fontfaceonload.js
Normal file
15
lib/plugin/ui/lib/ui-lib-fontfaceonload.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function UILibFontFaceOnLoadPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='uiLibFontFaceOnLoad';
|
||||||
|
ctx.description='Adds fontfaceonload js lib to resources.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.hostFileJSNodeModule({file: 'fontfaceonload.js', path: 'fontfaceonload/dist'});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
15
lib/plugin/ui/lib/ui-lib-jquery.js
Normal file
15
lib/plugin/ui/lib/ui-lib-jquery.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function UILibJQueryPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='uiLibJQuery';
|
||||||
|
ctx.description='Adds jquery js lib to resources.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.hostFileJSNodeModule({file: 'jquery.min.js', path: 'jquery/dist'});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
18
lib/plugin/ui/spa/ui-spa-style.js
Normal file
18
lib/plugin/ui/spa/ui-spa-style.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function UISpaStylePlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='uiSpaStyle';
|
||||||
|
ctx.description='Adds basic styling resources.';
|
||||||
|
ctx.dependencies.push('uiSpaTopcoatFont');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.hostTemplateCSS('css/flot');
|
||||||
|
ctx.hostTemplateCSS('css/panel');
|
||||||
|
ctx.hostTemplateCSS('css/style');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
19
lib/plugin/ui/spa/ui-spa-topcoat-font.js
Normal file
19
lib/plugin/ui/spa/ui-spa-topcoat-font.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
var fontPath = 'topcoat-fonts/font/SourceSansPro/';
|
||||||
|
|
||||||
|
return function UISpaTopcoatFontPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='uiSpaTopcoatFont';
|
||||||
|
ctx.description='Adds Source Sans Pro fonts.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
ctx.hostFileCSSFontNodeModule({file: 'SourceSansPro-Light.otf', path: fontPath, fontFamily: 'Source Sans', fontWeight: 200});
|
||||||
|
ctx.hostFileCSSFontNodeModule({file: 'SourceSansPro-Regular.otf', path: fontPath, fontFamily: 'Source Sans', fontWeight: 400});
|
||||||
|
ctx.hostFileCSSFontNodeModule({file: 'SourceSansPro-Semibold.otf',path: fontPath, fontFamily: 'Source Sans', fontWeight: 600});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
24
lib/plugin/ui/spa/ui-spa-topcoat.js-old
Normal file
24
lib/plugin/ui/spa/ui-spa-topcoat.js-old
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
return function UISpaTopcoatPlugin() {
|
||||||
|
|
||||||
|
this.configPlugin = function (ctx) {
|
||||||
|
ctx.key='uiSpaTopcoat';
|
||||||
|
ctx.description='Adds and hosts topcoat.css as client resource.';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.configServer = function(ctx) {
|
||||||
|
var filter = {
|
||||||
|
'(^.*url.*?;)': '', // removed all urls
|
||||||
|
'(@font[\\s\\S]*?})': '', // remove font-face
|
||||||
|
'(body[\\s\\S]*?})': '', // remove body
|
||||||
|
'(^\\s+)': '', // clean up white space
|
||||||
|
'(\\{[\\s\\/]+\\/.*)': '{', // rm comment on functions
|
||||||
|
'(^|\\s\\/\\/.*)': '', // rm comment lines
|
||||||
|
'(\\/\\*[\\s\\*\\!][\\s\\S]*?\\*\\/)': '', // rm comment blocks
|
||||||
|
};
|
||||||
|
ctx.hostFileCSSNodeModule({file: 'topcoat-mobile-dark.css',path: 'topcoat/css', filterRegex: filter});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
79
lib/tcrud-config.js
Normal file
79
lib/tcrud-config.js
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
var debug = require('debug')('ff:tcrud:config');
|
||||||
|
var configRegistry = require('./config-registry');
|
||||||
|
var configUtil = require('./config-util');
|
||||||
|
|
||||||
|
var mod = (function () {
|
||||||
|
|
||||||
|
return function TCrudConfig() {
|
||||||
|
|
||||||
|
this.getClientJSResources = function() {
|
||||||
|
return configRegistry.getMasterConfig().clientJSResources;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getClientCSSResources = function() {
|
||||||
|
return configRegistry.getMasterConfig().clientCSSResources;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getBackend = function(backendId) {
|
||||||
|
return configRegistry.getMasterConfig().backends[backendId];
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getRootTEntity = function() {
|
||||||
|
return configRegistry.getRootTEntity();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createTEntityNode = function(parent, tid, modelKeys, viewKeys) {
|
||||||
|
configRegistry.assertPhaseConfig();
|
||||||
|
var result = configUtil.clone(parent);
|
||||||
|
result.tchilds = [];
|
||||||
|
|
||||||
|
result.tid = tid;
|
||||||
|
parent.tchilds.push(result);
|
||||||
|
result.tparent = parent;
|
||||||
|
if (modelKeys) {
|
||||||
|
if (Array.isArray(modelKeys)) {
|
||||||
|
result.tmeta.tmodel.tkeys = modelKeys;
|
||||||
|
} else {
|
||||||
|
result.tmeta.tmodel.tkeys.push(modelKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (viewKeys) {
|
||||||
|
if (Array.isArray(modelKeys)) {
|
||||||
|
result.tkeys = viewKeys;
|
||||||
|
} else {
|
||||||
|
result.tkeys.push(viewKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createTEntity = function(parent, tid, modelKeys, viewKeys) {
|
||||||
|
configRegistry.assertPhaseConfig();
|
||||||
|
debug('createTEntity.tid: %s',tid);
|
||||||
|
var result = module.exports.createTEntityNode(parent,tid,modelKeys,viewKeys);
|
||||||
|
result.tmeta.tmodel.tid = tid;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createTField = function(parent, tid) {
|
||||||
|
configRegistry.assertPhaseConfig();
|
||||||
|
debug('createTField.tid: %s',tid);
|
||||||
|
var result = configUtil.clone(configRegistry.getMasterTemplates().masterTFieldTemplate);
|
||||||
|
result.tid = tid;
|
||||||
|
parent.tmeta.tfields[tid] = result;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createTView = function(tentity) {
|
||||||
|
debug('createTView: %s',tentity.tid);
|
||||||
|
configRegistry.assertPhaseServer();
|
||||||
|
var result = configUtil.clone(configRegistry.getMasterTemplates().masterTViewTemplate);
|
||||||
|
result.tid = tentity.tid;
|
||||||
|
configUtil.copyByTemplate('tview',result,tentity,configRegistry.getMasterTemplates().masterTViewTemplate);
|
||||||
|
configRegistry.pluginCall('fillTView',{tview: result,tentity: tentity});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = new mod;
|
139
lib/tcrud-setup.js
Normal file
139
lib/tcrud-setup.js
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
var express = require('express');
|
||||||
|
var bodyParser = require('body-parser');
|
||||||
|
var path = require('path');
|
||||||
|
var debug = require('debug')('ff:tcrud:setup');
|
||||||
|
var configRegistry = require('./config-registry');
|
||||||
|
var buildServerApi = require('./build-server-api');
|
||||||
|
var buildServerApiTEntity = require('./build-server-api-tentity');
|
||||||
|
|
||||||
|
var mod = (function () {
|
||||||
|
|
||||||
|
var server = null;
|
||||||
|
|
||||||
|
var expressCreate = function() {
|
||||||
|
if (server === null) {
|
||||||
|
server = express();
|
||||||
|
} else {
|
||||||
|
throw new Error('Can only create once.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var expressBuild = function(options) {
|
||||||
|
if (!options) {
|
||||||
|
options = {
|
||||||
|
viewsDir: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var viewsDirs = [];
|
||||||
|
viewsDirs.push(path.join(__dirname, 'www_views'));
|
||||||
|
if (options.viewsDir) {
|
||||||
|
viewsDirs.push(options.viewsDir);
|
||||||
|
}
|
||||||
|
server.set('view engine', 'ejs');
|
||||||
|
server.set('views', viewsDirs);
|
||||||
|
debug('build.views: '+viewsDirs);
|
||||||
|
|
||||||
|
server.use(bodyParser.json());
|
||||||
|
server.use(bodyParser.urlencoded());
|
||||||
|
debug('build.bodyParser');
|
||||||
|
|
||||||
|
buildServerApi.build(server);
|
||||||
|
buildServerApiTEntity.build(server);
|
||||||
|
debug('build.serverApi');
|
||||||
|
};
|
||||||
|
|
||||||
|
var expressListen = function() {
|
||||||
|
var tcrud = configRegistry.getRootTEntity();
|
||||||
|
var serverPortIndex = tcrud.tmeta.tserver.thost.indexOf(':',6); // TODO: make robust
|
||||||
|
var serverPort = tcrud.tmeta.tserver.thost.substring(serverPortIndex+1);
|
||||||
|
debug('listen port: '+serverPort);
|
||||||
|
server.listen(serverPort);
|
||||||
|
return serverPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function TCrudSetup() {
|
||||||
|
|
||||||
|
this.pluginLoad = function(plugin) {
|
||||||
|
configRegistry.assertPhaseInit();
|
||||||
|
configRegistry.pluginLoad(plugin);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.pluginEnable = function(pluginKey) {
|
||||||
|
configRegistry.assertPhaseInit();
|
||||||
|
configRegistry.pluginEnable(pluginKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.pluginEnableAll = function() {
|
||||||
|
configRegistry.assertPhaseInit();
|
||||||
|
configRegistry.pluginEnable('.*');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.pluginDisable = function(pluginKey) {
|
||||||
|
configRegistry.assertPhaseInit();
|
||||||
|
configRegistry.pluginEnable(pluginKey,false);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.phaseConfig = function() {
|
||||||
|
configRegistry.assertPhaseInit();
|
||||||
|
configRegistry.phaseNext();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.phaseServer = function() {
|
||||||
|
configRegistry.assertPhaseConfig();
|
||||||
|
configRegistry.phaseNext();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.phaseServerUp = function() {
|
||||||
|
configRegistry.assertPhaseServer();
|
||||||
|
configRegistry.phaseNext();
|
||||||
|
|
||||||
|
var ctx = {
|
||||||
|
server: server
|
||||||
|
}
|
||||||
|
configRegistry.pluginCall('configPostBoot',ctx);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.expressSimple = function(options) {
|
||||||
|
expressCreate();
|
||||||
|
expressBuild(options);
|
||||||
|
return expressListen();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.expressCreate = function() {
|
||||||
|
configRegistry.assertPhaseServer();
|
||||||
|
expressCreate();
|
||||||
|
return server;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.expressBuild = function(options) {
|
||||||
|
configRegistry.assertPhaseServer();
|
||||||
|
expressBuild(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.expressListen = function() {
|
||||||
|
configRegistry.assertPhaseServer();
|
||||||
|
return expressListen();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = new mod;
|
||||||
|
|
||||||
|
//
|
||||||
|
//ConfigSetupExpress.prototype.renderTemplatePath = function(viewPath) {
|
||||||
|
// if (!viewPath) {
|
||||||
|
// viewPath = '';
|
||||||
|
// }
|
||||||
|
// return function (req, res) {
|
||||||
|
// res.locals.query = req.query;
|
||||||
|
// var qi = req.url.indexOf('?');
|
||||||
|
// if (qi === -1) {
|
||||||
|
// qi = req.url.length;
|
||||||
|
// }
|
||||||
|
// res.render(viewPath + req.url.substring(req.route.path.length-1, qi));
|
||||||
|
// };
|
||||||
|
//}
|
18
lib/www_views/node-ff-tcrud/angular/index.ejs
Normal file
18
lib/www_views/node-ff-tcrud/angular/index.ejs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<title>Loading</title>
|
||||||
|
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
|
||||||
|
<script src="/api/plugin/uiLibFFSpaLoader/es5-ff-spa-loader.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/api/plugin/uiLibFFSpaLoader/es5-ff-spa-loader.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
FFSpaLoader.options.boot.debug.enable = true;
|
||||||
|
FFSpaLoader.options.boot.angular.modules.push('tcrudUI');
|
||||||
|
FFSpaLoader.options.server.assets = '/api/server/config/client-resources-mobile';
|
||||||
|
FFSpaLoader.start();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,14 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
tcrudUI.controller('ApplicationController',function($scope,$http,$location,navigationService) {
|
||||||
|
console.log('start menu controller');
|
||||||
|
$scope.goLink = function ( path ) {
|
||||||
|
$location.path( path );
|
||||||
|
};
|
||||||
|
$scope.navigationService = navigationService;
|
||||||
|
$scope.applicationMenu = {};
|
||||||
|
$http.get('<%= troot.tmeta.tserver.tslugs.tbase %>/<%= troot.tmeta.tserver.tslugs.tserver %>/config/menu').success(function(data, status, headers, config) {
|
||||||
|
$scope.applicationMenu = data.data;
|
||||||
|
$scope.applicationMenuKeys = Object.keys(data.data);
|
||||||
|
});
|
||||||
|
});
|
15
lib/www_views/node-ff-tcrud/angular/js/application-font.ejs
Normal file
15
lib/www_views/node-ff-tcrud/angular/js/application-font.ejs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
console.log('FFTCrudExample.fontFaceOnload check');
|
||||||
|
var ffolStartTime = new Date().getTime();
|
||||||
|
FontFaceOnload('Source Sans', {
|
||||||
|
timeout: 1234,
|
||||||
|
success: function() {
|
||||||
|
console.log('FFTCrudExample.FontFaceOnload success in '+(new Date().getTime()-ffolStartTime)+' ms.');
|
||||||
|
document.documentElement.className += ' fontLoaded';
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
console.log('FFTCrudExample.fontFaceOnload timeout.');
|
||||||
|
document.documentElement.className += ' fontLoaded';
|
||||||
|
}
|
||||||
|
});
|
26
lib/www_views/node-ff-tcrud/angular/js/application.ejs
Normal file
26
lib/www_views/node-ff-tcrud/angular/js/application.ejs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var serverUrl = window.FFServerUrl;
|
||||||
|
var crudRouteInit = [];
|
||||||
|
var pageRouteInit = [];
|
||||||
|
|
||||||
|
document.title = 'TCrud Example';
|
||||||
|
|
||||||
|
$(document.createElement('div')).attr('ng-controller', 'ApplicationController').attr('ng-include','\''+serverUrl+'/api/plugin/angular/thtml/application-top\'').appendTo($('body'));
|
||||||
|
$(document.createElement('div')).attr('ng-include','\''+serverUrl+'/api/plugin/angular/thtml/application-view\'').appendTo($('body'));
|
||||||
|
|
||||||
|
var tcrudUI = angular.module('tcrudUI', ['ngRoute','ngTouch','ngAnimate', 'ui.grid', 'ui.grid.pagination','ui.grid.cellNav', 'ui.grid.edit', 'ui.grid.resizeColumns', 'ui.grid.pinning', 'ui.grid.selection', 'ui.grid.moveColumns', 'ui.grid.exporter', 'ui.grid.importer', 'ui.grid.grouping', 'ui.grid.autoResize']).
|
||||||
|
config(['$routeProvider', '$locationProvider', '$sceDelegateProvider', function($routeProvider, $locationProvider, $sceDelegateProvider) {
|
||||||
|
|
||||||
|
// init routes
|
||||||
|
pageRouteInit.forEach(function(init) { init($routeProvider, $locationProvider); });
|
||||||
|
crudRouteInit.forEach(function(init) { init($routeProvider, $locationProvider); });
|
||||||
|
|
||||||
|
$sceDelegateProvider.resourceUrlWhitelist(['self',serverUrl+'/**']);
|
||||||
|
$routeProvider.otherwise({ redirectTo: '/ui' });
|
||||||
|
$locationProvider.html5Mode({requireBase: false});
|
||||||
|
}]);
|
||||||
|
|
||||||
|
tcrudUI.run(['$route', function($route) {
|
||||||
|
$route.reload(); // ng-view works inside the ng-include
|
||||||
|
}]);
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
$scope.<%= taction %>None = function () {
|
||||||
|
<% if (tview.tlist) { %>
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.tplugin.angular.tslug %>');
|
||||||
|
<% } else { %>
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/');
|
||||||
|
<% } %>
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
$routeProvider.when('<%= tview.tmeta.tplugin.angular.tbase %>/<%= tview.tslug %>/<%= tview[taction].tplugin.angular.tslug %><%= routeEnd %>', {
|
||||||
|
templateUrl: '<%= thtmlPrefix %>/<%= tview[taction].tplugin.angular.thtml %>',
|
||||||
|
controller: <%= tview[taction].tplugin.angular.tcontroller.prefix %><%= tviewCode %><%= tview[taction].tplugin.angular.tcontroller.postfix %>
|
||||||
|
});
|
173
lib/www_views/node-ff-tcrud/angular/js/crud/controller.ejs
Normal file
173
lib/www_views/node-ff-tcrud/angular/js/crud/controller.ejs
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
//
|
||||||
|
// Auto generated controller mapping for: <%= tview.tid %>
|
||||||
|
//
|
||||||
|
|
||||||
|
crudRouteInit.push(auto<%= tviewCode %>Init);
|
||||||
|
|
||||||
|
function auto<%= tviewCode %>Init($routeProvider, $locationProvider) {
|
||||||
|
<% if (tview.tlist) { %>
|
||||||
|
$routeProvider.when('<%= tview.tmeta.tplugin.angular.tbase %>/<%= tview.tslug %>/', {
|
||||||
|
redirectTo: '<%= tview.tmeta.tplugin.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.tplugin.angular.tslug %>'
|
||||||
|
});
|
||||||
|
<%- include('controller-route', {tview: tview,tviewCode: tviewCode,thtmlPrefix:thtmlPrefix,taction: 'tlist', routeEnd: ''}); %>
|
||||||
|
<% } %>
|
||||||
|
<% if (tview.tcreate) { %>
|
||||||
|
<%- include('controller-route', {tview: tview,tviewCode: tviewCode,thtmlPrefix:thtmlPrefix,taction: 'tcreate', routeEnd: ''}); %>
|
||||||
|
<% } %>
|
||||||
|
<% if (tview.tedit) { %>
|
||||||
|
<%- include('controller-route', {tview: tview,tviewCode: tviewCode,thtmlPrefix:thtmlPrefix,taction: 'tedit', routeEnd: '/'+tview.tmeta.tmodel.tkey}); %>
|
||||||
|
<% } %>
|
||||||
|
<% if (tview.tread) { %>
|
||||||
|
<%- include('controller-route', {tview: tview,tviewCode: tviewCode,thtmlPrefix:thtmlPrefix,taction: 'tread', routeEnd: '/'+tview.tmeta.tmodel.tkey}); %>
|
||||||
|
<% } %>
|
||||||
|
<% if (tview.tdelete) { %>
|
||||||
|
<%- include('controller-route', {tview: tview,tviewCode: tviewCode,thtmlPrefix:thtmlPrefix,taction: 'tdelete', routeEnd: '/'+tview.tmeta.tmodel.tkey}); %>
|
||||||
|
<% } %>
|
||||||
|
}
|
||||||
|
|
||||||
|
<% if (tview.tlist) { %>
|
||||||
|
function <%= tview.tlist.tplugin.angular.tcontroller.prefix %><%= tviewCode %><%= tview.tlist.tplugin.angular.tcontroller.postfix %>(<%= tview.tlist.tplugin.angular.tcontroller.argu %>) {
|
||||||
|
|
||||||
|
$scope.uiTableMain = {};
|
||||||
|
$scope.uiTableMain.enableColumnResizing = true;
|
||||||
|
$scope.uiTableMain.enableFiltering = false;
|
||||||
|
$scope.uiTableMain.enableGridMenu = true;
|
||||||
|
$scope.uiTableMain.showGridFooter = false;
|
||||||
|
$scope.uiTableMain.showColumnFooter = false;
|
||||||
|
$scope.uiTableMain.paginationPageSizes = [25, 50, 75];
|
||||||
|
$scope.uiTableMain.paginationPageSize = 25;
|
||||||
|
$scope.uiTableMain.enableFullRowSelection = true;
|
||||||
|
$scope.uiTableMain.multiSelect = false;
|
||||||
|
$scope.uiTableMain.columnDefs = [];
|
||||||
|
|
||||||
|
$scope.uiTableMain.onRegisterApi = function(gridApi){
|
||||||
|
$scope.gridApi = gridApi;
|
||||||
|
|
||||||
|
gridApi.selection.on.rowSelectionChanged($scope,function(row) {
|
||||||
|
if ($scope.gridApi.selection.getSelectedRows().length > 0) {
|
||||||
|
navigationService.actions.open = $scope.doEdit;
|
||||||
|
} else {
|
||||||
|
navigationService.actions.open = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var fetchData = function() {
|
||||||
|
$http.get('<%= tapiPrefix %>/<%= tview.tlist.tplugin.formatJSON.tslug %>').success(function(data, status, headers, config) {
|
||||||
|
$scope.uiTableMain.data = data.data;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
navigationService.actions.refresh = function() {
|
||||||
|
fetchData();
|
||||||
|
};
|
||||||
|
navigationService.actions.create = function() {
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/<%= tview.tslug %>/<%= tview.tcreate.tplugin.angular.tslug %>');
|
||||||
|
};
|
||||||
|
$scope.doEdit = function() {
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/<%= tview.tslug %>/<%= tview.tedit.tplugin.angular.tslug %>/'+$scope.gridApi.selection.getSelectedRows()[0].country_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
$http.get('<%= tapiPrefix2 %>').success(function(data, status, headers, config) {
|
||||||
|
var tview = data.data.tview;
|
||||||
|
tview.tlist.tfields.forEach(function (fieldKey) {
|
||||||
|
var field = tview.tmeta.tfields[fieldKey];
|
||||||
|
$scope.uiTableMain.columnDefs.push({
|
||||||
|
name: field.tname,
|
||||||
|
field: field.tid,
|
||||||
|
type2: field.ttype,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
navigationService.pageTitle = tview.tname;
|
||||||
|
fetchData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (tview.tcreate) { %>
|
||||||
|
function <%= tview.tcreate.tplugin.angular.tcontroller.prefix %><%= tviewCode %><%= tview.tcreate.tplugin.angular.tcontroller.postfix %>(<%= tview.tcreate.tplugin.angular.tcontroller.argu %>) {
|
||||||
|
$scope.data = {};
|
||||||
|
$scope.tcreateData = function () {
|
||||||
|
$http.post('<%= tapiPrefix %>/<%= tview.tcreate.tplugin.formatJSON.tslug %>', $scope.data).success(function(data) {
|
||||||
|
<% if (tview.tlist) { %>
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.tplugin.angular.tslug %>');
|
||||||
|
<% } else { %>
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/');
|
||||||
|
<% } %>
|
||||||
|
});
|
||||||
|
}
|
||||||
|
<%- include('controller-action-none', {tview: tview,taction: 'tcreate'}); %>
|
||||||
|
}
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (tview.tread) { %>
|
||||||
|
function <%= tview.tread.tplugin.angular.tcontroller.prefix %><%= tviewCode %><%= tview.tread.tplugin.angular.tcontroller.postfix %>(<%= tview.tread.tplugin.angular.tcontroller.argu %>) {
|
||||||
|
$scope.data = {};
|
||||||
|
$http.get('<%= tapiPrefix %>/<%= tview.tread.tplugin.formatJSON.tslug %>/' + <%= ejsRouteParams %>).success(function(data) {
|
||||||
|
$scope.data = data.data;
|
||||||
|
});
|
||||||
|
<%- include('controller-action-none', {tview: tview,taction: 'tread'}); %>
|
||||||
|
}
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (tview.tedit) { %>
|
||||||
|
function <%= tview.tedit.tplugin.angular.tcontroller.prefix %><%= tviewCode %><%= tview.tedit.tplugin.angular.tcontroller.postfix %>(<%= tview.tedit.tplugin.angular.tcontroller.argu %>) {
|
||||||
|
$scope.data = {};
|
||||||
|
var fetchData = function() {
|
||||||
|
$http.get('<%= tapiPrefix %>/<%= tview.tread.tplugin.formatJSON.tslug %>/' + <%= ejsRouteParams %>).success(function(data) {
|
||||||
|
$scope.data = data.data;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
|
||||||
|
$scope.teditData = function () {
|
||||||
|
$http.put('<%= tapiPrefix %>/<%= tview.tedit.tplugin.formatJSON.tslug %>/' + <%= ejsRouteParams %>, $scope.data ).success(function(data) {
|
||||||
|
<% if (tview.tread) { %>
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/<%= tview.tslug %>/<%= tview.tread.tplugin.angular.tslug %>/' + <%= ejsRouteParams %>);
|
||||||
|
<% } else { %>
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/');
|
||||||
|
<% } %>
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$scope.tdeleteData = function () {
|
||||||
|
$http.delete('<%= tapiPrefix %>/<%= tview.tdelete.tplugin.formatJSON.tslug %>/'+ <%= ejsRouteParams %>, $scope.data).success(function(data) {
|
||||||
|
<% if (tview.tlist) { %>
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.tplugin.angular.tslug %>');
|
||||||
|
<% } else { %>
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/');
|
||||||
|
<% } %>
|
||||||
|
});
|
||||||
|
}
|
||||||
|
<%- include('controller-action-none', {tview: tview,taction: 'tedit'}); %>
|
||||||
|
|
||||||
|
navigationService.actions.save = $scope.teditData;
|
||||||
|
navigationService.actions.cancel = $scope.teditNone;
|
||||||
|
navigationService.actions.delete = $scope.tdeleteData;
|
||||||
|
navigationService.actions.refresh = function() {
|
||||||
|
fetchData();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (tview.tdelete) { %>
|
||||||
|
function <%= tview.tdelete.tplugin.angular.tcontroller.prefix %><%= tviewCode %><%= tview.tdelete.tplugin.angular.tcontroller.postfix %>(<%= tview.tdelete.tplugin.angular.tcontroller.argu %>) {
|
||||||
|
$scope.data = {};
|
||||||
|
$http.get('<%= tapiPrefix %>/<%= tview.tread.tplugin.formatJSON.tslug %>/' + <%= ejsRouteParams %>).success(function(data) {
|
||||||
|
$scope.data = data.data;
|
||||||
|
console.log('delete obj: '+JSON.stringify(data.data));
|
||||||
|
});
|
||||||
|
$scope.tdeleteData = function () {
|
||||||
|
$http.delete('<%= tapiPrefix %>/<%= tview.tdelete.tplugin.formatJSON.tslug %>/'+ <%= ejsRouteParams %>, $scope.data).success(function(data) {
|
||||||
|
<% if (tview.tlist) { %>
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.tplugin.angular.tslug %>');
|
||||||
|
<% } else { %>
|
||||||
|
$location.url('<%= tview.tmeta.tplugin.angular.tbase %>/');
|
||||||
|
<% } %>
|
||||||
|
});
|
||||||
|
}
|
||||||
|
<%- include('controller-action-none', {tview: tview,taction: 'tdelete'}); %>
|
||||||
|
}
|
||||||
|
<% } %>
|
|
@ -0,0 +1,57 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
tcrudUI.factory('navigationService', ['$route', '$rootScope',
|
||||||
|
function($route, $rootScope) {
|
||||||
|
|
||||||
|
var actions = {
|
||||||
|
save: null,
|
||||||
|
cancel: null,
|
||||||
|
open: null,
|
||||||
|
delete: null,
|
||||||
|
create: null,
|
||||||
|
refresh: null
|
||||||
|
};
|
||||||
|
var resetActions = function() {
|
||||||
|
for (var key in actions) {
|
||||||
|
if (key.indexOf('Impl') > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
actions[key] = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
actions.saveImpl = function() {
|
||||||
|
actions.save();
|
||||||
|
resetActions();
|
||||||
|
};
|
||||||
|
actions.cancelImpl = function() {
|
||||||
|
actions.cancel();
|
||||||
|
resetActions();
|
||||||
|
};
|
||||||
|
actions.openImpl = function() {
|
||||||
|
actions.open();
|
||||||
|
resetActions();
|
||||||
|
};
|
||||||
|
actions.deleteImpl = function() {
|
||||||
|
actions.delete();
|
||||||
|
resetActions();
|
||||||
|
};
|
||||||
|
|
||||||
|
var pageTabs = [];
|
||||||
|
var pageTitle = '';
|
||||||
|
var pageLocations = [];
|
||||||
|
|
||||||
|
$rootScope.$on('$routeChangeSuccess', function() {
|
||||||
|
pageTabs = [];
|
||||||
|
pageTitle = '';
|
||||||
|
pageLocations = [];
|
||||||
|
resetActions(); // to late gives flikering..
|
||||||
|
//$rootScope.$apply();
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
actions: actions,
|
||||||
|
pageTabs: pageTabs,
|
||||||
|
pageTitle: pageTitle,
|
||||||
|
pageLocations: pageLocations,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
]);
|
|
@ -0,0 +1,20 @@
|
||||||
|
<div class="navbar-collapse" >
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li>
|
||||||
|
<button type="button" class="fa fa-plus btn btn-default" ng-click="navigationService.actions.create()" ng-show="navigationService.actions.create !== null">
|
||||||
|
New
|
||||||
|
</button>
|
||||||
|
<button type="button" class="fa fa-caret-left btn btn-default" ng-click="navigationService.actions.cancelImpl()" ng-show="navigationService.actions.cancel !== null">
|
||||||
|
</button>
|
||||||
|
<button type="button" class="fa fa-refresh btn btn-default" ng-click="navigationService.actions.refresh()" ng-show="navigationService.actions.refresh !== null">
|
||||||
|
</button>
|
||||||
|
<button type="button" class="fa fa-save btn btn-primary" ng-click="navigationService.actions.saveImpl()" ng-show="navigationService.actions.save !== null">
|
||||||
|
</button>
|
||||||
|
<button type="button" class="fa fa-file-o btn btn-success" ng-click="navigationService.actions.openImpl()" ng-show="navigationService.actions.open !== null">
|
||||||
|
Open
|
||||||
|
</button>
|
||||||
|
<button type="button" class="fa fa-trash-o btn btn-warning" data-toggle="modal" data-target="#deleteModal" ng-show="navigationService.actions.delete !== null">
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<div class="navbar-collapse" >
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li>
|
||||||
|
<button type="button" class="{{tab.icon}} btn btn-default" ng-repeat="tab in navigationService.pageTabs" ng-click="tab.click()">
|
||||||
|
{{tab.name}}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
|
@ -0,0 +1,69 @@
|
||||||
|
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||||
|
<div class="container">
|
||||||
|
<button type="button" class="navbar-menu" ng-click="isMenuExpanded = !isMenuExpanded;isExpanded = false">
|
||||||
|
<span class="sr-only">Toggle menu</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<div class="navbar-collapse navbar-header-left" ng-include="'/api/plugin/angular/thtml/application-top-action'"></div>
|
||||||
|
<div class="navbar-collapse navbar-header-left" ng-include="'/api/plugin/angular/thtml/application-top-tabs'"></div>
|
||||||
|
<button type="button" class="navbar-toggle navbar-header-right" ng-click="isExpanded = !isExpanded;isMenuExpanded = false">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<div class="for-sm-view-hide">
|
||||||
|
<div class="navbar-collapse">
|
||||||
|
<div class="navbar-right">
|
||||||
|
<ul class="nav navbar-nav navbar-right"><li><a href="/">Logout</a></li></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<div class="for-lg-view-hide">
|
||||||
|
<div class="navbar-collapse" ng-show="isExpanded" ng-click="isExpanded = false">
|
||||||
|
<div class="navbar-right">
|
||||||
|
<ul class="nav navbar-nav navbar-right"><li><a href="/">Logout</a></li></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="for-menu-view-hide">
|
||||||
|
<div class="navbar-collapse" ng-show="isMenuExpanded" ng-click="isMenuExpanded = false">
|
||||||
|
<ul class="nav navbar-nav-menu" ng-repeat="menuKey in applicationMenuKeys">
|
||||||
|
<li>
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li class="navbar-nav-menu-group"><i class="{{applicationMenu[menuKey].icon}}"></i> {{applicationMenu[menuKey].name}}</li>
|
||||||
|
<li class="" ng-repeat="item in applicationMenu[menuKey].items">
|
||||||
|
<a href="{{item.link}}" ng-click="goLink('{{item.link}}')"><i class="{{item.icon}}"></i> {{item.name}}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<br/>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>{{navigationService.pageTitle}}</p>
|
||||||
|
</div>
|
||||||
|
<div id="deleteModal" class="modal fade" role="dialog">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||||
|
<h4 class="modal-title">Confirm Delete</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>Are you sure to delete this record ?</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-danger" data-dismiss="modal" ng-click="navigationService.actions.deleteImpl()">Delete</button>
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<div role="main" class="container-fluid">
|
||||||
|
<div>
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<!--[if lt IE 7]>
|
||||||
|
<p class="alert alert-error">Your browser is <em>ancient!</em>
|
||||||
|
<a href="http://browsehappy.com/">Upgrade to a different browser</a> or
|
||||||
|
<a href="http://www.google.com/chromeframe/?redirect=true">install Google Chrome Frame</a> to experience this site.
|
||||||
|
</p>
|
||||||
|
<![endif]-->
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<div class="alert">
|
||||||
|
You are using an old version of Internet Explorer.
|
||||||
|
For better and safer browsing experience please <a href="http://www.microsoft.com/IE9">upgrade IE</a>
|
||||||
|
or install <a href="http://google.com/chrome">Google Chrome browser</a>.
|
||||||
|
</div>
|
||||||
|
<![endif]-->
|
||||||
|
</div>
|
||||||
|
<div class="fillHeightView" ng-view/>
|
||||||
|
</div>
|
||||||
|
</div>
|
16
lib/www_views/node-ff-tcrud/angular/thtml/crud/create.ejs
Normal file
16
lib/www_views/node-ff-tcrud/angular/thtml/crud/create.ejs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<h2>Create <%= tview.tname %></h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<form role="form">
|
||||||
|
<% tview.tedit.tfields.forEach(function (fieldKey) { %>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="<%= tview.tmeta.tfields[fieldKey].tid %>"><%= tview.tmeta.tfields[fieldKey].tname %></label>
|
||||||
|
<input ng-model="data.<%= tview.tmeta.tfields[fieldKey].tid %>" name="<%= tview.tmeta.tfields[fieldKey].tid %>" class="form-control"></input>
|
||||||
|
</div>
|
||||||
|
<% }) %>
|
||||||
|
<button type="submit" class="btn btn-default" ng-click="tcreateData()">Submit</button>
|
||||||
|
<button type="submit" class="btn btn-default" ng-click="tcreateNone()">Cancel</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-4"></div>
|
||||||
|
</div>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<h2>Delete <%= tview.tname %></h2>
|
||||||
|
<div>
|
||||||
|
<p>Are you sure you want to delete this <%= tview.tname %> <%= ejsKeyData %> ?</p>
|
||||||
|
<button ng-click="tdeleteData()">Yes</button> | -
|
||||||
|
<button ng-click="tdeleteNone()">No thanks</button>
|
||||||
|
<div>
|
12
lib/www_views/node-ff-tcrud/angular/thtml/crud/edit.ejs
Normal file
12
lib/www_views/node-ff-tcrud/angular/thtml/crud/edit.ejs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
<h2> Edit <%= tview.tname %></h2>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<form role="form">
|
||||||
|
<% tview.tedit.tfields.forEach(function (fieldKey) { %>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="<%= tview.tmeta.tfields[fieldKey].tid %>"><%= tview.tmeta.tfields[fieldKey].tname %></label>
|
||||||
|
<input ng-model="data.<%= tview.tmeta.tfields[fieldKey].tid %>" name="<%= tview.tmeta.tfields[fieldKey].tid %>" class="topcoat-text-input"></input>
|
||||||
|
</div>
|
||||||
|
<% }) %>
|
||||||
|
</form>
|
||||||
|
<div class="col-lg-4"></div>
|
1
lib/www_views/node-ff-tcrud/angular/thtml/crud/list.ejs
Normal file
1
lib/www_views/node-ff-tcrud/angular/thtml/crud/list.ejs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<div ui-grid="uiTableMain" class="grid fillHeightCalc" ng-swipe-left="doEdit()" ui-grid-pagination ui-grid-resize-columns ui-grid-move-columns ui-grid-exporter ui-grid-selection ui-grid-pinning ui-grid-auto-resize></div>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue