Express 4 Support
New naming convention
Glob patterns
CSS Linting
Uglify
CSS Min
Environmental Asset Management
DI Menu System
This commit is contained in:
Amos Haviv
2014-04-21 00:01:01 +03:00
parent 09f1eab636
commit 44bf81a494
60 changed files with 425 additions and 231 deletions

15
.csslintrc Normal file
View File

@@ -0,0 +1,15 @@
{
"adjoining-classes": false,
"box-model": false,
"box-sizing": false,
"floats": false,
"font-sizes": false,
"important": false,
"known-properties": false,
"overqualified-elements": false,
"qualified-headings": false,
"regex-selectors": false,
"unique-headings": false,
"universal-selector": false,
"unqualified-attributes": false
}

View File

@@ -68,6 +68,13 @@ var UserSchema = new Schema({
},
providerData: {},
additionalProvidersData: {},
roles: {
type: [{
type: String,
enum: ['user', 'admin']
}],
default: ['user']
},
updated: {
type: Date
},
@@ -114,8 +121,10 @@ UserSchema.statics.findUniqueUsername = function(username, suffix, callback) {
var _this = this;
var possibleUsername = username + (suffix || '');
_this.findOne({username: possibleUsername}, function(err, user) {
if(!err) {
_this.findOne({
username: possibleUsername
}, function(err, user) {
if (!err) {
if (!user) {
callback(possibleUsername);
} else {

View File

@@ -3,8 +3,8 @@
/**
* Module dependencies.
*/
var users = require('../../app/controllers/users'),
articles = require('../../app/controllers/articles');
var users = require('../../app/controllers/users.server.controller'),
articles = require('../../app/controllers/articles.server.controller');
module.exports = function(app) {
// Article Routes

View File

@@ -2,6 +2,6 @@
module.exports = function(app) {
// Root routing
var core = require('../../app/controllers/core');
var core = require('../../app/controllers/core.server.controller');
app.get('/', core.index);
};

View File

@@ -7,7 +7,7 @@ var passport = require('passport');
module.exports = function(app) {
// User Routes
var users = require('../../app/controllers/users');
var users = require('../../app/controllers/users.server.controller');
app.get('/users/me', users.me);
app.put('/users', users.update);
app.post('/users/password', users.changePassword);

View File

@@ -30,18 +30,11 @@
<meta name="twitter:image" content="/img/brand/logo.png">
<!-- Fav Icon -->
<link href="/img/brand/favicon.ico" rel="shortcut icon" type="image/x-icon">
<link href="/modules/core/img/brand/favicon.ico" rel="shortcut icon" type="image/x-icon">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap-theme.css">
<!-- Application CSS -->
<link rel="stylesheet" href="/css/common.css">
<!--Application Modules CSS-->
{% for modulesCSSFile in modulesCSSFiles %}
<link rel="stylesheet" href="{{modulesCSSFile}}">{% endfor %}
<!--Application CSS Files-->
{% for cssFile in cssFiles %}<link rel="stylesheet" href="{{cssFile}}">
{% endfor %}
<!-- HTML5 Shim -->
<!--[if lt IE 9]>
@@ -62,29 +55,13 @@
var user = {{ user | json | safe }};
</script>
<!--AngularJS-->
<script type="text/javascript" src="/lib/angular/angular.js"></script>
<script type="text/javascript" src="/lib/angular-resource/angular-resource.js"></script>
<script type="text/javascript" src="/lib/angular-cookies/angular-cookies.js"></script>
<script type="text/javascript" src="/lib/angular-animate/angular-animate.js"></script>
<!--Angular UI-->
<script type="text/javascript" src="/lib/angular-bootstrap/ui-bootstrap.js"></script>
<script type="text/javascript" src="/lib/angular-ui-utils/ui-utils.js"></script>
<script type="text/javascript" src="/lib/angular-ui-router/release/angular-ui-router.js"></script>
<!--AngularJS Application Init-->
<script type="text/javascript" src="/js/config.js"></script>
<script type="text/javascript" src="/js/application.js"></script>
<!--Application Modules-->
{% for modulesJSFile in modulesJSFiles %}
<script type="text/javascript" src="{{modulesJSFile}}"></script>
<!--Application JavaScript Files-->
{% for jsFile in jsFiles %}<script type="text/javascript" src="{{jsFile}}"></script>
{% endfor %}
{% if process.env.NODE_ENV === 'development' %}
<!--Livereload script rendered -->
<script type="text/javascript" src="http://localhost:35729/livereload.js"></script>
<!--Livereload script rendered -->
<script type="text/javascript" src="http://localhost:35729/livereload.js"></script>
{% endif %}
</body>

View File

@@ -5,7 +5,6 @@
"dependencies": {
"bootstrap": "~3",
"angular": "~1.2",
"angular-cookies": "~1.2",
"angular-resource": "~1.2",
"angular-animate": "~1.2",
"angular-mocks": "~1.2",

View File

@@ -1,15 +1,74 @@
'use strict';
var _ = require('lodash'),
utilities = require('./utilities');
glob = require('glob');
// Look for a valid NODE_ENV variable and if one cannot be found load the development NODE_ENV
process.env.NODE_ENV = ~utilities.walk('./config/env', /(.*)\.js$/).map(function(file) {
return file.split('/').pop().slice(0, -3);
}).indexOf(process.env.NODE_ENV) ? process.env.NODE_ENV : 'development';
/**
* Before we begin, lets set the envrionment variable
* We'll Look for a valid NODE_ENV variable and if one cannot be found load the development NODE_ENV
*/
glob('./config/env/' + process.env.NODE_ENV + '.js', {
sync: true
}, function(err, environmentFiles) {
process.env.NODE_ENV = environmentFiles.length ? process.env.NODE_ENV : 'development';
});
// Load app configurations
module.exports = _.extend(
require('./env/all'),
require('./env/' + process.env.NODE_ENV) || {}
);
);
/**
* Get the modules JavaScript files
*/
module.exports.getGlobbedFiles = function(globPatterns, removeRoot) {
// For context switching
var _this = this;
// The output array
var output = [];
// If glob pattern is array so we use each pattern in a recursive way, otherwise we use glob
if (_.isArray(globPatterns)) {
globPatterns.forEach(function(globPattern) {
output = _.union(output, _this.getGlobbedFiles(globPattern, removeRoot));
});
} else if (_.isString(globPatterns)) {
glob(globPatterns, {
sync: true
}, function(err, files) {
if (removeRoot) {
files = files.map(function(file) {
return file.replace(removeRoot, '');
});
}
output = _.union(output, files);
});
}
return output;
};
/**
* Get the modules JavaScript files
*/
module.exports.getJavaScriptAssets = function(includeTests) {
var output = this.getGlobbedFiles(this.assets.js, 'public/');
// To include tests
if (includeTests) {
output = _.union(output, this.getGlobbedFiles(this.assets.tests));
}
return output;
};
/**
* Get the modules CSS files
*/
module.exports.getCSSAssets = function() {
var output = this.getGlobbedFiles(this.assets.css, 'public/');
return output;
};

25
config/env/all.js vendored
View File

@@ -13,5 +13,28 @@ module.exports = {
port: process.env.PORT || 3000,
templateEngine: 'swig',
sessionSecret: 'MEAN',
sessionCollection: 'sessions'
sessionCollection: 'sessions',
assets: {
css: [
'public/lib/bootstrap/dist/css/bootstrap.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.css',
'public/modules/**/css/*.css'
],
js: [
'public/lib/angular/angular.js',
'public/lib/angular-resource/angular-resource.js',
'public/lib/angular-animate/angular-animate.js',
'public/lib/angular-ui-router/release/angular-ui-router.js',
'public/lib/angular-ui-utils/ui-utils.js',
'public/lib/angular-bootstrap/ui-bootstrap-tpls.js',
'public/config.js',
'public/application.js',
'public/modules/*/*.js',
'public/modules/*/*[!tests]*/*.js'
],
tests: [
'public/lib/angular-mocks/angular-mocks.js',
'public/modules/*/tests/*.js'
]
}
};

View File

@@ -1,7 +1,11 @@
'use strict';
module.exports = {
db: process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://localhost/mean',
db: process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://localhost/mean',
assets: {
css: 'public/dist/application.min.css',
js: 'public/dist/application.min.js'
},
facebook: {
clientID: 'APP_ID',
clientSecret: 'APP_SECRET',

View File

@@ -9,15 +9,14 @@ var express = require('express'),
flash = require('connect-flash'),
config = require('./config'),
consolidate = require('consolidate'),
path = require('path'),
utilities = require('./utilities');
path = require('path');
module.exports = function(db) {
// Initialize express app
var app = express();
// Initialize models
utilities.walk('./app/models').forEach(function(modelPath) {
// Globbing model files
config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
require(path.resolve(modelPath));
});
@@ -27,8 +26,8 @@ module.exports = function(db) {
description: config.app.description,
keywords: config.app.keywords,
facebookAppId: config.facebook.clientID,
modulesJSFiles: utilities.walk('./public/modules', /(.*)\.(js)/, /(.*)\.(spec.js)/, './public'),
modulesCSSFiles: utilities.walk('./public/modules', /(.*)\.(css)/, null, './public')
jsFiles: config.getJavaScriptAssets(),
cssFiles: config.getCSSAssets()
});
// Passing the request url to environment locals
@@ -104,8 +103,8 @@ module.exports = function(db) {
// Setting the app router and static folder
app.use(express.static(config.root + '/public'));
// Load Routes
utilities.walk('./app/routes').forEach(function(routePath) {
// Globbing routing files
config.getGlobbedFiles('./app/routes/**/*.js').forEach(function(routePath) {
require(path.resolve(routePath))(app);
});
@@ -132,4 +131,4 @@ module.exports = function(db) {
});
return app;
};
};

View File

@@ -3,7 +3,7 @@
var passport = require('passport'),
User = require('mongoose').model('User'),
path = require('path'),
utilities = require('./utilities');
config = require('./config');
module.exports = function() {
// Serialize sessions
@@ -21,7 +21,7 @@ module.exports = function() {
});
// Initialize strategies
utilities.walk('./config/strategies').forEach(function(strategyPath) {
require(path.resolve(strategyPath))();
config.getGlobbedFiles('./config/strategies/**/*.js').forEach(function(strategy) {
require(path.resolve(strategy))();
});
};
};

View File

@@ -3,7 +3,7 @@
var passport = require('passport'),
FacebookStrategy = require('passport-facebook').Strategy,
config = require('../config'),
users = require('../../app/controllers/users');
users = require('../../app/controllers/users.server.controller');
module.exports = function() {
// Use facebook strategy

View File

@@ -3,7 +3,7 @@
var passport = require('passport'),
GoogleStrategy = require('passport-google-oauth').OAuth2Strategy,
config = require('../config'),
users = require('../../app/controllers/users');
users = require('../../app/controllers/users.server.controller');
module.exports = function() {
// Use google strategy

View File

@@ -3,7 +3,7 @@
var passport = require('passport'),
LinkedInStrategy = require('passport-linkedin').Strategy,
config = require('../config'),
users = require('../../app/controllers/users');
users = require('../../app/controllers/users.server.controller');
module.exports = function() {
// Use linkedin strategy

View File

@@ -4,7 +4,6 @@ var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
User = require('mongoose').model('User');
module.exports = function() {
// Use local strategy
passport.use(new LocalStrategy({

View File

@@ -3,7 +3,7 @@
var passport = require('passport'),
TwitterStrategy = require('passport-twitter').Strategy,
config = require('../config'),
users = require('../../app/controllers/users');
users = require('../../app/controllers/users.server.controller');
module.exports = function() {
// Use twitter strategy

View File

@@ -1,39 +0,0 @@
'use strict';
/**
* Module dependencies.
*/
var fs = require('fs');
// Walk function to recursively get files
var _walk = function(root, includeRegex, excludeRegex, removePath) {
var output = [];
var directories = [];
includeRegex = includeRegex || /(.*)\.(js|coffee)$/;
// First read through files
fs.readdirSync(root).forEach(function(file) {
var newPath = root + '/' + file;
var stat = fs.statSync(newPath);
if (stat.isFile()) {
if (includeRegex.test(file) && (!excludeRegex || !excludeRegex.test(file))) {
output.push(newPath.replace(removePath, ''));
}
} else if (stat.isDirectory()) {
directories.push(newPath);
}
});
// Then recursively add directories
directories.forEach(function(directory) {
output = output.concat(_walk(directory, includeRegex, excludeRegex, removePath));
});
return output;
};
/**
* Exposing the walk function
*/
exports.walk = _walk;

View File

@@ -1,5 +1,7 @@
'use strict';
var config = require('./config/config');
module.exports = function(grunt) {
// Project Configuration
grunt.initConfig({
@@ -33,6 +35,7 @@ module.exports = function(grunt) {
},
clientCSS: {
files: ['public/**/css/*.css'],
tasks: ['csslint'],
options: {
livereload: true,
}
@@ -46,6 +49,31 @@ module.exports = function(grunt) {
}
}
},
csslint: {
options: {
csslintrc: '.csslintrc',
},
all: {
src: ['public/modules/**/css/*.css']
}
},
uglify: {
production: {
options: {
mangle: false
},
files: {
'public/dist/application.min.js': config.assets.js
}
}
},
cssmin: {
combine: {
files: {
'public/dist/application.min.css': config.assets.css
}
}
},
nodemon: {
dev: {
script: 'server.js',
@@ -80,19 +108,19 @@ module.exports = function(grunt) {
});
//Load NPM tasks
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-nodemon');
grunt.loadNpmTasks('grunt-concurrent');
grunt.loadNpmTasks('grunt-env');
require('load-grunt-tasks')(grunt);
//Making grunt default to force in order not to break the project.
grunt.option('force', true);
//Default task(s).
grunt.registerTask('default', ['jshint', 'concurrent']);
grunt.registerTask('default', ['jshint', 'csslint', 'concurrent']);
//Lint task(s).
grunt.registerTask('lint', ['jshint', 'csslint']);
//Build task(s).
grunt.registerTask('build', ['jshint', 'csslint', 'uglify', 'cssmin']);
//Test task.
grunt.registerTask('test', ['env:test', 'mochaTest', 'karma:unit']);

View File

@@ -3,10 +3,7 @@
/**
* Module dependencies.
*/
var utilities = require('./config/utilities');
// Grabbing module files using the walk function
var modulesJSFiles = utilities.walk('./public/modules', /(.*)\.js$/);
var applicationConfiguration = require('./config/config');
// Karma configuration
module.exports = function(config) {
@@ -15,18 +12,7 @@ module.exports = function(config) {
frameworks: ['jasmine'],
// List of files / patterns to load in the browser
files: [
'public/lib/angular/angular.js',
'public/lib/angular-animate/angular-animate.js',
'public/lib/angular-mocks/angular-mocks.js',
'public/lib/angular-cookies/angular-cookies.js',
'public/lib/angular-resource/angular-resource.js',
'public/lib/angular-bootstrap/ui-bootstrap.js',
'public/lib/angular-ui-utils/ui-utils.js',
'public/lib/angular-ui-router/release/angular-ui-router.js',
'public/js/config.js',
'public/js/application.js',
].concat(modulesJSFiles),
files: applicationConfiguration.assets.js.concat(applicationConfiguration.assets.tests),
// Test results reporter to use
// Possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'

View File

@@ -1,7 +1,7 @@
{
"name": "meanjs",
"description": "Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js.",
"version": "0.2.3",
"version": "0.3.0",
"private": false,
"author": "https://github.com/meanjs/mean/graphs/contributors",
"repository": {
@@ -33,7 +33,8 @@
"lodash": "~2.4.1",
"forever": "~0.11.00",
"bower": "~1.3.1",
"grunt-cli": "~0.1.13"
"grunt-cli": "~0.1.13",
"glob": "~3.2.9"
},
"devDependencies": {
"supertest": "~0.10.0",
@@ -42,10 +43,14 @@
"grunt-node-inspector": "~0.1.3",
"grunt-contrib-watch": "~0.6.1",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-csslint": "^0.2.0",
"grunt-contrib-uglify": "~0.4.0",
"grunt-contrib-cssmin": "~0.9.0",
"grunt-nodemon": "~0.2.0",
"grunt-concurrent": "~0.5.0",
"grunt-mocha-test": "~0.10.0",
"grunt-karma": "~0.8.2",
"load-grunt-tasks": "~0.4.0",
"karma": "~0.12.0",
"karma-jasmine": "~0.2.1",
"karma-coverage": "~0.2.0",

16
public/config.js Normal file
View File

@@ -0,0 +1,16 @@
'use strict';
// Init the application configuration object for AngularJS application
var ApplicationConfiguration = (function() {
return {
applicationModuleName: 'mean',
applicationModuleVendorDependencies: ['ngResource', 'ngAnimate', 'ui.router', 'ui.bootstrap', 'ui.utils'],
registerModule: function(moduleName) {
// Create angular module
angular.module(moduleName, []);
// Add the module to the AngularJS configuration file
angular.module(this.applicationModuleName).requires.push(moduleName);
}
};
})();

9
public/dist/application.min.css vendored Normal file

File diff suppressed because one or more lines are too long

12
public/dist/application.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

View File

@@ -1,23 +0,0 @@
'use strict';
// Init the application configuration module for AngularJS application
var ApplicationConfiguration = (function() {
// Init module configuration options
var applicationModuleName = 'mean';
var applicationModuleVendorDependencies = ['ngResource', 'ngCookies', 'ngAnimate', 'ui.router', 'ui.bootstrap', 'ui.utils'];
// Add a new vertical module
var registerModule = function(moduleName) {
// Create angular module
angular.module(moduleName, []);
// Add the module to the AngularJS configuration file
angular.module(applicationModuleName).requires.push(moduleName);
};
return {
applicationModuleName: applicationModuleName,
applicationModuleVendorDependencies: applicationModuleVendorDependencies,
registerModule: registerModule
};
})();

View File

@@ -0,0 +1,10 @@
'use strict';
// Configuring the Articles module
angular.module('articles').run(['Menus',
function(Menus) {
// Set top bar menu items
Menus.addMenuItem('topbar', 'Articles', 'articles');
Menus.addMenuItem('topbar', 'New Article', 'articles/create');
}
]);

View File

@@ -0,0 +1,62 @@
'use strict';
angular.module('articles').controller('ArticlesController', ['$scope', '$stateParams', '$location', 'Authentication', 'Articles',
function($scope, $stateParams, $location, Authentication, Articles) {
$scope.authentication = Authentication;
$scope.create = function() {
var article = new Articles({
title: this.title,
content: this.content
});
article.$save(function(response) {
$location.path('articles/' + response._id);
});
this.title = '';
this.content = '';
};
$scope.remove = function(article) {
if (article) {
article.$remove();
for (var i in $scope.articles) {
if ($scope.articles[i] === article) {
$scope.articles.splice(i, 1);
}
}
} else {
$scope.article.$remove(function() {
$location.path('articles');
});
}
};
$scope.update = function() {
var article = $scope.article;
if (!article.updated) {
article.updated = [];
}
article.updated.push(new Date().getTime());
article.$update(function() {
$location.path('articles/' + article._id);
});
};
$scope.find = function() {
Articles.query(function(articles) {
$scope.articles = articles;
});
};
$scope.findOne = function() {
Articles.get({
articleId: $stateParams.articleId
}, function(article) {
$scope.article = article;
});
};
}
]);

View File

@@ -1,62 +0,0 @@
'use strict';
angular.module('articles').controller('ArticlesController', ['$scope', '$stateParams', '$location', 'Authentication', 'Articles',
function($scope, $stateParams, $location, Authentication, Articles) {
$scope.authentication = Authentication;
$scope.create = function() {
var article = new Articles({
title: this.title,
content: this.content
});
article.$save(function(response) {
$location.path('articles/' + response._id);
});
this.title = '';
this.content = '';
};
$scope.remove = function(article) {
if (article) {
article.$remove();
for (var i in $scope.articles) {
if ($scope.articles[i] === article) {
$scope.articles.splice(i, 1);
}
}
} else {
$scope.article.$remove(function() {
$location.path('articles');
});
}
};
$scope.update = function() {
var article = $scope.article;
if (!article.updated) {
article.updated = [];
}
article.updated.push(new Date().getTime());
article.$update(function() {
$location.path('articles/' + article._id);
});
};
$scope.find = function() {
Articles.query(function(articles) {
$scope.articles = articles;
});
};
$scope.findOne = function() {
Articles.get({
articleId: $stateParams.articleId
}, function(article) {
$scope.article = article;
});
};
}
]);

View File

@@ -1,19 +1,10 @@
'use strict';
angular.module('core').controller('HeaderController', ['$scope', 'Authentication',
function($scope, Authentication) {
angular.module('core').controller('HeaderController', ['$scope', 'Authentication', 'Menus',
function($scope, Authentication, Menus) {
$scope.authentication = Authentication;
$scope.isCollapsed = false;
$scope.menu = [{
title: 'Articles',
link: 'articles',
uiRoute: '/articles'
}, {
title: 'New Article',
link: 'articles/create',
uiRoute: '/articles/create'
}];
$scope.menu = Menus.getMenu('topbar');
$scope.toggleCollapsibleMenu = function() {
$scope.isCollapsed = !$scope.isCollapsed;

View File

@@ -1,7 +1,7 @@
.content {
margin-top: 50px;
}
a.undecorated-link:hover {
.undecorated-link:hover {
text-decoration: none;
}
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,114 @@
'use strict';
//Menu service used for managing menus
angular.module('core').service('Menus', [
function() {
// Define a set of default roles
this.defaultRoles = ['user'];
// Define the menus object
this.menus = {};
// A private function for rendering decision
var shouldRender = function(user) {
if(user) {
for (var userRoleIndex in user.roles) {
for (var roleIndex in this.roles) {
if(this.roles[roleIndex] === user.roles[userRoleIndex]) {
return true;
}
}
}
} else {
return !this.requiresAuthentication;
}
return false;
};
// Validate menu existance
this.validateMenuExistance = function(menuId) {
if (menuId && menuId.length) {
if (this.menus[menuId]) {
return true;
} else {
throw new Error('Menu does not exists');
}
} else {
throw new Error('MenuId was not provided');
}
return false;
};
// Get the menu object by menu id
this.getMenu = function(menuId) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
// Return the menu object
return this.menus[menuId];
};
// Add new menu object by menu id
this.addMenu = function(menuId, requiresAuthentication, roles) {
// Create the new menu
this.menus[menuId] = {
requiresAuthentication: requiresAuthentication || true,
roles: roles || this.defaultRoles,
items: [],
shouldRender: shouldRender
};
// Return the menu object
return this.menus[menuId];
};
// Remove existing menu object by menu id
this.removeMenu = function(menuId) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
// Return the menu object
delete this.menus[menuId];
};
// Add menu item object
this.addMenuItem = function(menuId, menuItemTitle, menuItemURL, menuItemUIRoute, requiresAuthentication, roles) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
// Push new menu item
this.menus[menuId].items.push({
title: menuItemTitle,
link: menuItemURL,
uiRoute: menuItemUIRoute || ('/' + menuItemURL),
requiresAuthentication: requiresAuthentication || false,
roles: roles || this.defaultRoles,
shouldRender: shouldRender
});
// Return the menu object
return this.menus[menuId];
};
// Remove existing menu object by menu id
this.removeMenuItem = function(menuId, menuItemURL) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
// Search for menu item to remove
for (var itemIndex in this.menus[menuId].items) {
if (this.menus[menuId].items[itemIndex].menuItemURL === menuItemURL) {
this.menus[menuId].items.splice(itemIndex, 1);
}
}
// Return the menu object
return this.menus[menuId];
};
//Adding the topbar menu
this.addMenu('topbar');
}
]);

View File

@@ -9,8 +9,8 @@
<a href="/#!/" class="navbar-brand">MEAN.JS</a>
</div>
<nav class="collapse navbar-collapse" collapse="!isCollapsed" role="navigation">
<ul class="nav navbar-nav" data-ng-show="authentication.user">
<li data-ng-repeat="item in menu" data-ng-show="authentication.user" ui-route="{{item.uiRoute}}" ng-class="{active: $uiRoute}">
<ul class="nav navbar-nav" data-ng-if="menu.shouldRender(authentication.user);">
<li data-ng-repeat="item in menu.items" data-ng-if="item.shouldRender(authentication.user);" ui-route="{{item.uiRoute}}" ng-class="{active: $uiRoute}">
<a href="/#!/{{item.link}}">{{item.title}}</a>
</li>
</ul>

View File

@@ -1,5 +1,4 @@
'use strict';
/**
* Module dependencies.
*/
@@ -10,6 +9,7 @@ var config = require('./config/config'),
* Main application entry file.
* Please note that the order of loading is important.
*/
// Bootstrap db connection
var db = mongoose.connect(config.db);
@@ -26,4 +26,5 @@ app.listen(config.port);
exports = module.exports = app;
// Logging initialization
console.log('Express app started on port ' + config.port);
console.log('Using the "' + process.env.NODE_ENV + '" envrionment file');
console.log('MEAN.JS application started on port ' + config.port);