├── .bowerrc
├── .browserstack.json
├── .editorconfig
├── .gitignore
├── .jshintrc
├── .travis.yml
├── CONTRIBUTING.md
├── Gruntfile.js
├── LICENSE
├── README.md
├── app
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ └── glyphicons-halflings-regular.woff
├── images
│ ├── brand.png
│ ├── cs-nav-logo.png
│ ├── fade-to-white.png
│ ├── hvd_fonts_-_plutosanslight-webfont.eot
│ ├── icon-close.png
│ ├── logo.png
│ ├── logobig.png
│ ├── modal-header-bg.png
│ ├── nav-app-bg.png
│ ├── nav-app-item-bg.png
│ └── nav-main-bg.png
├── index.html
├── modules
│ ├── app
│ │ ├── controllers
│ │ │ ├── ApplicationController.js
│ │ │ ├── HelpController.js
│ │ │ └── HomeController.js
│ │ ├── main.js
│ │ ├── module.js
│ │ ├── styles
│ │ │ └── help.less
│ │ ├── tests
│ │ │ ├── e2e
│ │ │ │ └── home.test.js
│ │ │ └── unit
│ │ │ │ └── controllers
│ │ │ │ ├── application_controller.js
│ │ │ │ └── home_controller.js
│ │ └── views
│ │ │ ├── help.html
│ │ │ └── home.html
│ ├── auth
│ │ ├── controllers
│ │ │ ├── PasswordResetRequestController.js
│ │ │ ├── PasswordResetSubmitController.js
│ │ │ ├── SignInController.js
│ │ │ ├── SignOutController.js
│ │ │ ├── SignUpConfirmController.js
│ │ │ ├── SignUpController.js
│ │ │ ├── UserEditController.js
│ │ │ └── UsersListController.js
│ │ ├── filters
│ │ │ └── LastLoginFilter.js
│ │ ├── main.js
│ │ ├── models
│ │ │ └── UserModel.js
│ │ ├── module.js
│ │ ├── providers
│ │ │ ├── AuthHelpersProvider.js
│ │ │ └── SessionProvider.js
│ │ ├── services
│ │ │ ├── SessionService.js
│ │ │ └── UserService.js
│ │ ├── tests
│ │ │ └── e2e
│ │ │ │ ├── passwordReset.test.js
│ │ │ │ ├── signIn.test.js
│ │ │ │ ├── signOut.test.js
│ │ │ │ ├── signUp.test.js
│ │ │ │ └── users.test.js
│ │ └── views
│ │ │ ├── partials
│ │ │ └── signOut.html
│ │ │ ├── requestPasswordReset.html
│ │ │ ├── resetPassword.html
│ │ │ ├── signIn.html
│ │ │ ├── signUp.html
│ │ │ └── users
│ │ │ ├── form.html
│ │ │ ├── list.html
│ │ │ ├── show.html
│ │ │ └── table_actions.html
│ ├── cs_accounts
│ │ ├── controllers
│ │ │ ├── AccountChooserController.js
│ │ │ └── AccountsListController.js
│ │ ├── directives
│ │ │ └── AccountChooserDirective.js
│ │ ├── main.js
│ │ ├── models
│ │ │ └── AccountModel.js
│ │ ├── module.js
│ │ ├── providers
│ │ │ └── AccountProvider.js
│ │ ├── services
│ │ │ └── AccountService.js
│ │ ├── tests
│ │ │ └── e2e
│ │ │ │ └── accounts.test.js
│ │ └── views
│ │ │ ├── confirm.html
│ │ │ ├── form.html
│ │ │ ├── list.html
│ │ │ └── partials
│ │ │ ├── chooser.html
│ │ │ └── tableActions.html
│ ├── cs_common
│ │ ├── controllers
│ │ │ └── NavbarController.js
│ │ ├── directives
│ │ │ ├── ColorPickerDirective.js
│ │ │ ├── FocusedOnDirective.js
│ │ │ ├── LoadingDirective.js
│ │ │ ├── MustBeEqualToDirective.js
│ │ │ ├── NavbarDirective.js
│ │ │ ├── NgBlurDirective.js
│ │ │ ├── NgFocusDirective.js
│ │ │ ├── NgLoadDirective.js
│ │ │ ├── StringToNumberDirective.js
│ │ │ └── WarnUnsavedChangesDirective.js
│ │ ├── filters
│ │ │ ├── CapitalizeFilter.js
│ │ │ ├── StartsWithFilter.js
│ │ │ └── TimeAgoFilter.js
│ │ ├── main.js
│ │ ├── module.js
│ │ ├── providers
│ │ │ ├── HelpersProvider.js
│ │ │ ├── HttpOptionsProvider.js
│ │ │ ├── NavbarProvider.js
│ │ │ ├── ResourceFactoryProvider.js
│ │ │ └── TemplateProvider.js
│ │ ├── styles
│ │ │ └── navbar.less
│ │ └── views
│ │ │ ├── error.html
│ │ │ ├── navbar.html
│ │ │ └── page_not_found.html
│ ├── cs_messenger
│ │ ├── bower.json
│ │ ├── main.js
│ │ ├── module.js
│ │ ├── readme.md
│ │ ├── scripts
│ │ │ ├── messenger_directive.js
│ │ │ └── messenger_provider.js
│ │ └── views
│ │ │ └── messenger.html
│ ├── cs_modal
│ │ ├── bower.json
│ │ ├── main.js
│ │ ├── module.js
│ │ ├── readme.md
│ │ ├── scripts
│ │ │ └── cs_modal_factory.js
│ │ ├── styles
│ │ │ └── modals.less
│ │ └── views
│ │ │ ├── confirmModal.html
│ │ │ ├── modalBackdrop.html
│ │ │ └── modalWindow.html
│ ├── cs_table
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── bower.json
│ │ ├── controllers
│ │ │ └── CleverTableController.js
│ │ ├── directives
│ │ │ └── CleverTableDirective.js
│ │ ├── main.js
│ │ ├── module.js
│ │ ├── styles
│ │ │ └── tables.less
│ │ └── views
│ │ │ ├── filter
│ │ │ ├── select2.html
│ │ │ └── text.html
│ │ │ ├── partials
│ │ │ ├── filters.html
│ │ │ ├── header.html
│ │ │ ├── pager.html
│ │ │ ├── row.html
│ │ │ └── toolbar.html
│ │ │ └── table.html
│ ├── main.js
│ └── roles
│ │ ├── controllers
│ │ ├── PermissionEditController.js
│ │ ├── PermissionListController.js
│ │ ├── RoleEditController.js
│ │ └── RoleListController.js
│ │ ├── main.js
│ │ ├── models
│ │ ├── PermissionModel.js
│ │ └── RoleModel.js
│ │ ├── module.js
│ │ ├── providers
│ │ └── RoleHelpersProvider.js
│ │ ├── services
│ │ ├── PermissionService.js
│ │ └── RoleService.js
│ │ ├── tests
│ │ └── e2e
│ │ │ ├── permissions.test.js
│ │ │ └── roles.test.js
│ │ └── views
│ │ ├── permission
│ │ ├── form.html
│ │ ├── list.html
│ │ └── tableActions.html
│ │ └── role
│ │ ├── form.html
│ │ ├── list.html
│ │ └── tableActions.html
├── scripts
│ └── bootstrap.js
├── styles
│ ├── application.css
│ ├── bootstrap.css
│ ├── less
│ │ ├── application.less
│ │ └── bootstrap
│ │ │ ├── mixins.less
│ │ │ ├── theme.less
│ │ │ └── variables.less
│ └── preloader.css
└── ui.html
├── bower.json
├── config
├── global.json
└── index.js
├── lib
├── config
│ └── index.js
└── utils
│ ├── helpers.js
│ └── index.js
├── package.json
├── scripts
├── bs-tunnel-connect.sh
├── bs-tunnel-karma.sh
├── kill-phantomjs.sh
├── setup.js
└── testos.js
├── tasks
├── grunt
│ ├── .gitkeep
│ ├── clean.js
│ ├── compress.js
│ ├── concurrent.js
│ ├── connect.js
│ ├── copy.js
│ ├── cssmin.js
│ ├── htmlmin.js
│ ├── imagemin.js
│ ├── instrument.js
│ ├── jade.js
│ ├── jshint.js
│ ├── karma.js
│ ├── less.js
│ ├── makeReport.js
│ ├── ngAnnotate.js
│ ├── open.js
│ ├── protractor.js
│ ├── protractor_coverage.js
│ ├── requirejs.js
│ ├── rev.js
│ ├── run.js
│ ├── usemin.js
│ ├── useminPrepare.js
│ └── watch.js
└── gulp
│ └── .gitkeep
├── test-e2e.conf.js
├── test-unit.conf.js
└── tests
├── e2e
├── nav.test.js
└── pages.test.js
└── unit
└── main.js
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "app/components",
3 | "json": "bower.json"
4 | }
5 |
--------------------------------------------------------------------------------
/.browserstack.json:
--------------------------------------------------------------------------------
1 | {
2 | "username": "",
3 | "password": "",
4 | "key": ""
5 | }
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 |
9 | indent_style = space
10 | indent_size = 2
11 | end_of_line = lf
12 | charset = utf-8
13 | trim_trailing_whitespace = true
14 | insert_final_newline = true
15 |
16 | [*.md]
17 | trim_trailing_whitespace = false
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .settings
3 | .diff
4 | .patch
5 | .tmp
6 | .sass-cache
7 | .DS_Store
8 | libpeerconnection.log
9 |
10 | /scripts/*.jar
11 | /scripts/bs-tunnel.sh
12 | /scripts/BrowserStackTunnel.jar
13 | /scripts/*.exe
14 |
15 | /dist
16 | /app/components
17 | /node_modules
18 | /test/coverage
19 |
20 | scripts/Chromedriver
21 |
22 | scripts/chromedriver_2.9.zip
23 |
24 | scripts/chromedriver_2.10.zip
25 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "maxerr": 100,
3 | "passfail": false,
4 | "smarttabs": true,
5 | "browser": true,
6 | "predef": [
7 | "__dirname",
8 | "define",
9 | "describe",
10 | "it",
11 | "xit",
12 | "beforeEach",
13 | "afterEach",
14 | "expect",
15 | "spyOn",
16 | "runs",
17 | "waits",
18 | "waitsFor"
19 | ],
20 | "globals": {
21 | "require": true,
22 | "module": true,
23 | "sinon": true,
24 | "S": true,
25 | "steal": true,
26 | "test": true,
27 | "equal": true,
28 | "ok": true,
29 | "console": true,
30 | "process": true
31 | },
32 | "debug": false,
33 | "devel": false,
34 | "esnext": true,
35 | "strict": true,
36 | "globalstrict": true,
37 | "asi": false,
38 | "laxbreak": false,
39 | "laxcomma": true,
40 | "bitwise": true,
41 | "boss": false,
42 | "curly": true,
43 | "eqeqeq": true,
44 | "eqnull": false,
45 | "evil": false,
46 | "expr": true,
47 | "forin": false,
48 | "immed": true,
49 | "latedef": true,
50 | "loopfunc": false,
51 | "maxdepth": 3,
52 | "maxparams": false,
53 | "multistr": false,
54 | "noarg": true,
55 | "regexp": true,
56 | "shadow": false,
57 | "supernew": false,
58 | "undef": true,
59 | "unused": true,
60 | "quotmark": "single",
61 | "camelcase": true,
62 | "indent": 2,
63 | "newcap": true,
64 | "noempty": false,
65 | "nonew": true,
66 | "nomen": false,
67 | "onevar": false,
68 | "plusplus": false,
69 | "sub": false,
70 | "trailing": true,
71 | "white": false
72 | }
73 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | before_install:
2 | - npm install -g grunt-cli
3 | - npm install -g bower
4 | - npm install -g cleverstack-cli
5 |
6 | before_script:
7 | - export NODE_ENV=test
8 | - export NODE_PATH=./lib/:./modules/
9 |
10 | script:
11 | - "npm test"
12 |
13 | notifications:
14 | email:
15 | - cleverstack@github.com
16 | irc:
17 | - "chat.freenode.net#cleverstack"
18 |
19 | env:
20 | - NODE_ENV=test; NODE_PATH=./lib/:./modules/
21 |
22 | language: node_js
23 |
24 | node_js:
25 | - '0.10'
26 | - '0.11'
27 | - '0.12'
28 | - 'iojs'
29 |
30 | branches:
31 | only:
32 | - master
33 |
34 | cache:
35 | directories:
36 | - node_modules
37 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # A Word on Contributing
2 |
3 | Contributing to a project is not only adding slabs of code, fixing bugs, or creating optimizations, but it is also contributing to programmers, CTOs, fathers, mothers, sons and daughters. This project isn't about a team of developers or a "we the programmers" yacht club. It really about "us" and helpings others climb that same mountain. Whether the top of the mountain is making more money, improving your developing skills, or spending more time with your family we're all climbing the same rocks.
4 |
5 | > CleverStack aims to not be a framework or a stack, but an ecosystem. [An ecosystem is a community of living organisms (plants, animals and microbes) in conjunction with the nonliving components of their environment (things like air, water and mineral soil), interacting as a system](http://en.wikipedia.org/wiki/Ecosystem).
6 |
7 | > The vision for CleverStack is not to be the best performance framework (although, there is certainly concern for that), including support for all of the gadgets and gizmos (this too, is welcomed), or to be the next buzzword (it would be cool to see others talking about it though) it's more about shifting a developer into a different mindset. A mindset in which not only takes the [modularization principles](http://en.wikipedia.org/wiki/Modular_programming) on a vertical scale (e.g. reducing developing time), but a horizontal scale too (e.g. not needing to focus on every single detail, but being able to take a step back and look at your environment across the horizon).
8 |
9 | > I just wanted to thank you for not only looking into contributing towards CleverStack, but for even taking your time to considering it. I'm personally always available to lend out a hand, and I hope you never feel as if you can't reach out to me. I always look forward to discussing ideas, solving problems, and colloborating with others.
10 |
11 | > - Richard Gustin
12 |
13 | ## Submitting bug reports, issues, or enhancement requests.
14 |
15 | There are currently a few resources available to reach out to us:
16 |
17 | 1. [GitHub Issues](https://github.com/CleverStack/angular-seed/issues)
18 | 2. [Stack Overflow](http://stackoverflow.com/questions/tagged/cleverstack)
19 | 3. [Google Groups/Mailing list](https://groups.google.com/forum/#!forum/cleverstack)
20 | 4. [HipChat](http://www.hipchat.com/gwM43u4Mw)
21 |
22 | ## Submitting Pull Requests
23 |
24 | 1. Fork the repo
25 | 2. Create a new branch following the [Gitflow](https://www.atlassian.com/git/workflows#!workflow-gitflow) structure.
26 | 3. Refactors and documentation changes do not require a test, but if you're adding a new function please write a tests for that feature.
27 | 4. Please follow the [coding guidelines](https://github.com/CleverStack/angular-seed/blob/master/.jshintrc)
28 | 5. Push your changes and submit a [pull request](https://github.com/CleverStack/angular-seed/compare/) to the master branch.
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | , utils = require('utils')
3 | , merge = require('deepmerge')
4 | , registerFuncs = []
5 | , gruntConfig = {};
6 |
7 | /**
8 | * Helper function to load grunt task configuration objects and register tasks
9 | * @param {String} taskNames the names of the tasks you want to load
10 | */
11 | function loadGruntConfigs(taskNames, rootPath) {
12 | 'use strict';
13 |
14 | rootPath = rootPath || __dirname;
15 |
16 | taskNames.forEach(function(taskName) {
17 | var gruntTask = require(path.resolve(path.join(rootPath, 'tasks', 'grunt', taskName)))
18 | , hasRegister = gruntTask.config && gruntTask.register
19 | , taskConfig = {};
20 |
21 | // Extend the main grunt config with this tasks config
22 | taskConfig[taskName.replace('.js', '')] = !!hasRegister ? gruntTask.config : gruntTask;
23 | gruntConfig = merge(gruntConfig, taskConfig);
24 |
25 | // Allow registration of grunt tasks
26 | if (!!hasRegister) {
27 | registerFuncs.push(gruntTask.register);
28 | }
29 | });
30 | }
31 |
32 | module.exports = function (grunt) {
33 | 'use strict';
34 |
35 | require('time-grunt')(grunt);
36 | require('load-grunt-tasks')(grunt);
37 |
38 | // Load the base configuration object
39 | gruntConfig.appConfig = require(path.resolve(path.join(__dirname, 'config', 'global.json')));
40 |
41 | // Load the grunt task config files for all modules and the base
42 | loadGruntConfigs(utils.helpers.getFilesForFolder(path.resolve(path.join(__dirname, 'tasks', 'grunt'))));
43 |
44 | // Initialize the config
45 | grunt.initConfig(gruntConfig);
46 |
47 | // Fire the callbacks and allow the modules to register their tasks
48 | registerFuncs.forEach(function(registerTasks) {
49 | registerTasks(grunt);
50 | });
51 |
52 | grunt.registerTask('server', [
53 | 'clean:server',
54 | 'connect:livereload',
55 | 'connect:dist',
56 | 'concurrent:watch'
57 | ]);
58 |
59 | grunt.registerTask('build', [
60 | 'clean:dist',
61 | 'jade:compile',
62 | 'useminPrepare',
63 | 'jshint',
64 | 'imagemin',
65 | 'less',
66 | 'cssmin',
67 | 'copy:dist',
68 | 'ngAnnotate:dist',
69 | 'requirejs',
70 | // 'copy:distScripts',
71 | // 'compress',
72 | 'rev',
73 | 'usemin',
74 | 'htmlmin'
75 | ]);
76 |
77 | grunt.registerTask('serve', 'Alias.', [
78 | 'server'
79 | ]);
80 |
81 | grunt.registerTask('default', ['build']);
82 | };
83 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 CleverStack
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | CleverStack Angular Seed
2 | ====================
3 |
4 | [](https://gitter.im/CleverStack/angular-seed?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5 | [](http://badge.fury.io/gh/cleverstack%2Fangular-seed) [](https://david-dm.org/CleverStack/angular-seed) [](https://david-dm.org/CleverStack/angular-seed#info=devDependencies) [](https://codeclimate.com/github/CleverStack/angular-seed)
6 | [](https://travis-ci.org/CleverStack/angular-seed)
7 | [](https://codeclimate.com/github/CleverStack/angular-seed)
8 | [](http://gruntjs.com/)
9 |
10 | 
11 |
12 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
JavaScript Warning
76 |
77 |
78 |
79 |
80 |
Whoops it looks like your browser either doesn't support JavaScript or it has been disabled, please enable JavaScript and refresh the page.
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/app/modules/app/controllers/ApplicationController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'app' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'app.controllers' )
6 | .controller( 'ApplicationController', function( $scope, Helpers, Template, Session ) {
7 | $scope.helpers = Helpers;
8 | $scope.tpl = Template;
9 |
10 | $scope.currentUser = null;
11 |
12 | $scope.$watch( Session.getCurrentUser, function( user ) {
13 | $scope.currentUser = user || false;
14 | });
15 |
16 | ng.element('html').removeClass('no-js');
17 | }
18 | );
19 |
20 | });
21 |
--------------------------------------------------------------------------------
/app/modules/app/controllers/HelpController.js:
--------------------------------------------------------------------------------
1 | define(['angular', 'jquery', 'app'], function(ng, $) {
2 | 'use strict';
3 |
4 | ng
5 | .module('app.controllers')
6 | .controller('HelpController', function($scope, $window, Helpers) {
7 | $scope.helpers = Helpers;
8 | $('#forum_embed').get(0).src = 'http://groups.google.com/forum/embed/?place=forum/clever-stack&showsearch=true&showpopout=true&hidesubject=false&hidetitle=false&parenturl=' + encodeURIComponent($window.location.origin) + '#!forum/clever-stack';
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/app/modules/app/controllers/HomeController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'app' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'app.controllers' )
6 | .controller( 'HomeController', function( $scope, Helpers ) {
7 | $scope.welcome = 'Welcome to the CleverStack AngularJS Front-end!';
8 | $scope.helpers = Helpers;
9 | });
10 |
11 | });
12 |
--------------------------------------------------------------------------------
/app/modules/app/main.js:
--------------------------------------------------------------------------------
1 | define([
2 | // This modules definition
3 | './module',
4 |
5 | // CleverStack modules
6 | 'cs_common',
7 |
8 | // Controllers
9 | './controllers/ApplicationController',
10 | './controllers/HomeController',
11 | './controllers/HelpController'
12 |
13 | ], function() {
14 |
15 | });
16 |
--------------------------------------------------------------------------------
/app/modules/app/module.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng.module( 'app.controllers', [] );
5 |
6 | var module = ng.module( 'app', [
7 | 'cs_common',
8 | 'cs_table',
9 | 'cs_modal',
10 | 'auth',
11 | 'cs_accounts',
12 | 'roles',
13 | 'app.controllers'
14 | ]);
15 |
16 | module.config( function( $routeProvider, $locationProvider, TemplateProvider, HttpOptionsProvider, SessionProvider, NavbarProvider ) {
17 |
18 | // Turn on HTML5 PushState URL's
19 | $locationProvider.html5Mode( true );
20 |
21 | // Set the service that will be used for Sessions
22 | SessionProvider.setSessionService( 'SessionService' );
23 |
24 | // Set the domain of the API
25 | switch( window.location.host.match( '([^:]+):?(.*)' )[ 1 ] ) {
26 |
27 | case 'localhost':
28 | case '127.0.0.1':
29 | case 'local':
30 | default:
31 | HttpOptionsProvider.setDomain( 'http://localhost:8080' );
32 | break;
33 | }
34 |
35 | NavbarProvider.extend({
36 | app: [
37 | {
38 | label: 'Home',
39 | href: '/',
40 | class: 'fa-2x fa-home',
41 | order: 10,
42 | display: function() {
43 | return true;
44 | }
45 | },
46 | {
47 | label: 'Add New...',
48 | class: 'fa-2x fa-plus-circle',
49 | requiresSignIn: true,
50 | order: 20,
51 | subMenu: [
52 | {
53 | label: 'User',
54 | href: '/user/new',
55 | class: 'fa-user',
56 | requiresSignIn: true,
57 | order: 1,
58 | click: function( $scope, $event ) {
59 | $scope.helpers.openUserModal( false );
60 | $event.preventDefault();
61 | }
62 | },
63 | {
64 | label: 'Role',
65 | href: '/role/new',
66 | class: 'fa-group',
67 | requiresSignIn: true,
68 | order: 2,
69 | click: function( $scope, $event ) {
70 | $scope.helpers.openRoleModal( false );
71 | $event.preventDefault();
72 | }
73 | },
74 | {
75 | label: 'Permission',
76 | href: '/permission/new',
77 | class: 'fa-legal',
78 | requiresSignIn: true,
79 | order: 3,
80 | click: function( $scope, $event ) {
81 | $scope.helpers.openPermissionModal( false );
82 | $event.preventDefault();
83 | }
84 | }
85 | ]
86 | },
87 | {
88 | label: 'Help',
89 | href: '/help',
90 | class: 'fa-2x fa-question-circle',
91 | order: 40,
92 | display: function() {
93 | return true;
94 | }
95 | }
96 | ]
97 | });
98 |
99 | $routeProvider
100 | .when( '/', {
101 | templateUrl: TemplateProvider.view( 'app', 'home' ),
102 | controller: 'HomeController',
103 | public: true
104 | })
105 | .when( '/help', {
106 | templateUrl: TemplateProvider.view( 'app', 'help' ),
107 | controller: 'HelpController',
108 | public: true
109 | });
110 |
111 | });
112 |
113 | return module;
114 | });
115 |
--------------------------------------------------------------------------------
/app/modules/app/styles/help.less:
--------------------------------------------------------------------------------
1 | .btn {
2 | .hidden-xs {
3 | display: inline-block !important;
4 | }
5 | }
6 |
7 | @media (max-width: 767px) {
8 | .btn {
9 | .hidden-xs {
10 | display: none!important;
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/modules/app/tests/e2e/home.test.js:
--------------------------------------------------------------------------------
1 | // test if the homepage is loading
2 | describe('e2e: home', function() {
3 |
4 | var ptor;
5 | beforeEach(function() {
6 | browser.get('/');
7 | ptor = protractor.getInstance();
8 | });
9 |
10 | it('should load the home page', function() {
11 | expect(ptor.isElementPresent(by.id('home'))).toBe(true);
12 | });
13 |
14 | });
15 |
--------------------------------------------------------------------------------
/app/modules/app/tests/unit/controllers/application_controller.js:
--------------------------------------------------------------------------------
1 | define(['angular', 'angular-mocks'], function(ng) {
2 | 'use strict';
3 |
4 | describe('Controller: ApplicationController', function() {
5 |
6 | // load the controller's module
7 | beforeEach(ng.mock.module('app'));
8 |
9 | var ApplicationCtrl
10 | , scope;
11 |
12 | // Initialize the controller and a mock scope
13 | beforeEach(ng.mock.inject(function($controller, $rootScope) {
14 | scope = $rootScope.$new();
15 | ApplicationCtrl = $controller('ApplicationController', {
16 | $scope: scope
17 | });
18 | }));
19 |
20 | it('should have loaded helpers and set it on the scope', function() {
21 | scope.helpers.should.be.an('object');
22 | });
23 |
24 | it('should have loaded the template helper and set it on the scope', function() {
25 | scope.tpl.should.be.an('object');
26 | });
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/app/modules/app/tests/unit/controllers/home_controller.js:
--------------------------------------------------------------------------------
1 | define(['angular', 'angular-mocks'], function(ng) {
2 | 'use strict';
3 |
4 | describe('Controller: HomeController', function() {
5 |
6 | // load the controller's module
7 | beforeEach(ng.mock.module('app'));
8 |
9 | var HomeCtrl
10 | , scope;
11 |
12 | // Initialize the controller and a mock scope
13 | beforeEach(ng.mock.inject(function($controller, $rootScope) {
14 | scope = $rootScope.$new();
15 | HomeCtrl = $controller('HomeController', {
16 | $scope: scope
17 | });
18 | }));
19 |
20 | it('should display a welcome message', function() {
21 | scope.welcome.should.equal('Welcome to the CleverStack AngularJS Front-end!');
22 | });
23 |
24 | it('should have loaded helpers and set it on the scope', function() {
25 | scope.helpers.should.be.an('object');
26 | });
27 | });
28 |
29 | });
30 |
--------------------------------------------------------------------------------
/app/modules/app/views/help.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
38 |
39 | Help
40 | How to get help or advice when you are stuck on issues
41 |
42 |
43 |
44 |
45 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/app/modules/app/views/home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Homepage
5 |
{{welcome}}
6 |
7 |
To find helpful documentation please go to cleverstack.io
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/modules/auth/controllers/PasswordResetRequestController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'auth.controllers' )
6 | .controller( 'PasswordResetRequestController', function( $scope, $injector, Session, Helpers ) {
7 | var messenger = $injector.has( 'Messenger' ) ? $injector.get( 'Messenger' ) : $injector.get( '$log' );
8 |
9 | $scope.helpers = Helpers;
10 |
11 | $scope.submit = function() {
12 | if( $scope.form && $scope.form.$invalid ){
13 | return;
14 | }
15 | $scope.submitted = false;
16 | $scope.processing = true;
17 |
18 | Session.requestPasswordReset( { email: $scope.email } );
19 | };
20 |
21 | $scope.$on( 'SessionProvider:requestPasswordResetSuccess', function() {
22 | $scope.success = true;
23 |
24 | messenger.success( 'You will shortly receive a confirmation email. Please follow it to reset your password.' );
25 | });
26 |
27 | $scope.$on( 'SessionProvider:requestPasswordResetFailure', function( err ) {
28 | $scope.processing = false;
29 | $scope.success = false;
30 |
31 | messenger.error( err || 'Unknown email address.' );
32 | });
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/app/modules/auth/controllers/PasswordResetSubmitController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'underscore', '../module' ], function( ng, _ ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'auth.controllers' )
6 | .controller( 'PasswordResetSubmitController', function( $scope, $routeParams, $location, $injector, Session, Helpers ) {
7 | var messenger = $injector.has( 'Messenger' ) ? $injector.get( 'Messenger' ) : $injector.get( '$log' );
8 |
9 | $scope.helpers = Helpers;
10 | $scope.credentials = {
11 | token: $routeParams.t,
12 | user: $routeParams.u
13 | };
14 |
15 | $scope.submit = function() {
16 | if( $scope.form && $scope.form.$invalid ){
17 | return;
18 | }
19 |
20 | $scope.processing = true;
21 | $scope.submitted = false;
22 |
23 | Session.submitPasswordReset( _( $scope.credentials ).omit( 'passwordConfirmation' ) );
24 | };
25 |
26 | $scope.$on( 'SessionProvider:submitPasswordResetSuccess', function() {
27 | messenger.success( 'Your new password is saved. You may now sign in with your new password.' );
28 | });
29 |
30 | $scope.$on( 'SessionProvider:submitPasswordResetFailure', function() {
31 | $scope.processing = false;
32 | messenger.error( 'Unable to store new password.' );
33 | });
34 |
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/app/modules/auth/controllers/SignInController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'auth.controllers' )
6 | .controller( 'SignInController', function( $rootScope, $scope, $log, $location, $injector, Session, Helpers ) {
7 | var messenger = $injector.has( 'Messenger' ) ? $injector.get( 'Messenger' ) : $log;
8 |
9 | $scope.helpers = Helpers;
10 | $scope.processing = false;
11 | $scope.submitted = false;
12 |
13 | $scope.signIn = function() {
14 | if ( $scope.form && $scope.form.$invalid ) {
15 | messenger.warn( 'Fix form errors and try again.' );
16 | return;
17 | }
18 |
19 | if( $scope.processing ){
20 | return;
21 | }
22 |
23 | $scope.processing = true;
24 |
25 | Session.signIn( $scope.credentials );
26 |
27 | $scope.$on( 'SessionProvider:signInFailure', function( event, data ) {
28 | $scope.processing = false;
29 | messenger.error( data.message ? data.message : data );
30 | });
31 |
32 | $scope.$on( 'SessionProvider:signInSuccess', function( event ) {
33 | messenger.success( 'User
' + event.currentScope.credentials.username + ' signed in.' );
34 | $scope.processing = false;
35 | $location.path( '/' );
36 | });
37 | };
38 |
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/app/modules/auth/controllers/SignOutController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'auth.controllers' )
6 | .controller( 'SignOutController', function( $injector, $log, Session ) {
7 | $log.log( 'SignOutController: signOut()' );
8 | Session.signOut();
9 | });
10 | });
--------------------------------------------------------------------------------
/app/modules/auth/controllers/SignUpConfirmController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'auth.controllers' )
6 | .controller( 'SignUpConfirmController', function( $scope, Session, AuthHelpers, $routeParams ) {
7 |
8 | $scope.$on( 'SessionProvider:signUpConfirmationSuccess', function( event, data ) {
9 | Session.authenticate( data.user );
10 | $scope.success = true;
11 | });
12 |
13 | $scope.$on('SessionProvider:signUpConfirmationFailure', function(){
14 | $scope.failure = true;
15 | });
16 |
17 | Session.confirmSignUp( { id: $routeParams.u, token: $routeParams.t, name: $routeParams.n } );
18 |
19 | }
20 | );
21 | });
22 |
--------------------------------------------------------------------------------
/app/modules/auth/controllers/SignUpController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'underscore', '../module' ], function( ng, _ ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'auth.controllers' )
6 | .controller( 'SignUpController', function( $rootScope, $scope, $injector, $log, Account, Helpers, Session, $location ) {
7 | var messenger = $injector.has( 'Messenger' ) ? $injector.get( 'Messenger' ) : $log;
8 |
9 | $scope.helpers = Helpers;
10 | $scope.credentials = {};
11 |
12 | $scope.processing = false;
13 |
14 | $scope.signUp = function() {
15 | if ( $scope.form && $scope.form.$invalid ) {
16 | messenger.warn( 'Fix form errors and try again.' );
17 | return;
18 | }
19 |
20 | if ( $scope.processing ) {
21 | return;
22 | }
23 | $scope.processing = true;
24 |
25 | var credentials = _( $scope.credentials ).omit( 'passwordConfirmation' );
26 | credentials.username = credentials.email;
27 |
28 | Session.signUp( credentials );
29 | };
30 |
31 | $rootScope.$on( 'SessionProvider:signUpSuccess', function( /* event, user */ ) {
32 | $scope.success = true;
33 |
34 | // @TODO - run this code if users are not required to confirm their email!
35 | // Session.authenticate( user );
36 | // $location.url( '/pages' );
37 | });
38 |
39 | $rootScope.$on( 'SessionProvider:signUpFailure', function( event, data ) {
40 | $scope.success = false;
41 | $scope.processing = false;
42 | messenger.error( data && data.message ? data.message : 'Unable to Sign Up. Please try again. (or later)' );
43 | });
44 |
45 | $scope.checkUrl = function( $event ) {
46 | if ( !/(https?:\/\/)/ig.test( $event.target.value ) ) {
47 | $event.target.value = 'http://' + $event.target.value.replace( RegExp.$1, '' );
48 | $scope.credentials[ $event.target.name ] = $event.target.value;
49 | }
50 | };
51 | }
52 | );
53 | });
54 |
--------------------------------------------------------------------------------
/app/modules/auth/controllers/UserEditController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'auth.controllers' )
6 | .controller( 'UserEditController', function( $rootScope, $scope, $modalInstance, $injector, Helpers, UserService, user, roles, currentUser ) {
7 | var Messenger = $injector.has( 'Messenger' ) ? $injector.get( 'Messenger' ) : $injector.get( '$log' );
8 |
9 | $scope.helpers = Helpers;
10 | $scope.user = user;
11 | $scope.roles = roles;
12 | $scope.currentUser = currentUser;
13 |
14 | $scope.save = function() {
15 | var promise;
16 |
17 | if ( this.form && this.form.$invalid ) {
18 | return Messenger.warn( 'Fix form errors and try again.' );
19 | }
20 |
21 | if ($scope.user.Role !== null) {
22 | $scope.user.Role = parseInt($scope.user.Role, 10);
23 | }
24 |
25 | if ( !!$scope.user.id ) {
26 | promise = $scope.user.$save();
27 | } else {
28 | promise = UserService.create( $scope.user );
29 | }
30 |
31 | promise
32 | .then( function() {
33 | $rootScope.$broadcast( 'table:reload' );
34 | Messenger.success( 'User ' + $scope.user.fullName + ' (' + $scope.user.email + ') successfully ' + ( !!$scope.user.id ? 'updated.' : 'created.' ) );
35 | $modalInstance.close( $scope );
36 | })
37 | .catch( function( err ) {
38 | Messenger.error( 'Unable to ' + ( !!$scope.user.id ? 'update' : 'create' ) + ' user ' + $scope.user.firstName + ' ' + $scope.user.lastName + ' (' + $scope.user.email + ') due to error (' + err + ')' );
39 | });
40 | };
41 |
42 | $scope.cancel = function () {
43 | if ( $scope.user && typeof $scope.user.$get === 'function' ) {
44 | $scope.user.$get();
45 | }
46 | $modalInstance.dismiss( 'cancel' );
47 | };
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/app/modules/auth/controllers/UsersListController.js:
--------------------------------------------------------------------------------
1 | define(['angular', '../module'], function(ng) {
2 | 'use strict';
3 |
4 | ng
5 | .module('auth.controllers')
6 | .controller('UsersListController', function($scope, Helpers, dateFilter) {
7 | $scope.helpers = Helpers;
8 | $scope.welcome = 'This page lists all of the Users available in your account, you can add as many as you want';
9 | $scope.actionsTemplate = '/modules/auth/views/users/table_actions.html';
10 | $scope.sorting = {
11 | id: 'asc'
12 | };
13 | $scope.columns = [
14 | {
15 | name: 'id',
16 | title: 'ID',
17 | filter: true,
18 | filterType: 'text',
19 | glyph: 'slack',
20 | sortable: true,
21 | visible: true
22 | },
23 | {
24 | name: 'firstName',
25 | title: 'First Name',
26 | filter: true,
27 | filterType: 'text',
28 | glyph: 'user',
29 | sortable: true,
30 | visible: true,
31 | filterData: {}
32 | },
33 | {
34 | name: 'lastName',
35 | title: 'Last Name',
36 | filter: true,
37 | filterType: 'text',
38 | glyph: 'user',
39 | visible: true
40 | },
41 | {
42 | name: 'email',
43 | title: 'Email',
44 | filter: true,
45 | filterType: 'text',
46 | glyph: 'envelope',
47 | visible: true
48 | },
49 | {
50 | name: 'accessedAt',
51 | title: 'Last Login',
52 | filter: true,
53 | // filterType: 'calendar',
54 | visible: true,
55 | display: function(val) {
56 | if (val) {
57 | return dateFilter(val, 'short');
58 | }
59 | return 'Never';
60 | }
61 | },
62 | {
63 | name: 'createdAt',
64 | title: 'Date Registered',
65 | filter: true,
66 | // filterType: 'calendar',
67 | glyph: 'calendar',
68 | width: 100,
69 | visible: true,
70 | display: function(val) {
71 | return dateFilter(val, 'short');
72 | }
73 | }
74 | ];
75 |
76 | });
77 | });
78 |
--------------------------------------------------------------------------------
/app/modules/auth/filters/LastLoginFilter.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'auth.filters' )
6 | .filter( 'lastLogin', [
7 | 'dateFilter',
8 | function( dateFilter ) {
9 | return function( input, dateFormat ) {
10 | if ( input ) {
11 | return dateFilter( input, dateFormat || 'short' );
12 | }
13 | return 'Not Active';
14 | };
15 | }
16 | ]);
17 |
18 | });
19 |
--------------------------------------------------------------------------------
/app/modules/auth/main.js:
--------------------------------------------------------------------------------
1 | define([
2 |
3 | './module',
4 |
5 | // Helpers
6 | './providers/AuthHelpersProvider',
7 |
8 | // Providers
9 | './providers/SessionProvider',
10 |
11 | './models/UserModel',
12 |
13 | // Services
14 | './services/SessionService',
15 | './services/UserService',
16 |
17 | // Filters
18 | './filters/LastLoginFilter',
19 |
20 | // Controllers
21 | './controllers/SignUpController',
22 | './controllers/SignInController',
23 | './controllers/SignOutController',
24 | './controllers/UsersListController',
25 | './controllers/UserEditController',
26 | './controllers/PasswordResetRequestController',
27 | './controllers/PasswordResetSubmitController',
28 | './controllers/SignUpConfirmController',
29 |
30 | // Directives
31 |
32 |
33 | ], function() {
34 |
35 | });
36 |
--------------------------------------------------------------------------------
/app/modules/auth/models/UserModel.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'auth.models' )
6 | .factory( 'UserModel', function( ResourceFactory ) {
7 | return new ResourceFactory( '/auth/user', { id: '@id' }, {
8 | resend: {
9 | params: {
10 | Action: 'resend'
11 | },
12 | method: 'POST'
13 | },
14 | confirm: {
15 | params: {
16 | Action: 'confirm'
17 | },
18 | method: 'POST'
19 | }
20 | });
21 | });
22 |
23 | });
24 |
--------------------------------------------------------------------------------
/app/modules/auth/providers/AuthHelpersProvider.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'underscore', '../module' ], function( ng, _ ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'auth.providers' )
6 | .provider( 'AuthHelpers', [ function() {
7 | var helpers = {};
8 | var inheritedProviders = [];
9 |
10 | return {
11 | $get: function( $injector, UserService ) {
12 | var RoleService = $injector.has( 'RoleService' ) ? $injector.get( 'RoleService' ) : false
13 | , ModalFactory = $injector.has( 'ModalFactory' ) ? $injector.get( 'ModalFactory' ) : false;
14 |
15 | if ( inheritedProviders ) {
16 | inheritedProviders.forEach( function( inheritedProvider ) {
17 | var provider = $injector.get( inheritedProvider );
18 | if ( !provider ) {
19 | throw new Error( 'Unable to inject "' + inheritedProvider + '"' );
20 | }
21 | ng.extend( helpers, provider );
22 | });
23 | }
24 |
25 | helpers.openUserModal = function( user, currentUser ) {
26 | ModalFactory.open( user, '/modules/auth/views/users/form.html', {
27 | controller: 'UserEditController',
28 | resolve: {
29 | user: function() {
30 | if ( typeof user === 'object' ) {
31 | user.Role = user.Role && !isNaN(user.Role.id) ? parseInt(user.Role.id, 10) : user.Role;
32 | return user;
33 | } else if ( user !== false && user !== undefined ) {
34 | return UserService
35 | .get( { id: user } )
36 | .then( function( user ) {
37 | user.Role = user.Role && !isNaN(user.Role.id) ? parseInt(user.Role.id, 10) : user.Role;
38 |
39 | return user;
40 | });
41 | } else {
42 | return {Role: null};
43 | }
44 | },
45 | currentUser: function() {
46 | return currentUser;
47 | },
48 | roles: function() {
49 | if ( !!RoleService ) {
50 | return RoleService
51 | .list()
52 | .then(function( roles ) {
53 | _.each(roles, function(role) {
54 | role.Users = role.Users.map( function( user ) {
55 | return user.id;
56 | });
57 | role.Permissions = role.Permissions.map( function( permission ) {
58 | return permission.id;
59 | });
60 | });
61 | return roles;
62 | });
63 | } else {
64 | return [];
65 | }
66 | }
67 | }
68 | });
69 | };
70 |
71 | return helpers;
72 | },
73 |
74 | /**
75 | * @ngdoc function
76 | * @methodOf ngSeed.providers:CSAccountProvider
77 | * @name setAccountService
78 | * @param {String} serviceName the account service name
79 | */
80 | extend: function( providerName ) {
81 | if ( typeof providerName !== 'string' ) {
82 | throw new Error( 'Helpers: extend method expects a string (name of the helpers provider)' );
83 | }
84 | inheritedProviders.push( providerName );
85 | }
86 | };
87 |
88 | }]);
89 | });
90 |
--------------------------------------------------------------------------------
/app/modules/auth/services/SessionService.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'auth.services' )
6 | .service( 'SessionService', function( $resource ) {
7 |
8 | return $resource( '/auth/:Action', {}, {
9 | signIn: {
10 | method: 'POST',
11 | params: {
12 | Action: 'signIn'
13 | }
14 | },
15 | signOut: {
16 | method: 'POST',
17 | params: {
18 | Action: 'signOut'
19 | }
20 | },
21 | session: {
22 | method: 'GET',
23 | params: {
24 | Action: 'session'
25 | }
26 | },
27 | requestPasswordReset: {
28 | method: 'POST',
29 | params: {
30 | Action: 'recover'
31 | },
32 | url: '/auth/users/:Action'
33 | }
34 | });
35 |
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/app/modules/auth/services/UserService.js:
--------------------------------------------------------------------------------
1 | define(['angular', '../module'], function(ng) {
2 | 'use strict';
3 |
4 | ng
5 | .module('auth.services')
6 | .factory('UserService', function(UserModel) {
7 | var UserService = {
8 | model: UserModel,
9 |
10 | data: null,
11 |
12 | list: function(findOptions) {
13 | return UserModel.list(findOptions).$promise.then(function(users) {
14 | UserService.data = users;
15 | return UserService.data;
16 | });
17 | },
18 |
19 | get: function(findOptions) {
20 | return UserModel.get(findOptions).$promise;
21 | },
22 |
23 | create: function(data) {
24 | return UserModel.create(data).$promise;
25 | },
26 |
27 | confirm: function(data) {
28 | return UserModel.confirm(data).$promise;
29 | }
30 | };
31 |
32 | return UserService;
33 | });
34 |
35 | });
36 |
--------------------------------------------------------------------------------
/app/modules/auth/tests/e2e/passwordReset.test.js:
--------------------------------------------------------------------------------
1 | describe('e2e: passwordReset', function() {
2 |
3 | var ptor, submit, appMsg;
4 |
5 | beforeEach(function() {
6 | browser.get('/requestPasswordReset');
7 |
8 | ptor = protractor.getInstance();
9 | submit = element(by.css('button[type="submit"]'));
10 | appMsg = element(by.css('#app_message'));
11 | });
12 |
13 | it('Can reset password', function() {
14 | // Fill out the form
15 | element(by.model('email')).sendKeys('default@cleverstack.io');
16 |
17 | // Submit the form
18 | submit.click();
19 |
20 | browser.driver.sleep(1);
21 | browser.waitForAngular();
22 |
23 | // Did the right success message show up after signup?
24 | appMsg.isDisplayed().then(function(isDisplaying) {
25 | expect(isDisplaying).toBe(true);
26 | });
27 | expect(element(by.css('#app_message span')).getText()).toEqual('');
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/app/modules/auth/tests/e2e/signIn.test.js:
--------------------------------------------------------------------------------
1 | describe('e2e: signIn', function() {
2 |
3 | var ptor, appMsg, submit, username, password;
4 | beforeEach(function() {
5 | browser.get('/signIn');
6 | ptor = protractor.getInstance();
7 |
8 | appMsg = element(by.css('#app_message'));
9 | submit = element(by.css('button[type="submit"]'));
10 | username = element(by.model('credentials.username'));
11 | password = element(by.model('credentials.password'));
12 | });
13 |
14 | it('should not allow sign-in with a fake account', function() {
15 | username.sendKeys('fake@cleverstack.io');
16 | password.sendKeys('fake');
17 |
18 | submit.click();
19 |
20 | browser.driver.sleep(1);
21 | browser.waitForAngular();
22 |
23 | // Make sure we get error messages
24 | expect(appMsg.isDisplayed()).toBeTruthy();
25 | expect(element(by.css('#app_message span')).getText()).toEqual('Invalid login credentials.');
26 | });
27 |
28 | it('should not allow sign-in without a username', function() {
29 | username.sendKeys('');
30 | password.sendKeys('fake');
31 |
32 | submit.click();
33 |
34 | // Make sure we get error messages
35 | expect(appMsg.isDisplayed()).toBeTruthy();
36 | expect(element(by.css('#app_message span')).getText()).toEqual('Fix form errors and try again.');
37 | });
38 |
39 | it('should not allow sign-in without a password', function() {
40 | username.sendKeys('fake@cleverstack.io');
41 | password.sendKeys('');
42 |
43 | submit.click();
44 |
45 | // Make sure we get error messages
46 | expect(appMsg.isDisplayed()).toBeTruthy();
47 | expect(element(by.css('#app_message span')).getText()).toEqual('Fix form errors and try again.');
48 | });
49 |
50 | it('should allow sign-in with the default account', function() {
51 | username.sendKeys('default@cleverstack.io');
52 | password.sendKeys('clever');
53 |
54 | // Check to make sure we can't click submit multiple times while we are waiting
55 | browser.actions().doubleClick(submit).perform();
56 |
57 | browser.driver.sleep(1);
58 | browser.waitForAngular();
59 |
60 | expect(appMsg.isDisplayed()).toBeTruthy();
61 | expect(element(by.css('#app_message span')).getText()).toEqual('User default@cleverstack.io signed in.');
62 |
63 | // Make sure we get redirected OK
64 | expect(element(by.css('h1')).getText()).toEqual('Homepage');
65 | });
66 | });
67 |
--------------------------------------------------------------------------------
/app/modules/auth/tests/e2e/signOut.test.js:
--------------------------------------------------------------------------------
1 | describe('e2e: signOut', function() {
2 |
3 | var ptor;
4 | beforeEach(function() {
5 | browser.get('/');
6 | ptor = protractor.getInstance();
7 | appMsg = element(by.css('#app_message'));
8 | });
9 |
10 | it('should signOut of the default user account', function() {
11 | element(by.css('a[href="/signOut"]')).click();
12 |
13 | browser.driver.sleep(1);
14 | browser.waitForAngular();
15 |
16 | // Top message bar displayed with the right text?
17 | expect(appMsg.isDisplayed()).toBeTruthy();
18 | expect(element(by.css('#app_message span')).getText()).toEqual('You have signed out.');
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/app/modules/auth/tests/e2e/signUp.test.js:
--------------------------------------------------------------------------------
1 | describe('e2e: signUp', function() {
2 |
3 | var ptor, submit, appMsg;
4 |
5 | beforeEach(function() {
6 | browser.get('/signUp');
7 | ptor = protractor.getInstance();
8 | submit = element(by.css('button[type="submit"]'));
9 | appMsg = element(by.css('#app_message'));
10 | });
11 |
12 | it('Sign-up form validation works', function() {
13 |
14 | // Displays the validation errors for the form and all of its field's correctly when submit is clicked
15 | submit.click();
16 |
17 | browser.driver.sleep(1);
18 | browser.waitForAngular();
19 |
20 | // Top message bar displayed with the right text?
21 | appMsg.isDisplayed().then(function(isDisplaying) {
22 | expect(isDisplaying).toBe(true);
23 | expect(element(by.css('#app_message span')).getText()).toEqual('Fix form errors and try again.');
24 |
25 | // Individual error notices displayed correctly?
26 | expect(element(by.css('#signup :nth-child(2) .error')).isDisplayed()).toBeTruthy();
27 | expect(element(by.css('#signup :nth-child(3) .error')).isDisplayed()).toBeTruthy();
28 | expect(element(by.css('#signup :nth-child(4) .error')).isDisplayed()).toBeTruthy();
29 | expect(element(by.css('#signup :nth-child(5) .error')).isDisplayed()).toBeTruthy();
30 | expect(element(by.css('#signup :nth-child(7) .error')).isDisplayed()).toBeTruthy();
31 | });
32 | });
33 |
34 | it('Sign-up works for users', function() {
35 |
36 | // Fill out the form
37 | element(by.model('credentials.firstname')).sendKeys('Clever');
38 | element(by.model('credentials.lastname')).sendKeys('User');
39 | element(by.model('credentials.company')).sendKeys('CleverStack');
40 | element(by.model('credentials.domain')).sendKeys('example.com');
41 | element(by.model('credentials.email')).sendKeys('default-e2e@cleverstack.io');
42 | element(by.model('credentials.password')).sendKeys('Clever1~');
43 | element(by.model('credentials.passwordConfirmation')).sendKeys('Clever1~');
44 |
45 | // Submit the form
46 | submit.click();
47 |
48 | browser.driver.sleep(3);
49 | browser.waitForAngular();
50 |
51 | // Did the right success message show up after signup?
52 | element(by.css('div[rel=success]')).isDisplayed().then(function(isDisplaying) {
53 | expect(isDisplaying).toBe(true);
54 |
55 | expect(element(by.id('confirmation-message-1')).getText()).toEqual('Almost Done!');
56 | expect(element(by.id('confirmation-message-2')).getText()).toEqual('You should be receiving an email shortly with instructions on how to activate your account.');
57 | });
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/app/modules/auth/views/partials/signOut.html:
--------------------------------------------------------------------------------
1 |
Signing Out
2 |
You will be redirected after sign out...
--------------------------------------------------------------------------------
/app/modules/auth/views/requestPasswordReset.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Password Recovery
6 |
Please enter your email address used to sign up for your account
7 |
We will send you confirmation link.
8 |
9 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/modules/auth/views/resetPassword.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
Please choose a password that is :
10 |
11 | at least 8 characters long
12 | contains at least one uppercase letter
13 | contains at least one lowercase lette
14 | contains at least 1 number or special character
15 |
16 |
17 |
18 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/modules/auth/views/signIn.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/modules/auth/views/users/list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 | Add User
11 |
12 |
13 |
14 |
User List {{welcome}}
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/modules/auth/views/users/show.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/modules/auth/views/users/table_actions.html:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | Edit
9 |
10 |
11 |
16 |
17 |
18 | Deactivate
19 |
20 |
21 |
22 |
27 |
28 |
29 | Activate
30 |
31 |
32 |
33 |
38 |
39 |
40 | Re-send
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/controllers/AccountChooserController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_accounts.controllers' )
6 | .controller( 'AccountChooserController', function( $scope, $rootScope, Helpers, Account, Session ) {
7 |
8 | $scope.helpers = Helpers;
9 |
10 | $scope.accounts = null;
11 | $scope.account = null;
12 | $scope.currentUser = null;
13 |
14 | $scope.$watch( Account.getAccounts, function( accounts ) {
15 | $scope.accounts = accounts;
16 | });
17 |
18 | $scope.$watch( Account.getSelectedAccount, function( account ) {
19 | $scope.account = account;
20 | });
21 |
22 | $scope.$watch( Session.getCurrentUser, function( user ) {
23 | $scope.currentUser = user;
24 | });
25 |
26 | });
27 |
28 | });
29 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/controllers/AccountsListController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_accounts.controllers' )
6 | .controller( 'AccountsListController', function( $scope, Helpers, dateFilter ) {
7 | $scope.helpers = Helpers;
8 | $scope.welcome = 'This page lists all of the accounts in the system.';
9 | $scope.actionsTemplate = '/modules/cs_accounts/views/partials/tableActions.html';
10 |
11 | $scope.columns = [
12 | {
13 | name : 'id',
14 | title : 'ID',
15 | glyph : 'slack',
16 | filter : true,
17 | filterType : 'text',
18 | sortable : true,
19 | visible : true
20 | },
21 | {
22 | name: 'name',
23 | title: 'Name',
24 | filter: true,
25 | filterType: 'text',
26 | glyph: 'user',
27 | visible: true
28 | },
29 | {
30 | name: 'subDomain',
31 | title: 'Sub Domain',
32 | filter: true,
33 | filterType: 'text',
34 | glyph: 'user',
35 | visible: true
36 | },
37 | {
38 | name: 'email',
39 | title: 'Email',
40 | filter: true,
41 | filterType: 'text',
42 | glyph: 'envelope',
43 | visible: true
44 | },
45 | {
46 | name: 'createdAt',
47 | title: 'Date Registered',
48 | filter: false,
49 | glyph: 'calendar',
50 | width: 100,
51 | visible: true,
52 | display: function( val ) {
53 | return dateFilter( val, 'short' );
54 | }
55 | },
56 | {
57 | name: 'updatedAt',
58 | title: 'Date Updated',
59 | filter: true,
60 | glyph: 'calendar',
61 | filterType: 'text',
62 | visible: true,
63 | display: function( val ) {
64 | if ( val ) {
65 | return dateFilter( val, 'short' );
66 | }
67 | return 'Never';
68 | }
69 | }
70 | ];
71 | });
72 | });
73 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/directives/AccountChooserDirective.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_accounts.directives' )
6 | .directive( 'accountchooser', function( Template, $injector ) {
7 |
8 | return {
9 | restrict : 'E',
10 | transclude : true,
11 | scope : {
12 | heading : '@'
13 | },
14 | replace : true,
15 | templateUrl: Template.view( 'cs_accounts', 'partials/chooser' ),
16 | controller: 'AccountChooserController',
17 | link: function( $scope ) {
18 |
19 | $scope.selectAccount = function( account ) {
20 | $injector.get( 'Account' ).selectAccount( account );
21 | };
22 |
23 | }
24 | };
25 |
26 | });
27 |
28 | });
29 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/main.js:
--------------------------------------------------------------------------------
1 | define([
2 |
3 | './module',
4 |
5 | 'cs_common',
6 |
7 | './providers/AccountProvider',
8 |
9 | './models/AccountModel',
10 |
11 | './services/AccountService',
12 |
13 | './controllers/AccountsListController',
14 | './controllers/AccountChooserController',
15 |
16 | './directives/AccountChooserDirective'
17 |
18 | ], function() {
19 |
20 | });
21 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/models/AccountModel.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_accounts.models' )
6 | .factory( 'AccountModel', function( ResourceFactory ) {
7 | return new ResourceFactory( '/account', {}, {} );
8 | });
9 |
10 | });
11 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/module.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng.module( 'cs_accounts.providers', [] );
5 | ng.module( 'cs_accounts.controllers', [] );
6 | ng.module( 'cs_accounts.services', [] );
7 | ng.module( 'cs_accounts.filters', [] );
8 | ng.module( 'cs_accounts.models', [] );
9 | ng.module( 'cs_accounts.directives', [] );
10 |
11 | var module = ng.module( 'cs_accounts', [
12 | 'cs_common',
13 | 'cs_messenger',
14 | 'cs_modal',
15 | 'cs_table',
16 | 'auth',
17 | 'roles',
18 | 'cs_accounts.providers',
19 | 'cs_accounts.controllers',
20 | 'cs_accounts.models',
21 | 'cs_accounts.services',
22 | 'cs_accounts.directives',
23 | 'cs_accounts.filters'
24 | ]);
25 |
26 | module.config( function( $routeProvider, $injector, TemplateProvider, NavbarProvider ) {
27 | var settingsMenu;
28 |
29 | // Define menu structure for this module
30 | if ( ( settingsMenu = _.findWhere( NavbarProvider.getNavbar().right, { label: 'Settings' } ) ) !== undefined ) {
31 | settingsMenu.subMenu.push({
32 | label : 'Accounts',
33 | href : '/settings/accounts',
34 | class : 'fa-institution',
35 | requiresSignIn : true,
36 | order : 2,
37 | requiresPermission : 'Account.list'
38 | });
39 | }
40 |
41 | $routeProvider
42 | .when( '/settings/accounts', {
43 | templateUrl : TemplateProvider.view( 'cs_accounts', 'list' ),
44 | controller : 'AccountsListController',
45 | public : false
46 | });
47 |
48 | });
49 |
50 | return module;
51 | });
52 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/services/AccountService.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_accounts.services' )
6 | .factory( 'AccountService', function( AccountModel, UserModel ) {
7 | var AccountService = {
8 | model: AccountModel,
9 |
10 | data : null,
11 |
12 | list : function( findOptions ) {
13 | return AccountModel.list( findOptions ).$promise.then( function( accounts ) {
14 | AccountService.data = accounts;
15 | return AccountService.data;
16 | });
17 | },
18 |
19 | get: function( findOptions ) {
20 | return AccountModel.get( findOptions ).$promise;
21 | },
22 |
23 | create: function( data ) {
24 | return AccountModel.create( data ).$promise;
25 | },
26 |
27 | confirm: function( data ) {
28 | return UserModel.confirm( data ).$promise;
29 | }
30 | };
31 |
32 | return AccountService;
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/views/confirm.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Account Confirmation
6 |
7 |
8 |
9 |
10 |
Processing, please wait...
11 |
12 |
17 |
18 |
Sorry, but something's not right.
19 |
We were unable to authorize your account.
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/views/form.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/views/list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 | Create Account
12 |
13 |
14 |
Account List
15 | {{welcome}}
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/views/partials/chooser.html:
--------------------------------------------------------------------------------
1 |
5 |
9 |
10 |
11 |
12 | {{ ( account.name ? account.name : account.email ) | capitalize }}
13 |
14 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/app/modules/cs_accounts/views/partials/tableActions.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | Edit
10 |
11 |
12 |
17 |
18 |
19 | Delete
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/modules/cs_common/controllers/NavbarController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_common.controllers' )
6 | .controller( 'NavbarController', function( $rootScope, $scope, Session, Helpers, Navbar ) {
7 | $scope.helpers = Helpers;
8 |
9 | $scope.$watch( Session.getCurrentUser, function( user ) {
10 | $scope.currentUser = user || false;
11 | });
12 |
13 | $scope.$watch( Navbar.getNavbar, function( navbarItems ) {
14 | $scope.navbarItems = navbarItems || false;
15 | });
16 | }
17 | );
18 | });
19 |
--------------------------------------------------------------------------------
/app/modules/cs_common/directives/ColorPickerDirective.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'jqueryMinicolors', '../module' ], function( ng ){
2 | 'use strict';
3 |
4 | ng.module( 'cs_common.directives' )
5 | .directive( 'colorPicker',
6 | [
7 | function(){
8 | return {
9 | require: '?ngModel',
10 | link: function( $scope, $element, $attrs, ngModelCtrl ) {
11 |
12 | ngModelCtrl.$render = function() {
13 | $element.minicolors( 'value', ngModelCtrl.$modelValue );
14 | };
15 |
16 | $element.minicolors({
17 | theme: 'bootstrap',
18 | letterCase: 'uppercase',
19 | position: 'top right',
20 | change: function( hex ) {
21 | ngModelCtrl.$setViewValue( hex );
22 | !$scope.$$phase && $scope.$apply();
23 | }
24 | });
25 | }
26 | };
27 | }
28 | ]
29 | );
30 |
31 | });
32 |
--------------------------------------------------------------------------------
/app/modules/cs_common/directives/FocusedOnDirective.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'underscore', '../module' ], function( ng, _ ) {
2 | 'use strict';
3 |
4 | ng.module( 'cs_common.directives' )
5 | .directive( 'focusedOn', [
6 | '$timeout'
7 | ,function( $timeout ) {
8 | return function( $scope, $element, $attrs ) {
9 | function focus() {
10 | $timeout( function() {
11 | $element.focus();
12 | }, 20);
13 | }
14 |
15 | if( _( $attrs.focusedOn ).isEmpty() ) {
16 | return focus();
17 | }
18 |
19 | $scope.$watch( $attrs.focusedOn, function( newVal ) {
20 | if( newVal ) {
21 | focus();
22 | }
23 | });
24 |
25 | };
26 |
27 | }
28 | ]
29 |
30 | );
31 |
32 | });
33 |
--------------------------------------------------------------------------------
/app/modules/cs_common/directives/LoadingDirective.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_common.directives' )
6 | .directive( 'loading',
7 | [
8 | '$timeout',
9 | function( $timeout ) {
10 |
11 | return {
12 | restrict: 'C',
13 | link: function( $scope, $element ) {
14 | var promise;
15 |
16 | $scope.$on( '$routeChangeStart', function() {
17 | promise = $timeout( function() {
18 | $element.show();
19 | }, 400);
20 | });
21 |
22 | function removeLoader() {
23 | $timeout.cancel( promise );
24 | $element.hide();
25 | }
26 |
27 | $scope.$on('SessionProvider:signInRequired', removeLoader);
28 | $scope.$on('$routeChangeSuccess', removeLoader);
29 | }
30 | };
31 | }
32 | ]
33 |
34 | );
35 |
36 | });
37 |
--------------------------------------------------------------------------------
/app/modules/cs_common/directives/MustBeEqualToDirective.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_common.directives' )
6 | .directive( 'mustBeEqualTo', function() {
7 | var link = function( $scope, $element, $attrs, ctrl ) {
8 |
9 | function validate( value ) {
10 | ctrl.$setValidity( 'mustBeEqualTo', value === $scope.$eval( $attrs.mustBeEqualTo ) );
11 | return value;
12 | }
13 |
14 | $scope.$watch( $attrs.mustBeEqualTo, function( equalTo ) {
15 | if ( ng.isUndefined( equalTo ) ) {
16 | return;
17 | }
18 | $scope.equalTo = equalTo;
19 | return validate( $element.val() );
20 | });
21 |
22 | ctrl.$parsers.unshift( validate );
23 |
24 | };
25 |
26 | return {
27 | require: 'ngModel',
28 | link: link
29 | };
30 |
31 | });
32 |
33 | });
34 |
--------------------------------------------------------------------------------
/app/modules/cs_common/directives/NavbarDirective.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | /**
5 | * @ngdoc directive
6 | * @name ngSeed.directives:navbar
7 | * @description
8 | * Sets the current navbar option in focus.
9 | */
10 | ng
11 | .module( 'cs_common.directives' )
12 | .directive( 'navbar', function() {
13 | return {
14 | restrict: 'E',
15 | replace: true,
16 | transclude: true,
17 | templateUrl: 'modules/cs_common/views/navbar.html',
18 | scope: {
19 | heading: '@'
20 | },
21 | controller: 'NavbarController',
22 | link: function( $scope ) {
23 | //show if the item requires signIn and the user is logged in
24 | $scope.showItem = function( item ) {
25 | if ( item.requiresPermission ) {
26 | if ( !$scope.helpers.hasPermission( item.requiresPermission, $scope.currentUser ) ) {
27 | return false;
28 | }
29 | }
30 |
31 | if ( item.display && typeof item.display === 'function' ) {
32 | return item.display( $scope );
33 | } else {
34 | return ng.isDefined( $scope.currentUser ) && ng.isDefined( $scope.currentUser.id ) === item.requiresSignIn;
35 | }
36 | };
37 |
38 | $scope.classHandler = function( item ) {
39 | var css = '';
40 | if ( item.class ) {
41 | css = 'fa fa-fw ' + item.class;
42 | } else if ( item.glyph ) {
43 | css = 'glyphicon glyphicon-' + item.glyph;
44 | }
45 | return css;
46 | };
47 |
48 | }
49 | };
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/app/modules/cs_common/directives/NgBlurDirective.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | /**
5 | * Angular v1.1.5 still doesn't support ngBlur so we build our own
6 | */
7 | ng
8 | .module( 'cs_common.directives' )
9 | .directive( 'ngBlur', [
10 | '$parse',
11 | function( $parse ) {
12 | return function( scope, element, attr ) {
13 | var fn = $parse( attr.ngBlur );
14 | element.bind( 'blur', function( event ) {
15 | scope.$apply( function() {
16 | fn( scope, { $event: event} );
17 | });
18 | });
19 | };
20 | }
21 |
22 | ]
23 | );
24 |
25 | });
26 |
--------------------------------------------------------------------------------
/app/modules/cs_common/directives/NgFocusDirective.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | /**
5 | * Angular v1.1.5 still doesn't support ngFocus so we build our own
6 | */
7 | ng
8 | .module( 'cs_common.directives' )
9 | .directive( 'ngFocus', [
10 | '$parse',
11 | function( $parse ) {
12 | return function( scope, element, attr ) {
13 | var fn = $parse( attr.ngFocus );
14 | element.bind( 'focus', function( event ) {
15 | scope.$apply( function() {
16 | fn( scope, { $event: event } );
17 | });
18 | });
19 | };
20 | }
21 |
22 | ]
23 | );
24 |
25 | });
26 |
--------------------------------------------------------------------------------
/app/modules/cs_common/directives/NgLoadDirective.js:
--------------------------------------------------------------------------------
1 | define(['angular', '../module'], function(ng) {
2 | ng
3 | .module('cs_common.directives')
4 | .directive('ngLoad', [ '$parse', function($parse) {
5 | return {
6 | restrict: 'A',
7 | compile: function($element, attr) {
8 | var fn = $parse(attr.ngLoad);
9 |
10 | return function(scope, element, attr) {
11 | element.on('load', function(event) {
12 | scope.$apply(function() {
13 | fn(scope, {$event:event});
14 | });
15 | });
16 | };
17 |
18 | }
19 | };
20 | }]);
21 | });
22 |
--------------------------------------------------------------------------------
/app/modules/cs_common/directives/StringToNumberDirective.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | /**
5 | * @ngdoc directive
6 | * @name ngSeed.directives:string2number
7 | * @description
8 | * Converts a string to a number. Useful in type="number" input
9 | * elements that bind to a stringified number model.
10 | */
11 | ng
12 | .module( 'cs_common.directives' )
13 | .directive( 'stringToNumber', function() {
14 |
15 | return {
16 | restrict: 'A',
17 | require: 'ngModel',
18 | link: function( scope, element, attr, ngModel ) {
19 |
20 | /**
21 | * @ngdoc method
22 | * @name fromField
23 | * @methodOf ngSeed.directives:string2number
24 | * @param {Number, String} number Just the number that has been input.
25 | * @return {Number} The number.
26 | */
27 | function fromField( number ) {
28 | return Number( number );
29 | }
30 |
31 | /**
32 | * @ngdoc method
33 | * @name toField
34 | * @methodOf ngSeed.directives:string2number
35 | * @param {Number, String} number Just the number that has been input.
36 | * @return {Number} The number or 0.
37 | */
38 | function toField( text ) {
39 | return Number( text || 0 );
40 | }
41 |
42 | ngModel.$parsers.push( fromField );
43 | ngModel.$formatters.push( toField );
44 | }
45 | };
46 |
47 | });
48 |
49 | });
50 |
--------------------------------------------------------------------------------
/app/modules/cs_common/directives/WarnUnsavedChangesDirective.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'underscore', '../module' ], function( angular, _ ) {
2 | 'use strict';
3 |
4 | angular
5 | .module( 'cs_common.directives' )
6 | .directive( 'warnUnsavedChanges', [
7 | '$window',
8 | function( $window ) {
9 | return function( $scope, $element, $attrs ) {
10 | var master, cancelWatch;
11 |
12 | function applyWatch( model ) {
13 | master = angular.copy( model );
14 | attachDirtyFormWarningHandler( $scope );
15 | cancelWatch();
16 | }
17 |
18 | cancelWatch = $scope.$watch( $attrs.warnUnsavedChanges, function( model ) {
19 | if ( model && _( model ).has( '$resolved' ) ) {
20 | if ( model.$resolved === true ) {
21 | applyWatch( model );
22 | }
23 | } else {
24 | applyWatch( model );
25 | }
26 | }, true);
27 |
28 | function attachDirtyFormWarningHandler( $scope ){
29 |
30 | function dirtyFormWarningHandler( event ){
31 | if ( isDirty() ){
32 | if ( !$window.confirm( 'There are unsaved changes on this form. Are you sure you want to leave this page?' ) ) {
33 | event.preventDefault();
34 | }
35 | }
36 | }
37 |
38 | function isDirty() {
39 | return $scope.form.$dirty && !angular.equals( master, $scope[ $attrs.warnUnsavedChanges ] );
40 | }
41 |
42 | $scope.$on( '$locationChangeStart', dirtyFormWarningHandler );
43 |
44 | // function showWarning() {
45 | // return 'There\'s some unsaved changes.';
46 | // }
47 |
48 | // var attached;
49 | // $scope.$watch(isDirty, function(dirty) {
50 | // if(dirty && !attached) {
51 | // angular.element($window).on('beforeunload', showWarning);
52 | // attached = true;
53 | // } else {
54 | // angular.element($window).off('beforeunload', showWarning);
55 | // attached = false;
56 | // }
57 | // });
58 |
59 | $scope.$watch( 'processing', function( processing, previousValue ) {
60 | if( processing === false && previousValue === true ) {
61 | master = angular.copy( $scope[ $attrs.warnUnsavedChanges ] );
62 | }
63 | });
64 |
65 | }
66 |
67 | };
68 | }
69 | ]
70 |
71 | );
72 |
73 | });
--------------------------------------------------------------------------------
/app/modules/cs_common/filters/CapitalizeFilter.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'moment', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_common.filters' )
6 | .filter( 'capitalize', [
7 | function() {
8 | return function( input ) {
9 | return ( !!input ) ? input.replace( /([^\W_]+[^\s-]*) */g, function( txt ){ return txt.charAt( 0 ).toUpperCase() + txt.substr( 1 ).toLowerCase(); } ) : '';
10 | };
11 | }
12 | ]);
13 |
14 | });
--------------------------------------------------------------------------------
/app/modules/cs_common/filters/StartsWithFilter.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | /**
5 | * @ngdoc filter
6 | * @name ngSeed.filters:startsWith
7 | * @description
8 | *
9 | * Filters a collection with a simple regex.
10 | *
11 | * @example
12 |
13 |
14 |
24 |
25 |
26 |
27 |
28 |
29 | Name
30 |
31 |
32 | {{friend.name}}
33 |
34 |
35 |
36 |
37 |
38 | it('should be reverse ordered by aged', function() {
39 | expect(binding('predicate')).toBe('-age');
40 | expect(repeater('table.friend', 'friend in friends').column('friend.age')).
41 | toEqual(['35', '29', '21', '19', '10']);
42 | expect(repeater('table.friend', 'friend in friends').column('friend.name')).
43 | toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']);
44 | });
45 |
46 | it('should reorder the table when user selects different predicate', function() {
47 | element('.doc-example-live a:contains("Name")').click();
48 | expect(repeater('table.friend', 'friend in friends').column('friend.name')).
49 | toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']);
50 | expect(repeater('table.friend', 'friend in friends').column('friend.age')).
51 | toEqual(['35', '10', '29', '19', '21']);
52 |
53 | element('.doc-example-live a:contains("Phone")').click();
54 | expect(repeater('table.friend', 'friend in friends').column('friend.phone')).
55 | toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']);
56 | expect(repeater('table.friend', 'friend in friends').column('friend.name')).
57 | toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']);
58 | });
59 |
60 |
61 | */
62 | ng
63 | .module( 'cs_common.filters' )
64 | .filter( 'startsWith', function() {
65 |
66 | return function( str, letter, prop ) {
67 | letter = letter || undefined;
68 | if ( !letter ) {
69 | return str;
70 | }
71 | var filtered = [];
72 | str.forEach( function( i ) {
73 | if ( ( new RegExp( '^[' + letter.toLowerCase() + letter.toUpperCase() + ']' ) ).test( i[ prop ] ) ) {
74 | filtered.push( i );
75 | }
76 | });
77 | return filtered;
78 | };
79 | });
80 |
81 | });
82 |
--------------------------------------------------------------------------------
/app/modules/cs_common/filters/TimeAgoFilter.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'moment', '../module' ], function( ng, moment ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_common.filters' )
6 | .filter( 'timeAgo', [
7 | '$log',
8 | function( $log ) {
9 | return function( date ) {
10 | var dt = moment( date );
11 | if( !dt.isValid() ){
12 | $log.warn( 'timeAgoFilter: Invalid date input' );
13 | return date;
14 | }
15 |
16 | return dt.fromNow();
17 |
18 | };
19 | }
20 | ]);
21 |
22 | });
23 |
--------------------------------------------------------------------------------
/app/modules/cs_common/main.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'angular',
3 | 'ngCookies',
4 | 'ngResource',
5 | 'ngRoute',
6 | 'ngSanitize',
7 | 'cs_table',
8 |
9 | './module',
10 |
11 | // Providers
12 | './providers/HelpersProvider',
13 | './providers/TemplateProvider',
14 | './providers/HttpOptionsProvider',
15 | './providers/NavbarProvider',
16 | './providers/ResourceFactoryProvider',
17 |
18 | // Directives
19 | './directives/NgLoadDirective',
20 | './directives/ColorPickerDirective',
21 | './directives/FocusedOnDirective',
22 | './directives/LoadingDirective',
23 | './directives/MustBeEqualToDirective',
24 | './directives/NavbarDirective',
25 | './directives/NgBlurDirective',
26 | './directives/NgFocusDirective',
27 | './directives/StringToNumberDirective',
28 | './directives/WarnUnsavedChangesDirective',
29 |
30 | // Controllers
31 | './controllers/NavbarController',
32 |
33 | // Filters
34 | './filters/StartsWithFilter',
35 | './filters/TimeAgoFilter',
36 | './filters/CapitalizeFilter'
37 |
38 | ], function() {});
39 |
--------------------------------------------------------------------------------
/app/modules/cs_common/module.js:
--------------------------------------------------------------------------------
1 | define([ 'angular' ], function(ng) {
2 | 'use strict';
3 |
4 | ng.module('cs_common.providers', []);
5 | ng.module('cs_common.controllers', []);
6 | ng.module('cs_common.services', []);
7 | ng.module('cs_common.directives', []);
8 | ng.module('cs_common.filters', []);
9 |
10 | var module = ng.module('cs_common', [
11 | 'ngCookies',
12 | 'ngResource',
13 | 'ngRoute',
14 | 'ngSanitize',
15 | 'cs_table',
16 | 'http-auth-interceptor',
17 | 'cs_common.providers',
18 | 'cs_common.controllers',
19 | 'cs_common.services',
20 | 'cs_common.directives',
21 | 'cs_common.filters'
22 | ]);
23 |
24 | module.config(function($routeProvider, TemplateProvider) {
25 |
26 | TemplateProvider.setPath('/modules/:moduleName/views');
27 |
28 | $routeProvider
29 | .when('/error/page_not_found', {
30 | templateUrl: TemplateProvider.view('cs_common', 'page_not_found'),
31 | public: true
32 | })
33 | .when('/error', {
34 | templateUrl: TemplateProvider.view('cs_common', 'error'),
35 | public: true
36 | })
37 | .otherwise({
38 | redirectTo: '/error/page_not_found'
39 | });
40 |
41 | });
42 |
43 | return module;
44 | });
45 |
--------------------------------------------------------------------------------
/app/modules/cs_common/providers/HelpersProvider.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_common.providers' )
6 | .provider( 'Helpers', [
7 | function Helpers() {
8 |
9 | var helpers = {};
10 | var inheritedProviders = [];
11 |
12 | /**
13 | * @description
14 | * The actual service.
15 | */
16 | return {
17 | $get: [ '$injector', '$location', '$log',
18 | function( $injector, $location, $log ) {
19 |
20 | if ( inheritedProviders ) {
21 | inheritedProviders.forEach( function( inheritedProvider ) {
22 | var provider = $injector.get( inheritedProvider );
23 | if ( !provider ) {
24 | throw new Error( 'Unable to inject "' + inheritedProvider + '"' );
25 | }
26 | ng.extend( helpers, provider );
27 | });
28 | }
29 |
30 | if ( $injector.has( 'ModalFactory' ) ) {
31 | helpers.modal = $injector.get( 'ModalFactory' ).open;
32 | }
33 |
34 | helpers.hasError = function( $scope, fieldName, validation, validateOnSubmit ) {
35 | if ( !$scope.form ) {
36 | throw new Error( 'Expected $scope.form' );
37 | }
38 | var field = $scope.form[ fieldName ];
39 | if ( !field ) {
40 | throw new Error('Expected $scope.form to have a field \'' + fieldName + '\'');
41 | }
42 |
43 | if ( validateOnSubmit && !$scope.submitted ) {
44 | return false;
45 | }
46 |
47 | if ( validation ) {
48 | return ( field.$dirty && field.$error[ validation ] ) || ( $scope.submitted && field.$error[ validation ] );
49 | }
50 | return !!( ( field.$dirty && field.$invalid ) || ( $scope.submitted && field.$invalid ) );
51 | };
52 |
53 | helpers.isActive = function( path ) {
54 | var paths = path instanceof Array ? path : [ path ]
55 | , isActive = false;
56 |
57 | paths.every( function( _path ) {
58 | var regex = new RegExp( _path, 'ig' );
59 | if ( regex.test( $location.path() ) ) {
60 | isActive = true;
61 | return false;
62 | }
63 | return true;
64 | });
65 |
66 | return isActive;
67 | };
68 |
69 | helpers.redirect = function( path, $event ) {
70 | if ( $event ) {
71 | $event.stopPropagation();
72 | $event.preventDefault();
73 | }
74 |
75 | if ( !path ) {
76 | return $log.error( 'Path not provided' );
77 | }
78 |
79 | $location.url( path );
80 | return false;
81 | };
82 |
83 | return helpers;
84 |
85 | }
86 | ],
87 |
88 | /**
89 | * @ngdoc function
90 | * @methodOf ngSeed.providers:Helpers
91 | * @name setAccountService
92 | * @param {String} serviceName the account service name
93 | */
94 | extend: function( providerName ) {
95 | if ( typeof providerName !== 'string' ) {
96 | throw new Error( 'Helpers: extend method expects a string (name of the helpers provider)' );
97 | }
98 | inheritedProviders.push( providerName );
99 | }
100 |
101 | };
102 |
103 | }
104 |
105 | ]);
106 |
107 | });
108 |
--------------------------------------------------------------------------------
/app/modules/cs_common/providers/NavbarProvider.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'underscore', '../module' ], function( ng, _ ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_common.providers' )
6 | .provider( 'Navbar', [
7 | function () {
8 |
9 | var Navbar = {
10 | left: [],
11 | right: [],
12 | app: []
13 | };
14 |
15 | /**
16 | * @description
17 | * The actual service.
18 | */
19 | return {
20 | $get: [
21 | '$injector',
22 | function() {
23 | return {
24 | getNavbar: function() {
25 | return Navbar;
26 | }
27 | };
28 | }
29 | ],
30 |
31 | /**
32 | * @ngdoc function
33 | * @methodOf cleverStackNgSeed.providers:NavbarProvider
34 | * @name setTemplate
35 | * @param {String} theTemplate the template you want to use
36 | */
37 | setNavbar: function( navbar ) {
38 | Navbar = navbar;
39 | },
40 |
41 | getNavbar: function() {
42 | return Navbar;
43 | },
44 |
45 | extend: function( navbarItems ) {
46 | if ( !ng.isObject( navbarItems ) ) {
47 | throw new Error( 'NavbarProvider: extend method expects an object (your menu structure for your navbar)' );
48 | }
49 |
50 | Object.keys( navbarItems ).forEach( function( position ) {
51 | Navbar[ position ] = _.union( ( Navbar[ position ] || [] ), navbarItems[ position ] );
52 | });
53 | }
54 |
55 | };
56 |
57 | }
58 |
59 | ]);
60 |
61 | });
62 |
--------------------------------------------------------------------------------
/app/modules/cs_common/providers/ResourceFactoryProvider.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'underscore', 'inflection', '../module' ], function( ng, _, inflection ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_common.providers' )
6 | .provider( 'ResourceFactory', [
7 | function () {
8 |
9 | /**
10 | * @ngdoc service
11 | * @name ngSeed.services:$resourceFactory
12 | * @description
13 | * A service used to generate and register resources.
14 | */
15 |
16 | /**
17 | * @ngdoc function
18 | * @name ngSeed.services:ResourceFactory
19 | * @methodOf ngSeed.services:$resourceFactory
20 | * @param {String} resourceName The name of the resource.
21 | * @description
22 | * Generates a factory function that uses ngResource
23 | * to talk to a REST resource that can be directly used
24 | * with factory.
25 | *
26 | * Example of use with factory:
27 | * ```js
28 | * services
29 | * .factory('ResourceService', ResourceFactory('resource'));
30 | * ```
31 | */
32 | function ResourceFactory( resourceUrl, defaultParams, actions ) {
33 |
34 | /**
35 | * @ngdoc function
36 | * @name builder
37 | * @methodOf ngSeed.services:$resourceFactory
38 | * @description
39 | *
40 | * Generates an HTTP Resource.
41 | *
42 | * @param {$resource} $resource ngResource
43 | * @param {$httpOptions} $httpOptions The HTTP Options object.
44 | *
45 | * @return {resource} The actual resource for resourceName.
46 | */
47 | var builder = function ( $resource, HttpOptions ) {
48 | var singularUrl = HttpOptions.domain + inflection.singularize( resourceUrl ) + '/:id/:Action'
49 | , pluralUrl = HttpOptions.domain + inflection.pluralize( resourceUrl ) + '/:Action';
50 |
51 | actions = _.extend(
52 | {
53 | list: {
54 | method: 'GET',
55 | url: pluralUrl,
56 | isArray: true
57 | },
58 | get: {
59 | method: 'GET'
60 | },
61 | save: {
62 | method: 'PUT'
63 | },
64 | create: {
65 | method: 'POST'
66 | },
67 | destroy: {
68 | method: 'DELETE'
69 | }
70 | },
71 | actions
72 | );
73 |
74 | return $resource( singularUrl, defaultParams, actions );
75 | };
76 |
77 | return [ '$resource', 'HttpOptions', builder ];
78 | }
79 |
80 | /**
81 | * @description
82 | * The actual service.
83 | */
84 | return {
85 | $get: [
86 | '$injector',
87 | function( $injector ) {
88 | return function( resourceUrl, defaultParams, actions ) {
89 |
90 | // ng
91 | // .module( 'app.resources' )
92 | // .factory( resourceName, ResourceFactory( resourceName ) );
93 |
94 | return $injector.instantiate( new ResourceFactory( resourceUrl, defaultParams, actions ) );
95 | };
96 | }
97 | ]
98 | };
99 |
100 | }
101 |
102 | ]);
103 |
104 | });
105 |
--------------------------------------------------------------------------------
/app/modules/cs_common/views/error.html:
--------------------------------------------------------------------------------
1 |
Something went wrong :(
2 |
So you were redirected here.
3 |
4 |
5 |
6 |
7 |
... Sorry about that.
8 |
--------------------------------------------------------------------------------
/app/modules/cs_common/views/page_not_found.html:
--------------------------------------------------------------------------------
1 |
2 |
Page Not Found (404)
3 |
Whoops it looks like something went wrong during your request, please check the url and try again.
4 |
--------------------------------------------------------------------------------
/app/modules/cs_messenger/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "clever-messenger",
3 | "version": "0.1.0",
4 | "authors": [
5 | "Daniel Durante
"
6 | ],
7 | "description": "This module provides a service for creating alert messages.",
8 | "main": "main.js",
9 | "keywords": [
10 | "cleverstack",
11 | "clevertech",
12 | "cleverstack-module",
13 | "cleverstack-frontend"
14 | ],
15 | "license": "MIT",
16 | "homepage": "https://github.com/CleverStack/clever-messenger",
17 | "ignore": [
18 | "**/.*",
19 | "node_modules",
20 | "bower_components",
21 | "test",
22 | "tests"
23 | ],
24 | "rename": "cs_messenger"
25 | }
26 |
--------------------------------------------------------------------------------
/app/modules/cs_messenger/main.js:
--------------------------------------------------------------------------------
1 | define([
2 | './module',
3 |
4 | // Directives
5 | './scripts/messenger_directive',
6 |
7 | // Providers
8 | './scripts/messenger_provider'
9 | ], function() {});
10 |
--------------------------------------------------------------------------------
/app/modules/cs_messenger/module.js:
--------------------------------------------------------------------------------
1 | define(['angular'], function (ng) {
2 | 'use strict';
3 |
4 | ng.module('cs_messenger.directives', []);
5 | ng.module('cs_messenger.services', []);
6 |
7 | var module = ng.module('cs_messenger', [
8 | 'cs_common',
9 | 'cs_messenger.directives',
10 | 'cs_messenger.services'
11 | ]);
12 |
13 | return module;
14 | });
15 |
--------------------------------------------------------------------------------
/app/modules/cs_messenger/readme.md:
--------------------------------------------------------------------------------
1 | # Cleverstack Messenger module
2 |
3 | This module provides a service for creating alert messages.
4 |
5 | ## Setup
6 | 1. Add 'cs_messenger' to your app/modules/main.js file.
7 | It belongs in the `package` array at the top.
8 |
9 | 2. Add `cs_messenger` to your app/modules/application/main.js file.
10 | It belongs in the array of required modules.
11 |
12 | 3. Add `cs_messenger` to your app/modules/application/module.js file.
13 | `cs_messenger` belongs in your `app` module's array of required modules.
14 |
15 | ## Usage
16 | 1. In your controller, add `Messenger` to the controller's requires array.
17 |
18 | 2. In the template where you want to display the alerts (usually at the top of your app/index.html file) add a div with the messenger attribute `
`
19 |
20 | 3. In your controller, alerts can be displayed with the following code:
21 | `Messenger.error('An error has occured!');`
22 |
23 |
24 | ## Alert type
25 | In the example above, `error` is alert type and determines the alert's color.
26 |
27 | The valid types are:
28 | - error
29 | - warning
30 | - warn (alias of warning)
31 | - success
32 | - info
33 | - loading
34 | - loader (alias of loading)
35 |
36 | ## Dismissing an alert
37 | Aside from the loading alerts, alerts will disappear after 6 seconds by default. They can also be closed manually:
38 | `Messenger.close();`
39 |
40 | ## Messenger Options
41 | An options object can be passed as the 2nd argument of the Messenger alert functions to set the time to display the alert and whether there should be a close button.
42 | `Messenger.error('Error', { timeout: 3000, close: false })`
43 | - `timeout`: milliseconds until the alert should be hidden. 0 to not automatically hide the alert.
44 | - `close`: boolean for whether the alert should display a close button or not.
45 |
--------------------------------------------------------------------------------
/app/modules/cs_messenger/scripts/messenger_directive.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'underscore', '../module' ], function( ng, _ ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_messenger.directives' )
6 | .directive( 'messenger', function( $timeout, $log ) {
7 | return {
8 | templateUrl: '/modules/cs_messenger/views/messenger.html',
9 | link: function ($scope, element) {
10 |
11 | var alertClass, appMessage, alertType, icon, textWrapper, closeButton, closingPromise;
12 | var allowedTypes = ['warning', 'error', 'success', 'info', 'loading'];
13 | var defaultType = 'warning';
14 | var icons = {
15 | warn: 'icon-warning-sign',
16 | warning: 'icon-warning-sign',
17 | error: 'icon-exclamation-sign',
18 | success: 'icon-ok',
19 | info: 'icon-info-sign',
20 | loading: 'icon-loading'
21 | };
22 |
23 | $timeout(function() {
24 | appMessage = element.find('#app_message');
25 | alertType = appMessage.find('.alert');
26 | icon = appMessage.find('p i');
27 | textWrapper = appMessage.find('p span');
28 | closeButton = appMessage.find('button.close');
29 |
30 | appMessage.hide();
31 | });
32 |
33 | $scope.$on('messenger:newMessage', function(event, data) {
34 | $timeout.cancel(closingPromise);
35 | $scope.message = data.message;
36 | $scope.type = data.type;
37 |
38 | if (_($scope.message).isEmpty() || $scope.type === 'close') {
39 | appMessage.hide();
40 | return;
41 | }
42 |
43 | if (!_(allowedTypes).contains($scope.type)) {
44 | $scope.type = defaultType;
45 | }
46 |
47 | alertClass = $scope.type === 'loading' ? 'info' : $scope.type;
48 | alertClass = $scope.type === 'error' ? 'danger' : $scope.type;
49 |
50 | $scope.opts = data.opts;
51 | if ($scope.type === 'loading') {
52 | $scope.opts = {
53 | timeout: false,
54 | close: false
55 | };
56 | }
57 |
58 | showMessage();
59 |
60 | });
61 |
62 | function showMessage() {
63 | if( _( $scope.message ).isUndefined() || _( $scope.message ).isEmpty() ) {
64 | $log.warn( 'Empty message received' );
65 | return;
66 | }
67 |
68 | alertType.removeClass();
69 | alertType.addClass('alert');
70 | alertType.addClass('alert-' + alertClass);
71 |
72 | icon.removeClass();
73 | icon.addClass('pull-left');
74 | if ($scope.type === 'loading') {
75 | icon.addClass('icon-loading');
76 | } else {
77 | icon.addClass(icons[$scope.type]);
78 | }
79 |
80 | textWrapper.html($scope.message);
81 |
82 | if ($scope.opts.close) {
83 | closeButton
84 | .unbind()
85 | .show()
86 | .click($scope.closeMessage);
87 | } else {
88 | closeButton
89 | .unbind()
90 | .hide();
91 | }
92 |
93 | appMessage.show();
94 |
95 | if ($scope.opts.timeout) {
96 | closingPromise = $timeout(function() {
97 | appMessage.animate({height: 0, opacity: 0}, 1000, function() {
98 | appMessage
99 | .hide()
100 | .css({opacity:1, height: 'auto'});
101 | });
102 | }, $scope.opts.timeout, false);
103 | }
104 | }
105 |
106 | $scope.closeMessage = function() {
107 | appMessage.hide();
108 | };
109 |
110 | }
111 | };
112 | });
113 |
114 | });
115 |
--------------------------------------------------------------------------------
/app/modules/cs_messenger/scripts/messenger_provider.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'cs_messenger.services' )
6 | .factory( 'Messenger',
7 | [
8 | '$rootScope',
9 | function( $rootScope ) {
10 | var mService = {};
11 | var defaultOpts = {
12 | timeout: 6000, // mixed (miliseconds or false for no timeout)
13 | close: true // boolean - whether the message should have a close button
14 | };
15 |
16 | var notify = function( message, type, opts ){
17 | opts = opts ? ng.extend( ng.copy( defaultOpts ), opts ) : ng.copy( defaultOpts );
18 | $rootScope.$broadcast( 'messenger:newMessage', { type: type, message: message, opts: opts } );
19 | };
20 |
21 | mService.error = function( msg, opts ){ return notify(msg, 'error', opts); };
22 | mService.warning = function( msg, opts ){ return notify(msg, 'warning', opts); };
23 | mService.warn = mService.warning;
24 | mService.success = function( msg, opts ){ return notify(msg, 'success', opts); };
25 | mService.info = function( msg, opts ){ return notify(msg, 'info', opts); };
26 | mService.loading = function( msg, opts ){ return notify(msg, 'loading', opts); };
27 | mService.loader = mService.load = mService.loading;
28 | mService.close = function(){ return notify( '', 'close' ); };
29 |
30 | return mService;
31 | }
32 | ]
33 | );
34 |
35 | });
36 |
--------------------------------------------------------------------------------
/app/modules/cs_messenger/views/messenger.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
×
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/modules/cs_modal/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "clever-modal",
3 | "version": "0.1.0",
4 | "authors": [
5 | "Daniel Durante "
6 | ],
7 | "description": "This module will provides a factory for making modals.",
8 | "main": "main.js",
9 | "keywords": [
10 | "cleverstack",
11 | "clevertech",
12 | "cleverstack-module",
13 | "cleverstack-frontend"
14 | ],
15 | "license": "MIT",
16 | "homepage": "https://github.com/CleverStack/clever-modal",
17 | "ignore": [
18 | "**/.*",
19 | "node_modules",
20 | "bower_components",
21 | "test",
22 | "tests"
23 | ],
24 | "rename": "cs_modal",
25 | "resolutions": {
26 | "angular": ">=1.2.0-rc.2"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/modules/cs_modal/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file This is a require.js main.js file, use it to specify all the javascript files you need for your module.
3 | */
4 | define([
5 | './module',
6 |
7 | // Services
8 | './scripts/cs_modal_factory'
9 |
10 | ], function() {});
11 |
--------------------------------------------------------------------------------
/app/modules/cs_modal/module.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Instantiates and configures angular modules for your module.
3 | */
4 | define(['angular'], function (ng) {
5 | 'use strict';
6 |
7 | ng.module('cs_modal.services', []);
8 |
9 | var module = ng.module('cs_modal', [
10 | 'cs_common',
11 | 'cs_modal.services',
12 | 'ui.bootstrap'
13 | ]);
14 |
15 | module.config( [ '$provide', function( $provide ) {
16 | $provide.decorator('modalBackdropDirective', [ '$delegate', function( $delegate ) {
17 | $delegate[0].templateUrl = ['modules/cs_modal/views/', $delegate[0].name, '.html'].join('');
18 | return $delegate;
19 | }]);
20 |
21 | $provide.decorator('modalWindowDirective', [ '$delegate', function( $delegate ) {
22 | $delegate[0].templateUrl = ['modules/cs_modal/views/', $delegate[0].name, '.html'].join('');
23 | return $delegate;
24 | }]);
25 | }]);
26 |
27 | return module;
28 | });
29 |
--------------------------------------------------------------------------------
/app/modules/cs_modal/readme.md:
--------------------------------------------------------------------------------
1 | # Cleverstack Modal module
2 |
3 | This module will provides a factory for making modals.
4 |
5 | ## Setup
6 | Modals are created via the modal directive provided by the angular-bootstrap package, so this will need to be installed before you can start making modals.
7 |
8 | ### Setting up angular-bootstrap
9 | 1. Add angular-bootstrap to your bower.json.
10 |
11 | 2. run `bower install`
12 |
13 | 3. Add bootstrap to your app/modules/main.js file.
14 | - The path to the ui-bootstrap.js needs to be added to the paths object.
15 | - A shim needs to be added to the shim object for `ui-bootstrap` with a dependency on angular.
16 | - Lastly, ui-bootstrap needs to be added to the required array at the bottom.
17 |
18 | 4. Add `ui-bootstrap` to your app/modules/application/main.js file.
19 | It belongs in the array of required modules.
20 |
21 | 5. Add ui-bootstrap to your app/modules/application/module.js file.
22 | `'ui.bootstrap'` belongs in your `app` module's array of required modules.
23 |
24 | ### Setting up Cleverstack modal
25 | 1. Add 'cs_modal' to your app/modules/main.js file.
26 | It belongs in the `package` array at the top.
27 |
28 | 2. Add `cs_modal` to your app/modules/application/main.js file.
29 | It belongs in the array of required modules.
30 |
31 | 3. Add cs_modal to your app/modules/application/module.js file.
32 | `'cs_modal'` belongs in your `app` module's array of required modules.
33 |
--------------------------------------------------------------------------------
/app/modules/cs_modal/styles/modals.less:
--------------------------------------------------------------------------------
1 | @import "./../../../styles/less/bootstrap/variables.less";
2 | @import "./../../../styles/less/bootstrap/mixins.less";
3 |
4 | // ----------------------------------------------------------
5 | // Modal Custom Styling
6 | // ----------------------------------------------------------
7 |
8 | .modal {
9 | .modal-header { background:#343844 url('../images/modal-header-bg.png') left top repeat-x; color:#FFF;
10 | .close { color:#FFF; }
11 | }
12 | .modal-body { border-left: 7px solid #8cc63f;
13 | .container { width: 560px; }
14 | }
15 | .modal-helpertext { background:#EFEFF1; border-left:@trim-border; padding:20px 20px 20px 30px; font-size:12px; }
16 | }
17 | .modal-backdrop { #gradient > .radial(#FFF, #343743);
18 | &.in { opacity:0.6; }
19 | }
20 |
21 |
22 | /* Desktop @1200px
23 | ────────────────────────────────────────────────────────────*/
24 | @media ( max-width : @screen-lg ) {
25 |
26 | }
27 |
28 | /* Desktop @992px
29 | ────────────────────────────────────────────────────────────*/
30 | @media ( min-width: ( @screen-sm + 1 ) ) and ( max-width: @screen-md ) {
31 |
32 | }
33 |
34 | /* Mobile @768px
35 | ────────────────────────────────────────────────────────────*/
36 | @media ( min-width: ( @screen-xs + 1 ) ) and ( max-width: @screen-sm ) {
37 | .modal {
38 | .modal-body {
39 | .container {
40 | width: auto;
41 | }
42 | }
43 | }
44 | }
45 |
46 | /* Mobile @480px
47 | ────────────────────────────────────────────────────────────*/
48 | @media ( max-width : @screen-xs ) {
49 | .modal {
50 | .modal-body {
51 | .container {
52 | width: auto;
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/modules/cs_modal/views/confirmModal.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
{{warning.title}}
10 |
{{warning.message}}
11 |
12 |
13 |
41 |
--------------------------------------------------------------------------------
/app/modules/cs_modal/views/modalBackdrop.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/modules/cs_modal/views/modalWindow.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/modules/cs_table/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 CleverStack
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/app/modules/cs_table/README.md:
--------------------------------------------------------------------------------
1 | CleverStack Table Module
2 | ====================
3 | [](http://badge.fury.io/js/clever-table) [](http://badge.fury.io/gh/cleverstack%2Fclever-table) [](https://david-dm.org/CleverStack/clever-table) [](https://david-dm.org/CleverStack/clever-table#info=devDependencies) [](https://codeclimate.com/github/CleverStack/clever-table)
4 | [](https://travis-ci.org/CleverStack/clever-table)
5 | [](https://codeclimate.com/github/CleverStack/clever-table) [](https://www.npmjs.org/package/clever-table)
6 | [](http://gruntjs.com/)
7 |
8 | 
9 |
10 | This module provides an easy to use, extensible and responsive table solution for your application. (Based on the popular ngTable)
11 |
12 |
13 | ## Documentation
14 |
15 | See [cleverstack.io](http://cleverstack.io/documentation/#frontend) for more detailed information on the Angular seed or visit the [Getting Started Guide](http://cleverstack.io/getting-started/). For more information about using clever-table (and the angular-seed in general) please see the [Frontend](http://cleverstack.io/documentation/frontend) Documentation.
16 |
17 | ## Install
18 | 1. From your project folder run `clever install clever-table`
19 |
--------------------------------------------------------------------------------
/app/modules/cs_table/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "clever-table",
3 | "version": "1.0.0",
4 | "authors": [
5 | "Richard Gustin "
6 | ],
7 | "description": "This module provides an easy to use, extensible and responsive table solution for your application. (Based on the popular ngTable)",
8 | "main": "main.js",
9 | "dependencies": {
10 | "ng-table": "~0.3.3",
11 | "ng-table-resizable-columns": "https://github.com/esvit/ng-table-resizable-columns.git"
12 | },
13 | "keywords": [
14 | "table",
15 | "ngTable",
16 | "tables",
17 | "responsive",
18 | "cleverstack",
19 | "cleverstack-module",
20 | "cleverstack-frontend"
21 | ],
22 | "license": "MIT",
23 | "homepage": "https://github.com/CleverStack/clever-table",
24 | "ignore": [
25 | "**/.*",
26 | "node_modules",
27 | "bower_components",
28 | "test",
29 | "tests"
30 | ],
31 | "rename": "cs_table",
32 | "resolutions": {
33 | "angular": ">=1.2.0-rc.2"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/modules/cs_table/directives/CleverTableDirective.js:
--------------------------------------------------------------------------------
1 | define(['angular', '../module'], function(ng) {
2 | ng
3 | .module('cs_table.directives')
4 | .directive('cleverTable', function($timeout) {
5 | var directive = {};
6 |
7 | directive.scope = true;
8 | directive.restrict = 'A';
9 | directive.controller = 'CleverTableController';
10 | directive.templateUrl = '/modules/cs_table/views/table.html';
11 |
12 | directive.link = function(elem, attrs, transclude) {
13 | $timeout(function() {
14 | ng.element(window).trigger('resize');
15 | }, 0);
16 | };
17 |
18 | return directive;
19 | });
20 |
21 | });
22 |
--------------------------------------------------------------------------------
/app/modules/cs_table/main.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'angular',
3 | 'ngSanitize',
4 |
5 | 'ngTable',
6 | 'ngTableResizableColumns',
7 | 'selectn',
8 |
9 | './module',
10 |
11 | './directives/CleverTableDirective',
12 |
13 | './controllers/CleverTableController'
14 |
15 | ], function() {});
16 |
--------------------------------------------------------------------------------
/app/modules/cs_table/module.js:
--------------------------------------------------------------------------------
1 | define(['angular'], function(ng) {
2 | 'use strict';
3 |
4 | ng.module('cs_table.controllers', []);
5 | ng.module('cs_table.directives', []);
6 |
7 | var module = ng.module('cs_table', [
8 | 'ngSanitize',
9 | 'ui',
10 | 'ui.bootstrap',
11 | 'ngTable',
12 | 'ngTableResizableColumns',
13 | 'cs_table.controllers',
14 | 'cs_table.directives'
15 | ]);
16 |
17 | return module;
18 | });
19 |
--------------------------------------------------------------------------------
/app/modules/cs_table/styles/tables.less:
--------------------------------------------------------------------------------
1 | @import "./../../../styles/less/bootstrap/variables.less";
2 | @import "./../../../styles/less/bootstrap/mixins.less";
3 |
4 | .content {
5 | .table-responsive {
6 | width : 100%;
7 | font-size : @font-size-base;
8 | overflow-y : visible;
9 |
10 | .btn {
11 | .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base);
12 | }
13 |
14 | .btn-toolbar {
15 | min-width : 190px;
16 |
17 | .btn-group {
18 | float : initial;
19 | }
20 | }
21 |
22 | table {
23 | margin : 0;
24 | }
25 |
26 | .pagination {
27 | margin : 0;
28 | }
29 |
30 | .rc-handle-container {
31 | position: relative;
32 | }
33 | .rc-handle {
34 | position: absolute;
35 | width: 7px;
36 | cursor: ew-resize;
37 | margin-left: -3px;
38 | z-index: 2;
39 | }
40 | table.rc-table-resizing {
41 | cursor: ew-resize;
42 | }
43 | table.rc-table-resizing thead,
44 | table.rc-table-resizing thead > th,
45 | table.rc-table-resizing thead > th > a {
46 | cursor: ew-resize;
47 | }
48 | ul.dropdown-menu-form {
49 | padding: 5px 10px 0;
50 | max-height: 300px;
51 | overflow-y: scroll;
52 | }
53 | }
54 | }
55 |
56 | /* Mobile @1200px
57 | ────────────────────────────────────────────────────────────*/
58 | @media (max-width: @screen-lg) {
59 | .content {
60 | .table-responsive {
61 | table {
62 |
63 | }
64 | }
65 | }
66 | }
67 |
68 | /* Desktop @992px
69 | ────────────────────────────────────────────────────────────*/
70 | @media (min-width: (@screen-sm + 1)) and (max-width: @screen-md) {
71 | .content {
72 | .table-responsive {
73 | font-size : @font-size-small;
74 |
75 | .btn {
76 | .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);
77 | }
78 |
79 | .btn-toolbar {
80 | min-width : 170px;
81 | }
82 |
83 | table {
84 |
85 | }
86 | }
87 | }
88 | }
89 |
90 | /* Mobile @768px
91 | ────────────────────────────────────────────────────────────*/
92 | @media (min-width: (@screen-xs + 1)) and (max-width: @screen-sm) {
93 | .content {
94 | .table-responsive {
95 | font-size : 10px;
96 |
97 | .btn {
98 | .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);
99 | }
100 |
101 | .btn-toolbar {
102 | min-width : 140px;
103 | }
104 |
105 | table {
106 | button b span {
107 | display : none;
108 | }
109 | }
110 | }
111 | }
112 | }
113 |
114 | /* Mobile @480px
115 | ────────────────────────────────────────────────────────────*/
116 | @media (max-width: @screen-xs) {
117 | .content {
118 | .table-responsive {
119 | padding : 0;
120 | margin : 0;
121 | font-size : 9px;
122 |
123 | .btn {
124 | .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);
125 | }
126 |
127 | .btn-toolbar {
128 | min-width : 95px;
129 | }
130 |
131 | table {
132 | button b span {
133 | display : none;
134 | }
135 | }
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/app/modules/cs_table/views/filter/select2.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 | {{row[column.name]}}
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/modules/cs_table/views/filter/text.html:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/modules/cs_table/views/partials/filters.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
--------------------------------------------------------------------------------
/app/modules/cs_table/views/partials/header.html:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | {{column.title}}
11 |
12 |
13 |
14 |
15 | Actions
16 |
17 |
63 |
--------------------------------------------------------------------------------
/app/modules/cs_table/views/partials/pager.html:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/app/modules/cs_table/views/partials/row.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 | {{ outputRow( row, column.name ) }}
12 |
13 |
14 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/app/modules/cs_table/views/partials/toolbar.html:
--------------------------------------------------------------------------------
1 |
55 |
--------------------------------------------------------------------------------
/app/modules/cs_table/views/table.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/modules/main.js:
--------------------------------------------------------------------------------
1 | require.config({
2 | baseUrl: 'modules',
3 | packages: [
4 | 'app',
5 | 'cs_common',
6 | 'cs_table',
7 | 'cs_modal',
8 | 'cs_messenger',
9 | 'cs_accounts',
10 | 'auth',
11 | 'roles'
12 | ],
13 | paths: {
14 | angular: '../components/angular/angular',
15 | ngCookies: '../components/angular-cookies/angular-cookies',
16 | ngResource: '../components/angular-resource/angular-resource',
17 | ngRoute: '../components/angular-route/angular-route',
18 | ngSanitize: '../components/angular-sanitize/angular-sanitize',
19 | ngTable: '../components/ng-table/ng-table',
20 | ngTableResizableColumns: '../components/ng-table-resizable-columns/ng-table-resizable-columns.src',
21 | ngUi: '../components/angular-ui/build/angular-ui',
22 | ngUiBootstrap: '../components/angular-bootstrap/ui-bootstrap-tpls',
23 | httpAuthInterceptor: '../components/angular-http-auth/src/http-auth-interceptor',
24 | bootstrap: '../scripts/bootstrap',
25 | jquery: '../components/jquery/dist/jquery',
26 | jqueryMinicolors: '../components/jquery-minicolors/jquery.minicolors',
27 | underscore: '../components/underscore/underscore',
28 | selectn: '../components/selectn/selectn',
29 | inflection: '../components/inflection/lib/inflection',
30 | select2: '../components/select2/select2',
31 | 'ui.select2': '../components/angular-ui-select2/src/select2',
32 | moment: '../components/momentjs/moment'
33 | },
34 | shim: {
35 | angular: {
36 | deps: [ 'jquery' ],
37 | exports: 'angular'
38 | },
39 | ngCookies: {
40 | deps: [ 'angular' ]
41 | },
42 | ngResource: {
43 | deps: [ 'angular' ]
44 | },
45 | ngRoute: {
46 | deps: [ 'angular' ]
47 | },
48 | ngSanitize: {
49 | deps: [ 'angular' ]
50 | },
51 | ngTable: {
52 | deps: [ 'angular' ],
53 | exports: 'ngTable'
54 | },
55 | ngTableResizableColumns: {
56 | deps: [ 'angular' ],
57 | exports: 'ngTableResizableColumns'
58 | },
59 | ngUi: {
60 | deps: [ 'angular' ]
61 | },
62 | ngUiBootstrap: {
63 | deps: [ 'angular' ]
64 | },
65 | httpAuthInterceptor: {
66 | deps: [ 'angular' ]
67 | },
68 | bootstrap: {
69 | deps: [ 'jquery' ]
70 | },
71 | underscore: {
72 | exports: '_'
73 | },
74 | selectn: {
75 | deps: [ 'bootstrap' ]
76 | },
77 | inflection: {
78 | exports: 'inflection'
79 | },
80 | select2: {
81 | deps: [ 'jquery' ]
82 | },
83 | 'ui.select2': {
84 | deps: [ 'angular', 'select2' ]
85 | },
86 | moment: {
87 | exports: 'moment'
88 | },
89 | jqueryMinicolors: {
90 | deps: [ 'jquery' ]
91 | }
92 | },
93 | waitSeconds: 15
94 | });
95 |
96 | require([
97 | 'angular',
98 | 'bootstrap',
99 | 'ngUi',
100 | 'ngUiBootstrap',
101 | 'ngRoute',
102 | 'ngResource',
103 | 'ngSanitize',
104 | 'ngTable',
105 | 'ngTableResizableColumns',
106 | 'httpAuthInterceptor',
107 |
108 | 'ui.select2',
109 | 'selectn',
110 | 'inflection',
111 |
112 | // CleverStack modules
113 | 'cs_common',
114 | 'cs_table',
115 | 'cs_modal',
116 | 'cs_messenger',
117 | 'auth',
118 | 'roles',
119 | 'cs_accounts',
120 |
121 | // Main app module
122 | 'app',
123 |
124 | // Custom modules
125 |
126 |
127 | ], function(angular) {
128 | 'use strict';
129 |
130 | angular.element(document).ready(function() {
131 | angular.bootstrap(document, ['app']);
132 | });
133 | });
134 |
--------------------------------------------------------------------------------
/app/modules/roles/controllers/PermissionEditController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'underscore', '../module' ], function( ng, underscore ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'roles.controllers' )
6 | .controller( 'PermissionEditController', function( $rootScope, $scope, $injector, $modalInstance, Helpers, PermissionService, permission, roles ) {
7 | var Messenger = $injector.has( 'Messenger' ) ? $injector.get( 'Messenger' ) : $injector.get( '$log' );
8 |
9 | $scope.helpers = Helpers;
10 | $scope.roles = roles;
11 | $scope.permission = permission;
12 |
13 |
14 | $scope.save = function() {
15 | var promise;
16 |
17 | if ( this.form && this.form.$invalid ) {
18 | return Messenger.warn( 'Please fix the form errors highlighted red and try again.' );
19 | }
20 |
21 | $scope.permission.Roles = underscore.map($scope.permission.Roles, function(role) {
22 | return parseInt(role, 10);
23 | });
24 |
25 | if ( !!$scope.permission.id ) {
26 | promise = $scope.permission.$save();
27 | } else {
28 | promise = PermissionService.create( $scope.permission );
29 | }
30 |
31 | promise
32 | .then( function() {
33 | $rootScope.$broadcast( 'table:reload' );
34 | Messenger.success( 'Permission ' + $scope.permission.action + ' successfully ' + ( !!$scope.permission.id ? 'updated.' : 'created.' ) );
35 | $modalInstance.close( $scope );
36 | })
37 | .catch( function( err ) {
38 | Messenger.error( 'Unable to ' + ( !!$scope.permission.id ? 'update' : 'create' ) + ' permission ' + $scope.permission.action + ' due to error (' + (err.message || err) + ')' );
39 | });
40 | };
41 |
42 | $scope.cancel = function () {
43 | if ( $scope.permission && typeof $scope.permission.$get === 'function' ) {
44 | $scope.permission.$get();
45 | }
46 | $modalInstance.dismiss( 'cancel' );
47 | };
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/app/modules/roles/controllers/PermissionListController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'roles.controllers' )
6 | .controller( 'PermissionListController', function( $scope, Helpers ) {
7 | $scope.welcome = 'Viewing all Permissions available in your account, you can define your own custom ones by clicking the "Add Permission" Button.';
8 | $scope.helpers = Helpers;
9 | $scope.sorting = {
10 | id: 'asc'
11 | };
12 | $scope.columns = [
13 | {
14 | name : 'id',
15 | title : 'ID',
16 | glyph : 'slack',
17 | filter : true,
18 | filterType : 'text',
19 | sortable : true,
20 | visible : true
21 | },
22 | {
23 | name : 'action',
24 | title : 'Action Name',
25 | glyph : 'user',
26 | filter : true,
27 | filterType : 'text',
28 | sortable : true,
29 | visible : true
30 | },
31 | {
32 | name : 'description',
33 | title : 'Description',
34 | glyph : 'list',
35 | filter : true,
36 | filterType : 'text',
37 | sortable : true,
38 | visible : true
39 | }
40 | ];
41 | $scope.actionsTemplate = '/modules/roles/views/permission/tableActions.html';
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/app/modules/roles/controllers/RoleEditController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'underscore', '../module' ], function( ng, underscore ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'roles.controllers' )
6 | .controller( 'RoleEditController', function( $rootScope, $scope, $injector, $modalInstance, Helpers, RoleService, role, users, permissions ) {
7 | var Messenger = $injector.has( 'Messenger' ) ? $injector.get( 'Messenger' ) : $injector.get( '$log' );
8 |
9 | $scope.helpers = Helpers;
10 | $scope.role = role;
11 | $scope.users = users;
12 | $scope.permissions = permissions;
13 |
14 | $scope.save = function() {
15 | var promise;
16 |
17 | if ( this.form && this.form.$invalid ) {
18 | return Messenger.warn( 'Please fix the form errors highlighted red and try again.' );
19 | }
20 |
21 | $scope.role.Permissions = underscore.map($scope.role.Permissions, function(permission) {
22 | return parseInt(permission, 10);
23 | });
24 |
25 | $scope.role.Users = underscore.map($scope.role.Users, function(user) {
26 | return parseInt(user, 10);
27 | });
28 |
29 | if ( !!$scope.role.id ) {
30 | promise = $scope.role.$save();
31 | } else {
32 | promise = RoleService.create( $scope.role );
33 | }
34 |
35 | promise
36 | .then( function() {
37 | $rootScope.$broadcast( 'table:reload' );
38 | Messenger.success( 'Role ' + $scope.role.name + ' successfully ' + ( !!$scope.role.id ? 'updated.' : 'created.' ) );
39 | $modalInstance.close( $scope );
40 | })
41 | .catch( function( err ) {
42 | Messenger.error( 'Unable to ' + ( !!$scope.role.id ? 'update' : 'create' ) + ' role ' + $scope.role.name + ' due to error (' + (err.message || err) + ')' );
43 | });
44 | };
45 |
46 | $scope.cancel = function () {
47 | if ( $scope.role && typeof $scope.role.$get === 'function' ) {
48 | $scope.role.$get();
49 | }
50 | $modalInstance.dismiss( 'cancel' );
51 | };
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/app/modules/roles/controllers/RoleListController.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', '../module' ], function( ng ) {
2 | 'use strict';
3 |
4 | ng
5 | .module( 'roles.controllers' )
6 | .controller( 'RoleListController', function( $scope, Helpers ) {
7 | $scope.welcome = 'This page lists all of the Roles available in your account, you can add as many as you want';
8 | $scope.helpers = Helpers;
9 | $scope.sorting = {
10 | id: 'asc'
11 | };
12 | $scope.actionsTemplate = '/modules/roles/views/role/tableActions.html';
13 |
14 | $scope.columns = [
15 | {
16 | name : 'id',
17 | title : 'ID',
18 | glyph : 'slack',
19 | filter : true,
20 | filterType : 'text',
21 | sortable : true,
22 | visible : true
23 | },
24 | {
25 | name : 'name',
26 | title : 'Name',
27 | glyph : 'user',
28 | filter : true,
29 | filterType : 'text',
30 | sortable : true,
31 | visible : true
32 | },
33 | {
34 | name : 'description',
35 | title : 'Description',
36 | glyph : 'list',
37 | filter : true,
38 | filterType : 'text',
39 | sortable : true,
40 | visible : true
41 | }
42 | ];
43 |
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/app/modules/roles/main.js:
--------------------------------------------------------------------------------
1 | define([
2 | './module',
3 |
4 | // Providers
5 | './providers/RoleHelpersProvider',
6 |
7 | // Controllers
8 | './controllers/RoleListController',
9 | './controllers/RoleEditController',
10 | './controllers/PermissionListController',
11 | './controllers/PermissionEditController',
12 |
13 |
14 | // Directives
15 |
16 | // Models
17 | './models/RoleModel',
18 | './models/PermissionModel',
19 |
20 | // Services
21 | './services/RoleService',
22 | './services/PermissionService'
23 | ], function() {});
24 |
--------------------------------------------------------------------------------
/app/modules/roles/models/PermissionModel.js:
--------------------------------------------------------------------------------
1 | define(['angular', '../module'], function(ng) {
2 | 'use strict';
3 |
4 | ng
5 | .module('roles.models')
6 | .factory('PermissionModel', function($rootScope, Session, ResourceFactory) {
7 | var defaultParams = {
8 | id: '@id'
9 | };
10 |
11 | $rootScope.$watch(Session.getCurrentUser, function(user) {
12 | defaultParams.AccountId = user ? user.Account.id : null;
13 | });
14 |
15 | return new ResourceFactory('/account/:AccountId/permissions', defaultParams, {});
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/app/modules/roles/models/RoleModel.js:
--------------------------------------------------------------------------------
1 | define(['angular', '../module'], function(ng) {
2 | 'use strict';
3 |
4 | ng
5 | .module('roles.models')
6 | .factory('RoleModel', function($rootScope, Session, ResourceFactory) {
7 | var defaultParams = {
8 | id: '@id'
9 | };
10 |
11 | $rootScope.$watch(Session.getCurrentUser, function(user) {
12 | defaultParams.AccountId = user ? user.Account.id : null;
13 | });
14 |
15 | return new ResourceFactory('/account/:AccountId/roles', defaultParams, {});
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/app/modules/roles/module.js:
--------------------------------------------------------------------------------
1 | define( [ 'angular', 'underscore' ], function( ng, _ ) {
2 | 'use strict';
3 |
4 | ng.module( 'roles.providers', [] );
5 | ng.module( 'roles.controllers', [] );
6 | ng.module( 'roles.models', [] );
7 | ng.module( 'roles.services', [] );
8 | ng.module( 'roles.directives', [] );
9 | ng.module( 'roles.filters', [] );
10 |
11 | var module = ng.module( 'roles', [
12 | 'cs_common',
13 | 'cs_messenger',
14 | 'cs_modal',
15 | 'cs_table',
16 | 'auth',
17 | 'ui.bootstrap',
18 | 'ui',
19 | 'roles.providers',
20 | 'roles.controllers',
21 | 'roles.models',
22 | 'roles.services',
23 | 'roles.directives',
24 | 'roles.filters'
25 | ]);
26 |
27 | module.config( function( $routeProvider, TemplateProvider, HelpersProvider, NavbarProvider ) {
28 | var settingsMenu;
29 |
30 | // Create helpers for this module
31 | HelpersProvider.extend( 'RoleHelpers' );
32 |
33 | // Define menu structure for this module
34 | if ( ( settingsMenu = _.findWhere( NavbarProvider.getNavbar().right, { label: 'Settings' } ) ) !== undefined ) {
35 | settingsMenu.subMenu.push({
36 | label : 'Roles',
37 | href : '/settings/roles',
38 | class : 'fa-group',
39 | requiresSignIn : true,
40 | order : 5,
41 | requiresPermission : 'Role.list'
42 | });
43 |
44 | settingsMenu.subMenu.push({
45 | label : 'Permissions',
46 | href : '/settings/permissions',
47 | class : 'fa-legal',
48 | requiresSignIn : true,
49 | order : 6,
50 | requiresPermission : 'Permission.list'
51 | });
52 | }
53 |
54 | // Define routes provided by this module
55 | $routeProvider
56 | .when( '/settings/roles', {
57 | templateUrl : TemplateProvider.view( 'roles', 'role/list' ),
58 | controller : 'RoleListController',
59 | public : false,
60 | requiresPermission : 'Role.list'
61 | })
62 | .when( '/settings/role/:id', {
63 | templateUrl : TemplateProvider.view( 'roles', 'role/form' ),
64 | controller : 'RoleEditController',
65 | public : false,
66 | requiresPermission : 'Role.edit'
67 | })
68 | .when( '/settings/permissions', {
69 | templateUrl : TemplateProvider.view( 'roles', 'permission/list' ),
70 | controller : 'PermissionListController',
71 | public : false,
72 | requiresPermission : 'Permission.list'
73 | })
74 | .when( '/settings/permission/:id', {
75 | templateUrl : TemplateProvider.view( 'roles', 'permission/form' ),
76 | controller : 'PermissionEditController',
77 | public : false,
78 | requiresPermission : 'Permission.edit'
79 | });
80 | });
81 |
82 | return module;
83 | });
84 |
--------------------------------------------------------------------------------
/app/modules/roles/services/PermissionService.js:
--------------------------------------------------------------------------------
1 | define(['angular', '../module'], function(ng) {
2 | 'use strict';
3 |
4 | ng
5 | .module('roles.services')
6 | .factory('PermissionService', function(PermissionModel) {
7 | var PermissionService = {
8 |
9 | model: PermissionModel,
10 |
11 | data: null,
12 |
13 | list: function(findOptions) {
14 | return PermissionModel.list(findOptions).$promise.then(function(permissions) {
15 | PermissionService.data = permissions;
16 | return PermissionService.data;
17 | });
18 | },
19 |
20 | get: function(findOptions) {
21 | return PermissionModel.get(findOptions).$promise;
22 | },
23 |
24 | create: function(data) {
25 | return PermissionModel.create(data).$promise;
26 | }
27 | };
28 |
29 | return PermissionService;
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/app/modules/roles/services/RoleService.js:
--------------------------------------------------------------------------------
1 | define(['angular', '../module'], function(ng) {
2 | 'use strict';
3 |
4 | ng
5 | .module('roles.services')
6 | .factory('RoleService', function(RoleModel) {
7 | var RoleService = {
8 |
9 | model: RoleModel,
10 |
11 | data: null,
12 |
13 | list: function(findOptions) {
14 | return RoleModel.list(findOptions).$promise.then(function(roles) {
15 | RoleService.data = roles;
16 | return RoleService.data;
17 | });
18 | },
19 |
20 | get: function(findOptions) {
21 | return RoleModel.get(findOptions).$promise;
22 | },
23 |
24 | create: function(data) {
25 | return RoleModel.create(data).$promise;
26 | }
27 | };
28 |
29 | return RoleService;
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/app/modules/roles/views/permission/form.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
Create a new permission for the current account
9 |
{{permission.name}}
10 |
Tip: Exercise caution when assigning a role permissions, as any role that has been assigned Role.* rights can also add and remove other users.
11 |
12 |
13 |
86 |
--------------------------------------------------------------------------------
/app/modules/roles/views/permission/list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 | Create Permission
12 |
13 |
14 |
Permission List
15 | {{welcome}}
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/modules/roles/views/permission/tableActions.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | Edit
10 |
11 |
12 |
17 |
18 |
19 | Delete
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/modules/roles/views/role/list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 | Create Role
12 |
13 |
14 |
Role List
15 | {{welcome}}
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/modules/roles/views/role/tableActions.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | Edit
10 |
11 |
12 |
17 |
18 |
19 | Delete
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/styles/less/application.less:
--------------------------------------------------------------------------------
1 |
2 | /* Bootstrap Theme
3 | ────────────────────────────────────────────────────────────*/
4 | @import "bootstrap/theme.less";
5 | @import "bootstrap/variables.less";
6 |
7 |
8 | /* Global Styles
9 | ────────────────────────────────────────────────────────────*/
10 | body {
11 | padding-top : 67px;
12 |
13 | a {
14 | color : @brand-second-color;
15 | }
16 | }
17 | .jumbotron {
18 | font-size : 14px;
19 | background : none;
20 | border : 1px solid #D7D7D7;
21 | }
22 | .well {
23 | border-radius : 0;
24 | background : none;
25 | border : 0;
26 | border-left : @trim-border;
27 | .box-shadow( none );
28 | }
29 | .badge {
30 | background : #e4e7e7;
31 | color : #2c333d;
32 | border-radius : 5px;
33 | padding : 5px 8px;
34 | }
35 | .btn-lg {
36 | border-radius : 0;
37 | }
38 | .pagination > .active > a,
39 | .pagination > .active > span,
40 | .pagination > .active > a:hover,
41 | .pagination > .active > span:hover,
42 | .pagination > .active > a:focus,
43 | .pagination > .active > span:focus {
44 | background : @trim-color;
45 | border-color : darken( @trim-color, 10%);
46 | }
47 | html > .no-js > div.js-warning {
48 | display : none;
49 | }
50 |
51 | /* Success/Error Message Custom Styling
52 | ────────────────────────────────────────────────────────────*/
53 | .has-error .help-block {
54 | font-size : 11px;
55 | }
56 |
57 | #app_message {
58 | display : none;
59 | top : 45%;
60 | .alert {
61 | font-size : 13px;
62 | font-weight : bold;
63 | padding : 16px;
64 | border-radius : 2px;
65 | }
66 | .alert-warning {
67 | color : #000;
68 | }
69 | .alert-danger {
70 | color : #FFF;
71 | }
72 | }
73 |
74 | /* Form Custom Styling
75 | ────────────────────────────────────────────────────────────*/
76 | .wrapper-form {
77 | max-width : 900px;
78 | }
79 | .form-horizontal {
80 | label {
81 | font-size : 12px;
82 | }
83 | }
84 | .select2-container .select2-choices .select2-search-field input,
85 | .select2-container .select2-choice, .select2-container .select2-choices {
86 | border-radius : 0px;
87 | }
88 |
89 | .content {
90 | margin-top : 10px;
91 | padding-left : 116px;
92 | padding-right : 26px;
93 | }
94 |
95 | /* Mobile @1200px
96 | ────────────────────────────────────────────────────────────*/
97 | @media (max-width: @screen-lg) {
98 | .content {
99 |
100 | }
101 | }
102 |
103 | /* Desktop @992px
104 | ────────────────────────────────────────────────────────────*/
105 | @media (min-width: (@screen-sm + 1)) and (max-width: @screen-md) {
106 | .content {
107 |
108 | }
109 | }
110 |
111 | /* Mobile @768px
112 | ────────────────────────────────────────────────────────────*/
113 | @media (min-width: (@screen-xs + 1)) and (max-width: @screen-sm) {
114 | .content {
115 |
116 | }
117 | }
118 |
119 | /* Mobile @480px
120 | ────────────────────────────────────────────────────────────*/
121 | @media (max-width: @screen-xs) {
122 | .content {
123 | margin-top : 15px;
124 | padding-left : 71px;
125 | padding-right : 21px;
126 | }
127 | }
128 |
129 |
--------------------------------------------------------------------------------
/app/styles/preloader.css:
--------------------------------------------------------------------------------
1 | /*!_________ .__ _________ __ __
2 | \_ ___ \ | | ____ ___ __ ____ _______ / _____/_/ |_ _____ ____ | | __
3 | / \ \/ | | _/ __ \ \ \/ /_/ __ \ \_ __ \ \_____ \ \ __\\__ \ _/ ___\ | |/ /
4 | \ \____| |__\ ___/ \ / \ ___/ | | \/ / \ | | / __ \_\ \___ | <
5 | \______ /|____/ \___ > \_/ \___ > |__| /_______ / |__| (____ / \___ >|__|_ \
6 | \/ \/ \/ \/ \/ \/ \/ */
7 | .pace {
8 | -webkit-pointer-events: none;
9 | pointer-events: none;
10 | -webkit-user-select: none;
11 | -moz-user-select: none;
12 | user-select: none;
13 | }
14 |
15 | .pace-inactive {
16 | display: none;
17 | }
18 |
19 | .pace .pace-progress {
20 | background: #3F4452;
21 | position: fixed;
22 | z-index: 2000;
23 | top: 0;
24 | left: 0;
25 | height: 2px;
26 |
27 | -webkit-transition: width 1s;
28 | -moz-transition: width 1s;
29 | -o-transition: width 1s;
30 | transition: width 1s;
31 | }
32 |
33 | .pace .pace-progress-inner {
34 | display: block;
35 | position: absolute;
36 | right: 0px;
37 | width: 100px;
38 | height: 100%;
39 | box-shadow: 0 0 10px #3F4452, 0 0 5px #3F4452;
40 | opacity: 1.0;
41 | -webkit-transform: rotate(3deg) translate(0px, -4px);
42 | -moz-transform: rotate(3deg) translate(0px, -4px);
43 | -ms-transform: rotate(3deg) translate(0px, -4px);
44 | -o-transform: rotate(3deg) translate(0px, -4px);
45 | transform: rotate(3deg) translate(0px, -4px);
46 | }
47 |
48 | .pace .pace-activity {
49 | display: block;
50 | position: fixed;
51 | z-index: 2000;
52 | top: 15px;
53 | right: 15px;
54 | width: 14px;
55 | height: 14px;
56 | border: solid 2px transparent;
57 | border-top-color: #3F4452;
58 | border-left-color: #3F4452;
59 | border-radius: 10px;
60 | -webkit-animation: pace-spinner 400ms linear infinite;
61 | -moz-animation: pace-spinner 400ms linear infinite;
62 | -ms-animation: pace-spinner 400ms linear infinite;
63 | -o-animation: pace-spinner 400ms linear infinite;
64 | animation: pace-spinner 400ms linear infinite;
65 | }
66 |
67 | @-webkit-keyframes pace-spinner {
68 | 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); }
69 | 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }
70 | }
71 | @-moz-keyframes pace-spinner {
72 | 0% { -moz-transform: rotate(0deg); transform: rotate(0deg); }
73 | 100% { -moz-transform: rotate(360deg); transform: rotate(360deg); }
74 | }
75 | @-o-keyframes pace-spinner {
76 | 0% { -o-transform: rotate(0deg); transform: rotate(0deg); }
77 | 100% { -o-transform: rotate(360deg); transform: rotate(360deg); }
78 | }
79 | @-ms-keyframes pace-spinner {
80 | 0% { -ms-transform: rotate(0deg); transform: rotate(0deg); }
81 | 100% { -ms-transform: rotate(360deg); transform: rotate(360deg); }
82 | }
83 | @keyframes pace-spinner {
84 | 0% { transform: rotate(0deg); transform: rotate(0deg); }
85 | 100% { transform: rotate(360deg); transform: rotate(360deg); }
86 | }
87 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "author": {
4 | "name": "CleverStack",
5 | "email": "admin@cleverstack.io",
6 | "web": "http://cleverstack.io"
7 | },
8 | "version": "1.1.4",
9 | "collaborators": [
10 | "Richard Gustin ",
11 | "Simon W. Jackson ",
12 | "Daniel Young ",
13 | "Daniel Durante ",
14 | "Sam Deering "
15 | ],
16 | "dependencies": {
17 | "angular": "1.2.6",
18 | "angular-cookies": "1.2.6",
19 | "angular-resource": "1.2.6",
20 | "angular-route": "1.2.6",
21 | "angular-sanitize": "1.2.6",
22 | "angular-http-auth": "1.2.1",
23 | "async": "~0.2.5",
24 | "bootstrap": "~3.0.3",
25 | "angular-ui-bootstrap": "~0.10.0",
26 | "es5-shim": "~2.1.0",
27 | "jquery": "~1.10.2",
28 | "json3": "~3.2.4",
29 | "requirejs": "~2.1.9",
30 | "underscore": "~1.5.2",
31 | "pace": "~0.5.5",
32 | "fontawesome-actions": "~0.5.0",
33 | "ui-bootstrap": "~0.11.0",
34 | "angular-bootstrap": "~0.11.0",
35 | "selectn": "~0.9.6",
36 | "select2": "~3.4.8",
37 | "angular-ui-select2": "~0.0.5",
38 | "angular-ui": "~0.4.0",
39 | "inflection": "~1.3.8",
40 | "momentjs": "~2.8.1",
41 | "jquery-minicolors": "~2.1.6"
42 | },
43 | "devDependencies": {
44 | "angular-mocks": "1.2.6",
45 | "angular-scenario": "1.2.6",
46 | "sinon": "~1.7.3",
47 | "chai": "~1.8.1"
48 | },
49 | "resolutions": {
50 | "angular": "1.2.6",
51 | "angular-mocks": "1.2.6"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/config/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "dev": {
3 | "port": "9000",
4 | "path": "./app",
5 | "liveReloadPort": "35729",
6 | "hostname": "0.0.0.0"
7 | },
8 |
9 |
10 | "test": {
11 | "unit": {
12 | "port": "9090",
13 | "path": "./test",
14 | "coverage": {
15 | "port": "5555",
16 | "path": "./test/coverage/unit/"
17 | },
18 | "conf": "./test-unit.conf.js"
19 | },
20 | "e2e": {
21 | "seleniumPort": "4444",
22 | "path": "./test",
23 | "conf": "./test-e2e.conf.js",
24 | "coverage": {
25 | "port": "7776",
26 | "path": "./test/coverage/e2e/"
27 | },
28 | "report": {
29 | "port": "7777"
30 | },
31 | "instrumented": {
32 | "path": "./test/coverage/e2e/instrumented/"
33 | }
34 | }
35 | },
36 |
37 |
38 | "dist": {
39 | "port": "9009",
40 | "path": "./dist"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports = require(path.resolve(path.join(__dirname, '..', 'lib', 'config')));
4 |
--------------------------------------------------------------------------------
/lib/config/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | , fs = require('fs')
3 | , debug = require('debug')('cleverstack:config')
4 | , envOverride = process.env.NODE_ENV ? process.env.NODE_ENV.toLowerCase() : null
5 | , fileNames = ['global', 'default']
6 | , appRoot = path.resolve(path.join(__dirname, '..', '..'))
7 | , configRoot = path.join(appRoot, 'config')
8 | , configFiles = { global: [ path.join(configRoot, 'global.json') ], env: [] }
9 | , utils = require(path.join(appRoot, 'lib', 'utils'))
10 | , config;
11 |
12 | if (envOverride === null) {
13 | debug('No environment based config set using NODE_ENV, defaulting to "local" configuration');
14 | envOverride = 'local';
15 | }
16 |
17 | var envConfigFile = path.join(configRoot, envOverride + '.json');
18 | if (fs.existsSync(envConfigFile)) {
19 | configFiles.env.push(envConfigFile);
20 | }
21 |
22 | try {
23 | config = require('nconf').loadFilesSync([].concat(configFiles.global, configFiles.env));
24 | } catch(e) {
25 | debug('Error loading configuration: %s', e);
26 | debug('Files: %s', [].concat(configFiles.global, configFiles.env).join(',\n'));
27 | if (e.stack) {
28 | debug(e.stack);
29 | }
30 | process.exit(1);
31 | }
32 |
33 | module.exports = config;
34 |
--------------------------------------------------------------------------------
/lib/utils/helpers.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs')
2 | , path = require('path')
3 | , debug = require('debug')('cleverstack:utils:helpers');
4 |
5 | module.exports = {
6 | getFilesForFolder: function(folderName) {
7 | var files = [];
8 |
9 | if (fs.existsSync(folderName)) {
10 | fs.readdirSync(folderName).forEach(function(fileName) {
11 | if (fs.statSync(path.join(folderName, fileName)).isFile() && /\.js$/.test(fileName)) {
12 | files.push(fileName);
13 | }
14 | });
15 | }
16 |
17 | return files;
18 | },
19 |
20 | fallbackToIndex: function(connect, index, file) {
21 | return connect().use(function(req, res, next) {
22 | if(req.url === file) {
23 | return next();
24 | }
25 |
26 | if(/\/(.*.(html|js|css))$/.test(req.url)) {
27 | return res.end(fs.readFileSync(path.resolve(path.join(index.replace(file, ''), RegExp.$1))));
28 | }
29 |
30 | res.end(fs.readFileSync(index));
31 | });
32 | },
33 |
34 | mountFolder: function(connect, dir) {
35 | return connect.static(path.resolve(dir));
36 | }
37 | };
38 |
--------------------------------------------------------------------------------
/lib/utils/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | helpers: require('./helpers')
3 | };
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "angular-seed",
4 | "description": "Cleverstack Angular-Seed",
5 | "version": "1.2.0-rc-2",
6 | "author": {
7 | "name": "CleverStack",
8 | "email": "admin@cleverstack.io",
9 | "web": "http://cleverstack.io"
10 | },
11 | "collaborators": [
12 | "Richard Gustin ",
13 | "Simon W. Jackson ",
14 | "Daniel Young ",
15 | "Daniel Durrante ",
16 | "Sam Deering "
17 | ],
18 | "repository": {
19 | "type": "git",
20 | "url": "https://github.com/CleverStack/angular-seed.git"
21 | },
22 | "bugs": {
23 | "url": "https://github.com/CleverStack/angular-seed/issues"
24 | },
25 | "keywords": [
26 | "cleverstack",
27 | "framework",
28 | "seed",
29 | "angular"
30 | ],
31 | "license": "BSD-2-Clause",
32 | "dependencies": {},
33 | "devDependencies": {
34 | "debug": "~2.2.0",
35 | "deepmerge": "~0.2.10",
36 | "grunt-concurrent": "~0.4.1",
37 | "grunt-contrib-clean": "~0.5.0",
38 | "grunt-contrib-concat": "~0.3.0",
39 | "grunt-contrib-connect": "~0.5.0",
40 | "grunt-contrib-copy": "~0.4.1",
41 | "grunt-contrib-cssmin": "~0.7.0",
42 | "grunt-contrib-htmlmin": "~0.1.3",
43 | "grunt-contrib-imagemin": "~0.4.0",
44 | "grunt-contrib-jade": "^0.15.0",
45 | "grunt-contrib-jshint": "~0.7.1",
46 | "grunt-contrib-less": "~0.6.4",
47 | "grunt-contrib-livereload": "~0.1.2",
48 | "grunt-contrib-requirejs": "~0.4.1",
49 | "grunt-contrib-watch": "~0.5.2",
50 | "grunt-coveralls": "^0.3.0",
51 | "grunt-istanbul": "^0.3.0",
52 | "grunt-karma": "~0.6.2",
53 | "grunt-ng-annotate": "^0.3.2",
54 | "grunt-open": "~0.2.2",
55 | "grunt-protractor-coverage": "^0.2.8",
56 | "grunt-protractor-runner": "~0.1.6",
57 | "grunt-rev": "~0.1.0",
58 | "grunt-run": "^0.2.4",
59 | "grunt-usemin": "~0.1.12",
60 | "jshint-stylish": "^0.4.0",
61 | "karma": "~0.10.8",
62 | "karma-browserstack-launcher": "~0.0.7",
63 | "karma-chrome-launcher": "~0.1.1",
64 | "karma-coverage": "~0.1.0",
65 | "karma-firefox-launcher": "~0.1.2",
66 | "karma-growl-reporter": "~0.1.1",
67 | "karma-html2js-preprocessor": "~0.1.0",
68 | "karma-jasmine": "~0.1.4",
69 | "karma-junit-reporter": "~0.2.1",
70 | "karma-ng-html2js-preprocessor": "~0.1.0",
71 | "karma-opera-launcher": "~0.1.0",
72 | "karma-phantomjs-launcher": "~0.1.1",
73 | "karma-requirejs": "~0.2.0",
74 | "karma-safari-launcher": "~0.1.1",
75 | "karma-script-launcher": "~0.1.0",
76 | "load-grunt-tasks": "~0.2.0",
77 | "lodash": "^2.4.1",
78 | "nconf": "~0.7.1",
79 | "ng-annotate": "~0.9.11",
80 | "phantomjs": "~1.9.2",
81 | "protractor": "~0.24.2",
82 | "time-grunt": "~0.2.1"
83 | },
84 | "scripts": {
85 | "setup": "node scripts/setup",
86 | "setup-protractor": "grunt webdriver:update",
87 | "start": "grunt server",
88 | "bs-tunnel-karma": "sh scripts/bs-tunnel-karma.sh",
89 | "bs-tunnel": "sh scripts/bs-tunnel-connect.sh",
90 | "test": "grunt test:travis",
91 | "testos": "node scripts/testos"
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/scripts/bs-tunnel-connect.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | java -jar scripts/BrowserStackTunnel.jar YOUR_KEY localhost,9090,0
--------------------------------------------------------------------------------
/scripts/bs-tunnel-karma.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | java -jar scripts/BrowserStackTunnel.jar YOUR_KEY localhost,9876,0
--------------------------------------------------------------------------------
/scripts/kill-phantomjs.sh:
--------------------------------------------------------------------------------
1 | echo "Killing zombie phantomjs processes..."
2 | ps -ef | grep "bin/phantomjs" \
3 | | grep "capture.js" \
4 | | grep -oEi ' * [1-90]{5}' \
5 | | while read pid ; do kill -9 "$pid" \
6 | ; done
7 | echo "Done!"
--------------------------------------------------------------------------------
/scripts/setup.js:
--------------------------------------------------------------------------------
1 | var async_exec = require('child_process').exec
2 |
3 | async_exec('npm install shelljs', function (err, stdout, stderr) {
4 | require('shelljs/global');
5 |
6 | echo('About to setup Appgular environment');
7 | echo('It works if it finishes with OK');
8 |
9 | if(!which('bower')) {
10 | echo('Bower is missing...taking care of that now.');
11 | exec('npm install --global bower');
12 | echo(exec('bower --version').output);
13 | }
14 |
15 | if(!which('grunt')) {
16 | echo('Grunt is missing...taking care of that now.');
17 | exec('npm install --global grunt-cli');
18 | echo(exec('grunt --version').output);
19 | }
20 |
21 | if(!which('phantomjs')) {
22 | echo('PhantomJS is missing...taking care of that now.');
23 | exec('npm install --global phantomjs');
24 | echo(exec('phantomjs --version').output);
25 | }
26 |
27 | if(!which('karma')) {
28 | echo('Karma is missing...taking care of that now.');
29 | exec('npm install --global karma');
30 | echo(exec('karma --version').output);
31 | }
32 |
33 | echo('Installing devDependencies...');
34 | exec('npm install');
35 |
36 | echo('Installing components...');
37 | exec('bower install');
38 |
39 | echo('Downloading BrowserStackTunnel jar cli tool...');
40 | exec('wget http://www.browserstack.com/BrowserStackTunnel.jar');
41 | exec('mv BrowserStackTunnel.jar scripts/BrowserStackTunnel.jar');
42 |
43 | echo('OK!');
44 | });
45 |
--------------------------------------------------------------------------------
/scripts/testos.js:
--------------------------------------------------------------------------------
1 | var async_exec = require('child_process').exec
2 |
3 | async_exec('npm install shelljs', function (err, stdout, stderr) {
4 | require('shelljs/global');
5 | var os = require('os');
6 |
7 | echo('Testing OS environment');
8 |
9 | /*
10 | What platform you're running on: 'darwin', 'freebsd', 'linux', 'sunos' or 'win32'
11 | win32 (for 32 or 64 bit)
12 | */
13 | echo('OS detected is: '+os.platform());
14 |
15 | var isWin = /^win32/.test(os.platform());
16 | echo ('isWin = '+isWin);
17 |
18 | var isLinux = /^linux/.test(os.platform());
19 | echo ('isLinux = '+isLinux);
20 |
21 | var isMac = /^darwin/.test(os.platform()) || /^freebsd/.test(os.platform());
22 | echo ('isMac = '+isMac);
23 |
24 | });
25 |
--------------------------------------------------------------------------------
/tasks/grunt/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/tasks/grunt/.gitkeep
--------------------------------------------------------------------------------
/tasks/grunt/clean.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | server : '.tmp',
3 | dist: {
4 | files : [{
5 | dot : true,
6 | src : [ '.tmp', '<%= appConfig.dist.path %>/*', '!<%= appConfig.dist.path %>/.git*' ]
7 | }]
8 | },
9 | coverage: {
10 | files : [{
11 | dot : true,
12 | src : [ '<%= appConfig.test.unit.coverage.path %>*' ]
13 | }]
14 | },
15 | coverageE2E: {
16 | files : [{
17 | dot : true,
18 | src : [ '<%= appConfig.test.e2e.coverage.path %>*' ]
19 | }]
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/tasks/grunt/compress.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | main: {
3 | options: {
4 | mode: 'gzip'
5 | },
6 | files: [
7 | // Each of the files in the src/ folder will be output to
8 | // the dist/ folder each with the extension .gz.js
9 | { expand: true, src: [ 'scripts/*.js', ], dest: 'dist/', ext: '.js', cwd: '.tmp/' }
10 | ]
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/tasks/grunt/concurrent.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | watch: {
3 | tasks: [
4 | 'watch:livereload',
5 | 'watch:less',
6 | 'watch:jade'
7 | ],
8 | options: {
9 | logConcurrentOutput: true
10 | }
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/tasks/grunt/connect.js:
--------------------------------------------------------------------------------
1 | var utils = require('utils')
2 | , lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet
3 | , appConfig = require('config');
4 |
5 | module.exports = {
6 | options: {
7 | port: '<%= appConfig.dev.port %>',
8 | hostname: '<%= appConfig.dev.hostname %>',
9 | livereload: '<%= appConfig.dev.liveReloadPort %>'
10 | },
11 | livereload: {
12 | options: {
13 | middleware: function( connect ) {
14 | return [
15 | lrSnippet,
16 | utils.helpers.mountFolder( connect, '.tmp' ),
17 | utils.helpers.mountFolder( connect, appConfig.dev.path ),
18 | utils.helpers.fallbackToIndex( connect, 'app/index.html', '/index.html' )
19 | ];
20 | }
21 | }
22 | },
23 | dist: {
24 | options: {
25 | livereload: false,
26 | port: '<%= appConfig.dist.port %>',
27 | base: '<%= appConfig.dist.path %>',
28 | middleware: function( connect ) {
29 | return [
30 | connect.compress(),
31 | utils.helpers.mountFolder( connect, appConfig.dist.path ),
32 | utils.helpers.fallbackToIndex( connect, appConfig.dist.path + '/index.html', '/index.html' )
33 | ];
34 | }
35 | }
36 | },
37 | coverage: {
38 | options: {
39 | base: '<%= appConfig.test.unit.coverage.path %>',
40 | directory: '<%= appConfig.test.unit.coverage.path %>',
41 | port: '<%= appConfig.test.unit.coverage.port %>',
42 | keepalive: true,
43 | livereload: false
44 | }
45 | },
46 | coverageE2E: {
47 | options: {
48 | port: '<%= appConfig.test.e2e.coverage.port %>',
49 | middleware: function( connect ) {
50 | return [
51 | utils.helpers.mountFolder( connect, appConfig.test.e2e.instrumented.path + 'app' ),
52 | utils.helpers.fallbackToIndex( connect, appConfig.test.e2e.instrumented.path + 'app/index.html', '/index.html' )
53 | ];
54 | },
55 | livereload: false,
56 | debug: false
57 | }
58 | },
59 | coverageE2EReport: {
60 | options: {
61 | port: '<%= appConfig.test.e2e.report.port %>',
62 | middleware: function( connect ) {
63 | return [
64 | utils.helpers.mountFolder( connect, appConfig.test.e2e.coverage.path + '/reports' ),
65 | utils.helpers.fallbackToIndex( connect, appConfig.test.e2e.coverage.path + 'reports/index.html', '/index.html' )
66 | ];
67 | },
68 | keepalive: true,
69 | livereload: false
70 | }
71 | },
72 | coverageE2EReportNoWait: {
73 | options: {
74 | port: '<%= appConfig.test.e2e.report.port %>',
75 | middleware: function( connect ) {
76 | return [
77 | utils.helpers.mountFolder( connect, appConfig.test.e2e.coverage.path + '/reports' ),
78 | utils.helpers.fallbackToIndex( connect, appConfig.test.e2e.coverage.path + 'reports/index.html', '/index.html' )
79 | ];
80 | },
81 | keepalive: false,
82 | livereload: false
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/tasks/grunt/copy.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | config: {
3 | distScripts: {
4 | files: [{
5 | expand: true,
6 | dot: true,
7 | cwd: '<%= appConfig.dist.path %>',
8 | dest: '.tmp',
9 | src: [
10 | 'scripts/**/*'
11 | ]
12 | }]
13 | },
14 | dist: {
15 | files: [{
16 | expand: true,
17 | dot: true,
18 | cwd: '<%= appConfig.dev.path %>',
19 | dest: '<%= appConfig.dist.path %>',
20 | src: [
21 | '*.{ico,txt}',
22 | '.htaccess',
23 | 'components/**/*.{js,css,eot,svg,ttf,woff,png,jpg,jpeg,gif,webp}',
24 | 'images/{,*/}*.{gif,webp,png}',
25 | 'images/**/*.{gif,webp,png}',
26 | 'styles/fonts/**/*',
27 | 'scripts/**/*',
28 | 'fonts/**/*',
29 | 'home/**/*',
30 | 'modules/**/*',
31 | 'index.html'
32 | ]
33 | }]
34 | },
35 | coverageE2E: {
36 | files: [{
37 | expand: true,
38 | dot: true,
39 | cwd: '<%= appConfig.dev.path %>',
40 | dest: '<%= appConfig.test.e2e.instrumented.path %>app',
41 | src: [
42 | '*.{ico,txt}',
43 | '.htaccess',
44 | 'components/**/*.{js,css,eot,svg,ttf,woff,png,jpg,jpeg,gif,webp}',
45 | 'images/{,*/}*.{gif,webp,png}',
46 | 'images/**/*.{gif,webp,png}',
47 | 'styles/**/*',
48 | 'scripts/**/*',
49 | 'fonts/**/*',
50 | 'home/**/*',
51 | 'modules/main.js',
52 | 'modules/**/main.js',
53 | 'modules/**/module.js',
54 | 'modules/**/views/**',
55 | 'modules/**/styles/**',
56 | 'index.html'
57 | ]
58 | }]
59 | },
60 | bootstrap: {
61 | files: [
62 | {
63 | expand: true,
64 | filter: 'isFile',
65 | cwd: '<%= appConfig.dev.path %>/components/bootstrap/dist/js',
66 | dest: '<%= appConfig.dev.path %>/scripts',
67 | src: [ 'bootstrap.js' ]
68 | },
69 | {
70 | expand: true,
71 | filter: 'isFile',
72 | cwd: '<%= appConfig.dev.path %>/components/bootstrap/dist',
73 | dest: '<%= appConfig.dev.path %>',
74 | src: [ 'fonts/*' ]
75 | },
76 | {
77 | expand: true,
78 | filter: 'isFile',
79 | cwd: '<%= appConfig.dev.path %>/components/bootstrap/dist/css',
80 | dest: '<%= appConfig.dev.path %>/styles',
81 | src: [ 'bootstrap.css' ]
82 | },
83 | {
84 | expand: true,
85 | filter: 'isFile',
86 | cwd: '<%= appConfig.dev.path %>/components/bootstrap/less',
87 | dest: '<%= appConfig.dev.path %>/styles/less/bootstrap',
88 | src: [
89 | '**/*.less'
90 | ]
91 | }
92 | ]
93 | }
94 | },
95 | register: function(grunt) {
96 | // to initialise bootstrap run 'grunt bootstrap'
97 | grunt.registerTask('bootstrap', ['copy:bootstrap']);
98 | }
99 | };
100 |
--------------------------------------------------------------------------------
/tasks/grunt/cssmin.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | root: './app',
4 | relativeTo: '/'
5 | },
6 | dist: {
7 | files: {
8 | '<%= appConfig.dist.path %>/styles/screen.css': [
9 | '<%= appConfig.dev.path %>/styles/preloader.css',
10 | '<%= appConfig.dev.path %>/styles/bootstrap.css',
11 | '<%= appConfig.dev.path %>/components/fontawesome-actions/dist/css/font-awesome.min.css',
12 | '<%= appConfig.dev.path %>/components/angular-ui/build/angular-ui.min.css',
13 | '<%= appConfig.dev.path %>/components/ng-table/ng-table.min.css',
14 | '<%= appConfig.dev.path %>/components/jquery-minicolors/jquery.minicolors.css',
15 | '<%= appConfig.dev.path %>/components/select2/select2.css',
16 | '<%= appConfig.dev.path %>/components/select2/select2-bootstrap.css',
17 | '<%= appConfig.dev.path %>/styles/application.css'
18 | ]
19 | }
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/tasks/grunt/htmlmin.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | dist: {
3 | options: {
4 | collapseBooleanAttributes: true,
5 | collapseWhitespace: true,
6 | removeAttributeQuotes: true,
7 | removeComments: true,
8 | removeEmptyAttributes: true,
9 | removeRedundantAttributes: true,
10 | removeScriptTypeAttributes: true,
11 | removeStyleLinkTypeAttributes: true
12 | },
13 | files: [{
14 | expand: true,
15 | cwd: '<%= appConfig.dist.path %>',
16 | src: [ 'index.html', 'modules/**/views/**/*.html' ],
17 | dest: '<%= appConfig.dist.path %>'
18 | }]
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/tasks/grunt/imagemin.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | dist: {
3 | files: [{
4 | expand: true,
5 | cwd: '<%= appConfig.dev.path %>/images',
6 | src: '**/*.{png,jpg,jpeg}',
7 | dest: '<%= appConfig.dist.path %>/images'
8 | },
9 | {
10 | expand: true,
11 | cwd: '<%= appConfig.dev.path %>/components',
12 | src: '**/*.{png,jpg,jpeg}',
13 | dest: '<%= appConfig.dist.path %>/components'
14 | }]
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/tasks/grunt/instrument.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | lazy : true,
4 | basePath : '<%= appConfig.test.e2e.instrumented.path %>'
5 | },
6 | files: [
7 | 'app/modules/**/scripts/*.js',
8 | 'app/modules/**/controllers/*.js',
9 | 'app/modules/**/directives/*.js',
10 | 'app/modules/**/factories/*.js',
11 | 'app/modules/**/services/*.js',
12 | 'app/modules/**/providers/*.js',
13 | 'app/modules/**/models/*.js',
14 | 'app/modules/**/filters/*.js'
15 | ]
16 | };
17 |
--------------------------------------------------------------------------------
/tasks/grunt/jade.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | pretty: true,
4 | debug: true
5 | },
6 | compile: {
7 | expand: true,
8 | src: [
9 | './app/modules/**/views/**/*.jade'
10 | ],
11 | dest: './',
12 | ext: '.html'
13 | }
14 | };
--------------------------------------------------------------------------------
/tasks/grunt/jshint.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | jshintrc : '.jshintrc',
4 | reporter : require( 'jshint-stylish' ),
5 | ignores: [
6 | '<%= appConfig.dev.path %>/modules/**/test*/**/*.js'
7 | ]
8 | },
9 | all: [
10 | 'Gruntfile.js',
11 | '<%= appConfig.dev.path %>/modules/**/*.js'
12 | ]
13 | };
14 |
--------------------------------------------------------------------------------
/tasks/grunt/karma.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | config: {
3 | unit: {
4 | configFile: '<%= appConfig.test.unit.conf %>',
5 | autoWatch: false,
6 | singleRun: true
7 | },
8 | unitAuto: {
9 | configFile: '<%= appConfig.test.unit.conf %>',
10 | autoWatch: true,
11 | singleRun: false
12 | },
13 | unitCoverage: {
14 | configFile: '<%= appConfig.test.unit.conf %>',
15 | autoWatch: false,
16 | singleRun: true,
17 | reporters: [ 'progress', 'coverage' ],
18 | preprocessors: {
19 | './app/modules/**/*.js': [ 'coverage' ]
20 | },
21 | coverageReporter: {
22 | type: 'html',
23 | dir: '<%= appConfig.test.unit.coverage.path %>'
24 | }
25 | },
26 | travis: {
27 | configFile: '<%= appConfig.test.unit.conf %>',
28 | autoWatch: false,
29 | singleRun: true,
30 | browsers: [ 'PhantomJS' ]
31 | }
32 | },
33 | register: function(grunt) {
34 | grunt.registerTask('test:unit', 'Single run of unit tests.', [
35 | 'karma:unit'
36 | ]);
37 |
38 | grunt.registerTask('autotest:unit', 'Start up the auto unit test server.', [
39 | 'karma:unitAuto',
40 | 'watch:unitTests'
41 | ]);
42 |
43 | grunt.registerTask('test:travis', 'Single run of unit tests for Travis CI.', [
44 | 'karma:travis'
45 | ]);
46 |
47 | grunt.registerTask('test:unit-coverage', 'Run a unit test coverage report and server.', [
48 | 'test:run-unit-coverage',
49 | 'connect:coverage'
50 | ]);
51 |
52 | grunt.registerTask('test:run-unit-coverage', 'Run a unit test coverage report.', [
53 | 'clean:coverage',
54 | 'karma:unitCoverage',
55 | 'open:coverage'
56 | ]);
57 | }
58 | };
59 |
--------------------------------------------------------------------------------
/tasks/grunt/less.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | config: {
3 | css: {
4 | options: {
5 | paths: [ '<%= appConfig.dist.path %>/styles' ]
6 | },
7 | files: [
8 | {
9 | dest: '<%= appConfig.dev.path %>/styles/application.css',
10 | src: [
11 |
12 | '<%= appConfig.dev.path %>/styles/less/application.less',
13 | '<%= appConfig.dev.path %>/modules/**/styles/**/*.less',
14 | '<%= appConfig.dev.path %>/modules/**/styles/**/*.css'
15 | ]
16 | }
17 | ]
18 | }
19 | },
20 | register: function(grunt) {
21 | //for less compilation force
22 | grunt.option( 'force', true );
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/tasks/grunt/makeReport.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | src: '<%= appConfig.test.e2e.instrumented.path %>*.json',
3 | options: {
4 | type: 'html',
5 | dir: '<%= appConfig.test.e2e.coverage.path %>reports',
6 | print: 'detail'
7 | }
8 | };
9 |
--------------------------------------------------------------------------------
/tasks/grunt/ngAnnotate.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | singleQuotes: true,
4 | regexp: '^(ng\n?[\\ ]+(.*)|(module.*))$'
5 | },
6 | dist: {
7 | files: [ { add: true, src: 'dist/modules/**/*.js' } ]
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/tasks/grunt/open.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | server: {
3 | url: 'http://localhost:<%= connect.options.port %>'
4 | },
5 | test: {
6 | url: 'http://localhost:<%= connect.test.options.port %>'
7 | },
8 | dist: {
9 | url: 'http://localhost:<%= connect.dist.options.port %>'
10 | },
11 | coverage: {
12 | url: 'http://localhost:<%= appConfig.test.unit.coverage.port %>'
13 | },
14 | coverageE2E: {
15 | url: 'http://localhost:<%= appConfig.test.e2e.report.port %>'
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/tasks/grunt/protractor.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | config: {
3 | options: {
4 | configFile: '<%= appConfig.test.e2e.conf %>',
5 | args: {
6 | seleniumPort: '<%= appConfig.test.e2e.seleniumPort %>'
7 | }
8 | },
9 | singlerun: {
10 | keepAlive: false
11 | },
12 | auto: {
13 | keepAlive: true
14 | }
15 | },
16 | register: function(grunt) {
17 | grunt.registerTask('test:e2e', 'Single run of end to end (e2e) tests using protractor.', [
18 | 'connect:livereload',
19 | 'protractor:singlerun'
20 | ]);
21 |
22 | grunt.registerTask('autotest:e2e', 'Start up the auto end to end (e2e) test server using protractor.', [
23 | 'connect:livereload',
24 | 'protractor:auto',
25 | 'watch:e2eTests'
26 | ]);
27 |
28 | grunt.registerTask('test', 'Run both unit and e2e tests', [
29 | 'test:unit',
30 | 'test:e2e'
31 | ]);
32 |
33 | grunt.registerTask('test:coverage', 'Run a unit test coverage report.', [
34 | 'test:run-e2e-coverage',
35 | 'open:coverageE2E',
36 | 'connect:coverageE2EReportNoWait',
37 | 'test:unit-coverage'
38 | ]);
39 | }
40 | };
41 |
--------------------------------------------------------------------------------
/tasks/grunt/protractor_coverage.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | config: {
3 | local: {
4 | options: {
5 | configFile: '<%= appConfig.test.e2e.conf %>',
6 | keepAlive: true,
7 | noColor: false,
8 | coverageDir: '<%= appConfig.test.e2e.instrumented.path %>',
9 | args: {
10 | baseUrl: 'http://localhost:<%= appConfig.test.e2e.coverage.port %>'
11 | }
12 | }
13 | }
14 | },
15 | register: function(grunt) {
16 | grunt.registerTask('test:e2e-coverage', 'Run an e2e test coverage report and server.', [
17 | 'test:run-e2e-coverage',
18 | 'open:coverageE2E',
19 | 'connect:coverageE2EReport'
20 | ]);
21 |
22 | grunt.registerTask('test:run-e2e-coverage', 'Run an e2e test coverage report.', [
23 | 'clean:coverageE2E',
24 | 'copy:coverageE2E',
25 | 'instrument',
26 | 'connect:coverageE2E',
27 | 'protractor_coverage',
28 | 'makeReport'
29 | ]);
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/tasks/grunt/requirejs.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | compile: {
3 | options: {
4 | name: 'main',
5 | baseUrl: '<%= appConfig.dist.path %>/modules',
6 | out: '<%= appConfig.dist.path %>/scripts/scripts.js',
7 | findNestedDependencies: true,
8 | preserveLicenseComments: false,
9 | generateSourceMaps: false,
10 | optimize: 'uglify2',
11 | uglify2: {
12 | mangle: true,
13 | compress: {
14 | 'drop_console': true,
15 | 'drop_debugger': true,
16 | 'dead_code': true,
17 | 'join_vars': true,
18 | 'if_return': true,
19 | 'negate_iife': true,
20 | booleans: true,
21 | loops: true,
22 | unused: true
23 | }
24 | }
25 | }
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/tasks/grunt/rev.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | dist: {
3 | files: {
4 | src: [
5 | '<%= appConfig.dist.path %>/scripts/{,*/}*.js',
6 | '<%= appConfig.dist.path %>/styles/{,*/}*.css',
7 | '<%= appConfig.dist.path %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
8 | '<%= appConfig.dist.path %>/styles/fonts/*'
9 | ]
10 | }
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/tasks/grunt/run.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | config: {
3 | wbDriverUpdate: {
4 | args: [ './node_modules/protractor/bin/webdriver-manager', 'update', '--out_dir=./scripts/' ],
5 | options: {
6 | passArgs: [
7 | 'ie',
8 | 'chrome',
9 | 'standalone',
10 | 'seleniumPort'
11 | ]
12 | }
13 | },
14 | wbDriverStatus: {
15 | args: [ './node_modules/protractor/bin/webdriver-manager', 'status' ],
16 | options: {
17 | passArgs: [
18 | 'ie',
19 | 'chrome',
20 | 'standalone',
21 | 'seleniumPort'
22 | ]
23 | }
24 | },
25 | wbDriverStart: {
26 | args: [ './node_modules/protractor/bin/webdriver-manager', 'start', '--out_dir=./scripts/' ],
27 | options: {
28 | passArgs: [
29 | 'ie',
30 | 'chrome',
31 | 'standalone',
32 | 'seleniumPort'
33 | ]
34 | }
35 | }
36 | },
37 | register: function(grunt) {
38 | grunt.registerTask( 'webdriver', [
39 | 'run:wbDriverStatus',
40 | 'run:wbDriverUpdate'
41 | ]);
42 |
43 | grunt.registerTask( 'webdriver:update', [
44 | 'run:wbDriverUpdate'
45 | ]);
46 |
47 | grunt.registerTask( 'webdriver:status', [
48 | 'run:wbDriverStatus'
49 | ]);
50 |
51 | grunt.registerTask( 'webdriver:start', [
52 | 'run:wbDriverStart'
53 | ]);
54 | }
55 | };
56 |
--------------------------------------------------------------------------------
/tasks/grunt/usemin.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | html: [ '<%= appConfig.dist.path %>/index.html', '<%= appConfig.dist.path %>/modules/**/views/**/*.html' ],
3 | css: [ '<%= appConfig.dist.path %>/styles/**/*.css' ],
4 | options: {
5 | dirs: [ '<%= appConfig.dist.path %>' ]
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/tasks/grunt/useminPrepare.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | html: '<%= appConfig.dev.path %>/index.html',
3 | options: {
4 | root: '<%= appConfig.dev.path %>',
5 | dest: '<%= appConfig.dist.path %>'
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/tasks/grunt/watch.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | livereload: {
3 | options: {
4 | livereload: true
5 | },
6 | files: [
7 | '<%= appConfig.dev.path %>/components/bootstrap/{,*/}*.css',
8 | '<%= appConfig.dev.path %>/styles/{,*/}*.css',
9 | '<%= appConfig.dev.path %>/{,*/}*.html',
10 | '<%= appConfig.dev.path %>/modules/**/{,*/}*.{css,js,html}',
11 | '{.tmp,<%= appConfig.dev.path %>}/styles/*.css',
12 | '{.tmp,<%= appConfig.dev.path %>}/views/{,*/}*.html',
13 | '{.tmp,<%= appConfig.dev.path %>}/scripts/{,*/}*.js',
14 | '<%= appConfig.dev.path %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
15 | ]
16 | },
17 | jade: {
18 | files: [
19 | './app/modules/**/views/**/*.jade'
20 | ],
21 | tasks: [
22 | 'jade:compile'
23 | ]
24 | },
25 | less: {
26 | files: [
27 | '<%= appConfig.dev.path %>/components/bootstrap/less/*.less',
28 | '<%= appConfig.dev.path %>/styles/less/**/*.less',
29 | '<%= appConfig.dev.path %>/modules/**/styles/**/*.less'
30 | ],
31 | tasks: [
32 | 'less:css'
33 | ]
34 | },
35 | unitTests: {
36 | files: [
37 | 'test*/unit/**/*.js',
38 | '**/test*/unit/**/*.js'
39 | ]
40 | },
41 | e2eTests: {
42 | files: [
43 | 'test*/e2e/**/*.js',
44 | '**/test*/e2e/**/*.js'
45 | ],
46 | tasks: [ 'protractor:singlerun' ]
47 | }
48 | };
49 |
--------------------------------------------------------------------------------
/tasks/gulp/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/tasks/gulp/.gitkeep
--------------------------------------------------------------------------------
/test-unit.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // http://karma-runner.github.io/0.10/config/configuration-file.html
3 |
4 | module.exports = function(config) {
5 | config.set({
6 | // list of files / patterns to load in the browser
7 |
8 | // **/*.js: All files with a "js" extension in all subdirectories
9 | // **/!(jquery).js: Same as previous, but excludes "jquery.js"
10 | // **/(foo|bar).js: In all subdirectories, all "foo.js" or "bar.js" files
11 |
12 | files: [
13 | 'tests/unit/main.js',
14 | { pattern: 'app/modules/**/**/*.js', included: false, served: true },
15 | { pattern: 'app/modules/**/scripts/*.js', included: false, served: true },
16 | { pattern: 'app/modules/**/controllers/*.js', included: false, served: true },
17 | { pattern: 'app/modules/**/directives/*.js', included: false, served: true },
18 | { pattern: 'app/modules/**/factories/*.js', included: false, served: true },
19 | { pattern: 'app/modules/**/services/*.js', included: false, served: true },
20 | { pattern: 'app/components/**/*.js', included: false, served: true, watched: false },
21 | ],
22 |
23 | // list of files / patterns to exclude
24 | exclude: [
25 | 'app/modules/main.js',
26 | 'app/modules/**/test*/e2e/*'
27 | ],
28 |
29 | // sauceLabs: {
30 | // testName: 'CleverStack AngularJS (Frontend) Unit Tests',
31 | // username: '',
32 | // accessKey: ''
33 | // },
34 |
35 | // Define any custom launchers you want, use this for saucelabs
36 | customLaunchers: {
37 | slChrome: { base: 'SauceLabs', browserName: 'chrome', platform: 'Windows 7' },
38 | slFirefox: { base: 'SauceLabs', browserName: 'firefox', version: '27' },
39 | slIosSafari: { base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.9', version: '7.1' },
40 | slIe11: { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 8.1', version: '11' }
41 | },
42 |
43 | /* Start these browsers, currently available:
44 | Chrome
45 | ChromeCanary
46 | PhantomJS
47 | Firefox
48 | Opera
49 | Internet Explorer
50 | Safari
51 | */
52 | browsers: [
53 | 'Chrome',
54 | 'PhantomJS',
55 | ],
56 |
57 | // http://karma-runner.github.io/0.8/config/preprocessors.html
58 | preprocessors: {
59 | 'app/**/*.html': ['ng-html2js']
60 | },
61 |
62 | //https://github.com/karma-runner/karma-ng-html2js-preprocessor
63 | ngHtml2JsPreprocessor: {
64 | // strip this from the file path
65 | stripPrefix: 'app/',
66 | // prepend this to the
67 | // prependPrefix: '',
68 | // setting this option will create only a single module that contains templates
69 | // from all the files, so you can load them all with module('foo')
70 | // moduleName: 'templates'
71 | },
72 |
73 | // level of logging: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
74 | logLevel: config.LOG_INFO,
75 |
76 | // base path, that will be used to resolve files and exclude
77 | basePath: './',
78 |
79 | // web server port
80 | port: 9090,
81 |
82 | // testing framework to use (jasmine/mocha/qunit/...)
83 | frameworks: ['requirejs', 'jasmine'],
84 |
85 | // Additional reporters, such as growl, junit, teamcity or coverage
86 | reporters: ['progress'/*, 'saucelabs' */],
87 |
88 | // Continuous Integration mode, if true, it capture browsers, run tests and exit
89 | // singleRun: false, // (set it grunt file)
90 |
91 | // Set this for CI, encase its slow (SauceLabs)
92 | // captureTimeout: 120000,
93 |
94 | // enable / disable watching file and executing tests whenever any file changes
95 | // autoWatch: true, // (set it grunt file)
96 |
97 | // Enable or disable colors in the output (reporters and logs).
98 | colors: true
99 | });
100 | };
101 |
--------------------------------------------------------------------------------
/tests/e2e/nav.test.js:
--------------------------------------------------------------------------------
1 | // test the main navigation
2 | describe('e2e: navigation', function() {
3 |
4 | var ptor;
5 | browser.get('/');
6 | ptor = protractor.getInstance();
7 |
8 | beforeEach(function() {
9 | link = element(by.css('.navbar a[href="/signIn"]'));
10 | link.click();
11 | });
12 |
13 | it('should navigate to the /signIn page when clicking', function() {
14 | expect(ptor.getCurrentUrl()).toMatch(/\/signIn/);
15 | });
16 |
17 | //todo: not implemented yet
18 | // it('should make the nav class active when at /login', function() {
19 | // expect(link.getAttribute('class')).toMatch(/active/);
20 | // });
21 |
22 | });
23 |
--------------------------------------------------------------------------------
/tests/e2e/pages.test.js:
--------------------------------------------------------------------------------
1 | // test the main pages are working
2 | describe('e2e: pages', function() {
3 |
4 | var ptor;
5 | beforeEach(function() {
6 | browser.get('/');
7 | ptor = protractor.getInstance();
8 | });
9 |
10 | it('check the signIn page is accasible from the homepage and has a form', function() {
11 | element(by.css('a[href="/signIn"]')).click();
12 | expect(ptor.getCurrentUrl()).toMatch(/\/signIn/);
13 | expect(ptor.findElement(protractor.By.tagName('form')).getAttribute('id'))
14 | .toMatch('signIn');
15 | });
16 |
17 | it('check the signUp page is accasible from the homepage and has a form', function() {
18 | element(by.css('a[href="/signUp"]')).click();
19 | expect(ptor.getCurrentUrl()).toMatch(/\/signUp/);
20 | expect(ptor.findElement(protractor.By.tagName('form')).getAttribute('id'))
21 | .toMatch('signup');
22 | });
23 |
24 | });
25 |
--------------------------------------------------------------------------------