<commit_before>import '../testHelper';
import AlertActions from '../../app/assets/javascripts/actions/alert_actions.js';
import AlertsStore from '../../app/assets/javascripts/stores/alerts_store.js';

import sinon from 'sinon';

describe('AlertActions', () => {
  beforeEach(() => {
    sinon.stub($, 'ajax').yieldsTo('success', { success: true });
  });
  afterEach(() => {
    $.ajax.restore();
  });

  it('makes an ajax call for submitNeedHelpAlert', () => {
    AlertActions.submitNeedHelpAlert({}).then(() => {
      expect(AlertsStore.getNeedHelpAlertSubmitted()).to.be.true;
    });
    expect($.ajax.calledOnce).to.be.true;
    AlertActions.resetNeedHelpAlert().then(() => {
      expect(AlertsStore.getNeedHelpAlertSubmitted()).to.be.false;
      expect(AlertsStore.getNeedHelpAlertSubmitting()).to.be.false;
    });
  });
});
<commit_msg>Fix AlertActions test's handling of async functions<commit_after>import '../testHelper';
import AlertActions from '../../app/assets/javascripts/actions/alert_actions.js';
import AlertsStore from '../../app/assets/javascripts/stores/alerts_store.js';

import sinon from 'sinon';

describe('AlertActions', () => {
  beforeEach(() => {
    sinon.stub($, "ajax").yieldsTo("success", { success: true });
  });
  afterEach(() => {
    $.ajax.restore();
    AlertActions.resetNeedHelpAlert();
  });

  it('.submitNeedHelpAlert sets getNeedHelpAlertSubmitting to true', (done) => {
    AlertActions.submitNeedHelpAlert({}).then(() => {
      expect(AlertsStore.getNeedHelpAlertSubmitting()).to.be.true;
      done();
    });
  });

  it('.createNeedHelpAlert sets getNeedHelpAlertSubmitted to true', (done) => {
    AlertActions.createNeedHelpAlert({}).then(() => {
      expect(AlertsStore.getNeedHelpAlertSubmitted()).to.be.true;
      done();
    });
  });
});
<|endoftext|>


<commit_before>import expect from 'expect';
import defaultFont from '../fonts/ANSI_Shadow';
import simpleFont from '../fonts/simple';
import fontAnalyse from '../src/asciiNumbersFontUtils';

describe('ASCINumbersFontUtils', () => {
	describe('Passing valid font', () => {
		const fontStatistic = fontAnalyse(defaultFont);
		it('should return object with font height and width', () => {
			expect(fontStatistic.height).toBe(6);
			expect(fontStatistic.width).toBe(9);
		});
	});

	describe('Passing simple font', () => {
		const fontStatistic = fontAnalyse(simpleFont);
		it('should return height 1 and width 1', () => {
			expect(fontStatistic.height).toBe(1);
			expect(fontStatistic.width).toBe(1);
		});
	});

	describe('Passing invalid font', () => {
		const invalidFont = { 0: ['0'], 1: ['1'] };
		let error;

		try {
			fontAnalyse(invalidFont);
		} catch (exception) {
			error = exception;
		}

		it('should throw error', () => {
			expect(error).toBe('Font does not contain letter 2.');
		});
	});
});
<commit_msg>Fix not working test<commit_after>import expect from 'expect';
import defaultFont from '../fonts/ANSI_Shadow';
import simpleFont from '../fonts/simple';
import fontAnalyse from '../src/asciiNumbersFontUtils';

describe('ASCINumbersFontUtils', () => {
	describe('Passing valid font', () => {
		const fontStatistic = fontAnalyse(defaultFont);
		it('should return object with font height and width', () => {
			expect(fontStatistic.height).toBe(6);
			expect(fontStatistic.width).toBe(9);
		});
	});

	describe('Passing simple font', () => {
		const fontStatistic = fontAnalyse(simpleFont);
		it('should return height 1 and width 1', () => {
			expect(fontStatistic.height).toBe(1);
			expect(fontStatistic.width).toBe(1);
		});
	});

	describe('Passing invalid font', () => {
		const invalidFont = { 0: ['0'], 1: ['1'] };
		let errorMessage;

		try {
			fontAnalyse(invalidFont);
		} catch (exception) {
			errorMessage = exception.message;
		}

		it('should throw error', () => {
			expect(errorMessage).toBe('Font does not contain letter 2.');
		});
	});
});
<|endoftext|>


<commit_before>module.exports = [
  'div',
  'p',
  'h3',
  'pre',
  'blockquote',
  'textarea',
  'input',
  'span',
  'a',
  'button'
]
<commit_msg>testbench editable tags: remove button<commit_after>module.exports = [
  'div',
  'p',
  'h3',
  'pre',
  'blockquote',
  'textarea',
  'input',
  'span',
  'a'
]
<|endoftext|>


<commit_before>beforeEach(function () {
	Blockly.inject(document.body.appendChild(document.createElement("div")));
});

describe("goBlockly:blocks:simpleState:js", function() {
    it("should generate a text length lookup", function() {
        var text = Blockly.Block.obtain(Blockly.mainWorkspace, 'text');
        text.setFieldValue('foo', 'TEXT');

        var block = Blockly.Block.obtain(Blockly.mainWorkspace, 'simpleState');
        block.getInput('NAME').connection.connect(text.outputConnection);

        assert.equal(Blockly.JavaScript.workspaceToCode(), "'foo'.length");
    });
});
<commit_msg>Adds afterEach to tests to remove divs after testing is complete.<commit_after>var el;

beforeEach(function () {
	el = document.createElement("div");
	Blockly.inject(document.body.appendChild(el));
});

afterEach(function () {
	document.body.removeChild(el);
});

describe("goBlockly:blocks:simpleState:js", function() {
    it("should generate a text length lookup", function() {
        var text = Blockly.Block.obtain(Blockly.mainWorkspace, 'text');
        text.setFieldValue('foo', 'TEXT');

        var block = Blockly.Block.obtain(Blockly.mainWorkspace, 'simpleState');
        block.getInput('NAME').connection.connect(text.outputConnection);

        assert.equal(Blockly.JavaScript.workspaceToCode(), "'foo'.length");
    });
});
<|endoftext|>


<commit_before>const test = require('tap').test

// Remember to run `npm run test:build` before executing,
// otherwise the lib directory will not exist.

require('../../lib/ngn')
// require('../lib/eventemitter')
// require('../lib/net/bootstrap')
// require('../lib/utility/bootstrap')
// require('../lib/data/bootstrap')
// require('../lib/tasks/bootstrap')

test('Namespace', (t) => {
  t.ok(NGN !== undefined, 'NGN namespace is recognized.')
  t.ok(MissingNgnDependencyError !== undefined, 'NGN missing dependency error is recognized.')
  t.end()
})

test('Method Existance', (t) => {
  const methodList = [
    'global',
    'define',
    'public',
    'private',
    'const',
    'privateconst',
    'get',
    'set',
    'getset',
    'extend',
    'inherit',
    'slice',
    'splice',
    'nullIf',
    'nullif',
    'converge',
    'coalesce',
    'coalesceb',
    'nodelike',
    'dedupe',
    'typeof',
    'forceArray',
    'forceBoolean',
    'forceNumber',
    'processStackItem',
    'stack',
    'isFn',
    'wrap',
    'wrapClass',
    'deprecate',
    'deprecateClass',
    'getObjectMissingPropertyNames',
    'getObjectExtraneousPropertyNames',
    'objectHasAll',
    'objectHasAny',
    'objectHasExactly',
    'objectRequires',
    'needs',
    'createAlias',
    // 'CustomExceptionClass',
    // 'CustomException',
    'createException',
    'getType',
    'LEDGER_EVENT',
    'WARNING_EVENT',
    'INFO_EVENT',
    'ERROR_EVENT',
    'WARN',
    'INFO',
    'ERROR',

    // Classes
    'EventEmitter',
    'BUS',
    'NET',
    'DATA',
    'Task',
    'Tasks', // Deprecated in favor of Queue
    'Queue',
    'UTILITY',

    // Extras
    'version'
  ]

  for (let method of methodList) {
    t.ok(NGN.hasOwnProperty(method), `NGN.${method} exists.`)
  }

  let keys = Object.getOwnPropertyNames(NGN)

  for (let key of keys) {
    if (methodList.indexOf(key) < 0) {
      t.fail(`NGN.${key} has no sanity check.`)
    }
  }

  t.end()
})
<commit_msg>Cleanup isolated test suites.<commit_after>const test = require('tap').test

// Remember to run `npm run test:build` before executing,
// otherwise the lib directory will not exist.

require('../../lib/ngn')

test('Namespace', (t) => {
  t.ok(NGN !== undefined, 'NGN namespace is recognized.')
  t.ok(MissingNgnDependencyError !== undefined, 'NGN missing dependency error is recognized.')
  t.end()
})

test('Method Existance', (t) => {
  const methodList = [
    'global',
    'define',
    'public',
    'private',
    'const',
    'privateconst',
    'get',
    'set',
    'getset',
    'extend',
    'inherit',
    'slice',
    'splice',
    'nullIf',
    'nullif',
    'converge',
    'coalesce',
    'coalesceb',
    'nodelike',
    'dedupe',
    'typeof',
    'forceArray',
    'forceBoolean',
    'forceNumber',
    'processStackItem',
    'stack',
    'isFn',
    'wrap',
    'wrapClass',
    'deprecate',
    'deprecateClass',
    'getObjectMissingPropertyNames',
    'getObjectExtraneousPropertyNames',
    'objectHasAll',
    'objectHasAny',
    'objectHasExactly',
    'objectRequires',
    'needs',
    'createAlias',
    // 'CustomExceptionClass',
    // 'CustomException',
    'createException',
    'getType',
    'LEDGER_EVENT',
    'WARNING_EVENT',
    'INFO_EVENT',
    'ERROR_EVENT',
    'WARN',
    'INFO',
    'ERROR',

    // Classes
    'EventEmitter',
    'BUS',
    'NET',
    'DATA',
    'Task',
    'Tasks', // Deprecated in favor of Queue
    'Queue',
    'UTILITY',

    // Extras
    'version'
  ]

  for (let method of methodList) {
    t.ok(NGN.hasOwnProperty(method), `NGN.${method} exists.`)
  }

  let keys = Object.getOwnPropertyNames(NGN)

  for (let key of keys) {
    if (methodList.indexOf(key) < 0) {
      t.fail(`NGN.${key} has no sanity check.`)
    }
  }

  t.end()
})
<|endoftext|>


<commit_before>import { test } from 'tape';
import Pagination from '../../lib/components/Pagination';
import React from 'react/addons';
import $ from 'teaspoon';

const getList = props => $(<Pagination {...props} />)
	.shallowRender()
	.children('.Pagination__list');

const getPageNumbers = props => getList(props)
	.children()
	.get()
	.map(node => node.props.children);

test('Pagination. Basics', t => {

	t.ok(
		$(<Pagination {...{ currentPage: 1, pageSize: 10, total: 30 }} />)
			.shallowRender()
			.is('.Pagination'),
		'should create .Pagination container');

	t.equal(
		getList({ currentPage: 1, pageSize: 10, total: 30 })
			.length,
		1,
		'should create .Pagination__list container for pages');

	t.equal(
		getList({ currentPage: 1, pageSize: 10, total: 30 })
			.children().length,
		3,
		'should render 3 pages for 30 items with 10 items per page');

	t.equal(getList({ currentPage: 1, pageSize: 10, total: 30 })
		.children('.Pagination__list__item').length,
		3,
		'should create .Pagination__list__item containers for each page');

	t.equal(getList({ currentPage: 2, pageSize: 10, total: 30 })
		.children('.is-selected').length,
		1,
		'should add "is-selected" class to current page element');

	t.deepEqual(
		getPageNumbers({ currentPage: 1, pageSize: 10, total: 45 }),
		[1, 2, 3, 4, 5],
		'should render page numbers');

	t.end();
});

test('Pagination. Limit', t => {

	t.deepEqual(
		getPageNumbers({ currentPage: 1, pageSize: 10, total: 100, limit: 6 }),
		[1, 2, 3, 4, 5, 6, '...'],
		'should limit number of first pages when on first page');

	t.deepEqual(
		getPageNumbers({ currentPage: 10, pageSize: 10, total: 100, limit: 6 }),
		['...', 5, 6, 7, 8, 9, 10],
		'should limit number of last pages when on the last page');

	t.deepEqual(
		getPageNumbers({ currentPage: 111, pageSize: 10, total: 105, limit: 6 }),
		['...', 6, 7, 8, 9, 10, 11],
		'should limit number of last pages when on the last page and it is not filled in full');

	t.deepEqual(
		getPageNumbers({ currentPage: 10, pageSize: 25, total: 1000, limit: 5 }),
		['...', 8, 9, 10, 11, 12, '...'],
		'should limit number of pages in the middle of pagination (odd number)');

	t.deepEqual(
		getPageNumbers({ currentPage: 10, pageSize: 25, total: 1000, limit: 4 }),
		['...', 9, 10, 11, 12, '...'],
		'should limit number of pages in the middle of pagination (even number)');

	t.deepEqual(
		getPageNumbers({ currentPage: 4, pageSize: 36, total: 130, limit: 2 }),
		['...', 3, 4],
		'should render correctly when limit is extremely small');

	t.end();
});
<commit_msg>react/addons is deprecated<commit_after>import { test } from 'tape';
import Pagination from '../../lib/components/Pagination';
import React from 'react';
import $ from 'teaspoon';

const getList = props => $(<Pagination {...props} />)
	.shallowRender()
	.children('.Pagination__list');

const getPageNumbers = props => getList(props)
	.children()
	.get()
	.map(node => node.props.children);

test('Pagination. Basics', t => {

	t.ok(
		$(<Pagination {...{ currentPage: 1, pageSize: 10, total: 30 }} />)
			.shallowRender()
			.is('.Pagination'),
		'should create .Pagination container');

	t.equal(
		getList({ currentPage: 1, pageSize: 10, total: 30 })
			.length,
		1,
		'should create .Pagination__list container for pages');

	t.equal(
		getList({ currentPage: 1, pageSize: 10, total: 30 })
			.children().length,
		3,
		'should render 3 pages for 30 items with 10 items per page');

	t.equal(getList({ currentPage: 1, pageSize: 10, total: 30 })
		.children('.Pagination__list__item').length,
		3,
		'should create .Pagination__list__item containers for each page');

	t.equal(getList({ currentPage: 2, pageSize: 10, total: 30 })
		.children('.is-selected').length,
		1,
		'should add "is-selected" class to current page element');

	t.deepEqual(
		getPageNumbers({ currentPage: 1, pageSize: 10, total: 45 }),
		[1, 2, 3, 4, 5],
		'should render page numbers');

	t.end();
});

test('Pagination. Limit', t => {

	t.deepEqual(
		getPageNumbers({ currentPage: 1, pageSize: 10, total: 100, limit: 6 }),
		[1, 2, 3, 4, 5, 6, '...'],
		'should limit number of first pages when on first page');

	t.deepEqual(
		getPageNumbers({ currentPage: 10, pageSize: 10, total: 100, limit: 6 }),
		['...', 5, 6, 7, 8, 9, 10],
		'should limit number of last pages when on the last page');

	t.deepEqual(
		getPageNumbers({ currentPage: 111, pageSize: 10, total: 105, limit: 6 }),
		['...', 6, 7, 8, 9, 10, 11],
		'should limit number of last pages when on the last page and it is not filled in full');

	t.deepEqual(
		getPageNumbers({ currentPage: 10, pageSize: 25, total: 1000, limit: 5 }),
		['...', 8, 9, 10, 11, 12, '...'],
		'should limit number of pages in the middle of pagination (odd number)');

	t.deepEqual(
		getPageNumbers({ currentPage: 10, pageSize: 25, total: 1000, limit: 4 }),
		['...', 9, 10, 11, 12, '...'],
		'should limit number of pages in the middle of pagination (even number)');

	t.deepEqual(
		getPageNumbers({ currentPage: 4, pageSize: 36, total: 130, limit: 2 }),
		['...', 3, 4],
		'should render correctly when limit is extremely small');

	t.end();
});
<|endoftext|>


<commit_before>//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 = [];

            //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.title || $scope.selectedStep.wzTitle;
                if ($scope.selectedStep && stepTitle !== $scope.currentStep) {
                    //invoking goTo() with step title as argument
                    $scope.goTo(_.findWhere($scope.getEnabledSteps(), {title: $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 (_.isUndefined(editMode) || _.isNull(editMode)) return;

                if (editMode) {
                    _.each($scope.getEnabledSteps(), function(step) {
                        step.completed = true;
                    });
                }
            }, 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 _.indexOf($scope.getEnabledSteps(), 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 (!_.isUndefined($scope.currentStep)) {
                        $scope.currentStep = step.title || 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: _.indexOf($scope.getEnabledSteps() , 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(!_.isUndefined($scope.currentStep)){
                                $scope.currentStep = step.title || 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: _.indexOf($scope.getEnabledSteps(), 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;
                }
                return step.canenter($scope.context) === 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;
                }
                return step.canexit($scope.context) === true;
            }

            $scope.currentStepNumber = function() {
                //retreive current step number
                return _.indexOf($scope.getEnabledSteps() , $scope.selectedStep) + 1;
            };

            $scope.getEnabledSteps = function() {
                return _.filter($scope.steps, function(step){
                    return step.disabled !== 'true';
                });
            };

            //unSelect All Steps
            function unselectAll() {
                //traverse steps array and set each "selected" property to false
                _.each($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.title;
            };

            //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 = _.indexOf(enabledSteps, $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 (_.isNumber(step)) {
                    stepTo = enabledSteps[step];
                } else {
                    //finding the step associated with the title entered as goTo argument
                    stepTo = _.findWhere(enabledSteps, {title: 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 = _.indexOf($scope.getEnabledSteps() , $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 = _.indexOf($scope.getEnabledSteps() , $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]);
                }
            };
        }]
    };
});<commit_msg>Support custom onCancel function defined in the linked controller.<commit_after>//wizard directive
angular.module('mgo-angular-wizard').directive('wizard', function() {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: {
            currentStep: '=',
            onCancel: '&',
            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 = [];

            //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.title || $scope.selectedStep.wzTitle;
                if ($scope.selectedStep && stepTitle !== $scope.currentStep) {
                    //invoking goTo() with step title as argument
                    $scope.goTo(_.findWhere($scope.getEnabledSteps(), {title: $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 (_.isUndefined(editMode) || _.isNull(editMode)) return;

                if (editMode) {
                    _.each($scope.getEnabledSteps(), function(step) {
                        step.completed = true;
                    });
                }
            }, 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 _.indexOf($scope.getEnabledSteps(), 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 (!_.isUndefined($scope.currentStep)) {
                        $scope.currentStep = step.title || 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: _.indexOf($scope.getEnabledSteps() , 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(!_.isUndefined($scope.currentStep)){
                                $scope.currentStep = step.title || 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: _.indexOf($scope.getEnabledSteps(), 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;
                }
                return step.canenter($scope.context) === 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;
                }
                return step.canexit($scope.context) === true;
            }

            $scope.currentStepNumber = function() {
                //retreive current step number
                return _.indexOf($scope.getEnabledSteps() , $scope.selectedStep) + 1;
            };

            $scope.getEnabledSteps = function() {
                return _.filter($scope.steps, function(step){
                    return step.disabled !== 'true';
                });
            };

            //unSelect All Steps
            function unselectAll() {
                //traverse steps array and set each "selected" property to false
                _.each($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.title;
            };

            //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 = _.indexOf(enabledSteps, $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 (_.isNumber(step)) {
                    stepTo = enabledSteps[step];
                } else {
                    //finding the step associated with the title entered as goTo argument
                    stepTo = _.findWhere(enabledSteps, {title: 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 = _.indexOf($scope.getEnabledSteps() , $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() {
            	if ($scope.onCancel) {
                    //onCancel is linked to controller via wizard directive:
            		$scope.onCancel();
                } else {
                    //getting index of current step
                    var index = _.indexOf($scope.getEnabledSteps() , $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]);
                    }
                }
            };
        }]
    };
});<|endoftext|>


<commit_before>/* Amara, universalsubtitles.org
 *
 * Copyright (C) 2013 Participatory Culture Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see
 * http://www.gnu.org/licenses/agpl-3.0.html.
 */
(function() {

var $document = $(document);

$.fn.openModal = function(openEvent, setupData) {
    if(setupData === undefined) {
        setupData = {}
    }
    this.each(function() {
        var modal = $(this);
        if(setupData) {
            setupModal(modal, setupData);
        }
        var closeButton = $('button.close', modal);

        modal.addClass('shown');
        $('body').append('

');
        closeButton.bind('click.modal', onClose);
        modal.trigger('open');

        $document.bind('click.modal', function(evt) {
            if(openEvent && evt.timeStamp <= openEvent.timeStamp) return;
            var clickedModal = $(evt.target).closest('aside.modal');
            if(clickedModal.length == 0) {
                // click outside the modal
                onClose(evt);
            } else if($(evt.target).closest('button.close', clickedModal).length > 0) {
                // click on the close button
                onClose(evt);
            }
        });
        $document.bind('keydown.modal', function(evt) {
            if (evt.keyCode === 27) {
                onClose(evt);
            }
        });

        function onClose(evt) {
            evt.preventDefault();
            if(setupData.removeOnClose) {
                modal.remove();
            } else {
                modal.removeClass('shown');
            }
            $('body div.modal-overlay').remove();
            closeButton.unbind('click.modal');
            $document.unbind('click.modal');
            $document.unbind('keydown.modal');
            modal.trigger('close');
        }
    });

    function setupModal(modal, setupData) {
        if(setupData['clear-errors']) {
            $('ul.errorlist', modal).remove();
        }
        if(setupData['heading']) {
            $('h3', modal).text(setupData['heading']);
        }
        if(setupData['text']) {
            $('.text', modal).text(setupData['text']);
        }
        if(setupData['setFormValues']) {
            $.each(setupData['setFormValues'], function(name, value) {
                $('*[name=' + name + ']', modal).val(value);
            });
        }
        if(setupData['copyInput']) {
            var inputName = setupData['copyInput'];
            var form = $('form', modal);
            // Delete any inputs added before
            $('input[name=' + inputName + '].copied', form).remove();
            // Copy any inputs outside of forms into the modal
            $('input[name=' + inputName + ']')
                .not(':checkbox:not(:checked)').each(function() {
                    var input = $(this);
                    if(input.closest("form").length > 0) {
                        return;
                    }
                    input.clone().attr('type', 'hidden').addClass('copied').appendTo(form);
                });
        }
    }
}

window.ajaxOpenModal = function(url, params, setupData) {
    var setupData = $.extend({}, setupData, {removeOnClose: true});
    var loadingHTML = $('

');

    $('body').append(loadingHTML);

    $.get(url, params)
    .done(function(data, textStatus, xhr) {
        loadingHTML.remove();
        var modal = $(data)
        modal.updateBehaviors();
        modal.appendTo(document.body).openModal(null, setupData);
        $('form', modal).ajaxForm({
            url: url + '?' + $.param(params),
            beforeSubmit: function(data, form, options) {
                $('button.submit', form).append(
                    ' '
                ).prop('disabled', true);
            },
            error: function(xhr, errorString, textStatus) {
                modal.remove();
                showErrorModal("Error Submitting Form", textStatus);
            },
            success: function(responseText, textStatus, xhr) {
                if(xhr.getResponseHeader('X-Form-Success')) {
                    window.location.reload();
                } else {
                    var newModal = $(responseText);
                    modal.replaceWith(newModal);
                    newModal.openModal();
                }
            }
        });
    })
    .fail(function(xhr, textStatus, errorThrown) {
        console.log("error loading modal from " + url + "(" + textStatus + ")");
        loadingHTML.remove();
    });
}

window.showErrorModal = function(header, text) {
    var header = $('
').text(header);
    var text = $('
').text(text);
    var closeButton = $('<button class="close">');
    var modal = $('').append(closeButton, header, text);
    modal.appendTo('body').openModal();
}

$document.ready(function() {
    $('.open-modal').each(function() {
        var link = $(this);
        var modal = $('#' + link.data('modal'));

        link.bind('click', function(e) {
            e.preventDefault();
            modal.openModal(e, link.data());
        });
    });

    $('aside.modal.start-open').openModal();
});

})();
<commit_msg>Correctly setup ajax modals after a form error (#2418)<commit_after>/* Amara, universalsubtitles.org
 *
 * Copyright (C) 2013 Participatory Culture Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see
 * http://www.gnu.org/licenses/agpl-3.0.html.
 */
(function() {

var $document = $(document);

$.fn.openModal = function(openEvent, setupData) {
    if(setupData === undefined) {
        setupData = {}
    }
    this.each(function() {
        var modal = $(this);
        if(setupData) {
            setupModal(modal, setupData);
        }
        var closeButton = $('button.close', modal);

        modal.addClass('shown');
        $('body').append('

');
        closeButton.bind('click.modal', onClose);
        modal.trigger('open');

        $document.bind('click.modal', function(evt) {
            if(openEvent && evt.timeStamp <= openEvent.timeStamp) return;
            var clickedModal = $(evt.target).closest('aside.modal');
            if(clickedModal.length == 0) {
                // click outside the modal
                onClose(evt);
            } else if($(evt.target).closest('button.close', clickedModal).length > 0) {
                // click on the close button
                onClose(evt);
            }
        });
        $document.bind('keydown.modal', function(evt) {
            if (evt.keyCode === 27) {
                onClose(evt);
            }
        });

        function onClose(evt) {
            evt.preventDefault();
            if(setupData.removeOnClose) {
                modal.remove();
            } else {
                modal.removeClass('shown');
            }
            removeModalOverlay();
            closeButton.unbind('click.modal');
            $document.unbind('click.modal');
            $document.unbind('keydown.modal');
            modal.trigger('close');
        }
    });

    function setupModal(modal, setupData) {
        if(setupData['clear-errors']) {
            $('ul.errorlist', modal).remove();
        }
        if(setupData['heading']) {
            $('h3', modal).text(setupData['heading']);
        }
        if(setupData['text']) {
            $('.text', modal).text(setupData['text']);
        }
        if(setupData['setFormValues']) {
            $.each(setupData['setFormValues'], function(name, value) {
                $('*[name=' + name + ']', modal).val(value);
            });
        }
        if(setupData['copyInput']) {
            var inputName = setupData['copyInput'];
            var form = $('form', modal);
            // Delete any inputs added before
            $('input[name=' + inputName + '].copied', form).remove();
            // Copy any inputs outside of forms into the modal
            $('input[name=' + inputName + ']')
                .not(':checkbox:not(:checked)').each(function() {
                    var input = $(this);
                    if(input.closest("form").length > 0) {
                        return;
                    }
                    input.clone().attr('type', 'hidden').addClass('copied').appendTo(form);
                });
        }
    }
}

function removeModalOverlay() {
    $('body div.modal-overlay').remove();
}

window.ajaxOpenModal = function(url, params, setupData) {
    var setupData = $.extend({}, setupData, {removeOnClose: true});
    var loadingHTML = $('

');

    $('body').append(loadingHTML);

    function setupAjaxModal(modal) {
        modal.updateBehaviors();
        $('form', modal).ajaxForm({
            url: url + '?' + $.param(params),
            beforeSubmit: function(data, form, options) {
                $('button.submit', form).append(
                    ' '
                ).prop('disabled', true);
            },
            error: function(xhr, errorString, textStatus) {
                modal.remove();
                showErrorModal("Error Submitting Form", textStatus);
            },
            success: function(responseText, textStatus, xhr) {
                if(xhr.getResponseHeader('X-Form-Success')) {
                    window.location.reload();
                } else {
                    removeModalOverlay();
                    var newModal = $(responseText);
                    modal.replaceWith(newModal);
                    newModal.openModal();
                    setupAjaxModal(newModal);
                }
            }
        });
    }

    $.get(url, params)
    .done(function(data, textStatus, xhr) {
        loadingHTML.remove();
        var modal = $(data)
        modal.appendTo(document.body).openModal(null, setupData);
        setupAjaxModal(modal);
    })
    .fail(function(xhr, textStatus, errorThrown) {
        console.log("error loading modal from " + url + "(" + textStatus + ")");
        loadingHTML.remove();
    });
}

window.showErrorModal = function(header, text) {
    var header = $('
').text(header);
    var text = $('
').text(text);
    var closeButton = $('<button class="close">');
    var modal = $('').append(closeButton, header, text);
    modal.appendTo('body').openModal();
}

$document.ready(function() {
    $('.open-modal').each(function() {
        var link = $(this);
        var modal = $('#' + link.data('modal'));

        link.bind('click', function(e) {
            e.preventDefault();
            modal.openModal(e, link.data());
        });
    });

    $('aside.modal.start-open').openModal();
});

})();
<|endoftext|>


<commit_before>/**
 * Class for handeling graph plotting of pulse data.
 * Still needs loads of work and is only a cut/paste from template for now
 */
var plot;
var GraphPlotter = {
    choiceContainer: null,
    datasets: null,
    backendUrl: null,
    max_hr: 200,
    markings: [],
    formatters: {
            speed: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' km/h';
            },
            altitude: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' m';
            },
            length: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' km';
            },
            power: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' W';
            },
            hr: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' BPM';
            },
            temp: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' ℃';
            },
            time: function(val, axis) {
                var hours = Math.floor(val / 60);
                var minutes = val;

                if (hours)
                        return hours + 'h ' + minutes + 'm';
                return minutes + 'm';
            }

    },

    plotAccordingToChoices: function(ranges) {
        data = [];
        var that = this;
        var minIndex = null;
        var maxIndex = null;
        var min = null;
        var max = null;
        var xaxisattrs = {
            tickDecimals: 0,
            tickFormatter: this.xaxisformatter
        };
        if (ranges.xaxis != undefined) {
            var xaxe = plot.getXAxes()[0];
            min = ranges.xaxis.from;
            max = ranges.xaxis.to;
            xaxisattrs.min = min;
            xaxisattrs.max = max;

            for (dataset in this.datasets) {

                series = this.datasets[dataset]['data']

                for (k in series) {
                    if (min >= series[k][0])
                        minIndex = k;
                    if (max <= series[k][0]) {
                        maxIndex = k;
                        break;
                    }
                }
                break;
            }
        }
        $("#choices").find("input:checked").each(function () {
            var key = $(this).attr("name");
            if (key && that.datasets[key]) {
                if (key == 'hr')
                    that.datasets[key]['constraints'] = [that.constraint0, that.constraint1, that.constraint2, that.constraint3, that.constraint4, that.constraint5];
                data.push(that.datasets[key]);
            }
        });

        if (data.length > 0) {
            plot = $.plot($("#tripdiv"), data, {
                yaxes: [
                    { tickFormatter: this.formatters['speed'], max: 100},
                    { position: "right", min: 80, max: this.max_hr, tickFormatter: this.formatters['hr'] },
                    { position: "right", tickFormatter: this.formatters['power']},
                    { tickFormatter: this.formatters['altitude']} ,
                    { tickFormatter: this.formatters['temp']},

                    ],
                xaxis: xaxisattrs,
                legend: {
                    container: $("#tripdiv_legend"),
                    noColumns: 15
                },
                grid: {
                    hoverable: true,
                    clickable: true,
                    markings: this.markings,
                },
                crosshair: { mode: "x" },
                selection: { mode: "x" }
            });
        }

        if (minIndex != null && maxIndex != null) {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(minIndex, maxIndex);
            $.getJSON(this.backendUrl, { start: minIndex, stop: maxIndex }, function (avgs) {
                var items = $("#averages ul .data");
                $("#averages h4").removeClass("hidden");

                $.each(items, function (i, elem) {
                    var classlist = elem.className.split(" ");
                    for (k in classlist) {
                        if (classlist[k] in avgs) {
                            var key = classlist[k];
                            var e = $(elem);
                            var val = Math.round(avgs[key] * 10) / 10;
                            e.text(val);
                            e.parents(".hidden").removeClass("hidden");
                            e.attr('title', key.replace(/_/g, ' '))
                        }
                    }
                });
            });
        }
        else {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(0, 0);
            $("#averages ul li").addClass("hidden");
            $("#averages h4").addClass("hidden");
        }

    },
    showTooltip: function (x, y, contents) {
        $('
' + contents + '
').css( {
            position: 'absolute',
            display: 'none',
            top: y + 5,
            left: x + 5,
            border: '1px solid #fdd',
            padding: '2px',
            'background-color': '#fee',
            opacity: 0.80
        }).appendTo("body").fadeIn(200);
    },
    init: function(args) {
        this.datasets = args.datasets;
        var backendUrl = args.backendUrl;
        this.max_hr = args.max_hr;
        this.markings = args.markings;
        this.xaxisformatter = this.formatters[args.xaxisformatter];
        function evaluate(y,threshold) {
            return y < threshold;
        }
        this.constraint0 = {
            threshold: this.max_hr*0.6,
            color: "rgb(240,240,240)",
            evaluate : evaluate
        }
        this.constraint1 = {
            threshold: this.max_hr*0.72,
            color: "rgb(204,204,204)",
            evaluate : evaluate
        }
        this.constraint2 = {
            threshold: this.max_hr*0.82,
            color: "rgb(51,102,255)",
            evaluate : evaluate
        }
        this.constraint3 = {
            threshold: this.max_hr*0.87,
            color: "rgb(102,204,0)",
            evaluate : evaluate
        }
        this.constraint4 = {
            threshold: this.max_hr*0.92,
            color: "rgb(255,153,0)",
            evaluate : evaluate
        }
        this.constraint5 = {
            threshold: this.max_hr*0.97,
            color: "rgb(255,0,0)",
            evaluate : evaluate
        }

        var that = this;
        this.backendUrl = backendUrl;
        this.choiceContainer = $("#choices");

        $.each(this.datasets, function(key, val) {
            var checked = "checked = checked";
            if (key == 'cadence')
                checked = ''
            if (key == 'temp')
                checked = ''
            if (key == 'power')
                checked = ''

            that.choiceContainer.append('<input type="checkbox" name="' + key +
                '" ' + checked + ' id="chk_' + key + '">' + val.label + '</input>');
        });
        $("#reset_zoom").bind("click", function(evt) {
            evt.preventDefault();
            $("#scrollhacks").css("overflow", "hidden");
            $("#tripdiv").width( $("#tripdiv").width(980));
            that.plotAccordingToChoices({});
        });
        $("#enlarge").bind("click", function(evt) {
            evt.preventDefault();
            $("#scrollhacks").css("overflow", "scroll");
            $("#tripdiv").width( $("#tripdiv").width()*4);
        });
        this.choiceContainer.find("input").bind("click", function(evt) {
                that.plotAccordingToChoices({});
        });
        this.plotAccordingToChoices({});
        var previousPoint = null;
        $("#tripdiv").bind("plothover", function (event, pos, item) {
            if (item) {
                // Move marker to current pos
                if (typeof(Mapper) != "undefined") {
                    if (route_points.length >= item.dataIndex) {

                        var x = route_points[item.dataIndex].x;
                        var y = route_points[item.dataIndex].y;
                        Mapper.updatePosMarker(x, y);
                    }
                }

                if (previousPoint != item.datapoint) {
                    previousPoint = item.datapoint;

                    $("#tooltip").remove();
                    var x = item.datapoint[0].toFixed(2),
                        y = item.datapoint[1].toFixed(2);

                    that.showTooltip(item.pageX, item.pageY,
                    item.series.label + " at " + x + " is " + y);

                }
            }
            else {
                $("#tooltip").remove();
                previousPoint = null;
            }
        });

        $("#tripdiv").bind("plotclick", function (event, pos, item) {
            if (item) {
                $("#clickdata").text("You clicked point " + item.dataIndex + " in " + item.series.label + ".");
                plot.highlight(item.series, item.datapoint);
            }
        });

        $("#tripdiv").bind("plotselected", function (event, ranges) {
            that.plotAccordingToChoices(ranges);
        });
    }
};

<commit_msg>add crosshair, and start of patch to better legend<commit_after>/**
 * Class for handeling graph plotting of pulse data.
 * Still needs loads of work and is only a cut/paste from template for now
 */
var plot;
var GraphPlotter = {
    choiceContainer: null,
    datasets: null,
    backendUrl: null,
    max_hr: 200,
    markings: [],
    formatters: {
            speed: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' km/h';
            },
            altitude: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' m';
            },
            length: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' km';
            },
            power: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' W';
            },
            hr: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' BPM';
            },
            temp: function(val, axis) {
                return (val).toFixed(axis.tickDecimals) + ' ℃';
            },
            time: function(val, axis) {
                var hours = Math.floor(val / 60);
                var minutes = val;

                if (hours)
                        return hours + 'h ' + minutes + 'm';
                return minutes + 'm';
            }

    },

    plotAccordingToChoices: function(ranges) {
        data = [];
        var that = this;
        var minIndex = null;
        var maxIndex = null;
        var min = null;
        var max = null;
        var xaxisattrs = {
            tickDecimals: 0,
            tickFormatter: this.xaxisformatter
        };
        if (ranges.xaxis != undefined) {
            var xaxe = plot.getXAxes()[0];
            min = ranges.xaxis.from;
            max = ranges.xaxis.to;
            xaxisattrs.min = min;
            xaxisattrs.max = max;

            for (dataset in this.datasets) {

                series = this.datasets[dataset]['data']

                for (k in series) {
                    if (min >= series[k][0])
                        minIndex = k;
                    if (max <= series[k][0]) {
                        maxIndex = k;
                        break;
                    }
                }
                break;
            }
        }
        $("#choices").find("input:checked").each(function () {
            var key = $(this).attr("name");
            if (key && that.datasets[key]) {
                if (key == 'hr')
                    that.datasets[key]['constraints'] = [that.constraint0, that.constraint1, that.constraint2, that.constraint3, that.constraint4, that.constraint5];
                data.push(that.datasets[key]);
            }
        });

        if (data.length > 0) {
            plot = $.plot($("#tripdiv"), data, {
                yaxes: [
                    { tickFormatter: this.formatters['speed'], max: 100},
                    { position: "right", min: 80, max: this.max_hr, tickFormatter: this.formatters['hr'] },
                    { position: "right", tickFormatter: this.formatters['power']},
                    { tickFormatter: this.formatters['altitude']} ,
                    { tickFormatter: this.formatters['temp']},

                    ],
                xaxis: xaxisattrs,
                legend: {
                    container: $("#tripdiv_legend"),
                    noColumns: 15
                },
                grid: {
                    hoverable: true,
                    clickable: true,
                    markings: this.markings,
                },
                crosshair: { mode: "x" },
                selection: { mode: "x" }
            });
        }

        if (minIndex != null && maxIndex != null) {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(minIndex, maxIndex);
            $.getJSON(this.backendUrl, { start: minIndex, stop: maxIndex }, function (avgs) {
                var items = $("#averages ul .data");
                $("#averages h4").removeClass("hidden");

                $.each(items, function (i, elem) {
                    var classlist = elem.className.split(" ");
                    for (k in classlist) {
                        if (classlist[k] in avgs) {
                            var key = classlist[k];
                            var e = $(elem);
                            var val = Math.round(avgs[key] * 10) / 10;
                            e.text(val);
                            e.parents(".hidden").removeClass("hidden");
                            e.attr('title', key.replace(/_/g, ' '))
                        }
                    }
                });
            });
        }
        else {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(0, 0);
            $("#averages ul li").addClass("hidden");
            $("#averages h4").addClass("hidden");
        }

    },
    updateLegend: function(pos) {
        this.updateLegendTimeout = null;
       // var pos = this.latestPosition;
        var axes = plot.getAxes();
        if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
            pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
            return;

        var i, j, dataset = plot.getData();
        for (i = 0; i < dataset.length; ++i) {
            var series = dataset[i];

            // find the nearest points, x-wise
            for (j = 0; j < series.data.length; ++j)
                if (series.data[j][0] > pos.x)
                    break;

            // now interpolate
            var y, p1 = series.data[j - 1], p2 = series.data[j];

            if (p1 == null)
                y = p2[1];
            else if (p2 == null)
                y = p1[1];
            else
                y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);

            this.legends.eq(i).text(series.label.replace(/=.*/, "= " + y.toFixed(2)));
        }
    },
    showTooltip: function (x, y, contents) {
        $('
' + contents + '
').css( {
            position: 'absolute',
            display: 'none',
            top: y + 5,
            left: x + 5,
            padding: '2px',
            opacity: 0.80
        }).appendTo("body").fadeIn(100);
    },
    init: function(args) {
        this.datasets = args.datasets;
        var backendUrl = args.backendUrl;
        this.max_hr = args.max_hr;
        this.markings = args.markings;
        this.xaxisformatter = this.formatters[args.xaxisformatter];
        function evaluate(y,threshold) {
            return y < threshold;
        }
        this.constraint0 = {
            threshold: this.max_hr*0.6,
            color: "rgb(240,240,240)",
            evaluate : evaluate
        }
        this.constraint1 = {
            threshold: this.max_hr*0.72,
            color: "rgb(204,204,204)",
            evaluate : evaluate
        }
        this.constraint2 = {
            threshold: this.max_hr*0.82,
            color: "rgb(51,102,255)",
            evaluate : evaluate
        }
        this.constraint3 = {
            threshold: this.max_hr*0.87,
            color: "rgb(102,204,0)",
            evaluate : evaluate
        }
        this.constraint4 = {
            threshold: this.max_hr*0.92,
            color: "rgb(255,153,0)",
            evaluate : evaluate
        }
        this.constraint5 = {
            threshold: this.max_hr*0.97,
            color: "rgb(255,0,0)",
            evaluate : evaluate
        }

        var that = this;
        this.backendUrl = backendUrl;
        this.choiceContainer = $("#choices");

        $.each(this.datasets, function(key, val) {
            var checked = "checked = checked";
            if (key == 'cadence')
                checked = ''
            if (key == 'temp')
                checked = ''
            if (key == 'power')
                checked = ''

            that.choiceContainer.append('<input type="checkbox" name="' + key +
                '" ' + checked + ' id="chk_' + key + '">' + val.label + '</input>');
        });
        $("#reset_zoom").bind("click", function(evt) {
            evt.preventDefault();
            $("#scrollhacks").css("overflow", "hidden");
            $("#tripdiv").width( $("#tripdiv").width(980));
            that.plotAccordingToChoices({});
        });
        $("#enlarge").bind("click", function(evt) {
            evt.preventDefault();
            $("#scrollhacks").css("overflow", "scroll");
            $("#tripdiv").width( $("#tripdiv").width()*4);
        });
        this.choiceContainer.find("input").bind("click", function(evt) {
                that.plotAccordingToChoices({});
        });
        this.plotAccordingToChoices({});
        this.legends = $("#tripdiv .legendLabel");
        this.legends.each(function () {
        // fix the widths so they don't jump around
            $(this).css('width', $(this).width());
        });

        var previousPoint = null;
        this.updateLegendTimeout = null;
        this.latestPosition = null;
        $("#tripdiv").bind("plothover", function (event, pos, item) {
//            that.latestPosition = pos;
  //          if (!that.updateLegendTimeout) that.updateLegendTimeout = setTimeout(that.updateLegend, 50);
//            that.updateLegend(pos);
            if (item) {
                // Move marker to current pos
                if (typeof(Mapper) != "undefined") {
                    if (route_points.length >= item.dataIndex) {

                        var x = route_points[item.dataIndex].x;
                        var y = route_points[item.dataIndex].y;
                        Mapper.updatePosMarker(x, y);
                    }
                }

                if (previousPoint != item.datapoint) {
                    previousPoint = item.datapoint;

                    $("#gtooltip").remove();
                    var x = item.datapoint[0].toFixed(2),
                        y = item.datapoint[1].toFixed(2);

                    that.showTooltip(item.pageX, item.pageY,
                    item.series.label + " at " + x + " is " + y);

                }
            }
            else {
                $("#gtooltip").remove();
                previousPoint = null;
            }
        });

        $("#tripdiv").bind("plotclick", function (event, pos, item) {
            if (item) {
                $("#clickdata").text("You clicked point " + item.dataIndex + " in " + item.series.label + ".");
                plot.highlight(item.series, item.datapoint);
            }
        });

        $("#tripdiv").bind("plotselected", function (event, ranges) {
            that.plotAccordingToChoices(ranges);
        });
    }
};

<|endoftext|>


<commit_before>// nadesiko for web browser
// wnako3.js
const NakoCompiler = require('./nako3')
const PluginBrowser = require('./plugin_browser')
const NAKO_SCRIPT_RE = /^(なでしこ|nako|nadesiko)3?$/

class WebNakoCompiler extends NakoCompiler {
  constructor () {
    super()
    this.__varslist[0]['ナデシコ種類'] = 'wnako3'
  }

  /**
   * ブラウザでtype="なでしこ"というスクリプトを得て実行する
   */
  runNakoScript () {
    // スクリプトタグの中身を得る
    let nakoScriptCount = 0
    let scripts = document.querySelectorAll('script')
    for (let i = 0; i < scripts.length; i++) {
      let script = scripts[i]
      if (script.type.match(NAKO_SCRIPT_RE)) {
        nakoScriptCount++
        this.run(script.text)
      }
    }
    console.log('実行したなでしこの個数=', nakoScriptCount)
  }

  /**
   * type=なでしこ のスクリプトを自動実行するべきかどうかを返す
   * @returns {boolean} type=なでしこ のスクリプトを自動実行するべきかどうか
   */
  checkScriptTagParam () {
    let scripts = document.querySelectorAll('script')
    for (let i = 0; i < scripts.length; i++) {
      let script = scripts[i]
      let src = script.src || ''
      if (src.indexOf('wnako3.js?run') >= 0)
        {return true}

    }
    return false
  }

  /**
   * コードを生成 (override)
   * @param ast AST
   * @param isTest テストかどうか
   * @returns {string} コード
   */
  generate(ast, isTest) {
    let code = super.generate(ast, isTest)

    if (isTest && code !== '') {
      code = '// mocha初期化\n' +
        'mocha.setup("bdd");\n' +
        'mocha.checkLeaks();\n' +
        '\n' +
        code + '\n' +
        'mocha.run();// テスト実行\n'
    }

    return code
  }
}

// ブラウザなら navigator.nako3 になでしこを登録
if (typeof (navigator) === 'object') {
  const nako3 = navigator.nako3 = new WebNakoCompiler()
  nako3.addPluginObject('PluginBrowser', PluginBrowser)
  window.addEventListener('DOMContentLoaded', (e) => {
    const isAutoRun = nako3.checkScriptTagParam()
    if (isAutoRun) {nako3.runNakoScript()}
  }, false)
} else
  {module.exports = WebNakoCompiler}

<commit_msg>テスト結果をWeb Notificationsで通知するよう実装<commit_after>// nadesiko for web browser
// wnako3.js
const NakoCompiler = require('./nako3')
const PluginBrowser = require('./plugin_browser')
const NAKO_SCRIPT_RE = /^(なでしこ|nako|nadesiko)3?$/

class WebNakoCompiler extends NakoCompiler {
  constructor () {
    super()
    this.__varslist[0]['ナデシコ種類'] = 'wnako3'
  }

  /**
   * ブラウザでtype="なでしこ"というスクリプトを得て実行する
   */
  runNakoScript () {
    // スクリプトタグの中身を得る
    let nakoScriptCount = 0
    let scripts = document.querySelectorAll('script')
    for (let i = 0; i < scripts.length; i++) {
      let script = scripts[i]
      if (script.type.match(NAKO_SCRIPT_RE)) {
        nakoScriptCount++
        this.run(script.text)
      }
    }
    console.log('実行したなでしこの個数=', nakoScriptCount)
  }

  /**
   * type=なでしこ のスクリプトを自動実行するべきかどうかを返す
   * @returns {boolean} type=なでしこ のスクリプトを自動実行するべきかどうか
   */
  checkScriptTagParam () {
    let scripts = document.querySelectorAll('script')
    for (let i = 0; i < scripts.length; i++) {
      let script = scripts[i]
      let src = script.src || ''
      if (src.indexOf('wnako3.js?run') >= 0)
        {return true}

    }
    return false
  }

  /**
   * コードを生成 (override)
   * @param ast AST
   * @param isTest テストかどうか
   * @returns {string} コード
   */
  generate(ast, isTest) {
    let code = super.generate(ast, isTest)

    if (isTest && code !== '') {
      code = '// mocha初期化\n' +
        'mocha.setup("bdd");\n' +
        'mocha.growl();\n'+
        'mocha.checkLeaks();\n' +
        '\n' +
        code + '\n' +
        'mocha.run();// テスト実行\n'
    }

    return code
  }
}

// ブラウザなら navigator.nako3 になでしこを登録
if (typeof (navigator) === 'object') {
  const nako3 = navigator.nako3 = new WebNakoCompiler()
  nako3.addPluginObject('PluginBrowser', PluginBrowser)
  window.addEventListener('DOMContentLoaded', (e) => {
    const isAutoRun = nako3.checkScriptTagParam()
    if (isAutoRun) {nako3.runNakoScript()}
  }, false)
} else
  {module.exports = WebNakoCompiler}

<|endoftext|>


<commit_before>'use strict'
const Promise = require('bluebird')
const config = require('../server/init/configuration')
const log = require('../server/init/logging')
const EventEmitter = require('events')
const eventEmitter = new EventEmitter()

const {addDescription} = require('message-type')
const handleMessage = require('./handleMessage')
require('colors')
const {Client: AMQPClient, Policy} = require('amqp10')
const urlencode = require('urlencode')
const client = new AMQPClient(Policy.Utils.RenewOnSettle(1, 1, Policy.ServiceBusQueue))

client.on('connection:closed', msg => log.info('connection:closed event received', msg))
client.on('connection:opened', msg => log.info('connection to azure opened'))
client.on('connection:disconnected', msg => log.info('connection to azure disconnected'))

function detached (msg) {
  log.info(`Got a detached event for receiver, restart the azure client`)
  client.disconnect()
    .then(() => log.info('Client disconnected'))
    .then(start)
    .catch(e => log.error(e))
}

function start () {
  const sharedAccessKey = process.env.AZURE_SHARED_ACCESS_KEY || config.secure.azure.SharedAccessKey

  log.info('connecting with the following azure url:', `amqps://${config.full.azure.SharedAccessKeyName}:${(sharedAccessKey || '').replace(/\w/g, 'x')}@${config.full.azure.host}`)
  const queueName = config.secure.azure.queueName || config.full.azure.queueName
  log.info('connecting to the queue with name ', queueName)

  return client.connect(`amqps://${config.full.azure.SharedAccessKeyName}:${urlencode(sharedAccessKey)}@${config.full.azure.host}`)
    .then(() => client.createReceiver(queueName))
    .then(receiver => {
      log.info('receiver created:', receiver.id)

      receiver.on('errorReceived', err => log.warn('An error occured when trying to receive message from queue', err))

      receiver.on('detached', detached)

      receiver.on('message', message => {
        log.info(`New message from ug queue for receiver ${receiver.id}`, message)

        Promise.resolve(message)
        .then(initLogger)
        .then(() => {
          if (message.body) {
            return _processMessage(message)
          } else {
            log.info('Message is empty or undefined, deleting from queue...', message)
            return receiver.accept(message)
          }
        })
        .then(initLogger)
      })

      function _processMessage (MSG) {
        eventEmitter.emit('processMessageStart', MSG)
        let result
        return Promise.resolve(MSG.body)
        .then(addDescription)
        .then(handleMessage)
        .then(_result => {
          log.info('result from handleMessage', _result)
          result = _result
        })
        .then(() => receiver.accept(MSG))
        .then(() => eventEmitter.emit('messageProcessed', MSG, result))
        .catch(e => {
          log.error(e)
          log.info('Error Occured, releasing message back to queue...', MSG)
          return receiver.modify(MSG, {undeliverableHere: false, deliveryFailed: true})
        })
      }

      return receiver
    })
    .catch(e => log.error('An error occured:', e))
}

function initLogger (msg) {
  let config
  if (msg) {
    const {body} = msg
    config = {
      kthid: body && body.kthid,
      ug1Name: body && body.ug1Name,
      ugversion: (msg && msg.applicationProperties && msg.applicationProperties.UGVersion) || undefined,
      messageId: (msg && msg.properties && msg.properties.messageId) || undefined
    }
  } else {
    config = {}
  }

  log.init(config)

  return msg && msg.body
}

module.exports = {
  start, eventEmitter
}
<commit_msg>removed logging of shared access key<commit_after>'use strict'
const Promise = require('bluebird')
const config = require('../server/init/configuration')
const log = require('../server/init/logging')
const EventEmitter = require('events')
const eventEmitter = new EventEmitter()

const {addDescription} = require('message-type')
const handleMessage = require('./handleMessage')
require('colors')
const {Client: AMQPClient, Policy} = require('amqp10')
const urlencode = require('urlencode')
const client = new AMQPClient(Policy.Utils.RenewOnSettle(1, 1, Policy.ServiceBusQueue))

client.on('connection:closed', msg => log.info('connection:closed event received', msg))
client.on('connection:opened', msg => log.info('connection to azure opened'))
client.on('connection:disconnected', msg => log.info('connection to azure disconnected'))

function detached (msg) {
  log.info(`Got a detached event for receiver, restart the azure client`)
  client.disconnect()
    .then(() => log.info('Client disconnected'))
    .then(start)
    .catch(e => log.error(e))
}

function start () {
  const sharedAccessKey = process.env.AZURE_SHARED_ACCESS_KEY || config.secure.azure.SharedAccessKey

  log.info('connecting with the following azure url:', `amqps://${config.full.azure.SharedAccessKeyName}:${(sharedAccessKey || '').replace(/\w/g, 'x')}@${config.full.azure.host}`)
  const queueName = config.secure.azure.queueName || config.full.azure.queueName
  log.info('connecting to the queue with name ', queueName)

  return client.connect(`amqps://${config.full.azure.SharedAccessKeyName}:${urlencode(sharedAccessKey)}@${config.full.azure.host}`)
    .then(() => client.createReceiver(queueName))
    .then(receiver => {
      log.info('receiver created:', receiver.id)

      receiver.on('errorReceived', err => log.warn('An error occured when trying to receive message from queue', err))

      receiver.on('detached', detached)

      receiver.on('message', message => {
        log.info(`New message from ug queue for receiver ${receiver.id}`, message)

        Promise.resolve(message)
        .then(initLogger)
        .then(() => {
          if (message.body) {
            return _processMessage(message)
          } else {
            log.info('Message is empty or undefined, deleting from queue...', message)
            return receiver.accept(message)
          }
        })
        .then(initLogger)
      })

      function _processMessage (MSG) {
        eventEmitter.emit('processMessageStart', MSG)
        let result
        return Promise.resolve(MSG.body)
        .then(addDescription)
        .then(handleMessage)
        .then(_result => {
          log.info('result from handleMessage', _result)
          result = _result
        })
        .then(() => receiver.accept(MSG))
        .then(() => eventEmitter.emit('messageProcessed', MSG, result))
        .catch(e => {
          log.error(e)
          log.info('Error Occured, releasing message back to queue...', MSG)
          return receiver.modify(MSG, {undeliverableHere: false, deliveryFailed: true})
        })
      }

      return receiver
    })
    .catch(e => log.error('An error occured:', e))
}

function initLogger (msg) {
  let config
  if (msg) {
    const {body} = msg
    config = {
      kthid: body && body.kthid,
      ug1Name: body && body.ug1Name,
      ugversion: (msg && msg.applicationProperties && msg.applicationProperties.UGVersion) || undefined,
      messageId: (msg && msg.properties && msg.properties.messageId) || undefined
    }
  } else {
    config = {}
  }

  log.init(config)

  return msg && msg.body
}

module.exports = {
  start, eventEmitter
}
<|endoftext|>