<commit_before>'use strict';

angular.module('myApp.factories')

    .factory('lemma', function (nlp) {

        //returns an array of result objects with institute, course, degree, date and grade fields
        var parseEducationBackground = function (sentenceArray) {
            function Result() {
                this.institute = [];
                this.course = [];
                this.degree = [];
                this.date = [];
                this.grade = [];
            };
            var results = [];
            var instituteKeyWords = ["college", "university", "institute"];
            var courseKeyWords = ["computer", "computing", "engineering", "information technology", "physics", "it", "neuroscience"];
            var degreeKeyWords = ["bachelor's", "bachelor", "bsc", "master", "master's", "phd", "ph.d", "degree", "mscs", "msc", "be"];
            var gradeKeyWords = ["grade:", "cap", "gpa"];
            var prev = null;
            var result = new Result();
            sentenceArray.forEach(
                function (sentence) {
                    //assume 1 sentence
                    var tokens = nlp.pos(sentence).sentences[0].tokens;
                    tokens.forEach(
                        function (token) {
                            var hasKeyWord = function (keyWord) {
                                return token.text.toLowerCase().indexOf(keyWord) >= 0;
                            };
                            if (token.pos.tag === "NN" || token.pos.tag === "PRP") {
                                var isGrade = gradeKeyWords.some(hasKeyWord);
                                var isInstitute = instituteKeyWords.some(hasKeyWord);
                                var isCourse = courseKeyWords.some(hasKeyWord);
                                var isDegree = degreeKeyWords.some(hasKeyWord);
                                var idk = !(isInstitute || isCourse || isDegree || isGrade);
                                if (isInstitute || (idk && prev === "institute")) {
                                    if (prev !== "institute" && result.institute.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.institute.push(token.text);
                                    prev = "institute"
                                } else if (isCourse || (idk && prev === "course")) {
                                    if (prev !== "course" && result.course.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.course.push(token.text);
                                    prev = "course"
                                } else if (isDegree || (idk && prev === "degree")) {
                                    if (prev !== "degree" && result.degree.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.degree.push(token.text);
                                    prev = "degree"
                                } else if (isGrade) {
                                    if (prev !== "grade" && result.grade.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    prev = "grade"
                                } else {
                                    result.institute.push(token.text);
                                    prev = "institute"
                                }
                            } else if (token.pos.tag === "CD") {
                                //we have a number
                                if (prev == "grade") {
                                    result.grade.push(token.text);
                                } else {
                                    if (prev !== "date" && result.date.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.date.push(token.text);
                                    prev = "date"
                                }
                            } else if (token.pos.tag == "UH") {
                                //for symbol
                            } else {
                                //push into the same place as the last pushed place
                                if (prev === "course") {
                                    result.course.push(token.text);
                                } else if (prev === "degree") {
                                    result.degree.push(token.text);
                                } else if (prev === "grade") {
                                    result.grade.push(token.text);
                                } else if (prev === "date") {
                                    result.date.push(token.text);
                                } else {
                                    result.institute.push(token.text);
                                }
                            }
                        }
                    )
                    results.push(result);
                }
            )
            return results;
        }

        //get keywords from work experience
        var parseWorkExperience = function(sentenceArray) {
            var results = [];
            sentenceArray.forEach(
                function (sentence) {
                    var tokens = nlp.spot(sentence);
                    tokens.forEach(
                        function(token) {
                            results.push(token.analysis.singularize());
                        }
                    )
                    //because nlp library will not pick up the word research, which is quite important
                    if (sentence.toLowerCase().contains("research")) {
                        results.push("research");
                    }
                }
            )

            return results;
        }

        //split by sentences, then commas within each sentence
        //used for parsing of Skills too
        var parseInterestsAndSkills = function(sentenceArray) {
            var results = [];
            sentenceArray.forEach(
                function (sentence) {
                    var tokens = sentence.split(",");
                    results = results.concat(tokens.map(Function.prototype.call, String.prototype.trim));
                }
            )
            return results;
        }

        //returns all the sentence splitted up by " "
        var parseLanguages = function (sentenceArray) {
            var results = [];
            sentenceArray.forEach(
                function (sentence) {
                    var tokens = sentence.split(" ");
                    results = results.concat(tokens);
                }
            )
            return results;
        }

        //var test = ["National University of Singapore", "MSCS, IT, 2010 - 2012"];
        //console.log(parseEducationBackground(test));
        return {
            parse_education: parseEducationBackground,
            parse_language: parseLanguages,
            parse_interest: parseInterestsAndSkills,
            parse_skills: parseInterestsAndSkills,
            parse_work: parseWorkExperience
        }
    }
)
;<commit_msg>Parser: Fix check if text contains "research"<commit_after>'use strict';

angular.module('myApp.factories')

    .factory('lemma', function (nlp) {

        //returns an array of result objects with institute, course, degree, date and grade fields
        var parseEducationBackground = function (sentenceArray) {
            function Result() {
                this.institute = [];
                this.course = [];
                this.degree = [];
                this.date = [];
                this.grade = [];
            };
            var results = [];
            var instituteKeyWords = ["college", "university", "institute"];
            var courseKeyWords = ["computer", "computing", "engineering", "information technology", "physics", "it", "neuroscience"];
            var degreeKeyWords = ["bachelor's", "bachelor", "bsc", "master", "master's", "phd", "ph.d", "degree", "mscs", "msc", "be"];
            var gradeKeyWords = ["grade:", "cap", "gpa"];
            var prev = null;
            var result = new Result();
            sentenceArray.forEach(
                function (sentence) {
                    //assume 1 sentence
                    var tokens = nlp.pos(sentence).sentences[0].tokens;
                    tokens.forEach(
                        function (token) {
                            var hasKeyWord = function (keyWord) {
                                return token.text.toLowerCase().indexOf(keyWord) >= 0;
                            };
                            if (token.pos.tag === "NN" || token.pos.tag === "PRP") {
                                var isGrade = gradeKeyWords.some(hasKeyWord);
                                var isInstitute = instituteKeyWords.some(hasKeyWord);
                                var isCourse = courseKeyWords.some(hasKeyWord);
                                var isDegree = degreeKeyWords.some(hasKeyWord);
                                var idk = !(isInstitute || isCourse || isDegree || isGrade);
                                if (isInstitute || (idk && prev === "institute")) {
                                    if (prev !== "institute" && result.institute.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.institute.push(token.text);
                                    prev = "institute"
                                } else if (isCourse || (idk && prev === "course")) {
                                    if (prev !== "course" && result.course.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.course.push(token.text);
                                    prev = "course"
                                } else if (isDegree || (idk && prev === "degree")) {
                                    if (prev !== "degree" && result.degree.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.degree.push(token.text);
                                    prev = "degree"
                                } else if (isGrade) {
                                    if (prev !== "grade" && result.grade.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    prev = "grade"
                                } else {
                                    result.institute.push(token.text);
                                    prev = "institute"
                                }
                            } else if (token.pos.tag === "CD") {
                                //we have a number
                                if (prev == "grade") {
                                    result.grade.push(token.text);
                                } else {
                                    if (prev !== "date" && result.date.length > 0) {
                                        results.push(result);
                                        result = new Result();
                                    }
                                    result.date.push(token.text);
                                    prev = "date"
                                }
                            } else if (token.pos.tag == "UH") {
                                //for symbol
                            } else {
                                //push into the same place as the last pushed place
                                if (prev === "course") {
                                    result.course.push(token.text);
                                } else if (prev === "degree") {
                                    result.degree.push(token.text);
                                } else if (prev === "grade") {
                                    result.grade.push(token.text);
                                } else if (prev === "date") {
                                    result.date.push(token.text);
                                } else {
                                    result.institute.push(token.text);
                                }
                            }
                        }
                    )
                    results.push(result);
                }
            )
            return results;
        }

        //get keywords from work experience
        var parseWorkExperience = function(sentenceArray) {
            var results = [];
            sentenceArray.forEach(
                function (sentence) {
                    var tokens = nlp.spot(sentence);
                    tokens.forEach(
                        function(token) {
                            results.push(token.analysis.singularize());
                        }
                    )
                    //because nlp library will not pick up the word research, which is quite important
                    if (sentence.toLowerCase().indexOf("research") >= 0) {
                        results.push("research");
                    }
                }
            )

            return results;
        }

        //split by sentences, then commas within each sentence
        //used for parsing of Skills too
        var parseInterestsAndSkills = function(sentenceArray) {
            var results = [];
            sentenceArray.forEach(
                function (sentence) {
                    var tokens = sentence.split(",");
                    results = results.concat(tokens.map(Function.prototype.call, String.prototype.trim));
                }
            )
            return results;
        }

        //returns all the sentence splitted up by " "
        var parseLanguages = function (sentenceArray) {
            var results = [];
            sentenceArray.forEach(
                function (sentence) {
                    var tokens = sentence.split(" ");
                    results = results.concat(tokens);
                }
            )
            return results;
        }

        //var test = ["National University of Singapore", "MSCS, IT, 2010 - 2012"];
        //console.log(parseEducationBackground(test));
        return {
            parse_education: parseEducationBackground,
            parse_language: parseLanguages,
            parse_interest: parseInterestsAndSkills,
            parse_skills: parseInterestsAndSkills,
            parse_work: parseWorkExperience
        }
    }
)
;<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import cx from 'classnames';
import theme from './theme.css';

class Counter extends PureComponent {
  static propTypes = {
    borderColor: PropTypes.oneOf(['neutral', 'mint', 'aqua', 'violet', 'teal', 'gold', 'ruby', 'tealdark']),
    className: PropTypes.string,
    color: PropTypes.oneOf(['neutral', 'mint', 'aqua', 'violet', 'teal', 'gold', 'ruby']),
    count: PropTypes.number,
    maxCount: PropTypes.number,
    size: PropTypes.oneOf(['small', 'medium']),
  };

  static defaultProps = {
    borderColor: 'neutral',
    color: 'neutral',
    size: 'medium',
  };

  render() {
    const { borderColor, className, color, count, maxCount, size, ...others } = this.props;

    const classNames = cx(
      theme['counter'],
      theme[color],
      theme[size],
      theme[`border-${borderColor}`],
      className,
    );

    return (
      <Box className={classNames} element="span" {...others} data-teamleader-ui="counter">
        {count > maxCount ? `${maxCount}+` : count}
      </Box>
    );
  }
}

export default Counter;
<commit_msg>count prop is required now<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import cx from 'classnames';
import theme from './theme.css';

class Counter extends PureComponent {
  static propTypes = {
    borderColor: PropTypes.oneOf(['neutral', 'mint', 'aqua', 'violet', 'teal', 'gold', 'ruby', 'tealdark']),
    className: PropTypes.string,
    color: PropTypes.oneOf(['neutral', 'mint', 'aqua', 'violet', 'teal', 'gold', 'ruby']),
    count: PropTypes.number.isRequired,
    maxCount: PropTypes.number,
    size: PropTypes.oneOf(['small', 'medium']),
  };

  static defaultProps = {
    borderColor: 'neutral',
    color: 'neutral',
    size: 'medium',
  };

  render() {
    const { borderColor, className, color, count, maxCount, size, ...others } = this.props;

    const classNames = cx(theme['counter'], theme[color], theme[size], theme[`border-${borderColor}`], className);

    return (
      <Box className={classNames} element="span" {...others} data-teamleader-ui="counter">
        {count > maxCount ? `${maxCount}+` : count}
      </Box>
    );
  }
}

export default Counter;
<|endoftext|>


<commit_before>/* global define */

define([
    'marionette',
    '../core',
    '../query'
], function(Marionette, c, query) {

    var WorkspaceWorkflow = Marionette.Layout.extend({
        className: 'workspace-workflow',

        template: 'workflows/workspace',

        regions: {
            queries: '.query-region',
            publicQueries: '.public-query-region',
        },

        regionViews: {
            queries: query.QueryList,
            publicQueries: query.QueryList
        },

        initialize: function() {
            this.data = {};

            if (c.isSupported('2.2.0')) {
                if (!(this.data.publicQueries = this.options.public_queries)) {  // jshint ignore:line
                    throw new Error('public queries collection required');
                }
            }

            if (!(this.data.queries = this.options.queries)) {
                throw new Error('queries collection required');
            }

            if (!(this.data.context = this.options.context)) {
                throw new Error('context model required');
            }

            if (!(this.data.view = this.options.view)) {
                throw new Error('view model required');
            }

            // When this workflow is loaded, toggle shared components
            this.on('router:load', function() {
                // Fully hide the panel; do not leave an edge to show/hide
                c.panels.context.closePanel({full: true});
                c.panels.concept.closePanel({full: true});
            });
        },

        onRender: function() {
            this.queryView = new this.regionViews.queries({
                collection: this.data.queries,
                context: this.data.context,
                view: this.data.view,
                editable: true
            });

            if (c.isSupported('2.2.0')) {
                this.publicQueryView = new this.regionViews.publicQueries({
                    collection: this.data.publicQueries,
                    context: this.data.context,
                    view: this.data.view,
                    title: 'Public Queries',
                    emptyMessage: "There are no public queries. You can create a " +
                                  "new, public query by navigating to the 'Results'" +
                                  "page and clicking on the 'Save Query...' button. " +
                                  "While filling out the query form, you can mark " +
                                  "the query as public which will make it visible " +
                                  "to all users and cause it to be listed here."
                });

                // When the queries are synced we need to manually update the
                // public queries collection so that any changes to public
                // queries are reflected there. Right now, this is done lazily
                // rather than checking if the changed model is public or had
                // its publicity changed. If this becomes too slow we can
                // perform these checks but for now this is snappy enough.
                this.listenTo(this.data.queries, 'sync', function() {
                    this.data.publicQueries.fetch({reset: true});
                });
            }

            this.listenTo(c.data.concepts, 'reset', function() {
                this.queries.show(this.queryView);

                if (this.publicQueries) {
                    this.publicQueries.show(this.publicQueryView);
                }
            });
        }
    });

    return {
        WorkspaceWorkflow: WorkspaceWorkflow
    };

});
<commit_msg>Fix issue with navigating to the workspace via navigation bar<commit_after>/* global define */

define([
    'marionette',
    '../core',
    '../query'
], function(Marionette, c, query) {

    var WorkspaceWorkflow = Marionette.Layout.extend({
        className: 'workspace-workflow',

        template: 'workflows/workspace',

        regions: {
            queries: '.query-region',
            publicQueries: '.public-query-region',
        },

        regionViews: {
            queries: query.QueryList,
            publicQueries: query.QueryList
        },

        initialize: function() {
            this.data = {};

            if (c.isSupported('2.2.0')) {
                if (!(this.data.publicQueries = this.options.public_queries)) {  // jshint ignore:line
                    throw new Error('public queries collection required');
                }
            }

            if (!(this.data.queries = this.options.queries)) {
                throw new Error('queries collection required');
            }

            if (!(this.data.context = this.options.context)) {
                throw new Error('context model required');
            }

            if (!(this.data.view = this.options.view)) {
                throw new Error('view model required');
            }

            // When this workflow is loaded, toggle shared components
            this.on('router:load', function() {
                // Fully hide the panel; do not leave an edge to show/hide
                c.panels.context.closePanel({full: true});
                c.panels.concept.closePanel({full: true});
            });
        },

        onRender: function() {
            var queryView = new this.regionViews.queries({
                collection: this.data.queries,
                context: this.data.context,
                view: this.data.view,
                editable: true
            });

            this.queries.show(queryView);

            if (c.isSupported('2.2.0')) {
                var publicQueryView = new this.regionViews.publicQueries({
                    collection: this.data.publicQueries,
                    context: this.data.context,
                    view: this.data.view,
                    title: 'Public Queries',
                    emptyMessage: "There are no public queries. You can create a " +
                                  "new, public query by navigating to the 'Results'" +
                                  "page and clicking on the 'Save Query...' button. " +
                                  "While filling out the query form, you can mark " +
                                  "the query as public which will make it visible " +
                                  "to all users and cause it to be listed here."
                });

                // We explicitly set the editable option to false below because
                // users should not be able to edit the public queries
                // collection.
                this.publicQueries.show(publicQueryView);

                // When the queries are synced we need to manually update the
                // public queries collection so that any changes to public
                // queries are reflected there. Right now, this is done lazily
                // rather than checking if the changed model is public or had
                // its publicity changed. If this becomes too slow we can
                // perform these checks but for now this is snappy enough.
                this.listenTo(this.data.queries, 'sync', function() {
                    this.data.publicQueries.fetch({reset: true});
                });

            }

            this.listenTo(c.data.concepts, 'reset', function() {
                this.queries.show(queryView);

                if (this.publicQueries) {
                    this.publicQueries.show(publicQueryView);
                }
            });
        }
    });

    return {
        WorkspaceWorkflow: WorkspaceWorkflow
    };

});
<|endoftext|>


<commit_before>import anime from 'animejs';
import Logger from '../util/logger';

export default class FillCanvas {
  /* eslint no-param-reassign: "warn", class-methods-use-this: "warn" */
  constructor() {
    this.c = document.getElementById('backgroundPost');
    this.cxt = this.c.getContext('2d');
    this.toBind = $('.magicLink');
    this.cH = 0;
    this.cW = 0;
    this.animations = [];
    this.circles = [];
    this.colors = ['black', 'rgba(0, 0, 0, 0)'];
    this.colorPicker.index = 0;
    this.classBig = 'current_post';
    this.cloneCheck = true;
  }

  init() {
    Logger.log('begin', 'the expand function');
    this.resizeCanvas(); // Fix me?
    this.addMethods(); // Adds methods on bricks and circles to be called when animating
    window.addEventListener('resize', this.resizeCanvas);
    this.addClickListeners(this.toBind); // Adds triggers - animations will add to queue.
    this.animate(); // Begins animation engine - implaments queue.
  }

  addClickListeners(toBind) {
    const handleEvent = this.handleEvent;
    const bind = (i, x) => {
      x.addEventListener('touchstart',
        (e) => { handleEvent.call(this, e); }
      );
      x.addEventListener('mousedown',
        (e) => { handleEvent.call(this, e); }
      );
    };
    if (toBind instanceof jQuery) {
      $(toBind).each((i, x) => bind(i, x));
    } else {
      bind(0, toBind);
    }
  }

  handleEvent(e) {
    // Correct the event
    if (e.touches) {
      e.preventDefault();
      e = e.touches[0];
    }

    // Load variables
    const color = this.colorPicker();
    const currentColor = 'white';
    const nextColor = color.next;
    const targetR = Math.sqrt(
      Math.pow(
        Math.max(e.pageX - 0, this.cW - e.pageX), 2
      ) + Math.pow(
        Math.max(e.pageY - 0, this.cH - e.pageY), 2
      )
    );
    const rippleSize = Math.min(200, (this.cW * 0.4));
    const minCoverDuration = 750;
    const e2 = e || window.event;
    const element = e2.target || e2.srcElement;
    const newPage = $(element).closest('article');
    const removeAnimation = (animation) => {
      const index = this.animations.indexOf(animation); // indexOf works on what?
      Logger.log(`Supplimental. Removing animation ${animation} with index of ${index}`);
      if (index > -1) this.animations.splice(index, 1);
    };

    // Create page filling obj and animation
    const pageFill = new this.Circle({
      x: e.pageX,
      y: e.pageY,
      r: 0,
      fill: nextColor,
    });
    const fillAnimation = anime({
      targets: pageFill,
      r: targetR,
      duration: Math.max(targetR / 2, minCoverDuration),
      easing: 'easeOutQuart',
    });

    // Create ripple obj and animation
    const ripple = new this.Circle({
      x: e.pageX,
      y: e.pageY,
      r: 0,
      fill: currentColor,
      stroke: {
        width: 3,
        color: currentColor,
      },
      opacity: 1,
    });
    const rippleAnimation = anime({
      targets: ripple,
      r: rippleSize,
      opacity: {
        value: 0,
        delay: 400,
        duration: 600,
      },
      easing: 'easeOutExpo',
      duration: 900,
      complete: removeAnimation,
    });

    // Create particle objects and animation
    const particles = [];
    for (let i = 0; i < 20; i += 1) {
      const particle = new this.Circle({
        x: e.pageX,
        y: e.pageY,
        fill: currentColor,
        r: anime.random(30, 60),
      });
      particles.push(particle);
    }
    const particlesAnimation = anime({
      targets: particles,
      x(particle) {
        return particle.x + anime.random(rippleSize, -rippleSize);
      },
      y(particle) {
        return particle.y + anime.random(rippleSize * 1.15, -rippleSize * 1.15);
      },
      r: 0,
      easing: 'easeOutExpo',
      duration: anime.random(1000, 1300),
      complete: removeAnimation,
    });

    // Create brick animation and add method for returning bricks
    const bricks = document.querySelectorAll('.brick:not(.current_post)');
    for (const brick of bricks) {
      brick.draw = this.clonePost(newPage);
    }

    const brickAnimation = anime({
      targets: bricks,
      rotate: 500,
      translateX() {
        const random = (Math.floor(Math.random() * 2) ? -1 : 1) *
          (Math.floor(Math.random() * 600) + 600);
        return random;
      },
      translateY() {
        const random = (Math.floor(Math.random() * 2) ? -1 : 1) *
          (Math.floor(Math.random() * 300) + 600);
        return random;
      },
      duration() {
        return anime.random(500, 900); // Will set a random value from 50 to 100 to each divs
      },
      easing: 'linear',
      complete: removeAnimation,
    });
    Logger.log('On the launchpad');
    // Change the class, and enque the animations
    if (!newPage.hasClass(this.classBig)) {
      newPage.addClass(this.classBig);
      this.clonePost(newPage);
      this.animations.push(brickAnimation, fillAnimation, rippleAnimation, particlesAnimation);
    } else {
      Logger.log('We.re getting outta here');
      newPage.removeClass(this.classBig);
      removeAnimation(fillAnimation);
      removeAnimation(brickAnimation);
      this.animations.push(fillAnimation, rippleAnimation, particlesAnimation);
    }
  } // handleEvent

  colorPicker() {
    const colors = this.colors;
    const nextIndex = this.index < (colors.length - 1) ? this.index + 1 : 0;
    const currentCol = colors[this.index];
    const nextCol = colors[nextIndex];
    Logger.log(`Current color is ${this.index}, the next will be ${nextIndex}`);
    this.index = nextIndex;
    return {
      next: nextCol,
      current: currentCol,
    };
  }

  Circle(opts) {
    Object.assign(this, opts);
  }

  addMethods() {
    this.Circle.prototype.draw = function (cxt) {
      cxt.globalAlpha = this.opacity || 1;
      cxt.beginPath();
      cxt.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
      if (this.fill) {
        cxt.fillStyle = this.fill;
        cxt.fill();
      }
      cxt.closePath();
      cxt.globalAlpha = 1;
    };
  }

  extend(a, b) {
    return Object.assign(a, b);
  }

  animate() {
    const cW = this.cW;
    const cH = this.cH;
    const cxt = this.cxt;
    const animations = this.animations;

    anime({
      duration: Infinity,
      update() {
        cxt.fillStyle = 'transparent';
        cxt.fillRect(0, 0, cW, cH);
        animations.forEach((anim) => {
          anim.animatables.forEach((animatable) => {
            if (typeof animatable.target.draw !== 'undefined') {
              animatable.target.draw(cxt);
            }
          });
        });
      },
    });
  }

  resizeCanvas() {
    this.cW = window.innerWidth;
    this.cH = window.innerHeight;
    this.c.width = this.cW * window.devicePixelRatio;
    this.c.height = this.cH * window.devicePixelRatio;
    this.cxt.scale(window.devicePixelRatio, window.devicePixelRatio);
  }

  clonePost($brick) {
    if (this.cloneCheck) {
      this.cloneCheck = false;
      const currentPos = $brick[0].getBoundingClientRect();
      const currentDim = {
        x: currentPos.right - currentPos.left,
        y: currentPos.bottom - currentPos.top,
      };
      const $clone = $brick.clone(true, true);
      $clone.attr('id', 'bigBaby');
      this.addClickListeners($clone);
      $clone.css({
        width: currentDim.x,
        top: currentPos.top,
        left: currentPos.left,
        transition: 'all 2s',
      });
      $clone.appendTo('#heightDefined');
      $('main').css('z-index', 50);
    }
  }
}
<commit_msg>Animation script better encapsulated<commit_after>import anime from 'animejs';
import Logger from '../util/logger';

export default class FillCanvas {
  /* eslint no-param-reassign: "warn", class-methods-use-this: "warn" */
  constructor() {
    this.c = document.getElementById('backgroundPost');
    this.cxt = this.c.getContext('2d');
    this.toBind = $('.magicLink');
    this.cH = 0;
    this.cW = 0;
    this.animations = [];
    this.circles = [];
    this.classBig = 'current_post';
    this.cloneCheck = true;
  }

  init() {
    Logger.log('begin', 'the expand function');
    this.resizeCanvas(); // Fix me?
    this.addMethods(); // Adds methods on bricks and circles to be called when animating
    window.addEventListener('resize', this.resizeCanvas);
    this.addClickListeners(this.toBind); // Adds triggers - animations will add to queue.
    this.animate(); // Begins animation engine - implaments queue.
  }

  addClickListeners(toBind) {
    const handleEvent = this.handleEvent;
    const bind = (i, x) => {
      x.addEventListener('touchstart',
        (e) => { handleEvent.call(this, e); }
      );
      x.addEventListener('mousedown',
        (e) => { handleEvent.call(this, e); }
      );
    };
    if (toBind instanceof jQuery) {
      $(toBind).each((i, x) => bind(i, x));
    } else {
      bind(0, toBind);
    }
  }

  handleEvent(e) {
    // Correct the event
    if (e.touches) {
      e.preventDefault();
      e = e.touches[0];
    }

    // Load variables
    const currentColor = 'white';
    const nextColor = 'black';
    const targetR = Math.sqrt(
      Math.pow(
        Math.max(e.pageX - 0, this.cW - e.pageX), 2
      ) + Math.pow(
        Math.max(e.pageY - 0, this.cH - e.pageY), 2
      )
    );
    const rippleSize = Math.min(200, (this.cW * 0.4));
    const minCoverDuration = 750;
    const e2 = e || window.event;
    const element = e2.target || e2.srcElement;
    const newPage = $(element).closest('article');
    const removeAnimation = (animation) => {
      const index = this.animations.indexOf(animation); // indexOf works on what?
      Logger.log(`Supplimental. Removing animation ${animation} with index of ${index}`);
      if (index > -1) this.animations.splice(index, 1);
    };
    const funcPageFiller = function () {
      // Create page filling obj and animation
      this.pageFill = new this.Circle({
        x: e.pageX,
        y: e.pageY,
        r: 0,
        fill: nextColor,
      });
      this.fillAnimation = anime({
        targets: this.pageFill,
        r: targetR,
        duration: Math.max(targetR / 2, minCoverDuration),
        easing: 'easeOutQuart',
      });
    }.bind(this);

    // Create ripple obj and animation
    const funcRipple = function () {
      this.ripple = new this.Circle({
        x: e.pageX,
        y: e.pageY,
        r: 0,
        fill: currentColor,
        stroke: {
          width: 3,
          color: currentColor,
        },
        opacity: 1,
      });
      this.rippleAnimation = anime({
        targets: this.ripple,
        r: rippleSize,
        opacity: {
          value: 0,
          delay: 400,
          duration: 600,
        },
        easing: 'easeOutExpo',
        duration: 900,
        complete: this.removeAnimation,
      });
    }.bind(this);

    // Create particle objects and animation
    const funcParticles = function () {
      this.particles = [];
      for (let i = 0; i < 20; i += 1) {
        const particle = new this.Circle({
          x: e.pageX,
          y: e.pageY,
          fill: currentColor,
          r: anime.random(30, 60),
        });
        this.particles.push(particle);
      }
      this.particlesAnimation = anime({
        targets: this.particles,
        x(particle) {
          return particle.x + anime.random(rippleSize, -rippleSize);
        },
        y(particle) {
          return particle.y + anime.random(rippleSize * 1.15, -rippleSize * 1.15);
        },
        r: 0,
        easing: 'easeOutExpo',
        duration: anime.random(1000, 1300),
        complete: this.removeAnimation,
      });
    }.bind(this);

    // Create brick animation and add method for returning bricks
    const funcBricksplosion = () => {
      this.bricks = document.querySelectorAll('.brick:not(.current_post)');
      for (const brick of this.bricks) {
        brick.draw = this.clonePost(newPage);
      }
      this.brickAnimation = anime({
        targets: this.bricks,
        rotate: 500,
        translateX() {
          const random = (Math.floor(Math.random() * 2) ? -1 : 1) *
            (Math.floor(Math.random() * 600) + 600);
          return random;
        },
        translateY() {
          const random = (Math.floor(Math.random() * 2) ? -1 : 1) *
            (Math.floor(Math.random() * 300) + 600);
          return random;
        },
        duration() {
          return anime.random(500, 900); // Will set a random value from 50 to 100 to each divs
        },
        easing: 'linear',
        complete: this.removeAnimation,
      });
    };

    // Change the class, and enque the animations
    Logger.log('On the launchpad');
    if (!newPage.hasClass(this.classBig)) {
      funcPageFiller();
      funcRipple();
      funcParticles();
      funcBricksplosion();
      newPage.addClass(this.classBig);
      this.clonePost(newPage);
      this.animations.push(
        this.brickAnimation,
        this.fillAnimation,
        this.rippleAnimation,
        this.particlesAnimation
      );
    } else {
      Logger.log('We.re getting outta here');
      funcRipple();
      funcParticles();
      newPage.removeClass(this.classBig);
      removeAnimation(this.fillAnimation);
      removeAnimation(this.brickAnimation);
      this.animations.push(this.rippleAnimation, this.particlesAnimation);
    }
  } // handleEvent

  Circle(opts) {
    Object.assign(this, opts);
  }

  addMethods() {
    this.Circle.prototype.draw = function (cxt) {
      cxt.globalAlpha = this.opacity || 1;
      cxt.beginPath();
      cxt.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
      if (this.fill) {
        cxt.fillStyle = this.fill;
        cxt.fill();
      }
      cxt.closePath();
      cxt.globalAlpha = 1;
    };
  }

  extend(a, b) {
    return Object.assign(a, b);
  }

  animate() {
    const cW = this.cW;
    const cH = this.cH;
    const cxt = this.cxt;
    const animations = this.animations;

    anime({
      duration: Infinity,
      update() {
        cxt.fillStyle = 'transparent';
        cxt.fillRect(0, 0, cW, cH);
        animations.forEach((anim) => {
          anim.animatables.forEach((animatable) => {
            if (typeof animatable.target.draw !== 'undefined') {
              animatable.target.draw(cxt);
            }
          });
        });
      },
    });
  }

  resizeCanvas() {
    this.cW = window.innerWidth;
    this.cH = window.innerHeight;
    this.c.width = this.cW * window.devicePixelRatio;
    this.c.height = this.cH * window.devicePixelRatio;
    this.cxt.scale(window.devicePixelRatio, window.devicePixelRatio);
  }

  clonePost($brick) {
    if (this.cloneCheck) {
      this.cloneCheck = false;
      const currentPos = $brick[0].getBoundingClientRect();
      const currentDim = {
        x: currentPos.right - currentPos.left,
        y: currentPos.bottom - currentPos.top,
      };
      const $clone = $brick.clone(true, true);
      $clone.attr('id', 'bigBaby');
      this.addClickListeners($clone);
      $clone.css({
        width: currentDim.x,
        top: currentPos.top,
        left: currentPos.left,
        transition: 'all 2s',
      });
      $clone.appendTo('#heightDefined');
      $('main').css('z-index', 50);
    }
  }
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.audio',
  name: 'Beep',

  imports: [
    'setTimeout',
    'window'
  ],

  properties: [
    [ 'gain', 1.0 ],
    [ 'duration', 200 ],
    {
      name: 'type',
      value: 'sine',
      view: { class: 'foam.u2.view.ChoiceView', choices: [ 'sine', 'square', 'sawtooth', 'triangle' ] },
    },
    [ 'frequency' , 220 ]
  ],

  actions: [
    function play() {
      var audio = new this.window.AudioContext();
      var destination = audio.destination;
      var o = audio.createOscillator();
      var gain;
      if ( this.gain !== 1 ) {
        console.log('gain: ', this.gain);
        gain = audio.createGain();
        gain.gain.value = this.gain;
        gain.connect(destination);
        destination = gain;
      }
      o.frequency.value = this.frequency;
      o.type = this.type;
      o.connect(destination);
      o.start(0);
      this.setTimeout(function() {
        o.stop(0);
        if ( gain ) gain.disconnect(audio.destination);
        o.disconnect(destination);
        audio.close();
      }, this.duration);
    }
  ]
});
<commit_msg>Add Frequency Modulation to Beep.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.audio',
  name: 'Beep',

  imports: [
    'setTimeout',
    'window'
  ],

  properties: [
    [ 'gain', 1.0 ],
    [ 'duration', 200 ],
    {
      name: 'type',
      value: 'sine',
      view: { class: 'foam.u2.view.ChoiceView', choices: [ 'sine', 'square', 'sawtooth', 'triangle' ] },
    },
    [ 'frequency' , 220 ],
    [ 'fmFrequency', 0 ],
    [ 'fmAmplitude', 20 ],
    {
      name: 'fmType',
      value: 'sine',
      view: { class: 'foam.u2.view.ChoiceView', choices: [ 'sine', 'square', 'sawtooth', 'triangle' ] },
    },
  ],

  actions: [
    function play() {
      var audio = new this.window.AudioContext();
      var destination = audio.destination;
      var o = audio.createOscillator();
      var gain, fm, fmGain;

      if ( this.gain !== 1 ) {
        console.log('gain: ', this.gain);
        gain = audio.createGain();
        gain.gain.value = this.gain;
        gain.connect(destination);
        destination = gain;
      }
      o.frequency.value = this.frequency;
      o.type = this.type;
      o.connect(destination);

      if ( this.fmFrequency ) {
        fmGain = audio.createGain();
        fmGain.gain.value = this.fmAmplitude;
        fm = audio.createOscillator();
        fm.frequency.value = this.fmFrequency;
        fm.type = this.fmType;
        fm.connect(fmGain);
        fmGain.connect(o.frequency);
        fm.start();
      }
      o.start(0);

      this.setTimeout(function() {
        o.stop(0);
        if ( gain ) gain.disconnect(audio.destination);
        if ( fmGain ) fmGain.disconnect(o.frequency);
        if ( fm ) fm.stop(0);
        o.disconnect(destination);
        audio.close();
      }, this.duration);
    }
  ]
});
<|endoftext|>


<commit_before>var sfa = sfa || {};

sfa.homePage = {
    init: function () {
        this.startButton();
        this.toggleRadios();
    },
    startButton: function () {
        var that = this;
        $('#submit-button').on('click touchstart', function (e) {
            var isYesClicked = $('#have-everything').prop('checked'),
                errorShown = $('body').data('shownError') || false;
            if (!isYesClicked && !errorShown) {
                e.preventDefault();
                that.showError();
            }
        });
    },
    showError: function() {
        $('.error-message').removeClass("js-hidden").attr("aria-hidden");
        $('#what-you-need-form').addClass("error");
        $('body').data('shownError', true);
    },
    toggleRadios: function () {
        var radios = $('input[type=radio][name=everything-you-need]');
        radios.on('change', function () {

            radios.each(function () {
                if ($(this).prop('checked')) {
                    var target = $(this).parent().data("target");
                    $("#" + target).removeClass("js-hidden").attr("aria-hidden");
                } else {
                    var target = $(this).parent().data("target");
                    $("#" + target).addClass("js-hidden").attr("aria-hidden", "true");
                }
            });

        });
    }
}

sfa.navigation = {
    elems: {
        userNav: $('nav#user-nav > ul'),
        levyNav: $('ul#global-nav-links')
    },
    init: function () {
        this.setupMenus(this.elems.userNav);
        this.setupEvents(this.elems.userNav);
    },
    setupMenus: function (menu) {
       menu.find('ul').addClass("js-hidden").attr("aria-hidden", "true");
    },
    setupEvents: function (menu) {
        var that = this;
        menu.find('li.has-sub-menu > a').on('click', function (e) {
            var $that = $(this);
            that.toggleMenu($that, $that.next('ul'));
            e.stopPropagation();
            e.preventDefault();
        });
        // Focusout event on the links in the dropdown menu
        menu.find('li.has-sub-menu > ul > li > a').on('focusout', function (e) {
            // If its the last link in the drop down menu, then close
            var $that = $(this);
            if ($(this).parent().is(':last-child')) {
                that.toggleMenu($that, $that.next('ul'));
            }
        });

    },
    toggleMenu: function (link, subMenu) {
        var $li = link.parent();
        if ($li.hasClass("open")) {
            // Close menu
            $li.removeClass("open");
            subMenu.addClass("js-hidden").attr("aria-hidden", "true");
        } else {
            // Open menu
            this.closeAllOpenMenus();
            $li.addClass("open");
            subMenu.removeClass("js-hidden").attr("aria-hidden", "false");
        }
    },
    closeAllOpenMenus: function () {
        this.elems.userNav.find('li.has-sub-menu.open').removeClass('open').find('ul').addClass("js-hidden").attr("aria-hidden", "true");
        this.elems.levyNav.find('li.open').removeClass('open').addClass("js-hidden").attr("aria-hidden", "true");
    },
    linkSettings: function () {
        var $settingsLink = $('a#link-settings'),
            that = this;
        this.toggleUserMenu();
        $settingsLink.attr("aria-hidden", "false");
        $settingsLink.on('click touchstart', function (e) {
            var target = $(this).attr('href');
            $(this).toggleClass('open');
            that.toggleUserMenu();
            e.preventDefault();
        });
    },
    toggleUserMenu: function () {
        var $userNavParent = this.elems.userNav.parent();
        if ($userNavParent.hasClass("close")) {
            //open it
            $userNavParent.removeClass("close").attr("aria-hidden", "false");
        } else {
            // close it
            $userNavParent.addClass("close").attr("aria-hidden", "true");
        }
    }
}

sfa.forms = {
    init: function () {
        this.preventDoubleSubmit();
    },
    preventDoubleSubmit: function () {
        var forms = $('form').not('.has-client-side-validation');
        forms.on('submit', function (e) {
            var button = $(this).find('.button');
            button.attr('disabled', 'disabled');
            setTimeout(function () {
                button.removeAttr('disabled');
            }, 20000);
        });
    },
    removeDisabledAttr: function () {
        var btns = $('form').not('.has-client-side-validation').find('.button');
        btns.removeAttr('disabled');
    }
}

sfa.backLink = {
    init: function () {
        var backLink = $('<a>')
            .attr({ 'href': '#', 'class': 'link-back' })
            .text('Back')
            .on('click', function (e) { window.history.back(); e.preventDefault(); });
        $('#js-breadcrumbs').html(backLink);
    }
}

if (localStorage.getItem("answers") === null) {
    localStorage.setItem("answers", JSON.stringify([]));
}

var getAnswers = JSON.parse(localStorage.getItem("answers"));

sfa.welcomeWizard = {
    settings :  {
        noSteps: $('#welcome').data('total-steps'),
        accountId: $('#welcome').data('account-id')
    },
    init: function () {
        var that = this;

        var getAnswers = JSON.parse(localStorage.getItem("answers"));
		var indexAnswer = getIndexOf(this.settings.accountId, getAnswers);
		var answers = {};
		answers.accountId = this.settings.accountId;

		if (indexAnswer > -1) {
		    answers = getAnswers[indexAnswer];
		} else {
		    getAnswers.push(answers);
		}

		var radios = $('#welcome input:radio');

		var score = 0;
        radios.filter(':checked').each(function () {
		    score += parseInt($(this).val(), 10);
		});

		$('#confirmation').hide();

        radios.on('change', function () {
            answers[this.name] = this.value;
            listItem = $(this).closest('.todo-list--item');
            that.radioChange($(this).val(), listItem);
            localStorage.setItem("answers", JSON.stringify(getAnswers));
        });

        $.each(answers, function (i, val) {
            if (i !== 'accountId') {
                if (answers[i]) {
                    $("input[name='" + i + "'][value=" + val + "]").click()
                        .closest('.todo-list--item').removeClass('js-hidden').attr('aria-hidden', false);
                }
            }
        });

        this.editLinks();
    },
    editLinks: function () {
        var h2s = $('#welcome').find('h2');
        var that = this;
        var editLink = $('<a>')
                        .text('(review this step)')
                        .attr('href', '#')
                        .on('click', function (e) {
                            that.toggleStep($(this).closest('.todo-list--item'));
                            e.preventDefault();
                        });

        h2s.append(editLink);
    },
    toggleStep: function (step) {
        if (step.hasClass('complete')) {
            step.removeClass('complete');
        } else {
            step.addClass('complete');
        }
    },
    showStep: function (step) {
        step.removeClass('js-hidden').attr('aria-hidden', false);
    },
    radioChange: function (radioValue, listItem) {
        var that = this;
        if (radioValue == 2) {
            that.toggleStep(listItem);
            if (listItem.data('step') < that.settings.noSteps) {
                that.showStep(listItem.next());
            }
        }

        var score = 0;
        $('#welcome input:radio:checked').each(function () {
            score += parseInt($(this).val(), 10);
        });

        if (score == (that.settings.noSteps * 2)) {
            $('#confirmation').show();
        } else {
            $('#confirmation').hide();
        }
    }
}

getIndexOf = function (accountId, items) {
    var i = 0;
    var len = items.length;
    for (i = 0; i < len; i++) {
        if (accountId === items[i].accountId) {
            return i;
        }
    }
    return -1;
}

if ($('#js-breadcrumbs')) {
    sfa.backLink.init();
}

if ($('#welcome')) {
    sfa.welcomeWizard.init();
}

// Removed disabled attribute from buttons when user leaves the page
window.onunload = function () {
    sfa.forms.removeDisabledAttr();
};

sfa.forms.init();
sfa.navigation.init();
$('ul#global-nav-links').collapsableNav();

var selectionButtons = new GOVUK.SelectionButtons("label input[type='radio'], label input[type='checkbox'], section input[type='radio']");
var selectionButtonsOrgType = new GOVUK.SelectionButtons("section input[type='radio']", { parentElem: 'section' });

var showHideContent = new GOVUK.ShowHideContent();
showHideContent.init();

// stop apprentice - show/hide date block
$(".js-enabled #stop-effective").hide();

$(".js-enabled #WhenToMakeChange-Immediately").on('click touchstart', (function () {
    $("#stop-effective").hide();
}));

$(".js-enabled #WhenToMakeChange-SpecificDate").on('click touchstart', (function () {
    $("#stop-effective").show();
}));

if ($("#WhenToMakeChange-SpecificDate").is(':checked')) {
    $("#stop-effective").show();
}

// cohorts bingo balls - clickable block
$(".clickable").on('click touchstart', (function () {
    window.location = $(this).find("a").attr("href");
    return false;
}));

// apprentice filter page :: expand/collapse functionality
$('.container-head').on('click touchstart', (function () {
    $(this).toggleClass('showHide');
    $(this).next().toggleClass("hideOptions");

}));

<commit_msg>Correctly show completed steps when returning to the welcome wizard using the back button<commit_after>var sfa = sfa || {};

sfa.homePage = {
    init: function () {
        this.startButton();
        this.toggleRadios();
    },
    startButton: function () {
        var that = this;
        $('#submit-button').on('click touchstart', function (e) {
            var isYesClicked = $('#have-everything').prop('checked'),
                errorShown = $('body').data('shownError') || false;
            if (!isYesClicked && !errorShown) {
                e.preventDefault();
                that.showError();
            }
        });
    },
    showError: function() {
        $('.error-message').removeClass("js-hidden").attr("aria-hidden");
        $('#what-you-need-form').addClass("error");
        $('body').data('shownError', true);
    },
    toggleRadios: function () {
        var radios = $('input[type=radio][name=everything-you-need]');
        radios.on('change', function () {

            radios.each(function () {
                if ($(this).prop('checked')) {
                    var target = $(this).parent().data("target");
                    $("#" + target).removeClass("js-hidden").attr("aria-hidden");
                } else {
                    var target = $(this).parent().data("target");
                    $("#" + target).addClass("js-hidden").attr("aria-hidden", "true");
                }
            });

        });
    }
}

sfa.navigation = {
    elems: {
        userNav: $('nav#user-nav > ul'),
        levyNav: $('ul#global-nav-links')
    },
    init: function () {
        this.setupMenus(this.elems.userNav);
        this.setupEvents(this.elems.userNav);
    },
    setupMenus: function (menu) {
       menu.find('ul').addClass("js-hidden").attr("aria-hidden", "true");
    },
    setupEvents: function (menu) {
        var that = this;
        menu.find('li.has-sub-menu > a').on('click', function (e) {
            var $that = $(this);
            that.toggleMenu($that, $that.next('ul'));
            e.stopPropagation();
            e.preventDefault();
        });
        // Focusout event on the links in the dropdown menu
        menu.find('li.has-sub-menu > ul > li > a').on('focusout', function (e) {
            // If its the last link in the drop down menu, then close
            var $that = $(this);
            if ($(this).parent().is(':last-child')) {
                that.toggleMenu($that, $that.next('ul'));
            }
        });

    },
    toggleMenu: function (link, subMenu) {
        var $li = link.parent();
        if ($li.hasClass("open")) {
            // Close menu
            $li.removeClass("open");
            subMenu.addClass("js-hidden").attr("aria-hidden", "true");
        } else {
            // Open menu
            this.closeAllOpenMenus();
            $li.addClass("open");
            subMenu.removeClass("js-hidden").attr("aria-hidden", "false");
        }
    },
    closeAllOpenMenus: function () {
        this.elems.userNav.find('li.has-sub-menu.open').removeClass('open').find('ul').addClass("js-hidden").attr("aria-hidden", "true");
        this.elems.levyNav.find('li.open').removeClass('open').addClass("js-hidden").attr("aria-hidden", "true");
    },
    linkSettings: function () {
        var $settingsLink = $('a#link-settings'),
            that = this;
        this.toggleUserMenu();
        $settingsLink.attr("aria-hidden", "false");
        $settingsLink.on('click touchstart', function (e) {
            var target = $(this).attr('href');
            $(this).toggleClass('open');
            that.toggleUserMenu();
            e.preventDefault();
        });
    },
    toggleUserMenu: function () {
        var $userNavParent = this.elems.userNav.parent();
        if ($userNavParent.hasClass("close")) {
            //open it
            $userNavParent.removeClass("close").attr("aria-hidden", "false");
        } else {
            // close it
            $userNavParent.addClass("close").attr("aria-hidden", "true");
        }
    }
}

sfa.forms = {
    init: function () {
        this.preventDoubleSubmit();
    },
    preventDoubleSubmit: function () {
        var forms = $('form').not('.has-client-side-validation');
        forms.on('submit', function (e) {
            var button = $(this).find('.button');
            button.attr('disabled', 'disabled');
            setTimeout(function () {
                button.removeAttr('disabled');
            }, 20000);
        });
    },
    removeDisabledAttr: function () {
        var btns = $('form').not('.has-client-side-validation').find('.button');
        btns.removeAttr('disabled');
    }
}

sfa.backLink = {
    init: function () {
        var backLink = $('<a>')
            .attr({ 'href': '#', 'class': 'link-back' })
            .text('Back')
            .on('click', function (e) { window.history.back(); e.preventDefault(); });
        $('#js-breadcrumbs').html(backLink);
    }
}

if (localStorage.getItem("answers") === null) {
    localStorage.setItem("answers", JSON.stringify([]));
}

var getAnswers = JSON.parse(localStorage.getItem("answers"));

sfa.welcomeWizard = {
    settings :  {
        noSteps: $('#welcome').data('total-steps'),
        accountId: $('#welcome').data('account-id')
    },
    init: function () {
        var that = this;

        var getAnswers = JSON.parse(localStorage.getItem("answers"));
		var indexAnswer = getIndexOf(this.settings.accountId, getAnswers);
		var answers = {};
		answers.accountId = this.settings.accountId;

		if (indexAnswer > -1) {
		    answers = getAnswers[indexAnswer];
		} else {
		    getAnswers.push(answers);
		}

		var radios = $('#welcome input:radio');

		var score = 0;
        radios.filter(':checked').each(function () {
		    score += parseInt($(this).val(), 10);
		});

		$('#confirmation').hide();

        radios.on('change', function () {
            answers[this.name] = this.value;
            var listItem = $(this).closest('.todo-list--item');
            that.radioChange($(this).val(), listItem);
            localStorage.setItem("answers", JSON.stringify(getAnswers));
        });

        $.each(answers, function (i, val) {
            if (i !== 'accountId') {
                if (answers[i]) {
                    var radio = $("input[name='" + i + "'][value=" + val + "]")
                    if (radio.prop('checked') && val == 2) {
                        radio.closest('.todo-list--item').addClass('complete');
                    } else {
                        radio.click();
                    }
                    radio.closest('.todo-list--item').removeClass('js-hidden').attr('aria-hidden', false); // Show the entire row if its hidden
                }
            }
        });

        this.editLinks();
    },
    editLinks: function () {
        var h2s = $('#welcome').find('h2');
        var that = this;
        var editLink = $('<a>')
                        .text('(review this step)')
                        .attr('href', '#')
                        .on('click', function (e) {
                            that.toggleStep($(this).closest('.todo-list--item'));
                            e.preventDefault();
                        });

        h2s.append(editLink);
    },
    toggleStep: function (step) {
        if (step.hasClass('complete')) {
            step.removeClass('complete');
        } else {
            step.addClass('complete');
        }
    },
    showStep: function (step) {
        step.removeClass('js-hidden').attr('aria-hidden', false);
    },
    radioChange: function (radioValue, listItem) {
        var that = this;

        if (radioValue == 2) {
            listItem.addClass('complete');

            // If this step is not the last step, then show the next one
            if (listItem.data('step') < that.settings.noSteps) {
                that.showStep(listItem.next());
            }

        }

        var score = 0;
        $('#welcome input:radio:checked').each(function () {
            score += parseInt($(this).val(), 10);
        });

        if (score == (that.settings.noSteps * 2)) {
            $('#confirmation').show();
        } else {
            $('#confirmation').hide();
        }
    }
}

getIndexOf = function (accountId, items) {
    var i = 0;
    var len = items.length;
    for (i = 0; i < len; i++) {
        if (accountId === items[i].accountId) {
            return i;
        }
    }
    return -1;
}

if ($('#js-breadcrumbs')) {
    sfa.backLink.init();
}

if ($('#welcome')) {
    sfa.welcomeWizard.init();
}

// Removed disabled attribute from buttons when user leaves the page
window.onunload = function () {
    sfa.forms.removeDisabledAttr();
};

sfa.forms.init();
sfa.navigation.init();
$('ul#global-nav-links').collapsableNav();

var selectionButtons = new GOVUK.SelectionButtons("label input[type='radio'], label input[type='checkbox'], section input[type='radio']");
var selectionButtonsOrgType = new GOVUK.SelectionButtons("section input[type='radio']", { parentElem: 'section' });

var showHideContent = new GOVUK.ShowHideContent();
showHideContent.init();

// stop apprentice - show/hide date block
$(".js-enabled #stop-effective").hide();

$(".js-enabled #WhenToMakeChange-Immediately").on('click touchstart', (function () {
    $("#stop-effective").hide();
}));

$(".js-enabled #WhenToMakeChange-SpecificDate").on('click touchstart', (function () {
    $("#stop-effective").show();
}));

if ($("#WhenToMakeChange-SpecificDate").is(':checked')) {
    $("#stop-effective").show();
}

// cohorts bingo balls - clickable block
$(".clickable").on('click touchstart', (function () {
    window.location = $(this).find("a").attr("href");
    return false;
}));

// apprentice filter page :: expand/collapse functionality
$('.container-head').on('click touchstart', (function () {
    $(this).toggleClass('showHide');
    $(this).next().toggleClass("hideOptions");

}));

<|endoftext|>


<commit_before>function ElementModer(defaultMode) {
   this.elements = {};
   this.modes = {};
   if(!defaultMode) {
      this.mode = "default";
   }
   else {
      this.mode = defaultMode;
   }

   this.addElement = function(name, element) {
      this.elements[name] = element;
   };

   this.removeElement = function(name) {
      delete this.elements[name];
      for(var mode in this.modes) {
         delete this.modes[mode][name];
      }
   };

   this.setAttr = function(name, mode, attr) {
      if(!this.modes[mode]) {
         this.modes[mode] = {};
      }
      this.modes[mode][name] = attr;

      if(mode == this.mode) {
         this.elements[name].attr(attr);
      }
   };

   this.setMode = function(mode) {
      this.mode = mode;
      if(!this.modes[mode]) {
         this.modes[mode] = {};
         return;
      }
      for(var name in this.modes[mode]) {
         this.elements[name].attr(this.modes[mode][name]);
      }
   };

   this.getMode = function() {
      return this.mode;
   };
}

// LATER: should be allowed to customize the font in the button.

var _BUTTON_GUID = 0;

function Button(paper, xPos, yPos, width, height, text, repeat, initialDelay, stepDelay, delayFactory) {
   var self = this;
   _BUTTON_GUID++;
   this.guid = _BUTTON_GUID;

   this.init = function() {
      this.elements = {};
      var cornerRadius = 4;
      var shadowWidth = 1;
      this.elements.shadow = paper.rect(xPos + 1, yPos, width - 1 + shadowWidth, height + shadowWidth).attr({"r": cornerRadius});
      this.elements.rect = paper.rect(xPos, yPos, width, height).attr({"fill": "#dddddd", "r": cornerRadius});
      this.elements.text = paper.text(xPos + width / 2, yPos + height / 2, text).attr({"font-size": 16});
      this.elements.transLayer = paper.rect(xPos, yPos, width, height).attr({opacity: 0, fill: "black"});
      this.moder = new ElementModer("enabled");
      this.moder.addElement("shadow", this.elements.shadow);
      this.moder.addElement("rect", this.elements.rect);
      this.moder.addElement("text", this.elements.text);
      this.moder.setAttr("rect", "mousedown", {"fill": "#e5e5e5"});
      this.moder.setAttr("rect", "enabled", {"fill": "#dddddd"});
      this.moder.setAttr("rect", "disabled", {"fill": "#dddddd"});
      this.moder.setAttr("shadow", "enabled", {"fill": "black"});
      this.moder.setAttr("text", "enabled", {"fill": "black"});
      this.moder.setAttr("text", "mousedown", {"fill": "#aaaaaa"});
      this.moder.setAttr("text", "disabled", {"fill": "#aaaaaa"});
      this.elements.text[0].style.cursor = "default";
      this.enable();
   };

   this.applyFunction = function(funcName, argsList) {
      if(!argsList) {
         argsList = [];
      }
      for(var iElement in this.elements) {
         var element = this.elements[iElement];
         element[funcName].apply(element, argsList);
      }
   };

   this.enable = function() {
      if(this.enabled) {
         return;
      }
      this.enabled = true;
      this.mouseover = false;
      this.mousedown = false;

      var touchstart = function() {
         self.touchInProgress = true;
         self.lastTouchTime = new Date().getTime();
         handleMouseDown();
      }

      var mousedown = function() {
         if (self.touchInProgress) {
            return;
         }
         if (self.lastTouchTime != null) {
            var timeSinceTouch = new Date().getTime() - self.lastTouchTime;
            if (timeSinceTouch < 2000) {
               return;
            }
         }
         handleMouseDown();
      }

      var handleMouseDown = function() {
         if (self.lastMousedownTime != null) {
            var timeSinceDown = new Date().getTime() - self.lastMousedownTime;
            if (timeSinceDown < 100) {
               return;
            }
         }
         self.lastMousedownTime = new Date().getTime();
         if(self.mousedown){
            return
         }
         if(self.enabled) {
            self.mousedown = true;
            self.mouseover = true;
            self.moder.setMode("mousedown");
            if(repeat) {
               self._startRepeater();
            }
         }
      };

      var click = function() {
         if(self.enabled) {
            self.moder.setMode("enabled");
            if(!repeat && self.clickHandler) {
               self.clickHandler(self.clickData);
            }
         }
      };

      var touchend = function() {
         self.touchInProgress = false;
         self.lastTouchTime = new Date().getTime();
         mouseup();
      }

      var mouseup = function() {
         self.touchInProgress = false;
         if(self.enabled) {
            // If we received a mousedown event previously, and now the mouse is up
            // and the mouse is not over the button, then this was a drag attempt.
            if(self.mousedown && !self.mouseover) {
               if(self.dragAttemptHandler) {
                  self.dragAttemptHandler(self.dragAttemptData);
               }
            }
            self.mousedown = false;
            self.moder.setMode("enabled");
            if(repeat) {
               self._stopRepeater();
            }
         }
      };

      var mouseover = function() {
         if(self.enabled) {
            self.mouseover = true;
         }
      };

      var mouseout = function() {
         if(self.enabled) {
            self.mouseover = false;
         }
      };

      this.elements.transLayer.click(click);
      this.lastTouchTime = null;
      this.touchInProgress = false;
      this.lastMousedownTime = null;
      this.elements.transLayer.touchstart(touchstart);
      this.elements.transLayer.mousedown(mousedown);
      this.elements.transLayer.mouseover(mouseover);
      this.elements.transLayer.mouseout(mouseout);
      this.elements.transLayer.touchend(touchend);
      $(document).bind("mouseup.BUTTON_" + this.guid, mouseup);
      this.moder.setMode("enabled");
   };

   this._startRepeater = function() {
      if(!this.clickHandler) {
         return;
      }
      // First firing - immediately on mouse down.
      this.clickHandler(this.clickData);
      delayFactory.create(this.guid + "$buttonRepeatInitial", function() {
         // Second firing - after the initial delay.
         self.clickHandler(self.clickData);
         delayFactory.create(self.guid + "$buttonRepeatStep", function() {
            // Nth firing - after the step delay.
            self.clickHandler(self.clickData);
         }, stepDelay, true);
      }, initialDelay);
   };

   this._stopRepeater = function() {
      delayFactory.destroy(this.guid + "$buttonRepeatInitial");
      delayFactory.destroy(this.guid + "$buttonRepeatStep");
   };

   this.disable = function() {
      if(repeat) {
         this._stopRepeater();
      }
      this.moder.setMode("disabled");
      this.enabled = false;
      this.mouseover = false;
      this.mousedown = false;
      this.elements.transLayer.unclick();
      this.elements.transLayer.unmousedown();
      this.elements.transLayer.unmouseover();
      this.elements.transLayer.unmouseout();
   };

   this.click = function(handler, data) {
      this.clickHandler = handler;
      this.clickData = data;
   };

   this.unclick = function(handler) {
      delete this.clickHandler;
   };

   this.dragAttempt = function(handler, data) {
      this.dragAttemptHandler = handler;
      this.dragAttemptData = data;
   };

   this.setAttr = function(name, mode, attr) {
      this.moder.setAttr(name, mode, attr);
   };

   this.addElement = function(name, element) {
      this.elements[name] = element;
      this.moder.addElement(name, element);
      this.elements.transLayer.toFront();
   };

   this.changeOverlay = function(attr) {
      this.elements.transLayer.attr(attr);
   };

   this.show = function() {
      this.applyFunction("show");
   };

   this.getMode = function() {
      return this.moder.getMode();
   };

   this.hide = function() {
      this.applyFunction("hide");
   };

   this.remove = function() {
      $(document).unbind(".BUTTON_" + this.guid);
      this.disable();
      this.applyFunction("remove");
   };

   this.toFront = function() {
      this.elements.shadow.toFront();
      this.elements.rect.toFront();
      for(var iElement in this.elements) {
         if(iElement != "shadow" && iElement != "rect"){
            var element = this.elements[iElement];
            element.toFront();
         }
      }
      this.elements.transLayer.toFront();
   };

   this.init();
}

function Keyboard(data) {
   this.paper = data.paper;
   this.keys = data.keys;
   this.nRows = data.nRows;
   this.nCol = data.nCol;
   this.keyFiller = data.keyFiller;
   this.xPos = data.xPos;
   this.yPos = data.yPos;
   this.keyWidth = data.keyWidth;
   this.keyHeight = data.keyHeight;
   this.marginX = data.marginX;
   this.marginY = data.marginY;
   this.shiftOddRows = data.shiftOddRows;
   this.shiftEvenRows = data.shiftEvenRows;
   this.repeat = data.repeat;
   this.initialDelay = data.initialDelay;
   this.stepDelay = data.stepDelay;
   this.delayFactory = data.delayFactory;
   this.attr = data.attr;

   this.keyboard = [];

   for(var iRow = 0; iRow < this.nRows; iRow++){
      // this.keyboard[iRow] = [];
      for(var iCol = 0; iCol < this.nCol; iCol++){
         var x = this.xPos + iCol * (this.keyWidth + this.marginX);
         var y = this.yPos + iRow * (this.keyHeight + this.marginY);
         if (this.shiftOddRows && (iRow % 2 == 1)) {
            x += (this.keyWidth + this.marginX) / 2;
         }
         if (this.shiftEvenRows && (iRow % 2 == 0)) {
            x += (this.keyWidth + this.marginX) / 2;
         }
         var keyIndex = iCol + iRow * this.nCol;
         if (this.keys[keyIndex] != null) {
            var specialKey = (this.keyFiller) ? this.keyFiller(keyIndex,x,y) : null;
            if(!specialKey){
               var text = this.keys[keyIndex];
               this.keyboard[keyIndex] = new Button(this.paper,x,y,this.keyWidth,this.keyHeight,text,this.repeat, this.initialDelay, this.stepDelay, this.delayFactory);
               if(this.attr){
                  for(var iAttr = 0; iAttr < this.attr.length; iAttr++){
                     var attr = this.attr[iAttr];
                     var name = attr.name;
                     var mode = attr.mode;
                     this.keyboard[keyIndex].setAttr(name,mode,attr.attr);
                  }
               }
            }else{
               this.keyboard[keyIndex] = specialKey;
            }
         }
      }
   }

   this.remove = function() {
      for(var iRow = 0; iRow < this.nRows; iRow++){
         for(var iCol = 0; iCol < this.nCol; iCol++){
            var keyIndex = iCol + iRow * this.nCol;
            if (this.keys[keyIndex] != null) {
               this.keyboard[keyIndex].remove();
            }
         }
      }
   }
}
<commit_msg>[Fix] When we clicked on one button, all buttons executed the code mouseup<commit_after>function ElementModer(defaultMode) {
   this.elements = {};
   this.modes = {};
   if(!defaultMode) {
      this.mode = "default";
   }
   else {
      this.mode = defaultMode;
   }

   this.addElement = function(name, element) {
      this.elements[name] = element;
   };

   this.removeElement = function(name) {
      delete this.elements[name];
      for(var mode in this.modes) {
         delete this.modes[mode][name];
      }
   };

   this.setAttr = function(name, mode, attr) {
      if(!this.modes[mode]) {
         this.modes[mode] = {};
      }
      this.modes[mode][name] = attr;

      if(mode == this.mode) {
         this.elements[name].attr(attr);
      }
   };

   this.setMode = function(mode) {
      this.mode = mode;
      if(!this.modes[mode]) {
         this.modes[mode] = {};
         return;
      }
      for(var name in this.modes[mode]) {
         this.elements[name].attr(this.modes[mode][name]);
      }
   };

   this.getMode = function() {
      return this.mode;
   };
}

// LATER: should be allowed to customize the font in the button.

var _BUTTON_GUID = 0;

function Button(paper, xPos, yPos, width, height, text, repeat, initialDelay, stepDelay, delayFactory) {
   var self = this;
   _BUTTON_GUID++;
   this.guid = _BUTTON_GUID;

   this.init = function() {
      this.elements = {};
      var cornerRadius = 4;
      var shadowWidth = 1;
      this.elements.shadow = paper.rect(xPos + 1, yPos, width - 1 + shadowWidth, height + shadowWidth).attr({"r": cornerRadius});
      this.elements.rect = paper.rect(xPos, yPos, width, height).attr({"fill": "#dddddd", "r": cornerRadius});
      this.elements.text = paper.text(xPos + width / 2, yPos + height / 2, text).attr({"font-size": 16});
      this.elements.transLayer = paper.rect(xPos, yPos, width, height).attr({opacity: 0, fill: "black"});
      this.moder = new ElementModer("enabled");
      this.moder.addElement("shadow", this.elements.shadow);
      this.moder.addElement("rect", this.elements.rect);
      this.moder.addElement("text", this.elements.text);
      this.moder.setAttr("rect", "mousedown", {"fill": "#e5e5e5"});
      this.moder.setAttr("rect", "enabled", {"fill": "#dddddd"});
      this.moder.setAttr("rect", "disabled", {"fill": "#dddddd"});
      this.moder.setAttr("shadow", "enabled", {"fill": "black"});
      this.moder.setAttr("text", "enabled", {"fill": "black"});
      this.moder.setAttr("text", "mousedown", {"fill": "#aaaaaa"});
      this.moder.setAttr("text", "disabled", {"fill": "#aaaaaa"});
      this.elements.text[0].style.cursor = "default";
      this.enable();
   };

   this.applyFunction = function(funcName, argsList) {
      if(!argsList) {
         argsList = [];
      }
      for(var iElement in this.elements) {
         var element = this.elements[iElement];
         element[funcName].apply(element, argsList);
      }
   };

   this.enable = function() {
      if(this.enabled) {
         return;
      }
      this.enabled = true;
      this.mouseover = false;
      this.mousedown = false;

      var touchstart = function() {
         self.touchInProgress = true;
         self.lastTouchTime = new Date().getTime();
         handleMouseDown();
      }

      var mousedown = function() {
         if (self.touchInProgress) {
            return;
         }
         if (self.lastTouchTime != null) {
            var timeSinceTouch = new Date().getTime() - self.lastTouchTime;
            if (timeSinceTouch < 2000) {
               return;
            }
         }
         handleMouseDown();
      }

      var handleMouseDown = function() {
         if (self.lastMousedownTime != null) {
            var timeSinceDown = new Date().getTime() - self.lastMousedownTime;
            if (timeSinceDown < 100) {
               return;
            }
         }
         self.lastMousedownTime = new Date().getTime();
         if(self.mousedown){
            return
         }
         if(self.enabled) {
            self.mousedown = true;
            self.mouseover = true;
            self.moder.setMode("mousedown");
            if(repeat) {
               self._startRepeater();
            }
         }
      };

      var click = function() {
         if(self.enabled) {
            self.moder.setMode("enabled");
            if(!repeat && self.clickHandler) {
               self.clickHandler(self.clickData);
            }
         }
      };

      var touchend = function() {
         self.touchInProgress = false;
         self.lastTouchTime = new Date().getTime();
         mouseup();
      }

      var mouseup = function() {
         self.touchInProgress = false;
         if(self.enabled) {
            // If we received a mousedown event previously, and now the mouse is up
            // and the mouse is not over the button, then this was a drag attempt.
            if(self.mousedown && !self.mouseover) {
               if(self.dragAttemptHandler) {
                  self.dragAttemptHandler(self.dragAttemptData);
               }
            }
            self.mousedown = false;
            self.moder.setMode("enabled");
            if(repeat) {
               self._stopRepeater();
            }
         }
      };

      var mouseover = function() {
         if(self.enabled) {
            self.mouseover = true;
         }
      };

      var mouseout = function() {
         if(self.enabled) {
            self.mouseover = false;
         }
      };

      this.elements.transLayer.click(click);
      this.lastTouchTime = null;
      this.touchInProgress = false;
      this.lastMousedownTime = null;
      this.elements.transLayer.touchstart(touchstart);
      this.elements.transLayer.mousedown(mousedown);
      this.elements.transLayer.mouseover(mouseover);
      this.elements.transLayer.mouseout(mouseout);
      this.elements.transLayer.mouseup(mouseup);
      this.elements.transLayer.touchend(touchend);
      this.moder.setMode("enabled");
   };

   this._startRepeater = function() {
      if(!this.clickHandler) {
         return;
      }
      // First firing - immediately on mouse down.
      this.clickHandler(this.clickData);
      delayFactory.create(this.guid + "$buttonRepeatInitial", function() {
         // Second firing - after the initial delay.
         self.clickHandler(self.clickData);
         delayFactory.create(self.guid + "$buttonRepeatStep", function() {
            // Nth firing - after the step delay.
            self.clickHandler(self.clickData);
         }, stepDelay, true);
      }, initialDelay);
   };

   this._stopRepeater = function() {
      delayFactory.destroy(this.guid + "$buttonRepeatInitial");
      delayFactory.destroy(this.guid + "$buttonRepeatStep");
   };

   this.disable = function() {
      if(repeat) {
         this._stopRepeater();
      }
      this.moder.setMode("disabled");
      this.enabled = false;
      this.mouseover = false;
      this.mousedown = false;
      this.elements.transLayer.unclick();
      this.elements.transLayer.unmousedown();
      this.elements.transLayer.unmouseover();
      this.elements.transLayer.unmouseout();
   };

   this.click = function(handler, data) {
      this.clickHandler = handler;
      this.clickData = data;
   };

   this.unclick = function(handler) {
      delete this.clickHandler;
   };

   this.dragAttempt = function(handler, data) {
      this.dragAttemptHandler = handler;
      this.dragAttemptData = data;
   };

   this.setAttr = function(name, mode, attr) {
      this.moder.setAttr(name, mode, attr);
   };

   this.addElement = function(name, element) {
      this.elements[name] = element;
      this.moder.addElement(name, element);
      this.elements.transLayer.toFront();
   };

   this.changeOverlay = function(attr) {
      this.elements.transLayer.attr(attr);
   };

   this.show = function() {
      this.applyFunction("show");
   };

   this.getMode = function() {
      return this.moder.getMode();
   };

   this.hide = function() {
      this.applyFunction("hide");
   };

   this.remove = function() {
      this.disable();
      this.applyFunction("remove");
   };

   this.toFront = function() {
      this.elements.shadow.toFront();
      this.elements.rect.toFront();
      for(var iElement in this.elements) {
         if(iElement != "shadow" && iElement != "rect"){
            var element = this.elements[iElement];
            element.toFront();
         }
      }
      this.elements.transLayer.toFront();
   };

   this.init();
}

function Keyboard(data) {
   this.paper = data.paper;
   this.keys = data.keys;
   this.nRows = data.nRows;
   this.nCol = data.nCol;
   this.keyFiller = data.keyFiller;
   this.xPos = data.xPos;
   this.yPos = data.yPos;
   this.keyWidth = data.keyWidth;
   this.keyHeight = data.keyHeight;
   this.marginX = data.marginX;
   this.marginY = data.marginY;
   this.shiftOddRows = data.shiftOddRows;
   this.shiftEvenRows = data.shiftEvenRows;
   this.repeat = data.repeat;
   this.initialDelay = data.initialDelay;
   this.stepDelay = data.stepDelay;
   this.delayFactory = data.delayFactory;
   this.attr = data.attr;

   this.keyboard = [];

   for(var iRow = 0; iRow < this.nRows; iRow++){
      // this.keyboard[iRow] = [];
      for(var iCol = 0; iCol < this.nCol; iCol++){
         var x = this.xPos + iCol * (this.keyWidth + this.marginX);
         var y = this.yPos + iRow * (this.keyHeight + this.marginY);
         if (this.shiftOddRows && (iRow % 2 == 1)) {
            x += (this.keyWidth + this.marginX) / 2;
         }
         if (this.shiftEvenRows && (iRow % 2 == 0)) {
            x += (this.keyWidth + this.marginX) / 2;
         }
         var keyIndex = iCol + iRow * this.nCol;
         if (this.keys[keyIndex] != null) {
            var specialKey = (this.keyFiller) ? this.keyFiller(keyIndex,x,y) : null;
            if(!specialKey){
               var text = this.keys[keyIndex];
               this.keyboard[keyIndex] = new Button(this.paper,x,y,this.keyWidth,this.keyHeight,text,this.repeat, this.initialDelay, this.stepDelay, this.delayFactory);
               if(this.attr){
                  for(var iAttr = 0; iAttr < this.attr.length; iAttr++){
                     var attr = this.attr[iAttr];
                     var name = attr.name;
                     var mode = attr.mode;
                     this.keyboard[keyIndex].setAttr(name,mode,attr.attr);
                  }
               }
            }else{
               this.keyboard[keyIndex] = specialKey;
            }
         }
      }
   }

   this.remove = function() {
      for(var iRow = 0; iRow < this.nRows; iRow++){
         for(var iCol = 0; iCol < this.nCol; iCol++){
            var keyIndex = iCol + iRow * this.nCol;
            if (this.keys[keyIndex] != null) {
               this.keyboard[keyIndex].remove();
            }
         }
      }
   }
}
<|endoftext|>


<commit_before>import {useReducer, useMemo} from 'react';
import {createActions,
        PLAY, PLAYING, PLAY_FAILED, PAUSE, PAUSED, SCRUB_TO, SEEK_TO,
        FADE_OUT_AND_PAUSE, PLAY_AND_FADE_IN, CHANGE_VOLUME_FACTOR,
        PREBUFFER, PREBUFFERED, BUFFER_UNDERRUN, BUFFER_UNDERRUN_CONTINUE,
        WAITING, SEEKING, SEEKED, META_DATA_LOADED, DATA_LOADED, PROGRESS, TIME_UPDATE, ENDED,
        MOUSE_ENTERED, MOUSE_LEFT,
        MOUSE_ENTERED_CONTROLS, MOUSE_LEFT_CONTROLS,
        FOCUS_ENTERED_CONTROLS, FOCUS_LEFT_CONTROLS,
        USER_INTERACTION, USER_IDLE, SAVE_MEDIA_ELEMENT_ID, DISCARD_MEDIA_ELEMENT_ID} from './playerActions';

export function getInitialPlayerState(){
  return {
    isPlaying: false,
    shouldPlay: false,
    unplayed: true,
    dataLoaded: false,
    isLoading: true,
    playFailed: false,
    duration: 0,
    bufferedEnd: 0,
    shouldPrebuffer: true,
    fadeDuration: undefined,
    bufferUnderrun: undefined,
    scrubbingAt: undefined,
    currentTime: 0,
    mediaElementId: undefined,
    shouldSeekTo: undefined,
    userHovering: false,
    userHoveringControls: false,
    focusInsideControls: false,
    userIdle: false,
    volumeFactor: 1,
  };
}

export function playerStateReducer(state, action){
  switch(action.type){
    case PLAY:
      return {
        ...state,
        isLoading: true,
        shouldPlay: true,
        playFailed: false,
        unplayed: false,
        lastControlledVia: action.payload.via
      };
    case PLAYING:
      return {
        ...state,
        shouldPlay: true,
        isPlaying: true,
        userIdle: false
      };
    case PLAY_AND_FADE_IN:
      return {
        ...state,
        shouldPlay: true,
        fadeDuration: action.payload.fadeDuration,
        isLoading: true,
        lastControlledVia: action.payload.via
      };
    case FADE_OUT_AND_PAUSE:
      return {
        ...state,
        shouldPlay: false,
        fadeDuration: action.payload.fadeDuration,
        isLoading: false,
        lastControlledVia: action.payload.via
      };
    case PLAY_FAILED:
      return {
        ...state,
        shouldPlay: false,
        playFailed: true,
        fadeDuration: null,
        unplayed: true,
        isLoading: false
      };
    case PAUSE:
      return {
        ...state,
        shouldPlay: false,
        isLoading: false,
        fadeDuration: null,
        lastControlledVia: action.payload.via
      };
    case PAUSED:
      if (state.bufferUnderrun) {
        return {
          ...state,
          isPlaying: false
        };
      }
      else{
        return {
          ...state,
          shouldPlay: false,
          fadeDuration: null,
          isPlaying: false,
          isLoading: false
        };
      }
    case SCRUB_TO:
      return {
        ...state,
        scrubbingAt: action.payload.time
      };
    case SEEK_TO:
      return {
        ...state,
        shouldSeekTo: action.payload.time
      };
    case SEEKING:
      return {
        ...state,
        isLoading: true
      };
    case SEEKED:
      return {
        ...state,
        scrubbingAt: undefined,
        isLoading: false
      };
    case META_DATA_LOADED:
      return {
        ...state,
        currentTime: action.payload.currentTime,
        duration: action.payload.duration
      };
    case DATA_LOADED:
      return {
        ...state,
        dataLoaded: true
      };
    case PROGRESS:
      return {
        ...state,
        bufferedEnd: action.payload.bufferedEnd
      };
    case TIME_UPDATE:
      return {
        ...state,
        currentTime: action.payload.currentTime,
        duration: action.payload.duration,
        isLoading: false
      };
    case ENDED:
      return {
        ...state,
        shouldPlay: false,
        isPlaying: false,
        unplayed: true,
        lastControlledVia: null
      };
    case WAITING:
      return {
        ...state,
        isLoading: true
      };
    case PREBUFFER:
      return {
        ...state,
        shouldPrebuffer: true
      };
    case PREBUFFERED:
      return {
        ...state,
        shouldPrebuffer: false
      };
    case BUFFER_UNDERRUN:
      return {
        ...state,
        bufferUnderrun: true
      };
    case BUFFER_UNDERRUN_CONTINUE:
      return {
        ...state,
        bufferUnderrun: false
      };
    case MOUSE_ENTERED:
      return {
        ...state,
        userHovering: true
      };
    case MOUSE_LEFT:
      return {
        ...state,
        userHovering: false
      };
    case MOUSE_ENTERED_CONTROLS:
      return {
        ...state,
        userHoveringControls: true
      };
    case MOUSE_LEFT_CONTROLS:
      return {
        ...state,
        userHoveringControls: false
      };
    case FOCUS_ENTERED_CONTROLS:
      return {
        ...state,
        focusInsideControls: true,
        userIdle: false
      };
    case FOCUS_LEFT_CONTROLS:
      return {
        ...state,
        focusInsideControls: false,
        userIdle: false
      };
    case USER_INTERACTION:
      return {
        ...state,
        userIdle: false,
      };
    case USER_IDLE:
      return {
        ...state,
        userIdle: true,
      };
    case SAVE_MEDIA_ELEMENT_ID:
      return {
        ...state,
        mediaElementId: action.payload.id
      };
    case DISCARD_MEDIA_ELEMENT_ID:
      return {
        ...state,
        dataLoaded: false,
        isPlaying: false,
        mediaElementId: null
      };
     case CHANGE_VOLUME_FACTOR:
      return {
        ...state,
        volumeFactor: action.payload.volumeFactor,
        volumeFactorFadeDuration: action.payload.fadeDuration
      };
    default:
      return state;
  }
};

export function usePlayerState(){
  const [state, dispatch] = useReducer(playerStateReducer, getInitialPlayerState());
  const actions = useMemo(() => createActions(dispatch), [dispatch]);

  return [state, actions];
}
<commit_msg>Allow seeking to same position twice<commit_after>import {useReducer, useMemo} from 'react';
import {createActions,
        PLAY, PLAYING, PLAY_FAILED, PAUSE, PAUSED, SCRUB_TO, SEEK_TO,
        FADE_OUT_AND_PAUSE, PLAY_AND_FADE_IN, CHANGE_VOLUME_FACTOR,
        PREBUFFER, PREBUFFERED, BUFFER_UNDERRUN, BUFFER_UNDERRUN_CONTINUE,
        WAITING, SEEKING, SEEKED, META_DATA_LOADED, DATA_LOADED, PROGRESS, TIME_UPDATE, ENDED,
        MOUSE_ENTERED, MOUSE_LEFT,
        MOUSE_ENTERED_CONTROLS, MOUSE_LEFT_CONTROLS,
        FOCUS_ENTERED_CONTROLS, FOCUS_LEFT_CONTROLS,
        USER_INTERACTION, USER_IDLE, SAVE_MEDIA_ELEMENT_ID, DISCARD_MEDIA_ELEMENT_ID} from './playerActions';

export function getInitialPlayerState(){
  return {
    isPlaying: false,
    shouldPlay: false,
    unplayed: true,
    dataLoaded: false,
    isLoading: true,
    playFailed: false,
    duration: 0,
    bufferedEnd: 0,
    shouldPrebuffer: true,
    fadeDuration: undefined,
    bufferUnderrun: undefined,
    scrubbingAt: undefined,
    currentTime: 0,
    mediaElementId: undefined,
    shouldSeekTo: undefined,
    userHovering: false,
    userHoveringControls: false,
    focusInsideControls: false,
    userIdle: false,
    volumeFactor: 1,
  };
}

export function playerStateReducer(state, action){
  switch(action.type){
    case PLAY:
      return {
        ...state,
        isLoading: true,
        shouldPlay: true,
        playFailed: false,
        unplayed: false,
        lastControlledVia: action.payload.via
      };
    case PLAYING:
      return {
        ...state,
        shouldPlay: true,
        isPlaying: true,
        userIdle: false
      };
    case PLAY_AND_FADE_IN:
      return {
        ...state,
        shouldPlay: true,
        fadeDuration: action.payload.fadeDuration,
        isLoading: true,
        lastControlledVia: action.payload.via
      };
    case FADE_OUT_AND_PAUSE:
      return {
        ...state,
        shouldPlay: false,
        fadeDuration: action.payload.fadeDuration,
        isLoading: false,
        lastControlledVia: action.payload.via
      };
    case PLAY_FAILED:
      return {
        ...state,
        shouldPlay: false,
        playFailed: true,
        fadeDuration: null,
        unplayed: true,
        isLoading: false
      };
    case PAUSE:
      return {
        ...state,
        shouldPlay: false,
        isLoading: false,
        fadeDuration: null,
        lastControlledVia: action.payload.via
      };
    case PAUSED:
      if (state.bufferUnderrun) {
        return {
          ...state,
          isPlaying: false
        };
      }
      else{
        return {
          ...state,
          shouldPlay: false,
          fadeDuration: null,
          isPlaying: false,
          isLoading: false
        };
      }
    case SCRUB_TO:
      return {
        ...state,
        scrubbingAt: action.payload.time
      };
    case SEEK_TO:
      return {
        ...state,
        shouldSeekTo: action.payload.time
      };
    case SEEKING:
      return {
        ...state,
        isLoading: true
      };
    case SEEKED:
      return {
        ...state,
        shouldSeekTo: undefined,
        scrubbingAt: undefined,
        isLoading: false
      };
    case META_DATA_LOADED:
      return {
        ...state,
        currentTime: action.payload.currentTime,
        duration: action.payload.duration
      };
    case DATA_LOADED:
      return {
        ...state,
        dataLoaded: true
      };
    case PROGRESS:
      return {
        ...state,
        bufferedEnd: action.payload.bufferedEnd
      };
    case TIME_UPDATE:
      return {
        ...state,
        currentTime: action.payload.currentTime,
        duration: action.payload.duration,
        isLoading: false
      };
    case ENDED:
      return {
        ...state,
        shouldPlay: false,
        isPlaying: false,
        unplayed: true,
        lastControlledVia: null
      };
    case WAITING:
      return {
        ...state,
        isLoading: true
      };
    case PREBUFFER:
      return {
        ...state,
        shouldPrebuffer: true
      };
    case PREBUFFERED:
      return {
        ...state,
        shouldPrebuffer: false
      };
    case BUFFER_UNDERRUN:
      return {
        ...state,
        bufferUnderrun: true
      };
    case BUFFER_UNDERRUN_CONTINUE:
      return {
        ...state,
        bufferUnderrun: false
      };
    case MOUSE_ENTERED:
      return {
        ...state,
        userHovering: true
      };
    case MOUSE_LEFT:
      return {
        ...state,
        userHovering: false
      };
    case MOUSE_ENTERED_CONTROLS:
      return {
        ...state,
        userHoveringControls: true
      };
    case MOUSE_LEFT_CONTROLS:
      return {
        ...state,
        userHoveringControls: false
      };
    case FOCUS_ENTERED_CONTROLS:
      return {
        ...state,
        focusInsideControls: true,
        userIdle: false
      };
    case FOCUS_LEFT_CONTROLS:
      return {
        ...state,
        focusInsideControls: false,
        userIdle: false
      };
    case USER_INTERACTION:
      return {
        ...state,
        userIdle: false,
      };
    case USER_IDLE:
      return {
        ...state,
        userIdle: true,
      };
    case SAVE_MEDIA_ELEMENT_ID:
      return {
        ...state,
        mediaElementId: action.payload.id
      };
    case DISCARD_MEDIA_ELEMENT_ID:
      return {
        ...state,
        dataLoaded: false,
        isPlaying: false,
        mediaElementId: null
      };
     case CHANGE_VOLUME_FACTOR:
      return {
        ...state,
        volumeFactor: action.payload.volumeFactor,
        volumeFactorFadeDuration: action.payload.fadeDuration
      };
    default:
      return state;
  }
};

export function usePlayerState(){
  const [state, dispatch] = useReducer(playerStateReducer, getInitialPlayerState());
  const actions = useMemo(() => createActions(dispatch), [dispatch]);

  return [state, actions];
}
<|endoftext|>