<commit_before>var Gameplay = function () {};
Gameplay.prototype = {
  motivateKey: null,
  moveKey: null,

  developers: null,
  player: null,
  playerSprite: null,

  guiSprites: null,
  workGlimmers: null,

  developerCount: 6,
  playerMoveSpeed: 200,
  playerCloseDistance: 8,
  initialDevMotivation: 20,
  baseDevMotiovationScale: 1.5,
  baseDevProgressValue: 0.01,
  baseDevProgressInterval: 700, // ms
  maxDevMotivation: 20,
  motivationPerPress: 1.5,
  cartPalette: [0x0078ff, 0x6b76ff, 0x005e00, 0x4d00c8, 0xff0000, 0x00c500],

  gameStates: ['getReady', 'gameplay', 'playerLose', 'playerWinRound'],

  currentState: 'undef',
  targetPlayerIndex: 0,
  movingForward: false,
  timeSinceLastDownPress: 0,
  gameProgress: 0, /* between 0 and 1 */
  cartRoll: 0,

  motivateDev: function () {
    if (this.game.input.keyboard.isDown(Phaser.KeyCode.X) || this.game.input.gamepad.pad1.isDown(Phaser.Gamepad.BUTTON_5)) {
      return;
    }

    if (this.currentState !== 'gameplay') {
      return;
    }

    var closestDev = this.developers[this.targetPlayerIndex];
    for (var i = 0; i < this.developers.length; i++) {
      if (Phaser.Point.distance(this.player.position, this.developers[i].position) < Phaser.Point.distance(this.player.position, closestDev.position) ) {
        closestDev = this.developers[i];
      }
    }

    if (Phaser.Point.distance(this.player.position, closestDev.position) < 32) {
      closestDev.motivation = Math.min(this.maxDevMotivation, closestDev.motivation + this.motivationPerPress);
    }
  },

  reverseDirection: function () {
    if (this.timeSinceLastDownPress < 500) {
      this.movingForward = !this.movingForward;

      this.targetPlayerIndex = (this.movingForward ? (this.targetPlayerIndex + 1) : (this.targetPlayerIndex - 1 + this.developers.length)) % this.developers.length;
    }

    this.timeSinceLastDownPress = 0;
  },

  addGameProgress: function (value) {
    if (this.gameProgress >= 1) { return; }

    this.gameProgress += value;
  },

  // state transitions
  transition_getReady: function () {
    if (this.currentState !== 'undef' && this.currentState !== 'playerWinRound') {
      return;
    }

    console.log('get ready!');

    this.getReadyText.renderable = true;
    this.getReadyText.y = -20;
    var moveTextDownTween = this.game.add.tween(this.getReadyText);
    moveTextDownTween.to({y: ~~(this.game.height * 0.333)}, 500);
    var moveTextUpTween = this.game.add.tween(this.getReadyText);
    moveTextUpTween.to({y: -20}, 350, undefined, false, 1500);
    moveTextDownTween.chain(moveTextUpTween);
    moveTextUpTween.onComplete.add(function() {
      this.getReadyText.renderable = false;

      this.game.time.events.add(350, function () {
        this.transition_startGameplay();
      }, this);
    }, this);
    moveTextDownTween.start();

    this.currentState = 'getReady';
  },
  transition_startGameplay: function () {
    this.developers.forEach(function (dev) { dev.startWorking(); }, this);

    this.currentState = 'gameplay';
  },
  transition_playerLose: function () {
    //

    this.currentState = 'playerLose';
  },
  transition_playerWinRound: function () {
    this.developers.forEach(function (dev) { dev.stopWorking(); }, this);

    this.currentState = 'playerWinRound';
  },

  create: function () {
    this.game.stage.backgroundColor = '#000000';

    this.map = this.game.add.tilemap('level0');
    this.map.addTilesetImage('tiles', 'tiles');

    var backgroundLayer = this.map.createLayer('background');
    var foregroundLayer = this.map.createLayer('foreground');

    this.motivateKey = this.game.input.keyboard.addKey(Phaser.KeyCode.C);
    this.motivateKey.onDown.add(this.motivateDev, this);
    this.moveKey = this.game.input.keyboard.addKey(Phaser.KeyCode.X);
    this.moveKey.onDown.add(this.reverseDirection, this);
    this.game.input.gamepad.onDownCallback = function (buttonCode) { if (buttonCode === 4) { this.motivateDev(); } if (buttonCode === 5) { this.reverseDirection(); } };
    this.game.input.gamepad.callbackContext = this;

    this.guiSprites = this.game.add.group();

    var px = 0;
    var py = 0;

    this.developers = [];
    this.map.objects.gameplay.forEach(function(mapObject) {

      if (mapObject.name === 'Player') {
        px = mapObject.x;
        py = mapObject.y;
      } else if (mapObject.name === 'Dev') {
        var that = this;
        var newDev = this.game.add.sprite(~~(mapObject.x + 8), ~~(mapObject.y), 'sheet', 12);
        this.game.physics.arcade.enable(newDev);
        newDev.body.setSize(16, 16);
        newDev.anchor.setTo(0.5, 0);
        newDev.motivation = 20;
        newDev.motivationScale = this.baseDevMotiovationScale + Math.random() * 0.45 - 0.234;
        newDev.progressValue = this.baseDevProgressValue;
        newDev.progressInterval = this.baseDevProgressInterval + (Math.random() * 600 - 300);
        newDev.workLoop = null;
        newDev.addChild(this.game.add.sprite(0, 0, 'sheet', ~~(8 + Math.random() * 4))).anchor.setTo(0.5, 0);
        newDev.startWorking = function () {
          if (newDev.workLoop !== null) { return; }

          var bobbed = false;
          var initY = newDev.y;
          newDev.workLoop = that.game.time.events.loop(newDev.progressInterval, function() {
            that.addGameProgress( newDev.progressValue );
            var newGlimmer = that.workGlimmers.getFirstDead();
            if (newGlimmer) {
              newGlimmer.x = newDev.x;
              newGlimmer.y = newDev.y;
              newGlimmer.revive();
              newGlimmer.animations.play('glisten');
              var glimmerTween = this.game.add.tween(newGlimmer);
              glimmerTween.to({x: this.progress.x - (Math.random() * this.progress.width - this.progress.width / 2), y: this.progress.y + this.progress.height}, 500, undefined, false);
              glimmerTween.onComplete.add(function() { newGlimmer.kill(); }, this);
              glimmerTween.start();
            }
          }, that);
          newDev.bobLoop = that.game.time.events.loop(125, function () { bobbed = !bobbed; newDev.y = initY + (bobbed ? 1 : 0); }, that);
        };
        newDev.stopWorking = function () {
          that.game.time.events.remove(newDev.workLoop);
          that.game.time.events.remove(newDev.bobLoop);
          newDev.workLoop = null;
        };
        newDev.events.onKilled.add(function () { this.healthBar.kill(); }, newDev);

        this.developers.push(newDev);

        var devHealthBar = this.game.add.sprite(newDev.x - 16, newDev.y - 32, 'sheet', 29);
        devHealthBar.tint = 0x191919;
        var movingBit = devHealthBar.addChild(this.game.add.sprite(1, 31, 'sheet', 29));
        movingBit.anchor.y = 1;
        movingBit.tint = 0x77beFF;
        movingBit.width = 14;
        movingBit.height = 30;
        newDev.bar = movingBit;
        var flashingBar = devHealthBar.addChild(this.game.add.sprite(0, 0, 'sheet', 30));
        flashingBar.animations.add('flicker', [30, 31], 12, true);
        flashingBar.animations.play('flicker');
        this.guiSprites.add(devHealthBar);
        newDev.healthBar = devHealthBar;
      }
    }, this);

    var cosmeticLayer = this.map.createLayer('cosmetic');

    this.player = this.game.add.sprite(px, py + 16, undefined);
    this.game.physics.arcade.enable(this.player);
    this.player.body.setSize(16, 16);
    this.player.renderable = false;

    this.playerSprite = this.game.add.sprite(64, 64, 'sheet', 0);
    this.playerSprite.anchor.setTo(0.5, 0);
    this.playerSprite.animations.add('run', [0, 1], 7, true);
    this.playerSprite.animations.play('run');

    var progressText = this.game.add.bitmapText(14 * 16 + 16, 0.75, 'font', 'PROGRESS', 8);
    progressText.cacheAsBitmap = true;
    this.guiSprites.add(progressText);

    this.cartRoll = ~~(Math.random() * 6);
    var progressCart = this.game.add.sprite(14 * 16 + (this.game.width - 14 * 16) / 2, 32, 'carts', this.cartRoll);
    progressCart.anchor.x = 0.5;
    this.progress = progressCart;
    this.progress.crop(new Phaser.Rectangle(0, 0, 64, 0));

    var getReadyText = this.game.add.bitmapText(14 * 16 / 2, 0, 'font', 'THE DEVS ARE TIRED\nBUT WE GOTTA SHIP!!!', 8);
    getReadyText.align = 'center';
    getReadyText.anchor.x = 0.5;
    getReadyText.tint = 0x000000;
    getReadyText.renderable = false;
    this.getReadyText = getReadyText;
    this.guiSprites.addChild(getReadyText);
    this.guiSprites.bringToTop(getReadyText);

    this.workGlimmers = this.game.add.group();
    for (var i = 0; i < 10; i++) {
      var glimmer = this.game.add.sprite(0, 0, 'sheet', 24);
      glimmer.anchor.set(0.5);
      glimmer.kill();
      glimmer.animations.add('glisten', [24, 25, 26, 27], 8); // 500 ms long
      glimmer.tint = this.cartPalette[this.cartRoll];
      this.workGlimmers.add(glimmer);
    }

    this.targetPlayerIndex = 0;
    this.movingForward = true;
    this.timeSinceLastDownPress = 0;

    this.transition_getReady();
  },
  update: function () {

    this.game.world.bringToTop(this.player);
    this.timeSinceLastDownPress += this.game.time.physicsElapsedMS;
    // move toward the next developer
    if (this.game.input.keyboard.isDown(Phaser.KeyCode.X) || this.game.input.gamepad.pad1.isDown(Phaser.Gamepad.BUTTON_5)) {
      var target = this.developers[this.targetPlayerIndex];

      Phaser.Point.subtract(target.position, this.player.position, this.player.body.velocity);
      this.player.body.velocity = Phaser.Point.normalize(this.player.body.velocity);
      this.player.body.velocity.setMagnitude(this.playerMoveSpeed);
      this.playerSprite.scale.x = this.player.body.velocity.x > 0 ? 1 : -1;
    } else {
      this.player.body.velocity.set(0);
    }

    // if the player gets super close to the developer or a developer stops working, switch the target to the next one
    if (this.developers[this.targetPlayerIndex].alive === false || Phaser.Point.distance(this.player.position, this.developers[this.targetPlayerIndex].position) < this.playerCloseDistance) {
      var loopLimiter = 0;
      do {
        this.targetPlayerIndex = (this.movingForward ? (this.targetPlayerIndex + 1) : (this.targetPlayerIndex - 1 + this.developers.length)) % this.developers.length;
        loopLimiter++;
      } while (loopLimiter < this.developers.length && this.developers[this.targetPlayerIndex].alive === false);
    }

    if (this.currentState === 'gameplay') {
      this.developers.forEach(function(dev) {
        if (dev.motivation > 0) {
          dev.motivation -= this.game.time.physicsElapsed * dev.motivationScale;
          dev.bar.height = 30 * dev.motivation / 20;
        } else {
          dev.stopWorking();
          dev.kill();
        }
      }, this);
    }

    this.progress.cropRect.height = 40 * this.gameProgress;
    this.progress.updateCrop();

    // round position values later
    this.playerSprite.x = ~~(this.player.x);
    this.playerSprite.y = ~~(this.player.y);
  },
  render: function () {
    //this.game.debug.geom(new Phaser.Rectangle(0, 0, this.game.width, 16), '#333333');
    //this.game.debug.geom(new Phaser.Rectangle(0, 0, this.game.width * this.gameProgress, 16), 'pink');
  },
  shutdown: function () {
    this.player = null;
    this.playerSprite = null;
    this.developers = null;

    this.guiSprites = null;

    this.targetPlayerIndex = 0;

    this.motivateKey.removeAll();
    this.motivateKey = null;
    this.moveKey.removeAll();
    this.moveKey = null;
  }
};<commit_msg>Player can win round<commit_after>var Gameplay = function () {};
Gameplay.prototype = {
  motivateKey: null,
  moveKey: null,

  developers: null,
  player: null,
  playerSprite: null,

  guiSprites: null,
  workGlimmers: null,

  developerCount: 6,
  playerMoveSpeed: 200,
  playerCloseDistance: 8,
  initialDevMotivation: 20,
  baseDevMotiovationScale: 1.5,
  baseDevProgressValue: 0.01,
  baseDevProgressInterval: 700, // ms
  maxDevMotivation: 20,
  motivationPerPress: 1.5,
  cartPalette: [0x0078ff, 0x6b76ff, 0x005e00, 0x4d00c8, 0xff0000, 0x00c500],

  gameStates: ['getReady', 'gameplay', 'playerLose', 'playerWinRound'],

  currentState: 'undef',
  targetPlayerIndex: 0,
  movingForward: false,
  timeSinceLastDownPress: 0,
  gameProgress: 0, /* between 0 and 1 */
  cartRoll: 0,

  motivateDev: function () {
    if (this.game.input.keyboard.isDown(Phaser.KeyCode.X) || this.game.input.gamepad.pad1.isDown(Phaser.Gamepad.BUTTON_5)) {
      return;
    }

    if (this.currentState !== 'gameplay') {
      return;
    }

    var closestDev = this.developers[this.targetPlayerIndex];
    for (var i = 0; i < this.developers.length; i++) {
      if (Phaser.Point.distance(this.player.position, this.developers[i].position) < Phaser.Point.distance(this.player.position, closestDev.position) ) {
        closestDev = this.developers[i];
      }
    }

    if (Phaser.Point.distance(this.player.position, closestDev.position) < 32) {
      closestDev.motivation = Math.min(this.maxDevMotivation, closestDev.motivation + this.motivationPerPress);
    }
  },

  reverseDirection: function () {
    if (this.timeSinceLastDownPress < 500) {
      this.movingForward = !this.movingForward;

      this.targetPlayerIndex = (this.movingForward ? (this.targetPlayerIndex + 1) : (this.targetPlayerIndex - 1 + this.developers.length)) % this.developers.length;
    }

    this.timeSinceLastDownPress = 0;
  },

  addGameProgress: function (value) {
    if (this.currentState !== 'gameplay') {
      return;
    }

    this.gameProgress += value;

    if (this.gameProgress > 1) {
      this.gameProgress = 1;
      this.transition_playerWinRound();
    }
  },

  // state transitions
  transition_getReady: function () {
    if (this.currentState !== 'undef' && this.currentState !== 'playerWinRound') {
      return;
    }

    this.getReadyText.text = 'THE DEVS ARE TIRED\nBUT WE GOTTA SHIP!!!';
    this.getReadyText.renderable = true;
    this.getReadyText.y = -20;
    var moveTextDownTween = this.game.add.tween(this.getReadyText);
    moveTextDownTween.to({y: ~~(this.game.height * 0.333)}, 500);
    var moveTextUpTween = this.game.add.tween(this.getReadyText);
    moveTextUpTween.to({y: -20}, 350, undefined, false, 1500);
    moveTextDownTween.chain(moveTextUpTween);
    moveTextUpTween.onComplete.add(function() {
      this.getReadyText.renderable = false;

      this.game.time.events.add(350, function () {
        this.transition_startGameplay();
      }, this);
    }, this);
    moveTextDownTween.start();

    this.gameProgress = 0;
    this.cartRoll = ~~(Math.random() * 6);
    this.progress.frame = this.cartRoll;

    this.currentState = 'getReady';
  },
  transition_startGameplay: function () {
    this.developers.forEach(function (dev) { dev.startWorking(); }, this);

    this.currentState = 'gameplay';
  },
  transition_playerLose: function () {
    //

    this.currentState = 'playerLose';
  },
  transition_playerWinRound: function () {
    this.developers.forEach(function (dev) { dev.stopWorking(); }, this);

    this.getReadyText.text = 'Nice one!\nNext game coming up!';
    this.getReadyText.renderable = true;
    this.getReadyText.y = -20;
    var moveTextDownTween = this.game.add.tween(this.getReadyText);
    moveTextDownTween.to({y: ~~(this.game.height * 0.333)}, 500);
    var moveTextUpTween = this.game.add.tween(this.getReadyText);
    moveTextUpTween.to({y: -20}, 350, undefined, false, 1500);
    moveTextDownTween.chain(moveTextUpTween);
    moveTextUpTween.onComplete.add(function() {
      this.getReadyText.renderable = false;

      this.game.time.events.add(350, function () {
        this.transition_getReady();
      }, this);
    }, this);
    moveTextDownTween.start();

    this.currentState = 'playerWinRound';
  },

  create: function () {
    this.game.stage.backgroundColor = '#000000';

    this.map = this.game.add.tilemap('level0');
    this.map.addTilesetImage('tiles', 'tiles');

    var backgroundLayer = this.map.createLayer('background');
    var foregroundLayer = this.map.createLayer('foreground');

    this.motivateKey = this.game.input.keyboard.addKey(Phaser.KeyCode.C);
    this.motivateKey.onDown.add(this.motivateDev, this);
    this.moveKey = this.game.input.keyboard.addKey(Phaser.KeyCode.X);
    this.moveKey.onDown.add(this.reverseDirection, this);
    this.game.input.gamepad.onDownCallback = function (buttonCode) { if (buttonCode === 4) { this.motivateDev(); } if (buttonCode === 5) { this.reverseDirection(); } };
    this.game.input.gamepad.callbackContext = this;

    this.guiSprites = this.game.add.group();

    var px = 0;
    var py = 0;

    this.developers = [];
    this.map.objects.gameplay.forEach(function(mapObject) {

      if (mapObject.name === 'Player') {
        px = mapObject.x;
        py = mapObject.y;
      } else if (mapObject.name === 'Dev') {
        var that = this;
        var newDev = this.game.add.sprite(~~(mapObject.x + 8), ~~(mapObject.y), 'sheet', 12);
        this.game.physics.arcade.enable(newDev);
        newDev.body.setSize(16, 16);
        newDev.anchor.setTo(0.5, 0);
        newDev.motivation = 20;
        newDev.motivationScale = this.baseDevMotiovationScale + Math.random() * 0.45 - 0.234;
        newDev.progressValue = this.baseDevProgressValue;
        newDev.progressInterval = this.baseDevProgressInterval + (Math.random() * 600 - 300);
        newDev.workLoop = null;
        newDev.addChild(this.game.add.sprite(0, 0, 'sheet', ~~(8 + Math.random() * 4))).anchor.setTo(0.5, 0);
        newDev.startWorking = function () {
          if (newDev.workLoop !== null) { return; }

          var bobbed = false;
          var initY = newDev.y;
          newDev.workLoop = that.game.time.events.loop(newDev.progressInterval, function() {
            that.addGameProgress( newDev.progressValue );
            var newGlimmer = that.workGlimmers.getFirstDead();
            if (newGlimmer) {
              newGlimmer.x = newDev.x;
              newGlimmer.y = newDev.y;
              newGlimmer.tint = this.cartPalette[this.cartRoll];
              newGlimmer.revive();
              newGlimmer.animations.play('glisten');
              var glimmerTween = this.game.add.tween(newGlimmer);
              glimmerTween.to({x: this.progress.x - (Math.random() * this.progress.width - this.progress.width / 2), y: this.progress.y + this.progress.height}, 500, undefined, false);
              glimmerTween.onComplete.add(function() { newGlimmer.kill(); }, this);
              glimmerTween.start();
            }
          }, that);
          newDev.bobLoop = that.game.time.events.loop(125, function () { bobbed = !bobbed; newDev.y = initY + (bobbed ? 1 : 0); }, that);
        };
        newDev.stopWorking = function () {
          that.game.time.events.remove(newDev.workLoop);
          that.game.time.events.remove(newDev.bobLoop);
          newDev.workLoop = null;
        };
        newDev.events.onKilled.add(function () { this.healthBar.kill(); }, newDev);

        this.developers.push(newDev);

        var devHealthBar = this.game.add.sprite(newDev.x - 16, newDev.y - 32, 'sheet', 29);
        devHealthBar.tint = 0x191919;
        var movingBit = devHealthBar.addChild(this.game.add.sprite(1, 31, 'sheet', 29));
        movingBit.anchor.y = 1;
        movingBit.tint = 0x77beFF;
        movingBit.width = 14;
        movingBit.height = 30;
        newDev.bar = movingBit;
        var flashingBar = devHealthBar.addChild(this.game.add.sprite(0, 0, 'sheet', 30));
        flashingBar.animations.add('flicker', [30, 31], 12, true);
        flashingBar.animations.play('flicker');
        this.guiSprites.add(devHealthBar);
        newDev.healthBar = devHealthBar;
      }
    }, this);

    var cosmeticLayer = this.map.createLayer('cosmetic');

    this.player = this.game.add.sprite(px, py + 16, undefined);
    this.game.physics.arcade.enable(this.player);
    this.player.body.setSize(16, 16);
    this.player.renderable = false;

    this.playerSprite = this.game.add.sprite(64, 64, 'sheet', 0);
    this.playerSprite.anchor.setTo(0.5, 0);
    this.playerSprite.animations.add('run', [0, 1], 7, true);
    this.playerSprite.animations.play('run');

    var progressText = this.game.add.bitmapText(14 * 16 + 16, 0.75, 'font', 'PROGRESS', 8);
    progressText.cacheAsBitmap = true;
    this.guiSprites.add(progressText);

    this.cartRoll = ~~(Math.random() * 6);
    var progressCart = this.game.add.sprite(14 * 16 + (this.game.width - 14 * 16) / 2, 32, 'carts', this.cartRoll);
    progressCart.anchor.x = 0.5;
    this.progress = progressCart;
    this.progress.crop(new Phaser.Rectangle(0, 0, 64, 0));

    var getReadyText = this.game.add.bitmapText(14 * 16 / 2, 0, 'font', 'foo', 8);
    getReadyText.align = 'center';
    getReadyText.anchor.x = 0.5;
    getReadyText.tint = 0x000000;
    getReadyText.renderable = false;
    this.getReadyText = getReadyText;
    this.guiSprites.addChild(getReadyText);
    this.guiSprites.bringToTop(getReadyText);

    this.workGlimmers = this.game.add.group();
    for (var i = 0; i < 10; i++) {
      var glimmer = this.game.add.sprite(0, 0, 'sheet', 24);
      glimmer.anchor.set(0.5);
      glimmer.kill();
      glimmer.animations.add('glisten', [24, 25, 26, 27], 8); // 500 ms long
      glimmer.tint = this.cartPalette[this.cartRoll];
      this.workGlimmers.add(glimmer);
    }

    this.targetPlayerIndex = 0;
    this.movingForward = true;
    this.timeSinceLastDownPress = 0;

    this.transition_getReady();
  },
  update: function () {

    this.game.world.bringToTop(this.player);
    this.timeSinceLastDownPress += this.game.time.physicsElapsedMS;
    // move toward the next developer
    if (this.game.input.keyboard.isDown(Phaser.KeyCode.X) || this.game.input.gamepad.pad1.isDown(Phaser.Gamepad.BUTTON_5)) {
      var target = this.developers[this.targetPlayerIndex];

      Phaser.Point.subtract(target.position, this.player.position, this.player.body.velocity);
      this.player.body.velocity = Phaser.Point.normalize(this.player.body.velocity);
      this.player.body.velocity.setMagnitude(this.playerMoveSpeed);
      this.playerSprite.scale.x = this.player.body.velocity.x > 0 ? 1 : -1;
    } else {
      this.player.body.velocity.set(0);
    }

    // if the player gets super close to the developer or a developer stops working, switch the target to the next one
    if (this.developers[this.targetPlayerIndex].alive === false || Phaser.Point.distance(this.player.position, this.developers[this.targetPlayerIndex].position) < this.playerCloseDistance) {
      var loopLimiter = 0;
      do {
        this.targetPlayerIndex = (this.movingForward ? (this.targetPlayerIndex + 1) : (this.targetPlayerIndex - 1 + this.developers.length)) % this.developers.length;
        loopLimiter++;
      } while (loopLimiter < this.developers.length && this.developers[this.targetPlayerIndex].alive === false);
    }

    if (this.currentState === 'gameplay') {
      this.developers.forEach(function(dev) {
        if (dev.motivation > 0) {
          dev.motivation -= this.game.time.physicsElapsed * dev.motivationScale;
          dev.bar.height = 30 * dev.motivation / 20;
        } else {
          dev.stopWorking();
          dev.kill();
        }
      }, this);
    }

    this.progress.cropRect.height = 40 * this.gameProgress;
    this.progress.updateCrop();

    // round position values later
    this.playerSprite.x = ~~(this.player.x);
    this.playerSprite.y = ~~(this.player.y);
  },
  render: function () {
    //this.game.debug.geom(new Phaser.Rectangle(0, 0, this.game.width, 16), '#333333');
    //this.game.debug.geom(new Phaser.Rectangle(0, 0, this.game.width * this.gameProgress, 16), 'pink');
  },
  shutdown: function () {
    this.player = null;
    this.playerSprite = null;
    this.developers = null;

    this.guiSprites = null;

    this.targetPlayerIndex = 0;

    this.motivateKey.removeAll();
    this.motivateKey = null;
    this.moveKey.removeAll();
    this.moveKey = null;
  }
};<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 GeoMoose
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/** Collection of handy functions
 */

export function parseBoolean(bool, def=false) {
	if(typeof(bool) == "undefined") { return def; }
	var boolString = new String(bool);
	if(boolString.match(/true/i)) { return true; }
	else if(boolString == '1') { return true; }
	else if(boolString.match(/on/i)) { return true; }
	return false;
}

/** Parse a node from XML and return the text value.
 *
 *  Handy in this situation...
 *   <map>SOME STUFF HERE</map>
 *  Specify 'map' and 'SOME STUFF HERE' will be returned
 *  by the function.  Only the first 'tag' will be found if the
 *  xml fragment has multiple, unless 'multiple' is set to true.
 *
 *  @param xml      An XML fragment.
 *  @param tagName  The tagname to return.
 *  @param multiple Whether to return an array or the first element.
 *
 *  @returns Value of the text in the tag, or null if not found.
 */
export function getTagContents(xml, tagName, multiple) {
    // setup the array to handle multiple
    var contents = [];

    var tags = xml.getElementsByTagName(tagName);
    for(let tag of tags) {
        var node_value = null;
        for(let child of tag.childNodes) {
            // text type node is nodeType == 3
            if(child.nodeType == 3) {
                if(node_value == null) {
                    node_value = '';
                }
                node_value += child.nodeValue;
            }
        }

        // when multiple is not true, return the first value.
        if(multiple === true) {
            contents.push(node_value);
        } else {
            return node_value;
        }
    }

    return contents;
}

/** Compare two objects
 *
 *  @param objA The first object
 *  @param objB The second object
 *  @param deep Whether to go "deeper" into the object.
 *
 *  @returns boolean, true if they differ, false if they are the same.
 */
export function objectsDiffer(objA, objB, deep) {
    let a_keys = Object.keys(objA), b_keys = Object.keys(objB);

    for(let key of a_keys) {
        let b_type = typeof(objB[key]);
        switch(b_type) {
            // if the key from a does not exist in b, then they differ.
            case 'undefined':
                return true;
            // standard comparisons
            case 'string':
            case 'number':
                if(objA[key] != objB[key]) {
                    return true;
                }
            // GO DEEP!
            case 'object':
                // typeof(null) == 'object', this
                //  prevents trying to recurse on null
                if(objB[key] == null) {
                    if(objA[key] != null) {
                        return true;
                    }
                }
                if(deep === true && objectsDiffer(objA[key], objB[key], true)) {
                    return true;
                }
        }
    }

    // The above loop ensures that all the keys
    //  in "A" match a key in "B", if "B" has any
    //  extra keys then the objects differ.
    for(let key of b_keys) {
        if(a_keys.indexOf(key) < 0) {
            return true;
        }
    }

    return false;
}
<commit_msg>Added a map-source name utility function<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 GeoMoose
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/** Collection of handy functions
 */

export function parseBoolean(bool, def=false) {
	if(typeof(bool) == "undefined") { return def; }
	var boolString = new String(bool);
	if(boolString.match(/true/i)) { return true; }
	else if(boolString == '1') { return true; }
	else if(boolString.match(/on/i)) { return true; }
	return false;
}

/** Parse a node from XML and return the text value.
 *
 *  Handy in this situation...
 *   <map>SOME STUFF HERE</map>
 *  Specify 'map' and 'SOME STUFF HERE' will be returned
 *  by the function.  Only the first 'tag' will be found if the
 *  xml fragment has multiple, unless 'multiple' is set to true.
 *
 *  @param xml      An XML fragment.
 *  @param tagName  The tagname to return.
 *  @param multiple Whether to return an array or the first element.
 *
 *  @returns Value of the text in the tag, or null if not found.
 */
export function getTagContents(xml, tagName, multiple) {
    // setup the array to handle multiple
    var contents = [];

    var tags = xml.getElementsByTagName(tagName);
    for(let tag of tags) {
        var node_value = null;
        for(let child of tag.childNodes) {
            // text type node is nodeType == 3
            if(child.nodeType == 3) {
                if(node_value == null) {
                    node_value = '';
                }
                node_value += child.nodeValue;
            }
        }

        // when multiple is not true, return the first value.
        if(multiple === true) {
            contents.push(node_value);
        } else {
            return node_value;
        }
    }

    return contents;
}

/** Compare two objects
 *
 *  @param objA The first object
 *  @param objB The second object
 *  @param deep Whether to go "deeper" into the object.
 *
 *  @returns boolean, true if they differ, false if they are the same.
 */
export function objectsDiffer(objA, objB, deep) {
    let a_keys = Object.keys(objA), b_keys = Object.keys(objB);

    for(let key of a_keys) {
        let b_type = typeof(objB[key]);
        switch(b_type) {
            // if the key from a does not exist in b, then they differ.
            case 'undefined':
                return true;
            // standard comparisons
            case 'string':
            case 'number':
                if(objA[key] != objB[key]) {
                    return true;
                }
            // GO DEEP!
            case 'object':
                // typeof(null) == 'object', this
                //  prevents trying to recurse on null
                if(objB[key] == null) {
                    if(objA[key] != null) {
                        return true;
                    }
                }
                if(deep === true && objectsDiffer(objA[key], objB[key], true)) {
                    return true;
                }
        }
    }

    // The above loop ensures that all the keys
    //  in "A" match a key in "B", if "B" has any
    //  extra keys then the objects differ.
    for(let key of b_keys) {
        if(a_keys.indexOf(key) < 0) {
            return true;
        }
    }

    return false;
}

/** Get the map-sources name.  Paths are "/" split
 *  and so the first component should be the map-source name.
 *
 *  @param path
 *
 *  @returns a string with the map-source's name.
 */
export function getMapSourceName(path) {
    return path.split('/')[0];
}
<|endoftext|>


<commit_before>$(function () {

    //Return json with breeds list from db
    function fetchBreeds(speciesId) {
        var url = 'PopulateBreedList';
        var dropdown = $("#breed-selector");
        if (speciesId === null) {
            var speciesVal = $("#species-selector option:selected").val();
        } else {
            var speciesVal = speciesId;
        }
        if (speciesVal === "3" || speciesVal === "4") {
            dropdown.empty();
            $.ajax({
                url: 'PopulateBreedList',
                data: { speciesVal: speciesVal },
                type: "POST",
                datatype: "json",
                error: function (xhr, status, error) {
                    console.log("borked");
                    console.log(error);
                },
                success: function (json) {
                    $(json).each(function () {
                        //debugger;
                        $(document.createElement('option'))
                                    .attr('value', this.id)
                                    .text(this.name)
                                    .appendTo(dropdown);
                    })
                },
                complete: function () {
                    $("#breed-form-div").show();
                }
            })
        } else {
            $("#breed-form-div").hide();
        }
    }

    function addBreed(speciesVal, inputVal) {
        var params = { name: inputVal, speciesId: speciesVal }; // etc.

        var ser_data = jQuery.param(params);
        console.log(ser_data);
        debugger;

        $.ajax({
            url: 'AddBreed',
            type: 'POST',
            dataType: 'json',
            data: ser_data,
            success: function (result) {
                var speciesId = result.Id;
                fetchBreeds(speciesId);
            }
        });
    }

    //When species dropdown changes, change breeds list
    $("#species-selector").change(function () {
        fetchBreeds(null);
    });

    //open add breed modal on click
    //$("i.add-breed").click(function () {
    //    $(".add-breed-modal").show();
    //})

    //submit add breed form
    $("button.submit").click(function (e) {
        e.preventDefault();
        var speciesVal = parseInt($("#species-selector option:selected").val());
        var inputVal = $("input.new-breed").val();
        if (inputVal !== "") {
            $('.add-breed-modal').modal('hide');
            //debugger;
            addBreed(speciesVal, inputVal);
        } else {
            $('div.form-group.new-breed').addClass('has-error');
            $('#modal-help-block').show();
        }

    })

    //field clears on close
    $(document).on('hide.bs.modal', '.add-breed-modal', function (e) {
        var formGroup = $(this).find('div.form-group')
        var input = $("input.new-breed.form-control");
        $(input).val("");
        if ($(formGroup).hasClass('has-error')) {
            $(formGroup).removeClass('has-error');
            $('#modal-help-block').hide();
        }
    })

});<commit_msg>Update breed dropdown on breed add<commit_after>$(function () {

    //Return json with breeds list from db
    function fetchBreeds(speciesId) {
        var url = 'PopulateBreedList';
        var dropdown = $("#breed-selector");
        //if (speciesId === null) {
   var speciesVal = $("#species-selector option:selected").val();
        //} else {
        //    var speciesVal = speciesId;
        //}
        console.log(speciesVal);
        dropdown.empty();
        $.ajax({
            url: 'PopulateBreedList',
            data: { speciesVal: speciesVal },
            type: "POST",
            datatype: "json",
            error: function (xhr, status, error) {
                console.log("borked");
                console.log(error);
            },
            success: function (json) {
                $(json).each(function () {
                    $(document.createElement('option'))
                                .attr('value', this.id)
                                .text(this.name)
                                .appendTo(dropdown);
                })
            },
            complete: function () {
                $("#breed-form-div").show();
            }
        })
    }

    function addBreed(speciesVal, inputVal) {
        var params = { name: inputVal, speciesId: speciesVal }; // etc.

        var ser_data = jQuery.param(params);
        console.log(ser_data);
        var speciesId;

        $.ajax({
            url: 'AddBreed',
            type: 'POST',
            dataType: 'json',
            data: ser_data,
            success: function (result) {
                speciesId = result.Id;
            },
            complete: function () {
                fetchBreeds(speciesId);
            }
        });
    }

    //When species dropdown changes, change breeds list
    $("#species-selector").change(function () {
        fetchBreeds(null);
    });

    //open add breed modal on click
    //$("i.add-breed").click(function () {
    //    $(".add-breed-modal").show();
    //})

    //submit add breed form
    $("button.submit").click(function (e) {
        e.preventDefault();
        var speciesVal = parseInt($("#species-selector option:selected").val());
        var inputVal = $("input.new-breed").val();
        if (inputVal !== "") {
            $('.add-breed-modal').modal('hide');
            //debugger;
            addBreed(speciesVal, inputVal);
        } else {
            $('div.form-group.new-breed').addClass('has-error');
            $('#modal-help-block').show();
        }

    })

    //field clears on close
    $(document).on('hide.bs.modal', '.add-breed-modal', function (e) {
        var formGroup = $(this).find('div.form-group')
        var input = $("input.new-breed.form-control");
        $(input).val("");
        if ($(formGroup).hasClass('has-error')) {
            $(formGroup).removeClass('has-error');
            $('#modal-help-block').hide();
        }
    })

});<|endoftext|>


<commit_before>define([
    "dojo/_base/declare",
    "mxui/widget/_WidgetBase",
    "dijit/_TemplatedMixin",
    "dojo/dom-construct",
    "dojo/dom-attr",
    "dojo/dom-class",
    "dojo/_base/lang",
    "dojo/text!Ratings/widget/templates/ratings.html"
], function (declare, _WidgetBase, _TemplatedMixin, domConstruct, domAttr, domClass, lang, widgetTemplate) {
        "use strict";

        return declare("Ratings.widget.ratings_nologic", [ _WidgetBase, _TemplatedMixin ], {
            templateString : widgetTemplate,

            // Modeler properties
            voteEnabled : false,
            standardImage : "",
            mouseoverImage : "",
            name : "",
            onChangeMicroflow: "",

            // Internal properties
            divNode : "",
            mouseoverArray : null,
            root : window.mx.appUrl,
            ratingsListEvent : "",

            oldvalue : 0,
            newvalue : 0,

            onChange : function(){
            },

            //returns the value of this widget
            _getValueAttr : function(){
                logger.debug(this.id + "._getValueAttr");
                return this.newvalue;
            },

            //provides th value of this widget
            _setValueAttr : function(value){
                logger.debug(this.id + "._setValueAttr");
                this.oldvalue = parseInt(value, 10);
                this.newvalue = parseInt(value, 10);
                if (this.newvalue > 0) {
                    this.setRating(this.newvalue);
                } else if (this.mxcontext.getTrackObject()) {
                    domClass.remove(this.domNode, "hidden");
                    if (this.voteEnabled === true) {//set default value
                        this.newvalue = 0; //do not detach
                        this.onChange();
                    }
                    this.showCurrentValue();
                } else {
                    domClass.add(this.domNode, "hidden");
                }
            },

            postCreate : function(){
                logger.debug(this.id + ".postCreate");

                this.mouseoverArray = [];

                domClass.add(this.domNode, "ratings_widget");
                var ratingsList = domConstruct.create("ul");

                if (this.voteEnabled === true) {
                    this.ratingsListEvent = this.connect(ratingsList, "onmouseleave", lang.hitch(this, this.showCurrentValue));
                }
                for (var i = 1; i <= 5; i++) {
                    var imgNode =domConstruct.create("img",{"class": "ratings_image"}),
                        ratingsLi = domConstruct.create("li");
                    ratingsLi.appendChild(imgNode);

                    this.mouseoverArray[i-1] = {};
                    this.mouseoverArray[i-1].element = imgNode;
                    if (this.voteEnabled === true) { //can vote and not voted before
                        this.mouseoverArray[i-1].handlein = this.connect(imgNode, "onmouseenter", lang.hitch(this, this.displayImages, i));
                        this.mouseoverArray[i-1].handleout = this.connect(imgNode, "onmouseleave", lang.hitch(this, this.displayImages, i-1));
                        this.mouseoverArray[i-1].handleclick = this.connect(ratingsLi, "onclick", lang.hitch(this, this.setRating, i));
                    }
                    ratingsList.appendChild(ratingsLi);
                }

                this.domNode.appendChild(ratingsList);
                this.showCurrentValue();
                //NOT for attribute widgets: this.actRendered();
            },

            showCurrentValue : function () {
                this.displayImages(this.newvalue);
            },

            displayImages : function (iterator) {
                logger.debug(this.id + ".displayImages");

                if (iterator < 0 || iterator > 5) {
                    return;
                }

                for (var j = 0; j <= iterator-1; j++) {
                    domAttr.set(this.mouseoverArray[j].element, "src", this._getImagePath(this.mouseoverImage));
                }

                for (var k = 4; k > iterator-1; k--) {
                    domAttr.set(this.mouseoverArray[k].element, "src", this._getImagePath(this.standardImage));
                }
            },

            setRating : function(count) {
                logger.debug(this.id + ".onclickRating");
                this.newvalue = count;
                if (this.newvalue !== this.oldvalue) {
                    this.onChange();
                    this._callMicroflow(this.onChangeMicroflow);
                }

                this.displayImages(count);
                for (var i = 0; i < this.mouseoverArray.length; i++) {
                    if (this.mouseoverArray[i].handlein){
                        this.disconnect(this.mouseoverArray[i].handlein);
                    }
                    if (this.mouseoverArray[i].handleout) {
                        this.disconnect(this.mouseoverArray[i].handleout);
                    }
                }
            },

            _getImagePath : function (img) {
                return (this.root + (this.root.indexOf("localhost") !== -1 ? "/" : "" ) + img).split("?")[0]; // fix image path and remove cachebust
            },

            mouseleaveEvent : function(showVote, event) {
                logger.debug(this.id + ".mouseleaveEvent");
                this.setMouseOver(showVote - 1);
            },

            _callMicroflow: function(microflowName) {
                if (microflowName) {
                    window.mx.ui.action(microflowName, {
                        context: this.mxcontext,
                        origin: this.mxform,
                        callback: function() { },
                        error: function(error) {
                            window.mx.ui.error("Error executing microflow: " + microflowName + " " + error.message);
                        }
                    });
                }
            },

            uninitialize : function(){
                logger.debug(this.id + ".uninitialize");
                for (var i = 0; i < this.mouseoverArray.length; i++){
                    if (this.mouseoverArray[i].handlein){
                        this.disconnect(this.mouseoverArray[i].handlein);
                    }
                    if (this.mouseoverArray[i].handleout) {
                        this.disconnect(this.mouseoverArray[i].handleout);
                    }
                    if (this.mouseoverArray[i].handleclick) {
                        this.disconnect(this.mouseoverArray[i].handleclick);
                    }
                }
            }
        });
});

require(["Ratings/widget/ratings_nologic"]);
<commit_msg>Allow rating no logic to be 0<commit_after>define([
    "dojo/_base/declare",
    "mxui/widget/_WidgetBase",
    "dijit/_TemplatedMixin",
    "dojo/dom-construct",
    "dojo/dom-attr",
    "dojo/dom-class",
    "dojo/_base/lang",
    "dojo/text!Ratings/widget/templates/ratings.html"
], function (declare, _WidgetBase, _TemplatedMixin, domConstruct, domAttr, domClass, lang, widgetTemplate) {
        "use strict";

        return declare("Ratings.widget.ratings_nologic", [ _WidgetBase, _TemplatedMixin ], {
            templateString : widgetTemplate,

            // Modeler properties
            voteEnabled : false,
            standardImage : "",
            mouseoverImage : "",
            name : "",
            onChangeMicroflow: "",

            // Internal properties
            divNode : "",
            mouseoverArray : null,
            root : window.mx.appUrl,
            ratingsListEvent : "",

            oldvalue : 0,
            newvalue : 0,

            onChange : function(){
            },

            //returns the value of this widget
            _getValueAttr : function(){
                logger.debug(this.id + "._getValueAttr");
                return this.newvalue;
            },

            //provides th value of this widget
            _setValueAttr : function(value){
                logger.debug(this.id + "._setValueAttr");
                this.oldvalue = parseInt(value, 10);
                this.newvalue = parseInt(value, 10);
                if (this.newvalue >= 0) {
                    this.setRating(this.newvalue);
                } else if (this.mxcontext.getTrackObject()) {
                    domClass.remove(this.domNode, "hidden");
                    if (this.voteEnabled === true) {//set default value
                        this.newvalue = 0; //do not detach
                        this.onChange();
                    }
                    this.showCurrentValue();
                } else {
                    domClass.add(this.domNode, "hidden");
                }
            },

            postCreate : function(){
                logger.debug(this.id + ".postCreate");

                this.mouseoverArray = [];

                domClass.add(this.domNode, "ratings_widget");
                var ratingsList = domConstruct.create("ul");

                if (this.voteEnabled === true) {
                    this.ratingsListEvent = this.connect(ratingsList, "onmouseleave", lang.hitch(this, this.showCurrentValue));
                }
                for (var i = 1; i <= 5; i++) {
                    var imgNode =domConstruct.create("img",{"class": "ratings_image"}),
                        ratingsLi = domConstruct.create("li");
                    ratingsLi.appendChild(imgNode);

                    this.mouseoverArray[i-1] = {};
                    this.mouseoverArray[i-1].element = imgNode;
                    if (this.voteEnabled === true) { //can vote and not voted before
                        this.mouseoverArray[i-1].handlein = this.connect(imgNode, "onmouseenter", lang.hitch(this, this.displayImages, i));
                        this.mouseoverArray[i-1].handleout = this.connect(imgNode, "onmouseleave", lang.hitch(this, this.displayImages, i-1));
                        this.mouseoverArray[i-1].handleclick = this.connect(ratingsLi, "onclick", lang.hitch(this, this.setRating, i));
                    }
                    ratingsList.appendChild(ratingsLi);
                }

                this.domNode.appendChild(ratingsList);
                this.showCurrentValue();
                //NOT for attribute widgets: this.actRendered();
            },

            showCurrentValue : function () {
                this.displayImages(this.newvalue);
            },

            displayImages : function (iterator) {
                logger.debug(this.id + ".displayImages");

                if (iterator < 0 || iterator > 5) {
                    return;
                }

                for (var j = 0; j <= iterator-1; j++) {
                    domAttr.set(this.mouseoverArray[j].element, "src", this._getImagePath(this.mouseoverImage));
                }

                for (var k = 4; k > iterator-1; k--) {
                    domAttr.set(this.mouseoverArray[k].element, "src", this._getImagePath(this.standardImage));
                }
            },

            setRating : function(count) {
                logger.debug(this.id + ".onclickRating");
                this.newvalue = count;
                if (this.newvalue !== this.oldvalue) {
                    this.onChange();
                    this._callMicroflow(this.onChangeMicroflow);
                }

                this.displayImages(count);
                for (var i = 0; i < this.mouseoverArray.length; i++) {
                    if (this.mouseoverArray[i].handlein){
                        this.disconnect(this.mouseoverArray[i].handlein);
                    }
                    if (this.mouseoverArray[i].handleout) {
                        this.disconnect(this.mouseoverArray[i].handleout);
                    }
                }
            },

            _getImagePath : function (img) {
                return (this.root + (this.root.indexOf("localhost") !== -1 ? "/" : "" ) + img).split("?")[0]; // fix image path and remove cachebust
            },

            mouseleaveEvent : function(showVote, event) {
                logger.debug(this.id + ".mouseleaveEvent");
                this.setMouseOver(showVote - 1);
            },

            _callMicroflow: function(microflowName) {
                if (microflowName) {
                    window.mx.ui.action(microflowName, {
                        context: this.mxcontext,
                        origin: this.mxform,
                        callback: function() { },
                        error: function(error) {
                            window.mx.ui.error("Error executing microflow: " + microflowName + " " + error.message);
                        }
                    });
                }
            },

            uninitialize : function(){
                logger.debug(this.id + ".uninitialize");
                for (var i = 0; i < this.mouseoverArray.length; i++){
                    if (this.mouseoverArray[i].handlein){
                        this.disconnect(this.mouseoverArray[i].handlein);
                    }
                    if (this.mouseoverArray[i].handleout) {
                        this.disconnect(this.mouseoverArray[i].handleout);
                    }
                    if (this.mouseoverArray[i].handleclick) {
                        this.disconnect(this.mouseoverArray[i].handleclick);
                    }
                }
            }
        });
});

require(["Ratings/widget/ratings_nologic"]);
<|endoftext|>


<commit_before>const describeOptionalProp = require('../DescribeOptionalProp');
const statementSchema = require('../Helpers/StatementSchema');
const { string } = require('../Factory');

const validData = {
  objectType: 'SubStatement';
  actor: {
    objectType: 'Agent',
    mbox: 'mailto:test@example.com',
  },
  verb: {
    id: 'http://www.example.com',
  },
  object: {
    objectType: 'Activity',
    id: 'http://www.example.com',
  },
  result: {},
  context: {},
  timestamp: '2016-12-31T18:45:21+00:00',
  attachments: [],
};

module.exports = test => {
  describeOptionalProp('objectType', string, validData, test);
  statementSchema((data, valid) =>
    test(Object.assign({}, validData, data), valid);
  )
};
<commit_msg>Adds test for recursive sub statements.<commit_after>const describeOptionalProp = require('../DescribeOptionalProp');
const itsInvalid = require('../ItsInvalid');
const statementSchema = require('../Helpers/StatementSchema');
const { string } = require('../Factory');

const validData = {
  objectType: 'SubStatement';
  actor: {
    objectType: 'Agent',
    mbox: 'mailto:test@example.com',
  },
  verb: {
    id: 'http://www.example.com',
  },
  object: {
    objectType: 'Activity',
    id: 'http://www.example.com',
  },
  result: {},
  context: {},
  timestamp: '2016-12-31T18:45:21+00:00',
  attachments: [],
};

module.exports = test => {
  describeOptionalProp('objectType', string, validData, test);
  itsInvalid(Object.assign({}, validData, {
    object: {
      objectType: 'SubStatement',
      actor: {
        objectType: 'Agent',
        mbox: 'mailto:test@example.com',
      },
      verb: {
        id: 'http://www.example.com',
      },
      object: {
        objectType: 'Activity',
        id: 'http://www.example.com',
      },
    },
  }), 'object is a SubStatement', test);
  statementSchema((data, valid) =>
    test(Object.assign({}, validData, data), valid);
  )
};
<|endoftext|>


<commit_before>import express from "express"
import shrinkRay from "shrink-ray"
import uuid from "uuid"
import parameterProtection from "hpp"
import helmet from "helmet"
import PrettyError from "pretty-error"
import favicon from "serve-favicon"
import createLocaleMiddleware from "express-locale"
import cookieParser from "cookie-parser"
import bodyParser from "body-parser"

import {
  ABSOLUTE_CLIENT_OUTPUT_PATH,
  ABSOLUTE_PUBLIC_PATH
} from "./config"

const pretty = new PrettyError()

// this will skip events.js and http.js and similar core node files
pretty.skipNodeFiles()

// this will skip all the trace lines about express` core and sub-modules
pretty.skipPackage("express")

export default function createExpressServer(config)
{
  // Create our express based server.
  const server = express()

  // Create new middleware to serve a favicon from the given path to a favicon file.
  server.use(favicon(`${ABSOLUTE_PUBLIC_PATH}/favicon.ico`))

  // Attach a unique "nonce" to every response. This allows use to declare
  // inline scripts as being safe for execution against our content security policy.
  // @see https://helmetjs.github.io/docs/csp/
  server.use((request, response, next) => {
    response.locals.nonce = uuid() // eslint-disable-line no-param-reassign
    next()
  })

  // and use it for our app's error handler:
  server.use((error, request, response, next) => { // eslint-disable-line max-params
    console.log(pretty.render(error))
    next()
  })

  // Don't expose any software information to hackers.
  server.disable("x-powered-by")

  // Prevent HTTP Parameter pollution.
  server.use(parameterProtection())

  // Content Security Policy (CSP)
  //
  // If you are unfamiliar with CSPs then I highly recommend that you do some
  // reading on the subject:
  //  - https://content-security-policy.com/
  //  - https://developers.google.com/web/fundamentals/security/csp/
  //  - https://developer.mozilla.org/en/docs/Web/Security/CSP
  //  - https://helmetjs.github.io/docs/csp/
  //
  // If you are relying on scripts/styles/assets from other servers (internal or
  // external to your company) then you will need to explicitly configure the
  // CSP below to allow for this.  For example you can see I have had to add
  // the polyfill.io CDN in order to allow us to use the polyfill script.
  // It can be a pain to manage these, but it's a really great habit to get in
  // to.
  //
  // You may find CSPs annoying at first, but it is a great habit to build.
  // The CSP configuration is an optional item for helmet, however you should
  // not remove it without making a serious consideration that you do not require
  // the added security.
  const cspConfig = {
    directives: {
      defaultSrc: [ "'self'" ],

      scriptSrc:
      [
        // Allow scripts hosted from our application.
        "'self'",

        // Note: We will execution of any inline scripts that have the following
        // nonce identifier attached to them.
        // This is useful for guarding your application whilst allowing an inline
        // script to do data store rehydration (redux/mobx/apollo) for example.
        // @see https://helmetjs.github.io/docs/csp/
        (request, response) => `'nonce-${response.locals.nonce}'`,

        // FIXME: Required for eval-source-maps (devtool in webpack)
        process.env.NODE_ENV === "development" ? "'unsafe-eval'" : ""
      ].filter((value) => value !== ""),

      styleSrc: [ "'self'", "'unsafe-inline'", "blob:" ],
      imgSrc: [ "'self'", "data:" ],
      fontSrc: [ "'self'", "data:" ],

      // Note: Setting this to stricter than * breaks the service worker. :(
      // I can't figure out how to get around this, so if you know of a safer
      // implementation that is kinder to service workers please let me know.
      // ["'self'", 'ws:'],
      connectSrc: [ "*" ],

      // objectSrc: [ "'none'" ],
      // mediaSrc: [ "'none'" ],

      childSrc: [ "'self'" ]
    }
  }

  if (process.env.NODE_ENV === "development") {
    // When in development mode we need to add our secondary express server that
    // is used to host our client bundle to our csp config.
    Object.keys(cspConfig.directives).forEach((directive) =>
      cspConfig.directives[directive].push(`localhost:${process.env.CLIENT_DEVSERVER_PORT}`)
    )
  }

  server.use(helmet.contentSecurityPolicy(cspConfig))

  // The xssFilter middleware sets the X-XSS-Protection header to prevent
  // reflected XSS attacks.
  // @see https://helmetjs.github.io/docs/xss-filter/
  server.use(helmet.xssFilter())

  // Frameguard mitigates clickjacking attacks by setting the X-Frame-Options header.
  // @see https://helmetjs.github.io/docs/frameguard/
  server.use(helmet.frameguard("deny"))

  // Sets the X-Download-Options to prevent Internet Explorer from executing
  // downloads in your site’s context.
  // @see https://helmetjs.github.io/docs/ienoopen/
  server.use(helmet.ieNoOpen())

  // Don’t Sniff Mimetype middleware, noSniff, helps prevent browsers from trying
  // to guess (“sniff”) the MIME type, which can have security implications. It
  // does this by setting the X-Content-Type-Options header to nosniff.
  // @see https://helmetjs.github.io/docs/dont-sniff-mimetype/
  server.use(helmet.noSniff())

  if (hooks.onSecuredServerCreated)
    hooks.onSecuredServerCreated(server)

  // Parse cookies via standard express tooling
  server.use(cookieParser())

  // Detect client locale and match it with configuration
  server.use(createLocaleMiddleware({
    priority: [ "query", "cookie", "accept-language", "default" ],
    default: config.DEFAULT_LOCALE.replace(/-/, "_"),
    allowed: config.ALLOWED_LOCALES.map((entry) => entry.replace(/-/, "_"))
  }))

  // Parse application/x-www-form-urlencoded
  server.use(bodyParser.urlencoded({ extended: false }))

  // Parse application/json
  server.use(bodyParser.json())

  // Advanced response compression using a async zopfli/brotli combination
  // https://github.com/aickin/shrink-ray
  server.use(shrinkRay())

  // Configure static serving of our webpack bundled client files.
  server.use(
    process.env.CLIENT_BUNDLE_HTTP_PATH,
    express.static(ABSOLUTE_CLIENT_OUTPUT_PATH, {
      maxAge: process.env.CLIENT_BUNDLE_CACHE_MAXAGE
    })
  )

  // Configure static serving of our "public" root http path static files.
  server.use(express.static(ABSOLUTE_PUBLIC_PATH))

  return server
}
<commit_msg>Introduce customMiddleware as parameter of config in createExpressServer()<commit_after>import express from "express"
import shrinkRay from "shrink-ray"
import uuid from "uuid"
import parameterProtection from "hpp"
import helmet from "helmet"
import PrettyError from "pretty-error"
import favicon from "serve-favicon"
import createLocaleMiddleware from "express-locale"
import cookieParser from "cookie-parser"
import bodyParser from "body-parser"

import {
  ABSOLUTE_CLIENT_OUTPUT_PATH,
  ABSOLUTE_PUBLIC_PATH
} from "./config"

const pretty = new PrettyError()

// this will skip events.js and http.js and similar core node files
pretty.skipNodeFiles()

// this will skip all the trace lines about express` core and sub-modules
pretty.skipPackage("express")

export default function createExpressServer(config)
{
  // Create our express based server.
  const server = express()

  // Create new middleware to serve a favicon from the given path to a favicon file.
  server.use(favicon(`${ABSOLUTE_PUBLIC_PATH}/favicon.ico`))

  // Attach a unique "nonce" to every response. This allows use to declare
  // inline scripts as being safe for execution against our content security policy.
  // @see https://helmetjs.github.io/docs/csp/
  server.use((request, response, next) => {
    response.locals.nonce = uuid() // eslint-disable-line no-param-reassign
    next()
  })

  // and use it for our app's error handler:
  server.use((error, request, response, next) => { // eslint-disable-line max-params
    console.log(pretty.render(error))
    next()
  })

  // Don't expose any software information to hackers.
  server.disable("x-powered-by")

  // Prevent HTTP Parameter pollution.
  server.use(parameterProtection())

  // Content Security Policy (CSP)
  //
  // If you are unfamiliar with CSPs then I highly recommend that you do some
  // reading on the subject:
  //  - https://content-security-policy.com/
  //  - https://developers.google.com/web/fundamentals/security/csp/
  //  - https://developer.mozilla.org/en/docs/Web/Security/CSP
  //  - https://helmetjs.github.io/docs/csp/
  //
  // If you are relying on scripts/styles/assets from other servers (internal or
  // external to your company) then you will need to explicitly configure the
  // CSP below to allow for this.  For example you can see I have had to add
  // the polyfill.io CDN in order to allow us to use the polyfill script.
  // It can be a pain to manage these, but it's a really great habit to get in
  // to.
  //
  // You may find CSPs annoying at first, but it is a great habit to build.
  // The CSP configuration is an optional item for helmet, however you should
  // not remove it without making a serious consideration that you do not require
  // the added security.
  const cspConfig = {
    directives: {
      defaultSrc: [ "'self'" ],

      scriptSrc:
      [
        // Allow scripts hosted from our application.
        "'self'",

        // Note: We will execution of any inline scripts that have the following
        // nonce identifier attached to them.
        // This is useful for guarding your application whilst allowing an inline
        // script to do data store rehydration (redux/mobx/apollo) for example.
        // @see https://helmetjs.github.io/docs/csp/
        (request, response) => `'nonce-${response.locals.nonce}'`,

        // FIXME: Required for eval-source-maps (devtool in webpack)
        process.env.NODE_ENV === "development" ? "'unsafe-eval'" : ""
      ].filter((value) => value !== ""),

      styleSrc: [ "'self'", "'unsafe-inline'", "blob:" ],
      imgSrc: [ "'self'", "data:" ],
      fontSrc: [ "'self'", "data:" ],

      // Note: Setting this to stricter than * breaks the service worker. :(
      // I can't figure out how to get around this, so if you know of a safer
      // implementation that is kinder to service workers please let me know.
      // ["'self'", 'ws:'],
      connectSrc: [ "*" ],

      // objectSrc: [ "'none'" ],
      // mediaSrc: [ "'none'" ],

      childSrc: [ "'self'" ]
    }
  }

  if (process.env.NODE_ENV === "development") {
    // When in development mode we need to add our secondary express server that
    // is used to host our client bundle to our csp config.
    Object.keys(cspConfig.directives).forEach((directive) =>
      cspConfig.directives[directive].push(`localhost:${process.env.CLIENT_DEVSERVER_PORT}`)
    )
  }

  server.use(helmet.contentSecurityPolicy(cspConfig))

  // The xssFilter middleware sets the X-XSS-Protection header to prevent
  // reflected XSS attacks.
  // @see https://helmetjs.github.io/docs/xss-filter/
  server.use(helmet.xssFilter())

  // Frameguard mitigates clickjacking attacks by setting the X-Frame-Options header.
  // @see https://helmetjs.github.io/docs/frameguard/
  server.use(helmet.frameguard("deny"))

  // Sets the X-Download-Options to prevent Internet Explorer from executing
  // downloads in your site’s context.
  // @see https://helmetjs.github.io/docs/ienoopen/
  server.use(helmet.ieNoOpen())

  // Don’t Sniff Mimetype middleware, noSniff, helps prevent browsers from trying
  // to guess (“sniff”) the MIME type, which can have security implications. It
  // does this by setting the X-Content-Type-Options header to nosniff.
  // @see https://helmetjs.github.io/docs/dont-sniff-mimetype/
  server.use(helmet.noSniff())

  if (config.customMiddleware)
    config.customMiddleware.forEach(
      (middleware) => {
        if (middleware instanceof Array)
          server.use(...middleware)
        else
          server.use(middleware)
      }
    )

  // Parse cookies via standard express tooling
  server.use(cookieParser())

  // Detect client locale and match it with configuration
  server.use(createLocaleMiddleware({
    priority: [ "query", "cookie", "accept-language", "default" ],
    default: config.DEFAULT_LOCALE.replace(/-/, "_"),
    allowed: config.ALLOWED_LOCALES.map((entry) => entry.replace(/-/, "_"))
  }))

  // Parse application/x-www-form-urlencoded
  server.use(bodyParser.urlencoded({ extended: false }))

  // Parse application/json
  server.use(bodyParser.json())

  // Advanced response compression using a async zopfli/brotli combination
  // https://github.com/aickin/shrink-ray
  server.use(shrinkRay())

  // Configure static serving of our webpack bundled client files.
  server.use(
    process.env.CLIENT_BUNDLE_HTTP_PATH,
    express.static(ABSOLUTE_CLIENT_OUTPUT_PATH, {
      maxAge: process.env.CLIENT_BUNDLE_CACHE_MAXAGE
    })
  )

  // Configure static serving of our "public" root http path static files.
  server.use(express.static(ABSOLUTE_PUBLIC_PATH))

  return server
}
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import Card from 'material-ui/lib/card/card';
import CardText from 'material-ui/lib/card/card-text';
import { Link } from 'react-router';
import MediaStatus from './MediaStatus';
import MediaMetadataSummary from './MediaMetadataSummary';

class MediaCard extends Component {

  render() {
    const that = this;
    const props = that.props;
    const { media, annotated, annotatedType } = props;
    media.created_at = new Date(parseInt(media.published) * 1000);
    const data = JSON.parse(media.jsondata);

    const project = annotated;
    linkUrl = '/team/' + project.team.dbid + '/project/' + project.dbid + '/media/' + media.dbid;
    return (

        <Link to={linkUrl} className='media-card__clickable'>{/* TODO: linkify more selectively */}

<MediaStatus media={media} />

{data.title}

            <MediaMetadataSummary media={media} data={data} />

        </Link>

    );
  }
}

export default MediaCard;
<commit_msg>Only assemble MediaCard link if possible<commit_after>import React, { Component, PropTypes } from 'react';
import Card from 'material-ui/lib/card/card';
import CardText from 'material-ui/lib/card/card-text';
import { Link } from 'react-router';
import MediaStatus from './MediaStatus';
import MediaMetadataSummary from './MediaMetadataSummary';

class MediaCard extends Component {

  render() {
    const that = this;
    const props = that.props;
    const { media, annotated, annotatedType } = props;
    media.created_at = new Date(parseInt(media.published) * 1000);
    const data = JSON.parse(media.jsondata);

    let linkUrl = null;
    if (annotatedType === 'Project' && annotated && annotated.team) { // TODO: better support for media cards on sources
      const project = annotated;
      linkUrl = '/team/' + project.team.dbid + '/project/' + project.dbid + '/media/' + media.dbid;
    }

    return (

        <Link to={linkUrl} className='media-card__clickable'>{/* TODO: linkify more selectively */}

<MediaStatus media={media} />

{data.title}

            <MediaMetadataSummary media={media} data={data} />

        </Link>

    );
  }
}

export default MediaCard;
<|endoftext|>


<commit_before>/**
 * The Component Utility
 *
 * @module aui-component
 */

var Lang = A.Lang,

	concat = function(arr, arr2) {
		return (arr || []).concat(arr2 || []);
	},

	getClassName = A.ClassNameManager.getClassName,

	NAME = 'component',

	CSS_COMPONENT = getClassName(NAME),

	CSS_HELPER_HIDDEN = getClassName('helper', 'hidden'),
	CONSTRUCTOR_OBJECT = Object.prototype.constructor;

/**
 * A base class for Component, providing:
 *

 *
Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)

 *

 *

 *
 * Check the list of Configuration Attributes available for
 * Component.
 *
 * @param config {Object} Object literal specifying widget configuration properties.
 *
 * @class Component
 * @constructor
 * @extends Widget
 */
var Component = function(config) {
	var instance = this;

	instance._originalConfig = config;

	instance._setRender(config);

	Component.superclass.constructor.apply(this, arguments);

	INSTANCES[instance.get('id')] = instance;
};

var INSTANCES = Component._INSTANCES = {};

/**
 * Static property provides a string to identify the class.
 *
 * @property Component.NAME
 * @type String
 * @static
 */
Component.NAME = 'component';

/**
 * Static property used to define the default attribute
 * configuration for the Component.
 *
 * @property Component.ATTRS
 * @type Object
 * @static
 */
Component.ATTRS = {
	/**
	 * CSS class to be automatically added to the boundingBox.
	 *
	 * @attribute cssClass
	 * @default null
	 * @type String
	 */
	cssClass: {
		lazyAdd: false,
		value: null
	},

	/**
	 * css class added to hide the boundingBox when
     * visible is set to
     * false.
	 *
	 * @attribute hideClass
	 * @default 'aui-helper-hidden'
	 * @type String
	 */
	hideClass: {
		value: CSS_HELPER_HIDDEN
	},

	/**
	 * If true the render phase will be autimatically invoked
     * preventing the .render() manual call.
	 *
	 * @attribute render
	 * @default false
	 * @type boolean | Node
	 */
	render: {
		value: false,
		writeOnce: true
	}
};

A.extend(
	Component,
	A.Widget,
	{
		/**
		 * Construction logic executed during Component instantiation. Lifecycle.
		 *
		 * @method initializer
		 * @protected
		 */
		initializer: function(config) {
			var instance = this;

			if (config && config.cssClass) {
				instance._uiSetCssClass(config.cssClass);
			}

			instance._setComponentClassNames();

			instance.after('cssClassChange', instance._afterCssClassChange);
			instance.after('visibleChange', instance._afterComponentVisibleChange);
		},

		/**
		 * Clone the current Component.
		 *
		 * @method clone
		 * @param {Object} config
		 * @return {Widget} Cloned instance.
		 */
		clone: function(config) {
			var instance = this;

			config = config || {};

			config.id = config.id || A.guid();

			A.mix(config, instance._originalConfig);

			return new instance.constructor(config);
		},

		/**
		 * Toggle the visibility of the Panel toggling the value of the
	     * visible attribute.
		 *
		 * @method toggle
		 */
		toggle: function() {
			var instance = this;

			return instance.set('visible', !instance.get('visible'));
		},

		/**
		 * Fires after the value of the
		 * visible attribute change.
		 *
		 * @method _afterComponentVisibleChange
		 * @param {EventFacade} event
		 * @protected
		 */
		_afterComponentVisibleChange: function(event) {
			var instance = this;

			var hideClass = instance.get('hideClass');

			if (hideClass !== false) {
				var boundingBox = instance.get('boundingBox');

				var action = 'addClass';

				if (event.newVal) {
					action = 'removeClass';
				}

				boundingBox[action](hideClass || CSS_HELPER_HIDDEN);
			}
		},

		/**
		 * Fires after the value of the
		 * cssClass attribute change.
		 *
		 * @method _afterCssClassChange
		 * @param {EventFacade} event
		 * @protected
		 */
		_afterCssClassChange: function(event) {
			var instance = this;

			instance._uiSetCssClass(event.newVal, event.prevVal);
		},

		/**
		 * Renders the Component based upon a passed in interaction.
		 *
		 * @method _renderInteraction
		 * @protected
		 */
		_renderInteraction: function(event, parentNode) {
			var instance = this;

			instance.render(parentNode);

			var renderHandles = instance._renderHandles;

			for (var i = renderHandles.length - 1; i >= 0; i--) {
				var handle = renderHandles.pop();

				handle.detach();
			}
		},

		/**
		 * Set the class names on the Component contentBox.
		 *
		 * @method _setComponentClassNames
		 * @protected
		 */
		_setComponentClassNames: function() {
			var instance = this;

			var classes = instance._getClasses();
			var name;
			var buffer = [];

			for (var i = classes.length - 4; i >= 0; i--) {
				name = classes[i].NAME.toLowerCase();

				buffer.push(getClassName(name, 'content'));
			}

			instance.get('contentBox').addClass(buffer.join(' '));
		},

		/**
		 * Set the interaction and render behavior based upon an object
		 * (intercepts the default rendering behavior).
		 *
		 * @method _setRender
		 * @protected
		 */
		_setRender: function(config) {
			var instance = this;

			var render = config && config.render;

			if (render && render.constructor == CONSTRUCTOR_OBJECT) {
				var eventType = render.eventType || 'mousemove';
				var parentNode = render.parentNode;
				var selector = render.selector || parentNode;

				if (selector) {
					instance._renderHandles = [];

					var renderHandles = instance._renderHandles;

					if (!Lang.isArray(eventType)) {
						eventType = [eventType];
					}

					var renderInteraction = A.rbind(instance._renderInteraction, instance, parentNode);

					var interactionNode = A.one(selector);

					 for (var i = eventType.length - 1; i >= 0; i--) {
						renderHandles[i] = interactionNode.once(eventType[i], renderInteraction);
					 }

					delete config.render;
				}
			}
		},

		/**
		 * Applies the CSS classes to the boundingBox and
         * contentBox.
		 *
		 * @method _uiSetCssClass
		 * @protected
		 * @param {String} newVal
		 * @param {String} prevVal
		 */
		_uiSetCssClass: function(newVal, prevVal) {
			var instance = this;

			var prevValContent = prevVal + '-content';

			var newValContent = newVal + '-content';

			var boundingBox = instance.get('boundingBox');
			var contentBox = instance.get('contentBox');

			boundingBox.replaceClass(prevVal, newVal);
			contentBox.replaceClass(prevValContent, newValContent);
		}
	}
);

Component.getById = function(id) {
	return INSTANCES[id];
};

var COMP_PROTO = Component.prototype;

var DEFAULT_UI_ATTRS = A.Widget.prototype._UI_ATTRS;

var DEFAULT_BIND_ATTRS = DEFAULT_UI_ATTRS.BIND;
var DEFAULT_SYNC_ATTRS = DEFAULT_UI_ATTRS.SYNC;

Component.create = function(config) {
	config = config || {};

	var extendsClass = config.EXTENDS || A.Component;

	var component = config.constructor;

	if (!component || component == CONSTRUCTOR_OBJECT){
		component = function(){
			component.superclass.constructor.apply(this, arguments);
		};
	}

	var configProto = config.prototype;

	if (configProto) {
		var configProtoUIAttrs = configProto._UI_ATTRS || (configProto._UI_ATTRS = {
			BIND: DEFAULT_BIND_ATTRS.slice(0),
			SYNC: DEFAULT_SYNC_ATTRS.slice(0)
		});

		var BIND_UI_ATTRS = concat(config.BIND_UI_ATTRS, config.UI_ATTRS);
		var SYNC_UI_ATTRS = concat(config.SYNC_UI_ATTRS, config.UI_ATTRS);

		if (BIND_UI_ATTRS.length) {
			configProtoUIAttrs.BIND = concat(COMP_PROTO._UI_ATTRS.BIND, BIND_UI_ATTRS);
		}

		if (SYNC_UI_ATTRS.length) {
			configProtoUIAttrs.SYNC = concat(COMP_PROTO._UI_ATTRS.SYNC, SYNC_UI_ATTRS);
		}
	}

	var augmentsClasses = config.AUGMENTS;

	if (augmentsClasses && !Lang.isArray(augmentsClasses)) {
		augmentsClasses = [augmentsClasses];
	}

	A.mix(component, config);

	delete component.prototype;

	A.extend(component, extendsClass, configProto);

	if (augmentsClasses) {
		component = A.Base.build(config.NAME, component, augmentsClasses, { dynamic: false });
	}

	return component;
};

A.Component = Component;<commit_msg>AUI-332 Adding useARIA attribute to A.Component<commit_after>/**
 * The Component Utility
 *
 * @module aui-component
 */

var Lang = A.Lang,

	concat = function(arr, arr2) {
		return (arr || []).concat(arr2 || []);
	},

	getClassName = A.ClassNameManager.getClassName,

	NAME = 'component',

	CSS_COMPONENT = getClassName(NAME),

	CSS_HELPER_HIDDEN = getClassName('helper', 'hidden'),
	CONSTRUCTOR_OBJECT = Object.prototype.constructor;

/**
 * A base class for Component, providing:
 *

 *
Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)

 *

 *

 *
 * Check the list of Configuration Attributes available for
 * Component.
 *
 * @param config {Object} Object literal specifying widget configuration properties.
 *
 * @class Component
 * @constructor
 * @extends Widget
 */
var Component = function(config) {
	var instance = this;

	instance._originalConfig = config;

	instance._setRender(config);

	Component.superclass.constructor.apply(this, arguments);

	INSTANCES[instance.get('id')] = instance;
};

var INSTANCES = Component._INSTANCES = {};

/**
 * Static property provides a string to identify the class.
 *
 * @property Component.NAME
 * @type String
 * @static
 */
Component.NAME = 'component';

/**
 * Static property used to define the default attribute
 * configuration for the Component.
 *
 * @property Component.ATTRS
 * @type Object
 * @static
 */
Component.ATTRS = {
	/**
	* Boolean indicating if use of the WAI-ARIA Roles and States should be
	* enabled for the Widget.
	*
	* @attribute useARIA
	* @readOnly
	* @writeOnce
	* @default true
	* @type boolean
	*/
	useARIA: {
		writeOnce: true,
		value: false,
		validator: Lang.isBoolean
	},

	/**
	 * CSS class to be automatically added to the boundingBox.
	 *
	 * @attribute cssClass
	 * @default null
	 * @type String
	 */
	cssClass: {
		lazyAdd: false,
		value: null
	},

	/**
	 * css class added to hide the boundingBox when
     * visible is set to
     * false.
	 *
	 * @attribute hideClass
	 * @default 'aui-helper-hidden'
	 * @type String
	 */
	hideClass: {
		value: CSS_HELPER_HIDDEN
	},

	/**
	 * If true the render phase will be autimatically invoked
     * preventing the .render() manual call.
	 *
	 * @attribute render
	 * @default false
	 * @type boolean | Node
	 */
	render: {
		value: false,
		writeOnce: true
	}
};

A.extend(
	Component,
	A.Widget,
	{
		/**
		 * Construction logic executed during Component instantiation. Lifecycle.
		 *
		 * @method initializer
		 * @protected
		 */
		initializer: function(config) {
			var instance = this;

			if (config && config.cssClass) {
				instance._uiSetCssClass(config.cssClass);
			}

			instance._setComponentClassNames();

			instance.after('cssClassChange', instance._afterCssClassChange);
			instance.after('visibleChange', instance._afterComponentVisibleChange);
		},

		/**
		 * Clone the current Component.
		 *
		 * @method clone
		 * @param {Object} config
		 * @return {Widget} Cloned instance.
		 */
		clone: function(config) {
			var instance = this;

			config = config || {};

			config.id = config.id || A.guid();

			A.mix(config, instance._originalConfig);

			return new instance.constructor(config);
		},

		/**
		 * Toggle the visibility of the Panel toggling the value of the
	     * visible attribute.
		 *
		 * @method toggle
		 */
		toggle: function() {
			var instance = this;

			return instance.set('visible', !instance.get('visible'));
		},

		/**
		 * Fires after the value of the
		 * visible attribute change.
		 *
		 * @method _afterComponentVisibleChange
		 * @param {EventFacade} event
		 * @protected
		 */
		_afterComponentVisibleChange: function(event) {
			var instance = this;

			var hideClass = instance.get('hideClass');

			if (hideClass !== false) {
				var boundingBox = instance.get('boundingBox');

				var action = 'addClass';

				if (event.newVal) {
					action = 'removeClass';
				}

				boundingBox[action](hideClass || CSS_HELPER_HIDDEN);
			}
		},

		/**
		 * Fires after the value of the
		 * cssClass attribute change.
		 *
		 * @method _afterCssClassChange
		 * @param {EventFacade} event
		 * @protected
		 */
		_afterCssClassChange: function(event) {
			var instance = this;

			instance._uiSetCssClass(event.newVal, event.prevVal);
		},

		/**
		 * Renders the Component based upon a passed in interaction.
		 *
		 * @method _renderInteraction
		 * @protected
		 */
		_renderInteraction: function(event, parentNode) {
			var instance = this;

			instance.render(parentNode);

			var renderHandles = instance._renderHandles;

			for (var i = renderHandles.length - 1; i >= 0; i--) {
				var handle = renderHandles.pop();

				handle.detach();
			}
		},

		/**
		 * Set the class names on the Component contentBox.
		 *
		 * @method _setComponentClassNames
		 * @protected
		 */
		_setComponentClassNames: function() {
			var instance = this;

			var classes = instance._getClasses();
			var name;
			var buffer = [];

			for (var i = classes.length - 4; i >= 0; i--) {
				name = classes[i].NAME.toLowerCase();

				buffer.push(getClassName(name, 'content'));
			}

			instance.get('contentBox').addClass(buffer.join(' '));
		},

		/**
		 * Set the interaction and render behavior based upon an object
		 * (intercepts the default rendering behavior).
		 *
		 * @method _setRender
		 * @protected
		 */
		_setRender: function(config) {
			var instance = this;

			var render = config && config.render;

			if (render && render.constructor == CONSTRUCTOR_OBJECT) {
				var eventType = render.eventType || 'mousemove';
				var parentNode = render.parentNode;
				var selector = render.selector || parentNode;

				if (selector) {
					instance._renderHandles = [];

					var renderHandles = instance._renderHandles;

					if (!Lang.isArray(eventType)) {
						eventType = [eventType];
					}

					var renderInteraction = A.rbind(instance._renderInteraction, instance, parentNode);

					var interactionNode = A.one(selector);

					 for (var i = eventType.length - 1; i >= 0; i--) {
						renderHandles[i] = interactionNode.once(eventType[i], renderInteraction);
					 }

					delete config.render;
				}
			}
		},

		/**
		 * Applies the CSS classes to the boundingBox and
         * contentBox.
		 *
		 * @method _uiSetCssClass
		 * @protected
		 * @param {String} newVal
		 * @param {String} prevVal
		 */
		_uiSetCssClass: function(newVal, prevVal) {
			var instance = this;

			var prevValContent = prevVal + '-content';

			var newValContent = newVal + '-content';

			var boundingBox = instance.get('boundingBox');
			var contentBox = instance.get('contentBox');

			boundingBox.replaceClass(prevVal, newVal);
			contentBox.replaceClass(prevValContent, newValContent);
		}
	}
);

Component.getById = function(id) {
	return INSTANCES[id];
};

var COMP_PROTO = Component.prototype;

var DEFAULT_UI_ATTRS = A.Widget.prototype._UI_ATTRS;

var DEFAULT_BIND_ATTRS = DEFAULT_UI_ATTRS.BIND;
var DEFAULT_SYNC_ATTRS = DEFAULT_UI_ATTRS.SYNC;

Component.create = function(config) {
	config = config || {};

	var extendsClass = config.EXTENDS || A.Component;

	var component = config.constructor;

	if (!component || component == CONSTRUCTOR_OBJECT){
		component = function(){
			component.superclass.constructor.apply(this, arguments);
		};
	}

	var configProto = config.prototype;

	if (configProto) {
		var configProtoUIAttrs = configProto._UI_ATTRS || (configProto._UI_ATTRS = {
			BIND: DEFAULT_BIND_ATTRS.slice(0),
			SYNC: DEFAULT_SYNC_ATTRS.slice(0)
		});

		var BIND_UI_ATTRS = concat(config.BIND_UI_ATTRS, config.UI_ATTRS);
		var SYNC_UI_ATTRS = concat(config.SYNC_UI_ATTRS, config.UI_ATTRS);

		if (BIND_UI_ATTRS.length) {
			configProtoUIAttrs.BIND = concat(COMP_PROTO._UI_ATTRS.BIND, BIND_UI_ATTRS);
		}

		if (SYNC_UI_ATTRS.length) {
			configProtoUIAttrs.SYNC = concat(COMP_PROTO._UI_ATTRS.SYNC, SYNC_UI_ATTRS);
		}
	}

	var augmentsClasses = config.AUGMENTS;

	if (augmentsClasses && !Lang.isArray(augmentsClasses)) {
		augmentsClasses = [augmentsClasses];
	}

	A.mix(component, config);

	delete component.prototype;

	A.extend(component, extendsClass, configProto);

	if (augmentsClasses) {
		component = A.Base.build(config.NAME, component, augmentsClasses, { dynamic: false });
	}

	return component;
};

A.Component = Component;<|endoftext|>


<commit_before>import fs from "fs-extra";
import path from "path";
import inquirer from "inquirer";
import sha1 from "sha1";
import readFileSyncStrip from "../lib/readFileSyncStrip";
import logger from "../lib/logger";
import { warn } from "../lib/logsColorScheme";

function doUpdate(from, to) {
  logger.info("Updating .babelrc file...");
  fs.copySync(from, to);
}

export default function updateBabelConfig() {
  return new Promise(resolve => {

    const projectConfigPath = path.join(process.cwd(), ".babelrc");
    const latestConfigPath = path.join(__dirname, "../..", "new", ".babelrc");
    const projectSha = sha1(readFileSyncStrip(projectConfigPath));
    const previousSha = sha1(readFileSyncStrip(path.join(__dirname, "previous", ".babelrc")));
    const latestSha = sha1(readFileSyncStrip(latestConfigPath));

    if (projectSha === latestSha) {
      return resolve();
    }
    else if (projectSha !== previousSha) {
      const question = {
        type: "confirm",
        name: "confirm",
        message: `${warn("The format of .babelrc is out of date. Would you like to automatically update it?")}`
      };

      inquirer.prompt([question], function (answers) {
        if (!answers.confirm) {
          const latestConfig = fs.readFileSync(latestConfigPath);
          logger.info(`It is recommended that you update your .babelrc file. Here is an example file:\n${latestConfig}`);
          return resolve();
        }

        doUpdate(latestConfigPath, projectConfigPath);
        return resolve();
      });
    }
    doUpdate(latestConfigPath, projectConfigPath);
    return resolve();
  });
}
<commit_msg>Cleanup autoupgrade logic<commit_after>import fs from "fs-extra";
import path from "path";
import inquirer from "inquirer";
import sha1 from "sha1";
import readFileSyncStrip from "../lib/readFileSyncStrip";
import logger from "../lib/logger";
import { warn } from "../lib/logsColorScheme";

function doUpdate(from, to) {
  logger.info("Updating .babelrc file...");
  fs.copySync(from, to);
}

export default function updateBabelConfig() {
  return new Promise(resolve => {

    const projectConfigPath = path.join(process.cwd(), ".babelrc");
    const latestConfigPath = path.join(__dirname, "../..", "new", ".babelrc");
    const projectSha = sha1(readFileSyncStrip(projectConfigPath));
    const previousSha = sha1(readFileSyncStrip(path.join(__dirname, "previous", ".babelrc")));
    const latestSha = sha1(readFileSyncStrip(latestConfigPath));

    if (projectSha === latestSha) {
      resolve();
    }
    else if (projectSha === previousSha) {
      doUpdate(latestConfigPath, projectConfigPath);
      resolve();
    }
    else {
      const question = {
        type: "confirm",
        name: "confirm",
        message: `${warn("The format of .babelrc is out of date. Would you like to automatically update it?")}`
      };

      inquirer.prompt([question], function (answers) {
        if (!answers.confirm) {
          const latestConfig = fs.readFileSync(latestConfigPath);
          logger.info(`It is recommended that you update your .babelrc file. Here is an example file:\n${latestConfig}`);
          return resolve();
        }

        doUpdate(latestConfigPath, projectConfigPath);
        resolve();
      });
    }
  });
}
<|endoftext|>