diff --git a/lib/resources/dashboard.js b/lib/resources/dashboard.js index 14ce51e..2372430 100644 --- a/lib/resources/dashboard.js +++ b/lib/resources/dashboard.js @@ -7,251 +7,243 @@ var util = require('util') , fs = require('fs') , ejs = require('ejs') , keys = require('../keys') - , loadTypes = require('../type-loader'); + , loadTypes = require('../type-loader') + , async = require('async'); function Dashboard() { // internal resource this.internal = true; + + this.loadTypes = async.memoize(this.loadTypes); + this.loadLayout = async.memoize(this.loadLayout); - Resource.apply(this, arguments); + Resource.apply(this, arguments); } util.inherits(Dashboard, Resource); module.exports = Dashboard; -Dashboard.prototype.render = function(ctx, options) { - var self = this - , rendered - , resourceTypes - , layout = this.layout - , appName = path.basename(path.resolve('./')) - , env = ctx.server && ctx.server.options.env; - options = options || {}; - var context = { - resourceId: options.resourceId - , resourceType: options.resourceType - , page: options.page - , basicDashboard: options.basicDashboard - , events: options.events - , appName: appName - , env: env - }; +Dashboard.prototype.handle = function(ctx, next) { + var query = ctx.req.query; - if (layout) { - var finish = function(context, render) { - try { - rendered = layout({context: context, render: render, scripts: options.scripts || [], css: options.css || null}); - ctx.res.setHeader('Content-Type', 'text/html'); - ctx.res.end(rendered); - } catch (ex) { - ctx.res.end(ex.message); - } - }; - - if (options.pagePath) { - fs.readFile(options.pagePath, 'utf-8', function(err, file) { - if (err) return ctx.done(err); - finish(context, {bodyHtml: file}); - }); - } else { - finish(context, {}); - } - + if (ctx.req.url === this.path) { + return httpUtil.redirect(ctx.res, ctx.req.url + '/'); + } else if (ctx.url === '/__is-root') { + ctx.done(null, {isRoot: ctx.req.isRoot}); + } else if (ctx.url.indexOf('/__custom') === 0) { + this.serveCustomAsset(ctx, next); + } else if (ctx.url.indexOf('.') !== -1) { + filed(path.join(__dirname, 'dashboard', ctx.url)).pipe(ctx.res); + } else if (!ctx.req.isRoot && ctx.server.options.env !== 'development') { + filed(path.join(__dirname, 'dashboard', 'auth.html')).pipe(ctx.res); } else { - fs.readFile(path.join(__dirname, 'dashboard', 'index.ejs'), 'utf-8', function(err, layout) { - if (err) return ctx.done(err); - self.layout = ejs.compile(layout, {open: '<{', close: '}>'}); //Avoid conlicts by using non-standard tags - Dashboard.prototype.render.call(self, ctx, options); - - }); + this.render(ctx); } + }; -Dashboard.prototype.route = function(ctx) { + +Dashboard.prototype.serveCustomAsset = function(ctx, next) { var parts = ctx.url.split('/').filter(function(p) { return p; }) - , resourceId - , resource - , resourceType - , page - , pagePath - , scripts = [] - , render = this.render; + , resourceTypePath = parts[1] + , resource = this; - if (parts.length) { - resourceId = parts[0]; - resource = ctx.server.resources.filter(function(r) { return r.name === resourceId.toLowerCase() })[0]; - - if (resource) { - - var renderResource = function(extras) { - var options = { - resourceId: resourceId - , resourceType: resourceType.name - , events: resourceType.events - , page: page - , pagePath: pagePath - , scripts: scripts - }; - - if (extras) { - Object.keys(extras).forEach(function(k) { - options[k] = extras[k]; - }); - } - - render(ctx, options); - }; - - resourceType = resource.constructor; - - debug("Editing resource %s of type %s", resourceId, resourceType.name); - - if (resourceType.dashboard) { - - if (resourceType.dashboard.pages) { - page = parts[1] || resourceType.dashboard.pages[0].toLowerCase(); - } else if (parts[1] === 'events' && resourceType.events) { - pagePath = path.join(__dirname, 'dashboard', 'events.html'); - page = 'events'; - return renderResource(); - } else { - page = 'index'; - } - - if (page === 'config') page = 'index'; - - if (resourceType.dashboard.scripts) { - resourceType.dashboard.scripts.forEach(function(s) { - scripts.push('/__custom/' + resourceType.name.toLowerCase() + s); - }); - } - - pagePath = path.join(resourceType.dashboard.path, page + '.html'); - - var checkFilesAndRender = function() { - fs.stat(path.join(resourceType.dashboard.path, 'js', page + '.js'), function(err, stat) { - if (stat) { - scripts.push('/__custom/' + resourceType.name.toLowerCase() + '/js/' + page + '.js'); - } - - fs.stat(path.join(resourceType.dashboard.path, 'style.css'), function(errCss, statCss) { - if (page === 'index') page = 'config'; - renderResource({ - css: statCss && '/__custom/' + resourceType.name.toLowerCase() + '/style.css' - }); - }); - - }); - }; - - if (page === 'events') { - return fs.stat(pagePath, function(err, stat) { - if (stat) { - checkFilesAndRender(); - } else { - pagePath = path.join(__dirname, 'dashboard', 'events.html'); - renderResource(); - } - }); - } else { - checkFilesAndRender(); - } - - } else if (resourceType.basicDashboard) { - page = parts[1] || 'config'; - if (page === 'events' && resourceType.events) { - pagePath = path.join(__dirname, 'dashboard', 'events.html'); - } else { - pagePath = path.join(__dirname, 'dashboard', 'basic.html'); - scripts.push('/js/basic.js'); - } - - renderResource({ - basicDashboard: resourceType.basicDashboard - }); - } else { - page = parts[1] || 'config'; - if (page === 'events' && resourceType.events) { - pagePath = path.join(__dirname, 'dashboard', 'events.html'); - } else { - pagePath = path.join(__dirname, 'dashboard', 'default.html'); - scripts.push('/js/default.js'); - } - - renderResource(); - } - - } else { - this.render(ctx); - } - - } else { - this.render(ctx); - } -}; - -Dashboard.prototype.serve = function(ctx, next) { - var parts = ctx.url.split('/').filter(function(p) { return p; }) - , resourceTypePath = parts[1]; - - loadTypes(function(defaults, types) { + resource.loadTypes(function(err, types) { var resourceTypeId , resourceType , dashboardPath , reqUrl = parts.slice(2).join('/'); - Object.keys(defaults).forEach(function(key) { - types[key] = defaults[key]; - }); - resourceTypeId = Object.keys(types).filter(function(t) { return t.toLowerCase() === resourceTypePath; })[0]; if (resourceTypeId) { resourceType = types[resourceTypeId]; dashboardPath = resourceType && resourceType.dashboard && resourceType.dashboard.path; if (dashboardPath) { - filed(path.join(dashboardPath, reqUrl)).pipe(ctx.res); - } else { - next(); + return filed(path.join(dashboardPath, reqUrl)).pipe(ctx.res); } - } else { - next(); } + + next(); }); - - // , resourceType = ctx.server.resources.filter(function(r) { return r.name === resourceId.toLowerCase() })[0]; - // , dashboardPath = resourceType && resourceType.dashboard && resourceType.dashboard.path - // , reqUrl = parts.slice(2).join('/'); - - // filed(path.join(dashboardPath, reqUrl)).pipe(ctx.res); }; -Dashboard.prototype.auth = function(ctx) { - filed(path.join(__dirname, 'dashboard', 'auth.html')).pipe(ctx.res); +Dashboard.prototype.loadTypes = function(fn) { + loadTypes(function(defaults, types) { + Object.keys(defaults).forEach(function(key) { + types[key] = defaults[key]; + }); + fn(null, types); + }); }; -Dashboard.prototype.handle = function(ctx, next) { - var query = ctx.req.query - , parts; +Dashboard.prototype.render = function(ctx) { + var self = this + , appName = path.basename(path.resolve('./')) + , env = ctx.server && ctx.server.options.env; - if (ctx.req.url === this.path) { - return httpUtil.redirect(ctx.res, ctx.req.url + '/'); - } + async.parallel({ + layout: self.loadLayout + , options: async.apply(self.loadPage.bind(self), ctx) + }, function(err, results) { + if (err) return ctx.done(err); - if (ctx.url === '/__is-root') { - ctx.done(null, {isRoot: ctx.req.isRoot}); - } else if (ctx.url.indexOf('/__custom') === 0) { - this.serve(ctx, next); - } else if (ctx.url.indexOf('.') !== -1) { - filed(path.join(__dirname, 'dashboard', ctx.url)).pipe(ctx.res); - } else { + var options = results.options || {} + , layout = results.layout + , render = {}; - if (ctx.req.isRoot || ctx.server.options.env === 'development') { - this.route(ctx); - } else { - this.auth(ctx); + var context = { + resourceId: options.resourceId + , resourceType: options.resourceType + , page: options.page + , basicDashboard: options.basicDashboard + , events: options.events + , appName: appName + , env: env + }; + + render.bodyHtml = options.bodyHtml; + + try { + var rendered = results.layout({context: context, render: render, scripts: options.scripts || [], css: options.css || null}); + ctx.res.setHeader('Content-Type', 'text/html'); + ctx.res.end(rendered); + } catch (ex) { + console.log("PROBLEM", ex); + ctx.done(ex.message); + } + }); +}; + +Dashboard.prototype.loadLayout = function(fn) { + var self = this; + + fs.readFile(path.join(__dirname, 'dashboard', 'index.ejs'), 'utf-8', function(err, layout) { + if (err) return fn(err); + var layoutTemplate = ejs.compile(layout, {open: '<{', close: '}>'}); //Avoid conlicts by using non-standard tags + fn(null, layoutTemplate); + }); +}; + +Dashboard.prototype.loadPage = function(ctx, fn) { + var parts = ctx.url.split('/').filter(function(p) { return p; }) + , resourceId + , resource + , resourceType + , options = {} + , self = this + , dashboardPath + , pagePath; + + if (parts.length) { + resourceId = parts[0]; + resource = ctx.server.resources.filter(function(r) { return r.name === resourceId.toLowerCase() })[0]; + + if (resource) { + options.resourceId = resourceId; + resourceType = resource.constructor; + options.resourceType = resourceType.name; + options.events = resourceType.events; + options.scripts = []; + + var page = parts[1]; + if (page === 'config') page = 'index'; + + if (resourceType.dashboard || resourceType.basicDashboard) { + dashboardPath = resourceType.dashboard && resourceType.dashboard.path; + + async.waterfall([ + function(fn) { + if (dashboardPath) { + pagePath = path.join(dashboardPath, page + '.html'); + fs.exists(pagePath, function(exists) { + fn(null, exists); + }); + } else { + fn(null, false); + } + }, + + function(exists, fn) { + if (exists) { + self.loadAdvancedDashboard({ + pagePath: pagePath + , dashboardPath: dashboardPath + , page: page + , resourceType: resourceType + , options: options + }, fn); + } else { + self.loadBasicDashboard(resourceType, options, fn); + } + } + ], function(err) { + fn(err, options); + }); + } else { + + } + + debug("Editing resource %s of type %s", resourceId, resourceType.name); + + return; } } - + + fn(); //blank page +}; + +Dashboard.prototype.loadAdvancedDashboard = function(data, fn) { + var pagePath = data.pagePath + , dashboardPath = data.dashboardPath + , page = data.page + , resourceType = data.resourceType + , options = data.options; + + + async.parallel({ + bodyHtml: function(fn) { + fs.readFile(pagePath, 'utf-8', fn); + }, + + scripts: function(fn) { + if (resourceType.dashboard.scripts) { + resourceType.dashboard.scripts.forEach(function(s) { + options.scripts.push('/__custom/' + resourceType.name.toLowerCase() + s); + }); + } + + fs.exists(path.join(dashboardPath, 'js', page + '.js'), function(exists) { + if (exists) { + options.scripts.push('/__custom/' + resourceType.name.toLowerCase() + '/js/' + page + '.js'); + } + + fn(); + }); + }, + + stylesheet: function(fn) { + fs.exists(path.join(resourceType.dashboard.path, 'style.css'), function(exists) { + if (exists) { + options.css = '/__custom/' + resourceType.name.toLowerCase() + '/style.css'; + } + + fn(); + }); + } + }, function(err, results) { + if (err) return fn(err); + + options.bodyHtml = results.bodyHtml; + + if (page === 'index') page = 'config'; + options.page = page; + + fn(null, options); + }); +}; + +Dashboard.prototype.loadBasicDashboard = function(resourceType, options, fn) { + }; \ No newline at end of file diff --git a/lib/resources/dashboard.old.js b/lib/resources/dashboard.old.js new file mode 100644 index 0000000..14ce51e --- /dev/null +++ b/lib/resources/dashboard.old.js @@ -0,0 +1,257 @@ +var util = require('util') + , httpUtil = require('../util/http') + , filed = require('filed') + , Resource = require('../resource') + , path = require('path') + , debug = require('debug')('dashboard') + , fs = require('fs') + , ejs = require('ejs') + , keys = require('../keys') + , loadTypes = require('../type-loader'); + +function Dashboard() { + // internal resource + this.internal = true; + + Resource.apply(this, arguments); +} +util.inherits(Dashboard, Resource); +module.exports = Dashboard; + +Dashboard.prototype.render = function(ctx, options) { + var self = this + , rendered + , resourceTypes + , layout = this.layout + , appName = path.basename(path.resolve('./')) + , env = ctx.server && ctx.server.options.env; + + options = options || {}; + + var context = { + resourceId: options.resourceId + , resourceType: options.resourceType + , page: options.page + , basicDashboard: options.basicDashboard + , events: options.events + , appName: appName + , env: env + }; + + if (layout) { + var finish = function(context, render) { + try { + rendered = layout({context: context, render: render, scripts: options.scripts || [], css: options.css || null}); + ctx.res.setHeader('Content-Type', 'text/html'); + ctx.res.end(rendered); + } catch (ex) { + ctx.res.end(ex.message); + } + }; + + if (options.pagePath) { + fs.readFile(options.pagePath, 'utf-8', function(err, file) { + if (err) return ctx.done(err); + finish(context, {bodyHtml: file}); + }); + } else { + finish(context, {}); + } + + } else { + fs.readFile(path.join(__dirname, 'dashboard', 'index.ejs'), 'utf-8', function(err, layout) { + if (err) return ctx.done(err); + self.layout = ejs.compile(layout, {open: '<{', close: '}>'}); //Avoid conlicts by using non-standard tags + Dashboard.prototype.render.call(self, ctx, options); + + }); + } +}; + +Dashboard.prototype.route = function(ctx) { + var parts = ctx.url.split('/').filter(function(p) { return p; }) + , resourceId + , resource + , resourceType + , page + , pagePath + , scripts = [] + , render = this.render; + + if (parts.length) { + resourceId = parts[0]; + resource = ctx.server.resources.filter(function(r) { return r.name === resourceId.toLowerCase() })[0]; + + if (resource) { + + var renderResource = function(extras) { + var options = { + resourceId: resourceId + , resourceType: resourceType.name + , events: resourceType.events + , page: page + , pagePath: pagePath + , scripts: scripts + }; + + if (extras) { + Object.keys(extras).forEach(function(k) { + options[k] = extras[k]; + }); + } + + render(ctx, options); + }; + + resourceType = resource.constructor; + + debug("Editing resource %s of type %s", resourceId, resourceType.name); + + if (resourceType.dashboard) { + + if (resourceType.dashboard.pages) { + page = parts[1] || resourceType.dashboard.pages[0].toLowerCase(); + } else if (parts[1] === 'events' && resourceType.events) { + pagePath = path.join(__dirname, 'dashboard', 'events.html'); + page = 'events'; + return renderResource(); + } else { + page = 'index'; + } + + if (page === 'config') page = 'index'; + + if (resourceType.dashboard.scripts) { + resourceType.dashboard.scripts.forEach(function(s) { + scripts.push('/__custom/' + resourceType.name.toLowerCase() + s); + }); + } + + pagePath = path.join(resourceType.dashboard.path, page + '.html'); + + var checkFilesAndRender = function() { + fs.stat(path.join(resourceType.dashboard.path, 'js', page + '.js'), function(err, stat) { + if (stat) { + scripts.push('/__custom/' + resourceType.name.toLowerCase() + '/js/' + page + '.js'); + } + + fs.stat(path.join(resourceType.dashboard.path, 'style.css'), function(errCss, statCss) { + if (page === 'index') page = 'config'; + renderResource({ + css: statCss && '/__custom/' + resourceType.name.toLowerCase() + '/style.css' + }); + }); + + }); + }; + + if (page === 'events') { + return fs.stat(pagePath, function(err, stat) { + if (stat) { + checkFilesAndRender(); + } else { + pagePath = path.join(__dirname, 'dashboard', 'events.html'); + renderResource(); + } + }); + } else { + checkFilesAndRender(); + } + + } else if (resourceType.basicDashboard) { + page = parts[1] || 'config'; + if (page === 'events' && resourceType.events) { + pagePath = path.join(__dirname, 'dashboard', 'events.html'); + } else { + pagePath = path.join(__dirname, 'dashboard', 'basic.html'); + scripts.push('/js/basic.js'); + } + + renderResource({ + basicDashboard: resourceType.basicDashboard + }); + } else { + page = parts[1] || 'config'; + if (page === 'events' && resourceType.events) { + pagePath = path.join(__dirname, 'dashboard', 'events.html'); + } else { + pagePath = path.join(__dirname, 'dashboard', 'default.html'); + scripts.push('/js/default.js'); + } + + renderResource(); + } + + } else { + this.render(ctx); + } + + } else { + this.render(ctx); + } +}; + +Dashboard.prototype.serve = function(ctx, next) { + var parts = ctx.url.split('/').filter(function(p) { return p; }) + , resourceTypePath = parts[1]; + + loadTypes(function(defaults, types) { + var resourceTypeId + , resourceType + , dashboardPath + , reqUrl = parts.slice(2).join('/'); + + Object.keys(defaults).forEach(function(key) { + types[key] = defaults[key]; + }); + + resourceTypeId = Object.keys(types).filter(function(t) { return t.toLowerCase() === resourceTypePath; })[0]; + + if (resourceTypeId) { + resourceType = types[resourceTypeId]; + dashboardPath = resourceType && resourceType.dashboard && resourceType.dashboard.path; + if (dashboardPath) { + filed(path.join(dashboardPath, reqUrl)).pipe(ctx.res); + } else { + next(); + } + } else { + next(); + } + }); + + // , resourceType = ctx.server.resources.filter(function(r) { return r.name === resourceId.toLowerCase() })[0]; + // , dashboardPath = resourceType && resourceType.dashboard && resourceType.dashboard.path + // , reqUrl = parts.slice(2).join('/'); + + // filed(path.join(dashboardPath, reqUrl)).pipe(ctx.res); +}; + +Dashboard.prototype.auth = function(ctx) { + filed(path.join(__dirname, 'dashboard', 'auth.html')).pipe(ctx.res); +}; + +Dashboard.prototype.handle = function(ctx, next) { + var query = ctx.req.query + , parts; + + if (ctx.req.url === this.path) { + return httpUtil.redirect(ctx.res, ctx.req.url + '/'); + } + + if (ctx.url === '/__is-root') { + ctx.done(null, {isRoot: ctx.req.isRoot}); + } else if (ctx.url.indexOf('/__custom') === 0) { + this.serve(ctx, next); + } else if (ctx.url.indexOf('.') !== -1) { + filed(path.join(__dirname, 'dashboard', ctx.url)).pipe(ctx.res); + } else { + + if (ctx.req.isRoot || ctx.server.options.env === 'development') { + this.route(ctx); + } else { + this.auth(ctx); + } + } + +}; \ No newline at end of file