<commit_before>/* @flow */

var resolveStyles = require('./resolve-styles.js');
var printStyles = require('./print-styles.js');

var enhanceWithRadium = function (ComposedComponent: constructor): constructor {
  class RadiumEnhancer extends ComposedComponent {
    _radiumMediaQueryListenersByQuery: {[query: string]: {remove: () => void}};
    _radiumMouseUpListener: {remove: () => void};

    constructor () {
      super(...arguments);

      this.state = this.state || {};
      this.state._radiumStyleState = {};

      if (RadiumEnhancer.printStyleClass) {
        this.printStyleClass = RadiumEnhancer.printStyleClass;
      }
    }

    render () {
      var renderedElement = super.render();
      return resolveStyles(this, renderedElement);
    }

    componentWillUnmount () {
      if (super.componentWillUnmount) {
        super.componentWillUnmount();
      }

      if (this._radiumMouseUpListener) {
        this._radiumMouseUpListener.remove();
      }

      if (this._radiumMediaQueryListenersByQuery) {
        Object.keys(this._radiumMediaQueryListenersByQuery).forEach(
          function (query) {
            this._radiumMediaQueryListenersByQuery[query].remove();
          },
          this
        );
      }
    }
  }

  // Class inheritance uses Object.create and because of __proto__ issues
  // with IE <10 any static properties of the superclass aren't inherited and
  // so need to be manually populated
  // See http://babeljs.io/docs/advanced/caveats/#classes-10-and-below-
  var staticKeys = [
    'defaultProps',
    'propTypes',
    'contextTypes',
    'childContextTypes'
  ];

  staticKeys.forEach((key) => {
    if (ComposedComponent.hasOwnProperty(key)) {
      RadiumEnhancer[key] = ComposedComponent[key];
    }
  });

  if (process.env.NODE_ENV !== 'production') {
    // This fixes React Hot Loader by exposing the original components top level
    // prototype methods on the Radium enhanced prototype as discussed in #219.
    Object.keys(ComposedComponent.prototype).forEach(key => {
      if (!RadiumEnhancer.prototype.hasOwnProperty(key)) {
        var descriptor = Object.getOwnPropertyDescriptor(ComposedComponent.prototype, key);
        Object.defineProperty(RadiumEnhancer.prototype, key, descriptor);
      }
    });
  }

  RadiumEnhancer.displayName =
    ComposedComponent.displayName ||
    ComposedComponent.name ||
    'Component';

  RadiumEnhancer.printStyleClass = printStyles.addPrintStyles(RadiumEnhancer);

  return RadiumEnhancer;
};

module.exports = enhanceWithRadium;
<commit_msg>[#313] Ensure components top level prototype methods are all exposed<commit_after>/* @flow */

var resolveStyles = require('./resolve-styles.js');
var printStyles = require('./print-styles.js');

var enhanceWithRadium = function (ComposedComponent: constructor): constructor {
  class RadiumEnhancer extends ComposedComponent {
    _radiumMediaQueryListenersByQuery: {[query: string]: {remove: () => void}};
    _radiumMouseUpListener: {remove: () => void};

    constructor () {
      super(...arguments);

      this.state = this.state || {};
      this.state._radiumStyleState = {};

      if (RadiumEnhancer.printStyleClass) {
        this.printStyleClass = RadiumEnhancer.printStyleClass;
      }
    }

    render () {
      var renderedElement = super.render();
      return resolveStyles(this, renderedElement);
    }

    componentWillUnmount () {
      if (super.componentWillUnmount) {
        super.componentWillUnmount();
      }

      if (this._radiumMouseUpListener) {
        this._radiumMouseUpListener.remove();
      }

      if (this._radiumMediaQueryListenersByQuery) {
        Object.keys(this._radiumMediaQueryListenersByQuery).forEach(
          function (query) {
            this._radiumMediaQueryListenersByQuery[query].remove();
          },
          this
        );
      }
    }
  }

  // Class inheritance uses Object.create and because of __proto__ issues
  // with IE <10 any static properties of the superclass aren't inherited and
  // so need to be manually populated
  // See http://babeljs.io/docs/advanced/caveats/#classes-10-and-below-
  // This also fixes React Hot Loader by exposing the original components top level
  // prototype methods on the Radium enhanced prototype as discussed in #219.
  Object.keys(ComposedComponent.prototype).forEach(key => {
    if (!RadiumEnhancer.prototype.hasOwnProperty(key)) {
      var descriptor = Object.getOwnPropertyDescriptor(ComposedComponent.prototype, key);
      Object.defineProperty(RadiumEnhancer.prototype, key, descriptor);
    }
  });

  RadiumEnhancer.displayName =
    ComposedComponent.displayName ||
    ComposedComponent.name ||
    'Component';

  RadiumEnhancer.printStyleClass = printStyles.addPrintStyles(RadiumEnhancer);

  return RadiumEnhancer;
};

module.exports = enhanceWithRadium;
<|endoftext|>


<commit_before>/**
 * Player.js
 *
 * Foofighter.js — Player entity
 *
 * This class represents the data model and display entity for a
 * Player's startship in the game environment.
 */

;(function( FooFighter ){

'use strict';

function Player ( gameState, group ) {
    this.gameState = gameState;
    this.config = {};
    this.sprite = {};
    this.movementVelocity = 300;
    this.displayStates = {
        neutral: 'player.png',
        left: 'playerLeft.png',
        right: 'playerRight.png'
    };
    this.fireTimer = 250;
    this.canFire = true;
    this.lastFired = new Date().getTime();
    this.group = group;
    this.config.laser = {
        velocity: -500,
        fireTimer: 250
    };
    this.lasers = gameState.groups.lasers;
    this.bindEvents();
}

var proto = Player.prototype;

proto.bindEvents = function(){
    var vent = this.gameState.vent;

    vent.on('create', this.create.bind(this));
    vent.on('update', function(){
        this.movementHandler();
        this.weaponHandler();
    }.bind(this));
    return this;
};

proto.create = function(){
    var game = this.gameState.game;

    // Build the sprite entitiy
    this.sprite = game.add.sprite(
        game.world.centerX, game.world.centerY,
        'sprites', this.displayStates.neutral
    );
    // Anchor in the center of the sprite
    this.sprite.anchor = {
        x: 0.5,
        y: 0.5
    };
    // Add it to the correct display group
    this.group.add(this.sprite);
    this.sprite.events.onKilled.add(this.onKill.bind(this));
    return this;
};

proto.movementHandler = function(){
    var game = this.gameState.game,
        magnitude = this.movementVelocity,
        modifier = 1,
        axis,
        cursors = this.gameState.cursors;

    // Reset any prior velocity vals
    this.sprite.body.velocity.setTo(0, 0);

    // Detect which cursor keys are pressed and modify the sprite
    // display frame texture for X axis directions
    if ( cursors.up.isDown ) {
        modifier = -1;
        axis = 'y';
    } else if ( cursors.down.isDown ) {
        modifier = 1;
        axis = 'y';
    } else if ( cursors.left.isDown ) {
        this.sprite.loadTexture('sprites', this.displayStates.left);
        modifier = -1;
        axis = 'x';
    } else if ( cursors.right.isDown ) {
        this.sprite.loadTexture('sprites', this.displayStates.right);
        modifier = 1;
        axis = 'x';
    } else {
        this.sprite.loadTexture('sprites', this.displayStates.neutral);
    }

    // This is just the movement speed + directional modifier
    this.sprite.body.velocity[axis] = (modifier * magnitude);
    return this;
};

proto.weaponHandler = function(){
    var game = this.gameState.game,
        cursors = this.gameState.cursors,
        keyboard = this.gameState.keyboard,
        currTime = new Date().getTime(),
        lastFired = this.lastFired,
        throttleVal = this.config.laser.fireTimer,
        laser;

    // If we're dead, don't fire a got damn laser
    if ( !this.sprite.alive ) {
        return false;
    }

    // If spacebar is pressed in this loop step, create a laser and
    // make sure we can't fire again for N milliseconds
    if ( keyboard.isDown(Phaser.Keyboard.SPACEBAR) ) {
        if ( currTime - lastFired >= throttleVal ) {
            this.createLaser();
            this.gameState.updateScore(-2);
            this.lastFired = currTime;
        }
    }
    return this;
};

proto.createLaser = function(){
    var game = this.gameState.game,
        velocity = this.config.laser.velocity,
        laser;

    // Create our laser sprite entity
    laser = game.add.sprite(
        this.sprite.body.x + this.sprite.body.width/2,
        this.sprite.body.y - 10,
        'sprites', 'laserGreen.png'
    );
    // Keep track of all our onscreen lasers (for collision detection)
    this.lasers.add(laser);
    // Anchor to the center of the sprite
    laser.anchor = {
        x: 0.5,
        y: 0.5
    };
    // Set the movement speed
    laser.body.velocity.y = velocity;
    // Clean up any lasers that leave the game scence
    laser.events.onOutOfBounds.add(laser.kill, laser);
    return this;
};

proto.onKill = function(){
    var vent = this.gameState.vent;

    vent.emit('game-over');
};

FooFighter.Player = Player;

})(FooFighter);
<commit_msg>implement sprite pooling for player lasers<commit_after>/**
 * Player.js
 *
 * Foofighter.js — Player entity
 *
 * This class represents the data model and display entity for a
 * Player's startship in the game environment.
 */

;(function( FooFighter ){

'use strict';

function Player ( gameState, group ) {
    this.gameState = gameState;
    this.config = {};
    this.sprite = {};
    this.movementVelocity = 300;
    this.displayStates = {
        neutral: 'player.png',
        left: 'playerLeft.png',
        right: 'playerRight.png'
    };
    this.fireTimer = 250;
    this.canFire = true;
    this.lastFired = new Date().getTime();
    this.group = group;
    this.config.laser = {
        velocity: -500,
        fireTimer: 250
    };
    this.lasers = gameState.groups.lasers;
    this.bindEvents();
}

var proto = Player.prototype;

proto.bindEvents = function(){
    var vent = this.gameState.vent;

    vent.on('create', this.create.bind(this));
    vent.on('update', function(){
        this.movementHandler();
        this.weaponHandler();
    }.bind(this));
    return this;
};

proto.create = function(){
    var game = this.gameState.game;

    // Build the sprite entitiy
    this.sprite = game.add.sprite(
        game.world.centerX, game.world.centerY,
        'sprites', this.displayStates.neutral
    );
    // Anchor in the center of the sprite
    this.sprite.anchor = {
        x: 0.5,
        y: 0.5
    };
    // Add it to the correct display group
    this.group.add(this.sprite);
    this.sprite.events.onKilled.add(this.onKill.bind(this));
    return this;
};

proto.movementHandler = function(){
    var game = this.gameState.game,
        magnitude = this.movementVelocity,
        modifier = 1,
        axis,
        cursors = this.gameState.cursors;

    // Reset any prior velocity vals
    this.sprite.body.velocity.setTo(0, 0);

    // Detect which cursor keys are pressed and modify the sprite
    // display frame texture for X axis directions
    if ( cursors.up.isDown ) {
        modifier = -1;
        axis = 'y';
    } else if ( cursors.down.isDown ) {
        modifier = 1;
        axis = 'y';
    } else if ( cursors.left.isDown ) {
        this.sprite.loadTexture('sprites', this.displayStates.left);
        modifier = -1;
        axis = 'x';
    } else if ( cursors.right.isDown ) {
        this.sprite.loadTexture('sprites', this.displayStates.right);
        modifier = 1;
        axis = 'x';
    } else {
        this.sprite.loadTexture('sprites', this.displayStates.neutral);
    }

    // This is just the movement speed + directional modifier
    this.sprite.body.velocity[axis] = (modifier * magnitude);
    return this;
};

proto.weaponHandler = function(){
    var game = this.gameState.game,
        cursors = this.gameState.cursors,
        keyboard = this.gameState.keyboard,
        currTime = new Date().getTime(),
        lastFired = this.lastFired,
        throttleVal = this.config.laser.fireTimer,
        laser;

    // If we're dead, don't fire a got damn laser
    if ( !this.sprite.alive ) {
        return false;
    }

    // If spacebar is pressed in this loop step, create a laser and
    // make sure we can't fire again for N milliseconds
    if ( keyboard.isDown(Phaser.Keyboard.SPACEBAR) ) {
        if ( currTime - lastFired >= throttleVal ) {
            this.createLaser();
            this.gameState.updateScore(-2);
            this.lastFired = currTime;
        }
    }
    return this;
};

proto.createLaser = function(){
    var game = this.gameState.game,
        velocity = this.config.laser.velocity,
        pos,
        laser;

    pos = {
        x: this.sprite.body.x + this.sprite.body.width/2,
        y:this.sprite.body.y - 10
    };

    laser = this.lasers.getFirstExists(false);

    if ( !laser ) {
        // Create our laser sprite entity
        laser = this.lasers.create(
            pos.x,
            pos.y,
            'sprites', 'laserGreen.png'
        );
        // Anchor to the center of the sprite
        laser.anchor = {
            x: 0.5,
            y: 0.5
        };
        // Set the movement speed
        // Clean up any lasers that leave the game scence
        laser.events.onOutOfBounds.add(laser.kill, laser);
    } else {
        laser.x = pos.x;
        laser.y = pos.y
        laser.revive();
    }

    laser.body.velocity.y = velocity;

    return this;
};

proto.onKill = function(){
    var vent = this.gameState.vent;

    vent.emit('game-over');
};

FooFighter.Player = Player;

})(FooFighter);
<|endoftext|>


<commit_before>/**
 * Player.js
 *
 * Foofighter.js — Player entity
 *
 * This class represents the data model and display entity for a
 * Player's startship in the game environment.
 */

;(function( FooFighter ){

'use strict';

function Player ( gameState, group ) {
    this.gameState = gameState;
    this.config = {};
    this.sprite = {};
    this.movementVelocity = 300;
    this.displayStates = {
        neutral: 'player.png',
        left: 'playerLeft.png',
        right: 'playerRight.png'
    };
    this.fireTimer = 250;
    this.canFire = true;
    this.lastFired = new Date().getTime();
    this.group = group;
    this.config.laser = {
        velocity: -500,
        fireTimer: 250
    };
    this.lasers = gameState.groups.lasers;
    this.bindEvents();
}

var proto = Player.prototype;

proto.bindEvents = function(){
    var vent = this.gameState.vent;

    vent.on('create', this.create.bind(this));
    vent.on('update', function(){
        this.movementHandler();
        this.weaponHandler();
    }.bind(this));
    return this;
};

proto.create = function(){
    var game = this.gameState.game;

    // Build the sprite entitiy
    this.sprite = game.add.sprite(
        game.world.centerX, game.world.centerY,
        'sprites', this.displayStates.neutral
    );
    // Anchor in the center of the sprite
    this.sprite.anchor = {
        x: 0.5,
        y: 0.5
    };
    // Add it to the correct display group
    this.group.add(this.sprite);
    this.sprite.events.onKilled.add(this.onKill.bind(this));
    return this;
};

proto.movementHandler = function(){
    var game = this.gameState.game,
        magnitude = this.movementVelocity,
        modifier = 1,
        axis,
        cursors = this.gameState.cursors;

    // Reset any prior velocity vals
    this.sprite.body.velocity.setTo(0, 0);

    // Detect which cursor keys are pressed and modify the sprite
    // display frame texture for X axis directions
    if ( cursors.up.isDown ) {
        modifier = -1;
        axis = 'y';
    } else if ( cursors.down.isDown ) {
        modifier = 1;
        axis = 'y';
    } else if (cursors.left.isDown) {
        this.sprite.loadTexture('sprites', this.displayStates.left);
        modifier = -1;
        axis = 'x';
    } else if (cursors.right.isDown) {
        this.sprite.loadTexture('sprites', this.displayStates.right);
        modifier = 1;
        axis = 'x';
    } else {
        this.sprite.loadTexture('sprites', this.displayStates.neutral);
    }

    // This is just the movement speed + directional modifier
    this.sprite.body.velocity[axis] = (modifier * magnitude);
    return this;
};

proto.weaponHandler = function(){
    var game = this.gameState.game,
        cursors = this.gameState.cursors,
        keyboard = this.gameState.keyboard,
        currTime = new Date().getTime(),
        lastFired = this.lastFired,
        throttleVal = this.config.laser.fireTimer,
        laser;

    // If we're dead, don't fire a got damn laser
    if ( !this.sprite.alive ) {
        return false;
    }

    // If spacebar is pressed in this loop step, create a laser and
    // make sure we can't fire again for N milliseconds
    if ( keyboard.isDown(Phaser.Keyboard.SPACEBAR) ) {
        if ( currTime - lastFired >= throttleVal ) {
            this.createLaser();
            this.gameState.updateScore(-2);
            this.lastFired = currTime;
        }
    }
    return this;
};

proto.createLaser = function(){
    var game = this.gameState.game,
        velocity = this.config.laser.velocity,
        laser;

    // Create our laser sprite entity
    laser = game.add.sprite(
        this.sprite.body.x + this.sprite.body.width/2,
        this.sprite.body.y - 10,
        'sprites', 'laserGreen.png'
    );
    // Keep track of all our onscreen lasers (for collision detection)
    this.lasers.add(laser);
    // Anchor to the center of the sprite
    laser.anchor = {
        x: 0.5,
        y: 0.5
    };
    // Set the movement speed
    laser.body.velocity.y = velocity;
    // Clean up any lasers that leave the game scence
    laser.events.onOutOfBounds.add(laser.kill, laser);
    return this;
};

proto.onKill = function(){
    var vent = this.gameState.vent;

    vent.emit('game-over');
};

FooFighter.Player = Player;

})(FooFighter);
<commit_msg>idiomatic change<commit_after>/**
 * Player.js
 *
 * Foofighter.js — Player entity
 *
 * This class represents the data model and display entity for a
 * Player's startship in the game environment.
 */

;(function( FooFighter ){

'use strict';

function Player ( gameState, group ) {
    this.gameState = gameState;
    this.config = {};
    this.sprite = {};
    this.movementVelocity = 300;
    this.displayStates = {
        neutral: 'player.png',
        left: 'playerLeft.png',
        right: 'playerRight.png'
    };
    this.fireTimer = 250;
    this.canFire = true;
    this.lastFired = new Date().getTime();
    this.group = group;
    this.config.laser = {
        velocity: -500,
        fireTimer: 250
    };
    this.lasers = gameState.groups.lasers;
    this.bindEvents();
}

var proto = Player.prototype;

proto.bindEvents = function(){
    var vent = this.gameState.vent;

    vent.on('create', this.create.bind(this));
    vent.on('update', function(){
        this.movementHandler();
        this.weaponHandler();
    }.bind(this));
    return this;
};

proto.create = function(){
    var game = this.gameState.game;

    // Build the sprite entitiy
    this.sprite = game.add.sprite(
        game.world.centerX, game.world.centerY,
        'sprites', this.displayStates.neutral
    );
    // Anchor in the center of the sprite
    this.sprite.anchor = {
        x: 0.5,
        y: 0.5
    };
    // Add it to the correct display group
    this.group.add(this.sprite);
    this.sprite.events.onKilled.add(this.onKill.bind(this));
    return this;
};

proto.movementHandler = function(){
    var game = this.gameState.game,
        magnitude = this.movementVelocity,
        modifier = 1,
        axis,
        cursors = this.gameState.cursors;

    // Reset any prior velocity vals
    this.sprite.body.velocity.setTo(0, 0);

    // Detect which cursor keys are pressed and modify the sprite
    // display frame texture for X axis directions
    if ( cursors.up.isDown ) {
        modifier = -1;
        axis = 'y';
    } else if ( cursors.down.isDown ) {
        modifier = 1;
        axis = 'y';
    } else if ( cursors.left.isDown ) {
        this.sprite.loadTexture('sprites', this.displayStates.left);
        modifier = -1;
        axis = 'x';
    } else if ( cursors.right.isDown ) {
        this.sprite.loadTexture('sprites', this.displayStates.right);
        modifier = 1;
        axis = 'x';
    } else {
        this.sprite.loadTexture('sprites', this.displayStates.neutral);
    }

    // This is just the movement speed + directional modifier
    this.sprite.body.velocity[axis] = (modifier * magnitude);
    return this;
};

proto.weaponHandler = function(){
    var game = this.gameState.game,
        cursors = this.gameState.cursors,
        keyboard = this.gameState.keyboard,
        currTime = new Date().getTime(),
        lastFired = this.lastFired,
        throttleVal = this.config.laser.fireTimer,
        laser;

    // If we're dead, don't fire a got damn laser
    if ( !this.sprite.alive ) {
        return false;
    }

    // If spacebar is pressed in this loop step, create a laser and
    // make sure we can't fire again for N milliseconds
    if ( keyboard.isDown(Phaser.Keyboard.SPACEBAR) ) {
        if ( currTime - lastFired >= throttleVal ) {
            this.createLaser();
            this.gameState.updateScore(-2);
            this.lastFired = currTime;
        }
    }
    return this;
};

proto.createLaser = function(){
    var game = this.gameState.game,
        velocity = this.config.laser.velocity,
        laser;

    // Create our laser sprite entity
    laser = game.add.sprite(
        this.sprite.body.x + this.sprite.body.width/2,
        this.sprite.body.y - 10,
        'sprites', 'laserGreen.png'
    );
    // Keep track of all our onscreen lasers (for collision detection)
    this.lasers.add(laser);
    // Anchor to the center of the sprite
    laser.anchor = {
        x: 0.5,
        y: 0.5
    };
    // Set the movement speed
    laser.body.velocity.y = velocity;
    // Clean up any lasers that leave the game scence
    laser.events.onOutOfBounds.add(laser.kill, laser);
    return this;
};

proto.onKill = function(){
    var vent = this.gameState.vent;

    vent.emit('game-over');
};

FooFighter.Player = Player;

})(FooFighter);
<|endoftext|>


<commit_before>"use strict";

var axisUp = new THREE.Vector3(0, 1, 0),
    PI_2 = Math.PI / 2;

var Player = function Player (camera, input, pointer) {
    this.height = 100;
    this.width = 100;
    this.jumpCount = 0;
    this.jumpStrength = 5;
    this.currentJumpStrength = 0;

    this.position = new THREE.Vector3(0, 0, 0);
    this.movement = new THREE.Vector3(0, 0, 0);

    this.actionCommand = input.commands.action;
    this.leftCommand = input.commands.left;
    this.rightCommand = input.commands.right;
    this.upCommand = input.commands.up;
    this.downCommand = input.commands.down;
    this.viewZCommand = input.commands.viewZ;
    this.viewXCommand = input.commands.viewX;
    this.viewYMinusCommand = input.commands.viewYPlus;
    this.viewYPlusCommand = input.commands.viewYMinus;

    this.pointer = pointer;
    this.camera = camera;
};

Player.prototype.update = function (dt, gravity, checkCollision) {
    //MOVEMENTS
    this.movement.x = this.leftCommand.active ? this.leftCommand.value : -this.rightCommand.value;
    this.movement.z = this.upCommand.active ? this.upCommand.value : -this.downCommand.value;
    this.movement.y = 0;

    if (this.movement.x || this.movement.z) {
        // TODO the theta and phi should be calculated on the player entity and then passed to the camera
        this.movement.normalize();
        this.movement.applyAxisAngle(axisUp, -this.camera.theta + PI_2);
    }

    if (this.viewYPlusCommand.active) {
        this.movement.y = this.viewYPlusCommand.value * 2.5;
    } else {
        this.movement.y = -this.viewYMinusCommand.value * 2;
    }

    if (this.actionCommand.down && this.jumpCount === 0) {
        this.currentJumpStrength = this.jumpStrength;
        this.jumpCount++;
    }

    if (this.currentJumpStrength > 0.001) {
        this.movement.y += this.currentJumpStrength;
        this.currentJumpStrength *= 0.9;
    } else {
        this.currentJumpStrength = 0;
    }

    this.movement.add(gravity);
    this.movement.multiplyScalar(dt);

    this.camera.setMousePosition(
        this.pointer.movementX + Math.sign(this.viewXCommand.value) * Math.pow(this.viewXCommand.value, 2) * 25,
        this.pointer.movementY + Math.sign(this.viewZCommand.value) * Math.pow(this.viewZCommand.value, 2) * 25,
        dt
    );

    this.position.z = this.position.z + this.movement.z;
    this.position.x = this.position.x + this.movement.x;
    this.position.y = this.position.y + this.movement.y;

    checkCollision(this);

    this.camera.position.z = this.position.z;
    this.camera.position.x = this.position.x;
    this.camera.position.y = this.position.y;

    this.camera.position.y+= this.height * 0.25;
};

module.exports = Player;

<commit_msg>player: remove useless code<commit_after>"use strict";

var axisUp = new THREE.Vector3(0, 1, 0),
    PI_2 = Math.PI / 2;

var Player = function Player (camera, input, pointer) {
    this.height = 100;
    this.width = 100;
    this.jumpCount = 0;
    this.jumpStrength = 5;
    this.currentJumpStrength = 0;

    this.position = new THREE.Vector3(0, 0, 0);
    this.movement = new THREE.Vector3(0, 0, 0);

    this.actionCommand = input.commands.action;
    this.leftCommand = input.commands.left;
    this.rightCommand = input.commands.right;
    this.upCommand = input.commands.up;
    this.downCommand = input.commands.down;
    this.viewZCommand = input.commands.viewZ;
    this.viewXCommand = input.commands.viewX;
    this.viewYMinusCommand = input.commands.viewYPlus;
    this.viewYPlusCommand = input.commands.viewYMinus;

    this.pointer = pointer;
    this.camera = camera;
};

Player.prototype.update = function (dt, gravity, checkCollision) {
    //MOVEMENTS
    this.movement.x = this.leftCommand.active ? this.leftCommand.value : -this.rightCommand.value;
    this.movement.z = this.upCommand.active ? this.upCommand.value : -this.downCommand.value;
    this.movement.y = 0;

    if (this.movement.x || this.movement.z) {
        // TODO the theta and phi should be calculated on the player entity and then passed to the camera
        this.movement.normalize();
        this.movement.applyAxisAngle(axisUp, -this.camera.theta + PI_2);
    }

    if (this.viewYPlusCommand.active) {
        this.movement.y = this.viewYPlusCommand.value * 2.5;
    }

    if (this.actionCommand.down && this.jumpCount === 0) {
        this.currentJumpStrength = this.jumpStrength;
        this.jumpCount++;
    }

    if (this.currentJumpStrength > 0.001) {
        this.movement.y += this.currentJumpStrength;
        this.currentJumpStrength *= 0.9;
    } else {
        this.currentJumpStrength = 0;
    }

    this.movement.add(gravity);
    this.movement.multiplyScalar(dt);

    this.camera.setMousePosition(
        this.pointer.movementX + Math.sign(this.viewXCommand.value) * Math.pow(this.viewXCommand.value, 2) * 25,
        this.pointer.movementY + Math.sign(this.viewZCommand.value) * Math.pow(this.viewZCommand.value, 2) * 25,
        dt
    );

    this.position.z = this.position.z + this.movement.z;
    this.position.x = this.position.x + this.movement.x;
    this.position.y = this.position.y + this.movement.y;

    checkCollision(this);

    this.camera.position.z = this.position.z;
    this.camera.position.x = this.position.x;
    this.camera.position.y = this.position.y;

    this.camera.position.y+= this.height * 0.25;
};

module.exports = Player;

<|endoftext|>


<commit_before>Components.utils.import("resource://gre/modules/Services.jsm");

var EXPORTED_SYMBOLS = ["ScreenUtils"];

var ScreenUtils = {

  mScreenManager: null,

  alignPanelsForWindow: function(aWindow)
  {
    var doc = aWindow.document;

    var x = aWindow.screenX;
    var y = aWindow.screenY;
    var w = aWindow.outerWidth;
    var h = aWindow.outerHeight;

    var panels = doc.querySelectorAll('panel[floating="true"][open="true"]');

    // edge case, we have only one monitor and the window uses
    // the whole screen width ; move panels to the right
    if (this.screenManager.numberOfScreens == 1
        && w == aWindow.screen.availWidth) {
      for (var i = 0; i < panels.length; i++) {
        var p = panels[i];
        p.sizeTo(panels[0].boxObject.width, h / panels.length - 5);
        p.moveTo(w - p.boxObject.width, y + (h * i / panels.length));
      }
      return;
    }

    // first order the panels
    var leftPanels  = [];
    var rightPanels = [];
    for (var i = 0; i < panels.length; i++) {
      var p = panels[i];
      if (p.boxObject.screenX < x && p.boxObject.width <= x)
        leftPanels.push({
                         panel: p,
                         x: p.boxObject.screenX,
                         w: p.boxObject.width
                       });
      else
        rightPanels.push({
                         panel: p,
                         x: p.boxObject.screenX,
                         w: p.boxObject.width
                       });
    }

    // ********* RIGHT PANELS *********
    // sort the right panels by x order
    function compareRightPanels(a, b) {
      if (a.x < b.x)
        return -1;
      if (a.x > b.x)
        return +1;
      return 0;
    }
    rightPanels.sort(compareRightPanels);

    // aggregate the right panels
    var originX = x + w + 5;
    for (var i = 0; i < rightPanels.length; i++) {
      if (0 < i &&
          rightPanels[i].x >= rightPanels[i-1].x &&
          rightPanels[i].x <= rightPanels[i-1].x + rightPanels[i-1].w) {
        rightPanels[i].newx = rightPanels[i-1].newx;
        rightPanels[i].source = rightPanels[i-1].source;
        rightPanels[i].weight = rightPanels[i-1].weight + 1;
        rightPanels[rightPanels[i-1].source].flex++;
        rightPanels[rightPanels[i].source].maxWidth = Math.max(rightPanels[i].w, rightPanels[rightPanels[i].source].maxWidth);
      }
      else {
        if (0 < i)
          originX += rightPanels[rightPanels[i-1].source].maxWidth + 5;
        rightPanels[i].source = i;
        rightPanels[i].weight = 1;
        rightPanels[i].flex = 1;
        rightPanels[i].maxWidth = rightPanels[i].w;
        rightPanels[i].newx = originX;
      }
    }
    for (var i = 0; i < rightPanels.length; i++) {
      rightPanels[i].h = h / rightPanels[rightPanels[i].source].flex;
      rightPanels[i].y = y + rightPanels[i].h * (rightPanels[i].weight - 1);

      rightPanels[i].panel.sizeTo(rightPanels[rightPanels[i].source].maxWidth, rightPanels[i].h - 5);
    }

    // we need to reposition using a timeout because the sizeTo are still flushing
    function postRightAlignment()
    {
      var delta = 0;
      for (var i = 0; i < rightPanels.length; i++) {
        delta += ScreenUtils.CheckAvailableSpace(rightPanels[rightPanels[i].source].newx,
                                                 rightPanels[rightPanels[i].source].maxWidth);
        rightPanels[i].panel.moveTo(rightPanels[rightPanels[i].source].newx + delta, rightPanels[i].y);
      }
    }
    var timer = Components.classes["@mozilla.org/timer;1"]
                          .createInstance(Components.interfaces.nsITimer);
    timer.initWithCallback(postRightAlignment, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);

    // ********* LEFT PANELS *********
    // sort the left panels by decreasing x order
    function compareLeftPanels(a, b) {
      if (a.x < b.x)
        return +1;
      if (a.x > b.x)
        return -1;
      return 0;
    }
    leftPanels.sort(compareLeftPanels);

    // aggregate the left panels
    var originX = x - 5;
    for (var i = 0; i < leftPanels.length; i++) {
      if (0 < i &&
          leftPanels[i-1].x >= leftPanels[i].x &&
          leftPanels[i-1].x <= leftPanels[i].x + leftPanels[i].w) {
        leftPanels[i].newx = leftPanels[i-1].newx;
        leftPanels[i].source = leftPanels[i-1].source;
        leftPanels[i].weight = leftPanels[i-1].weight + 1;
        leftPanels[leftPanels[i-1].source].flex++;
        leftPanels[leftPanels[i].source].maxWidth = Math.max(leftPanels[i].w, leftPanels[leftPanels[i].source].maxWidth);
      }
      else {
        if (0 < i)
          originX -= leftPanels[leftPanels[i-1].source].maxWidth + 5;
        leftPanels[i].source = i;
        leftPanels[i].weight = 1;
        leftPanels[i].flex = 1;
        leftPanels[i].maxWidth = leftPanels[i].w;
        leftPanels[i].newx = originX;
      }
    }
    for (var i = 0; i < leftPanels.length; i++) {
      leftPanels[i].h = h / leftPanels[leftPanels[i].source].flex;
      leftPanels[i].y = y + leftPanels[i].h * (leftPanels[i].weight - 1);

      leftPanels[i].panel.sizeTo(leftPanels[leftPanels[i].source].maxWidth, leftPanels[i].h - 5);
    }

    // we need to reposition using a timeout because the sizeTo are still flushing
    function postLeftAlignment()
    {
      var delta = 0;
      for (var i = 0; i < leftPanels.length; i++) {
        delta += ScreenUtils.CheckAvailableSpace(leftPanels[leftPanels[i].source].newx,
                                                 leftPanels[leftPanels[i].source].maxWidth,
                                                 true);
        leftPanels[i].panel.moveTo(leftPanels[leftPanels[i].source].newx - delta - leftPanels[leftPanels[i].source].maxWidth,
                                   leftPanels[i].y);
      }
    }
    var timer = Components.classes["@mozilla.org/timer;1"]
                          .createInstance(Components.interfaces.nsITimer);
    timer.initWithCallback(postLeftAlignment, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
  },

  CheckAvailableSpace: function(x, w, aAtBeginningOfScreen)
  {
    var screens = this.screens;
    for (var i = 0 ; i < screens.length; i++) {
      var s = screens[i];
      if (x >= s.min
          && x < s.max) {
        if (!aAtBeginningOfScreen && s.max - x < w)
          return s.max - x;
        if (aAtBeginningOfScreen && w > x - s.min)
          return x - s.min;
      }
    }
    return 0;
  },

  get screenManager()
  {
    if (this.mScreenManager)
      return this.mScreenManager;

    this.mScreenManager = Components.classes["@mozilla.org/gfx/screenmanager;1"]
                            .getService(Components.interfaces.nsIScreenManager);
    return this.mScreenManager;
  },

  get numberOfScreens() {
    return this.mScreenManager.numberOfScreens;
  },

  get screens()
  {
    var screens = [];
    var min = 0;
    var screenManager = this.screenManager;
    var numberOfScreens = screenManager.numberOfScreens;
    for (var i = 0; i < numberOfScreens; i++) {
      var screen = screenManager.screenForIndex(i);
      var left = {}, top = {}, width = {}, height = {};
      screen.GetRectDisplayPix(left, top, width, height);
      screens.push( { width: width.value,
                      height: height.value,
                      min: left.value,
                      max: (left.value + width.value),
                      factor: screen.contentsScaleFactor,
                      id: screen.id} );
    }
    screens.sort(function(a,b) {
      if (a.min < b.min)
        return -1;
      if (a.min > b.min)
        return 1;
      return 0;
    });
    var realMin = 0;
    for (var i = 0; i < screens.length; i++) {
      var s = screens[i];
      s.realMin = realMin;
      realMin += s.width * s.factor;
      s.realMax = realMin;
    }
    screens.sort(function(a,b) {
      if (a.id < b.id)
        return -1;
      if (a.id > b.id)
        return 1;
      return 0;
    });
    return screens;
  },

  get availableWidth()
  {
    var screens = this.screens;
    var w = 0;
    for (var i = 0; i < screens.length; i++)
      s += screens[i].width;
    return s;
  }
};
<commit_msg>better screen detection<commit_after>Components.utils.import("resource://gre/modules/Services.jsm");

var EXPORTED_SYMBOLS = ["ScreenUtils"];

var ScreenUtils = {

  mScreenManager: null,

  alignPanelsForWindow: function(aWindow)
  {
    var doc = aWindow.document;

    var x = aWindow.screenX;
    var y = aWindow.screenY;
    var w = aWindow.outerWidth;
    var h = aWindow.outerHeight;

    var panels = doc.querySelectorAll('panel[floating="true"][open="true"]');

    // edge case, we have only one monitor and the window uses
    // the whole screen width ; move panels to the right
    if (this.screenManager.numberOfScreens == 1
        && w == aWindow.screen.availWidth) {
      for (var i = 0; i < panels.length; i++) {
        var p = panels[i];
        p.sizeTo(panels[0].boxObject.width, h / panels.length - 5);
        p.moveTo(w - p.boxObject.width, y + (h * i / panels.length));
      }
      return;
    }

    // first order the panels
    var leftPanels  = [];
    var rightPanels = [];
    for (var i = 0; i < panels.length; i++) {
      var p = panels[i];
      if (p.boxObject.screenX < x && p.boxObject.width <= x)
        leftPanels.push({
                         panel: p,
                         x: p.boxObject.screenX,
                         w: p.boxObject.width
                       });
      else
        rightPanels.push({
                         panel: p,
                         x: p.boxObject.screenX,
                         w: p.boxObject.width
                       });
    }

    // ********* RIGHT PANELS *********
    // sort the right panels by x order
    function compareRightPanels(a, b) {
      if (a.x < b.x)
        return -1;
      if (a.x > b.x)
        return +1;
      return 0;
    }
    rightPanels.sort(compareRightPanels);

    // aggregate the right panels
    var originX = x + w + 5;
    for (var i = 0; i < rightPanels.length; i++) {
      if (0 < i &&
          rightPanels[i].x >= rightPanels[i-1].x &&
          rightPanels[i].x <= rightPanels[i-1].x + rightPanels[i-1].w) {
        rightPanels[i].newx = rightPanels[i-1].newx;
        rightPanels[i].source = rightPanels[i-1].source;
        rightPanels[i].weight = rightPanels[i-1].weight + 1;
        rightPanels[rightPanels[i-1].source].flex++;
        rightPanels[rightPanels[i].source].maxWidth = Math.max(rightPanels[i].w, rightPanels[rightPanels[i].source].maxWidth);
      }
      else {
        if (0 < i)
          originX += rightPanels[rightPanels[i-1].source].maxWidth + 5;
        rightPanels[i].source = i;
        rightPanels[i].weight = 1;
        rightPanels[i].flex = 1;
        rightPanels[i].maxWidth = rightPanels[i].w;
        rightPanels[i].newx = originX;
      }
    }
    for (var i = 0; i < rightPanels.length; i++) {
      rightPanels[i].h = h / rightPanels[rightPanels[i].source].flex;
      rightPanels[i].y = y + rightPanels[i].h * (rightPanels[i].weight - 1);

      rightPanels[i].panel.sizeTo(rightPanels[rightPanels[i].source].maxWidth, rightPanels[i].h - 5);
    }

    // we need to reposition using a timeout because the sizeTo are still flushing
    function postRightAlignment()
    {
      var delta = 0;
      for (var i = 0; i < rightPanels.length; i++) {
        delta += ScreenUtils.CheckAvailableSpace(rightPanels[rightPanels[i].source].newx,
                                                 rightPanels[rightPanels[i].source].maxWidth);
        rightPanels[i].panel.moveTo(rightPanels[rightPanels[i].source].newx + delta, rightPanels[i].y);
      }
    }
    var timer = Components.classes["@mozilla.org/timer;1"]
                          .createInstance(Components.interfaces.nsITimer);
    timer.initWithCallback(postRightAlignment, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);

    // ********* LEFT PANELS *********
    // sort the left panels by decreasing x order
    function compareLeftPanels(a, b) {
      if (a.x < b.x)
        return +1;
      if (a.x > b.x)
        return -1;
      return 0;
    }
    leftPanels.sort(compareLeftPanels);

    // aggregate the left panels
    var originX = x - 5;
    for (var i = 0; i < leftPanels.length; i++) {
      if (0 < i &&
          leftPanels[i-1].x >= leftPanels[i].x &&
          leftPanels[i-1].x <= leftPanels[i].x + leftPanels[i].w) {
        leftPanels[i].newx = leftPanels[i-1].newx;
        leftPanels[i].source = leftPanels[i-1].source;
        leftPanels[i].weight = leftPanels[i-1].weight + 1;
        leftPanels[leftPanels[i-1].source].flex++;
        leftPanels[leftPanels[i].source].maxWidth = Math.max(leftPanels[i].w, leftPanels[leftPanels[i].source].maxWidth);
      }
      else {
        if (0 < i)
          originX -= leftPanels[leftPanels[i-1].source].maxWidth + 5;
        leftPanels[i].source = i;
        leftPanels[i].weight = 1;
        leftPanels[i].flex = 1;
        leftPanels[i].maxWidth = leftPanels[i].w;
        leftPanels[i].newx = originX;
      }
    }
    for (var i = 0; i < leftPanels.length; i++) {
      leftPanels[i].h = h / leftPanels[leftPanels[i].source].flex;
      leftPanels[i].y = y + leftPanels[i].h * (leftPanels[i].weight - 1);

      leftPanels[i].panel.sizeTo(leftPanels[leftPanels[i].source].maxWidth, leftPanels[i].h - 5);
    }

    // we need to reposition using a timeout because the sizeTo are still flushing
    function postLeftAlignment()
    {
      var delta = 0;
      for (var i = 0; i < leftPanels.length; i++) {
        delta += ScreenUtils.CheckAvailableSpace(leftPanels[leftPanels[i].source].newx,
                                                 leftPanels[leftPanels[i].source].maxWidth,
                                                 true);
        leftPanels[i].panel.moveTo(leftPanels[leftPanels[i].source].newx - delta - leftPanels[leftPanels[i].source].maxWidth,
                                   leftPanels[i].y);
      }
    }
    var timer = Components.classes["@mozilla.org/timer;1"]
                          .createInstance(Components.interfaces.nsITimer);
    timer.initWithCallback(postLeftAlignment, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
  },

  CheckAvailableSpace: function(x, w, aAtBeginningOfScreen)
  {
    var screens = this.screens;
    for (var i = 0 ; i < screens.length; i++) {
      var s = screens[i];
      if (x >= s.min
          && x < s.max) {
        if (!aAtBeginningOfScreen && s.max - x < w)
          return s.max - x;
        if (aAtBeginningOfScreen && w > x - s.min)
          return x - s.min;
      }
    }
    return 0;
  },

  get screenManager()
  {
    if (this.mScreenManager)
      return this.mScreenManager;

    this.mScreenManager = Components.classes["@mozilla.org/gfx/screenmanager;1"]
                            .getService(Components.interfaces.nsIScreenManager);
    return this.mScreenManager;
  },

  get numberOfScreens() {
    return this.mScreenManager.numberOfScreens;
  },

  get screens()
  {
    var screens = [];
    var min = 0;
    var screenManager = this.screenManager;
    var numberOfScreens = screenManager.numberOfScreens;
    for (var i = 0; i < numberOfScreens; i++) {
      var screen = screenManager.screenForIndex(i);
      var left = {}, top = {}, width = {}, height = {};
      screen.GetRectDisplayPix(left, top, width, height);
      screens.push( { width: width.value,
                      height: height.value,
                      min: left.value,
                      max: (left.value + width.value),
                      factor: screen.contentsScaleFactor,
                      id: screen.id} );
    }
    screens.sort(function(a,b) {
      if (a.min < b.min)
        return -1;
      if (a.min > b.min)
        return 1;
      return 0;
    });
    var realMin = 0;
    for (var i = 0; i < screens.length; i++) {
      var s = screens[i];
      s.realMin = realMin;
      realMin += s.width;
      s.realMax = realMin;
    }
    screens.sort(function(a,b) {
      if (a.id < b.id)
        return -1;
      if (a.id > b.id)
        return 1;
      return 0;
    });
    return screens;
  },

  get availableWidth()
  {
    var screens = this.screens;
    var w = 0;
    for (var i = 0; i < screens.length; i++)
      s += screens[i].width;
    return s;
  }
};
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from "prop-types"
import classnames from 'classnames';
import fuzzysearch from 'fuzzysearch';

export default class FuzzyPicker extends React.Component {
  constructor(props) {
    super();
    this.state = {
      selectedIndex: 0, // which item is selected?
      items: this.getInitialItems(props), // the items wich are displayed in the fuzzy find list
    };
  }

  // Move the selected index up or down.
  onMoveUp() {
    if (this.state.selectedIndex > 0) {
      this.selectIndex(--this.state.selectedIndex);

    // User is at the start of the list. Should we cycle back to the end again?
    } else if (this.props.cycleAtEndsOfList) {
      this.selectIndex(this.state.items.length-1);
    }
  }
  onMoveDown() {
    let itemsLength = this.state.items.length - 1;
    if (this.state.selectedIndex < itemsLength) {
      this.selectIndex(++this.state.selectedIndex);

    // User is at the end of the list. Should we cycle back to the start again?
    } else if (this.props.cycleAtEndsOfList) {
      this.selectIndex(0);
    }
  }

  // handle key events in the textbox
  onKeyDown(event) {
    switch (event.key) {
      // Moving up and down
      // Either arrow keys, tab/shift+tab, or ctrl+j/ctrl+k (what's used in vim sometimes)
      case 'ArrowUp': {
        this.onMoveUp();
        event.preventDefault();
        break;
      }
      case 'ArrowDown': {
        this.onMoveDown();
        event.preventDefault();
        break;
      }
      case 'j': {
        if (event.ctrlKey) {
          this.onMoveDown();
        }
        break;
      }
      case 'k': {
        if (event.ctrlKey) {
          this.onMoveUp();
        }
        break;
      }
      case 'Tab': {
        if (event.shiftKey) {
          this.onMoveUp();
        } else {
          this.onMoveDown();
        }
        event.preventDefault();
        break;
      }

      case 'Enter': { // Enter key
        let item = this.state.items[this.state.selectedIndex];
        if (item) {
          this.setState({items: this.getInitialItems(this.props)});
          this.props.onChange(item);
          if (this.props.autoCloseOnEnter) {
            this.props.onClose();
          }
        }
        break;
      }
      case 'Escape': {
        this.setState({items: this.getInitialItems(this.props)});
        this.props.onClose();
      }
    }
  }

  // Get the list of initial items.
  // Defaults to none, but the 'showAllItems' property can be enabled
  // to show all items by default.
  getInitialItems(props) {
    if (props.showAllItems) {
      return props.items;
    }
    else {
      return [];
    }
  }

  // When the user types into the textbox, this handler is called.
  // Though the textbox is an uncontrolled input, this is needed to regenerate the
  // list of choices under the textbox.
  onInputChanged({target: {value}}) {
    if (value.length) {
      // Pick the closest matching items if possible.
      let items = this.props.items.filter(item => fuzzysearch(
        value.toLowerCase(),
        this.props.itemValue(item).toLowerCase()
      ));
      this.setState({items: items.slice(0, this.props.displayCount), selectedIndex: 0});
    } else {
      // initially, show an empty picker or all items.
      this.setState({items: this.getInitialItems(this.props), selectedIndex: 0});
    }
  }

  // Highlight the given item
  selectIndex(ct) {
    this.props.onChangeHighlightedItem(this.state.items[ct]); // fire a callback
    this.setState({selectedIndex: ct}); // update the state for real
  }

  onClickOnBg(event) {
    if (event.target.className === 'fuzzy-switcher-background') {
      this.props.onClose();
    }
  }

  render() {
    if (this.props.isOpen) {
      return

              {this.props.label}

              tab or ↑↓ to navigate
              tab or ?? to navigate
              enter to select
              esc to dismiss

          <input
            type="text"
            className="fuzzy-input"
            autoFocus
            onKeyDown={this.onKeyDown.bind(this)}
            onChange={this.onInputChanged.bind(this)}
          />

            {this.state.items.map((item, ct) => {
              // render each item
              return
{this.props.renderItem(item)}
;
            })}

;
    } else {
      return null;
    }
  }
}
FuzzyPicker.propTypes = {
  items: PropTypes.arrayOf(PropTypes.any).isRequired,
  showAllItems: PropTypes.bool,
  label: PropTypes.string,
  displayCount: PropTypes.number,
  cycleAtEndsOfList: PropTypes.bool,
  onChangeHighlightedItem: PropTypes.func,
  onChange: PropTypes.func,
  onClose: PropTypes.func,
  autoCloseOnEnter: PropTypes.bool,

  renderItem: PropTypes.func,
  itemValue: PropTypes.func,
};
FuzzyPicker.defaultProps = {
  showAllItems: false,
  label: 'Search', // The text above the searchbox that describes what's happening
  displayCount: 5, // How many items to display at once
  cycleAtEndsOfList: true, // When a user arrows past the end of the list, should the highlight wrap?
  onChangeHighlightedItem(item) {}, // Called when the user highlights a new item
  onChange(item) {}, // Called when an item is selected
  onClose() {}, // Called when the popup is closed
  autoCloseOnEnter: false,

  // By default, the item as its value (ie, each item is a string.)
  renderItem(item) { return item; },
  itemValue(item) { return item; },
};
<commit_msg>Removed redundant help text.<commit_after>import React from 'react';
import PropTypes from "prop-types"
import classnames from 'classnames';
import fuzzysearch from 'fuzzysearch';

export default class FuzzyPicker extends React.Component {
  constructor(props) {
    super();
    this.state = {
      selectedIndex: 0, // which item is selected?
      items: this.getInitialItems(props), // the items wich are displayed in the fuzzy find list
    };
  }

  // Move the selected index up or down.
  onMoveUp() {
    if (this.state.selectedIndex > 0) {
      this.selectIndex(--this.state.selectedIndex);

    // User is at the start of the list. Should we cycle back to the end again?
    } else if (this.props.cycleAtEndsOfList) {
      this.selectIndex(this.state.items.length-1);
    }
  }
  onMoveDown() {
    let itemsLength = this.state.items.length - 1;
    if (this.state.selectedIndex < itemsLength) {
      this.selectIndex(++this.state.selectedIndex);

    // User is at the end of the list. Should we cycle back to the start again?
    } else if (this.props.cycleAtEndsOfList) {
      this.selectIndex(0);
    }
  }

  // handle key events in the textbox
  onKeyDown(event) {
    switch (event.key) {
      // Moving up and down
      // Either arrow keys, tab/shift+tab, or ctrl+j/ctrl+k (what's used in vim sometimes)
      case 'ArrowUp': {
        this.onMoveUp();
        event.preventDefault();
        break;
      }
      case 'ArrowDown': {
        this.onMoveDown();
        event.preventDefault();
        break;
      }
      case 'j': {
        if (event.ctrlKey) {
          this.onMoveDown();
        }
        break;
      }
      case 'k': {
        if (event.ctrlKey) {
          this.onMoveUp();
        }
        break;
      }
      case 'Tab': {
        if (event.shiftKey) {
          this.onMoveUp();
        } else {
          this.onMoveDown();
        }
        event.preventDefault();
        break;
      }

      case 'Enter': { // Enter key
        let item = this.state.items[this.state.selectedIndex];
        if (item) {
          this.setState({items: this.getInitialItems(this.props)});
          this.props.onChange(item);
          if (this.props.autoCloseOnEnter) {
            this.props.onClose();
          }
        }
        break;
      }
      case 'Escape': {
        this.setState({items: this.getInitialItems(this.props)});
        this.props.onClose();
      }
    }
  }

  // Get the list of initial items.
  // Defaults to none, but the 'showAllItems' property can be enabled
  // to show all items by default.
  getInitialItems(props) {
    if (props.showAllItems) {
      return props.items;
    }
    else {
      return [];
    }
  }

  // When the user types into the textbox, this handler is called.
  // Though the textbox is an uncontrolled input, this is needed to regenerate the
  // list of choices under the textbox.
  onInputChanged({target: {value}}) {
    if (value.length) {
      // Pick the closest matching items if possible.
      let items = this.props.items.filter(item => fuzzysearch(
        value.toLowerCase(),
        this.props.itemValue(item).toLowerCase()
      ));
      this.setState({items: items.slice(0, this.props.displayCount), selectedIndex: 0});
    } else {
      // initially, show an empty picker or all items.
      this.setState({items: this.getInitialItems(this.props), selectedIndex: 0});
    }
  }

  // Highlight the given item
  selectIndex(ct) {
    this.props.onChangeHighlightedItem(this.state.items[ct]); // fire a callback
    this.setState({selectedIndex: ct}); // update the state for real
  }

  onClickOnBg(event) {
    if (event.target.className === 'fuzzy-switcher-background') {
      this.props.onClose();
    }
  }

  render() {
    if (this.props.isOpen) {
      return

              {this.props.label}

              tab or ↑↓ to navigate
              enter to select
              esc to dismiss

          <input
            type="text"
            className="fuzzy-input"
            autoFocus
            onKeyDown={this.onKeyDown.bind(this)}
            onChange={this.onInputChanged.bind(this)}
          />

            {this.state.items.map((item, ct) => {
              // render each item
              return
{this.props.renderItem(item)}
;
            })}

;
    } else {
      return null;
    }
  }
}
FuzzyPicker.propTypes = {
  items: PropTypes.arrayOf(PropTypes.any).isRequired,
  showAllItems: PropTypes.bool,
  label: PropTypes.string,
  displayCount: PropTypes.number,
  cycleAtEndsOfList: PropTypes.bool,
  onChangeHighlightedItem: PropTypes.func,
  onChange: PropTypes.func,
  onClose: PropTypes.func,
  autoCloseOnEnter: PropTypes.bool,

  renderItem: PropTypes.func,
  itemValue: PropTypes.func,
};
FuzzyPicker.defaultProps = {
  showAllItems: false,
  label: 'Search', // The text above the searchbox that describes what's happening
  displayCount: 5, // How many items to display at once
  cycleAtEndsOfList: true, // When a user arrows past the end of the list, should the highlight wrap?
  onChangeHighlightedItem(item) {}, // Called when the user highlights a new item
  onChange(item) {}, // Called when an item is selected
  onClose() {}, // Called when the popup is closed
  autoCloseOnEnter: false,

  // By default, the item as its value (ie, each item is a string.)
  renderItem(item) { return item; },
  itemValue(item) { return item; },
};
<|endoftext|>


<commit_before>// @flow

import React, { Component } from 'react';
import styled from 'styled-components';

type Props = {
  history: string[],
  index: number,
  onChangeIndex: (index: number) => any,
};

const isFirst = (index: number): boolean => index === -1;
const isLast = <T>(history: T[], index: number) => index >= history.length;

class History extends Component<Props> {

  goBack = () => {
    const { index, onChangeIndex } = this.props;
    if (isFirst(index)) { return; }
    onChangeIndex(index - 1);
  };

  goForward = () => {
    const { history, index, onChangeIndex } = this.props;
    if (isLast(history, index)) { return; }
    onChangeIndex(index + 1);
  };

  render() {
    const { history, index } = this.props;
    return (

        <Controls>
          <Control
            active={!isFirst(index)}
            onClick={this.goBack}
          >« prev</Control>
          <Control
            active={!isLast(history, index)}
            onClick={this.goForward}
          >next »</Control>
        </Controls>

    );
  }
}

const Controls = styled.div`
  display: flex;
  margin: 20px 0;
`;

type ControlProps = {
  active: boolean,
};

const Control = styled.div`
  margin-right: 10px;
  cursor: ${({ active }: ControlProps) => active ? 'pointer' : 'auto'};
  color: ${({ active }: ControlProps) => active ? '#000' : '#aaa'};
  pointer-events: ${({ active }: ControlProps) => active ? 'auto' : 'none'};
`;

export default History;
<commit_msg>fix end<commit_after>// @flow

import React, { Component } from 'react';
import styled from 'styled-components';

type Props = {
  history: string[],
  index: number,
  onChangeIndex: (index: number) => any,
};

const isFirst = (index: number): boolean => index === -1;
const isLast = <T>(history: T[], index: number) => index >= history.length - 1;

class History extends Component<Props> {

  goBack = () => {
    const { index, onChangeIndex } = this.props;
    if (isFirst(index)) { return; }
    onChangeIndex(index - 1);
  };

  goForward = () => {
    const { history, index, onChangeIndex } = this.props;
    if (isLast(history, index)) { return; }
    onChangeIndex(index + 1);
  };

  render() {
    const { history, index } = this.props;
    return (

        <Controls>
          <Control
            active={!isFirst(index)}
            onClick={this.goBack}
          >« prev</Control>
          <Control
            active={!isLast(history, index)}
            onClick={this.goForward}
          >next »</Control>
        </Controls>

    );
  }
}

const Controls = styled.div`
  display: flex;
  margin: 20px 0;
`;

type ControlProps = {
  active: boolean,
};

const Control = styled.div`
  margin-right: 10px;
  cursor: ${({ active }: ControlProps) => active ? 'pointer' : 'auto'};
  color: ${({ active }: ControlProps) => active ? '#000' : '#aaa'};
  pointer-events: ${({ active }: ControlProps) => active ? 'auto' : 'none'};
`;

export default History;
<|endoftext|>


<commit_before>var app = angular.module('app', ['ui.router', 'ui.bootstrap', 'ui.select2', 'ngAnimate', 'notify', 'ui.utils', 'angularjs-dropdown-multiselect', 'ngSanitize', 'kendo.directives']);

app.config([
    '$urlRouterProvider', function($urlRouterProvider) {
        $urlRouterProvider.otherwise('/');
    }
]);

app.config([
    '$httpProvider', 'notifyProvider', 'datepickerConfig', 'datepickerPopupConfig', function ($httpProvider, notifyProvider, datepickerConfig, datepickerPopupConfig) {
        $httpProvider.interceptors.push("httpBusyInterceptor");
        // for some reason templates aren't updated so this is needed
        $httpProvider.defaults.headers.get = {
            'Cache-Control': 'no-cache'
        };
        notifyProvider.globalTimeToLive(5000);
        notifyProvider.onlyUniqueMessages(false);

        // global config for UI Bootstrap
        datepickerPopupConfig.datepickerPopup = "dd-MM-yyyy"; // set default date format
    }
]);

app.run([
    '$rootScope', '$http', '$state', '$modal', 'notify', 'userService', 'uiSelect2Config',
    function ($rootScope, $http, $state, $modal, notify, userService, uiSelect2Config) {
        //init info
        $rootScope.page = {
            title: 'Index',
            subnav: []
        };

        $rootScope.$state = $state;

        //this will try to authenticate - to see if the user's already logged in
        userService.getUser();

        uiSelect2Config.dropdownAutoWidth = true;

        //logout function for top navigation bar
        $rootScope.logout = function() {
            userService.logout().then(function() {
                $state.go('index');
            });
        };

        //when changing states, we might need to authorize the user
        $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {

            if (toState.noAuth) return; //no need to auth

            userService.auth(toState.adminRoles).then(function(val) {
                //Authentication OK!

            }, function() {
                event.preventDefault();

                //Bad authentication
                $state.go('index', { to: toState.name, toParams: toParams });
            });
        });

        //when something goes wrong during state change (e.g a rejected resolve)
        $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {
            console.log(error);
            $state.go('index');
        });
    }
]);
<commit_msg>Changed calendar starting day to Monday instead Sunday<commit_after>var app = angular.module('app', ['ui.router', 'ui.bootstrap', 'ui.select2', 'ngAnimate', 'notify', 'ui.utils', 'angularjs-dropdown-multiselect', 'ngSanitize', 'kendo.directives']);

app.config([
    '$urlRouterProvider', function($urlRouterProvider) {
        $urlRouterProvider.otherwise('/');
    }
]);

app.config([
    '$httpProvider', 'notifyProvider', 'datepickerConfig', 'datepickerPopupConfig', function ($httpProvider, notifyProvider, datepickerConfig, datepickerPopupConfig) {
        $httpProvider.interceptors.push("httpBusyInterceptor");
        // for some reason templates aren't updated so this is needed
        $httpProvider.defaults.headers.get = {
            'Cache-Control': 'no-cache'
        };
        notifyProvider.globalTimeToLive(5000);
        notifyProvider.onlyUniqueMessages(false);

        // global config for UI Bootstrap
        datepickerConfig.startingDay = 1; // set starting day of the calendar to monday
        datepickerPopupConfig.datepickerPopup = "dd-MM-yyyy"; // set default date format
    }
]);

app.run([
    '$rootScope', '$http', '$state', '$modal', 'notify', 'userService', 'uiSelect2Config',
    function ($rootScope, $http, $state, $modal, notify, userService, uiSelect2Config) {
        //init info
        $rootScope.page = {
            title: 'Index',
            subnav: []
        };

        $rootScope.$state = $state;

        //this will try to authenticate - to see if the user's already logged in
        userService.getUser();

        uiSelect2Config.dropdownAutoWidth = true;

        //logout function for top navigation bar
        $rootScope.logout = function() {
            userService.logout().then(function() {
                $state.go('index');
            });
        };

        //when changing states, we might need to authorize the user
        $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {

            if (toState.noAuth) return; //no need to auth

            userService.auth(toState.adminRoles).then(function(val) {
                //Authentication OK!

            }, function() {
                event.preventDefault();

                //Bad authentication
                $state.go('index', { to: toState.name, toParams: toParams });
            });
        });

        //when something goes wrong during state change (e.g a rejected resolve)
        $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {
            console.log(error);
            $state.go('index');
        });
    }
]);
<|endoftext|>


<commit_before>
openerp.hr_timesheet_sheet = function(instance) {
    var QWeb = instance.web.qweb;
    var _t = instance.web._t;

    instance.hr_timesheet_sheet.WeeklyTimesheet = instance.web.form.FormWidget.extend(instance.web.form.ReinitializeWidgetMixin, {
        events: {
            "click .oe_timesheet_weekly_account a": "go_to",
        },
        init: function() {
            this._super.apply(this, arguments);
            this.set({
                sheets: [],
                date_to: false,
                date_from: false,
            });
            this.field_manager.on("field_changed:timesheet_ids", this, this.query_sheets);
            this.field_manager.on("field_changed:date_from", this, function() {
                this.set({"date_from": instance.web.str_to_date(this.field_manager.get_field_value("date_from"))});
            });
            this.field_manager.on("field_changed:date_to", this, function() {
                this.set({"date_to": instance.web.str_to_date(this.field_manager.get_field_value("date_to"))});
            });
            this.field_manager.on("field_changed:user_id", this, function() {
                this.set({"user_id": this.field_manager.get_field_value("user_id")});
            });
            this.on("change:sheets", this, this.update_sheets);
            this.res_o2m_drop = new instance.web.DropMisordered();
            this.render_drop = new instance.web.DropMisordered();
            this.description_line = _t("/");
        },
        go_to: function(event) {
            var id = JSON.parse($(event.target).data("id"));
            this.do_action({
                type: 'ir.actions.act_window',
                res_model: "account.analytic.account",
                res_id: id,
                views: [[false, 'form']],
                target: 'current'
            });
        },
        query_sheets: function() {
            var self = this;
            if (self.updating)
                return;
            var commands = this.field_manager.get_field_value("timesheet_ids");
            this.res_o2m_drop.add(new instance.web.Model(this.view.model).call("resolve_2many_commands", ["timesheet_ids", commands, [],
                    new instance.web.CompoundContext()]))
                .done(function(result) {
                self.querying = true;
                self.set({sheets: result});
                self.querying = false;
            });
        },
        update_sheets: function() {
            var self = this;
            if (self.querying)
                return;
            self.updating = true;
            self.field_manager.set_values({timesheet_ids: self.get("sheets")}).done(function() {
                self.updating = false;
            });
        },
        initialize_field: function() {
            instance.web.form.ReinitializeWidgetMixin.initialize_field.call(this);
            var self = this;
            self.on("change:sheets", self, self.initialize_content);
            self.on("change:date_to", self, self.initialize_content);
            self.on("change:date_from", self, self.initialize_content);
            self.on("change:user_id", self, self.initialize_content);
        },
        initialize_content: function() {
            var self = this;
            if (self.setting)
                return;
            // don't render anything until we have date_to and date_from
            if (!self.get("date_to") || !self.get("date_from"))
                return;
            this.destroy_content();

            // it's important to use those vars to avoid race conditions
            var dates;
            var accounts;
            var account_names;
            var default_get;
            return this.render_drop.add(new instance.web.Model("hr.analytic.timesheet").call("default_get", [
                ['account_id','general_account_id', 'journal_id','date','name','user_id','product_id','product_uom_id','to_invoice','amount','unit_amount'],
                new instance.web.CompoundContext({'user_id': self.get('user_id')})]).then(function(result) {
                default_get = result;
                // calculating dates
                dates = [];
                var start = self.get("date_from");
                var end = self.get("date_to");
                while (start <= end) {
                    dates.push(start);
                    start = start.clone().addDays(1);
                }
                // group by account
                accounts = _(self.get("sheets")).chain()
                .map(function(el) {
                    // much simpler to use only the id in all cases
                    if (typeof(el.account_id) === "object")
                        el.account_id = el.account_id[0];
                    return el;
                })
                .groupBy("account_id").value();

                var account_ids = _.map(_.keys(accounts), function(el) { return el === "false" ? false : Number(el) });

                return new instance.web.Model("hr.analytic.timesheet").call("multi_on_change_account_id", [[], account_ids,
                    new instance.web.CompoundContext({'user_id': self.get('user_id')})]).then(function(accounts_defaults) {
                    accounts = _(accounts).chain().map(function(lines, account_id) {
                        account_defaults = _.extend({}, default_get, accounts_defaults[account_id]);
                        // group by days
                        account_id = account_id === "false" ? false :  Number(account_id);
                        var index = _.groupBy(lines, "date");
                        var days = _.map(dates, function(date) {
                            var day = {day: date, lines: index[instance.web.date_to_str(date)] || []};
                            // add line where we will insert/remove hours
                            var to_add = _.find(day.lines, function(line) { return line.name === self.description_line });
                            if (to_add) {
                                day.lines = _.without(day.lines, to_add);
                                day.lines.unshift(to_add);
                            } else {
                                day.lines.unshift(_.extend(_.clone(account_defaults), {
                                    name: self.description_line,
                                    unit_amount: 0,
                                    date: instance.web.date_to_str(date),
                                    account_id: account_id,
                                }));
                            }
                            return day;
                        });
                        return {account: account_id, days: days, account_defaults: account_defaults};
                    }).value();

                    // we need the name_get of the analytic accounts
                    return new instance.web.Model("account.analytic.account").call("name_get", [_.pluck(accounts, "account"),
                        new instance.web.CompoundContext()]).then(function(result) {
                        account_names = {};
                        _.each(result, function(el) {
                            account_names[el[0]] = el[1];
                        });
                        accounts = _.sortBy(accounts, function(el) {
                            return account_names[el.account];
                        });
                    });;
                });
            })).then(function(result) {
                // we put all the gathered data in self, then we render
                self.dates = dates;
                self.accounts = accounts;
                self.account_names = account_names;
                self.default_get = default_get;
                //real rendering
                self.display_data();
            });
        },
        destroy_content: function() {
            if (this.dfm) {
                this.dfm.destroy();
                this.dfm = undefined;
            }
        },
        display_data: function() {
            var self = this;
            self.$el.html(QWeb.render("hr_timesheet_sheet.WeeklyTimesheet", {widget: self}));
            _.each(self.accounts, function(account) {
                _.each(_.range(account.days.length), function(day_count) {
                    if (!self.get('effective_readonly')) {
                        self.get_box(account, day_count).val(self.sum_box(account, day_count)).change(function() {
                            var num = Number($(this).val());
                            if (isNaN(num)) {
                                $(this).val(self.sum_box(account, day_count));
                            } else {
                                account.days[day_count].lines[0].unit_amount += num - self.sum_box(account, day_count);
                                self.display_totals();
                                self.sync();
                            }
                        });
                    } else {
                        self.get_box(account, day_count).html(self.sum_box(account, day_count));
                    }
                });
            });
            self.display_totals();
            self.$(".oe_timesheet_weekly_adding button").click(_.bind(this.init_add_account, this));
        },
        init_add_account: function() {
            var self = this;
            if (self.dfm)
                return;
            self.$(".oe_timesheet_weekly_add_row").show();
            self.dfm = new instance.web.form.DefaultFieldManager(self);
            self.dfm.extend_field_desc({
                account: {
                    relation: "account.analytic.account",
                },
            });
            self.account_m2o = new instance.web.form.FieldMany2One(self.dfm, {
                attrs: {
                    name: "account",
                    type: "many2one",
                    domain: [
                        ['type','in',['normal', 'contract']],
                        ['state', '<>', 'close'],
                        ['use_timesheets','=',1],
                        ['id', 'not in', _.pluck(self.accounts, "account")],
                    ],
                    context: {
                        default_use_timesheets: 1,
                        default_type: "contract",
                    },
                    modifiers: '{"required": true}',
                },
            });
            self.account_m2o.prependTo(self.$(".oe_timesheet_weekly_add_row td"));
            self.$(".oe_timesheet_weekly_add_row button").click(function() {
                var id = self.account_m2o.get_value();
                if (id === false) {
                    self.dfm.set({display_invalid_fields: true});
                    return;
                }
                var ops = self.generate_o2m_value();
                new instance.web.Model("hr.analytic.timesheet").call("on_change_account_id", [[], id]).then(function(res) {
                    var def = _.extend({}, self.default_get, res.value, {
                        name: self.description_line,
                        unit_amount: 0,
                        date: instance.web.date_to_str(self.dates[0]),
                        account_id: id,
                    });
                    ops.push(def);
                    self.set({"sheets": ops});
                });
            });
        },
        get_box: function(account, day_count) {
            return this.$('[data-account="' + account.account + '"][data-day-count="' + day_count + '"]');
        },
        get_total: function(account) {
            return this.$('[data-account-total="' + account.account + '"]');
        },
        get_day_total: function(day_count) {
            return this.$('[data-day-total="' + day_count + '"]');
        },
        get_super_total: function() {
            return this.$('.oe_timesheet_weekly_supertotal');
        },
        sum_box: function(account, day_count) {
            var line_total = 0;
            _.each(account.days[day_count].lines, function(line) {
                line_total += line.unit_amount;
            });
            return line_total;
        },
        display_totals: function() {
            var self = this;
            var day_tots = _.map(_.range(self.dates.length), function() { return 0 });
            var super_tot = 0;
            _.each(self.accounts, function(account) {
                var acc_tot = 0;
                _.each(_.range(self.dates.length), function(day_count) {
                    var sum = self.sum_box(account, day_count);
                    acc_tot += sum;
                    day_tots[day_count] += sum;
                    super_tot += sum;
                });
                self.get_total(account).html(acc_tot);
            });
            _.each(_.range(self.dates.length), function(day_count) {
                self.get_day_total(day_count).html(day_tots[day_count]);
            });
            self.get_super_total().html(super_tot);
        },
        sync: function() {
            var self = this;
            self.setting = true;
            self.set({sheets: this.generate_o2m_value()});
            self.setting = false;
        },
        generate_o2m_value: function() {
            var self = this;
            var ops = [];

            _.each(self.accounts, function(account) {
                var auth_keys = _.extend(_.clone(account.account_defaults), {
                    name: true, unit_amount: true, date: true, account_id:true,
                });
                _.each(account.days, function(day) {
                    _.each(day.lines, function(line) {
                        if (line.unit_amount !== 0) {
                            var tmp = _.clone(line);
                            tmp.id = undefined;
                            _.each(line, function(v, k) {
                                if (v instanceof Array) {
                                    tmp[k] = v[0];
                                }
                            });
                            // we have to remove some keys, because analytic lines are shitty
                            _.each(_.keys(tmp), function(key) {
                                if (auth_keys[key] === undefined) {
                                    tmp[key] = undefined;
                                }
                            });
                            ops.push(tmp);
                        }
                    });
                });
            });
            return ops;
        },
    });

    instance.web.form.custom_widgets.add('weekly_timesheet', 'instance.hr_timesheet_sheet.WeeklyTimesheet');

};
<commit_msg>[FIX] hr_timesheet_sheet: typo in javascript code<commit_after>
openerp.hr_timesheet_sheet = function(instance) {
    var QWeb = instance.web.qweb;
    var _t = instance.web._t;

    instance.hr_timesheet_sheet.WeeklyTimesheet = instance.web.form.FormWidget.extend(instance.web.form.ReinitializeWidgetMixin, {
        events: {
            "click .oe_timesheet_weekly_account a": "go_to",
        },
        init: function() {
            this._super.apply(this, arguments);
            this.set({
                sheets: [],
                date_to: false,
                date_from: false,
            });
            this.field_manager.on("field_changed:timesheet_ids", this, this.query_sheets);
            this.field_manager.on("field_changed:date_from", this, function() {
                this.set({"date_from": instance.web.str_to_date(this.field_manager.get_field_value("date_from"))});
            });
            this.field_manager.on("field_changed:date_to", this, function() {
                this.set({"date_to": instance.web.str_to_date(this.field_manager.get_field_value("date_to"))});
            });
            this.field_manager.on("field_changed:user_id", this, function() {
                this.set({"user_id": this.field_manager.get_field_value("user_id")});
            });
            this.on("change:sheets", this, this.update_sheets);
            this.res_o2m_drop = new instance.web.DropMisordered();
            this.render_drop = new instance.web.DropMisordered();
            this.description_line = _t("/");
        },
        go_to: function(event) {
            var id = JSON.parse($(event.target).data("id"));
            this.do_action({
                type: 'ir.actions.act_window',
                res_model: "account.analytic.account",
                res_id: id,
                views: [[false, 'form']],
                target: 'current'
            });
        },
        query_sheets: function() {
            var self = this;
            if (self.updating)
                return;
            var commands = this.field_manager.get_field_value("timesheet_ids");
            this.res_o2m_drop.add(new instance.web.Model(this.view.model).call("resolve_2many_commands", ["timesheet_ids", commands, [],
                    new instance.web.CompoundContext()]))
                .done(function(result) {
                self.querying = true;
                self.set({sheets: result});
                self.querying = false;
            });
        },
        update_sheets: function() {
            var self = this;
            if (self.querying)
                return;
            self.updating = true;
            self.field_manager.set_values({timesheet_ids: self.get("sheets")}).done(function() {
                self.updating = false;
            });
        },
        initialize_field: function() {
            instance.web.form.ReinitializeWidgetMixin.initialize_field.call(this);
            var self = this;
            self.on("change:sheets", self, self.initialize_content);
            self.on("change:date_to", self, self.initialize_content);
            self.on("change:date_from", self, self.initialize_content);
            self.on("change:user_id", self, self.initialize_content);
        },
        initialize_content: function() {
            var self = this;
            if (self.setting)
                return;
            // don't render anything until we have date_to and date_from
            if (!self.get("date_to") || !self.get("date_from"))
                return;
            this.destroy_content();

            // it's important to use those vars to avoid race conditions
            var dates;
            var accounts;
            var account_names;
            var default_get;
            return this.render_drop.add(new instance.web.Model("hr.analytic.timesheet").call("default_get", [
                ['account_id','general_account_id', 'journal_id','date','name','user_id','product_id','product_uom_id','to_invoice','amount','unit_amount'],
                new instance.web.CompoundContext({'user_id': self.get('user_id')})]).then(function(result) {
                default_get = result;
                // calculating dates
                dates = [];
                var start = self.get("date_from");
                var end = self.get("date_to");
                while (start <= end) {
                    dates.push(start);
                    start = start.clone().addDays(1);
                }
                // group by account
                accounts = _(self.get("sheets")).chain()
                .map(function(el) {
                    // much simpler to use only the id in all cases
                    if (typeof(el.account_id) === "object")
                        el.account_id = el.account_id[0];
                    return el;
                })
                .groupBy("account_id").value();

                var account_ids = _.map(_.keys(accounts), function(el) { return el === "false" ? false : Number(el) });

                return new instance.web.Model("hr.analytic.timesheet").call("multi_on_change_account_id", [[], account_ids,
                    new instance.web.CompoundContext({'user_id': self.get('user_id')})]).then(function(accounts_defaults) {
                    accounts = _(accounts).chain().map(function(lines, account_id) {
                        account_defaults = _.extend({}, default_get, (accounts_defaults[account_id] || {}).value || {});
                        // group by days
                        account_id = account_id === "false" ? false :  Number(account_id);
                        var index = _.groupBy(lines, "date");
                        var days = _.map(dates, function(date) {
                            var day = {day: date, lines: index[instance.web.date_to_str(date)] || []};
                            // add line where we will insert/remove hours
                            var to_add = _.find(day.lines, function(line) { return line.name === self.description_line });
                            if (to_add) {
                                day.lines = _.without(day.lines, to_add);
                                day.lines.unshift(to_add);
                            } else {
                                day.lines.unshift(_.extend(_.clone(account_defaults), {
                                    name: self.description_line,
                                    unit_amount: 0,
                                    date: instance.web.date_to_str(date),
                                    account_id: account_id,
                                }));
                            }
                            return day;
                        });
                        return {account: account_id, days: days, account_defaults: account_defaults};
                    }).value();

                    // we need the name_get of the analytic accounts
                    return new instance.web.Model("account.analytic.account").call("name_get", [_.pluck(accounts, "account"),
                        new instance.web.CompoundContext()]).then(function(result) {
                        account_names = {};
                        _.each(result, function(el) {
                            account_names[el[0]] = el[1];
                        });
                        accounts = _.sortBy(accounts, function(el) {
                            return account_names[el.account];
                        });
                    });;
                });
            })).then(function(result) {
                // we put all the gathered data in self, then we render
                self.dates = dates;
                self.accounts = accounts;
                self.account_names = account_names;
                self.default_get = default_get;
                //real rendering
                self.display_data();
            });
        },
        destroy_content: function() {
            if (this.dfm) {
                this.dfm.destroy();
                this.dfm = undefined;
            }
        },
        display_data: function() {
            var self = this;
            self.$el.html(QWeb.render("hr_timesheet_sheet.WeeklyTimesheet", {widget: self}));
            _.each(self.accounts, function(account) {
                _.each(_.range(account.days.length), function(day_count) {
                    if (!self.get('effective_readonly')) {
                        self.get_box(account, day_count).val(self.sum_box(account, day_count)).change(function() {
                            var num = Number($(this).val());
                            if (isNaN(num)) {
                                $(this).val(self.sum_box(account, day_count));
                            } else {
                                account.days[day_count].lines[0].unit_amount += num - self.sum_box(account, day_count);
                                self.display_totals();
                                self.sync();
                            }
                        });
                    } else {
                        self.get_box(account, day_count).html(self.sum_box(account, day_count));
                    }
                });
            });
            self.display_totals();
            self.$(".oe_timesheet_weekly_adding button").click(_.bind(this.init_add_account, this));
        },
        init_add_account: function() {
            var self = this;
            if (self.dfm)
                return;
            self.$(".oe_timesheet_weekly_add_row").show();
            self.dfm = new instance.web.form.DefaultFieldManager(self);
            self.dfm.extend_field_desc({
                account: {
                    relation: "account.analytic.account",
                },
            });
            self.account_m2o = new instance.web.form.FieldMany2One(self.dfm, {
                attrs: {
                    name: "account",
                    type: "many2one",
                    domain: [
                        ['type','in',['normal', 'contract']],
                        ['state', '<>', 'close'],
                        ['use_timesheets','=',1],
                        ['id', 'not in', _.pluck(self.accounts, "account")],
                    ],
                    context: {
                        default_use_timesheets: 1,
                        default_type: "contract",
                    },
                    modifiers: '{"required": true}',
                },
            });
            self.account_m2o.prependTo(self.$(".oe_timesheet_weekly_add_row td"));
            self.$(".oe_timesheet_weekly_add_row button").click(function() {
                var id = self.account_m2o.get_value();
                if (id === false) {
                    self.dfm.set({display_invalid_fields: true});
                    return;
                }
                var ops = self.generate_o2m_value();
                new instance.web.Model("hr.analytic.timesheet").call("on_change_account_id", [[], id]).then(function(res) {
                    var def = _.extend({}, self.default_get, res.value, {
                        name: self.description_line,
                        unit_amount: 0,
                        date: instance.web.date_to_str(self.dates[0]),
                        account_id: id,
                    });
                    ops.push(def);
                    self.set({"sheets": ops});
                });
            });
        },
        get_box: function(account, day_count) {
            return this.$('[data-account="' + account.account + '"][data-day-count="' + day_count + '"]');
        },
        get_total: function(account) {
            return this.$('[data-account-total="' + account.account + '"]');
        },
        get_day_total: function(day_count) {
            return this.$('[data-day-total="' + day_count + '"]');
        },
        get_super_total: function() {
            return this.$('.oe_timesheet_weekly_supertotal');
        },
        sum_box: function(account, day_count) {
            var line_total = 0;
            _.each(account.days[day_count].lines, function(line) {
                line_total += line.unit_amount;
            });
            return line_total;
        },
        display_totals: function() {
            var self = this;
            var day_tots = _.map(_.range(self.dates.length), function() { return 0 });
            var super_tot = 0;
            _.each(self.accounts, function(account) {
                var acc_tot = 0;
                _.each(_.range(self.dates.length), function(day_count) {
                    var sum = self.sum_box(account, day_count);
                    acc_tot += sum;
                    day_tots[day_count] += sum;
                    super_tot += sum;
                });
                self.get_total(account).html(acc_tot);
            });
            _.each(_.range(self.dates.length), function(day_count) {
                self.get_day_total(day_count).html(day_tots[day_count]);
            });
            self.get_super_total().html(super_tot);
        },
        sync: function() {
            var self = this;
            self.setting = true;
            self.set({sheets: this.generate_o2m_value()});
            self.setting = false;
        },
        generate_o2m_value: function() {
            var self = this;
            var ops = [];

            _.each(self.accounts, function(account) {
                var auth_keys = _.extend(_.clone(account.account_defaults), {
                    name: true, unit_amount: true, date: true, account_id:true,
                });
                _.each(account.days, function(day) {
                    _.each(day.lines, function(line) {
                        if (line.unit_amount !== 0) {
                            var tmp = _.clone(line);
                            tmp.id = undefined;
                            _.each(line, function(v, k) {
                                if (v instanceof Array) {
                                    tmp[k] = v[0];
                                }
                            });
                            // we have to remove some keys, because analytic lines are shitty
                            _.each(_.keys(tmp), function(key) {
                                if (auth_keys[key] === undefined) {
                                    tmp[key] = undefined;
                                }
                            });
                            ops.push(tmp);
                        }
                    });
                });
            });
            return ops;
        },
    });

    instance.web.form.custom_widgets.add('weekly_timesheet', 'instance.hr_timesheet_sheet.WeeklyTimesheet');

};
<|endoftext|>


<commit_before>
import Expression from './base'
import Literal from './literal'
import { compose, useMany, useConditions } from './mixin'

const mixin = compose(
  useConditions(),
  useMany('columns')
)

/**
 * @class JoinExpression
 */
export default class Join extends mixin(Expression) {
  /**
   * @param {Any} table
   * @param {String} type
   * @constructor
   */
  constructor (table, type = 'inner') {
    super()

    this.type = type
    this.table = table
  }

  /**
   * @param {Any} table
   * @param {String} type
   * @returns {Expression}
   */
  static from (table, type = 'inner') {
    if (table instanceof Join) return table

    if (table instanceof Literal) return table

    return new Join(Literal.from(table), type)
  }

  /**
   * @param {Compiler} compiler
   * @returns {String}
   */
  compile (compiler) {
    return compiler.compileJoin(this)
  }

  /**
   * @returns {Join}
   * @override
   */
  clone () {
    // we cannot use `new Join(this.table, this.type)` here,
    // because join is using mixins

    let join = super.clone()

    join.table = this.table
    join.type = this.type

    return join
  }
}
<commit_msg>Delete join.js<commit_after><|endoftext|>