<commit_before>'use strict';

angular.module('streamium.provider.controller', ['ngRoute'])

.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.when('/provider', {
      templateUrl: 'provider/create.html',
      controller: 'CreateStreamCtrl'
    });

    $routeProvider.when('/provider/:streamId', {
      templateUrl: 'provider/stream.html',
      controller: 'BroadcastStreamCtrl'
    });

    $routeProvider.when('/provider/:streamId/cashout', {
      templateUrl: 'provider/cashout.html',
      controller: 'CashoutStreamCtrl'
    });
  }
])

.controller('CreateStreamCtrl', function($scope, $location, Rates, StreamiumProvider, bitcore) {
  $scope.stream = {};

  $scope.stream.name = config.DEBUG ? config.defaults.providerStream : '';
  $scope.stream.address = config.DEBUG ? config.defaults.providerAddress : '';
  $scope.stream.rate = 60;

  $scope.stream.error = null;
  $scope.stream.loading = false;

  $scope.otherNetwork = config.otherNetwork;
  $scope.linkToOther = config.linkToOther;

  if (!DetectRTC.isWebRTCSupported) {
    return $location.path('/no-webrtc');
  }

  $scope.normalizeName = function() {
    var name = $scope.stream.name || '';
    name = name.trim().toLowerCase().replace(/ |\\/g, '-');
    $scope.stream.name = name;
  };

  $scope.usdHourToBtcSec = function(usdHour) {
    var usdSecond = usdHour / 3600;
    var btcSecond = bitcore.Unit.fromFiat(usdSecond, Rates.rate).toBTC();
    return btcSecond ? btcSecond : 0;
  }

  $scope.usdHourToBtcMin = function(usdHour) {
    var usdSecond = usdHour / 60;
    var btcSecond = bitcore.Unit.fromFiat(usdSecond, Rates.rate).toBTC();
    return btcSecond ? btcSecond : 0;
  }

  $scope.submit = function() {
    if (!$scope.form.$valid) return;

    var priceRate = $scope.usdHourToBtcMin($scope.stream.rate);

    if (priceRate < 0) {
      $scope.stream.error = "Price rate must be a positive number";
      return;
    }

    $scope.stream.loading = true;
    StreamiumProvider.init(
      $scope.stream.name,
      $scope.stream.address,
      priceRate,
      function onCreate(err, done) {
        $scope.stream.loading = false;
        if (err) {
          $scope.stream.error = "Channel name is taken, please pick a different one";
        } else {
          $location.path('/provider/' + $scope.stream.name);
        }

        $scope.$apply();
      });
  };
})

.controller('BroadcastStreamCtrl', function($scope, $location, $routeParams, video, StreamiumProvider) {
  var name = $location.$$url.split('/')[2];
  $scope.requiresApproval = true;

  $scope.peers = {};

  StreamiumProvider.on('broadcast:start', function(peer) {
    console.log('Start broadcast for ' + peer);
    $scope.peers[peer] = peer;
    video.broadcast(peer, function(err) {
      if (err) throw err;
      $scope.broadcasting = true;
      $scope.$apply();
    });
  });

  StreamiumProvider.on('broadcast:end', function(peer) {
    if ($scope.peers[peer]) {
      delete $scope.peers[peer];
      video.end(peer);
    }
    $scope.$apply();
  });

  StreamiumProvider.on('balanceUpdated', function() {
    $scope.$apply();
  });

  $scope.end = function() {
    StreamiumProvider.endAllBroadcasts();
    $location.path('/provider/' + $routeParams.streamId + '/cashout');
  };

  var startCamera = function() {
    $scope.client = StreamiumProvider;
    $scope.filming = true;
    video.setPeer(StreamiumProvider.peer);
    video.camera(function(err, stream) {
      if (err) {
        console.log(err);
        return;
      }

      $scope.requiresApproval = false;
      $scope.videoSrc = URL.createObjectURL(stream);
      $scope.$digest();
    });
  };
  if (!StreamiumProvider.streamId) {
    // TODO: remove this
    StreamiumProvider.init(name, 'n3vNjpQB8GUVNz5R2hSM8rq4EgMEQqS4AZ', 0.001, function(err) {
      if (err) {
        console.log(err);
        return;
      }
      startCamera();
    });
  } else {
    startCamera();
  }
})

.controller('CashoutStreamCtrl', function(StreamiumProvider, $location, Duration, $scope, bitcore) {
  $scope.client = StreamiumProvider;
  $scope.totalMoney = 0;
  $scope.clients = [];
  for (var i in $scope.client.mapClientIdToProvider) {
    var amount = $scope.client.mapClientIdToProvider[i].currentAmount;
    var time = Duration.for(StreamiumProvider.rate, amount);
    $scope.totalMoney += amount;
    if (amount > 0) {
      var txId = $scope.client.mapClientIdToProvider[i].paymentTx.id;
      $scope.clients.push({
        amount: amount,
        timeSpent: time / 1000,
        transactionName: txId.substr(0, 4) + '...' + txId.substr(60, 64),
        transactionUrl:  'https://'
          + (bitcore.Networks.defaultNetwork.name === 'testnet' ? 'test-' : '')
          + 'insight.bitpay.com/tx/' + txId
      });
    }
  }
});
<commit_msg>Requires >= 0 rather than >0<commit_after>'use strict';

angular.module('streamium.provider.controller', ['ngRoute'])

.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.when('/provider', {
      templateUrl: 'provider/create.html',
      controller: 'CreateStreamCtrl'
    });

    $routeProvider.when('/provider/:streamId', {
      templateUrl: 'provider/stream.html',
      controller: 'BroadcastStreamCtrl'
    });

    $routeProvider.when('/provider/:streamId/cashout', {
      templateUrl: 'provider/cashout.html',
      controller: 'CashoutStreamCtrl'
    });
  }
])

.controller('CreateStreamCtrl', function($scope, $location, Rates, StreamiumProvider, bitcore) {
  $scope.stream = {};

  $scope.stream.name = config.DEBUG ? config.defaults.providerStream : '';
  $scope.stream.address = config.DEBUG ? config.defaults.providerAddress : '';
  $scope.stream.rate = 60;

  $scope.stream.error = null;
  $scope.stream.loading = false;

  $scope.otherNetwork = config.otherNetwork;
  $scope.linkToOther = config.linkToOther;

  if (!DetectRTC.isWebRTCSupported) {
    return $location.path('/no-webrtc');
  }

  $scope.normalizeName = function() {
    var name = $scope.stream.name || '';
    name = name.trim().toLowerCase().replace(/ |\\/g, '-');
    $scope.stream.name = name;
  };

  $scope.usdHourToBtcSec = function(usdHour) {
    var usdSecond = usdHour / 3600;
    var btcSecond = bitcore.Unit.fromFiat(usdSecond, Rates.rate).toBTC();
    return btcSecond ? btcSecond : 0;
  }

  $scope.usdHourToBtcMin = function(usdHour) {
    var usdSecond = usdHour / 60;
    var btcSecond = bitcore.Unit.fromFiat(usdSecond, Rates.rate).toBTC();
    return btcSecond ? btcSecond : 0;
  }

  $scope.submit = function() {
    if (!$scope.form.$valid) return;

    var priceRate = $scope.usdHourToBtcMin($scope.stream.rate);

    if (priceRate <= 0) {
      $scope.stream.error = "Price rate must be a positive number";
      return;
    }

    $scope.stream.loading = true;
    StreamiumProvider.init(
      $scope.stream.name,
      $scope.stream.address,
      priceRate,
      function onCreate(err, done) {
        $scope.stream.loading = false;
        if (err) {
          $scope.stream.error = "Channel name is taken, please pick a different one";
        } else {
          $location.path('/provider/' + $scope.stream.name);
        }

        $scope.$apply();
      });
  };
})

.controller('BroadcastStreamCtrl', function($scope, $location, $routeParams, video, StreamiumProvider) {
  var name = $location.$$url.split('/')[2];
  $scope.requiresApproval = true;

  $scope.peers = {};

  StreamiumProvider.on('broadcast:start', function(peer) {
    console.log('Start broadcast for ' + peer);
    $scope.peers[peer] = peer;
    video.broadcast(peer, function(err) {
      if (err) throw err;
      $scope.broadcasting = true;
      $scope.$apply();
    });
  });

  StreamiumProvider.on('broadcast:end', function(peer) {
    if ($scope.peers[peer]) {
      delete $scope.peers[peer];
      video.end(peer);
    }
    $scope.$apply();
  });

  StreamiumProvider.on('balanceUpdated', function() {
    $scope.$apply();
  });

  $scope.end = function() {
    StreamiumProvider.endAllBroadcasts();
    $location.path('/provider/' + $routeParams.streamId + '/cashout');
  };

  var startCamera = function() {
    $scope.client = StreamiumProvider;
    $scope.filming = true;
    video.setPeer(StreamiumProvider.peer);
    video.camera(function(err, stream) {
      if (err) {
        console.log(err);
        return;
      }

      $scope.requiresApproval = false;
      $scope.videoSrc = URL.createObjectURL(stream);
      $scope.$digest();
    });
  };
  if (!StreamiumProvider.streamId) {
    // TODO: remove this
    StreamiumProvider.init(name, 'n3vNjpQB8GUVNz5R2hSM8rq4EgMEQqS4AZ', 0.001, function(err) {
      if (err) {
        console.log(err);
        return;
      }
      startCamera();
    });
  } else {
    startCamera();
  }
})

.controller('CashoutStreamCtrl', function(StreamiumProvider, $location, Duration, $scope, bitcore) {
  $scope.client = StreamiumProvider;
  $scope.totalMoney = 0;
  $scope.clients = [];
  for (var i in $scope.client.mapClientIdToProvider) {
    var amount = $scope.client.mapClientIdToProvider[i].currentAmount;
    var time = Duration.for(StreamiumProvider.rate, amount);
    $scope.totalMoney += amount;
    if (amount > 0) {
      var txId = $scope.client.mapClientIdToProvider[i].paymentTx.id;
      $scope.clients.push({
        amount: amount,
        timeSpent: time / 1000,
        transactionName: txId.substr(0, 4) + '...' + txId.substr(60, 64),
        transactionUrl:  'https://'
          + (bitcore.Networks.defaultNetwork.name === 'testnet' ? 'test-' : '')
          + 'insight.bitpay.com/tx/' + txId
      });
    }
  }
});
<|endoftext|>


<commit_before>const PLAYER_ACCELERATION = 5.0;

class Player {
  get X() {
    return this.sprite.x;
  }
  get Y() {
    return this.sprite.y;
  }

  constructor() {
    const startX = 8 * 16;
    const startY = 8 * 12.5;

    this.sprite = game.add.sprite(startX, startY, 'player');
    this.sprite.animations.add('idle', [0, 1], 6, true);
    this.sprite.play('idle');
    this.sprite.gameObject = this;
    this.sprite.anchor.set(0.5, 0.5);
    game.physics.arcade.enable(this.sprite);
    this.sprite.body.maxVelocity.set(40, 40);
    this.sprite.body.collideWorldBounds = true;
    // player.body.gravity.y = 100;
    game.camera.follow(this.sprite);
    this.cursors = game.input.keyboard.createCursorKeys();
    this.jetpackSprite = game.add.sprite(startX + 5, startY, 'player');
    this.jetpackSprite.animations.add('idle', [4, 5], 8, true);
    this.jetpackSprite.animations.play('idle');
    this.jetpackSprite.anchor.set(1, 0.35);
    this.keys = {
      LEFT: game.input.keyboard.addKey(Phaser.Keyboard.LEFT),
      RIGHT: game.input.keyboard.addKey(Phaser.Keyboard.RIGHT),
      UP: game.input.keyboard.addKey(Phaser.Keyboard.UP),
      DOWN: game.input.keyboard.addKey(Phaser.Keyboard.DOWN),
      SLOW: game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR), // Remove the space bar
      STATION_0: game.input.keyboard.addKey(Phaser.Keyboard.Z), // Four Station Keys
      STATION_1: game.input.keyboard.addKey(Phaser.Keyboard.X),
      STATION_2: game.input.keyboard.addKey(Phaser.Keyboard.C),
      STATION_3: game.input.keyboard.addKey(Phaser.Keyboard.V),
    };
  }
  registerStationSignals(signals) {
    signals.onTriggerEnter.add(this.onStationEnter, this);
    signals.onTriggerExit.add(this.onStationExit, this);
  }
  onStationEnter(a) {
    console.log('Entering station', a);
    a.registerInputSignal('keyInput', this.keys.STATION_0.onDown);
    a.registerInputSignal('keyInput', this.keys.STATION_1.onDown);
    a.registerInputSignal('keyInput', this.keys.STATION_2.onDown);
    a.registerInputSignal('keyInput', this.keys.STATION_3.onDown);
  }
  onStationExit(a) {
    console.log('Exiting station', a);
    a.unregisterInputSignal('keyInput', this.keys.STATION_0.onDown);
    a.unregisterInputSignal('keyInput', this.keys.STATION_1.onDown);
    a.unregisterInputSignal('keyInput', this.keys.STATION_2.onDown);
    a.unregisterInputSignal('keyInput', this.keys.STATION_3.onDown);
  }
  update(canMove = true) {
    // Handle player -> world collisions
    if (shipWallLayer) {
      game.physics.arcade.collide(player.sprite, shipWallLayer, this.onCollide);
    }
    // Movement
    const LEFT = this.keys.LEFT.isDown;
    const RIGHT = this.keys.RIGHT.isDown;
    const UP = this.keys.UP.isDown;
    const DOWN = this.keys.DOWN.isDown;

    this.sprite.scale.x = (LEFT && !RIGHT) ? -1 : this.sprite.scale.x;
    this.sprite.scale.x = (!LEFT && RIGHT) ? 1 : this.sprite.scale.x;

    // Move the little thruster
    this.jetpackSprite.position.set(this.X, this.Y);
    this.jetpackSprite.scale.x = this.sprite.scale.x;

    let dX = 0;
    let dY = 0;
    dX -= LEFT ? 1 : 0;
    dX += RIGHT ? 1 : 0;
    dY -= UP ? 1 : 0;
    dY += DOWN ? 1 : 0;

    // Do dampening if needed
    if (!LEFT && !RIGHT) {
      dX = -this.sprite.body.acceleration.x * 0.125;
    }
    if (!UP && !DOWN) {
      dY = -this.sprite.body.acceleration.y * 0.125;
    }
    if (!UP && !DOWN && !LEFT && !RIGHT) {
      this.jetpackSprite.alpha = 0;
    } else {
      this.jetpackSprite.alpha = 1;
    }
    this.sprite.body.acceleration.x += dX * PLAYER_ACCELERATION;
    this.sprite.body.acceleration.y += dY * PLAYER_ACCELERATION;
    // Apply Space Dampeners
    if (this.keys.SLOW.isDown) {
      console.log('Don\'t forget to remove the spacebar');
      this.sprite.body.acceleration.set(0, 0);
      this.sprite.body.velocity.x *= 0.85;
      this.sprite.body.velocity.y *= 0.85;
    }
    if (!canMove) {
      this.sprite.body.velocity.set(0, 0);
      this.sprite.body.acceleration.set(0, 0);
    }
  }
  onCollide(sprite1, sprite2) {
    sprite1.body.acceleration.set(0, 0);
  }
  render() {
    if (DEBUG) {
      game.debug.body(this.sprite);
      const dbgVelStr = sprintf('velocity: %d, %d', this.sprite.body.velocity.x, this.sprite.body.velocity.y);
      debugText(dbgVelStr);
      const dbgAccStr = sprintf('acceleration: %d, %d', this.sprite.body.acceleration.x, this.sprite.body.acceleration.y);
      debugText(dbgAccStr)
    }
  }
  destroy() {
    this.sprite.destroy();
  }
}
<commit_msg>Removes slowdown<commit_after>const PLAYER_ACCELERATION = 5.0;

class Player {
  get X() {
    return this.sprite.x;
  }
  get Y() {
    return this.sprite.y;
  }

  constructor() {
    const startX = 8 * 16;
    const startY = 8 * 12.5;

    this.sprite = game.add.sprite(startX, startY, 'player');
    this.sprite.animations.add('idle', [0, 1], 6, true);
    this.sprite.play('idle');
    this.sprite.gameObject = this;
    this.sprite.anchor.set(0.5, 0.5);
    game.physics.arcade.enable(this.sprite);
    this.sprite.body.maxVelocity.set(40, 40);
    this.sprite.body.collideWorldBounds = true;
    // player.body.gravity.y = 100;
    game.camera.follow(this.sprite);
    this.cursors = game.input.keyboard.createCursorKeys();
    this.jetpackSprite = game.add.sprite(startX + 5, startY, 'player');
    this.jetpackSprite.animations.add('idle', [4, 5], 8, true);
    this.jetpackSprite.animations.play('idle');
    this.jetpackSprite.anchor.set(1, 0.35);
    this.keys = {
      LEFT: game.input.keyboard.addKey(Phaser.Keyboard.LEFT),
      RIGHT: game.input.keyboard.addKey(Phaser.Keyboard.RIGHT),
      UP: game.input.keyboard.addKey(Phaser.Keyboard.UP),
      DOWN: game.input.keyboard.addKey(Phaser.Keyboard.DOWN),
      SLOW: game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR), // Remove the space bar
      STATION_0: game.input.keyboard.addKey(Phaser.Keyboard.Z), // Four Station Keys
      STATION_1: game.input.keyboard.addKey(Phaser.Keyboard.X),
      STATION_2: game.input.keyboard.addKey(Phaser.Keyboard.C),
      STATION_3: game.input.keyboard.addKey(Phaser.Keyboard.V),
    };
  }
  registerStationSignals(signals) {
    signals.onTriggerEnter.add(this.onStationEnter, this);
    signals.onTriggerExit.add(this.onStationExit, this);
  }
  onStationEnter(a) {
    console.log('Entering station', a);
    a.registerInputSignal('keyInput', this.keys.STATION_0.onDown);
    a.registerInputSignal('keyInput', this.keys.STATION_1.onDown);
    a.registerInputSignal('keyInput', this.keys.STATION_2.onDown);
    a.registerInputSignal('keyInput', this.keys.STATION_3.onDown);
  }
  onStationExit(a) {
    console.log('Exiting station', a);
    a.unregisterInputSignal('keyInput', this.keys.STATION_0.onDown);
    a.unregisterInputSignal('keyInput', this.keys.STATION_1.onDown);
    a.unregisterInputSignal('keyInput', this.keys.STATION_2.onDown);
    a.unregisterInputSignal('keyInput', this.keys.STATION_3.onDown);
  }
  update(canMove = true) {
    // Handle player -> world collisions
    if (shipWallLayer) {
      game.physics.arcade.collide(player.sprite, shipWallLayer, this.onCollide);
    }
    // Movement
    const LEFT = this.keys.LEFT.isDown;
    const RIGHT = this.keys.RIGHT.isDown;
    const UP = this.keys.UP.isDown;
    const DOWN = this.keys.DOWN.isDown;

    this.sprite.scale.x = (LEFT && !RIGHT) ? -1 : this.sprite.scale.x;
    this.sprite.scale.x = (!LEFT && RIGHT) ? 1 : this.sprite.scale.x;

    // Move the little thruster
    this.jetpackSprite.position.set(this.X, this.Y);
    this.jetpackSprite.scale.x = this.sprite.scale.x;

    let dX = 0;
    let dY = 0;
    dX -= LEFT ? 1 : 0;
    dX += RIGHT ? 1 : 0;
    dY -= UP ? 1 : 0;
    dY += DOWN ? 1 : 0;

    // Do dampening if needed
    if (!LEFT && !RIGHT) {
      dX = -this.sprite.body.acceleration.x * 0.125;
    }
    if (!UP && !DOWN) {
      dY = -this.sprite.body.acceleration.y * 0.125;
    }
    if (!UP && !DOWN && !LEFT && !RIGHT) {
      this.jetpackSprite.alpha = 0;
    } else {
      this.jetpackSprite.alpha = 1;
    }
    this.sprite.body.acceleration.x += dX * PLAYER_ACCELERATION;
    this.sprite.body.acceleration.y += dY * PLAYER_ACCELERATION;
    // Apply Space Dampeners
    if (this.keys.SLOW.isDown && DEBUG) {
      console.log('Don\'t forget to remove the spacebar');
      this.sprite.body.acceleration.set(0, 0);
      this.sprite.body.velocity.x *= 0.85;
      this.sprite.body.velocity.y *= 0.85;
    }
    if (!canMove) {
      this.sprite.body.velocity.set(0, 0);
      this.sprite.body.acceleration.set(0, 0);
    }
  }
  onCollide(sprite1, sprite2) {
    sprite1.body.acceleration.set(0, 0);
  }
  render() {
    if (DEBUG) {
      game.debug.body(this.sprite);
      const dbgVelStr = sprintf('velocity: %d, %d', this.sprite.body.velocity.x, this.sprite.body.velocity.y);
      debugText(dbgVelStr);
      const dbgAccStr = sprintf('acceleration: %d, %d', this.sprite.body.acceleration.x, this.sprite.body.acceleration.y);
      debugText(dbgAccStr)
    }
  }
  destroy() {
    this.sprite.destroy();
  }
}
<|endoftext|>


<commit_before>var contextMenu = require("../actions/contextMenu");
var downMenu = require("../actions/downMenu");
//var enterMenu = require("../actions/enterMenu");

var request = require("request");

var watchSeason = function(host){
  console.log(contextMenuAction);
  request(contextMenuAction, function(error, response, body){
      console.log("menu contextual");
      request(downMenuAction, function(error, response, body){
        console.log("Reproducir");
        request(downMenuAction, function(error, response, body){
          console.log("Añadir a favoritos");
          request(downMenuAction, function(error, response, body){
            console.log("Información de serie de tv");
            request(downMenuAction, function(error, response, body){
              console.log("Marcar como no visto");
              request(downMenuAction, function(error, response, body){
                console.log("Marcar como visto");
//                request(enterMenuAction, function(error, response, body){
//                  console.log("Marcado!!");
//                });
              });
            });
          });
        });
      });
  });
};

exports.watchSeason = watchSeason
<commit_msg>Implementation the command to mark as watched one season<commit_after>var contextualMenu = require("../actions/contextMenu");
var downMenu = require("../actions/downMenu");
var enterMenu = require("../actions/enterMenu");

var request = require("request");

var watchSeason = function(host){

  contextualActionUrl = host+JSON.stringify(contextualMenu.action);
  downActionUrl = host+JSON.stringify(downMenu.action);
  enterActionUrl = host+JSON.stringify(enterMenu.action);
  request(contextualActionUrl, function(error, response, body){
    console.log("Menu contextual");
    request(downActionUrl, function(error, response, body){
      console.log("Reproducir");
      request(downActionUrl, function(error, response, body){
        console.log("Añadir a favoritos");
        request(downActionUrl, function(error, response, body){
          console.log("Información de serie de tv");
          request(downActionUrl, function(error, response, body){
            console.log("Marcar como no visto");
            request(downActionUrl, function(error, response, body){
              console.log("Marcar como visto");
              request(enterActionUrl, function(error, response, body){
                console.log("Marcado!!");
              });
            });
          });
        });
      });
    });
  });
};

exports.exec = watchSeason
<|endoftext|>


<commit_before>'use strict'

let path  = require('path')
let fs    = require('fs')
let async = require('async')
let ejs   = require('./lib/ejs')

/*
 * Rename the extension of a file in a path.
 * @param {string} filePath - Path to a file.
 * @param {string} fileExt - New extension of the file.
 * @returns {string} filePath - Path ending with the new fileExt.
 */
const renameExtension = function(filePath, fileExt) {

	let parsedPath = path.parse(filePath)

	return parsedPath.dir + path.sep + parsedPath.name + '.' + fileExt

}

/*
 * Read and parse a JSON-file.
 * @param {string} filePath - Path to a valid JSON file.
 * @returns {object} JSON
 */
const readJson = function(filePath) {

	let data = fs.readFileSync(filePath)

	return JSON.parse(data)

}

/*
 * Load EJS and transform to HTML.
 * @public
 * @param {string} filePath - Absolute path to the requested file.
 * @param {string} srcPath - Absolute path to the source folder.
 * @param {string} distPath - Absolute path to the export folder.
 * @param {Object} route - The route which matched the request URL.
 * @param {function} next - The callback that handles the response. Receives the following properties: err, result, savePath.
 */
module.exports = function(filePath, srcPath, distPath, route, next) {

	filePath = renameExtension(filePath, 'ejs')

	let savePath     = renameExtension(filePath.replace(srcPath, distPath), 'html')
	let dataPath     = path.join(process.cwd(), 'data.json')
	let relativePath = path.relative(srcPath, filePath)

	let current     = path.parse(relativePath)
	let environment = process.env
	let dataJSON    = readJson(dataPath)
	let globalData  = dataJSON['*'] || {}
	let pageData    = dataJSON[current.name] || {}

	let data = Object.assign({}, globalData, pageData, {
		current,
		environment
	})

	async.waterfall([

		(next)      => fs.readFile(filePath, 'utf8', next),
		(str, next) => ejs(filePath, str, data, next)

	], (err, str) => {

		if (err!=null) {
			next(err, null, null)
			return false
		}

		next(null, str, savePath)

	})

}<commit_msg>Added caching support<commit_after>'use strict'

let path  = require('path')
let fs    = require('fs')
let async = require('async')
let ejs   = require('./lib/ejs')

/*
 * Rename the extension of a file in a path.
 * @param {string} filePath - Path to a file.
 * @param {string} fileExt - New extension of the file.
 * @returns {string} filePath - Path ending with the new fileExt.
 */
const renameExtension = function(filePath, fileExt) {

	let parsedPath = path.parse(filePath)

	return parsedPath.dir + path.sep + parsedPath.name + '.' + fileExt

}

/*
 * Read and parse a JSON-file.
 * @param {string} filePath - Path to a valid JSON file.
 * @returns {object} JSON
 */
const readJson = function(filePath) {

	let data = fs.readFileSync(filePath)

	return JSON.parse(data)

}

/*
 * Load EJS and transform to HTML.
 * @public
 * @param {string} filePath - Absolute path to the requested file.
 * @param {string} srcPath - Absolute path to the source folder.
 * @param {string} distPath - Absolute path to the export folder.
 * @param {Object} route - The route which matched the request URL.
 * @param {function} next - The callback that handles the response. Receives the following properties: err, result, savePath.
 */
module.exports = function(filePath, srcPath, distPath, route, next) {

	filePath = renameExtension(filePath, 'ejs')

	let savePath     = renameExtension(filePath.replace(srcPath, distPath), 'html')
	let dataPath     = path.join(process.cwd(), 'data.json')
	let relativePath = path.relative(srcPath, filePath)

	let current     = path.parse(relativePath)
	let environment = process.env
	let dataJSON    = readJson(dataPath)
	let globalData  = dataJSON['*'] || {}
	let pageData    = dataJSON[current.name] || {}

	let data = Object.assign({}, globalData, pageData, {
		current,
		environment
	})

	async.waterfall([

		(next)      => fs.readFile(filePath, 'utf8', next),
		(str, next) => ejs(filePath, str, data, next)

	], (err, str) => {

		if (err!=null) {
			next(err, null, null)
			return false
		}

		next(null, str, savePath)

	})

}

/**
 * Attach an array to the function, which contains a list of
 * extensions used by the handler. The array will be used by Rosid for caching purposes.
 */
module.exports.cache = [
	'.ejs',
	'.json'
]<|endoftext|>


<commit_before>function LightManager() {
    this._lights = [];
    this._models = {};

    /**
     * Updating light parameters can lead to updating the (lazy) scene structure, which
     * in turn updates the lights. If we are in updating the lights, flag is set to true.
     * @type {boolean}
     * @private
     */
    this._inUpdate = false;
}

LightManager.prototype = {
    add: function (light) {
        this._lights.push(light);
        this._addModel(light.model);
    },

    remove: function (light) {
        var index = this._lights.indexOf(light);
        if (index != -1) {
            this._lights.splice(index, 1);
        }
        this._removeModel(light.model);
    },

    fillGlobalParameters: function (globals, force) {
        for (var id in this._models) {
            var entry = this._models[id];
            /* Fill globals only if this was not already done before */
            if (entry.changed || force) {
                var prefix = id + "Light";
                for (var param in entry.parameters) {
                    var name = prefix + param.charAt(0).toUpperCase() + param.slice(1);
                    globals[name] = entry.parameters[param];
                }
                entry.changed = false;
            }
        }
    },

    lightValueChanged: function (light) {
        if (this._inUpdate)
            return;
        this._inUpdate = true;

        var lights = light ? [light] : this._lights;
        var that = this;

        lights.forEach(function(light) {
            var model = light.model;
            var entry = that.getModelEntry(model.id);
            var offset = entry.lightModels.indexOf(model);
            if (offset < 0) {
                //These changes are for a light that no longer exists so we can ignore them
                //This can happen for ex. during a delayed change notification that isn't fired until after a remove()
                return;
            }
            model.fillLightParameters(entry.parameters, offset);
            model.getLightData(entry.parameters, offset);
            entry.changed = true;
        });
        this._inUpdate = false;
    },

    getModelEntry: function (id) {
        return this._models[id];
    },

    getModels: function (id) {
        return Object.keys(this._models);
    },

    getModelCount: function (id) {
        var model = this.getModelEntry(id);
        return model ? model.lightModels.length : 0;
    },

    _addModel: function (model) {
        var entry = this._models[model.id];
        if (!entry) {
            entry = this._models[model.id] = {lightModels: [], parameters: {}};
        }
        entry.lightModels.push(model);
        this._lightStructureChanged(entry);
    },

    _removeModel: function (model) {
        var entry = this.getModelEntry(model.id);
        var index = entry.lightModels.indexOf(model);
        if (index != -1) {
            entry.lightModels.splice(index, 1);
        }
        this._lightStructureChanged(entry);
    },

    _lightStructureChanged: function (entry) {
        this._inUpdate = true;
        var length = entry.lightModels.length;
        if (!length) {
            entry.parameters = {};
            return;
        }
        var model = entry.lightModels[0];
        entry.parameters = model.allocateParameterArray(length);
        entry.lightModels.forEach(function (lightModel, offset) {
            lightModel.fillLightParameters(entry.parameters, offset)
            lightModel.getLightData(entry.parameters, offset);
        });
        entry.changed = true;
        this._inUpdate = false;

    }
};

module.exports = LightManager;
<commit_msg>Fixes #194: Boah war das fies...<commit_after>function LightManager() {
    this._lights = [];
    this._models = {};

    /**
     * Updating light parameters can lead to updating the (lazy) scene structure, which
     * in turn updates the lights. If we are in updating the lights, flag is set to true.
     * @type {boolean}
     * @private
     */
    this._inUpdate = false;
}

LightManager.prototype = {
    add: function (light) {
        this._lights.push(light);
        this._addModel(light.model);
    },

    remove: function (light) {
        var index = this._lights.indexOf(light);
        if (index != -1) {
            this._lights.splice(index, 1);
        }
        this._removeModel(light.model);
    },

    fillGlobalParameters: function (globals, force) {
        for (var id in this._models) {
            var entry = this._models[id];
            /* Fill globals only if this was not already done before */
            if (entry.changed || force) {
                var prefix = id + "Light";
                for (var param in entry.parameters) {
                    var name = prefix + param.charAt(0).toUpperCase() + param.slice(1);
                    globals[name] = entry.parameters[param];
                }
                entry.changed = false;
            }
        }
    },

    lightValueChanged: function (light) {
        if (this._inUpdate)
            return;
        this._inUpdate = true;

        var lights = light ? [light] : this._lights;
        var that = this;

        lights.forEach(function(light) {
            var model = light.model;
            var entry = that.getModelEntry(model.id);
            var offset = entry.lightModels.indexOf(model);
            if (offset < 0) {
                //These changes are for a light that no longer exists so we can ignore them
                //This can happen for ex. during a delayed change notification that isn't fired until after a remove()
                return;
            }
            model.fillLightParameters(entry.parameters, offset);
            model.getLightData(entry.parameters, offset);
            entry.changed = true;
        });
        this._inUpdate = false;
    },

    getModelEntry: function (id) {
        return this._models[id];
    },

    getModels: function (id) {
        return Object.keys(this._models);
    },

    getModelCount: function (id) {
        var model = this.getModelEntry(id);
        return model ? model.lightModels.length : 0;
    },

    _addModel: function (model) {
        var entry = this._models[model.id];
        if (!entry) {
            entry = this._models[model.id] = {lightModels: [], parameters: {}};
        }
        entry.lightModels.push(model);
        this._lightStructureChanged(entry);
    },

    _removeModel: function (model) {
        var entry = this.getModelEntry(model.id);
        var index = entry.lightModels.indexOf(model);
        if (index != -1) {
            entry.lightModels.splice(index, 1);
        }
        this._lightStructureChanged(entry);
    },

    _lightStructureChanged: function (entry) {
        this._inUpdate = true;
        var length = entry.lightModels.length;
        if (!length) {
            entry.parameters = {};
            this._inUpdate = false;
            return;
        }
        var model = entry.lightModels[0];
        entry.parameters = model.allocateParameterArray(length);
        entry.lightModels.forEach(function (lightModel, offset) {
            lightModel.fillLightParameters(entry.parameters, offset)
            lightModel.getLightData(entry.parameters, offset);
        });
        entry.changed = true;
        this._inUpdate = false;
    }
};

module.exports = LightManager;
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name ratemycoopApp.controller:ReviewformCtrl
 * @description
 * # ReviewformCtrl
 * Controller of the ratemycoopApp
 */
angular.module('ratemycoopApp')
  .controller('ReviewformCtrl', function ($scope, Company, Major, City, Perk, PayType, User, $routeParams) {
    $scope.loading = {
      main: true, // Promise, must be turned to false somewhere
      perks: true // Promise, must be turned to false somewhere
    };

    /**
     * Initialize Session
     */
    if (User.isAuthenticated()) {
      $scope.user = User.getCurrent(
        function (success) {
          console.log(success);
          $scope.formData.userId = success.id;
        }
      );
    } else {
      // TODO: Must handle unauthenticated and redirect to login screen.
      console.log('ERROR: User must be authenticated');
      $scope.user = null;
    }

    /**
     * Used if we want to fetch for pay types, as opposed to using just
     * $scope.payTypes
     */
    $scope.fetchedPayTypes = PayType.find({},
      function (success) {
      });

    $scope.payTypes = [{id: 1, name: "Hourly"}, {id: 2, name: "Salary"}, {id: 3, name: "Stipend"}];

    /**
     * Get company info on-load
     */
    $scope.company = Company.findOne({
        filter: {
          where: {name: $routeParams.companyname},
          include: ['perks', 'majors', 'reviews', {'locations': 'region'}]
        }
      },
      function (successData) {
        $scope.loading.main = false;
      }
    );

    /**
     * Get major info on-load
     */
    $scope.majors = Major.find({},
      function (successData) {
        angular.forEach(successData, function (result) {
          result.title = result.name;
          result.description = result.code;
        });

        $('#majorSearch').search({
          source: $scope.majors,
          maxResults: 4,
          searchFields: ['code', 'name']
        })
      }
    );

    $scope.allPerks = Perk.find({},
      function (successData) {
        angular.forEach(successData, function (value) {
          value['isSelected'] = false;
        });
        $scope.loading.perks = false;
        // Success allperks
      }
    );

    $scope.addPerk = function (perk) {
      $scope.perkSearchQuery = "";
      perk.isSelected = true;
      console.log(perk);
      $scope.formData.perks.push(perk);
    };

    $scope.unselectPerk = function (perk) {
      console.log($scope.formData.perks.length);
      perk.isSelected = false;
      var i = $scope.formData.perks.indexOf(perk);
      if (i > -1) {
        $scope.formData.perks.splice(i, 1);
      }

    };

    $scope.printFormData = function () {
      console.log($scope.formData);
    };

    $scope.formData = {
      overallRating: 0,
      cultureRating: 0,
      difficultyRating: 0,

      description: "",

      pay: "",
      payTypeId: $scope.payTypes[0].id,

      //userId: $scope.user.id == set when async call to USER returns

      perks: [],

      returnOffer: false,
      recommend: false,
      anonymous: false

    };

    $scope.submitReview = function () {
      console.log("Review is being submitted :) ");
      /* Validation */
      // Pay type validation

      var pushObject = prepForPush($scope.formData);
    };

    function prepForPush(formData) {

      var pushObj = {
        "anonymous": formData.anonymous,
        "returnOffer": formData.returnOffer,
        "recommend": formData.recommend,
        "description": formData.description,
        "userId": formData.userId,
        "companyId": 0,
        "payTypeId": 0,
        "pay": 0

      }
    }

    /**
     * Wizard variables.
     * @type {{currStep: string, s1: string, s2: string, s3: string}}
     */
    $scope.wizard = {
      currStep: "wizardStepOne",
      s1: "wizardStepOne",
      s2: "wizardStepTwo",
      s3: "wizardStepThree"
    };

    angular.element(document).ready(function () {
      setTimeout(setupSemantic, 400);
    });

    function setupSemantic() {
      $('.ui.accordion').accordion();
      $('.ui.selection.dropdown').dropdown();
      $('#payType').dropdown();
      $('.rating').rating({
        /* see http://bit.ly/1M0OaL9 of why we need to do this */
        onRate: function (val) {
          $scope.$apply(function () {
            var ratings = $('.rating').rating('get rating');
            $scope.formData.overallRating = ratings[0];
            $scope.formData.cultureRating = ratings[1];
            $scope.formData.difficultyRating = ratings[2];
          });
        }
      });
      $('#privacyCheckbox').checkbox({
        onChange: function () {
          /* see http://bit.ly/1M0OaL9 of why we need to do this */
          $scope.$apply(function () {
            $scope.formData.anonymous = !$scope.formData.anonymous;
          });
        }
      });
      $('#returnOfferCheckbox').checkbox({
        onChange: function () {
          /* see http://bit.ly/1M0OaL9 of why we need to do this */
          $scope.$apply(function () {
            $scope.formData.returnOffer = !$scope.formData.returnOffer;
          });
        }
      });
      $('#recommendCheckbox').checkbox({
        onChange: function () {
          /* see http://bit.ly/1M0OaL9 of why we need to do this */
          $scope.$apply(function () {
            $scope.formData.recommend = !$scope.formData.recommend;
          });
        }
      });

      $('#locationSearch').search({
        apiSettings: {
          //TODO: not hardcode url, use another system for searching
          url: "https://ratemycoop.io/api/v1/Cities/search?query={query}"
        },
        searchFields: ['name']

      });

      $('#reviewForm').form(
        {
          major: {
            identifier: 'majorSearchInput',
            rules: [{
              type: 'empty',
              prompt: 'Please enter your major'
            }]
          },
          city: {
            identifier: 'locationSearchInput',
            rules: [{
              type: 'empty',
              prompt: 'Please enter your major'
            }]
          },
          pay: {
            identifier: 'payInput',
            rules: [
              {
                type: 'empty',
                prompt: 'Please enter a valid pay'
              },
              {
                type: 'length[2]'
              }
            ]
          },
          payType: {
            identifier: 'payTypeInput',
            prompt: 'prompt'
          }
        },
        {
          on: 'blur'
        }
      );

    }

  });
<commit_msg>- data ready for input<commit_after>'use strict';

/**
 * @ngdoc function
 * @name ratemycoopApp.controller:ReviewformCtrl
 * @description
 * # ReviewformCtrl
 * Controller of the ratemycoopApp
 */
angular.module('ratemycoopApp')
  .controller('ReviewformCtrl', function ($scope, Company, Major, City, Perk, PayType, User, $routeParams) {
    $scope.loading = {
      main: true, // Promise, must be turned to false somewhere
      perks: true // Promise, must be turned to false somewhere
    };

    /**
     * Initialize Session
     */
    if (User.isAuthenticated()) {
      $scope.user = User.getCurrent(
        function (success) {
          $scope.formData.userId = success.id;
        }
      );
    } else {
      // TODO: Must handle unauthenticated and redirect to login screen.
      console.log('ERROR: User must be authenticated');
      $scope.user = null;
    }

    /**
     * Used if we want to fetch for pay types, as opposed to using just
     * $scope.payTypes
     */
    $scope.fetchedPayTypes = PayType.find({},
      function (success) {
      });

    $scope.payTypes = [{id: 1, name: "Hourly"}, {id: 2, name: "Salary"}, {id: 3, name: "Stipend"}];

    /**
     * Get company info on-load
     */
    $scope.company = Company.findOne({
        filter: {
          where: {name: $routeParams.companyname},
          include: ['perks', 'majors', 'reviews', {'locations': 'region'}]
        }
      },
      function (successData) {
        $scope.loading.main = false;
      }
    );

    /**
     * Get major info on-load
     */
    $scope.majors = Major.find({},
      function (successData) {
        angular.forEach(successData, function (result) {
          result.title = result.name;
          result.description = result.code;
        });

        $('#majorSearch').search({
          source: $scope.majors,
          maxResults: 4,
          searchFields: ['code', 'name']
        })
      }
    );

    $scope.allPerks = Perk.find({},
      function (successData) {
        angular.forEach(successData, function (value) {
          value['isSelected'] = false;
        });
        $scope.loading.perks = false;
        // Success allperks
      }
    );

    $scope.addPerk = function (perk) {
      perk.isSelected = true; //This toggles ui change
      $scope.formData.perks.push(perk.id); // This adds only id, to formData.perks
    };

    $scope.unselectPerk = function (perk) {
      perk.isSelected = false; // this toggles ui change
      var i = $scope.formData.perks.indexOf(perk.id); // this finds and removes perk id from perks
      if (i > -1) {
        $scope.formData.perks.splice(i, 1);
      }

    };

    $scope.printFormData = function () {
      console.log($scope.formData);
    };

    $scope.formData = {
      overallRating: 0,
      cultureRating: 0,
      difficultyRating: 0,

      description: "",

      pay: "",
      payTypeId: $scope.payTypes[0].id,

      //userId: $scope.user.id == set when async call to USER returns

      perks: [],

      returnOffer: false,
      recommend: false,
      anonymous: false

    };

    $scope.submitReview = function () {
      console.log("Review is being submitted :) ");
      var pushObject = prepForPush($scope.formData);
    };

    function prepForPush(formData) {
      // Validate pay input:
      var isValidPay = formData.pay.search(/^\$?[\d,]+(\.\d*)?$/) >= 0;
      if (isValidPay) {
        formData.pay = formData.pay.replace(/[^0-9\.]/g, '');
      } else {
        formData.pay = null;
      }

      var pushObj = {
        anonymous: formData.anonymous,
        returnOffer: formData.returnOffer,
        recommend: formData.recommend,
        description: formData.description,
        userId: formData.userId,
        companyId: $scope.company.id,
        payTypeId: formData.payTypeId,
        pay: formData.pay,
        perks: formData.perks
      }
    }

    /**
     * Wizard variables.
     * @type {{currStep: string, s1: string, s2: string, s3: string}}
     */
    $scope.wizard = {
      currStep: "wizardStepOne",
      s1: "wizardStepOne",
      s2: "wizardStepTwo",
      s3: "wizardStepThree"
    };

    angular.element(document).ready(function () {
      setTimeout(setupSemantic, 400);
    });

    function setupSemantic() {
      $('.ui.accordion').accordion();
      $('.ui.selection.dropdown').dropdown();
      $('#payType').dropdown();
      $('.rating').rating({
        /* see http://bit.ly/1M0OaL9 of why we need to do this */
        onRate: function (val) {
          $scope.$apply(function () {
            var ratings = $('.rating').rating('get rating');
            $scope.formData.overallRating = ratings[0];
            $scope.formData.cultureRating = ratings[1];
            $scope.formData.difficultyRating = ratings[2];
          });
        }
      });
      $('#privacyCheckbox').checkbox({
        onChange: function () {
          /* see http://bit.ly/1M0OaL9 of why we need to do this */
          $scope.$apply(function () {
            $scope.formData.anonymous = !$scope.formData.anonymous;
          });
        }
      });
      $('#returnOfferCheckbox').checkbox({
        onChange: function () {
          /* see http://bit.ly/1M0OaL9 of why we need to do this */
          $scope.$apply(function () {
            $scope.formData.returnOffer = !$scope.formData.returnOffer;
          });
        }
      });
      $('#recommendCheckbox').checkbox({
        onChange: function () {
          /* see http://bit.ly/1M0OaL9 of why we need to do this */
          $scope.$apply(function () {
            $scope.formData.recommend = !$scope.formData.recommend;
          });
        }
      });

      $('#locationSearch').search({
        apiSettings: {
          //TODO: not hardcode url, use another system for searching
          url: "https://ratemycoop.io/api/v1/Cities/search?query={query}"
        },
        searchFields: ['name']

      });

      $('#reviewForm').form(
        {
          major: {
            identifier: 'majorSearchInput',
            rules: [{
              type: 'empty',
              prompt: 'Please enter your major'
            }]
          },
          city: {
            identifier: 'locationSearchInput',
            rules: [{
              type: 'empty',
              prompt: 'Please enter your major'
            }]
          },
          pay: {
            identifier: 'payInput',
            rules: [
              {
                type: 'empty',
                prompt: 'Please enter a valid pay'
              },
              {
                type: 'length[2]'
              }
            ]
          },
          payType: {
            identifier: 'payTypeInput',
            prompt: 'prompt'
          }
        },
        {
          on: 'blur'
        }
      );

    }

  });
<|endoftext|>


<commit_before>require("ember-handlebars/ext");
require("ember-views/views/collection_view");
require("ember-handlebars/views/metamorph_view");

/**
@module ember
@submodule ember-handlebars
*/

var get = Ember.get, set = Ember.set;
var fmt = Ember.String.fmt;

Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
  init: function() {
    var itemController = get(this, 'itemController');
    var binding;

    if (itemController) {
      var controller = get(this, 'controller.container').lookupFactory('controller:array').create({
        parentController: get(this, 'controller'),
        itemController: itemController,
        target: get(this, 'controller'),
        _eachView: this
      });

      this.disableContentObservers(function() {
        set(this, 'content', controller);
        binding = new Ember.Binding('content', '_eachView.dataSource').oneWay();
        binding.connect(controller);
      });

      set(this, '_arrayController', controller);
    } else {
      this.disableContentObservers(function() {
        binding = new Ember.Binding('content', 'dataSource').oneWay();
        binding.connect(this);
      });
    }

    return this._super();
  },

  _assertArrayLike: function(content) {
    Ember.assert(fmt("The value that #each loops over must be an Array. You " +
                     "passed %@, but it should have been an ArrayController",
                     [content.constructor]),
                     !Ember.ControllerMixin.detect(content) ||
                       (content && content.isGenerated) ||
                       content instanceof Ember.ArrayController);
    Ember.assert(fmt("The value that #each loops over must be an Array. You passed %@", [(Ember.ControllerMixin.detect(content) && content.get('model') !== undefined) ? fmt("'%@' (wrapped in %@)", [content.get('model'), content]) : content]), Ember.Array.detect(content));
  },

  disableContentObservers: function(callback) {
    Ember.removeBeforeObserver(this, 'content', null, '_contentWillChange');
    Ember.removeObserver(this, 'content', null, '_contentDidChange');

    callback.call(this);

    Ember.addBeforeObserver(this, 'content', null, '_contentWillChange');
    Ember.addObserver(this, 'content', null, '_contentDidChange');
  },

  itemViewClass: Ember._MetamorphView,
  emptyViewClass: Ember._MetamorphView,

  createChildView: function(view, attrs) {
    view = this._super(view, attrs);

    // At the moment, if a container view subclass wants
    // to insert keywords, it is responsible for cloning
    // the keywords hash. This will be fixed momentarily.
    var keyword = get(this, 'keyword');
    var content = get(view, 'content');

    if (keyword) {
      var data = get(view, 'templateData');

      data = Ember.copy(data);
      data.keywords = view.cloneKeywords();
      set(view, 'templateData', data);

      // In this case, we do not bind, because the `content` of
      // a #each item cannot change.
      data.keywords[keyword] = content;
    }

    // If {{#each}} is looping over an array of controllers,
    // point each child view at their respective controller.
    if (content && get(content, 'isController')) {
      set(view, 'controller', content);
    }

    return view;
  },

  destroy: function() {
    if (!this._super()) { return; }

    var arrayController = get(this, '_arrayController');

    if (arrayController) {
      arrayController.destroy();
    }

    return this;
  }
});

var GroupedEach = Ember.Handlebars.GroupedEach = function(context, path, options) {
  var self = this,
      normalized = Ember.Handlebars.normalizePath(context, path, options.data);

  this.context = context;
  this.path = path;
  this.options = options;
  this.template = options.fn;
  this.containingView = options.data.view;
  this.normalizedRoot = normalized.root;
  this.normalizedPath = normalized.path;
  this.content = this.lookupContent();

  this.addContentObservers();
  this.addArrayObservers();

  this.containingView.on('willClearRender', function() {
    self.destroy();
  });
};

GroupedEach.prototype = {
  contentWillChange: function() {
    this.removeArrayObservers();
  },

  contentDidChange: function() {
    this.content = this.lookupContent();
    this.addArrayObservers();
    this.rerenderContainingView();
  },

  contentArrayWillChange: Ember.K,

  contentArrayDidChange: function() {
    this.rerenderContainingView();
  },

  lookupContent: function() {
    return Ember.Handlebars.get(this.normalizedRoot, this.normalizedPath, this.options);
  },

  addArrayObservers: function() {
    if (!this.content) { return; }

    this.content.addArrayObserver(this, {
      willChange: 'contentArrayWillChange',
      didChange: 'contentArrayDidChange'
    });
  },

  removeArrayObservers: function() {
    if (!this.content) { return; }

    this.content.removeArrayObserver(this, {
      willChange: 'contentArrayWillChange',
      didChange: 'contentArrayDidChange'
    });
  },

  addContentObservers: function() {
    Ember.addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange);
    Ember.addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange);
  },

  removeContentObservers: function() {
    Ember.removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange);
    Ember.removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange);
  },

  render: function() {
    if (!this.content) { return; }

    var content = this.content,
        contentLength = get(content, 'length'),
        data = this.options.data,
        template = this.template;

    data.insideEach = true;
    for (var i = 0; i < contentLength; i++) {
      template(content.objectAt(i), { data: data });
    }
  },

  rerenderContainingView: function() {
    var self = this;
    Ember.run.scheduleOnce('render', this, function() {
      // It's possible it's been destroyed after we enqueued a re-render call.
      if (!self.destroyed) {
        self.containingView.rerender();
      }
    });
  },

  destroy: function() {
    this.removeContentObservers();
    if (this.content) {
      this.removeArrayObservers();
    }
    this.destroyed = true;
  }
};

/**
  The `{{#each}}` helper loops over elements in a collection, rendering its
  block once for each item. It is an extension of the base Handlebars `{{#each}}`
  helper:

  ```javascript
  Developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}];
  ```

  ```handlebars
  {{#each Developers}}
    {{name}}
  {{/each}}
  ```

  `{{each}}` supports an alternative syntax with element naming:

  ```handlebars
  {{#each person in Developers}}
    {{person.name}}
  {{/each}}
  ```

  When looping over objects that do not have properties, `{{this}}` can be used
  to render the object:

  ```javascript
  DeveloperNames = ['Yehuda', 'Tom', 'Paul']
  ```

  ```handlebars
  {{#each DeveloperNames}}
    {{this}}
  {{/each}}
  ```
  ### {{else}} condition
  `{{#each}}` can have a matching `{{else}}`. The contents of this block will render
  if the collection is empty.

  ```
  {{#each person in Developers}}
    {{person.name}}
  {{else}}
    <p>Sorry, nobody is available for this task.</p>
  {{/each}}
  ```
  ### Specifying a View class for items
  If you provide an `itemViewClass` option that references a view class
  with its own `template` you can omit the block.

  The following template:

  ```handlebars
  {{#view App.MyView }}
    {{each view.items itemViewClass="App.AnItemView"}}
  {{/view}}
  ```

  And application code

  ```javascript
  App = Ember.Application.create({
    MyView: Ember.View.extend({
      items: [
        Ember.Object.create({name: 'Dave'}),
        Ember.Object.create({name: 'Mary'}),
        Ember.Object.create({name: 'Sara'})
      ]
    })
  });

  App.AnItemView = Ember.View.extend({
    template: Ember.Handlebars.compile("Greetings {{name}}")
  });
  ```

  Will result in the HTML structure below

  ```html
  <div class="ember-view">
    <div class="ember-view">Greetings Dave</div>
    <div class="ember-view">Greetings Mary</div>
    <div class="ember-view">Greetings Sara</div>
  </div>
  ```

  If an `itemViewClass` is defined on the helper, and therefore the helper is not
  being used as a block, an `emptyViewClass` can also be provided optionally.
  The `emptyViewClass` will match the behavior of the `{{else}}` condition
  described above. That is, the `emptyViewClass` will render if the collection
  is empty.

  ### Representing each item with a Controller.
  By default the controller lookup within an `{{#each}}` block will be
  the controller of the template where the `{{#each}}` was used. If each
  item needs to be presented by a custom controller you can provide a
  `itemController` option which references a controller by lookup name.
  Each item in the loop will be wrapped in an instance of this controller
  and the item itself will be set to the `content` property of that controller.

  This is useful in cases where properties of model objects need transformation
  or synthesis for display:

  ```javascript
  App.DeveloperController = Ember.ObjectController.extend({
    isAvailableForHire: function() {
      return !this.get('content.isEmployed') && this.get('content.isSeekingWork');
    }.property('isEmployed', 'isSeekingWork')
  })
  ```

  ```handlebars
  {{#each person in developers itemController="developer"}}
    {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}}
  {{/each}}
  ```

  Each itemController will receive a reference to the current controller as
  a `parentController` property.

  ### (Experimental) Grouped Each

  When used in conjunction with the experimental [group helper](https://github.com/emberjs/group-helper),
  you can inform Handlebars to re-render an entire group of items instead of
  re-rendering them one at a time (in the event that they are changed en masse
  or an item is added/removed).

  ```handlebars
  {{#group}}
    {{#each people}}
      {{firstName}} {{lastName}}
    {{/each}}
  {{/group}}
  ```

  This can be faster than the normal way that Handlebars re-renders items
  in some cases.

  If for some reason you have a group with more than one `#each`, you can make
  one of the collections be updated in normal (non-grouped) fashion by setting
  the option `groupedRows=true` (counter-intuitive, I know).

  For example,

  ```handlebars
  {{dealershipName}}

  {{#group}}
    {{#each dealers}}
      {{firstName}} {{lastName}}
    {{/each}}

    {{#each car in cars groupedRows=true}}
      {{car.make}} {{car.model}} {{car.color}}
    {{/each}}
  {{/group}}
  ```
  Any change to `dealershipName` or the `dealers` collection will cause the
  entire group to be re-rendered. However, changes to the `cars` collection
  will be re-rendered individually (as normal).

  Note that `group` behavior is also disabled by specifying an `itemViewClass`.

  @method each
  @for Ember.Handlebars.helpers
  @param [name] {String} name for item (used with `in`)
  @param [path] {String} path
  @param [options] {Object} Handlebars key/value pairs of options
  @param [options.itemViewClass] {String} a path to a view class used for each item
  @param [options.itemController] {String} name of a controller to be created for each item
  @param [options.groupedRows] {boolean} enable normal item-by-item rendering when inside a `#group` helper
*/
Ember.Handlebars.registerHelper('each', function eachHelper(path, options) {
  if (arguments.length === 4) {
    Ember.assert("If you pass more than one argument to the each helper, it must be in the form #each foo in bar", arguments[1] === "in");

    var keywordName = arguments[0];

    options = arguments[3];
    path = arguments[2];
    if (path === '') { path = "this"; }

    options.hash.keyword = keywordName;
  }

  if (arguments.length === 1) {
    options = path;
    path = 'this';
  }

  options.hash.dataSourceBinding = path;
  // Set up emptyView as a metamorph with no tag
  //options.hash.emptyViewClass = Ember._MetamorphView;

  if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) {
    new Ember.Handlebars.GroupedEach(this, path, options).render();
  } else {
    return Ember.Handlebars.helpers.collection.call(this, 'Ember.Handlebars.EachView', options);
  }
});
<commit_msg>remove unneeded get<commit_after>require("ember-handlebars/ext");
require("ember-views/views/collection_view");
require("ember-handlebars/views/metamorph_view");

/**
@module ember
@submodule ember-handlebars
*/

var get = Ember.get, set = Ember.set;
var fmt = Ember.String.fmt;

Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
  init: function() {
    var itemController = get(this, 'itemController');
    var binding;

    if (itemController) {
      var controller = get(this, 'controller.container').lookupFactory('controller:array').create({
        parentController: get(this, 'controller'),
        itemController: itemController,
        target: get(this, 'controller'),
        _eachView: this
      });

      this.disableContentObservers(function() {
        set(this, 'content', controller);
        binding = new Ember.Binding('content', '_eachView.dataSource').oneWay();
        binding.connect(controller);
      });

      set(this, '_arrayController', controller);
    } else {
      this.disableContentObservers(function() {
        binding = new Ember.Binding('content', 'dataSource').oneWay();
        binding.connect(this);
      });
    }

    return this._super();
  },

  _assertArrayLike: function(content) {
    Ember.assert(fmt("The value that #each loops over must be an Array. You " +
                     "passed %@, but it should have been an ArrayController",
                     [content.constructor]),
                     !Ember.ControllerMixin.detect(content) ||
                       (content && content.isGenerated) ||
                       content instanceof Ember.ArrayController);
    Ember.assert(fmt("The value that #each loops over must be an Array. You passed %@", [(Ember.ControllerMixin.detect(content) && content.get('model') !== undefined) ? fmt("'%@' (wrapped in %@)", [content.get('model'), content]) : content]), Ember.Array.detect(content));
  },

  disableContentObservers: function(callback) {
    Ember.removeBeforeObserver(this, 'content', null, '_contentWillChange');
    Ember.removeObserver(this, 'content', null, '_contentDidChange');

    callback.call(this);

    Ember.addBeforeObserver(this, 'content', null, '_contentWillChange');
    Ember.addObserver(this, 'content', null, '_contentDidChange');
  },

  itemViewClass: Ember._MetamorphView,
  emptyViewClass: Ember._MetamorphView,

  createChildView: function(view, attrs) {
    view = this._super(view, attrs);

    // At the moment, if a container view subclass wants
    // to insert keywords, it is responsible for cloning
    // the keywords hash. This will be fixed momentarily.
    var keyword = get(this, 'keyword');
    var content = get(view, 'content');

    if (keyword) {
      var data = get(view, 'templateData');

      data = Ember.copy(data);
      data.keywords = view.cloneKeywords();
      set(view, 'templateData', data);

      // In this case, we do not bind, because the `content` of
      // a #each item cannot change.
      data.keywords[keyword] = content;
    }

    // If {{#each}} is looping over an array of controllers,
    // point each child view at their respective controller.
    if (content && content.isController) {
      set(view, 'controller', content);
    }

    return view;
  },

  destroy: function() {
    if (!this._super()) { return; }

    var arrayController = get(this, '_arrayController');

    if (arrayController) {
      arrayController.destroy();
    }

    return this;
  }
});

var GroupedEach = Ember.Handlebars.GroupedEach = function(context, path, options) {
  var self = this,
      normalized = Ember.Handlebars.normalizePath(context, path, options.data);

  this.context = context;
  this.path = path;
  this.options = options;
  this.template = options.fn;
  this.containingView = options.data.view;
  this.normalizedRoot = normalized.root;
  this.normalizedPath = normalized.path;
  this.content = this.lookupContent();

  this.addContentObservers();
  this.addArrayObservers();

  this.containingView.on('willClearRender', function() {
    self.destroy();
  });
};

GroupedEach.prototype = {
  contentWillChange: function() {
    this.removeArrayObservers();
  },

  contentDidChange: function() {
    this.content = this.lookupContent();
    this.addArrayObservers();
    this.rerenderContainingView();
  },

  contentArrayWillChange: Ember.K,

  contentArrayDidChange: function() {
    this.rerenderContainingView();
  },

  lookupContent: function() {
    return Ember.Handlebars.get(this.normalizedRoot, this.normalizedPath, this.options);
  },

  addArrayObservers: function() {
    if (!this.content) { return; }

    this.content.addArrayObserver(this, {
      willChange: 'contentArrayWillChange',
      didChange: 'contentArrayDidChange'
    });
  },

  removeArrayObservers: function() {
    if (!this.content) { return; }

    this.content.removeArrayObserver(this, {
      willChange: 'contentArrayWillChange',
      didChange: 'contentArrayDidChange'
    });
  },

  addContentObservers: function() {
    Ember.addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange);
    Ember.addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange);
  },

  removeContentObservers: function() {
    Ember.removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange);
    Ember.removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange);
  },

  render: function() {
    if (!this.content) { return; }

    var content = this.content,
        contentLength = get(content, 'length'),
        data = this.options.data,
        template = this.template;

    data.insideEach = true;
    for (var i = 0; i < contentLength; i++) {
      template(content.objectAt(i), { data: data });
    }
  },

  rerenderContainingView: function() {
    var self = this;
    Ember.run.scheduleOnce('render', this, function() {
      // It's possible it's been destroyed after we enqueued a re-render call.
      if (!self.destroyed) {
        self.containingView.rerender();
      }
    });
  },

  destroy: function() {
    this.removeContentObservers();
    if (this.content) {
      this.removeArrayObservers();
    }
    this.destroyed = true;
  }
};

/**
  The `{{#each}}` helper loops over elements in a collection, rendering its
  block once for each item. It is an extension of the base Handlebars `{{#each}}`
  helper:

  ```javascript
  Developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}];
  ```

  ```handlebars
  {{#each Developers}}
    {{name}}
  {{/each}}
  ```

  `{{each}}` supports an alternative syntax with element naming:

  ```handlebars
  {{#each person in Developers}}
    {{person.name}}
  {{/each}}
  ```

  When looping over objects that do not have properties, `{{this}}` can be used
  to render the object:

  ```javascript
  DeveloperNames = ['Yehuda', 'Tom', 'Paul']
  ```

  ```handlebars
  {{#each DeveloperNames}}
    {{this}}
  {{/each}}
  ```
  ### {{else}} condition
  `{{#each}}` can have a matching `{{else}}`. The contents of this block will render
  if the collection is empty.

  ```
  {{#each person in Developers}}
    {{person.name}}
  {{else}}
    <p>Sorry, nobody is available for this task.</p>
  {{/each}}
  ```
  ### Specifying a View class for items
  If you provide an `itemViewClass` option that references a view class
  with its own `template` you can omit the block.

  The following template:

  ```handlebars
  {{#view App.MyView }}
    {{each view.items itemViewClass="App.AnItemView"}}
  {{/view}}
  ```

  And application code

  ```javascript
  App = Ember.Application.create({
    MyView: Ember.View.extend({
      items: [
        Ember.Object.create({name: 'Dave'}),
        Ember.Object.create({name: 'Mary'}),
        Ember.Object.create({name: 'Sara'})
      ]
    })
  });

  App.AnItemView = Ember.View.extend({
    template: Ember.Handlebars.compile("Greetings {{name}}")
  });
  ```

  Will result in the HTML structure below

  ```html
  <div class="ember-view">
    <div class="ember-view">Greetings Dave</div>
    <div class="ember-view">Greetings Mary</div>
    <div class="ember-view">Greetings Sara</div>
  </div>
  ```

  If an `itemViewClass` is defined on the helper, and therefore the helper is not
  being used as a block, an `emptyViewClass` can also be provided optionally.
  The `emptyViewClass` will match the behavior of the `{{else}}` condition
  described above. That is, the `emptyViewClass` will render if the collection
  is empty.

  ### Representing each item with a Controller.
  By default the controller lookup within an `{{#each}}` block will be
  the controller of the template where the `{{#each}}` was used. If each
  item needs to be presented by a custom controller you can provide a
  `itemController` option which references a controller by lookup name.
  Each item in the loop will be wrapped in an instance of this controller
  and the item itself will be set to the `content` property of that controller.

  This is useful in cases where properties of model objects need transformation
  or synthesis for display:

  ```javascript
  App.DeveloperController = Ember.ObjectController.extend({
    isAvailableForHire: function() {
      return !this.get('content.isEmployed') && this.get('content.isSeekingWork');
    }.property('isEmployed', 'isSeekingWork')
  })
  ```

  ```handlebars
  {{#each person in developers itemController="developer"}}
    {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}}
  {{/each}}
  ```

  Each itemController will receive a reference to the current controller as
  a `parentController` property.

  ### (Experimental) Grouped Each

  When used in conjunction with the experimental [group helper](https://github.com/emberjs/group-helper),
  you can inform Handlebars to re-render an entire group of items instead of
  re-rendering them one at a time (in the event that they are changed en masse
  or an item is added/removed).

  ```handlebars
  {{#group}}
    {{#each people}}
      {{firstName}} {{lastName}}
    {{/each}}
  {{/group}}
  ```

  This can be faster than the normal way that Handlebars re-renders items
  in some cases.

  If for some reason you have a group with more than one `#each`, you can make
  one of the collections be updated in normal (non-grouped) fashion by setting
  the option `groupedRows=true` (counter-intuitive, I know).

  For example,

  ```handlebars
  {{dealershipName}}

  {{#group}}
    {{#each dealers}}
      {{firstName}} {{lastName}}
    {{/each}}

    {{#each car in cars groupedRows=true}}
      {{car.make}} {{car.model}} {{car.color}}
    {{/each}}
  {{/group}}
  ```
  Any change to `dealershipName` or the `dealers` collection will cause the
  entire group to be re-rendered. However, changes to the `cars` collection
  will be re-rendered individually (as normal).

  Note that `group` behavior is also disabled by specifying an `itemViewClass`.

  @method each
  @for Ember.Handlebars.helpers
  @param [name] {String} name for item (used with `in`)
  @param [path] {String} path
  @param [options] {Object} Handlebars key/value pairs of options
  @param [options.itemViewClass] {String} a path to a view class used for each item
  @param [options.itemController] {String} name of a controller to be created for each item
  @param [options.groupedRows] {boolean} enable normal item-by-item rendering when inside a `#group` helper
*/
Ember.Handlebars.registerHelper('each', function eachHelper(path, options) {
  if (arguments.length === 4) {
    Ember.assert("If you pass more than one argument to the each helper, it must be in the form #each foo in bar", arguments[1] === "in");

    var keywordName = arguments[0];

    options = arguments[3];
    path = arguments[2];
    if (path === '') { path = "this"; }

    options.hash.keyword = keywordName;
  }

  if (arguments.length === 1) {
    options = path;
    path = 'this';
  }

  options.hash.dataSourceBinding = path;
  // Set up emptyView as a metamorph with no tag
  //options.hash.emptyViewClass = Ember._MetamorphView;

  if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) {
    new Ember.Handlebars.GroupedEach(this, path, options).render();
  } else {
    return Ember.Handlebars.helpers.collection.call(this, 'Ember.Handlebars.EachView', options);
  }
});
<|endoftext|>


<commit_before>/* eslint-disable import/no-extraneous-dependencies */
import React, {PropTypes} from 'react'
import FormBuilderPropTypes from '../../FormBuilderPropTypes'
import ItemForm from './ItemForm'
import ItemPreview from './ItemPreview'
import ArrayContainer from './ArrayContainer'
import DropDownButton from 'part:@sanity/components/buttons/dropdown'
import Button from 'part:@sanity/components/buttons/default'
import Fieldset from 'part:@sanity/components/fieldsets/default'
import EditItemPopOver from 'part:@sanity/components/edititem/popover'
import DefaultList from 'part:@sanity/components/lists/default'
import GridList from 'part:@sanity/components/lists/grid'
import {SortableContainer, SortableElement} from 'react-sortable-hoc'

const SortableDefaultList = SortableContainer(DefaultList)

const SortableItem = SortableElement(props => {
  return (

      {props.children}

  )
})

export default class Arr extends React.Component {
  static displayName = 'Array';
  static valueContainer = ArrayContainer;

  static propTypes = {
    type: FormBuilderPropTypes.type,
    field: FormBuilderPropTypes.field,
    value: PropTypes.instanceOf(ArrayContainer),
    level: PropTypes.number,
    onChange: PropTypes.func,
    description: PropTypes.string
  };

  static defaultProps = {
    onChange() {}
  };

  static contextTypes = {
    formBuilder: PropTypes.object
  };

  state = {
    addItemField: null,
    editIndex: -1
  };

  handleAddBtnClick = () => {
    if (this.props.type.of.length > 1) {
      this.setState({selectType: true})
      return
    }

    this.append(this.createValueForField(this.props.type.of[0]))

    this.setState({
      selectType: false,
      editIndex: this.props.value.length
    })
  }

  insert(itemValue, position, atIndex) {
    const {onChange, value} = this.props
    if (value.isEmpty()) {
      onChange({
        patch: {
          type: 'set',
          value: [itemValue]
        }
      })
      return
    }
    onChange({
      patch: {
        path: [atIndex],
        type: 'insert',
        position: position,
        items: [itemValue]
      }
    })
  }

  prepend(value) {
    this.insert(value, 'before', 0)
  }

  append(value) {
    this.insert(value, 'after', -1)
  }

  createValueForField(field) {
    return {_type: field.type}
  }

  handleRemoveItem = index => {
    if (index === this.state.editIndex) {
      this.setState({editIndex: -1})
    }
    const patch = {
      type: 'unset',
      path: [index]
    }
    this.props.onChange({patch})
  }

  handleClose = () => {
    const {editIndex} = this.state
    const itemValue = this.props.value.at(editIndex)
    if (itemValue.isEmpty()) {
      this.handleRemoveItem(editIndex)
    }
    this.setState({editIndex: -1})
  }

  handleDropDownAction = menuItem => {
    this.append(this.createValueForField(menuItem.field))
  }

  renderSelectType() {
    const {type} = this.props

    const items = type.of.map((field, i) => {
      return {
        title: field.title || field.type,
        index: `action${i}`,
        field: field
      }
    })

    return (
      <DropDownButton items={items} ripple inverted kind="add" onAction={this.handleDropDownAction}>
        New {this.props.field.title}
      </DropDownButton>
    )
  }

  handleItemChange = (event, index) => {
    const {onChange} = this.props
    // Rewrite patch by prepending the item index to its path
    onChange({
      patch: {
        ...event.patch,
        path: [index, ...(event.patch.path || [])]
      }
    })
  }

  handleItemEdit = index => {
    this.setState({editIndex: index})
  }

  handleMove = event => {
    this.props.onChange({
      patch: {
        type: 'move',
        value: {from: event.oldIndex, to: event.newIndex}
      }
    })
  }

  handleItemEnter = () => {
    this.setState({editIndex: -1})
  }

  renderEditItemForm(index) {
    const itemValue = this.props.value.at(index)
    const itemField = this.getItemField(itemValue)
    const actions = [{kind: 'danger', title: 'Remove', handleClick: () => this.handleRemoveItem(index)}]
    return (
      <EditItemPopOver actions={actions} title={itemField.title} onClose={this.handleClose}>
        <ItemForm
          focus
          index={index}
          field={itemField}
          level={this.props.level + 1}
          value={itemValue}
          onChange={this.handleItemChange}
          onEnter={this.handleItemEnter}
          onRemove={this.handleRemoveItem}
        />
      </EditItemPopOver>
    )
  }

  getItemField(item) {
    const {type} = this.props
    return type.of.find(ofType => ofType.type === item.context.field.type)
  }

  renderItem = (item, index) => {
    const {type} = this.props
    const {editIndex} = this.state
    const itemField = this.getItemField(item)
    if (!itemField) {
      return (

Invalid type:
{JSON.stringify(item.context.field.type)}

Only allowed types are:
{JSON.stringify(type.of)}

      )
    }

    return (
      <SortableItem key={index} disabled={editIndex > 0} index={index}>
        <ItemPreview
          index={index}
          field={itemField}
          value={item}
          onEdit={this.handleItemEdit}
          onRemove={this.handleRemoveItem}
        />
        {editIndex === index && this.renderEditItemForm(editIndex)}
      </SortableItem>
    )
  }

  renderList() {
    const {value, type} = this.props
    if (type.options && type.options.view == 'grid') {
      return <GridList renderItem={this.renderItem} items={value.value} />
    }

    return (
      <SortableDefaultList
        lockAxis="y"
        distance={5}
        onSortEnd={this.handleMove}
        renderItem={this.renderItem}
        items={value.value}
        useDragHandle
        decoration="divider"
      />
    )
  }

  render() {
    const {field, level} = this.props

    return (
      <Fieldset legend={field.title} description={field.description} level={level}>

        {this.renderList()}

          {
            this.props.type.of.length == 1
            && <Button onClick={this.handleAddBtnClick} ripple kind="add">
              Add
            </Button>
          }
          {
            this.props.type.of.length > 1 && this.renderSelectType()
          }

      </Fieldset>
    )
  }
}
<commit_msg>Don't use .isEmpty() for determining whether to emit set or insert<commit_after>/* eslint-disable import/no-extraneous-dependencies */
import React, {PropTypes} from 'react'
import FormBuilderPropTypes from '../../FormBuilderPropTypes'
import ItemForm from './ItemForm'
import ItemPreview from './ItemPreview'
import ArrayContainer from './ArrayContainer'
import DropDownButton from 'part:@sanity/components/buttons/dropdown'
import Button from 'part:@sanity/components/buttons/default'
import Fieldset from 'part:@sanity/components/fieldsets/default'
import EditItemPopOver from 'part:@sanity/components/edititem/popover'
import DefaultList from 'part:@sanity/components/lists/default'
import GridList from 'part:@sanity/components/lists/grid'
import {SortableContainer, SortableElement} from 'react-sortable-hoc'

const SortableDefaultList = SortableContainer(DefaultList)

const SortableItem = SortableElement(props => {
  return (

      {props.children}

  )
})

export default class Arr extends React.Component {
  static displayName = 'Array';
  static valueContainer = ArrayContainer;

  static propTypes = {
    type: FormBuilderPropTypes.type,
    field: FormBuilderPropTypes.field,
    value: PropTypes.instanceOf(ArrayContainer),
    level: PropTypes.number,
    onChange: PropTypes.func,
    description: PropTypes.string
  };

  static defaultProps = {
    onChange() {}
  };

  static contextTypes = {
    formBuilder: PropTypes.object
  };

  state = {
    addItemField: null,
    editIndex: -1
  };

  handleAddBtnClick = () => {
    if (this.props.type.of.length > 1) {
      this.setState({selectType: true})
      return
    }

    this.append(this.createValueForField(this.props.type.of[0]))

    this.setState({
      selectType: false,
      editIndex: this.props.value.length
    })
  }

  insert(itemValue, position, atIndex) {
    const {onChange, value} = this.props
    if (value.length === 0) {
      onChange({
        patch: {
          type: 'set',
          value: [itemValue]
        }
      })
      return
    }
    onChange({
      patch: {
        path: [atIndex],
        type: 'insert',
        position: position,
        items: [itemValue]
      }
    })
  }

  prepend(value) {
    this.insert(value, 'before', 0)
  }

  append(value) {
    this.insert(value, 'after', -1)
  }

  createValueForField(field) {
    return {_type: field.type}
  }

  handleRemoveItem = index => {
    if (index === this.state.editIndex) {
      this.setState({editIndex: -1})
    }
    const patch = {
      type: 'unset',
      path: [index]
    }
    this.props.onChange({patch})
  }

  handleClose = () => {
    const {editIndex} = this.state
    const itemValue = this.props.value.at(editIndex)
    if (itemValue.isEmpty()) {
      this.handleRemoveItem(editIndex)
    }
    this.setState({editIndex: -1})
  }

  handleDropDownAction = menuItem => {
    this.setState({editIndex: this.props.value.length})
    this.append(this.createValueForField(menuItem.field))
  }

  renderSelectType() {
    const {type} = this.props

    const items = type.of.map((field, i) => {
      return {
        title: field.title || field.type,
        index: `action${i}`,
        field: field
      }
    })

    return (
      <DropDownButton items={items} ripple inverted kind="add" onAction={this.handleDropDownAction}>
        New {this.props.field.title}
      </DropDownButton>
    )
  }

  handleItemChange = (event, index) => {
    const {onChange} = this.props
    // Rewrite patch by prepending the item index to its path
    onChange({
      patch: {
        ...event.patch,
        path: [index, ...(event.patch.path || [])]
      }
    })
  }

  handleItemEdit = index => {
    this.setState({editIndex: index})
  }

  handleMove = event => {
    this.props.onChange({
      patch: {
        type: 'move',
        value: {from: event.oldIndex, to: event.newIndex}
      }
    })
  }

  handleItemEnter = () => {
    this.setState({editIndex: -1})
  }

  renderEditItemForm(index) {
    const itemValue = this.props.value.at(index)
    const itemField = this.getItemField(itemValue)
    const actions = [{kind: 'danger', title: 'Remove', handleClick: () => this.handleRemoveItem(index)}]
    return (
      <EditItemPopOver actions={actions} title={itemField.title} onClose={this.handleClose}>
        <ItemForm
          focus
          index={index}
          field={itemField}
          level={this.props.level + 1}
          value={itemValue}
          onChange={this.handleItemChange}
          onEnter={this.handleItemEnter}
          onRemove={this.handleRemoveItem}
        />
      </EditItemPopOver>
    )
  }

  getItemField(item) {
    const {type} = this.props
    return type.of.find(ofType => ofType.type === item.context.field.type)
  }

  renderItem = (item, index) => {
    const {type} = this.props
    const {editIndex} = this.state
    const itemField = this.getItemField(item)
    if (!itemField) {
      return (

Invalid type:
{JSON.stringify(item.context.field.type)}

Only allowed types are:
{JSON.stringify(type.of)}

      )
    }

    return (
      <SortableItem key={index} disabled={editIndex > 0} index={index}>
        <ItemPreview
          index={index}
          field={itemField}
          value={item}
          onEdit={this.handleItemEdit}
          onRemove={this.handleRemoveItem}
        />
        {editIndex === index && this.renderEditItemForm(editIndex)}
      </SortableItem>
    )
  }

  renderList() {
    const {value, type} = this.props
    if (type.options && type.options.view == 'grid') {
      return <GridList renderItem={this.renderItem} items={value.value} />
    }

    return (
      <SortableDefaultList
        lockAxis="y"
        distance={5}
        onSortEnd={this.handleMove}
        renderItem={this.renderItem}
        items={value.value}
        useDragHandle
        decoration="divider"
      />
    )
  }

  render() {
    const {field, level} = this.props

    return (
      <Fieldset legend={field.title} description={field.description} level={level}>

        {this.renderList()}

          {
            this.props.type.of.length == 1
            && <Button onClick={this.handleAddBtnClick} ripple kind="add">
              Add
            </Button>
          }
          {
            this.props.type.of.length > 1 && this.renderSelectType()
          }

      </Fieldset>
    )
  }
}
<|endoftext|>


<commit_before>/* This function takes a mount ID and determines whether the French translation
 * has a sound rather than a quote (which almost all of them do).
 *
 * @params {object} mount - The mount object.
 *
 * @example
 * // Returns true - mount 1 has a sound in French.
 * require('sounds.js)({ id: 1, ... });
 *
 * @example
 * // Returns false - mount speaks French.
 * require('sounds.js)()
 *
 * @example
 * // Returns string - mount 2 makes a sound but also speaks French.
 * require('sounds.js)({ id: 2, ... });
 *
 * @returns {(bool|string)} - if it has a sound or a sound override.
 */
module.exports = (mount) => {
  const quote = mount.quote.fr;

  switch (mount.id) {
    case 4:
      return override('(bâillement)', '(yawning');

    case 6:
    case 141:
      return override('Identification en cours...', 'Identification in progress...');

    case 8:
      return override('(feulement)', '(growl)');

    case 9:
      return override('(regard fixe)', '(stare)');

    case 21:
      return override('Autorisation en cours...', 'Authorization in progress...');

    case 27:
      return override('(crépitement)', '(crackling)');

    case 48:
      return override('Mise à jour en cours...\\nNe pas éteindre le module.', 'Update in progress...\\nDo not turn off the module.')

    case 70:
      return override('Vers les cieux, compagnon!', 'Towards the heavens, companion!');

    case 91:
      return override('Bip bip... Mise à niveau des systèmes recommandée...', 'Beep beep... System upgrade recommended...');

    case 101:
      return override('Protocole de conduite responsable engagé', 'Responsible protocol of conduct engaged!')

    case 106:
      return override('Un petit œuf, deux petits œufs...', 'One small egg, two small eggs...')

    default:
      return true;
  }

  function override(match, replacement, stripNewLines) {
    // Throw an error if the quote no longer matches the test.
    if (quote !== match && !quote.match(match))
      throw new Error(
        'Mount ' + mount.id + ' sound "' + quote + '" doesn\'t match test `' + match.toString()
      );

    return quote.replace(match, replacement);
  }
}<commit_msg>Removed redundant !<commit_after>/* This function takes a mount ID and determines whether the French translation
 * has a sound rather than a quote (which almost all of them do).
 *
 * @params {object} mount - The mount object.
 *
 * @example
 * // Returns true - mount 1 has a sound in French.
 * require('sounds.js)({ id: 1, ... });
 *
 * @example
 * // Returns false - mount speaks French.
 * require('sounds.js)()
 *
 * @example
 * // Returns string - mount 2 makes a sound but also speaks French.
 * require('sounds.js)({ id: 2, ... });
 *
 * @returns {(bool|string)} - if it has a sound or a sound override.
 */
module.exports = (mount) => {
  const quote = mount.quote.fr;

  switch (mount.id) {
    case 4:
      return override('(bâillement)', '(yawning');

    case 6:
    case 141:
      return override('Identification en cours...', 'Identification in progress...');

    case 8:
      return override('(feulement)', '(growl)');

    case 9:
      return override('(regard fixe)', '(stare)');

    case 21:
      return override('Autorisation en cours...', 'Authorization in progress...');

    case 27:
      return override('(crépitement)', '(crackling)');

    case 48:
      return override('Mise à jour en cours...\\nNe pas éteindre le module.', 'Update in progress...\\nDo not turn off the module.')

    case 70:
      return override('Vers les cieux, compagnon!', 'Towards the heavens, companion!');

    case 91:
      return override('Bip bip... Mise à niveau des systèmes recommandée...', 'Beep beep... System upgrade recommended...');

    case 101:
      return override('Protocole de conduite responsable engagé', 'Responsible protocol of conduct engaged')

    case 106:
      return override('Un petit œuf, deux petits œufs...', 'One small egg, two small eggs...')

    default:
      return true;
  }

  function override(match, replacement, stripNewLines) {
    // Throw an error if the quote no longer matches the test.
    if (quote !== match && !quote.match(match))
      throw new Error(
        'Mount ' + mount.id + ' sound "' + quote + '" doesn\'t match test `' + match.toString()
      );

    return quote.replace(match, replacement);
  }
}<|endoftext|>


<commit_before>(function () {
  'use strict';

  var voicebaseMediaPlayer = function ($timeout, $compile, voicebasePlayerService, voicebaseUrl) {
    return {
      restrict: 'E',
      templateUrl: 'voicebase-media-player/directives/voicebase-media-player.tpl.html',
      scope: {
        token: '@',
        mediaId: '@',
        mediaUrl: '@',
        mediaType: '@',
        playerType: '@' // 'jwplayer' or 'video_js'
      },
      link: function (scope) {

        scope.$watch(function () {
          return voicebasePlayerService.getMediaReady();
        }, function (newValue) {
          if (newValue === true) {
            initPlayer();
          }
        });

        var initPlayer = function () {
          destroyPlayer();
          jQuery('.vbs-media-player').append('

');

          var $player = jQuery('#vbs-console-player-wrap');
          if(scope.playerType === 'video_js') {
            createVideoJsPlayer();
          }
          else if(scope.playerType === 'jwplayer') {
            createJwPlayer();
          }

          $player.voicebase({
            playerId: 'player',
            playerType: scope.playerType,
            apiUrl: voicebaseUrl.getBaseUrl() + '/',
            mediaID: scope.mediaId,
            token: scope.token,
            apiVersion: '2.0',
            mediaTypeOverride: checkType(),
            localSearch: true,
            localSearchHelperUrl: voicebasePortal.localSearchUrl,
            keywordsGroups: true,
            showPredictionsBlock: true,
            actionFlag: {
              downloadMedia: false,
              downloadTranscript: false,
              orderTranscript: false
            }
          });
        };

        var checkType = function () {
          var type = 'video';
          if(scope.mediaType.indexOf('video') > -1) {
            type = 'video';
          }
          else if (scope.mediaType.indexOf('audio') > -1) {
            type = 'audio';
          }
          return type;
        };

        var createVideoJsPlayer = function () {
          var playerDir = $compile('<videojs media-url="{{ mediaUrl }}" media-type="{{ mediaType }}"></videojs>')(scope);
          jQuery('#vbs-console-player-wrap').append(playerDir);
        };

        var createJwPlayer = function () {
          jQuery('#vbs-console-player-wrap').append('

');

          jwplayer('player').setup({
            file: scope.mediaUrl,
            primary: 'html5',
            width: '100%',
            height: '264'
          });
        };

        var destroyPlayer = function () {
          voicebasePlayerService.destroyVoicebase();
        };
      }
    };
  };

  angular.module('voicebasePlayerModule')
    .directive('voicebaseMediaPlayer', voicebaseMediaPlayer);

})();

<commit_msg>[V2-1034] - Remove sharing for media browser<commit_after>(function () {
  'use strict';

  var voicebaseMediaPlayer = function ($timeout, $compile, voicebasePlayerService, voicebaseUrl) {
    return {
      restrict: 'E',
      templateUrl: 'voicebase-media-player/directives/voicebase-media-player.tpl.html',
      scope: {
        token: '@',
        mediaId: '@',
        mediaUrl: '@',
        mediaType: '@',
        playerType: '@' // 'jwplayer' or 'video_js'
      },
      link: function (scope) {

        scope.$watch(function () {
          return voicebasePlayerService.getMediaReady();
        }, function (newValue) {
          if (newValue === true) {
            initPlayer();
          }
        });

        var initPlayer = function () {
          destroyPlayer();
          jQuery('.vbs-media-player').append('

');

          var $player = jQuery('#vbs-console-player-wrap');
          if(scope.playerType === 'video_js') {
            createVideoJsPlayer();
          }
          else if(scope.playerType === 'jwplayer') {
            createJwPlayer();
          }

          $player.voicebase({
            playerId: 'player',
            playerType: scope.playerType,
            apiUrl: voicebaseUrl.getBaseUrl() + '/',
            mediaID: scope.mediaId,
            token: scope.token,
            apiVersion: '2.0',
            mediaTypeOverride: checkType(),
            localSearch: true,
            localSearchHelperUrl: voicebasePortal.localSearchUrl,
            keywordsGroups: true,
            showPredictionsBlock: true,
            actionFlag: {
              downloadMedia: false,
              downloadTranscript: false,
              orderTranscript: false,
              share: false
            }
          });
        };

        var checkType = function () {
          var type = 'video';
          if(scope.mediaType.indexOf('video') > -1) {
            type = 'video';
          }
          else if (scope.mediaType.indexOf('audio') > -1) {
            type = 'audio';
          }
          return type;
        };

        var createVideoJsPlayer = function () {
          var playerDir = $compile('<videojs media-url="{{ mediaUrl }}" media-type="{{ mediaType }}"></videojs>')(scope);
          jQuery('#vbs-console-player-wrap').append(playerDir);
        };

        var createJwPlayer = function () {
          jQuery('#vbs-console-player-wrap').append('

');

          jwplayer('player').setup({
            file: scope.mediaUrl,
            primary: 'html5',
            width: '100%',
            height: '264'
          });
        };

        var destroyPlayer = function () {
          voicebasePlayerService.destroyVoicebase();
        };
      }
    };
  };

  angular.module('voicebasePlayerModule')
    .directive('voicebaseMediaPlayer', voicebaseMediaPlayer);

})();

<|endoftext|>