summaryrefslogtreecommitdiff
path: root/www
diff options
context:
space:
mode:
Diffstat (limited to 'www')
-rw-r--r--www/css/style.css19
-rw-r--r--www/img/portalurl.pngbin0 -> 32544 bytes
-rw-r--r--www/index.html10
-rw-r--r--www/js/WizardCtrl.js167
-rw-r--r--www/js/app.js13
-rw-r--r--www/lib/angular-wizard/.bower.json32
-rw-r--r--www/lib/angular-wizard/.gitignore20
-rw-r--r--www/lib/angular-wizard/.travis.yml7
-rw-r--r--www/lib/angular-wizard/CHANGELOG.md0
-rw-r--r--www/lib/angular-wizard/CONTRIBUTE.md17
-rw-r--r--www/lib/angular-wizard/Gruntfile.js201
-rw-r--r--www/lib/angular-wizard/README.md265
-rw-r--r--www/lib/angular-wizard/bower.json21
-rw-r--r--www/lib/angular-wizard/dist/angular-wizard.css138
-rw-r--r--www/lib/angular-wizard/dist/angular-wizard.js446
-rw-r--r--www/lib/angular-wizard/dist/angular-wizard.less179
-rw-r--r--www/lib/angular-wizard/dist/angular-wizard.min.css1
-rw-r--r--www/lib/angular-wizard/dist/angular-wizard.min.js7
-rw-r--r--www/lib/angular-wizard/karma.conf.js80
-rw-r--r--www/lib/angular-wizard/license.md21
-rw-r--r--www/lib/angular-wizard/package.json58
-rw-r--r--www/lib/angular-wizard/src/angular-wizard.less179
-rw-r--r--www/lib/angular-wizard/src/angularModule.js1
-rw-r--r--www/lib/angular-wizard/src/step.html2
-rw-r--r--www/lib/angular-wizard/src/step.js23
-rw-r--r--www/lib/angular-wizard/src/wizard.html8
-rw-r--r--www/lib/angular-wizard/src/wizard.js340
-rw-r--r--www/lib/angular-wizard/src/wizardButtons.js26
-rw-r--r--www/lib/angular-wizard/src/wizardHandler.js26
-rw-r--r--www/lib/angular-wizard/test/angularWizardSpec.js299
-rw-r--r--www/templates/wizard.html91
31 files changed, 2694 insertions, 3 deletions
diff --git a/www/css/style.css b/www/css/style.css
index 3f08dbd8..32aaba63 100644
--- a/www/css/style.css
+++ b/www/css/style.css
@@ -866,4 +866,21 @@ body { font-family: sans-serif; }
.visred {
fill:#FF0000;
-} \ No newline at end of file
+}
+
+.wizardtip
+{
+ margin-left:5px;
+ margin-right:5px;
+ margin-top:10px;
+ margin-bottom:5px;
+ padding: 5px 5px 5px 5px;
+ background-color: #cccccc;
+ color:#333232;
+ border-radius: 10px;
+ border-width: 3px;
+ border-color:#6f6d6d;
+ border-style: solid;
+}
+
+
diff --git a/www/img/portalurl.png b/www/img/portalurl.png
new file mode 100644
index 00000000..e8ac371e
--- /dev/null
+++ b/www/img/portalurl.png
Binary files differ
diff --git a/www/index.html b/www/index.html
index d4cdfe3d..6e3564ca 100644
--- a/www/index.html
+++ b/www/index.html
@@ -28,6 +28,7 @@
<!--<link rel="stylesheet" href="external/ionic.content.banner.css">-->
<link rel="stylesheet" href="external/radio.css">
<link rel="stylesheet" href="lib/ion-datetime-picker/release/ion-datetime-picker.min.css">
+ <link rel="stylesheet" href="lib/angular-wizard/dist/angular-wizard.min.css">
@@ -55,6 +56,7 @@
<script src="cordova.js"></script>
<script src="js/ionicUtils.js"></script>
<script src="lib/ionic-native-transitions/dist/ionic-native-transitions.min.js"></script>
+ <script src="lib/angular-wizard/dist/angular-wizard.min.js"></script>
<!-- your app's js -->
@@ -102,6 +104,8 @@
<script src="js/MontageHistoryCtrl.js"></script>
<script src="js/NewsCtrl.js"></script>
<script src="js/TimelineModalCtrl.js"></script>
+ <script src="js/WizardCtrl.js"></script>
+
<script src="lib/ion-datetime-picker/release/ion-datetime-picker.min.js"></script>
<script src="js/EventsModalGraphCtrl.js"></script>
@@ -234,6 +238,12 @@
<i class="icon ion-help"></i>
</span> Help
</ion-item>
+
+ <ion-item nav-clear menu-close href="#/wizard">
+ <span class=" item-icon-left">
+ <i class="icon ion-help"></i>
+ </span> wizard
+ </ion-item>
<div ng-if="$root.showBlog">
<ion-item nav-clear menu-close href="#/news">
diff --git a/www/js/WizardCtrl.js b/www/js/WizardCtrl.js
new file mode 100644
index 00000000..8dacfee7
--- /dev/null
+++ b/www/js/WizardCtrl.js
@@ -0,0 +1,167 @@
+/* jshint -W041 */
+/* jslint browser: true*/
+/* global cordova,StatusBar,angular,console, Masonry, URI */
+
+angular.module('zmApp.controllers').controller('zmApp.WizardCtrl', ['$scope', '$rootScope', '$ionicModal', 'ZMDataModel','$ionicSideMenuDelegate', '$ionicHistory', '$state', '$ionicPopup', 'SecuredPopups',function ($scope, $rootScope, $ionicModal, ZMDataModel,$ionicSideMenuDelegate, $ionicHistory, $state, $ionicPopup, SecuredPopups) {
+$scope.openMenu = function () {
+ $ionicSideMenuDelegate.toggleLeft();
+ };
+
+
+
+ function addhttp(url) {
+
+ if ((!/^(f|ht)tps?:\/\//i.test(url)) && (url != "")) {
+ url = "http://" + url;
+ }
+ return url;
+ }
+
+ function validURL(url)
+ {
+ if (!url)
+
+ return ({status:false, code:"URL cannot be empty"});
+ url = addhttp(url);
+ return ({status:true, code:""});
+
+ }
+
+
+ $scope.exitAuth = function()
+ {
+ ZMDataModel.zmLog ("Wizard: validating auth syntax");
+ if ($scope.wizard.useauth)
+ {
+ if (!$scope.wizard.usezmauth && !$scope.wizard.usebasicauth)
+ {
+ $rootScope.zmPopup = SecuredPopups.show('show',{
+ title: 'Whoops!',
+ template: 'You need to enable at least one authentication mechanism',
+ buttons: [{text: 'Ok'}]
+
+ });
+ return false;
+ }
+ if ($scope.wizard.usezmauth)
+ {
+ if ((!$scope.wizard.zmuser) || (!$scope.wizard.zmpassword))
+ {
+ $rootScope.zmPopup = SecuredPopups.show('show',{
+ title: 'Whoops!',
+ template: 'Please enter a valid username and password for ZM auth',
+ buttons: [{text: 'Ok'}]
+
+ });
+ return false;
+ }
+ }
+
+ if ($scope.wizard.usebasicauth)
+ {
+ if ((!$scope.wizard.basicuser) || (!$scope.wizard.basicpassword))
+ {
+ $rootScope.zmPopup = SecuredPopups.show('show',{
+ title: 'Whoops!',
+ template: 'Please enter a valid username and password for basic auth',
+ buttons: [{text: 'Ok'}]
+
+ });
+ return false;
+ }
+ }
+ }
+ return true;
+
+ };
+
+ $scope.exitPortal = function()
+ {
+ ZMDataModel.zmLog ("Wizard: validating portal url syntax");
+
+ if (!$scope.wizard.portalurl)
+ {
+ $rootScope.zmPopup = SecuredPopups.show('show',{
+ title: 'Whoops!',
+ template: 'Portal url cannot be empty',
+ buttons: [{text: 'Ok'}]
+
+ });
+ return false;
+ }
+
+ $scope.wizard.portalurl = $scope.wizard.portalurl.toLowerCase().trim();
+ $scope.wizard.portalurl = addhttp($scope.wizard.portalurl);
+ ZMDataModel.zmLog ("Wizard: stripped url:"+$scope.wizard.portalurl);
+
+ var c = URI.parse ($scope.wizard.portalurl);
+
+ if (!c.scheme)
+ {
+ $rootScope.zmPopup = SecuredPopups.show('show',{
+ title: 'Whoops!',
+ template: 'URL seems invalid (no protocol detected)',
+ buttons: [{text: 'Ok'}]
+
+ });
+ return false;
+ }
+
+
+ if (c.userinfo) // basic auth stuff in here, take it out and put it into the next screen
+ {
+ $scope.wizard.useauth = true;
+ $scope.wizard.usebasicauth = true;
+ var barray = c.userinfo.split(":",2);
+ $scope.wizard.basicuser = barray[0];
+ $scope.wizard.basicpassword = barray[1];
+ }
+
+ $scope.wizard.portalurl = c.scheme+"://";
+ if (c.host) $scope.wizard.portalurl += c.host;
+ if (c.port) $scope.wizard.portalurl += ":"+c.host;
+ if (c.path) $scope.wizard.portalurl += c.path;
+ ZMDataModel.zmLog ("Wizard: normalized url:"+$scope.wizard.portalurl);
+ return true;
+ };
+
+ $scope.toggleAuth = function()
+ {
+ $scope.wizard.useauth = !$scope.wizard.useauth;
+ if (!$scope.wizard.useauth)
+ {
+ $scope.wizard.usebasicauth = false;
+ $scope.wizard.usezmauth = false;
+ }
+ };
+
+
+ $scope.toggleTip = function()
+ {
+ $scope.wizard.tipshow = !$scope.wizard.tipshow;
+ if ($scope.wizard.tipshow)
+ $scope.wizard.tiptext = "hide tip";
+ else
+ $scope.wizard.tiptext = "show tip";
+ };
+
+
+ $scope.$on('$ionicView.enter', function () {
+ //console.log("**VIEW ** Help Ctrl Entered");
+
+ $scope.wizard = {
+ tipshow:false,
+ tiptext:"show tip",
+ useauth:false,
+ usebasicauth:false,
+ usezmauth:false,
+ portalurl: "",
+ basicuser : "",
+ basicpassword : "",
+ zmuser : "",
+ zmpassword : ""
+ };
+
+ });
+
+}]);
diff --git a/www/js/app.js b/www/js/app.js
index 4eb7548f..18fdc820 100644
--- a/www/js/app.js
+++ b/www/js/app.js
@@ -19,7 +19,8 @@ angular.module('zmApp', [
'com.2fdevs.videogular',
'com.2fdevs.videogular.plugins.controls',
'com.2fdevs.videogular.plugins.overlayplay',
- 'ionic-native-transitions'
+ 'ionic-native-transitions',
+ 'mgo-angular-wizard'
@@ -1588,7 +1589,15 @@ angular.module('zmApp', [
})
-
+ .state('wizard', {
+ data: {
+ requireLogin: false
+ },
+ url: "/wizard",
+ templateUrl: "templates/wizard.html",
+ controller: 'zmApp.WizardCtrl',
+
+ })
.state('zm-portal-login', {
data: {
diff --git a/www/lib/angular-wizard/.bower.json b/www/lib/angular-wizard/.bower.json
new file mode 100644
index 00000000..17be6a8e
--- /dev/null
+++ b/www/lib/angular-wizard/.bower.json
@@ -0,0 +1,32 @@
+{
+ "name": "angular-wizard",
+ "version": "0.6.1",
+ "main": [
+ "./dist/angular-wizard.min.js",
+ "./dist/angular-wizard.min.css"
+ ],
+ "description": "Easy to use Wizard library for AngularJS ",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/mgonto/angular-wizard.git"
+ },
+ "dependencies": {
+ "angular": "*"
+ },
+ "ignore": [
+ "node_modules",
+ "components",
+ "lib"
+ ],
+ "homepage": "https://github.com/mgonto/angular-wizard",
+ "_release": "0.6.1",
+ "_resolution": {
+ "type": "version",
+ "tag": "v0.6.1",
+ "commit": "d1a8147b585888655850e4f50749ae6180b8ca92"
+ },
+ "_source": "https://github.com/mgonto/angular-wizard.git",
+ "_target": "~0.6.1",
+ "_originalSource": "angular-wizard",
+ "_direct": true
+} \ No newline at end of file
diff --git a/www/lib/angular-wizard/.gitignore b/www/lib/angular-wizard/.gitignore
new file mode 100644
index 00000000..5ae53eed
--- /dev/null
+++ b/www/lib/angular-wizard/.gitignore
@@ -0,0 +1,20 @@
+lib-cov
+*.seed
+*.log
+*.csv
+*.dat
+*.out
+*.pid
+*.gz
+
+pids
+logs
+results
+lib
+node_modules
+components
+bower_components
+npm-debug.log
+src/*.tpls.js
+.idea/
+angular-wizard.iml
diff --git a/www/lib/angular-wizard/.travis.yml b/www/lib/angular-wizard/.travis.yml
new file mode 100644
index 00000000..1426a7a2
--- /dev/null
+++ b/www/lib/angular-wizard/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+ - "0.10"
+
+before_script:
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/www/lib/angular-wizard/CHANGELOG.md b/www/lib/angular-wizard/CHANGELOG.md
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/www/lib/angular-wizard/CHANGELOG.md
diff --git a/www/lib/angular-wizard/CONTRIBUTE.md b/www/lib/angular-wizard/CONTRIBUTE.md
new file mode 100644
index 00000000..73a2b43f
--- /dev/null
+++ b/www/lib/angular-wizard/CONTRIBUTE.md
@@ -0,0 +1,17 @@
+In order to Contribute just git clone the repository and then run:
+
+```
+npm install grunt-cli --global
+npm install
+grunt
+```
+
+Be sure to have PhantomJS installed as Karma tests use it. Otherwise, in mac just run
+
+```
+brew install phantomjs
+```
+
+All changes must be done in src/restangular.js and then after running grunt all changes will be submited to dist/
+
+Please submit a Pull Request or create issues for anything you want :).
diff --git a/www/lib/angular-wizard/Gruntfile.js b/www/lib/angular-wizard/Gruntfile.js
new file mode 100644
index 00000000..06825277
--- /dev/null
+++ b/www/lib/angular-wizard/Gruntfile.js
@@ -0,0 +1,201 @@
+ 'use strict';
+
+module.exports = function(grunt) {
+
+ // Project configuration.
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+ meta: {
+ banner: [
+ '/**',
+ ' * <%= pkg.description %>',
+ ' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>' +
+ ' * @link <%= pkg.homepage %>',
+ ' * @author <%= pkg.author %>',
+ ' * @license MIT License, http://www.opensource.org/licenses/MIT',
+ ' */\n'
+ ].join('\n')
+ },
+ dirs: {
+ dest: 'dist'
+ },
+ clean: [
+ '<%= dirs.dest %>'
+ ],
+ concat: {
+ options: {
+ banner: '<%= meta.banner %>'
+ },
+ dist: {
+ src: ['src/*.js'],
+ dest: '<%= dirs.dest %>/<%= pkg.name %>.js'
+ }
+ },
+ recess: {
+ build: {
+ src: [ 'src/angular-wizard.less' ],
+ dest: '<%= dirs.dest %>/<%= pkg.name %>.css',
+ options: {
+ compile: true,
+ compress: false,
+ noUnderscores: false,
+ noIDs: false,
+ zeroUnits: false
+ }
+ },
+ compile: {
+ src: [ 'src/angular-wizard.less' ],
+ dest: '<%= dirs.dest %>/<%= pkg.name %>.min.css',
+ options: {
+ compile: true,
+ compress: true,
+ noUnderscores: false,
+ noIDs: false,
+ zeroUnits: false
+ }
+ }
+ },
+ less: {
+ build: {
+ options: {
+ paths: ["<%= dirs.dest %>"],
+ cleancss: true,
+ },
+ files: {"<%= dirs.dest %>/<%= pkg.name %>.css": "src/angular-wizard.less"}
+ }
+ },
+ cssmin: {
+ options: {
+ shorthandCompacting: false,
+ roundingPrecision: -1
+ },
+ target: {
+ files: {
+ '<%= dirs.dest %>/<%= pkg.name %>.min.css': ['<%= dirs.dest %>/<%= pkg.name %>.css']
+ }
+ }
+ },
+ copy: {
+ less_files: {
+ files: [
+ {
+ src: [ 'src/angular-wizard.less' ],
+ dest: '<%= dirs.dest %>',
+ cwd: '.',
+ expand: true,
+ flatten: true
+ }
+ ]
+ }
+ },
+ bowerInstall: {
+ install: {
+ }
+ },
+ html2js: {
+ angularwizard: {
+ options: {
+ base: 'src'
+ },
+ src: [ 'src/*.html' ],
+ dest: 'src/<%= pkg.name %>.tpls.js'
+ }
+ },
+ uglify: {
+ options: {
+ banner: '<%= meta.banner %>'
+ },
+ dist: {
+ src: ['<%= concat.dist.dest %>'],
+ dest: '<%= dirs.dest %>/<%= pkg.name %>.min.js'
+ }
+ },
+ karma: {
+ options: {
+ configFile: 'karma.conf.js'
+ },
+ build: {
+ singleRun: true,
+ autoWatch: false
+ },
+ travis: {
+ singleRun: true,
+ autoWatch: false,
+ browsers: ['Firefox']
+ },
+ dev: {
+ autoWatch: true
+ }
+ },
+ changelog: {
+ options: {
+ dest: 'CHANGELOG.md'
+ }
+ }
+ });
+
+ // Load the plugin that provides the "concat" task.
+ grunt.loadNpmTasks('grunt-contrib-concat');
+
+ // Load the plugin that provides the "uglify" task.
+ grunt.loadNpmTasks('grunt-contrib-uglify');
+
+ grunt.loadNpmTasks('grunt-bower-task');
+
+ grunt.renameTask("bower", "bowerInstall");
+
+ grunt.loadNpmTasks('grunt-karma');
+ grunt.loadNpmTasks('grunt-karma');
+
+ grunt.loadNpmTasks('grunt-conventional-changelog');
+
+ grunt.loadNpmTasks('grunt-contrib-less');
+ grunt.loadNpmTasks('grunt-contrib-cssmin');
+ grunt.loadNpmTasks('grunt-contrib-clean');
+ grunt.loadNpmTasks('grunt-contrib-copy');
+ grunt.loadNpmTasks('grunt-ng-annotate');
+ grunt.loadNpmTasks('grunt-html2js');
+
+
+ // Default task.
+ grunt.registerTask('default', ['build']);
+
+ // Build task.
+ grunt.registerTask('build', [
+ 'clean',
+ 'bowerInstall',
+ 'copy',
+ 'less',
+ 'cssmin',
+ 'html2js',
+ 'concat',
+ 'uglify',
+ 'karma:build']);
+
+ grunt.registerTask('test', ['build']);
+
+ grunt.registerTask('travis', ['build']);
+
+ // Provides the "bump" task.
+ grunt.registerTask('bump', 'Increment version number', function() {
+ var versionType = grunt.option('type');
+ function bumpVersion(version, versionType) {
+ var type = {patch: 2, minor: 1, major: 0},
+ parts = version.split('.'),
+ idx = type[versionType || 'patch'];
+ parts[idx] = parseInt(parts[idx], 10) + 1;
+ while(++idx < parts.length) { parts[idx] = 0; }
+ return parts.join('.');
+ }
+ var version;
+ function updateFile(file) {
+ var json = grunt.file.readJSON(file);
+ version = json.version = bumpVersion(json.version, versionType || 'patch');
+ grunt.file.write(file, JSON.stringify(json, null, ' '));
+ }
+ updateFile('package.json');
+ updateFile('bower.json');
+ grunt.log.ok('Version bumped to ' + version);
+ });
+
+};
diff --git a/www/lib/angular-wizard/README.md b/www/lib/angular-wizard/README.md
new file mode 100644
index 00000000..c85aae34
--- /dev/null
+++ b/www/lib/angular-wizard/README.md
@@ -0,0 +1,265 @@
+# Angular-Wizard
+
+[![PayPal donate button](http://img.shields.io/paypal/donate.png?color=yellow)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=martin%40gon%2eto&lc=US&item_name=Martin%20Gontovnikas&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted "Donate once-off to this project using PayPal")
+[![Donate on Gratipay](http://img.shields.io/gratipay/mgonto.svg)](https://gratipay.com/mgonto/)
+
+Angular-wizard is a component that will make it easy for you to create wizards in your app. You can check a running example of the wizard [by clicking here](http://mgonto.github.io/angular-wizard/)
+
+# How do I add this to my project?
+You can download this by:
+
+* Using bower and running `bower install angular-wizard`
+* Using npm and running `npm install angular-wizard`
+* Downloading it manually by getting the files from the dist folder
+* Using JsDelivr CDN files:
+
+````html
+<!-- Use LATEST folder to always get the latest version-->
+<script type="text/javascript" src="http://cdn.jsdelivr.net/angular.wizard/latest/angular-wizard.min.js"></script>
+<link rel="stylesheet" type="text/css" href="http://cdn.jsdelivr.net/angular.wizard/latest/angular-wizard.min.css">
+
+<!-- Or use TAG number for specific version -->
+<script type="text/javascript" src="http://cdn.jsdelivr.net/angular.wizard/0.6.1/angular-wizard.min.js"></script>
+<link rel="stylesheet" type="text/css" href="http://cdn.jsdelivr.net/angular.wizard/0.6.1/angular-wizard.min.css">
+````
+
+The dist folder contains the following files:
+
+* JS files needed for the directives and services
+* CSS files with default styles for the directive
+* LESS file with styles for the directive. If you have less in your project, I recommend using the less instead of the CSS since it has variables to configure Wizard colors.
+
+# Dependencies
+Angular-wizard depends on Angular.
+
+# Starter Guide
+
+## First example
+
+The first thing we need to do is add a dependency to angular-wizard module which is called `mgo-angular-wizard`.
+
+We can do this simply by doing:
+
+````js
+angular.module('your-app', ['mgo-angular-wizard']);
+````
+
+Now, in some HTML for a controller, you can just add a wizard as follows:
+
+````html
+<wizard on-finish="finishedWizard()">
+ <wz-step title="Starting">
+ <h1>This is the first step</h1>
+ <p>Here you can use whatever you want. You can use other directives, binding, etc.</p>
+ <input type="submit" wz-next value="Continue" />
+ </wz-step>
+ <wz-step title="Continuing">
+ <h1>Continuing</h1>
+ <p>You have continued here!</p>
+ <input type="submit" wz-next value="Go on" />
+ </wz-step>
+ <wz-step title="More steps">
+ <p>Even more steps!!</p>
+ <input type="submit" wz-next value="Finish now" />
+ </wz-step>
+</wizard>
+````
+
+This will look like the following when you're in the second step:
+
+[![Looks like](http://f.cl.ly/items/2J0X0l2e3u3Q0R0q2C1Z/Screen%20Shot%202014-01-29%20at%206.14.29%20PM.png)](http://f.cl.ly/items/2J0X0l2e3u3Q0R0q2C1Z/Screen%20Shot%202014-01-29%20at%206.14.29%20PM.png)
+
+Let's go step by step to see how this works.
+
+1) You need to declare a master `wizard` directive. This wizard directive, has the following options as attributes:
+* **on-finish**: Here you can put a function to be called when the wizard is finished. The syntax here is very similar to `ng-click`
+* **name**: The name of the wizard. By default, it's called "Default wizard". It's used for the `WizardHandler` which we'll explain later.
+* **edit-mode**: If set to true, this will set the wizard as edit mode. Edit mode means that all steps have been completed and the user can now navigate to and modify any step. Defaults to false.
+* **hide-indicators**: If set to true, the indicators in the bottom of the page showing the current page and allowing navigation for the wizard will be hidden. Defaults to false.
+* **current-step**: You need to set here a property from your scope (similar to `ng-model`) and that property will always have the name of the current step being shown on the screen.
+* **template**: Path to a custom template.
+
+2) Inside the wizard, we can have as many steps as we want. Each step MUST have a title which is going to be used to identify it. Inside each step, we can put whatever we want. Other directives, bindings, controls, forms, etc. Each step can have the following attributes (we will go into detail on each further below):
+* **wz-title:** A unique title used for identifying each step.
+* **canenter**
+* **canexit**
+* **wz-disabled**
+* **description:** A description available to use in each step's UI.
+* **wz-data** Data you wish to make available to the steps scope.
+
+3) Inside the step, we now see a button which has a `wz-next` attribute. That means that clicking that button will send the user to the next step of wizard. Similar to `wz-next`, we have the following attributes:
+* **wz-previous**: Goes to the previous step
+* **wz-cancel**: Goes back to the first step
+* **wz-finish**: Finishes the wizard and calls the on-finish later on. It's important to note that if we're in the last step and we put `wz-next` it'll be the same as putting `wz-finish` as the wizard will know we're at the last screen.
+* **wz-reset**: This will reset the wizard meaning bring the user to the first step and reset each step to being incomplete.
+
+All of this attributes can receive an optional function to be called before changing the step. Something like:
+
+````html
+<input type="button" wz-next="setMode(mode)" value="Next" />
+````
+
+In this case, the `setMode` function will be called before going to the next step.
+
+## Wizard Dynamic Steps
+A step can be conditionally disabled and may change at any time either adding it or removing it from the wizard step flow.
+
+ **Example**
+
+HTML
+````html
+<wizard on-finish="finishedWizard()">
+ <wz-step title="Starting" wz-disabled="{{disabled}}">
+ <h1>This is the first step</h1>
+ <p>Here you can use whatever you want. You can use other directives, binding, etc.</p>
+ <input type="submit" wz-next value="Continue" />
+ </wz-step>
+ <wz-step title="Continuing">
+ <h1>Continuing</h1>
+ <p>You have continued here!</p>
+ <input type="submit" wz-next value="Go on" />
+ </wz-step>
+ <wz-step title="More steps">
+ <p>Even more steps!!</p>
+ <input type="submit" wz-next value="Finish now" />
+ </wz-step>
+</wizard>
+````
+Controller
+````javascript
+//this will cause the step to be hidden
+$scope.disabled = 'true';
+````
+
+
+## Wizard Step Validation
+The wzStep directive has the following options as attributes:
+* **canexit**: Here you can reference a function from your controller. If this attribute is listed the function must return true in order for the wizard to move to the next step. Promises are supported but must resolve with a thruthy value. If it is ommitted no validation will be required.
+* **canenter**: Here you can reference a function from your controller. If this attribute is listed the function must return true in order for the wizard to move into this step. Promises are supported but must resolve with a thruthy value. If it is ommitted no validation will be required.
+
+ **Example**
+
+HTML
+````html
+<wizard on-finish="finishedWizard()">
+ <wz-step title="Starting" canexit="exitValidation">
+ <h1>This is the first step</h1>
+ <p>Here you can use whatever you want. You can use other directives, binding, etc.</p>
+ <input type="submit" wz-next value="Continue" />
+ </wz-step>
+ <wz-step title="Continuing" canenter="enterValidation">
+ <h1>Continuing</h1>
+ <p>You have continued here!</p>
+ <input type="submit" wz-next value="Go on" />
+ </wz-step>
+ <wz-step title="More steps">
+ <p>Even more steps!!</p>
+ <input type="submit" wz-next value="Finish now" />
+ </wz-step>
+</wizard>
+````
+Controller
+````javascript
+$scope.enterValidation = function(){
+ return true;
+};
+
+$scope.exitValidation = function(){
+ return true;
+};
+//example using context object
+$scope.exitValidation = function(context){
+ return context.firstName === "Jacob";
+}
+//example using promises
+$scope.exitValidation = function(){
+ var d = $q.defer()
+ $timeout(function(){
+ return d.resolve(true);
+ }, 2000);
+ return d.promise;
+}
+````
+If a step requires information from a previous step to populate itself you can access this information through the `context` object. The context object is automatically passed in as an argument into your canexit and canenter methods. You can access the context objext from your controller via: `WizardHandler.wizard().context`
+
+## Manipulating the wizard from a service
+There are some times where we actually want to manipulate the wizard from the controller instead of from the HTML.
+
+For those cases, we can inject the `WizardHandler` to our controller.
+
+The main function of this service is the `wizard(name)` which will let you get the wizard to manipulate it. If you have just one wizard in the screen and you didn't set a name to it, you can just call it as `wizard()`. Let's see an example:
+
+````html
+<wz-step title="Cool step">
+ <input type="submit" ng-click="changeLabelAndGoNext()" />
+</wz-step>
+````
+
+````js
+// In your controller
+$scope.changeLabelAndGoNext = function() {
+ $scope.model.label = "Hola Gonto";
+ WizardHandler.wizard().next();
+}
+````
+
+In this case, we're changing a label and moving forward on the steps.
+The functions available in the `wizard()` are:
+* **next**: Goes to the next step.
+* **previous**: Goes to the previous step.
+* **cancel**: Goes to the previous step.
+* **reset**: Goes to the first step and resets all steps to incomplete.
+* **finish**: Finishes the wizard.
+* **goTo(number|title)**: This goes to the indicated step. It can receive either the number of the step (starting from 0) or the title of the step to go to.
+* **currentStepNumber()**: This returns a Number which is the current step number you are on.
+* **currentStepTitle()**: This returns a String which is the title of the step you are on.
+* **currentStepDescription()**: This returns a String which is the description of the step you are on.
+* **currentStep()**: This returns an Object which is the current step you are on.
+* **totalStepCount()**: This returns an Number which is the total number of **enabled** steps.
+* **getEnabledSteps()**: This returns an Array which is the **enabled** steps.
+
+## Navigation bar
+
+Any changed you wish to make to the navigation bar can be done by overwritting the CSS. Because everyone wants the navigation bar in a different location and in a different style we have provided a default which you can change via your own HTML and CSS. The navigation bar shown below works in the following way:
+
+* Completed steps are painted as green
+* Current step is painted as dark grey
+* Future step is painted as light grey
+* Editing step (Modifying a step already completed in the past) is painted as red
+* You can click in any completed step to go back to that step. You can't click in the current step nor in the future ones unless you've already completed a future step before (for example in EditMode all steps are completed by default)
+
+### Color Definitions
+All of those colors are variables in the `angular-wizard.less`. You can easily change them by importing the `angular-wizard.less` file into your own less file(s) and change the variables.
+The available variables are:
+* @wz-color-default
+* @wz-color-done
+* @wz-color-current
+* @wz-color-editing
+
+# Contributors
+
+* @sebazelonka helped me with all of the styles in the Wizard.
+* [@jacobscarter](https://github.com/jacobscarter) is helping with manteinance, PRS merging and adding new features
+
+# Live sample
+
+You can check out a live sample of the Wizard [clicking here](http://mgonto.github.io/angular-wizard/)
+
+# Releases Notes
+Releases notes are together with releases in GitHub at: https://github.com/mgonto/angular-wizard/releases
+
+
+# License
+The MIT License
+
+Copyright (c) 2013-2014 Martin Gontovnikas http://www.gon.to/
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/mgonto/angular-wizard/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
+
diff --git a/www/lib/angular-wizard/bower.json b/www/lib/angular-wizard/bower.json
new file mode 100644
index 00000000..d0d5aca2
--- /dev/null
+++ b/www/lib/angular-wizard/bower.json
@@ -0,0 +1,21 @@
+{
+ "name": "angular-wizard",
+ "version": "0.6.1",
+ "main": [
+ "./dist/angular-wizard.min.js",
+ "./dist/angular-wizard.min.css"
+ ],
+ "description": "Easy to use Wizard library for AngularJS ",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/mgonto/angular-wizard.git"
+ },
+ "dependencies": {
+ "angular": "*"
+ },
+ "ignore": [
+ "node_modules",
+ "components",
+ "lib"
+ ]
+} \ No newline at end of file
diff --git a/www/lib/angular-wizard/dist/angular-wizard.css b/www/lib/angular-wizard/dist/angular-wizard.css
new file mode 100644
index 00000000..97efc9d4
--- /dev/null
+++ b/www/lib/angular-wizard/dist/angular-wizard.css
@@ -0,0 +1,138 @@
+.steps-indicator {
+ /* ---- steps quantity ---- */
+ right: 0;
+ bottom: 0;
+ left: 0;
+ margin: 0;
+ padding: 20px 0 0 0;
+ height: 30px;
+ list-style: none;
+ /* --- http://www.paulirish.com/2012/box-sizing-border-box-ftw/ ---- */
+}
+.steps-indicator:before {
+ background-color: #e6e6e6;
+ content: '';
+ position: absolute;
+ height: 1px;
+}
+.steps-indicator.steps-2:before {
+ left: calc(100% / 2 / 2);
+ right: calc(100% / 2 / 2);
+}
+.steps-indicator.steps-3:before {
+ left: calc(100% / 3 / 2);
+ right: calc(100% / 3 / 2);
+}
+.steps-indicator.steps-4:before {
+ left: calc(100% / 4 / 2);
+ right: calc(100% / 4 / 2);
+}
+.steps-indicator.steps-5:before {
+ left: calc(100% / 5 / 2);
+ right: calc(100% / 5 / 2);
+}
+.steps-indicator.steps-6:before {
+ left: calc(100% / 6 / 2);
+ right: calc(100% / 6 / 2);
+}
+.steps-indicator.steps-7:before {
+ left: calc(100% / 7 / 2);
+ right: calc(100% / 7 / 2);
+}
+.steps-indicator.steps-8:before {
+ left: calc(100% / 8 / 2);
+ right: calc(100% / 8 / 2);
+}
+.steps-indicator.steps-9:before {
+ left: calc(100% / 9 / 2);
+ right: calc(100% / 9 / 2);
+}
+.steps-indicator.steps-10:before {
+ left: calc(100% / 10 / 2);
+ right: calc(100% / 10 / 2);
+}
+.steps-indicator * {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.steps-indicator li {
+ position: relative;
+ float: left;
+ margin: 0;
+ padding: 0;
+ padding-top: 10px;
+ text-align: center;
+ line-height: 15px;
+}
+.steps-indicator li a {
+ color: #808080;
+ text-decoration: none;
+ text-transform: uppercase;
+ font-weight: bold;
+ transition: 0.25s;
+ cursor: pointer;
+}
+.steps-indicator li a:before {
+ position: absolute;
+ top: -7px;
+ left: calc(50% - 7px);
+ width: 14px;
+ height: 14px;
+ border-radius: 100%;
+ background-color: #e6e6e6;
+ content: '';
+ transition: 0.25s;
+}
+.steps-indicator li a:hover {
+ color: #4d4d4d;
+}
+.steps-indicator.steps-2 li {
+ width: calc(100% / 2);
+}
+.steps-indicator.steps-3 li {
+ width: calc(100% / 3);
+}
+.steps-indicator.steps-4 li {
+ width: calc(100% / 4);
+}
+.steps-indicator.steps-5 li {
+ width: calc(100% / 5);
+}
+.steps-indicator.steps-6 li {
+ width: calc(100% / 6);
+}
+.steps-indicator.steps-7 li {
+ width: calc(100% / 7);
+}
+.steps-indicator.steps-8 li {
+ width: calc(100% / 8);
+}
+.steps-indicator.steps-9 li {
+ width: calc(100% / 9);
+}
+.steps-indicator.steps-10 li {
+ width: calc(100% / 10);
+}
+.steps-indicator.steps-11 li {
+ width: calc(100% / 11);
+}
+.steps-indicator li.default {
+ pointer-events: none;
+}
+.steps-indicator li.default a:hover {
+ color: #808080;
+}
+.steps-indicator li.current,
+.steps-indicator li.editing {
+ pointer-events: none;
+}
+.steps-indicator li.current a:before {
+ background-color: #808080;
+}
+.steps-indicator li.done a:before {
+ background-color: #339933;
+}
+.steps-indicator li.editing a:before {
+ background-color: #ff0000;
+}
diff --git a/www/lib/angular-wizard/dist/angular-wizard.js b/www/lib/angular-wizard/dist/angular-wizard.js
new file mode 100644
index 00000000..b7923b73
--- /dev/null
+++ b/www/lib/angular-wizard/dist/angular-wizard.js
@@ -0,0 +1,446 @@
+/**
+ * Easy to use Wizard library for AngularJS
+ * @version v0.6.0 - 2015-12-31 * @link https://github.com/mgonto/angular-wizard
+ * @author Martin Gontovnikas <martin@gon.to>
+ * @license MIT License, http://www.opensource.org/licenses/MIT
+ */
+angular.module('templates-angularwizard', ['step.html', 'wizard.html']);
+
+angular.module("step.html", []).run(["$templateCache", function($templateCache) {
+ $templateCache.put("step.html",
+ "<section ng-show=\"selected\" ng-class=\"{current: selected, done: completed}\" class=\"step\" ng-transclude>\n" +
+ "</section>");
+}]);
+
+angular.module("wizard.html", []).run(["$templateCache", function($templateCache) {
+ $templateCache.put("wizard.html",
+ "<div>\n" +
+ " <div class=\"steps\" ng-transclude></div>\n" +
+ " <ul class=\"steps-indicator steps-{{getEnabledSteps().length}}\" ng-if=\"!hideIndicators\">\n" +
+ " <li ng-class=\"{default: !step.completed && !step.selected, current: step.selected && !step.completed, done: step.completed && !step.selected, editing: step.selected && step.completed}\" ng-repeat=\"step in getEnabledSteps()\">\n" +
+ " <a ng-click=\"goTo(step)\">{{step.title || step.wzTitle}}</a>\n" +
+ " </li>\n" +
+ " </ul>\n" +
+ "</div>\n" +
+ "");
+}]);
+
+angular.module('mgo-angular-wizard', ['templates-angularwizard']);
+
+angular.module('mgo-angular-wizard').directive('wzStep', function() {
+ return {
+ restrict: 'EA',
+ replace: true,
+ transclude: true,
+ scope: {
+ wzTitle: '@',
+ canenter : '=',
+ canexit : '=',
+ disabled: '@?wzDisabled',
+ description: '@',
+ wzData: '='
+ },
+ require: '^wizard',
+ templateUrl: function(element, attributes) {
+ return attributes.template || "step.html";
+ },
+ link: function($scope, $element, $attrs, wizard) {
+ $scope.title = $scope.wzTitle;
+ wizard.addStep($scope);
+ }
+ };
+});
+
+//wizard directive
+angular.module('mgo-angular-wizard').directive('wizard', function() {
+ return {
+ restrict: 'EA',
+ replace: true,
+ transclude: true,
+ scope: {
+ currentStep: '=',
+ onFinish: '&',
+ hideIndicators: '=',
+ editMode: '=',
+ name: '@'
+ },
+ templateUrl: function(element, attributes) {
+ return attributes.template || "wizard.html";
+ },
+
+ //controller for wizard directive, treat this just like an angular controller
+ controller: ['$scope', '$element', '$log', 'WizardHandler', '$q', function($scope, $element, $log, WizardHandler, $q) {
+ //this variable allows directive to load without having to pass any step validation
+ var firstRun = true;
+ //creating instance of wizard, passing this as second argument allows access to functions attached to this via Service
+ WizardHandler.addWizard($scope.name || WizardHandler.defaultName, this);
+
+ $scope.$on('$destroy', function() {
+ WizardHandler.removeWizard($scope.name || WizardHandler.defaultName);
+ });
+
+ //steps array where all the scopes of each step are added
+ $scope.steps = [];
+
+ var stepIdx = function(step) {
+ var idx = 0;
+ var res = -1;
+ angular.forEach($scope.getEnabledSteps(), function(currStep) {
+ if (currStep === step) {
+ res = idx;
+ }
+ idx++;
+ });
+ return res;
+ };
+
+ var stepByTitle = function(titleToFind) {
+ var foundStep = null;
+ angular.forEach($scope.getEnabledSteps(), function(step) {
+ if (step.wzTitle === titleToFind) {
+ foundStep = step;
+ }
+ });
+ return foundStep;
+ };
+
+ //access to context object for step validation
+ $scope.context = {};
+
+ //watching changes to currentStep
+ $scope.$watch('currentStep', function(step) {
+ //checking to make sure currentStep is truthy value
+ if (!step) return;
+ //setting stepTitle equal to current step title or default title
+ var stepTitle = $scope.selectedStep.wzTitle;
+ if ($scope.selectedStep && stepTitle !== $scope.currentStep) {
+ //invoking goTo() with step title as argument
+ $scope.goTo(stepByTitle($scope.currentStep));
+ }
+
+ });
+
+ //watching steps array length and editMode value, if edit module is undefined or null the nothing is done
+ //if edit mode is truthy, then all steps are marked as completed
+ $scope.$watch('[editMode, steps.length]', function() {
+ var editMode = $scope.editMode;
+ if (angular.isUndefined(editMode) || (editMode === null)) return;
+
+ if (editMode) {
+ angular.forEach($scope.getEnabledSteps(), function(step) {
+ step.completed = true;
+ });
+ } else {
+ var completedStepsIndex = $scope.currentStepNumber() - 1;
+ angular.forEach($scope.getEnabledSteps(), function(step, stepIndex) {
+ if(stepIndex >= completedStepsIndex) {
+ step.completed = false;
+ }
+ });
+ }
+ }, true);
+
+ //called each time step directive is loaded
+ this.addStep = function(step) {
+ //pushing the scope of directive onto step array
+ $scope.steps.push(step);
+ //if this is first step being pushed then goTo that first step
+ if ($scope.getEnabledSteps().length === 1) {
+ //goTo first step
+ $scope.goTo($scope.getEnabledSteps()[0]);
+ }
+ };
+
+ this.context = $scope.context;
+
+ $scope.getStepNumber = function(step) {
+ return stepIdx(step) + 1;
+ };
+
+ $scope.goTo = function(step) {
+ //if this is the first time the wizard is loading it bi-passes step validation
+ if(firstRun){
+ //deselect all steps so you can set fresh below
+ unselectAll();
+ $scope.selectedStep = step;
+ //making sure current step is not undefined
+ if (!angular.isUndefined($scope.currentStep)) {
+ $scope.currentStep = step.wzTitle;
+ }
+ //setting selected step to argument passed into goTo()
+ step.selected = true;
+ //emit event upwards with data on goTo() invoktion
+ $scope.$emit('wizard:stepChanged', {step: step, index: stepIdx(step)});
+ //setting variable to false so all other step changes must pass validation
+ firstRun = false;
+ } else {
+ //createing variables to capture current state that goTo() was invoked from and allow booleans
+ var thisStep;
+ //getting data for step you are transitioning out of
+ if($scope.currentStepNumber() > 0){
+ thisStep = $scope.currentStepNumber() - 1;
+ } else if ($scope.currentStepNumber() === 0){
+ thisStep = 0;
+ }
+ //$log.log('steps[thisStep] Data: ', $scope.getEnabledSteps()[thisStep].canexit);
+ $q.all([canExitStep($scope.getEnabledSteps()[thisStep], step), canEnterStep(step)]).then(function(data) {
+ if(data[0] && data[1]){
+ //deselect all steps so you can set fresh below
+ unselectAll();
+
+ //$log.log('value for canExit argument: ', $scope.currentStep.canexit);
+ $scope.selectedStep = step;
+ //making sure current step is not undefined
+ if(!angular.isUndefined($scope.currentStep)){
+ $scope.currentStep = step.wzTitle;
+ }
+ //setting selected step to argument passed into goTo()
+ step.selected = true;
+ //emit event upwards with data on goTo() invoktion
+ $scope.$emit('wizard:stepChanged', {step: step, index: stepIdx(step)});
+ //$log.log('current step number: ', $scope.currentStepNumber());
+ }
+ });
+ }
+ };
+
+ function canEnterStep(step) {
+ var defer,
+ canEnter;
+ //If no validation function is provided, allow the user to enter the step
+ if(step.canenter === undefined){
+ return true;
+ }
+ //If canenter is a boolean value instead of a function, return the value
+ if(typeof step.canenter === 'boolean'){
+ return step.canenter;
+ }
+ //Check to see if the canenter function is a promise which needs to be returned
+ canEnter = step.canenter($scope.context);
+ if(angular.isFunction(canEnter.then)){
+ defer = $q.defer();
+ canEnter.then(function(response){
+ defer.resolve(response);
+ });
+ return defer.promise;
+ } else {
+ return canEnter === true;
+ }
+ }
+
+ function canExitStep(step, stepTo) {
+ var defer,
+ canExit;
+ //Exiting the step should be allowed if no validation function was provided or if the user is moving backwards
+ if(typeof(step.canexit) === 'undefined' || $scope.getStepNumber(stepTo) < $scope.currentStepNumber()){
+ return true;
+ }
+ //If canexit is a boolean value instead of a function, return the value
+ if(typeof step.canexit === 'boolean'){
+ return step.canexit;
+ }
+ //Check to see if the canexit function is a promise which needs to be returned
+ canExit = step.canexit($scope.context);
+ if(angular.isFunction(canExit.then)){
+ defer = $q.defer();
+ canExit.then(function(response){
+ defer.resolve(response);
+ });
+ return defer.promise;
+ } else {
+ return canExit === true;
+ }
+ }
+
+ $scope.currentStepNumber = function() {
+ //retreive current step number
+ return stepIdx($scope.selectedStep) + 1;
+ };
+
+ $scope.getEnabledSteps = function() {
+ return $scope.steps.filter(function(step){
+ return step.disabled !== 'true';
+ });
+ };
+
+ //unSelect All Steps
+ function unselectAll() {
+ //traverse steps array and set each "selected" property to false
+ angular.forEach($scope.getEnabledSteps(), function (step) {
+ step.selected = false;
+ });
+ //set selectedStep variable to null
+ $scope.selectedStep = null;
+ }
+
+ //ALL METHODS ATTACHED TO this ARE ACCESSIBLE VIA WizardHandler.wizard().methodName()
+
+ this.currentStepTitle = function(){
+ return $scope.selectedStep.wzTitle;
+ };
+
+ this.currentStepDescription = function(){
+ return $scope.selectedStep.description;
+ };
+
+ this.currentStep = function(){
+ return $scope.selectedStep;
+ };
+
+ this.totalStepCount = function() {
+ return $scope.getEnabledSteps().length;
+ }
+
+ //Access to enabled steps from outside
+ this.getEnabledSteps = function(){
+ return $scope.getEnabledSteps();
+ };
+
+ //Access to current step number from outside
+ this.currentStepNumber = function(){
+ return $scope.currentStepNumber();
+ };
+ //method used for next button within step
+ this.next = function(callback) {
+ var enabledSteps = $scope.getEnabledSteps();
+ //setting variable equal to step you were on when next() was invoked
+ var index = stepIdx($scope.selectedStep);
+ //checking to see if callback is a function
+ if(angular.isFunction(callback)){
+ if(callback()){
+ if (index === enabledSteps.length - 1) {
+ this.finish();
+ } else {
+ //invoking goTo() with step number next in line
+ $scope.goTo(enabledSteps[index + 1]);
+ }
+ } else {
+ return;
+ }
+ }
+ if (!callback) {
+ //completed property set on scope which is used to add class/remove class from progress bar
+ $scope.selectedStep.completed = true;
+ }
+ //checking to see if this is the last step. If it is next behaves the same as finish()
+ if (index === enabledSteps.length - 1) {
+ this.finish();
+ } else {
+ //invoking goTo() with step number next in line
+ $scope.goTo(enabledSteps[index + 1]);
+ }
+
+ };
+
+ //used to traverse to any step, step number placed as argument
+ this.goTo = function(step) {
+ var enabledSteps = $scope.getEnabledSteps();
+ var stepTo;
+ //checking that step is a Number
+ if (angular.isNumber(step)) {
+ stepTo = enabledSteps[step];
+ } else {
+ //finding the step associated with the title entered as goTo argument
+ stepTo = stepByTitle(step);
+ }
+ //going to step
+ $scope.goTo(stepTo);
+ };
+
+ //calls finish() which calls onFinish() which is declared on an attribute and linked to controller via wizard directive.
+ this.finish = function() {
+ if ($scope.onFinish) {
+ $scope.onFinish();
+ }
+ };
+
+ this.previous = function() {
+ //getting index of current step
+ var index = stepIdx($scope.selectedStep);
+ //ensuring you aren't trying to go back from the first step
+ if (index === 0) {
+ throw new Error("Can't go back. It's already in step 0");
+ } else {
+ //go back one step from current step
+ $scope.goTo($scope.getEnabledSteps()[index - 1]);
+ }
+ };
+
+ //cancel is alias for previous.
+ this.cancel = function() {
+ //getting index of current step
+ var index = stepIdx($scope.selectedStep);
+ //ensuring you aren't trying to go back from the first step
+ if (index === 0) {
+ throw new Error("Can't go back. It's already in step 0");
+ } else {
+ //go back one step from current step
+ $scope.goTo($scope.getEnabledSteps()[0]);
+ }
+ };
+
+ //reset
+ this.reset = function(){
+ //traverse steps array and set each "completed" property to false
+ angular.forEach($scope.getEnabledSteps(), function (step) {
+ step.completed = false;
+ });
+ //go to first step
+ this.goTo(0);
+ };
+ }]
+ };
+});
+function wizardButtonDirective(action) {
+ angular.module('mgo-angular-wizard')
+ .directive(action, function() {
+ return {
+ restrict: 'A',
+ replace: false,
+ require: '^wizard',
+ link: function($scope, $element, $attrs, wizard) {
+
+ $element.on("click", function(e) {
+ e.preventDefault();
+ $scope.$apply(function() {
+ $scope.$eval($attrs[action]);
+ wizard[action.replace("wz", "").toLowerCase()]();
+ });
+ });
+ }
+ };
+ });
+}
+
+wizardButtonDirective('wzNext');
+wizardButtonDirective('wzPrevious');
+wizardButtonDirective('wzFinish');
+wizardButtonDirective('wzCancel');
+wizardButtonDirective('wzReset');
+
+angular.module('mgo-angular-wizard').factory('WizardHandler', function() {
+ var service = {};
+
+ var wizards = {};
+
+ service.defaultName = "defaultWizard";
+
+ service.addWizard = function(name, wizard) {
+ wizards[name] = wizard;
+ };
+
+ service.removeWizard = function(name) {
+ delete wizards[name];
+ };
+
+ service.wizard = function(name) {
+ var nameToUse = name;
+ if (!name) {
+ nameToUse = service.defaultName;
+ }
+
+ return wizards[nameToUse];
+ };
+
+ return service;
+});
diff --git a/www/lib/angular-wizard/dist/angular-wizard.less b/www/lib/angular-wizard/dist/angular-wizard.less
new file mode 100644
index 00000000..5f13666a
--- /dev/null
+++ b/www/lib/angular-wizard/dist/angular-wizard.less
@@ -0,0 +1,179 @@
+@wz-color-default: #E6E6E6;
+@wz-color-current: #808080;
+@wz-color-done: #339933;
+@wz-color-editing: #FF0000;
+
+.steps-indicator {
+ /* ---- steps quantity ---- */
+
+
+ right: 0;
+ bottom: 0;
+ left: 0;
+ margin: 0;
+ padding: 20px 0 0 0;
+ height: 30px;
+ list-style: none;
+
+
+
+ &:before {
+ background-color: @wz-color-default;
+ content: '';
+ position: absolute;
+ height: 1px;
+ }
+
+ &.steps-2:before {
+ left: ~'calc(100% / 2 / 2)';
+ right: ~'calc(100% / 2 / 2)';
+ }
+
+ &.steps-3:before {
+ left: ~'calc(100% / 3 / 2)';
+ right: ~'calc(100% / 3 / 2)';
+ }
+
+ &.steps-4:before {
+ left: ~'calc(100% / 4 / 2)';
+ right: ~'calc(100% / 4 / 2)';
+ }
+
+ &.steps-5:before {
+ left: ~'calc(100% / 5 / 2)';
+ right: ~'calc(100% / 5 / 2)';
+ }
+
+ &.steps-6:before {
+ left: ~'calc(100% / 6 / 2)';
+ right: ~'calc(100% / 6 / 2)';
+ }
+
+ &.steps-7:before {
+ left: ~'calc(100% / 7 / 2)';
+ right: ~'calc(100% / 7 / 2)';
+ }
+
+ &.steps-8:before {
+ left: ~'calc(100% / 8 / 2)';
+ right: ~'calc(100% / 8 / 2)';
+ }
+
+ &.steps-9:before {
+ left: ~'calc(100% / 9 / 2)';
+ right: ~'calc(100% / 9 / 2)';
+ }
+
+ &.steps-10:before {
+ left: ~'calc(100% / 10 / 2)';
+ right: ~'calc(100% / 10 / 2)';
+ }
+
+ /* --- http://www.paulirish.com/2012/box-sizing-border-box-ftw/ ---- */
+ * {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+
+
+ li {
+ position: relative;
+ float: left;
+ margin: 0;
+ padding: 0;
+ padding-top: 10px;
+ text-align: center;
+ line-height: 15px;
+
+ a {
+ color: @wz-color-current;
+ text-decoration: none;
+ text-transform: uppercase;
+ font-weight: bold;
+ transition: 0.25s;
+ cursor: pointer;
+
+ &:before {
+ position: absolute;
+ top: -7px;
+ left: ~'calc(50% - 7px)';
+ width: 14px;
+ height: 14px;
+ border-radius: 100%;
+ background-color: @wz-color-default;
+ content: '';
+ transition: 0.25s;
+ }
+
+ &:hover {
+ color: darken(@wz-color-current, 20%);
+ }
+ }
+ }
+
+ &.steps-2 li {
+ width: ~'calc(100% / 2)';
+ }
+
+ &.steps-3 li {
+ width: ~'calc(100% / 3)';
+ }
+
+ &.steps-4 li {
+ width: ~'calc(100% / 4)';
+ }
+
+ &.steps-5 li {
+ width: ~'calc(100% / 5)';
+ }
+
+ &.steps-6 li {
+ width: ~'calc(100% / 6)';
+ }
+
+ &.steps-7 li {
+ width: ~'calc(100% / 7)';
+ }
+
+ &.steps-8 li {
+ width: ~'calc(100% / 8)';
+ }
+
+ &.steps-9 li {
+ width: ~'calc(100% / 9)';
+ }
+
+ &.steps-10 li {
+ width: ~'calc(100% / 10)';
+ }
+
+ &.steps-11 li {
+ width: ~'calc(100% / 11)';
+ }
+
+ li.default {
+ pointer-events: none;
+
+ a:hover {
+ color: @wz-color-current;
+ }
+ }
+
+ li.current,
+ li.editing {
+ pointer-events: none;
+ }
+
+ li.current a:before {
+ background-color: @wz-color-current;
+ }
+
+ li.done a:before {
+ background-color: @wz-color-done;
+ }
+
+ li.editing a:before {
+ background-color: @wz-color-editing;
+ }
+}
diff --git a/www/lib/angular-wizard/dist/angular-wizard.min.css b/www/lib/angular-wizard/dist/angular-wizard.min.css
new file mode 100644
index 00000000..32cbfb46
--- /dev/null
+++ b/www/lib/angular-wizard/dist/angular-wizard.min.css
@@ -0,0 +1 @@
+.steps-indicator li a:before,.steps-indicator:before{background-color:#e6e6e6;content:''}.steps-indicator li.current,.steps-indicator li.default,.steps-indicator li.editing{pointer-events:none}.steps-indicator{right:0;bottom:0;left:0;margin:0;padding:20px 0 0;height:30px;list-style:none}.steps-indicator:before{position:absolute;height:1px}.steps-indicator.steps-2:before{left:calc(100% / 2 / 2);right:calc(100% / 2 / 2)}.steps-indicator.steps-3:before{left:calc(100% / 3 / 2);right:calc(100% / 3 / 2)}.steps-indicator.steps-4:before{left:calc(100% / 4 / 2);right:calc(100% / 4 / 2)}.steps-indicator.steps-5:before{left:calc(100% / 5 / 2);right:calc(100% / 5 / 2)}.steps-indicator.steps-6:before{left:calc(100% / 6 / 2);right:calc(100% / 6 / 2)}.steps-indicator.steps-7:before{left:calc(100% / 7 / 2);right:calc(100% / 7 / 2)}.steps-indicator.steps-8:before{left:calc(100% / 8 / 2);right:calc(100% / 8 / 2)}.steps-indicator.steps-9:before{left:calc(100% / 9 / 2);right:calc(100% / 9 / 2)}.steps-indicator.steps-10:before{left:calc(100% / 10 / 2);right:calc(100% / 10 / 2)}.steps-indicator *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.steps-indicator li{position:relative;float:left;margin:0;padding:0;padding-top:10px;text-align:center;line-height:15px}.steps-indicator li a{color:grey;text-decoration:none;text-transform:uppercase;font-weight:700;transition:.25s;cursor:pointer}.steps-indicator li a:before{position:absolute;top:-7px;left:calc(50% - 7px);width:14px;height:14px;border-radius:100%;transition:.25s}.steps-indicator li a:hover{color:#4d4d4d}.steps-indicator.steps-2 li{width:calc(100% / 2)}.steps-indicator.steps-3 li{width:calc(100% / 3)}.steps-indicator.steps-4 li{width:calc(100% / 4)}.steps-indicator.steps-5 li{width:calc(100% / 5)}.steps-indicator.steps-6 li{width:calc(100% / 6)}.steps-indicator.steps-7 li{width:calc(100% / 7)}.steps-indicator.steps-8 li{width:calc(100% / 8)}.steps-indicator.steps-9 li{width:calc(100% / 9)}.steps-indicator.steps-10 li{width:calc(100% / 10)}.steps-indicator.steps-11 li{width:calc(100% / 11)}.steps-indicator li.default a:hover{color:grey}.steps-indicator li.current a:before{background-color:grey}.steps-indicator li.done a:before{background-color:#393}.steps-indicator li.editing a:before{background-color:red} \ No newline at end of file
diff --git a/www/lib/angular-wizard/dist/angular-wizard.min.js b/www/lib/angular-wizard/dist/angular-wizard.min.js
new file mode 100644
index 00000000..6927a90c
--- /dev/null
+++ b/www/lib/angular-wizard/dist/angular-wizard.min.js
@@ -0,0 +1,7 @@
+/**
+ * Easy to use Wizard library for AngularJS
+ * @version v0.6.0 - 2015-12-31 * @link https://github.com/mgonto/angular-wizard
+ * @author Martin Gontovnikas <martin@gon.to>
+ * @license MIT License, http://www.opensource.org/licenses/MIT
+ */
+function wizardButtonDirective(a){angular.module("mgo-angular-wizard").directive(a,function(){return{restrict:"A",replace:!1,require:"^wizard",link:function(b,c,d,e){c.on("click",function(c){c.preventDefault(),b.$apply(function(){b.$eval(d[a]),e[a.replace("wz","").toLowerCase()]()})})}}})}angular.module("templates-angularwizard",["step.html","wizard.html"]),angular.module("step.html",[]).run(["$templateCache",function(a){a.put("step.html",'<section ng-show="selected" ng-class="{current: selected, done: completed}" class="step" ng-transclude>\n</section>')}]),angular.module("wizard.html",[]).run(["$templateCache",function(a){a.put("wizard.html",'<div>\n <div class="steps" ng-transclude></div>\n <ul class="steps-indicator steps-{{getEnabledSteps().length}}" ng-if="!hideIndicators">\n <li ng-class="{default: !step.completed && !step.selected, current: step.selected && !step.completed, done: step.completed && !step.selected, editing: step.selected && step.completed}" ng-repeat="step in getEnabledSteps()">\n <a ng-click="goTo(step)">{{step.title || step.wzTitle}}</a>\n </li>\n </ul>\n</div>\n')}]),angular.module("mgo-angular-wizard",["templates-angularwizard"]),angular.module("mgo-angular-wizard").directive("wzStep",function(){return{restrict:"EA",replace:!0,transclude:!0,scope:{wzTitle:"@",canenter:"=",canexit:"=",disabled:"@?wzDisabled",description:"@",wzData:"="},require:"^wizard",templateUrl:function(a,b){return b.template||"step.html"},link:function(a,b,c,d){a.title=a.wzTitle,d.addStep(a)}}}),angular.module("mgo-angular-wizard").directive("wizard",function(){return{restrict:"EA",replace:!0,transclude:!0,scope:{currentStep:"=",onFinish:"&",hideIndicators:"=",editMode:"=",name:"@"},templateUrl:function(a,b){return b.template||"wizard.html"},controller:["$scope","$element","$log","WizardHandler","$q",function(a,b,c,d,e){function f(b){var c,d;return void 0===b.canenter?!0:"boolean"==typeof b.canenter?b.canenter:(d=b.canenter(a.context),angular.isFunction(d.then)?(c=e.defer(),d.then(function(a){c.resolve(a)}),c.promise):d===!0)}function g(b,c){var d,f;return"undefined"==typeof b.canexit||a.getStepNumber(c)<a.currentStepNumber()?!0:"boolean"==typeof b.canexit?b.canexit:(f=b.canexit(a.context),angular.isFunction(f.then)?(d=e.defer(),f.then(function(a){d.resolve(a)}),d.promise):f===!0)}function h(){angular.forEach(a.getEnabledSteps(),function(a){a.selected=!1}),a.selectedStep=null}var i=!0;d.addWizard(a.name||d.defaultName,this),a.$on("$destroy",function(){d.removeWizard(a.name||d.defaultName)}),a.steps=[];var j=function(b){var c=0,d=-1;return angular.forEach(a.getEnabledSteps(),function(a){a===b&&(d=c),c++}),d},k=function(b){var c=null;return angular.forEach(a.getEnabledSteps(),function(a){a.wzTitle===b&&(c=a)}),c};a.context={},a.$watch("currentStep",function(b){if(b){var c=a.selectedStep.wzTitle;a.selectedStep&&c!==a.currentStep&&a.goTo(k(a.currentStep))}}),a.$watch("[editMode, steps.length]",function(){var b=a.editMode;if(!angular.isUndefined(b)&&null!==b)if(b)angular.forEach(a.getEnabledSteps(),function(a){a.completed=!0});else{var c=a.currentStepNumber()-1;angular.forEach(a.getEnabledSteps(),function(a,b){b>=c&&(a.completed=!1)})}},!0),this.addStep=function(b){a.steps.push(b),1===a.getEnabledSteps().length&&a.goTo(a.getEnabledSteps()[0])},this.context=a.context,a.getStepNumber=function(a){return j(a)+1},a.goTo=function(b){if(i)h(),a.selectedStep=b,angular.isUndefined(a.currentStep)||(a.currentStep=b.wzTitle),b.selected=!0,a.$emit("wizard:stepChanged",{step:b,index:j(b)}),i=!1;else{var c;a.currentStepNumber()>0?c=a.currentStepNumber()-1:0===a.currentStepNumber()&&(c=0),e.all([g(a.getEnabledSteps()[c],b),f(b)]).then(function(c){c[0]&&c[1]&&(h(),a.selectedStep=b,angular.isUndefined(a.currentStep)||(a.currentStep=b.wzTitle),b.selected=!0,a.$emit("wizard:stepChanged",{step:b,index:j(b)}))})}},a.currentStepNumber=function(){return j(a.selectedStep)+1},a.getEnabledSteps=function(){return a.steps.filter(function(a){return"true"!==a.disabled})},this.currentStepTitle=function(){return a.selectedStep.wzTitle},this.currentStepDescription=function(){return a.selectedStep.description},this.currentStep=function(){return a.selectedStep},this.totalStepCount=function(){return a.getEnabledSteps().length},this.getEnabledSteps=function(){return a.getEnabledSteps()},this.currentStepNumber=function(){return a.currentStepNumber()},this.next=function(b){var c=a.getEnabledSteps(),d=j(a.selectedStep);if(angular.isFunction(b)){if(!b())return;d===c.length-1?this.finish():a.goTo(c[d+1])}b||(a.selectedStep.completed=!0),d===c.length-1?this.finish():a.goTo(c[d+1])},this.goTo=function(b){var c,d=a.getEnabledSteps();c=angular.isNumber(b)?d[b]:k(b),a.goTo(c)},this.finish=function(){a.onFinish&&a.onFinish()},this.previous=function(){var b=j(a.selectedStep);if(0===b)throw new Error("Can't go back. It's already in step 0");a.goTo(a.getEnabledSteps()[b-1])},this.cancel=function(){var b=j(a.selectedStep);if(0===b)throw new Error("Can't go back. It's already in step 0");a.goTo(a.getEnabledSteps()[0])},this.reset=function(){angular.forEach(a.getEnabledSteps(),function(a){a.completed=!1}),this.goTo(0)}}]}}),wizardButtonDirective("wzNext"),wizardButtonDirective("wzPrevious"),wizardButtonDirective("wzFinish"),wizardButtonDirective("wzCancel"),wizardButtonDirective("wzReset"),angular.module("mgo-angular-wizard").factory("WizardHandler",function(){var a={},b={};return a.defaultName="defaultWizard",a.addWizard=function(a,c){b[a]=c},a.removeWizard=function(a){delete b[a]},a.wizard=function(c){var d=c;return c||(d=a.defaultName),b[d]},a}); \ No newline at end of file
diff --git a/www/lib/angular-wizard/karma.conf.js b/www/lib/angular-wizard/karma.conf.js
new file mode 100644
index 00000000..fbc77e33
--- /dev/null
+++ b/www/lib/angular-wizard/karma.conf.js
@@ -0,0 +1,80 @@
+// Karma configuration
+// Generated on Fri Aug 09 2013 14:14:35 GMT-0500 (CDT)
+
+module.exports = function(config) {
+ var configuration = {
+
+ // base path, that will be used to resolve files and exclude
+ basePath: '',
+
+ frameworks: ["jasmine"],
+
+ // list of files / patterns to load in the browser
+ files: [
+ 'https://ajax.googleapis.com/ajax/libs/angularjs/1.3.3/angular.js',
+ 'https://ajax.googleapis.com/ajax/libs/angularjs/1.3.3/angular-mocks.js',
+ 'http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js',
+ 'dist/*.min.js',
+ 'test/*.js'
+ ],
+
+
+ // list of files to exclude
+ exclude: [
+
+ ],
+
+
+ // test results reporter to use
+ // possible values: 'dots', 'progress', 'junit'
+ reporters: ['progress'],
+
+
+ // web server port
+ port: 9876,
+
+
+ // cli runner port
+ runnerPort: 9100,
+
+
+ // enable / disable colors in the output (reporters and logs)
+ colors: true,
+
+
+ // level of logging
+ // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
+ logLevel: config.LOG_INFO,
+
+
+ // enable / disable watching file and executing tests whenever any file changes
+ autoWatch: true,
+
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ browsers: ['Chrome', 'Firefox'],
+
+
+ // If browser does not capture in given timeout [ms], kill it
+ captureTimeout: 60000,
+
+
+ // Continuous Integration mode
+ // if true, it capture browsers, run tests and exit
+ singleRun: false
+
+ };
+
+ if (process.env.TRAVIS) {
+ configuration.browsers = ['Firefox', 'PhantomJS'];
+ }
+
+ config.set(configuration);
+};
diff --git a/www/lib/angular-wizard/license.md b/www/lib/angular-wizard/license.md
new file mode 100644
index 00000000..725d9f26
--- /dev/null
+++ b/www/lib/angular-wizard/license.md
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2013 Martin Gontovnikas http://gon.to/
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/www/lib/angular-wizard/package.json b/www/lib/angular-wizard/package.json
new file mode 100644
index 00000000..5548d085
--- /dev/null
+++ b/www/lib/angular-wizard/package.json
@@ -0,0 +1,58 @@
+{
+ "name": "angular-wizard",
+ "description": "Easy to use Wizard library for AngularJS",
+ "version": "0.6.1",
+ "filename": "angular-wizard.min.js",
+ "main": "./dist/angular-wizard.min.js",
+ "homepage": "https://github.com/mgonto/angular-wizard",
+ "author": "Martin Gontovnikas <martin@gon.to>",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/mgonto/angular-wizard.git"
+ },
+ "engines": {
+ "node": ">= 0.9"
+ },
+ "keywords": [
+ "angular",
+ "client",
+ "browser",
+ "wizard",
+ "form",
+ "steps"
+ ],
+ "maintainers": [
+ {
+ "name": "Martin Gontovnikas",
+ "website": "http://gon.to/"
+ }
+ ],
+ "dependencies": {},
+ "devDependencies": {
+ "grunt": "~0.4.1",
+ "grunt-bower": "*",
+ "grunt-bower-task": "*",
+ "grunt-bump": "0.0.6",
+ "grunt-cli": "^0.1.x",
+ "grunt-contrib-clean": "~0.4.1",
+ "grunt-contrib-concat": "~0.3.0",
+ "grunt-contrib-copy": "~0.4.1",
+ "grunt-contrib-less": "~1.0.0",
+ "grunt-contrib-cssmin": "~0.12.2",
+ "grunt-contrib-uglify": "~0.2.0",
+ "grunt-conventional-changelog": "~0.1.1",
+ "grunt-html2js": "~0.1.3",
+ "grunt-karma": "~0.9.x",
+ "grunt-ng-annotate": "^0.6.0",
+ "grunt-zip": "*",
+ "jasmine-core": "^2.1.3",
+ "karma-chrome-launcher": "^0.1.7",
+ "karma-firefox-launcher": "~0.1.x",
+ "karma-jasmine": "~0.3.x",
+ "karma-phantomjs-launcher": "~0.1.x"
+ },
+ "scripts": {
+ "test": "grunt travis --verbose"
+ },
+ "license": "MIT"
+} \ No newline at end of file
diff --git a/www/lib/angular-wizard/src/angular-wizard.less b/www/lib/angular-wizard/src/angular-wizard.less
new file mode 100644
index 00000000..5f13666a
--- /dev/null
+++ b/www/lib/angular-wizard/src/angular-wizard.less
@@ -0,0 +1,179 @@
+@wz-color-default: #E6E6E6;
+@wz-color-current: #808080;
+@wz-color-done: #339933;
+@wz-color-editing: #FF0000;
+
+.steps-indicator {
+ /* ---- steps quantity ---- */
+
+
+ right: 0;
+ bottom: 0;
+ left: 0;
+ margin: 0;
+ padding: 20px 0 0 0;
+ height: 30px;
+ list-style: none;
+
+
+
+ &:before {
+ background-color: @wz-color-default;
+ content: '';
+ position: absolute;
+ height: 1px;
+ }
+
+ &.steps-2:before {
+ left: ~'calc(100% / 2 / 2)';
+ right: ~'calc(100% / 2 / 2)';
+ }
+
+ &.steps-3:before {
+ left: ~'calc(100% / 3 / 2)';
+ right: ~'calc(100% / 3 / 2)';
+ }
+
+ &.steps-4:before {
+ left: ~'calc(100% / 4 / 2)';
+ right: ~'calc(100% / 4 / 2)';
+ }
+
+ &.steps-5:before {
+ left: ~'calc(100% / 5 / 2)';
+ right: ~'calc(100% / 5 / 2)';
+ }
+
+ &.steps-6:before {
+ left: ~'calc(100% / 6 / 2)';
+ right: ~'calc(100% / 6 / 2)';
+ }
+
+ &.steps-7:before {
+ left: ~'calc(100% / 7 / 2)';
+ right: ~'calc(100% / 7 / 2)';
+ }
+
+ &.steps-8:before {
+ left: ~'calc(100% / 8 / 2)';
+ right: ~'calc(100% / 8 / 2)';
+ }
+
+ &.steps-9:before {
+ left: ~'calc(100% / 9 / 2)';
+ right: ~'calc(100% / 9 / 2)';
+ }
+
+ &.steps-10:before {
+ left: ~'calc(100% / 10 / 2)';
+ right: ~'calc(100% / 10 / 2)';
+ }
+
+ /* --- http://www.paulirish.com/2012/box-sizing-border-box-ftw/ ---- */
+ * {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+
+
+ li {
+ position: relative;
+ float: left;
+ margin: 0;
+ padding: 0;
+ padding-top: 10px;
+ text-align: center;
+ line-height: 15px;
+
+ a {
+ color: @wz-color-current;
+ text-decoration: none;
+ text-transform: uppercase;
+ font-weight: bold;
+ transition: 0.25s;
+ cursor: pointer;
+
+ &:before {
+ position: absolute;
+ top: -7px;
+ left: ~'calc(50% - 7px)';
+ width: 14px;
+ height: 14px;
+ border-radius: 100%;
+ background-color: @wz-color-default;
+ content: '';
+ transition: 0.25s;
+ }
+
+ &:hover {
+ color: darken(@wz-color-current, 20%);
+ }
+ }
+ }
+
+ &.steps-2 li {
+ width: ~'calc(100% / 2)';
+ }
+
+ &.steps-3 li {
+ width: ~'calc(100% / 3)';
+ }
+
+ &.steps-4 li {
+ width: ~'calc(100% / 4)';
+ }
+
+ &.steps-5 li {
+ width: ~'calc(100% / 5)';
+ }
+
+ &.steps-6 li {
+ width: ~'calc(100% / 6)';
+ }
+
+ &.steps-7 li {
+ width: ~'calc(100% / 7)';
+ }
+
+ &.steps-8 li {
+ width: ~'calc(100% / 8)';
+ }
+
+ &.steps-9 li {
+ width: ~'calc(100% / 9)';
+ }
+
+ &.steps-10 li {
+ width: ~'calc(100% / 10)';
+ }
+
+ &.steps-11 li {
+ width: ~'calc(100% / 11)';
+ }
+
+ li.default {
+ pointer-events: none;
+
+ a:hover {
+ color: @wz-color-current;
+ }
+ }
+
+ li.current,
+ li.editing {
+ pointer-events: none;
+ }
+
+ li.current a:before {
+ background-color: @wz-color-current;
+ }
+
+ li.done a:before {
+ background-color: @wz-color-done;
+ }
+
+ li.editing a:before {
+ background-color: @wz-color-editing;
+ }
+}
diff --git a/www/lib/angular-wizard/src/angularModule.js b/www/lib/angular-wizard/src/angularModule.js
new file mode 100644
index 00000000..816d5bec
--- /dev/null
+++ b/www/lib/angular-wizard/src/angularModule.js
@@ -0,0 +1 @@
+angular.module('mgo-angular-wizard', ['templates-angularwizard']);
diff --git a/www/lib/angular-wizard/src/step.html b/www/lib/angular-wizard/src/step.html
new file mode 100644
index 00000000..59f13f29
--- /dev/null
+++ b/www/lib/angular-wizard/src/step.html
@@ -0,0 +1,2 @@
+<section ng-show="selected" ng-class="{current: selected, done: completed}" class="step" ng-transclude>
+</section> \ No newline at end of file
diff --git a/www/lib/angular-wizard/src/step.js b/www/lib/angular-wizard/src/step.js
new file mode 100644
index 00000000..2a266255
--- /dev/null
+++ b/www/lib/angular-wizard/src/step.js
@@ -0,0 +1,23 @@
+angular.module('mgo-angular-wizard').directive('wzStep', function() {
+ return {
+ restrict: 'EA',
+ replace: true,
+ transclude: true,
+ scope: {
+ wzTitle: '@',
+ canenter : '=',
+ canexit : '=',
+ disabled: '@?wzDisabled',
+ description: '@',
+ wzData: '='
+ },
+ require: '^wizard',
+ templateUrl: function(element, attributes) {
+ return attributes.template || "step.html";
+ },
+ link: function($scope, $element, $attrs, wizard) {
+ $scope.title = $scope.wzTitle;
+ wizard.addStep($scope);
+ }
+ };
+});
diff --git a/www/lib/angular-wizard/src/wizard.html b/www/lib/angular-wizard/src/wizard.html
new file mode 100644
index 00000000..0e8c660b
--- /dev/null
+++ b/www/lib/angular-wizard/src/wizard.html
@@ -0,0 +1,8 @@
+<div>
+ <div class="steps" ng-transclude></div>
+ <ul class="steps-indicator steps-{{getEnabledSteps().length}}" ng-if="!hideIndicators">
+ <li ng-class="{default: !step.completed && !step.selected, current: step.selected && !step.completed, done: step.completed && !step.selected, editing: step.selected && step.completed}" ng-repeat="step in getEnabledSteps()">
+ <a ng-click="goTo(step)">{{step.title || step.wzTitle}}</a>
+ </li>
+ </ul>
+</div>
diff --git a/www/lib/angular-wizard/src/wizard.js b/www/lib/angular-wizard/src/wizard.js
new file mode 100644
index 00000000..f8200004
--- /dev/null
+++ b/www/lib/angular-wizard/src/wizard.js
@@ -0,0 +1,340 @@
+//wizard directive
+angular.module('mgo-angular-wizard').directive('wizard', function() {
+ return {
+ restrict: 'EA',
+ replace: true,
+ transclude: true,
+ scope: {
+ currentStep: '=',
+ onFinish: '&',
+ hideIndicators: '=',
+ editMode: '=',
+ name: '@'
+ },
+ templateUrl: function(element, attributes) {
+ return attributes.template || "wizard.html";
+ },
+
+ //controller for wizard directive, treat this just like an angular controller
+ controller: ['$scope', '$element', '$log', 'WizardHandler', '$q', function($scope, $element, $log, WizardHandler, $q) {
+ //this variable allows directive to load without having to pass any step validation
+ var firstRun = true;
+ //creating instance of wizard, passing this as second argument allows access to functions attached to this via Service
+ WizardHandler.addWizard($scope.name || WizardHandler.defaultName, this);
+
+ $scope.$on('$destroy', function() {
+ WizardHandler.removeWizard($scope.name || WizardHandler.defaultName);
+ });
+
+ //steps array where all the scopes of each step are added
+ $scope.steps = [];
+
+ var stepIdx = function(step) {
+ var idx = 0;
+ var res = -1;
+ angular.forEach($scope.getEnabledSteps(), function(currStep) {
+ if (currStep === step) {
+ res = idx;
+ }
+ idx++;
+ });
+ return res;
+ };
+
+ var stepByTitle = function(titleToFind) {
+ var foundStep = null;
+ angular.forEach($scope.getEnabledSteps(), function(step) {
+ if (step.wzTitle === titleToFind) {
+ foundStep = step;
+ }
+ });
+ return foundStep;
+ };
+
+ //access to context object for step validation
+ $scope.context = {};
+
+ //watching changes to currentStep
+ $scope.$watch('currentStep', function(step) {
+ //checking to make sure currentStep is truthy value
+ if (!step) return;
+ //setting stepTitle equal to current step title or default title
+ var stepTitle = $scope.selectedStep.wzTitle;
+ if ($scope.selectedStep && stepTitle !== $scope.currentStep) {
+ //invoking goTo() with step title as argument
+ $scope.goTo(stepByTitle($scope.currentStep));
+ }
+
+ });
+
+ //watching steps array length and editMode value, if edit module is undefined or null the nothing is done
+ //if edit mode is truthy, then all steps are marked as completed
+ $scope.$watch('[editMode, steps.length]', function() {
+ var editMode = $scope.editMode;
+ if (angular.isUndefined(editMode) || (editMode === null)) return;
+
+ if (editMode) {
+ angular.forEach($scope.getEnabledSteps(), function(step) {
+ step.completed = true;
+ });
+ } else {
+ var completedStepsIndex = $scope.currentStepNumber() - 1;
+ angular.forEach($scope.getEnabledSteps(), function(step, stepIndex) {
+ if(stepIndex >= completedStepsIndex) {
+ step.completed = false;
+ }
+ });
+ }
+ }, true);
+
+ //called each time step directive is loaded
+ this.addStep = function(step) {
+ //pushing the scope of directive onto step array
+ $scope.steps.push(step);
+ //if this is first step being pushed then goTo that first step
+ if ($scope.getEnabledSteps().length === 1) {
+ //goTo first step
+ $scope.goTo($scope.getEnabledSteps()[0]);
+ }
+ };
+
+ this.context = $scope.context;
+
+ $scope.getStepNumber = function(step) {
+ return stepIdx(step) + 1;
+ };
+
+ $scope.goTo = function(step) {
+ //if this is the first time the wizard is loading it bi-passes step validation
+ if(firstRun){
+ //deselect all steps so you can set fresh below
+ unselectAll();
+ $scope.selectedStep = step;
+ //making sure current step is not undefined
+ if (!angular.isUndefined($scope.currentStep)) {
+ $scope.currentStep = step.wzTitle;
+ }
+ //setting selected step to argument passed into goTo()
+ step.selected = true;
+ //emit event upwards with data on goTo() invoktion
+ $scope.$emit('wizard:stepChanged', {step: step, index: stepIdx(step)});
+ //setting variable to false so all other step changes must pass validation
+ firstRun = false;
+ } else {
+ //createing variables to capture current state that goTo() was invoked from and allow booleans
+ var thisStep;
+ //getting data for step you are transitioning out of
+ if($scope.currentStepNumber() > 0){
+ thisStep = $scope.currentStepNumber() - 1;
+ } else if ($scope.currentStepNumber() === 0){
+ thisStep = 0;
+ }
+ //$log.log('steps[thisStep] Data: ', $scope.getEnabledSteps()[thisStep].canexit);
+ $q.all([canExitStep($scope.getEnabledSteps()[thisStep], step), canEnterStep(step)]).then(function(data) {
+ if(data[0] && data[1]){
+ //deselect all steps so you can set fresh below
+ unselectAll();
+
+ //$log.log('value for canExit argument: ', $scope.currentStep.canexit);
+ $scope.selectedStep = step;
+ //making sure current step is not undefined
+ if(!angular.isUndefined($scope.currentStep)){
+ $scope.currentStep = step.wzTitle;
+ }
+ //setting selected step to argument passed into goTo()
+ step.selected = true;
+ //emit event upwards with data on goTo() invoktion
+ $scope.$emit('wizard:stepChanged', {step: step, index: stepIdx(step)});
+ //$log.log('current step number: ', $scope.currentStepNumber());
+ }
+ });
+ }
+ };
+
+ function canEnterStep(step) {
+ var defer,
+ canEnter;
+ //If no validation function is provided, allow the user to enter the step
+ if(step.canenter === undefined){
+ return true;
+ }
+ //If canenter is a boolean value instead of a function, return the value
+ if(typeof step.canenter === 'boolean'){
+ return step.canenter;
+ }
+ //Check to see if the canenter function is a promise which needs to be returned
+ canEnter = step.canenter($scope.context);
+ if(angular.isFunction(canEnter.then)){
+ defer = $q.defer();
+ canEnter.then(function(response){
+ defer.resolve(response);
+ });
+ return defer.promise;
+ } else {
+ return canEnter === true;
+ }
+ }
+
+ function canExitStep(step, stepTo) {
+ var defer,
+ canExit;
+ //Exiting the step should be allowed if no validation function was provided or if the user is moving backwards
+ if(typeof(step.canexit) === 'undefined' || $scope.getStepNumber(stepTo) < $scope.currentStepNumber()){
+ return true;
+ }
+ //If canexit is a boolean value instead of a function, return the value
+ if(typeof step.canexit === 'boolean'){
+ return step.canexit;
+ }
+ //Check to see if the canexit function is a promise which needs to be returned
+ canExit = step.canexit($scope.context);
+ if(angular.isFunction(canExit.then)){
+ defer = $q.defer();
+ canExit.then(function(response){
+ defer.resolve(response);
+ });
+ return defer.promise;
+ } else {
+ return canExit === true;
+ }
+ }
+
+ $scope.currentStepNumber = function() {
+ //retreive current step number
+ return stepIdx($scope.selectedStep) + 1;
+ };
+
+ $scope.getEnabledSteps = function() {
+ return $scope.steps.filter(function(step){
+ return step.disabled !== 'true';
+ });
+ };
+
+ //unSelect All Steps
+ function unselectAll() {
+ //traverse steps array and set each "selected" property to false
+ angular.forEach($scope.getEnabledSteps(), function (step) {
+ step.selected = false;
+ });
+ //set selectedStep variable to null
+ $scope.selectedStep = null;
+ }
+
+ //ALL METHODS ATTACHED TO this ARE ACCESSIBLE VIA WizardHandler.wizard().methodName()
+
+ this.currentStepTitle = function(){
+ return $scope.selectedStep.wzTitle;
+ };
+
+ this.currentStepDescription = function(){
+ return $scope.selectedStep.description;
+ };
+
+ this.currentStep = function(){
+ return $scope.selectedStep;
+ };
+
+ this.totalStepCount = function() {
+ return $scope.getEnabledSteps().length;
+ }
+
+ //Access to enabled steps from outside
+ this.getEnabledSteps = function(){
+ return $scope.getEnabledSteps();
+ };
+
+ //Access to current step number from outside
+ this.currentStepNumber = function(){
+ return $scope.currentStepNumber();
+ };
+ //method used for next button within step
+ this.next = function(callback) {
+ var enabledSteps = $scope.getEnabledSteps();
+ //setting variable equal to step you were on when next() was invoked
+ var index = stepIdx($scope.selectedStep);
+ //checking to see if callback is a function
+ if(angular.isFunction(callback)){
+ if(callback()){
+ if (index === enabledSteps.length - 1) {
+ this.finish();
+ } else {
+ //invoking goTo() with step number next in line
+ $scope.goTo(enabledSteps[index + 1]);
+ }
+ } else {
+ return;
+ }
+ }
+ if (!callback) {
+ //completed property set on scope which is used to add class/remove class from progress bar
+ $scope.selectedStep.completed = true;
+ }
+ //checking to see if this is the last step. If it is next behaves the same as finish()
+ if (index === enabledSteps.length - 1) {
+ this.finish();
+ } else {
+ //invoking goTo() with step number next in line
+ $scope.goTo(enabledSteps[index + 1]);
+ }
+
+ };
+
+ //used to traverse to any step, step number placed as argument
+ this.goTo = function(step) {
+ var enabledSteps = $scope.getEnabledSteps();
+ var stepTo;
+ //checking that step is a Number
+ if (angular.isNumber(step)) {
+ stepTo = enabledSteps[step];
+ } else {
+ //finding the step associated with the title entered as goTo argument
+ stepTo = stepByTitle(step);
+ }
+ //going to step
+ $scope.goTo(stepTo);
+ };
+
+ //calls finish() which calls onFinish() which is declared on an attribute and linked to controller via wizard directive.
+ this.finish = function() {
+ if ($scope.onFinish) {
+ $scope.onFinish();
+ }
+ };
+
+ this.previous = function() {
+ //getting index of current step
+ var index = stepIdx($scope.selectedStep);
+ //ensuring you aren't trying to go back from the first step
+ if (index === 0) {
+ throw new Error("Can't go back. It's already in step 0");
+ } else {
+ //go back one step from current step
+ $scope.goTo($scope.getEnabledSteps()[index - 1]);
+ }
+ };
+
+ //cancel is alias for previous.
+ this.cancel = function() {
+ //getting index of current step
+ var index = stepIdx($scope.selectedStep);
+ //ensuring you aren't trying to go back from the first step
+ if (index === 0) {
+ throw new Error("Can't go back. It's already in step 0");
+ } else {
+ //go back one step from current step
+ $scope.goTo($scope.getEnabledSteps()[0]);
+ }
+ };
+
+ //reset
+ this.reset = function(){
+ //traverse steps array and set each "completed" property to false
+ angular.forEach($scope.getEnabledSteps(), function (step) {
+ step.completed = false;
+ });
+ //go to first step
+ this.goTo(0);
+ };
+ }]
+ };
+}); \ No newline at end of file
diff --git a/www/lib/angular-wizard/src/wizardButtons.js b/www/lib/angular-wizard/src/wizardButtons.js
new file mode 100644
index 00000000..0afb46f8
--- /dev/null
+++ b/www/lib/angular-wizard/src/wizardButtons.js
@@ -0,0 +1,26 @@
+function wizardButtonDirective(action) {
+ angular.module('mgo-angular-wizard')
+ .directive(action, function() {
+ return {
+ restrict: 'A',
+ replace: false,
+ require: '^wizard',
+ link: function($scope, $element, $attrs, wizard) {
+
+ $element.on("click", function(e) {
+ e.preventDefault();
+ $scope.$apply(function() {
+ $scope.$eval($attrs[action]);
+ wizard[action.replace("wz", "").toLowerCase()]();
+ });
+ });
+ }
+ };
+ });
+}
+
+wizardButtonDirective('wzNext');
+wizardButtonDirective('wzPrevious');
+wizardButtonDirective('wzFinish');
+wizardButtonDirective('wzCancel');
+wizardButtonDirective('wzReset');
diff --git a/www/lib/angular-wizard/src/wizardHandler.js b/www/lib/angular-wizard/src/wizardHandler.js
new file mode 100644
index 00000000..8957c941
--- /dev/null
+++ b/www/lib/angular-wizard/src/wizardHandler.js
@@ -0,0 +1,26 @@
+angular.module('mgo-angular-wizard').factory('WizardHandler', function() {
+ var service = {};
+
+ var wizards = {};
+
+ service.defaultName = "defaultWizard";
+
+ service.addWizard = function(name, wizard) {
+ wizards[name] = wizard;
+ };
+
+ service.removeWizard = function(name) {
+ delete wizards[name];
+ };
+
+ service.wizard = function(name) {
+ var nameToUse = name;
+ if (!name) {
+ nameToUse = service.defaultName;
+ }
+
+ return wizards[nameToUse];
+ };
+
+ return service;
+});
diff --git a/www/lib/angular-wizard/test/angularWizardSpec.js b/www/lib/angular-wizard/test/angularWizardSpec.js
new file mode 100644
index 00000000..2b155dbb
--- /dev/null
+++ b/www/lib/angular-wizard/test/angularWizardSpec.js
@@ -0,0 +1,299 @@
+describe( 'AngularWizard', function() {
+ var $compile, $q, $rootScope, $timeout, WizardHandler;
+
+ beforeEach(module('mgo-angular-wizard'));
+
+
+ beforeEach(inject(function(_$compile_, _$q_, _$rootScope_, _$timeout_, _WizardHandler_) {
+ $compile = _$compile_;
+ $q = _$q_;
+ $rootScope = _$rootScope_;
+ $timeout = _$timeout_;
+ WizardHandler = _WizardHandler_;
+ }));
+
+ /**
+ * Create the generic view with wizard to test
+ * @param {Scope} scope A scope to bind to
+ * @return {[DOM element]} A DOM element compiled
+ */
+ function createGenericView(scope) {
+ scope.referenceCurrentStep = null;
+ var element = angular.element('<wizard on-finish="finishedWizard()" current-step="referenceCurrentStep" ng-init="msg = 14" >'
+ + ' <wz-step wz-title="Starting" canenter="enterValidation" description="Step description">'
+ + ' <h1>This is the first step</h1>'
+ + ' <p>Here you can use whatever you want. You can use other directives, binding, etc.</p>'
+ + ' <input type="submit" wz-next value="Continue" />'
+ + ' </wz-step>'
+ + ' <wz-step wz-title="Dynamic" wz-disabled="{{dynamicStepDisabled == \'Y\'}}">'
+ + ' <h1>Dynamic {{dynamicStepDisabled}}</h1>'
+ + ' <p>You have continued here!</p>'
+ + ' <input type="submit" wz-next value="Go on" />'
+ + ' </wz-step>'
+ + ' <wz-step wz-title="Continuing" canexit="stepValidation">'
+ + ' <h1>Continuing</h1>'
+ + ' <p>You have continued here!</p>'
+ + ' <input type="submit" wz-next value="Go on" />'
+ + ' </wz-step>'
+ + ' <wz-step wz-title="More steps" canenter="enterValidation">'
+ + ' <p>Even more steps!!</p>'
+ + ' <input type="submit" wz-next value="Finish now" />'
+ + ' </wz-step>'
+ + '</wizard>');
+ var elementCompiled = $compile(element)(scope);
+ $rootScope.$digest();
+ return elementCompiled;
+ }
+
+ it("should correctly create the wizard", function() {
+ var scope = $rootScope.$new();
+ var view = createGenericView(scope);
+ expect(WizardHandler).toBeTruthy();
+ expect(view.find('section').length).toEqual(4);
+ // expect the correct step to be desirable one
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ });
+ it( "should go to the next step", function() {
+ var scope = $rootScope.$new();
+ var view = createGenericView(scope);
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Dynamic');
+ });
+ it( "should render only those steps which are enabled", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ });
+ it( "should enable or disable dynamic steps based on conditions", function() {
+ var scope = $rootScope.$new();
+ var view = createGenericView(scope);
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ scope.dynamicStepDisabled = 'Y';
+ $rootScope.$digest();
+ WizardHandler.wizard().goTo(2);
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('More steps');
+ });
+ it( "should return to a previous step", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ WizardHandler.wizard().previous();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ });
+ it( "should go to a step specified by name", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().goTo('More steps');
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('More steps');
+ });
+ it( "should go to a step specified by index", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().goTo(2);
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('More steps');
+ });
+ it( "should go to next step becasue callback is truthy", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next(function(){
+ return true
+ });
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ });
+ it( "should NOT go to next step because callback is falsey", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next(function(){
+ return false
+ });
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ });
+ it( "should go to next step because CANEXIT is UNDEFINED", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ });
+ it( "should go to next step because CANEXIT is TRUE", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ scope.stepValidation = function(){
+ return true;
+ };
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('More steps');
+ });
+ it( "should NOT go to next step because CANEXIT is FALSE", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ scope.stepValidation = function(){
+ return false;
+ };
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ });
+ it( "should go to next step because CANENTER is TRUE", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ scope.enterValidation = function(){
+ return true;
+ };
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('More steps');
+ });
+ it( "should NOT go to next step because CANENTER is FALSE", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ scope.enterValidation = function(){
+ return false;
+ };
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ });
+ it( "should NOT return to a previous step. Although CANEXIT is false and we are heading to a previous state, the can enter validation is false", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ scope.stepValidation = function(){
+ return false;
+ };
+ scope.enterValidation = function(){
+ return false;
+ };
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ WizardHandler.wizard().previous();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ });
+ it( "should return to a previous step even though CANEXIT is false", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ scope.stepValidation = function(){
+ return false;
+ };
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ WizardHandler.wizard().previous();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ });
+ it( "should go to the next step because the promise that CANENTER returns resolves to true", function(done) {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ scope.enterValidation = function(){
+ var deferred = $q.defer();
+ $timeout(function () {
+ deferred.resolve(true);
+ done();
+ });
+ return deferred.promise;
+ };
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ WizardHandler.wizard().next();
+ $timeout.flush();
+ expect(scope.referenceCurrentStep).toEqual('More steps');
+ });
+ it( "should go to the next step because CANEXIT is set to true", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ scope.exitValidation = true;
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Continuing');
+ WizardHandler.wizard().next();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('More steps');
+ });
+ it( "should finish", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var flag = false;
+ scope.finishedWizard = function() { flag = true; };
+ var view = createGenericView(scope);
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().finish();
+ expect(flag).toBeTruthy();
+ $rootScope.$digest();
+ });
+ it( "should go to first step when reset is called", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ WizardHandler.wizard().goTo(2);
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('More steps');
+ WizardHandler.wizard().reset();
+ $rootScope.$digest();
+ expect(scope.referenceCurrentStep).toEqual('Starting');
+ });
+ it( "step description should be accessible", function() {
+ var scope = $rootScope.$new();
+ scope.dynamicStepDisabled = 'Y';
+ var view = createGenericView(scope);
+ expect(view.isolateScope().steps[0].description).toEqual('Step description');
+ });
+});
diff --git a/www/templates/wizard.html b/www/templates/wizard.html
new file mode 100644
index 00000000..ee29fe21
--- /dev/null
+++ b/www/templates/wizard.html
@@ -0,0 +1,91 @@
+<ion-view view-title="Wizard" ng-cloak cache-view="false" >
+
+ <ion-nav-buttons side="left">
+ <button class="button button-icon button-clear ion-navicon" ng-click="openMenu()"></button>
+
+
+ </ion-nav-buttons>
+
+
+ <ion-content class="padding" overflow-scroll="false">
+
+ <wizard on-finish="finishedWizard()">
+
+ <wz-step wz-title="1" canexit="exitPortal">
+ <h4>Welcome to zmWizard</h4>
+ <p>Configuring ZoneMinder can be a pain. Lets see if zmWizard can help. In the next few screens, I will ask you some simple questions and do my best to guess the settings for you.</p>
+
+ <h4>What is your Zoneminder portal url?</h4>
+ <label class="item item-input">
+ <input type="text" placeholder="typically http://server/zm" ng-model="wizard.portalurl">
+ </label>
+
+ <a class="button icon-left ion-information-circled button-clear button-dark" ng-click="toggleTip()">{{wizard.tiptext}}</a>
+
+
+ <div class="wizardtip" ng-show="wizard.tipshow">
+ <b>Tip: </b>Confused? You can easily find out your portal URL by noting down the url you see on your browser when accessing ZoneMinder Console.
+
+ <img src="img/portalurl.png" width="30%">
+ </div>
+
+ <br/><input type="button" wz-next value="Next" />
+
+ </wz-step>
+
+
+
+ <wz-step wz-title="2" canexit="exitAuth" >
+ <h4>Portal Authentication</h4>
+ <p>Lets talk about how you have configured authentication If you have enabled authentication, toggle this button</p>
+ <ion-toggle ng-change="toggleAuth" ng-model="wizard.useauth" toggle-class="toggle-calm">I use authentication</ion-toggle>
+
+ <ion-toggle ng-show="wizard.useauth" ng-model="wizard.usezmauth" toggle-class="toggle-calm">I use ZM authentication</ion-toggle>
+ <label class="item item-input item-floating-label" ng-show="wizard.usezmauth">
+ <span class="input-label">user name</span>
+ <input type="text" ng-model="wizard.zmuser" placeholder="zm auth username" >
+ </label>
+ <label class="item item-input item-floating-label" ng-show="wizard.usezmauth">
+ <span class="input-label">password</span>
+ <input type="password" ng-model="wizard.zmpassword" placeholder="zm auth password" >
+ </label>
+
+
+ <ion-toggle ng-show="wizard.useauth" ng-model="wizard.usebasicauth" toggle-class="toggle-calm">I use Basic authentication</ion-toggle>
+ <label class="item item-input item-floating-label" ng-show="wizard.usebasicauth">
+ <span class="input-label">user name</span>
+ <input type="text" ng-model="wizard.basicuser" placeholder="basic auth username" >
+ </label>
+ <label class="item item-input item-floating-label" ng-show="wizard.usebasicauth">
+ <span class="input-label">password</span>
+ <input type="password" ng-model="wizard.basicpassword" placeholder="basic auth password" >
+ </label>
+
+
+ <a class="button icon-left ion-information-circled button-clear button-dark" ng-click="toggleTip()">{{wizard.tiptext}}</a>
+
+
+ <div class="wizardtip" ng-show="wizard.tipshow">
+ <b>Tip: </b>Confused? <i>ZM Auth</i> is the authentication used when you enable OPT_USE_AUTH in the ZM console options screen.<br/>
+ <i>Basic Auth</i> is when you configure a username and password in your webserver. If you are using LDAP authentication, its likely basic auth.
+ </div>
+
+ <br/>
+ <input type="button" wz-previous value="Prev" />
+ <input type="button" wz-next value="Next" />
+
+ </wz-step>
+
+
+ <wz-step wz-title="3">
+ <h4>Lets try and validate your inputs</h4>
+ <p>I am now going to try and log into the portal using:
+ <br/>Portal: {{wizard.portalurl}}
+
+ </p>
+ <input type="button" wz-next value="Finish now" />
+ </wz-step>
+</wizard>
+ </ion-content>
+
+</ion-view> \ No newline at end of file