├── .bowerrc ├── .editorconfig ├── .gitignore ├── .jshintrc ├── .yo-rc.json ├── History.md ├── LICENSE ├── README.md ├── bower.json ├── dist ├── angular-ux.js └── angular-ux.min.js ├── example ├── README.md ├── app.css ├── app.js ├── details.html ├── home.html └── index.html ├── gulpfile.js ├── karma-dist-concatenated.conf.js ├── karma-dist-minified.conf.js ├── karma-src.conf.js ├── package.json ├── src ├── angularUx.js ├── angularUx.prefix ├── angularUx.suffix └── modules │ ├── global.js │ ├── pages.js │ └── theme.js └── test └── unit └── angularUx └── angularUxSpec.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower" 3 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ._* 2 | .~lock.* 3 | .buildpath 4 | .DS_Store 5 | .idea 6 | .project 7 | .settings 8 | 9 | # Ignore node stuff 10 | node_modules/ 11 | npm-debug.log 12 | libpeerconnection.log 13 | 14 | # OS-specific 15 | .DS_Store 16 | 17 | # Bower components 18 | bower 19 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "curly": true, 6 | "eqeqeq": true, 7 | "immed": true, 8 | "indent": 2, 9 | "latedef": true, 10 | "newcap": true, 11 | "noarg": true, 12 | "quotmark": "single", 13 | "regexp": true, 14 | "undef": true, 15 | "strict": false, 16 | "smarttabs": true, 17 | "expr": true, 18 | 19 | 20 | "evil": true, 21 | "browser": true, 22 | "regexdash": true, 23 | "wsh": true, 24 | "trailing": true, 25 | "sub": true, 26 | "unused": true, 27 | "laxcomma": true, 28 | 29 | "globals": { 30 | "after": false, 31 | "before": false, 32 | "afterEach": false, 33 | "beforeEach": false, 34 | "describe": false, 35 | "it": false, 36 | "angular": false, 37 | "expect": false, 38 | "inject": false, 39 | "module": false, 40 | "sinon": false, 41 | "browser": false, 42 | "element": false, 43 | "by": false, 44 | "xit": false 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-angularjs-gulp-library": { 3 | "props": { 4 | "author": { 5 | "name": "Martin Gontovnikas", 6 | "email": "martin@gon.to" 7 | }, 8 | "libraryName": { 9 | "original": "angular-ux", 10 | "camelized": "angularUx", 11 | "dasherized": "angular-ux", 12 | "slugified": "angular-ux", 13 | "parts": [ 14 | "angular", 15 | "ux" 16 | ] 17 | }, 18 | "includeModuleDirectives": false, 19 | "includeModuleFilters": false, 20 | "includeModuleServices": false, 21 | "includeAngularModuleResource": false, 22 | "includeAngularModuleCookies": false, 23 | "includeAngularModuleSanitize": false, 24 | "librarySrcDirectory": "src/angularUx", 25 | "libraryUnitTestDirectory": "test/unit/angularUx", 26 | "libraryUnitE2eDirectory": "test/e2e/angularUx" 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.0.2 / 2015-03-18 3 | ================== 4 | 5 | * Fixed bug with theming query param 6 | * Fixing HTML 7 | 8 | 0.0.1 / 2015-03-18 9 | ================== 10 | 11 | * Added README 12 | * Added build 13 | * Changing URL on ux-go 14 | * New version 15 | * Added example app 16 | * Created UX module 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Martin Gontovnikas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-ux 2 | 3 | Angular UX is a library that helps you create live, navigable prototypes with the help of AngularJS but without having to learn how to code ;). **DESIGNERS, I'm looking at you!** 4 | 5 | ## Key features 6 | 7 | * Helps you create **live, navigable prototypes** 8 | * It's **intended for designers**, not coders 9 | * **No need to code** a single line of JS. 10 | 11 | ## Installing it 12 | 13 | You have several options: 14 | 15 | ````bash 16 | bower install angular-ux 17 | ```` 18 | 19 | ````bash 20 | npm install angular-ux 21 | ```` 22 | 23 | ````html 24 | 25 | ```` 26 | 27 | ## Configuring it 28 | 29 | ### Setting up our prototype app 30 | The first thing we need to do is setup a new `index.html` which will be the point of entry for our app. 31 | Besides linking to the specific CSS and JS files we need for our prototype, we always need to reference `jQuery`, `angular.js`, `angular-animate` and `angular-ux` in that order. 32 | 33 | > We also need some way of serving the directory where the `index.html` and the other files will reside. For that, we can use `npm` command `serve` or `python -M SimpleHTTPServer` 34 | 35 | ### Setting up the Angular application 36 | 37 | Now, we need to setup the Angular application. This will be the only javascript we need to code to have our prototype running. The good thing is that it’s just copy and paste ;). 38 | 39 | ```html 40 | 41 | 42 | ``` 43 | 44 | ```js 45 | // app.js 46 | angular.module(‘prototype’, [‘ngAnimate’, ‘ux’]) 47 | .controller(‘MainCtrl’, function($scope) { 48 | $scope.data = {}; 49 | }); 50 | ``` 51 | 52 | ## Usage / Features 53 | 54 | ### Navigating through different pages 55 | The first thing all prototypes need is the ability to navigate through different pages. 56 | For this, we can use the `ux-page` directive. 57 | 58 | ```html 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | ``` 68 | ```html 69 | 70 | 71 | Go to Details page 72 | ``` 73 | 74 | In this case, we’re creating 2 different pages. The content of each of those pages are in separate files which we’re including using the `ng-include` directive. Note that we added the `home` attribute to the `ux-page` that will be the main one (displayed by default). 75 | 76 | Then, in the `home.html`, we have a link that navigates the user to the `Details` page. For that, we’re using the `ux-go` directive with the name of the page that we want to browse to. 77 | 78 | > **Note**: It’s important to note that you must put the `href=“”` in the link so that it’s clickable. 79 | 80 | ### Theming 81 | 82 | When you’re prototyping you want to try different themes (colors, typographies, sizes, etc.) at the same time to see which one works better. 83 | For that, you can use a the `ux-themeable` feature from `angular-ux`: 84 | 85 | ```html 86 |
87 |

Title

88 |

This is some text

89 |
90 | ``` 91 | 92 | First you need to add the `ux-themeable` directive to the parent HTML element that you want to theme. Then, to change themes, you need to specify the theme name as a query parameter in the prototype URL. For example, if you go to `http://localhost:3000/#/?page=Details&uxTheme=option1`, the `div.content` will end up having an additional class named `option1` which means we can style it as follows: 93 | 94 | ```css 95 | div.content.option1 h1 { 96 | font-size: 38px; 97 | } 98 | 99 | div.content.option1 p { 100 | color: red 101 | } 102 | ``` 103 | 104 | Alternatively, you can set the query parameter to use for this `ux-themeable` as follows: 105 | 106 | ```html 107 |
108 |

Title

109 |

This is some text

110 |
111 | ``` 112 | 113 | Then, the URL to add `option1` class to `div.content` would be `http://localhost:3000/#/?page=Details&ucontentTheme=option1` 114 | 115 | ## Examples 116 | 117 | You can see a live example in [the example folder](https://github.com/mgonto/angular-ux/tree/master/example). 118 | 119 | To start the sample, just run `serve` or `python -M SimpleHTTPServer` on **the repository root** and then go to `http://localhost:3000/example/` 120 | 121 | ## License 122 | 123 | MIT 124 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-ux", 3 | "version": "0.0.2", 4 | "authors": [ 5 | { 6 | "name": "Martin Gontovnikas", 7 | "email": "martin@gon.to", 8 | "url": "http://gon.to/" 9 | } 10 | ], 11 | "main": [ 12 | "dist/angular-ux.js" 13 | ], 14 | "ignore": [ 15 | "src", 16 | "test", 17 | "gulpfile.js", 18 | "**/.*" 19 | ], 20 | "dependencies": { 21 | "angular": "~1.3.14" 22 | }, 23 | "devDependencies": { 24 | "angular-mocks": "~1.3.14", 25 | "angular-scenario": "~1.3.14" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /dist/angular-ux.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | 4 | // Create all modules and define dependencies to make sure they exist 5 | // and are loaded in the correct order to satisfy dependency injection 6 | // before all nested files are concatenated by Grunt 7 | 8 | // Modules 9 | angular.module('ux', 10 | [ 11 | 'ux.pages', 12 | 'ux.themes' 13 | ]); 14 | 15 | angular.module('ux.global', []) 16 | .service('uxGlobal', ["$location", function($location) { 17 | this.pages = []; 18 | this.currentPage = null; 19 | 20 | this.registerPage = function(name, home) { 21 | this.pages.push(name); 22 | if (home || $location.search().page == name) { 23 | this.changePage(name, !$location.search().page); 24 | } 25 | }; 26 | 27 | this.changePage = function(name, changeUrl) { 28 | if (this.pages.indexOf(name) < 0) { 29 | throw new Error("The page you want to go to doesn't exist"); 30 | } 31 | if (changeUrl) { 32 | var params = $location.search(); 33 | params.page = name; 34 | $location.search(params); 35 | } 36 | this.currentPage = name; 37 | }; 38 | }]) 39 | 40 | angular.module('ux.pages', ['ux.global']) 41 | .directive('uxPage', function() { 42 | return { 43 | restrict: 'E', 44 | replace: true, 45 | template: '
' + 46 | '
', 47 | transclude: true, 48 | scope: { 49 | name: '@' 50 | }, 51 | controller: ["uxGlobal", "$attrs", "$scope", function(uxGlobal, $attrs, $scope) { 52 | uxGlobal.registerPage($scope.name, typeof $attrs.home !== 'undefined'); 53 | 54 | $scope.getCurrentPage = function() { 55 | return uxGlobal.currentPage; 56 | } 57 | }] 58 | }; 59 | }) 60 | .directive('uxGo', function() { 61 | return { 62 | restrict: 'A', 63 | replace: false, 64 | scope: { 65 | uxGo: '@' 66 | }, 67 | controller: ["uxGlobal", "$attrs", "$element", "$scope", function(uxGlobal, $attrs, $element, $scope) { 68 | $element.on('click', function(e) { 69 | e.preventDefault(); 70 | 71 | $scope.$apply(function() { 72 | uxGlobal.changePage($scope.uxGo, true); 73 | }) 74 | }); 75 | }] 76 | }; 77 | }); 78 | 79 | angular.module('ux.themes', []) 80 | .directive('uxThemable', function() { 81 | return { 82 | restrict: 'A', 83 | replace: false, 84 | scope: { 85 | uxThemable: '@' 86 | }, 87 | controller: ["$element", "$location", "$scope", function($element, $location, $scope) { 88 | function checkTheme() { 89 | var params = $location.search(); 90 | var theme = ($scope.uxThemable && params[$scope.uxThemable]) || params.uxTheme; 91 | if (theme) { 92 | $element.addClass(theme); 93 | } 94 | } 95 | $scope.$on('$locationChangeSuccess', function() { 96 | checkTheme(); 97 | }); 98 | checkTheme(); 99 | }] 100 | }; 101 | }); 102 | 103 | }()); -------------------------------------------------------------------------------- /dist/angular-ux.min.js: -------------------------------------------------------------------------------- 1 | !function(){angular.module("ux",["ux.pages","ux.themes"]),angular.module("ux.global",[]).service("uxGlobal",["$location",function(e){this.pages=[],this.currentPage=null,this.registerPage=function(n,t){this.pages.push(n),(t||e.search().page==n)&&this.changePage(n,!e.search().page)},this.changePage=function(n,t){if(this.pages.indexOf(n)<0)throw new Error("The page you want to go to doesn't exist");if(t){var a=e.search();a.page=n,e.search(a)}this.currentPage=n}}]),angular.module("ux.pages",["ux.global"]).directive("uxPage",function(){return{restrict:"E",replace:!0,template:'
',transclude:!0,scope:{name:"@"},controller:["uxGlobal","$attrs","$scope",function(e,n,t){e.registerPage(t.name,"undefined"!=typeof n.home),t.getCurrentPage=function(){return e.currentPage}}]}}).directive("uxGo",function(){return{restrict:"A",replace:!1,scope:{uxGo:"@"},controller:["uxGlobal","$attrs","$element","$scope",function(e,n,t,a){t.on("click",function(n){n.preventDefault(),a.$apply(function(){e.changePage(a.uxGo,!0)})})}]}}),angular.module("ux.themes",[]).directive("uxThemable",function(){return{restrict:"A",replace:!1,scope:{uxThemable:"@"},controller:["$element","$location","$scope",function(e,n,t){function a(){var a=n.search(),r=t.uxThemable&&a[t.uxThemable]||a.uxTheme;r&&e.addClass(r)}t.$on("$locationChangeSuccess",function(){a()}),a()}]}})}(); -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Working sample 2 | 3 | To start the sample, just run `serve` or `python -M SimpleHTTPServer 3000` on **the repository root (not this directory)** and then go to `http://localhost:3000/example/` 4 | -------------------------------------------------------------------------------- /example/app.css: -------------------------------------------------------------------------------- 1 | .main-card { 2 | width: 40%; 3 | margin: 0 auto; 4 | } 5 | 6 | .details.ng-hide-remove { 7 | animation: bounceIn 1s; 8 | -webkit-animation: bounceIn 1s; 9 | -moz-animation: bounceIn 1s; 10 | -ms-animation: bounceIn 1s; 11 | } 12 | 13 | .details.ng-hide-add { 14 | animation: bounceOut 1s; 15 | -webkit-animation: bounceOut 1s; 16 | -moz-animation: bounceOut 1s; 17 | -ms-animation: bounceOut 1s; 18 | } 19 | 20 | .red h1, .red p, .red h2, .red li { 21 | color: red; 22 | } 23 | -------------------------------------------------------------------------------- /example/app.js: -------------------------------------------------------------------------------- 1 | angular.module('proto', ['ux', 'ngAnimate']) 2 | .controller('MainCtrl', function($scope) { 3 | $scope.data = {}; 4 | }); 5 | 6 | 7 | -------------------------------------------------------------------------------- /example/details.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Details card

4 |
5 |
6 |

Martin Gontovnikas

7 |

Message from home: {{data.message || 'No message'}}

8 |

Gonto is a tech nerd that works as a Developer Advocate at Auth0. He <3 OSS, JS, meat and a good beer in that order. He has built Restangular, factory_pal, angular-jwt and many other OSS projects!

9 | 14 |
15 |
16 | -------------------------------------------------------------------------------- /example/home.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Person Card

4 | 5 | Show details 6 | 7 |
8 |
9 |
10 |

Name

11 |

Martin Gontovnikas

12 |
13 |
14 |

Occupation

15 |

Developer Advocate at Auth0

16 |
17 |
18 |

Special message

19 | 20 |
21 |
22 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mauris tellus, vehicula ut tellus id, suscipit dapibus tortor. Integer viverra turpis ac fringilla hendrerit. Sed faucibus posuere felis et pellentesque. Cras varius tortor vitae molestie tempor. Proin ut viverra elit, ac gravida tortor.

23 | 24 | Hide details 25 | 26 | 27 | Go to details page 28 | 29 |
30 |
31 |
32 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | karma = require('karma').server, 3 | concat = require('gulp-concat'), 4 | uglify = require('gulp-uglify'), 5 | rename = require('gulp-rename'), 6 | ngAnnotate = require('gulp-ng-annotate'), 7 | sourceFiles = [ 8 | 'src/angularUx.prefix', 9 | 'src/angularUx.js', 10 | 'src/modules/**/*.js', 11 | 'src/angularUx.suffix' 12 | ]; 13 | 14 | gulp.task('build', function() { 15 | gulp.src(sourceFiles) 16 | .pipe(concat('angular-ux.js')) 17 | .pipe(ngAnnotate()) 18 | .pipe(gulp.dest('./dist/')) 19 | .pipe(uglify()) 20 | .pipe(rename('angular-ux.min.js')) 21 | .pipe(gulp.dest('./dist')) 22 | }); 23 | 24 | /** 25 | * Run test once and exit 26 | */ 27 | gulp.task('test', function (done) { 28 | karma.start({ 29 | configFile: __dirname + '/karma-src.conf.js', 30 | singleRun: true 31 | }, done); 32 | }); 33 | 34 | gulp.task('test-debug', function (done) { 35 | karma.start({ 36 | configFile: __dirname + '/karma-src.conf.js', 37 | singleRun: false, 38 | autoWatch: true 39 | }, done); 40 | }); 41 | 42 | /** 43 | * Run test once and exit 44 | */ 45 | gulp.task('test-dist-concatenated', function (done) { 46 | karma.start({ 47 | configFile: __dirname + '/karma-dist-concatenated.conf.js', 48 | singleRun: true 49 | }, done); 50 | }); 51 | 52 | /** 53 | * Run test once and exit 54 | */ 55 | gulp.task('test-dist-minified', function (done) { 56 | karma.start({ 57 | configFile: __dirname + '/karma-dist-minified.conf.js', 58 | singleRun: true 59 | }, done); 60 | }); 61 | 62 | gulp.task('default', ['test', 'build']); 63 | gulp.task('dist', ['test','test-dist-concatenated', 'test-dist-minified']); 64 | -------------------------------------------------------------------------------- /karma-dist-concatenated.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha', 'chai-jquery', 'jquery-1.8.3', 'sinon-chai'], 14 | 15 | plugins: [ 16 | 'karma-mocha', 17 | 'karma-chai', 18 | 'karma-sinon-chai', 19 | 'karma-chrome-launcher', 20 | 'karma-phantomjs-launcher', 21 | 'karma-jquery', 22 | 'karma-chai-jquery', 23 | 'karma-mocha-reporter' 24 | ], 25 | 26 | // list of files / patterns to load in the browser 27 | files: [ 28 | 'bower/angular/angular.js', 29 | 'bower/angular-mocks/angular-mocks.js', 30 | 'dist/angular-ux.js', 31 | 'test/unit/**/*.js' 32 | ], 33 | 34 | 35 | // list of files to exclude 36 | exclude: [ 37 | ], 38 | 39 | 40 | // preprocess matching files before serving them to the browser 41 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 42 | preprocessors: { 43 | }, 44 | 45 | 46 | // test results reporter to use 47 | // possible values: 'dots', 'progress' 48 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 49 | reporters: ['mocha'], 50 | 51 | 52 | // web server port 53 | port: 9876, 54 | 55 | 56 | // enable / disable colors in the output (reporters and logs) 57 | colors: true, 58 | 59 | 60 | // level of logging 61 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 62 | logLevel: config.LOG_INFO, 63 | 64 | 65 | // enable / disable watching file and executing tests whenever any file changes 66 | autoWatch: true, 67 | 68 | 69 | // start these browsers 70 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 71 | browsers: ['PhantomJS'], 72 | 73 | 74 | // Continuous Integration mode 75 | // if true, Karma captures browsers, runs the tests and exits 76 | singleRun: false 77 | }); 78 | }; 79 | -------------------------------------------------------------------------------- /karma-dist-minified.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha', 'chai-jquery', 'jquery-1.8.3', 'sinon-chai'], 14 | 15 | plugins: [ 16 | 'karma-mocha', 17 | 'karma-chai', 18 | 'karma-sinon-chai', 19 | 'karma-chrome-launcher', 20 | 'karma-phantomjs-launcher', 21 | 'karma-jquery', 22 | 'karma-chai-jquery', 23 | 'karma-mocha-reporter' 24 | ], 25 | 26 | // list of files / patterns to load in the browser 27 | files: [ 28 | 'bower/angular/angular.js', 29 | 'bower/angular-mocks/angular-mocks.js', 30 | 'dist/angular-ux.min.js', 31 | 'test/unit/**/*.js' 32 | ], 33 | 34 | 35 | // list of files to exclude 36 | exclude: [ 37 | ], 38 | 39 | 40 | // preprocess matching files before serving them to the browser 41 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 42 | preprocessors: { 43 | }, 44 | 45 | 46 | // test results reporter to use 47 | // possible values: 'dots', 'progress' 48 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 49 | reporters: ['mocha'], 50 | 51 | 52 | // web server port 53 | port: 9876, 54 | 55 | 56 | // enable / disable colors in the output (reporters and logs) 57 | colors: true, 58 | 59 | 60 | // level of logging 61 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 62 | logLevel: config.LOG_INFO, 63 | 64 | 65 | // enable / disable watching file and executing tests whenever any file changes 66 | autoWatch: true, 67 | 68 | 69 | // start these browsers 70 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 71 | browsers: ['PhantomJS'], 72 | 73 | 74 | // Continuous Integration mode 75 | // if true, Karma captures browsers, runs the tests and exits 76 | singleRun: false 77 | }); 78 | }; 79 | -------------------------------------------------------------------------------- /karma-src.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha', 'chai-jquery', 'jquery-1.8.3', 'sinon-chai'], 14 | 15 | plugins: [ 16 | 'karma-mocha', 17 | 'karma-chai', 18 | 'karma-sinon-chai', 19 | 'karma-chrome-launcher', 20 | 'karma-phantomjs-launcher', 21 | 'karma-jquery', 22 | 'karma-chai-jquery', 23 | 'karma-mocha-reporter' 24 | ], 25 | 26 | // list of files / patterns to load in the browser 27 | files: [ 28 | 'bower/angular/angular.js', 29 | 'bower/angular-mocks/angular-mocks.js', 30 | 'src/**/*.js', 31 | 'test/unit/**/*.js' 32 | ], 33 | 34 | 35 | // list of files to exclude 36 | exclude: [ 37 | ], 38 | 39 | 40 | // preprocess matching files before serving them to the browser 41 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 42 | preprocessors: { 43 | }, 44 | 45 | 46 | // test results reporter to use 47 | // possible values: 'dots', 'progress' 48 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 49 | reporters: ['mocha'], 50 | 51 | 52 | // web server port 53 | port: 9876, 54 | 55 | 56 | // enable / disable colors in the output (reporters and logs) 57 | colors: true, 58 | 59 | 60 | // level of logging 61 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 62 | logLevel: config.LOG_INFO, 63 | 64 | 65 | // enable / disable watching file and executing tests whenever any file changes 66 | autoWatch: true, 67 | 68 | 69 | // start these browsers 70 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 71 | browsers: ['PhantomJS'], 72 | 73 | 74 | // Continuous Integration mode 75 | // if true, Karma captures browsers, runs the tests and exits 76 | singleRun: false 77 | }); 78 | }; 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-ux", 3 | "version": "0.0.2", 4 | "author": { 5 | "name": "Martin Gontovnikas", 6 | "email": "martin@gon.to", 7 | "url": "http://gon.to/" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "chai": "^1.9.1", 12 | "chai-jquery": "^1.2.3", 13 | "karma-mocha-reporter": "^0.3.1", 14 | "gulp": "^3.8.7", 15 | "gulp-concat": "^2.3.4", 16 | "gulp-rename": "^1.2.0", 17 | "gulp-uglify": "^0.3.1", 18 | "karma": "^0.12.22", 19 | "karma-chai": "^0.1.0", 20 | "karma-chai-jquery": "^1.0.0", 21 | "karma-chrome-launcher": "^0.1.4", 22 | "gulp-ng-annotate": "^0.3.3", 23 | "karma-jasmine": "^0.1.5", 24 | "karma-jquery": "^0.1.0", 25 | "karma-mocha": "^0.1.8", 26 | "karma-phantomjs-launcher": "^0.1.4", 27 | "karma-sinon-chai": "^0.2.0", 28 | "mocha": "^1.21.4", 29 | "sinon": "^1.10.3", 30 | "sinon-chai": "^2.5.0" 31 | }, 32 | "engines": { 33 | "node": ">=0.8.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/angularUx.js: -------------------------------------------------------------------------------- 1 | // Create all modules and define dependencies to make sure they exist 2 | // and are loaded in the correct order to satisfy dependency injection 3 | // before all nested files are concatenated by Grunt 4 | 5 | // Modules 6 | angular.module('ux', 7 | [ 8 | 'ux.pages', 9 | 'ux.themes' 10 | ]); 11 | -------------------------------------------------------------------------------- /src/angularUx.prefix: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | -------------------------------------------------------------------------------- /src/angularUx.suffix: -------------------------------------------------------------------------------- 1 | }()); -------------------------------------------------------------------------------- /src/modules/global.js: -------------------------------------------------------------------------------- 1 | angular.module('ux.global', []) 2 | .service('uxGlobal', function($location) { 3 | this.pages = []; 4 | this.currentPage = null; 5 | 6 | this.registerPage = function(name, home) { 7 | this.pages.push(name); 8 | if (home || $location.search().page == name) { 9 | this.changePage(name, !$location.search().page); 10 | } 11 | }; 12 | 13 | this.changePage = function(name, changeUrl) { 14 | if (this.pages.indexOf(name) < 0) { 15 | throw new Error("The page you want to go to doesn't exist"); 16 | } 17 | if (changeUrl) { 18 | var params = $location.search(); 19 | params.page = name; 20 | $location.search(params); 21 | } 22 | this.currentPage = name; 23 | }; 24 | }) 25 | -------------------------------------------------------------------------------- /src/modules/pages.js: -------------------------------------------------------------------------------- 1 | angular.module('ux.pages', ['ux.global']) 2 | .directive('uxPage', function() { 3 | return { 4 | restrict: 'E', 5 | replace: true, 6 | template: '
' + 7 | '
', 8 | transclude: true, 9 | scope: { 10 | name: '@' 11 | }, 12 | controller: function(uxGlobal, $attrs, $scope) { 13 | uxGlobal.registerPage($scope.name, typeof $attrs.home !== 'undefined'); 14 | 15 | $scope.getCurrentPage = function() { 16 | return uxGlobal.currentPage; 17 | } 18 | } 19 | }; 20 | }) 21 | .directive('uxGo', function() { 22 | return { 23 | restrict: 'A', 24 | replace: false, 25 | scope: { 26 | uxGo: '@' 27 | }, 28 | controller: function(uxGlobal, $attrs, $element, $scope) { 29 | $element.on('click', function(e) { 30 | e.preventDefault(); 31 | 32 | $scope.$apply(function() { 33 | uxGlobal.changePage($scope.uxGo, true); 34 | }) 35 | }); 36 | } 37 | }; 38 | }); 39 | -------------------------------------------------------------------------------- /src/modules/theme.js: -------------------------------------------------------------------------------- 1 | angular.module('ux.themes', []) 2 | .directive('uxThemable', function() { 3 | return { 4 | restrict: 'A', 5 | replace: false, 6 | scope: { 7 | uxThemable: '@' 8 | }, 9 | controller: function($element, $location, $scope) { 10 | function checkTheme() { 11 | var params = $location.search(); 12 | var theme = ($scope.uxThemable && params[$scope.uxThemable]) || params.uxTheme; 13 | if (theme) { 14 | $element.addClass(theme); 15 | } 16 | } 17 | $scope.$on('$locationChangeSuccess', function() { 18 | checkTheme(); 19 | }); 20 | checkTheme(); 21 | } 22 | }; 23 | }); 24 | -------------------------------------------------------------------------------- /test/unit/angularUx/angularUxSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('AngularUX', function() { 4 | 5 | it('should be true', function() { 6 | expect(true).to.be.true; 7 | }); 8 | 9 | }); 10 | --------------------------------------------------------------------------------