UNPKG

we-core

Version:

We.js is a node.js framework for build real time applications, sites or blogs!

353 lines (307 loc) 9.33 kB
/** * We.js Plugin Class * * */ var _ = require('lodash'), path = require('path'), fs = require('fs'), async = require('async'), requireAll = require('require-all'); module.exports = function (we) { /** * We.js plugin Class constructor * * @param {string} name plugin npm pakage name * @param {string} projectPath project path where the plugin is instaled */ function Plugin(pluginPath) { this.pluginPath = pluginPath; this.we = we; this.events = this.we.events; this.hooks = this.we.hooks; this.router = this.we.router; /** * We.js Assets * @type {Object} */ this.assets = this.we.view.assets; this.addJs = this.we.view.assets.addJs; this.addCss = this.we.view.assets.addCss; this['package.json'] = require( path.join( pluginPath , 'package.json') ); this.controllersPath = path.join( this.pluginPath, this.controllerFolder ); this.modelsPath = path.join( this.pluginPath, this.modelFolder ); this.templatesPath = this.pluginPath + '/server/templates'; this.helpersPath = this.pluginPath + '/server/helpers'; this.resourcesPath = this.pluginPath + '/server/resources'; this.routesPath = this.pluginPath + '/server/routes'; this.helpers = {}; this.layouts = {}; this.templates = {}; /** * Default plugin config object * * @type {Object} */ this.configs = {}; /** * Default plugin resources * * @type {Object} */ this.controllers = {}; this.models = {}; this.routes = {}; this.appFiles = []; this.appAdminFiles = []; } /** * Default initializer function, override in plugin.js file if need * * @param {Object} we we.js object * @param {Function} cb callback */ Plugin.prototype.init = function initPlugin(we, cb) { return cb(); } /** * Set plugin config * @param {Object} config */ Plugin.prototype.setConfigs = function setConfigs(configs) { this.configs = configs; } // default plugin paths Plugin.prototype.controllerFolder = 'server/controllers'; Plugin.prototype.modelFolder = 'server/models'; /** * Set plugin routes * * @param {object} routes */ Plugin.prototype.setRoutes = function setRoutes(routes) { var routePaths = Object.keys(routes); var routePath; for (var i = routePaths.length - 1; i >= 0; i--) { routePath = routePaths[i]; this.setRoute(routePath, routes[routePath]); } } /** * Set one route in plugin routes * @param {string} path route path * @param {object} configs route configs how will be avaible as res.locals */ Plugin.prototype.setRoute = function(routePath, configs) { this.routes[routePath] = configs; this.routes[routePath].path = routePath; this.routes[routePath].pluginPath = this.pluginPath; } Plugin.prototype.setResource = function(opts) { var router = this.we.router; var fullName = (opts.namePrefix || '') + opts.name; // first save resource in name or merge route options if exists if (!router.resourcesByName[fullName]) { router.resourcesByName[fullName] = opts; } else { _.merge(router.resourcesByName[fullName], opts); } if (opts.parent) { // is subroute if (!router.resourcesByName[opts.parent]) { // parent dont are set // temporary create parent resource wit subroutes attr router.resourcesByName[opts.parent] = { subRoutes: {} }; // add reference to route in parent subroutes router.resourcesByName[opts.parent].subRoutes[fullName] = router.resourcesByName[fullName]; } else { // parent resource is set if (!router.resourcesByName[opts.parent].subRoutes) { // add subRoutes object if dont are set router.resourcesByName[opts.parent].subRoutes = {}; } if (!router.resourcesByName[opts.parent].subRoutes[fullName]) { router.resourcesByName[opts.parent].subRoutes[fullName] = {}; } // add reference to route in parent resource subroutes router.resourcesByName[opts.parent].subRoutes[fullName] = router.resourcesByName[fullName]; } } else { // is route route router.resources[fullName] = router.resourcesByName[fullName]; } } /** * Set plugin helpers DEPRECATED! * Now this feature have a auto load! * @param {object} helpers */ Plugin.prototype.setHelpers = function setHelpers() { this.we.log.warn('DEPRECATED! Plugin.setHelpers in plugin: ', this.pluginPath); } /** * Set plugin layouts * @param {object} layouts */ Plugin.prototype.setLayouts = function setLayouts(layouts) { this.layouts = layouts; } /** * Set plugin templates DEPRECATED! * Now this feature have a auto load! * @param {object} templates */ Plugin.prototype.setTemplates = function setTemplates() { this.we.log.warn('DEPRECATED! Plugin.setTemplates in plugin: ', this.pluginPath); } /** * Load all we.js plugin features * * Auto load avaible for plugins, helpers ... * */ Plugin.prototype.loadFeatures = function loadFeatures(we, cb) { var self = this; async.parallel([ function loadControllesAndModels(done) { self.loadControllers(we); self.loadModels(we); done(); }, function loadPluginTemplates (done) { if (we.view.loadFromCache()) return done(); self.loadTemplates(done); }, function loadHelpers(done) { self.loadHelpers(done); }, function loaderHookExtensor(done) { we.hooks.trigger('plugin:load:features', { plugin: self, we: we }, done); }, // load resources then the routes function loadResources(done) { self.loadResources(function(){ self.loadRoutes(done); }); } ], function (err){ if (err) return cb(err); if (self.layouts) _.merge(we.view.configuration.layouts, self.layouts); cb(); }); } /** * load plugin controllers */ Plugin.prototype.loadControllers = function loadControllers() { try { this.controllers = requireAll({ dirname : this.controllersPath, filter : /(.+)\.js$/ }); } catch(e) { if (e.code !== 'ENOENT') throw e; } }; /** * load plugin models */ Plugin.prototype.loadModels = function loadModels(we) { try { this.models = requireAll({ dirname : this.modelsPath, filter : /(.+)\.js$/, resolve : function (model) { return model(we); } }); } catch(e) { if (e.code !== 'ENOENT') throw e; } }; /** * Load all plugin template paths * * Runs in we.js bootstrap */ Plugin.prototype.loadTemplates = function loadTemplates (cb) { var we = this.we; var self = this, templateName; // load template folders we.utils.listFilesRecursive(this.templatesPath, function (err, list){ for (var i = 0; i < list.length; i++) { if (list[i].indexOf('.hbs', list[i].length - 4) >-1) { templateName = list[i].substring(0, list[i].length-4).substring(self.templatesPath.length+1); // ensures that template names always have / slashes if (path.sep != '/') templateName = templateName.split(path.sep).join('/'); self.templates[templateName] = list[i]; we.view.configuration.templates[templateName] = list[i]; } } cb(); }); } /** * Load helpers from folder server/helpers * * @param {Object} we * @param {Function} cb callback */ Plugin.prototype.loadHelpers = function loadHelpers(cb) { var we = this.we; var self = this, name, file; fs.readdir(this.helpersPath , function (err, list){ if (err) { if (err.code === 'ENOENT') return cb(); return cb(err); } for (var i = 0; i < list.length; i++) { if (list[i].indexOf('.js', list[i].length - 3) >-1) { name = list[i].substring(0, list[i].length-3); file = self.helpersPath +'/'+list[i]; self.helpers[name] = file; we.view.configuration.helpers[name] = file; } } cb(); }); } /** * Load route resources from folder server/resources * * @param {Function} cb callback */ Plugin.prototype.loadResources = function loadResources(cb) { var self = this; fs.readdir(this.resourcesPath , function (err, list){ if (err) { if (err.code === 'ENOENT') return cb(); throw err; } for (var i = 0; i < list.length; i++) { self.setResource(require(self.resourcesPath+'/'+list[i])); } cb(); }); } /** * Load routes from folder server/routes * * @param {Function} cb callback */ Plugin.prototype.loadRoutes = function loadRoutes(cb) { var self = this; fs.readdir(this.routesPath , function (err, list) { if (err) { if (err.code === 'ENOENT') return cb(); throw err; } for (var i = 0; i < list.length; i++) { self.setRoutes(require(self.routesPath+'/'+list[i])); } cb(); }); } return Plugin; }