├── .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 | [![Join the chat at https://gitter.im/CleverStack/angular-seed](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/CleverStack/angular-seed?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | [![GitHub version](https://badge.fury.io/gh/cleverstack%2Fangular-seed.png)](http://badge.fury.io/gh/cleverstack%2Fangular-seed) [![Dependency Status](https://david-dm.org/CleverStack/angular-seed.png)](https://david-dm.org/CleverStack/angular-seed) [![devDependency Status](https://david-dm.org/CleverStack/angular-seed/dev-status.png)](https://david-dm.org/CleverStack/angular-seed#info=devDependencies) [![Code Climate](https://codeclimate.com/github/CleverStack/angular-seed.png)](https://codeclimate.com/github/CleverStack/angular-seed) 6 | [![Build Status](https://secure.travis-ci.org/CleverStack/angular-seed.png?branch=master)](https://travis-ci.org/CleverStack/angular-seed) 7 | [![Coverage](https://codeclimate.com/github/CleverStack/angular-seed/coverage.png)](https://codeclimate.com/github/CleverStack/angular-seed) 8 | [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/) 9 | 10 | ![CleverStack Angular Seed](http://cleverstack.github.io/assets/img/logos/angular-seed-logo-clean.png "CleverStack Angular Seed") 11 | 12 |
13 | CleverStack Angular Seed provides you with a cutting edge AngularJS development workflow. It's been designed to provide you with a super fast test driven front-end development lifecycle. Everything you need should be just one command away, if it's not please open an issue or fork and submit a pull request. 14 |
15 | 16 | ## Documentation 17 | 18 | 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/) 19 | 20 | ## Install 21 | 22 | Install is made easy using the CleverStack CLI, first install [node.js](http://nodejs.org) and wget (linux and mac, required for setup-protractor script) 23 | 24 | 1. `$ npm install -g cleverstack-cli` 25 | 2. `$ clever init my-app` && `$ cd my-app` 26 | 4. `$ clever serve` 27 | 5. Go to: `http://localhost:9000` 28 | 29 | ## License 30 | 31 | See our [LICENSE](https://github.com/CleverStack/angular-seed/blob/master/LICENSE) 32 | -------------------------------------------------------------------------------- /app/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /app/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /app/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /app/images/brand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/images/brand.png -------------------------------------------------------------------------------- /app/images/cs-nav-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/images/cs-nav-logo.png -------------------------------------------------------------------------------- /app/images/fade-to-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/images/fade-to-white.png -------------------------------------------------------------------------------- /app/images/hvd_fonts_-_plutosanslight-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/images/hvd_fonts_-_plutosanslight-webfont.eot -------------------------------------------------------------------------------- /app/images/icon-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/images/icon-close.png -------------------------------------------------------------------------------- /app/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/images/logo.png -------------------------------------------------------------------------------- /app/images/logobig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/images/logobig.png -------------------------------------------------------------------------------- /app/images/modal-header-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/images/modal-header-bg.png -------------------------------------------------------------------------------- /app/images/nav-app-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/images/nav-app-bg.png -------------------------------------------------------------------------------- /app/images/nav-app-item-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/images/nav-app-item-bg.png -------------------------------------------------------------------------------- /app/images/nav-main-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CleverStack/angular-seed/f91a5ad3bb1df2303948ccb578b7841b952e96f6/app/images/nav-main-bg.png -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | CleverStack 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 53 | 54 | 58 | 59 | 60 |
61 |
62 |
63 |
64 | 65 | 66 | 67 | 68 | 69 | 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 |
10 |
11 | 12 | Invalid email address 13 | Please enter your email address 14 |
15 | 16 |
17 | 18 |
19 |
20 |
-------------------------------------------------------------------------------- /app/modules/auth/views/resetPassword.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 63 |
64 |
65 |
66 |
-------------------------------------------------------------------------------- /app/modules/auth/views/signIn.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | 7 | 8 | Invalid email 9 | Email is required 10 |
11 |
12 | 13 | 22 | Password is required 23 | Invalid password 24 |
25 |
26 |
27 |
28 | 29 |
30 |
31 |

forgot my password

32 |
33 |
34 |
35 |
36 |
37 |
38 |
-------------------------------------------------------------------------------- /app/modules/auth/views/users/list.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 13 |
14 |

User List
{{welcome}}

15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /app/modules/auth/views/users/show.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 |
7 | 8 |
9 | 10 |
11 | 12 |
13 | 14 |
15 |

INACTIVE

16 |
17 |
18 | 19 |
20 | 21 |
22 |

23 |
24 |
25 | 26 |
27 | 28 |
29 |

30 |
31 |
32 | 33 |
34 | 35 |
36 |

37 |
38 |
39 | 40 |
41 | 42 |
43 |

44 |
45 |
46 | 47 | 48 |
49 | 50 |
51 | 52 |
53 |
54 |
55 |
-------------------------------------------------------------------------------- /app/modules/auth/views/users/table_actions.html: -------------------------------------------------------------------------------- 1 |
2 | 11 | 21 | 22 | 32 | 33 | 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 |
13 |

Congratulations!

14 |

Your account is now active.

15 |

Choose a plan to unlock features

16 |
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 |
4 | 5 |
6 | 7 |
8 | 17 | Company name is required 18 |
19 |
20 | 21 |
22 | 23 |
24 | 31 |
32 |
33 | 34 |
35 | 36 |
37 | 44 | Invalid email address 45 |
46 |
47 | 48 |
49 | 50 |
51 |

52 |
53 |
54 | 55 |
56 | 57 |
58 |

59 |

Use this email address to forward new prospects into your resume pool without relating them to a specific job posting.

60 |
61 |
62 | 63 |
64 |
65 | 66 | or Cancel 67 |
68 | 69 |
-------------------------------------------------------------------------------- /app/modules/cs_accounts/views/list.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 13 |
14 |

Account List
15 | {{welcome}} 16 |

17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /app/modules/cs_accounts/views/partials/chooser.html: -------------------------------------------------------------------------------- 1 |
5 | 15 | 20 |
21 | -------------------------------------------------------------------------------- /app/modules/cs_accounts/views/partials/tableActions.html: -------------------------------------------------------------------------------- 1 |
2 | 11 | 12 | 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 | 30 | 31 | 32 | 33 | 34 |
Name
{{friend.name}}
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 | 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 | [![NPM version](https://badge.fury.io/js/clever-table.png)](http://badge.fury.io/js/clever-table) [![GitHub version](https://badge.fury.io/gh/cleverstack%2Fclever-table.png)](http://badge.fury.io/gh/cleverstack%2Fclever-table) [![Dependency Status](https://david-dm.org/CleverStack/clever-table.png)](https://david-dm.org/CleverStack/clever-table) [![devDependency Status](https://david-dm.org/CleverStack/clever-table/dev-status.png)](https://david-dm.org/CleverStack/clever-table#info=devDependencies) [![Code Climate](https://codeclimate.com/github/CleverStack/clever-table.png)](https://codeclimate.com/github/CleverStack/clever-table) 4 | [![Build Status](https://secure.travis-ci.org/CleverStack/clever-table.png?branch=master)](https://travis-ci.org/CleverStack/clever-table) 5 | [![Coverage](https://codeclimate.com/github/CleverStack/clever-table/coverage.png)](https://codeclimate.com/github/CleverStack/clever-table) [![NPM downloads](http://img.shields.io/npm/dm/clever-table.png)](https://www.npmjs.org/package/clever-table) 6 | [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/) 7 | 8 | ![CleverStack AngularJS Table Module](http://cleverstack.github.io/assets/img/logos/angular-seed-logo-clean.png "CleverStack AngularJS Table Module") 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 | 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 | 12 | 13 | 86 | -------------------------------------------------------------------------------- /app/modules/roles/views/permission/list.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 13 |
14 |

Permission List
15 | {{welcome}} 16 |

17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /app/modules/roles/views/permission/tableActions.html: -------------------------------------------------------------------------------- 1 |
2 | 11 | 12 | 21 |
22 | -------------------------------------------------------------------------------- /app/modules/roles/views/role/list.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 13 |
14 |

Role List
15 | {{welcome}} 16 |

17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /app/modules/roles/views/role/tableActions.html: -------------------------------------------------------------------------------- 1 |
2 | 11 | 12 | 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 | --------------------------------------------------------------------------------