<commit_before>/**
 * @copyright 2014 Quri, Loïc CHOLLIER
 * @copyright 2015 Prometheus Research, LLC
 */

import autobind           from 'autobind-decorator';
import React, {PropTypes} from 'react';
import MinuteView         from './MinuteView';
import HourView           from './HourView';
import Glyphicon          from './Glyphicon';
import Constants          from './Constants';

export default class DateTimePickerTime extends React.Component {

  static propTypes = {
    viewDate: PropTypes.object.isRequired,
    selectedDate: PropTypes.object.isRequired,
    togglePeriod: PropTypes.func.isRequired,
    mode: PropTypes.oneOf([
      Constants.MODE_DATE,
      Constants.MODE_DATETIME,
      Constants.MODE_TIME
    ]),
    onSelectedDate: PropTypes.func.isRequired,
  };

  constructor(props) {
    super(props);
    this.state = {
      minutesDisplayed: false,
      hoursDisplayed: false
    };
  }

  render() {
    return (

        {this.renderPicker()}
        {this.state.hoursDisplayed &&
          <HourView
            onSelectedDate={this.props.onSelectedDate}
            selectedDate={this.props.selectedDate}
            onClose={this.goBack}
            />}
        {this.state.minutesDisplayed &&
          <MinuteView
            onSelectedDate={this.props.onSelectedDate}
            selectedDate={this.props.selectedDate}
            onClose={this.goBack}
            />}

    );
  }

  renderPicker() {
    if (!this.state.minutesDisplayed && !this.state.hoursDisplayed) {
      return (

                <Glyphicon glyph="chevron-up" />

                <Glyphicon glyph="chevron-up" />

                {this.props.selectedDate.format('HH')}
                :
                {this.props.selectedDate.format('mm')}

                <Glyphicon glyph="chevron-down" />

                <Glyphicon glyph="chevron-down" />

      );
    }
  }

  @autobind
  onPrevHour() {
    let selectedDate = this.props.selectedDate.subtract(1, 'hours');
    this.props.onSelectedDate(selectedDate);
  }

  @autobind
  onNextHour() {
    let selectedDate = this.props.selectedDate.add(1, 'hours');
    this.props.onSelectedDate(selectedDate);
  }

  @autobind
  onPrevMinute() {
    let selectedDate = this.props.selectedDate.subtract(1, 'minutes');
    this.props.onSelectedDate(selectedDate);
  }

  @autobind
  onNextMinute() {
    let selectedDate = this.props.selectedDate.add(1, 'minutes');
    this.props.onSelectedDate(selectedDate);
  }

  @autobind
  goBack() {
    return this.setState({
      minutesDisplayed: false,
      hoursDisplayed: false
    });
  }

  @autobind
  showMinutes() {
    return this.setState({
      minutesDisplayed: true
    });
  }

  @autobind
  showHours() {
    return this.setState({
      hoursDisplayed: true
    });
  }

}
<commit_msg>Remove <DateTimePickerTime /><commit_after><|endoftext|>


<commit_before>'use strict';

// var BrM = require('br-masks');

var m = angular.module('idf.br-filters', []);

// module.exports = m.name;

m.filter('percentage', ['$filter', function($filter) {
	return function(input, decimals) {
		if (angular.isUndefined(input) || input === null) {
			return input;
		}

		return $filter('number')(input * 100, decimals) + '%';
	};
}])
.filter('brCep', [function() {
	return function(input) {
		return BrM.cep(input);
	};
}])
.filter('brPhoneNumber', [function() {
	return function(input) {
		return BrM.phone(input);
	};
}])
.filter('brCpf', [function() {
	return function(input) {
		return BrM.cpf(input);
	};
}])
.filter('brCnpj', [function() {
	return function(input) {
		return BrM.cnpj(input);
	};
}])
.filter('brCpfCnpj', [function() {
	return function(input) {
		return BrM.cpfCnpj(input);
	};
}])
.filter('brIe', [function() {
	return function(input, uf) {
		return BrM.ie(input,uf);
	};
}])
.filter('finance', ['$locale', function($locale) {
	return function(input, currency, decimals) {
		if (angular.isUndefined(input) || input === null) {
			return input;
		}

		var decimalDelimiter = $locale.NUMBER_FORMATS.DECIMAL_SEP,
			thousandsDelimiter = $locale.NUMBER_FORMATS.GROUP_SEP,
			currencySym = '';

		if(currency === true) {
			currencySym = $locale.NUMBER_FORMATS.CURRENCY_SYM + ' ';
		} else if (currency) {
			currencySym = currency;
		}

		return currencySym + BrM.finance(input, decimals, decimalDelimiter, thousandsDelimiter);
	};
}])
.filter('nfeAccessKey', [function() {
	return function(input) {
		return BrM.nfeAccessKey(input);
	};
}]);
<commit_msg>Tentando alterar depois de colocar em produção<commit_after>'use strict';

// var BrM = require('br-masks');

var m = angular.module('idf.br-filters', []);

// module.exports = m.name;

m.filter('percentage', ['$filter', function($filter) {
	return function(input, decimals) {
		if (angular.isUndefined(input) || input === null) {
			return input;
		}

		return $filter('number')(input * 100, decimals) + '%';
	};
}])
.filter('brCep', [function() {
	return function(input) {
		return BrM.cep(input);
	};
}])
.filter('brPhoneNumber', [function() {
	return function(input) {
		return BrM.phone(input);
	};
}])
.filter('brCpf', [function() {
	return function(input) {
		return BrM.cpf(input);
	};
}])
.filter('brCnpj', [function() {
	return function(input) {
		return BrM.cnpj(input);
	};
}])
.filter('brCpfCnpj', [function() {
	return function(input) {
		return BrM.cpfCnpj(input);
	};
}])
.filter('brIe', [function() {
	return function(input, uf) {
		return BrM.ie(input,uf);
	};
}])
.filter('finance', ['$locale', function($locale) {
	return function(input, currency, decimals) {
		if (angular.isUndefined(input) || input === null) {
			return input;
		}

		var decimalDelimiter = $locale.NUMBER_FORMATS.DECIMAL_SEP,
			thousandsDelimiter = $locale.NUMBER_FORMATS.GROUP_SEP,
			currencySym = '';

		if(currency === true) {
			currencySym = $locale.NUMBER_FORMATS.CURRENCY_SYM + ' ';
		} else if (currency) {
			currencySym = currency;
		}

		return currencySym + BrM.finance(input, decimals, decimalDelimiter, thousandsDelimiter);
	};
}])
.filter('nfeAccessKey', [function() {
	return function(input) {
		return BrM.nfeAccessKey(input);
	};
}]);
<|endoftext|>


<commit_before>'use strict'
var Model = require('../model/model.js');
var CONST = require('../model/const.js');
var InterfaceUtil = require('../assets/interface-utils.js');
var Inputs = require('../triggers/inputs.js');

var _addInteractions = false
  , _showRegister = false
  , _pseudoEmpty = false
  , _emailEmpty = false
  , _interactionRegister = []
  , _interactionLogin = []
  , _state = -1;

function checkInteractions_(event) {
  if (event.type &&
    event.type  === CONST.eventType.UP){
    switch(event.key){
        case CONST.uiElements.BTN_CUSTO :
          _showRegister = true;
          break;
        case CONST.uiElements.BTN_OK :
          var inputPseudo = document.getElementById('pseudo-register');
          var inputEmail = document.getElementById('email-register');
          Model.gameModel.user = {}
          if (inputPseudo && inputPseudo.value){
            _pseudoEmpty = false;
            Model.gameModel.user.displayName = inputPseudo.value;
            inputPseudo.style.border = "";
            // TODO faire quelque chose avec le code de confirmation
          }else{
            _pseudoEmpty = true;
            inputPseudo.style.border = "thin solid red";
            inputPseudo.placeholder = "PSEUDO OBLIGATOIRE";
            // TODO
            return;

          }
          if (inputEmail && inputEmail.value){
            _emailEmpty = false;
            Model.gameModel.user.email = inputEmail.value;
            inputEmail.style.border = "";
            // TODO faire quelque chose avec le code de confirmation
          }else{
            _emailEmpty = true;
            inputEmail.style.border = "thin solid red";
            inputEmail.placeholder = "EMAIL OBLIGATOIRE";
            // TODO
            return;

          }
          document.body.removeChild(inputPseudo);
          document.body.removeChild(inputEmail);
          Model.ui.changeScreen = CONST.screens.CHOOSE_USER;
          break;
      }
    }
}

function registerInteractions_(){
  Inputs.registerInteraction({
    type : CONST.eventType.UP
    , key : [CONST.uiElements.BTN_CUSTO
          , CONST.uiElements.BTN_OK
          ]
    , callback : checkInteractions_
  });
}

function paintLogins_(position){
  var arrayInstructions = [];

  // Boutons de login
  var xBtns = 1.5;
  var ecart = 2;

  var positionGooglePlus = {
      x: xBtns
    , y : position.y + 3
  }
  arrayInstructions.push({
      key : 'socials' // Sprite
      , wOriValue : CONST.ui.UNIT // wOriValue
      , hOriValue : CONST.ui.UNIT // hOriValue
      , rowOri :  0 // rowOri
      , colOri : 1 // colOri
      , rowDest :  positionGooglePlus.y // rowDest
      , colDest :  positionGooglePlus.x // colDest
    });
  arrayInstructions.push({drawText : true
      , text : "Google "
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionGooglePlus.x + 2) // X
      , y : CONST.ui.UNIT * (positionGooglePlus.y + 1)  - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (position.w - 2 - 5) // Max Width
      , lineHeight : 30 // Line Height
  });

  var positionTwitter = {
      x: xBtns
    , y : positionGooglePlus.y + ecart
  }
  arrayInstructions.push({
      key : 'socials' // Sprite
      , wOriValue : CONST.ui.UNIT // wOriValue
      , hOriValue : CONST.ui.UNIT // hOriValue
      , rowOri :  1 // rowOri
      , colOri : 1 // colOri
      , rowDest :  positionTwitter.y // rowDest
      , colDest :  positionTwitter.x // colDest
    });
  arrayInstructions.push({drawText : true
      , text : "Twitter"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionTwitter.x + 2) // X
      , y : CONST.ui.UNIT * (positionTwitter.y + 1)  - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (position.w - 2 - 5) // Max Width
      , lineHeight : 30 // Line Height
  });

  var positionGithub = {
      x: xBtns
    , y : positionTwitter.y + ecart
  }
  arrayInstructions.push({
      key : 'socials' // Sprite
      , wOriValue : CONST.ui.UNIT // wOriValue
      , hOriValue : CONST.ui.UNIT // hOriValue
      , rowOri :  0 // rowOri
      , colOri : 0 // colOri
      , rowDest :  positionGithub.y // rowDest
      , colDest :  positionGithub.x // colDest
    });
  arrayInstructions.push({drawText : true
      , text : "Github"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionGithub.x + 2) // X
      , y : CONST.ui.UNIT * (positionGithub.y + 1)  - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (position.w - 2 - 5) // Max Width
      , lineHeight : 30 // Line Height
  });

  var positionCusto = {
      x: xBtns
    , y : positionGithub.y + ecart
  }
  arrayInstructions.push({
      key : 'socials' // Sprite
      , wOriValue : CONST.ui.UNIT // wOriValue
      , hOriValue : CONST.ui.UNIT // hOriValue
      , rowOri :  1 // rowOri
      , colOri : 0 // colOri
      , rowDest :  positionCusto.y // rowDest
      , colDest :  positionCusto.x // colDest
    });
  arrayInstructions.push({drawText : true
      , text : "Créer son compte"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionCusto.x + 2) // X
      , y : CONST.ui.UNIT * (positionCusto.y + 1)  - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (position.w - 4) // Max Width
      , lineHeight : 30 // Line Height
  });

  // Mise à jour de la map d'interaction
  if (_interactionLogin.length === 0 ){
    var interaction = [];
    _interactionLogin = interaction;
    interaction.push({
        x : CONST.ui.UNIT * positionGooglePlus.x
      , y : CONST.ui.UNIT * positionGooglePlus.y
      , w : CONST.ui.UNIT
      , h : CONST.ui.UNIT
      , key : CONST.uiElements.BTN_G_PLUS
    });
    interaction.push({
        x : CONST.ui.UNIT * positionTwitter.x
      , y : CONST.ui.UNIT * positionTwitter.y
      , w : CONST.ui.UNIT
      , h : CONST.ui.UNIT
      , key : CONST.uiElements.BTN_TWITTER
    });
    interaction.push({
        x : CONST.ui.UNIT * positionGithub.x
      , y : CONST.ui.UNIT * positionGithub.y
      , w : CONST.ui.UNIT
      , h : CONST.ui.UNIT
      , key : CONST.uiElements.BTN_GITHUB
    });
    interaction.push({
        x : CONST.ui.UNIT * positionCusto.x
      , y : CONST.ui.UNIT * positionCusto.y
      , w : CONST.ui.UNIT
      , h : CONST.ui.UNIT
      , key : CONST.uiElements.BTN_CUSTO
    });
  }

  return arrayInstructions;

}

function paintRegister_(position){
  var arrayInstructions = [];

  var positionPseudo = {
    x : position.x + 0.5,
    y : position.y + 2,
    w : Model.ui.screenSize.width - 1
  };
  arrayInstructions.push({drawText : true
      , text : "Pseudo"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionPseudo.x + 1) // X
      , y : CONST.ui.UNIT * (positionPseudo.y + 1) - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (positionPseudo.w - 2) // Max Width
      , lineHeight : 30 // Line Height
  });
  // Gestion du champ de saisie du pseudo
  var inputPseudo = document.getElementById('pseudo-register');
  if (!inputPseudo){
    inputPseudo = document.createElement('input');
    inputPseudo.id = 'pseudo-register';
    inputPseudo.type = 'text';
    inputPseudo.placeholder = 'votre pseudo';
    inputPseudo.style.position = 'absolute';
    inputPseudo.style.top = (CONST.ui.UNIT * (positionPseudo.y + 1))+'px';
    inputPseudo.style.left = (CONST.ui.UNIT * (positionPseudo.x + 1))+'px';
    inputPseudo.style.width = (CONST.ui.UNIT * (positionPseudo.w - 4))+'px';
    document.body.appendChild(inputPseudo);
    // input = document.querySelector('#code-confirmation');

  }

  var positionEmail = {
    x : positionPseudo.x,
    y : positionPseudo.y + 2,
    w : positionPseudo.w
  };
  arrayInstructions.push({drawText : true
      , text : "Email"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionEmail.x + 1) // X
      , y : CONST.ui.UNIT * (positionEmail.y + 1) - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (positionEmail.w - 2) // Max Width
      , lineHeight : 30 // Line Height
  });

  // Gestion du champ de saisie du email
  var inputEmail = document.getElementById('email-register');
  if (!inputEmail){
    inputEmail = document.createElement('input');
    inputEmail.id = 'email-register';
    inputEmail.type = 'text';
    inputEmail.placeholder = 'email de contact';
    inputEmail.style.position = 'absolute';
    inputEmail.style.top = (CONST.ui.UNIT * (positionEmail.y + 1))+'px';
    inputEmail.style.left = (CONST.ui.UNIT * (positionEmail.x + 1))+'px';
    inputEmail.style.width = (CONST.ui.UNIT * (positionEmail.w - 4))+'px';
    document.body.appendChild(inputEmail);
    // input = document.querySelector('#code-confirmation');

  }

  // Boutons
  var positionBtnValid = {
      x : (Model.ui.screenSize.width - 6) / 2
    , y : positionEmail.y  + 2
    , w : 6
    , h : 3
  };
  Array.prototype.push.apply(arrayInstructions, InterfaceUtil.drawBtn(positionBtnValid));
  arrayInstructions.push({drawText : true
      , text : "Valider"
      , fontSize : '30px'
      , x :  CONST.ui.UNIT * (positionBtnValid.x + 1) // X
      , y : CONST.ui.UNIT * (positionBtnValid.y + 2) - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (positionBtnValid.w - 2) // Max Width
      , lineHeight : 30 // Line Height
  });

  // Mise à jour de la map d'interaction
  if (_interactionRegister.length === 0 ){
    var interaction = [];
    _interactionRegister = interaction;
    interaction.push({
        x : CONST.ui.UNIT * positionBtnValid.x
      , y : CONST.ui.UNIT * positionBtnValid.y
      , w : CONST.ui.UNIT * positionBtnValid.w
      , h : CONST.ui.UNIT * positionBtnValid.h
      , key : CONST.uiElements.BTN_OK
    });
  }

  return arrayInstructions;
}

// API :

function loginScreen(){
  if (!_addInteractions){
    registerInteractions_()
    _addInteractions = true;
  }

  var arrayInstructions = InterfaceUtil.drawAlphaBackground();

  // Zone autour du personnage
  var position = {
        x: 0
      , y :3
      , w: Model.ui.screenSize.width - 1
      , h: Model.ui.screenSize.height - 4}
  Array.prototype.push.apply(arrayInstructions, InterfaceUtil.drawZoneTexteAvecTitre(position));
  // Titre
  arrayInstructions.push({drawText : true
      , text : "Veuillez vous logguer"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (position.x + 1) // X
      , y : CONST.ui.UNIT * (position.y + 1) - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (position.w - 2) // Max Width
      , lineHeight : 30 // Line Height
  });

  if (_showRegister){
    Array.prototype.push.apply(arrayInstructions, paintRegister_(position));

  }else{
    Array.prototype.push.apply(arrayInstructions, paintLogins_(position));
  }

  // Mise à jour de la map d'interaction
  if (Model.ui.changeScreen === CONST.screens.LOGIN){
    _showRegister = false;
    _state = -1;
  }

  var currentState = _showRegister ? 1 : 0;
  if (_state != currentState){
    if (_showRegister){
      Model.ui.mapInteraction = _interactionRegister;
    }else{
      Model.ui.mapInteraction = _interactionLogin;
    }
    _state = currentState;
  }

  return arrayInstructions;
}

module.exports = {
	loginScreen : loginScreen
};<commit_msg>fix(#1)<commit_after>'use strict'
var Model = require('../model/model.js');
var CONST = require('../model/const.js');
var InterfaceUtil = require('../assets/interface-utils.js');
var Inputs = require('../triggers/inputs.js');

var _addInteractions = false
  , _showRegister = false
  , _pseudoEmpty = false
  , _emailEmpty = false
  , _interactionRegister = []
  , _interactionLogin = []
  , _state = -1;

function checkInteractions_(event) {
  if (event.type &&
    event.type  === CONST.eventType.UP){
    switch(event.key){
        case CONST.uiElements.BTN_CUSTO :
          _showRegister = true;
          break;
        case CONST.uiElements.BTN_OK :
          var inputPseudo = document.getElementById('pseudo-register');
          var inputEmail = document.getElementById('email-register');
          Model.gameModel.user = {}
          if (inputPseudo && inputPseudo.value){
            _pseudoEmpty = false;
            Model.gameModel.user.displayName = inputPseudo.value;
            inputPseudo.style.border = "";
            // TODO faire quelque chose avec le code de confirmation
          }else{
            _pseudoEmpty = true;
            inputPseudo.style.border = "thin solid red";
            inputPseudo.placeholder = "PSEUDO OBLIGATOIRE";
            return;

          }
          if (inputEmail && inputEmail.value){
            _emailEmpty = false;
            Model.gameModel.user.email = inputEmail.value;
            inputEmail.style.border = "";
            // TODO faire quelque chose avec le code de confirmation
          }else{
            _emailEmpty = true;
            inputEmail.style.border = "thin solid red";
            inputEmail.placeholder = "EMAIL OBLIGATOIRE";
            return;

          }
          document.body.removeChild(inputPseudo);
          document.body.removeChild(inputEmail);
          Model.ui.changeScreen = CONST.screens.CHOOSE_USER;
          break;
      }
    }
}

function registerInteractions_(){
  Inputs.registerInteraction({
    type : CONST.eventType.UP
    , key : [CONST.uiElements.BTN_CUSTO
          , CONST.uiElements.BTN_OK
          ]
    , callback : checkInteractions_
  });
}

function paintLogins_(position){
  var arrayInstructions = [];

  // Boutons de login
  var xBtns = 1.5;
  var ecart = 2;

  var positionGooglePlus = {
      x: xBtns
    , y : position.y + 3
  }
  arrayInstructions.push({
      key : 'socials' // Sprite
      , wOriValue : CONST.ui.UNIT // wOriValue
      , hOriValue : CONST.ui.UNIT // hOriValue
      , rowOri :  0 // rowOri
      , colOri : 1 // colOri
      , rowDest :  positionGooglePlus.y // rowDest
      , colDest :  positionGooglePlus.x // colDest
    });
  arrayInstructions.push({drawText : true
      , text : "Google "
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionGooglePlus.x + 2) // X
      , y : CONST.ui.UNIT * (positionGooglePlus.y + 1)  - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (position.w - 2 - 5) // Max Width
      , lineHeight : 30 // Line Height
  });

  var positionTwitter = {
      x: xBtns
    , y : positionGooglePlus.y + ecart
  }
  arrayInstructions.push({
      key : 'socials' // Sprite
      , wOriValue : CONST.ui.UNIT // wOriValue
      , hOriValue : CONST.ui.UNIT // hOriValue
      , rowOri :  1 // rowOri
      , colOri : 1 // colOri
      , rowDest :  positionTwitter.y // rowDest
      , colDest :  positionTwitter.x // colDest
    });
  arrayInstructions.push({drawText : true
      , text : "Twitter"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionTwitter.x + 2) // X
      , y : CONST.ui.UNIT * (positionTwitter.y + 1)  - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (position.w - 2 - 5) // Max Width
      , lineHeight : 30 // Line Height
  });

  var positionGithub = {
      x: xBtns
    , y : positionTwitter.y + ecart
  }
  arrayInstructions.push({
      key : 'socials' // Sprite
      , wOriValue : CONST.ui.UNIT // wOriValue
      , hOriValue : CONST.ui.UNIT // hOriValue
      , rowOri :  0 // rowOri
      , colOri : 0 // colOri
      , rowDest :  positionGithub.y // rowDest
      , colDest :  positionGithub.x // colDest
    });
  arrayInstructions.push({drawText : true
      , text : "Github"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionGithub.x + 2) // X
      , y : CONST.ui.UNIT * (positionGithub.y + 1)  - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (position.w - 2 - 5) // Max Width
      , lineHeight : 30 // Line Height
  });

  var positionCusto = {
      x: xBtns
    , y : positionGithub.y + ecart
  }
  arrayInstructions.push({
      key : 'socials' // Sprite
      , wOriValue : CONST.ui.UNIT // wOriValue
      , hOriValue : CONST.ui.UNIT // hOriValue
      , rowOri :  1 // rowOri
      , colOri : 0 // colOri
      , rowDest :  positionCusto.y // rowDest
      , colDest :  positionCusto.x // colDest
    });
  arrayInstructions.push({drawText : true
      , text : "Créer son compte"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionCusto.x + 2) // X
      , y : CONST.ui.UNIT * (positionCusto.y + 1)  - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (position.w - 4) // Max Width
      , lineHeight : 30 // Line Height
  });

  // Mise à jour de la map d'interaction
  if (_interactionLogin.length === 0 ){
    var interaction = [];
    _interactionLogin = interaction;
    interaction.push({
        x : CONST.ui.UNIT * positionGooglePlus.x
      , y : CONST.ui.UNIT * positionGooglePlus.y
      , w : CONST.ui.UNIT
      , h : CONST.ui.UNIT
      , key : CONST.uiElements.BTN_G_PLUS
    });
    interaction.push({
        x : CONST.ui.UNIT * positionTwitter.x
      , y : CONST.ui.UNIT * positionTwitter.y
      , w : CONST.ui.UNIT
      , h : CONST.ui.UNIT
      , key : CONST.uiElements.BTN_TWITTER
    });
    interaction.push({
        x : CONST.ui.UNIT * positionGithub.x
      , y : CONST.ui.UNIT * positionGithub.y
      , w : CONST.ui.UNIT
      , h : CONST.ui.UNIT
      , key : CONST.uiElements.BTN_GITHUB
    });
    interaction.push({
        x : CONST.ui.UNIT * positionCusto.x
      , y : CONST.ui.UNIT * positionCusto.y
      , w : CONST.ui.UNIT
      , h : CONST.ui.UNIT
      , key : CONST.uiElements.BTN_CUSTO
    });
  }

  return arrayInstructions;

}

function paintRegister_(position){
  var arrayInstructions = [];

  var positionPseudo = {
    x : position.x + 0.5,
    y : position.y + 2,
    w : Model.ui.screenSize.width - 1
  };
  arrayInstructions.push({drawText : true
      , text : "Pseudo"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionPseudo.x + 1) // X
      , y : CONST.ui.UNIT * (positionPseudo.y + 1) - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (positionPseudo.w - 2) // Max Width
      , lineHeight : 30 // Line Height
  });
  // Gestion du champ de saisie du pseudo
  var inputPseudo = document.getElementById('pseudo-register');
  if (!inputPseudo){
    inputPseudo = document.createElement('input');
    inputPseudo.id = 'pseudo-register';
    inputPseudo.type = 'text';
    inputPseudo.placeholder = 'votre pseudo';
    inputPseudo.style.position = 'absolute';
    inputPseudo.style.top = (CONST.ui.UNIT * (positionPseudo.y + 1))+'px';
    inputPseudo.style.left = (CONST.ui.UNIT * (positionPseudo.x + 1))+'px';
    inputPseudo.style.width = (CONST.ui.UNIT * (positionPseudo.w - 4))+'px';
    document.body.appendChild(inputPseudo);
    // input = document.querySelector('#code-confirmation');

  }

  var positionEmail = {
    x : positionPseudo.x,
    y : positionPseudo.y + 2,
    w : positionPseudo.w
  };
  arrayInstructions.push({drawText : true
      , text : "Email"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (positionEmail.x + 1) // X
      , y : CONST.ui.UNIT * (positionEmail.y + 1) - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (positionEmail.w - 2) // Max Width
      , lineHeight : 30 // Line Height
  });

  // Gestion du champ de saisie du email
  var inputEmail = document.getElementById('email-register');
  if (!inputEmail){
    inputEmail = document.createElement('input');
    inputEmail.id = 'email-register';
    inputEmail.type = 'text';
    inputEmail.placeholder = 'email de contact';
    inputEmail.style.position = 'absolute';
    inputEmail.style.top = (CONST.ui.UNIT * (positionEmail.y + 1))+'px';
    inputEmail.style.left = (CONST.ui.UNIT * (positionEmail.x + 1))+'px';
    inputEmail.style.width = (CONST.ui.UNIT * (positionEmail.w - 4))+'px';
    document.body.appendChild(inputEmail);
    // input = document.querySelector('#code-confirmation');

  }

  // Boutons
  var positionBtnValid = {
      x : (Model.ui.screenSize.width - 6) / 2
    , y : positionEmail.y  + 2
    , w : 6
    , h : 3
  };
  Array.prototype.push.apply(arrayInstructions, InterfaceUtil.drawBtn(positionBtnValid));
  arrayInstructions.push({drawText : true
      , text : "Valider"
      , fontSize : '30px'
      , x :  CONST.ui.UNIT * (positionBtnValid.x + 1) // X
      , y : CONST.ui.UNIT * (positionBtnValid.y + 2) - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (positionBtnValid.w - 2) // Max Width
      , lineHeight : 30 // Line Height
  });

  // Mise à jour de la map d'interaction
  if (_interactionRegister.length === 0 ){
    var interaction = [];
    _interactionRegister = interaction;
    interaction.push({
        x : CONST.ui.UNIT * positionBtnValid.x
      , y : CONST.ui.UNIT * positionBtnValid.y
      , w : CONST.ui.UNIT * positionBtnValid.w
      , h : CONST.ui.UNIT * positionBtnValid.h
      , key : CONST.uiElements.BTN_OK
    });
  }

  return arrayInstructions;
}

// API :

function loginScreen(){
  if (!_addInteractions){
    registerInteractions_()
    _addInteractions = true;
  }

  var arrayInstructions = InterfaceUtil.drawAlphaBackground();

  // Zone autour du personnage
  var position = {
        x: 0
      , y :3
      , w: Model.ui.screenSize.width - 1
      , h: Model.ui.screenSize.height - 4}
  Array.prototype.push.apply(arrayInstructions, InterfaceUtil.drawZoneTexteAvecTitre(position));
  // Titre
  arrayInstructions.push({drawText : true
      , text : "Veuillez vous logguer"
      , fontSize : '20px'
      , x :  CONST.ui.UNIT * (position.x + 1) // X
      , y : CONST.ui.UNIT * (position.y + 1) - CONST.ui.UNIT / 3 // Y
      , w : CONST.ui.UNIT * (position.w - 2) // Max Width
      , lineHeight : 30 // Line Height
  });

  if (_showRegister){
    Array.prototype.push.apply(arrayInstructions, paintRegister_(position));

  }else{
    Array.prototype.push.apply(arrayInstructions, paintLogins_(position));
  }

  // Mise à jour de la map d'interaction
  if (Model.ui.changeScreen === CONST.screens.LOGIN){
    _showRegister = false;
    _state = -1;
  }

  var currentState = _showRegister ? 1 : 0;
  if (_state != currentState){
    if (_showRegister){
      Model.ui.mapInteraction = _interactionRegister;
    }else{
      Model.ui.mapInteraction = _interactionLogin;
    }
    _state = currentState;
  }

  return arrayInstructions;
}

module.exports = {
	loginScreen : loginScreen
};<|endoftext|>


<commit_before>/********** TOASTS **********/

function toastAdd (data) {

	// This is used to initialise the toasts
	if (window.toastInt === undefined) {

		// Stop this conditional from calling again
		toastInt = true;

		// Create the toasts container element
		toastCache = document.createElement("div");
		toastCache.setAttribute("id", "toasts");
		document.body.appendChild(toastCache);

		// Create the toast timeout variable
		toastTimeout = null;

		// Create the toast array
		toastArray = new Array();

	};

	var toastElement = document.createElement("div");
	toastElement.className = "toast " + data.type;
	//toastElement.onclick = toastRemove(this);
	toastElement.setAttribute("onclick", "toastRemove(this)");

	// TODO: Convert following two conditionals to catch/match for simplicity

	function createTextElement (targetClass, targetText) {
		var toastElementText = document.createElement("span");
		toastElementText.classList.add(targetClass);
		toastElementText.innerHTML = targetText;
		toastElement.appendChild(toastElementText);
	};

	// Check if the title property has been passed; if so, add title element
	if (data.hasOwnProperty("title") !== false) {
		createTextElement("title", data.title);
	};

	// Check if the subtitle property has been passed; if so, add subtitle element
	if (data.hasOwnProperty("subtitle") !== false) {
		createTextElement("subtitle", data.subtitle);
	};

	toastCache.appendChild(toastElement);

	toastArray.push(toastElement);

	setTimeout(function() {
		toastElement.classList.add("visible");
		toastReorder(0);
	}, 0);

};

function toastRemove (target) {

	var targetIndex = toastArray.indexOf(target);
	toastArray.splice(targetIndex, 1);
	target.classList.remove("visible");

	setTimeout(function () {
		target.remove();
	}, 500);

	setTimeout(function () {
		toastReorder(0);
	}, 50);

	clearTimeout(toastTimeout);

};

function toastClear () {

	for (var i = 0; i < toastArray.length; i++) {
		toastArray[i].classList.remove("visible");
		setTimeout(function () {
			toastArray.splice(0, toastArray.length);
			toastCache.innerHTML = "";
		}, 500);
	};

};

function toastReorder (target) {

	var heights = 0;

	for (var i = target; i < toastArray.length; i++) {

		if (i > 0) {
			heights = heights - parseInt(toastArray[i - 1].offsetHeight) - 20;
		};

		toastArray[i].style = "-webkit-transform: translateY(" + heights + "px); -moz-transform: translateY(" + heights + "px); -ms-transform: translateY(" + heights + "px); -o-transform: translateY(" + heights + "px); transform: translateY(" + heights + "px)";

	};

};<commit_msg>Fixed targeting on toast removal and reordering (should increase performance)<commit_after>/********** TOASTS **********/

function toastAdd (data) {

	// This is used to initialise the toasts
	if (window.toastInt === undefined) {

		// Stop this conditional from calling again
		toastInt = true;

		// Create the toasts container element
		toastCache = document.createElement("div");
		toastCache.setAttribute("id", "toasts");
		document.body.appendChild(toastCache);

		// Create the toast timeout variable
		toastTimeout = null;

		// Create the toast array
		toastArray = new Array();

	};

	var toastElement = document.createElement("div");
	toastElement.className = "toast " + data.type;
	//toastElement.onclick = toastRemove(this);
	toastElement.setAttribute("onclick", "toastRemove(this)");

	// TODO: Convert following two conditionals to catch/match for simplicity

	function createTextElement (targetClass, targetText) {
		var toastElementText = document.createElement("span");
		toastElementText.classList.add(targetClass);
		toastElementText.innerHTML = targetText;
		toastElement.appendChild(toastElementText);
	};

	// Check if the title property has been passed; if so, add title element
	if (data.hasOwnProperty("title") !== false) {
		createTextElement("title", data.title);
	};

	// Check if the subtitle property has been passed; if so, add subtitle element
	if (data.hasOwnProperty("subtitle") !== false) {
		createTextElement("subtitle", data.subtitle);
	};

	toastCache.appendChild(toastElement);

	toastArray.push(toastElement);

	setTimeout(function() {
		toastElement.classList.add("visible");
		toastReorder(0);
	}, 0);

};

function toastRemove (target) {

	var targetIndex = toastArray.indexOf(target);
	toastArray.splice(targetIndex, 1);
	target.classList.remove("visible");

	setTimeout(function () {
		target.remove();
	}, 500);

	setTimeout(function () {
		toastReorder(targetIndex);
	}, 50);

	clearTimeout(toastTimeout);

};

function toastClear () {

	for (var i = 0; i < toastArray.length; i++) {
		toastArray[i].classList.remove("visible");
		setTimeout(function () {
			toastArray.splice(0, toastArray.length);
			toastCache.innerHTML = "";
		}, 500);
	};

};

function toastReorder (target) {

	for (var i = target; i < toastArray.length; i++) {

		if (i == 0) {
			var targetOffset = 0;
		}
		else {
			var targetOffset = parseInt(toastArray[i - 1].dataset.toastOffset) - parseInt(toastArray[i - 1].offsetHeight) - 20;
		};

		toastArray[i].style = "-webkit-transform: translateY(" + targetOffset + "px); -moz-transform: translateY(" + targetOffset + "px); -ms-transform: translateY(" + targetOffset + "px); -o-transform: translateY(" + targetOffset + "px); transform: translateY(" + targetOffset + "px)";
		toastArray[i].dataset.toastOffset = targetOffset;

	};

};<|endoftext|>


<commit_before>export class BTDComponent {
  constructor(settings, TDObject) {
    if (!settings) {
      throw new Error('Please pass Better TweetDeck\'s settings to the constructor');
    }

    if (!TDObject) {
      throw new Error('Please pass the TD global in the constructor');
    }

    this.settings = settings;
    this.TD = TDObject;
  }
}
<commit_msg>:wrench: make BTDComponent an abstract clas<commit_after>export class BTDComponent {
  constructor(settings, TDObject) {
    if (new.target === BTDComponent) {
      throw new Error('BTDComponent cannot be instanciated directly, create a class that extends it.');
    }

    if (!settings) {
      throw new Error('Please pass Better TweetDeck\'s settings to the constructor');
    }

    if (!TDObject) {
      throw new Error('Please pass the TD global in the constructor');
    }

    this.settings = settings;
    this.TD = TDObject;
  }
}
<|endoftext|>


<commit_before>import {removeAttr} from './attr';
import {isNode, isString, startsWith, toNode, toNodes} from './lang';

export function query(selector, context) {
    return toNode(selector) || find(selector, isContextSelector(selector) ? context : document);
}

export function queryAll(selector, context) {
    const nodes = toNodes(selector);
    return nodes.length && nodes || findAll(selector, isContextSelector(selector) ? context : document);
}

export function find(selector, context) {
    return toNode(_query(selector, context, 'querySelector'));
}

export function findAll(selector, context) {
    return toNodes(_query(selector, context, 'querySelectorAll'));
}

function _query(selector, context = document, queryFn) {

    if (!selector || !isString(selector)) {
        return null;
    }

    selector = selector.replace(contextSanitizeRe, '$1 *');

    let removes;

    if (isContextSelector(selector)) {

        removes = [];

        selector = selector.split(',').map((selector, i) => {

            let ctx = context;

            selector = selector.trim();

            if (selector[0] === '!') {

                const selectors = selector.substr(1).trim().split(' ');
                ctx = closest(context.parentNode, selectors[0]);
                selector = selectors.slice(1).join(' ').trim();

            }

            if (selector[0] === '-') {

                const selectors = selector.substr(1).trim().split(' ');
                const prev = (ctx || context).previousElementSibling;
                ctx = matches(prev, selector.substr(1)) ? prev : null;
                selector = selectors.slice(1).join(' ');

            }

            if (!ctx) {
                return null;
            }

            if (!ctx.id) {
                ctx.id = `uk-${Date.now()}${i}`;
                removes.push(() => removeAttr(ctx, 'id'));
            }

            return `#${escape(ctx.id)} ${selector}`;

        }).filter(Boolean).join(',');

        context = document;

    }

    try {

        return context[queryFn](selector);

    } catch (e) {

        return null;

    } finally {

        removes && removes.forEach(remove => remove());

    }

}

const contextSelectorRe = /(^|,)\s*[!>+~-]/;
const contextSanitizeRe = /([!>+~-])(?=\s+[!>+~-]|\s*$)/g;

function isContextSelector(selector) {
    return isString(selector) && selector.match(contextSelectorRe);
}

const elProto = Element.prototype;
const matchesFn = elProto.matches || elProto.webkitMatchesSelector || elProto.msMatchesSelector;

export function matches(element, selector) {
    return toNodes(element).some(element => matchesFn.call(element, selector));
}

const closestFn = elProto.closest || function (selector) {
    let ancestor = this;

    do {

        if (matches(ancestor, selector)) {
            return ancestor;
        }

        ancestor = ancestor.parentNode;

    } while (ancestor && ancestor.nodeType === 1);
};

export function closest(element, selector) {

    if (startsWith(selector, '>')) {
        selector = selector.slice(1);
    }

    return isNode(element)
        ? element.parentNode && closestFn.call(element, selector)
        : toNodes(element).map(element => element.parentNode && closestFn.call(element, selector)).filter(Boolean);
}

export function parents(element, selector) {
    const elements = [];
    let parent = toNode(element).parentNode;

    while (parent && parent.nodeType === 1) {

        if (matches(parent, selector)) {
            elements.push(parent);
        }

        parent = parent.parentNode;
    }

    return elements;
}

const escapeFn = window.CSS && CSS.escape || function (css) { return css.replace(/([^\x7f-\uFFFF\w-])/g, match => `\\${match}`); };
export function escape(css) {
    return isString(css) ? escapeFn.call(null, css) : '';
}
<commit_msg>fix: allow to call `query` and `queryAll` on contentDocuments<commit_after>import {removeAttr} from './attr';
import {isDocument, isNode, isString, startsWith, toNode, toNodes} from './lang';

export function query(selector, context) {
    return toNode(selector) || find(selector, getContext(selector, context));
}

export function queryAll(selector, context) {
    const nodes = toNodes(selector);
    return nodes.length && nodes || findAll(selector, getContext(selector, context));
}

function getContext(selector, context = document) {
    return isContextSelector(selector) || isDocument(context)
        ? context
        : context.ownerDocument;
}

export function find(selector, context) {
    return toNode(_query(selector, context, 'querySelector'));
}

export function findAll(selector, context) {
    return toNodes(_query(selector, context, 'querySelectorAll'));
}

function _query(selector, context = document, queryFn) {

    if (!selector || !isString(selector)) {
        return null;
    }

    selector = selector.replace(contextSanitizeRe, '$1 *');

    let removes;

    if (isContextSelector(selector)) {

        removes = [];

        selector = selector.split(',').map((selector, i) => {

            let ctx = context;

            selector = selector.trim();

            if (selector[0] === '!') {

                const selectors = selector.substr(1).trim().split(' ');
                ctx = closest(context.parentNode, selectors[0]);
                selector = selectors.slice(1).join(' ').trim();

            }

            if (selector[0] === '-') {

                const selectors = selector.substr(1).trim().split(' ');
                const prev = (ctx || context).previousElementSibling;
                ctx = matches(prev, selector.substr(1)) ? prev : null;
                selector = selectors.slice(1).join(' ');

            }

            if (!ctx) {
                return null;
            }

            if (!ctx.id) {
                ctx.id = `uk-${Date.now()}${i}`;
                removes.push(() => removeAttr(ctx, 'id'));
            }

            return `#${escape(ctx.id)} ${selector}`;

        }).filter(Boolean).join(',');

        context = document;

    }

    try {

        return context[queryFn](selector);

    } catch (e) {

        return null;

    } finally {

        removes && removes.forEach(remove => remove());

    }

}

const contextSelectorRe = /(^|,)\s*[!>+~-]/;
const contextSanitizeRe = /([!>+~-])(?=\s+[!>+~-]|\s*$)/g;

function isContextSelector(selector) {
    return isString(selector) && selector.match(contextSelectorRe);
}

const elProto = Element.prototype;
const matchesFn = elProto.matches || elProto.webkitMatchesSelector || elProto.msMatchesSelector;

export function matches(element, selector) {
    return toNodes(element).some(element => matchesFn.call(element, selector));
}

const closestFn = elProto.closest || function (selector) {
    let ancestor = this;

    do {

        if (matches(ancestor, selector)) {
            return ancestor;
        }

        ancestor = ancestor.parentNode;

    } while (ancestor && ancestor.nodeType === 1);
};

export function closest(element, selector) {

    if (startsWith(selector, '>')) {
        selector = selector.slice(1);
    }

    return isNode(element)
        ? element.parentNode && closestFn.call(element, selector)
        : toNodes(element).map(element => element.parentNode && closestFn.call(element, selector)).filter(Boolean);
}

export function parents(element, selector) {
    const elements = [];
    let parent = toNode(element).parentNode;

    while (parent && parent.nodeType === 1) {

        if (matches(parent, selector)) {
            elements.push(parent);
        }

        parent = parent.parentNode;
    }

    return elements;
}

const escapeFn = window.CSS && CSS.escape || function (css) { return css.replace(/([^\x7f-\uFFFF\w-])/g, match => `\\${match}`); };
export function escape(css) {
    return isString(css) ? escapeFn.call(null, css) : '';
}
<|endoftext|>


<commit_before>import {css} from './style';
import {Promise} from './promise';
import {isVisible, parents} from './filter';
import {offset, offsetPosition, position} from './dimensions';
import {clamp, intersectRect, isDocument, isWindow, toNode, toWindow} from './lang';

export function isInView(element, offsetTop = 0, offsetLeft = 0) {

    if (!isVisible(element)) {
        return false;
    }

    return intersectRect(...scrollParents(element).map(parent => {

        const {top, left, bottom, right} = offset(getViewport(parent));

        return {
            top: top - offsetTop,
            left: left - offsetLeft,
            bottom: bottom + offsetTop,
            right: right + offsetLeft
        };
    }).concat(offset(element)));
}

export function scrollTop(element, top) {

    if (isWindow(element) || isDocument(element)) {
        element = getScrollingElement(element);
    } else {
        element = toNode(element);
    }

    element.scrollTop = top;
}

export function scrollIntoView(element, {offset: offsetBy = 0} = {}) {

    if (!isVisible(element)) {
        return;
    }

    const parents = scrollParents(element);
    let diff = 0;
    return parents.reduce((fn, scrollElement, i) => {

        const {scrollTop, scrollHeight, clientHeight} = scrollElement;
        const maxScroll = scrollHeight - clientHeight;

        let top = Math.ceil(position(parents[i - 1] || element, getViewport(scrollElement)).top - offsetBy) + diff + scrollTop;

        if (top > maxScroll) {
            diff = top - maxScroll;
            top = maxScroll;
        } else {
            diff = 0;
        }

        return () => scrollTo(scrollElement, top - scrollTop).then(fn);

    }, () => Promise.resolve())();

    function scrollTo(element, top) {
        return new Promise(resolve => {

            const scroll = element.scrollTop;
            const duration = getDuration(Math.abs(top));
            const start = Date.now();

            (function step() {

                const percent = ease(clamp((Date.now() - start) / duration));

                scrollTop(element, scroll + top * percent);

                // scroll more if we have not reached our destination
                if (percent !== 1) {
                    requestAnimationFrame(step);
                } else {
                    resolve();
                }

            })();
        });
    }

    function getDuration(dist) {
        return 40 * Math.pow(dist, .375);
    }

    function ease(k) {
        return 0.5 * (1 - Math.cos(Math.PI * k));
    }

}

export function scrolledOver(element, heightOffset = 0) {

    if (!isVisible(element)) {
        return 0;
    }

    const [scrollElement] = scrollParents(element, /auto|scroll/);
    const {scrollHeight, scrollTop} = scrollElement;
    const viewport = getViewport(scrollElement);
    const viewportHeight = offset(viewport).height;
    const viewportTop = offsetPosition(element)[0] - scrollTop - offsetPosition(scrollElement)[0];
    const viewportDist = Math.min(viewportHeight, viewportTop + scrollTop);

    const top = viewportTop - viewportDist;
    const dist = Math.min(
        offset(element).height + heightOffset + viewportDist,
        scrollHeight - (viewportTop + scrollTop),
        scrollHeight - viewportHeight
    );

    return clamp(-1 * top / dist);
}

export function scrollParents(element, overflowRe = /auto|scroll|hidden/, scrollable = false) {
    const scrollEl = getScrollingElement(element);
    const scrollParents = parents(element).filter(parent =>
        parent === scrollEl || overflowRe.test(css(parent, 'overflow'))
        && !scrollable || parent.scrollHeight < Math.round(offset(parent).height)
    );
    return scrollParents.length ? scrollParents : [scrollEl];
}

export function getViewport(scrollElement) {
    return scrollElement === getScrollingElement(scrollElement) ? window : scrollElement;
}

function getScrollingElement(element) {
    const {document} = toWindow(element);
    return document.scrollingElement || document.documentElement;
}
<commit_msg>fix: compatibility for browsers where document.scrollingElement is document.body<commit_after>import {css} from './style';
import {Promise} from './promise';
import {isVisible, parents} from './filter';
import {height, offset, offsetPosition, position} from './dimensions';
import {clamp, intersectRect, isDocument, isWindow, toNode, toWindow} from './lang';

export function isInView(element, offsetTop = 0, offsetLeft = 0) {

    if (!isVisible(element)) {
        return false;
    }

    return intersectRect(...scrollParents(element).map(parent => {

        const {top, left, bottom, right} = offset(getViewport(parent));

        return {
            top: top - offsetTop,
            left: left - offsetLeft,
            bottom: bottom + offsetTop,
            right: right + offsetLeft
        };
    }).concat(offset(element)));
}

export function scrollTop(element, top) {

    if (isWindow(element) || isDocument(element)) {
        element = getScrollingElement(element);
    } else {
        element = toNode(element);
    }

    element.scrollTop = top;
}

export function scrollIntoView(element, {offset: offsetBy = 0} = {}) {

    if (!isVisible(element)) {
        return;
    }

    const parents = scrollParents(element);
    let diff = 0;
    return parents.reduce((fn, scrollElement, i) => {

        const {scrollTop, scrollHeight} = scrollElement;
        const viewport = getViewport(scrollElement);
        const maxScroll = scrollHeight - height(viewport);

        let top = Math.ceil(position(parents[i - 1] || element, viewport).top - offsetBy) + diff + scrollTop;

        if (top > maxScroll) {
            diff = top - maxScroll;
            top = maxScroll;
        } else {
            diff = 0;
        }

        return () => scrollTo(scrollElement, top - scrollTop).then(fn);

    }, () => Promise.resolve())();

    function scrollTo(element, top) {
        return new Promise(resolve => {

            const scroll = element.scrollTop;
            const duration = getDuration(Math.abs(top));
            const start = Date.now();

            (function step() {

                const percent = ease(clamp((Date.now() - start) / duration));

                scrollTop(element, scroll + top * percent);

                // scroll more if we have not reached our destination
                if (percent !== 1) {
                    requestAnimationFrame(step);
                } else {
                    resolve();
                }

            })();
        });
    }

    function getDuration(dist) {
        return 40 * Math.pow(dist, .375);
    }

    function ease(k) {
        return 0.5 * (1 - Math.cos(Math.PI * k));
    }

}

export function scrolledOver(element, heightOffset = 0) {

    if (!isVisible(element)) {
        return 0;
    }

    const [scrollElement] = scrollParents(element, /auto|scroll/);
    const {scrollHeight, scrollTop} = scrollElement;
    const viewport = getViewport(scrollElement);
    const viewportHeight = height(viewport);
    const viewportTop = offsetPosition(element)[0] - scrollTop - offsetPosition(scrollElement)[0];
    const viewportDist = Math.min(viewportHeight, viewportTop + scrollTop);

    const top = viewportTop - viewportDist;
    const dist = Math.min(
        height(element) + heightOffset + viewportDist,
        scrollHeight - (viewportTop + scrollTop),
        scrollHeight - viewportHeight
    );

    return clamp(-1 * top / dist);
}

export function scrollParents(element, overflowRe = /auto|scroll|hidden/, scrollable = false) {
    const scrollEl = getScrollingElement(element);
    const scrollParents = parents(element).filter(parent =>
        parent === scrollEl || overflowRe.test(css(parent, 'overflow'))
        && !scrollable || parent.scrollHeight < Math.round(height(parent))
    );
    return scrollParents.length ? scrollParents : [scrollEl];
}

export function getViewport(scrollElement) {
    return scrollElement === getScrollingElement(scrollElement) ? window : scrollElement;
}

function getScrollingElement(element) {
    const {document} = toWindow(element);
    return document.scrollingElement || document.documentElement;
}
<|endoftext|>


<commit_before>$(".numberpicker-down-button").unbind('click').on("click", function()
{
	var inputElement = $(this).parent().parent().find('input[type="number"]');
	inputElement.val(parseFloat(inputElement.val() || 1) - 1);
	inputElement.trigger('keyup');
	inputElement.trigger('change');
});

$(".numberpicker-up-button").unbind('click').on("click", function()
{
	var inputElement = $(this).parent().parent().find('input[type="number"]');
	inputElement.val(parseFloat(inputElement.val() || 0) + 1);
	inputElement.trigger('keyup');
	inputElement.trigger('change');
});

$(".numberpicker").on("keyup", function()
{
	if ($(this).attr("data-not-equal") && !$(this).attr("data-not-equal").toString().isEmpty() && $(this).attr("data-not-equal") == $(this).val())
	{
		$(this)[0].setCustomValidity("error");
	}
	else
	{
		$(this)[0].setCustomValidity("");
	}
});

$(".numberpicker").each(function()
{
	new MutationObserver(function(mutations)
	{
		mutations.forEach(function(mutation)
		{
			if (mutation.type == "attributes" && (mutation.attributeName == "min" || mutation.attributeName == "max" || mutation.attributeName == "data-not-equal" || mutation.attributeName == "data-initialised"))
			{
				var element = $(mutation.target);
				var min = element.attr("min");
				var decimals = element.attr("data-decimals");

				var max = "";
				if (element.hasAttr("max"))
				{
					max = element.attr("max");
				}

				if (element.hasAttr("data-not-equal"))
				{
					var notEqual = element.attr("data-not-equal");

					if (notEqual != "NaN")
					{
						if (max.isEmpty())
						{
							element.parent().find(".invalid-feedback").text(__t("This cannot be lower than %1$s or equal %2$s and needs to be a valid number with max. %3$s decimal places", parseFloat(min).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), parseFloat(notEqual).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), decimals));
						}
						else
						{
							element.parent().find(".invalid-feedback").text(__t("This must be between %1$s and %2$s, cannot equal %3$s and needs to be a valid number with max. %4$s decimal places", parseFloat(min).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), parseFloat(max).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), parseFloat(notEqual).toLocaleString(undefined, { minimumFractionDigits: decimals, maximumFractionDigits: decimals }), decimals));
						}

						return;
					}
				}

				if (max.isEmpty())
				{
					element.parent().find(".invalid-feedback").text(__t("This cannot be lower than %1$s and needs to be a valid number with max. %2$s decimal places", parseFloat(min).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), decimals));
				}
				else
				{
					element.parent().find(".invalid-feedback").text(__t("This must between %1$s and %2$s and needs to be a valid number with max. %3$s decimal places", parseFloat(min).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), parseFloat(max).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), decimals));
				}
			}
		});
	}).observe(this, {
		attributes: true
	});
});
$(".numberpicker").attr("data-initialised", "true"); // Dummy change to trigger MutationObserver above once

$(".numberpicker").on("keydown", function(e)
{
	if (e.key == "ArrowUp")
	{
		e.preventDefault();
		$(this).parent().find(".numberpicker-up-button").click();
	}
	else if (e.key == "ArrowDown")
	{
		e.preventDefault();
		$(this).parent().find(".numberpicker-down-button").click();
	}
});

$(".numberpicker.locale-number-input.locale-number-currency").on("blur", function()
{
	if (BoolVal(Grocy.UserSettings.stock_auto_decimal_separator_prices))
	{
		var value = this.value.toString();
		var decimalPlaces = parseInt(Grocy.UserSettings.stock_decimal_places_prices);

		if (value.length <= decimalPlaces)
		{
			return;
		}

		var valueNew = parseFloat(value.substring(0, value.length - decimalPlaces) + '.' + value.slice(decimalPlaces * -1)).toLocaleString(undefined, { minimumFractionDigits: decimalPlaces, maximumFractionDigits: decimalPlaces });
		$(this).val(valueNew);
	}
});
<commit_msg>Optimized "auto decimal separator for price inputs" (references #1345)<commit_after>$(".numberpicker-down-button").unbind('click').on("click", function()
{
	var inputElement = $(this).parent().parent().find('input[type="number"]');
	inputElement.val(parseFloat(inputElement.val() || 1) - 1);
	inputElement.trigger('keyup');
	inputElement.trigger('change');
});

$(".numberpicker-up-button").unbind('click').on("click", function()
{
	var inputElement = $(this).parent().parent().find('input[type="number"]');
	inputElement.val(parseFloat(inputElement.val() || 0) + 1);
	inputElement.trigger('keyup');
	inputElement.trigger('change');
});

$(".numberpicker").on("keyup", function()
{
	if ($(this).attr("data-not-equal") && !$(this).attr("data-not-equal").toString().isEmpty() && $(this).attr("data-not-equal") == $(this).val())
	{
		$(this)[0].setCustomValidity("error");
	}
	else
	{
		$(this)[0].setCustomValidity("");
	}
});

$(".numberpicker").each(function()
{
	new MutationObserver(function(mutations)
	{
		mutations.forEach(function(mutation)
		{
			if (mutation.type == "attributes" && (mutation.attributeName == "min" || mutation.attributeName == "max" || mutation.attributeName == "data-not-equal" || mutation.attributeName == "data-initialised"))
			{
				var element = $(mutation.target);
				var min = element.attr("min");
				var decimals = element.attr("data-decimals");

				var max = "";
				if (element.hasAttr("max"))
				{
					max = element.attr("max");
				}

				if (element.hasAttr("data-not-equal"))
				{
					var notEqual = element.attr("data-not-equal");

					if (notEqual != "NaN")
					{
						if (max.isEmpty())
						{
							element.parent().find(".invalid-feedback").text(__t("This cannot be lower than %1$s or equal %2$s and needs to be a valid number with max. %3$s decimal places", parseFloat(min).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), parseFloat(notEqual).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), decimals));
						}
						else
						{
							element.parent().find(".invalid-feedback").text(__t("This must be between %1$s and %2$s, cannot equal %3$s and needs to be a valid number with max. %4$s decimal places", parseFloat(min).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), parseFloat(max).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), parseFloat(notEqual).toLocaleString(undefined, { minimumFractionDigits: decimals, maximumFractionDigits: decimals }), decimals));
						}

						return;
					}
				}

				if (max.isEmpty())
				{
					element.parent().find(".invalid-feedback").text(__t("This cannot be lower than %1$s and needs to be a valid number with max. %2$s decimal places", parseFloat(min).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), decimals));
				}
				else
				{
					element.parent().find(".invalid-feedback").text(__t("This must between %1$s and %2$s and needs to be a valid number with max. %3$s decimal places", parseFloat(min).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), parseFloat(max).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: decimals }), decimals));
				}
			}
		});
	}).observe(this, {
		attributes: true
	});
});
$(".numberpicker").attr("data-initialised", "true"); // Dummy change to trigger MutationObserver above once

$(".numberpicker").on("keydown", function(e)
{
	if (e.key == "ArrowUp")
	{
		e.preventDefault();
		$(this).parent().find(".numberpicker-up-button").click();
	}
	else if (e.key == "ArrowDown")
	{
		e.preventDefault();
		$(this).parent().find(".numberpicker-down-button").click();
	}
});

$(".numberpicker.locale-number-input.locale-number-currency").on("blur", function()
{
	if (BoolVal(Grocy.UserSettings.stock_auto_decimal_separator_prices))
	{
		var value = this.value.toString();
		var decimalPlaces = parseInt(Grocy.UserSettings.stock_decimal_places_prices);

		if (value.length <= decimalPlaces)
		{
			value = value.padStart(Grocy.UserSettings.stock_decimal_places_prices, "0");
		}

		var valueNew = parseFloat(value.substring(0, value.length - decimalPlaces) + '.' + value.slice(decimalPlaces * -1)).toLocaleString(undefined, { minimumFractionDigits: decimalPlaces, maximumFractionDigits: decimalPlaces });
		$(this).val(valueNew);
	}
});
<|endoftext|>


<commit_before>(function ($) {
	$.widgets.image = function (input, size, type, quality) {
		input.attr ('type', 'hidden');
		var search = $('<input/>');
		search.attr ('type', 'file');
		search.attr ('accept', 'image/*');
		search.css ('float', 'left')
		      .css ('clear', 'both');
		input.next (search);
		var div = $('<div/>');
		div.css ('width', size+'px');
		div.css ('height', size+'px');
		div.css ('position', 'relative');
		div.css ('overflow', 'hidden');
		div.css ('margin-bottom', '8px');
		div.css ('background', '-webkit-linear-gradient(bottom,#ddd,#eee)');
		div.css ('background', 'linear-gradient(bottom,#ddd,#eee)');
		div.css ('float', 'left');
		div.css ('clear', 'left');
		div.css ('display', 'inline-block');
		search.next (div);
		div.next ($('<div>').css ('clear', 'both'));
		var img = false;
		var ratio, x, y;
		var getDataURL = false;
		var rotate = $('<input>').attr ('type', 'button').val ('rotar');
		rotate.css ('display', 'none')
		      .css ('float', 'left')
		      .css ('margin-left', '.5em')
		      .css ('width', 'auto')
		      .css ('padding', '.25em .5em')
		      .css ('line-height', '1em')
		      .css ('text-indent', '0');
		function load_image (data_url) {
			div.empty ();
			img = $('<img/>');
			img.event ('load', function () {
				rotate.css ('display', 'inline-block');
				img.css ('position', 'absolute');
				ratio = Math.max (size / img.native.naturalWidth, size / img.native.naturalHeight);
				img.css ('width', Math.ceil (img.native.naturalWidth * ratio) + 'px');
				img.css ('height', Math.ceil (img.native.naturalHeight * ratio) + 'px');
				x = Math.round ((size - img.native.naturalWidth * ratio) * .5);
				y = Math.round ((size - img.native.naturalHeight * ratio) * .5);
				getDataURL = function (fn, simg) {
					if (!simg) {
						simg = new Image ();
						simg.src = img.attr ('src');
					}
					if (Math.min (simg.naturalWidth, simg.naturalHeight) > size * 1.8) {
						var canvas = document.createElement ('canvas');
						canvas.width = Math.ceil (simg.naturalWidth / 1.8);
						canvas.height = Math.ceil (simg.naturalHeight / 1.8);
						var context = canvas.getContext ('2d');
						context.drawImage (simg, 0, 0, canvas.width, canvas.height);
						var cimg = new Image ();
						cimg.onload = function () {
							getDataURL (fn, cimg);
						};
						cimg.src = canvas.toDataURL ();
					} else {
						var sratio = Math.max (size / simg.naturalWidth, size / simg.naturalHeight);
						var canvas = document.createElement ('canvas');
						canvas.width = size;
						canvas.height = size;
						var context = canvas.getContext ('2d');
						context.drawImage (simg, x, y, Math.ceil (simg.naturalWidth * sratio), Math.ceil (simg.naturalHeight * sratio));
						fn (canvas.toDataURL (type, quality));
					}
				};
				img.css ('left', x + 'px');
				img.css ('top', y + 'px');
				div.append (img);
				var mx, my, mb = false;
				img.event ('mousedown', function (e) {
					e.preventDefault ();
					mb = true;
					mx = e.pageX;
					my = e.pageY;
				});
				img.event ('mousemove', function (e) {
					if (mb) {
						x += e.pageX - mx;
						y += e.pageY - my;
						if (x > 0) x = 0;
						if (y > 0) y = 0;
						var minX = -Math.floor (img.native.naturalWidth * ratio) + size;
						var minY = -Math.floor (img.native.naturalHeight * ratio) + size;
						if (x < minX) {
							x = minX;
						}
						if (y < minY) {
							y = minY;
						}
						mx = e.pageX;
						my = e.pageY;
						img.css ('left', x + 'px');
						img.css ('top', y + 'px');
					}
				});
				img.event ('mouseup', function (e) {
					mb = false;
					getDataURL (function (url) {
						input.val (url);
					});
				});
				getDataURL (function (url) {
					input.val (url);
				});
			});
			img.attr ('src', data_url);
		}
		search.event ('change', function () {
			var reader = new FileReader ();
			reader.onload = function (e) {
				load_image (reader.result);
			};
			reader.readAsDataURL (search.native.files[0]);
		});
		div.next (rotate);
		rotate.click (function () {
			var canvas = document.createElement ('canvas');
			canvas.width = img.native.naturalHeight;
			canvas.height = img.native.naturalWidth;
			var ctx = canvas.getContext ('2d');
			ctx.rotate (90*Math.PI/180);
			ctx.drawImage (img.native, 0, -canvas.width);
			load_image (canvas.toDataURL ());
		});
	};
}) (window.$);
<commit_msg>Added mobile support to image widget. Now you can drag and clip the image with your fingers :-)<commit_after>(function ($) {
	$.widgets.image = function (input, size, type, quality) {
		input.attr ('type', 'hidden');
		var search = $('<input/>');
		search.attr ('type', 'file');
		search.attr ('accept', 'image/*');
		search.css ('float', 'left')
		      .css ('clear', 'both');
		input.next (search);
		var div = $('<div/>');
		div.css ('width', size+'px');
		div.css ('height', size+'px');
		div.css ('position', 'relative');
		div.css ('overflow', 'hidden');
		div.css ('margin-bottom', '8px');
		div.css ('background', '-webkit-linear-gradient(bottom,#ddd,#eee)');
		div.css ('background', 'linear-gradient(bottom,#ddd,#eee)');
		div.css ('float', 'left');
		div.css ('clear', 'left');
		div.css ('display', 'inline-block');
		search.next (div);
		div.next ($('<div>').css ('clear', 'both'));
		var img = false;
		var ratio, x, y;
		var getDataURL = false;
		var rotate = $('<input>').attr ('type', 'button').val ('rotar');
		rotate.css ('display', 'none')
		      .css ('float', 'left')
		      .css ('margin-left', '.5em')
		      .css ('width', 'auto')
		      .css ('padding', '.25em .5em')
		      .css ('line-height', '1em')
		      .css ('text-indent', '0');
		function load_image (data_url) {
			div.empty ();
			img = $('<img/>');
			img.event ('load', function () {
				rotate.css ('display', 'inline-block');
				img.css ('position', 'absolute');
				ratio = Math.max (size / img.native.naturalWidth, size / img.native.naturalHeight);
				img.css ('width', Math.ceil (img.native.naturalWidth * ratio) + 'px');
				img.css ('height', Math.ceil (img.native.naturalHeight * ratio) + 'px');
				x = Math.round ((size - img.native.naturalWidth * ratio) * .5);
				y = Math.round ((size - img.native.naturalHeight * ratio) * .5);
				getDataURL = function (fn, simg) {
					if (!simg) {
						simg = new Image ();
						simg.src = img.attr ('src');
					}
					if (Math.min (simg.naturalWidth, simg.naturalHeight) > size * 1.8) {
						var canvas = document.createElement ('canvas');
						canvas.width = Math.ceil (simg.naturalWidth / 1.8);
						canvas.height = Math.ceil (simg.naturalHeight / 1.8);
						var context = canvas.getContext ('2d');
						context.drawImage (simg, 0, 0, canvas.width, canvas.height);
						var cimg = new Image ();
						cimg.onload = function () {
							getDataURL (fn, cimg);
						};
						cimg.src = canvas.toDataURL ();
					} else {
						var sratio = Math.max (size / simg.naturalWidth, size / simg.naturalHeight);
						var canvas = document.createElement ('canvas');
						canvas.width = size;
						canvas.height = size;
						var context = canvas.getContext ('2d');
						context.drawImage (simg, x, y, Math.ceil (simg.naturalWidth * sratio), Math.ceil (simg.naturalHeight * sratio));
						fn (canvas.toDataURL (type, quality));
					}
				};
				img.css ('left', x + 'px');
				img.css ('top', y + 'px');
				div.append (img);
				var mx, my, mb = false;
				function mouse_down (e) {
					e.preventDefault ();
					mb = true;
					mx = e.pageX;
					my = e.pageY;
				}
				function mouse_move (e) {
					if (mb) {
						x += e.pageX - mx;
						y += e.pageY - my;
						if (x > 0) x = 0;
						if (y > 0) y = 0;
						var minX = -Math.floor (img.native.naturalWidth * ratio) + size;
						var minY = -Math.floor (img.native.naturalHeight * ratio) + size;
						if (x < minX) {
							x = minX;
						}
						if (y < minY) {
							y = minY;
						}
						mx = e.pageX;
						my = e.pageY;
						img.css ('left', x + 'px');
						img.css ('top', y + 'px');
					}
				}
				function mouse_up (e) {
					mb = false;
					getDataURL (function (url) {
						input.val (url);
					});
				}
				img.event ('mousedown', mouse_down);
				img.event ('mousemove', mouse_move);
				img.event ('mouseup', mouse_up);
				img.event ('touchstart', function (e) {
					if (e.touches.length == 1) {
						e.pageX = e.touches[0].pageX;
						e.pageY = e.touches[0].pageY;
						mouse_down (e);
					}
				});
				img.event ('touchmove', function (e) {
					if (e.touches.length == 1) {
						e.pageX = e.touches[0].pageX;
						e.pageY = e.touches[0].pageY;
						mouse_move (e);
					}
				});
				img.event ('touchend', function (e) {
					if (!e.touches.length) {
						mouse_up (e);
					}
				});
				getDataURL (function (url) {
					input.val (url);
				});
			});
			img.attr ('src', data_url);
		}
		search.event ('change', function () {
			var reader = new FileReader ();
			reader.onload = function (e) {
				load_image (reader.result);
			};
			reader.readAsDataURL (search.native.files[0]);
		});
		div.next (rotate);
		rotate.click (function () {
			var canvas = document.createElement ('canvas');
			canvas.width = img.native.naturalHeight;
			canvas.height = img.native.naturalWidth;
			var ctx = canvas.getContext ('2d');
			ctx.rotate (90*Math.PI/180);
			ctx.drawImage (img.native, 0, -canvas.width);
			load_image (canvas.toDataURL ());
		});
	};
}) (window.$);
<|endoftext|>


<commit_before>jsns.define("hr.widgets.jsonobjecteditor", [
    "hr.toggles",
    "hr.plugins.jdorn.json-editor",
    "hr.promiseutils"
],
function (exports, module, toggles, jsonEditor, promiseUtils) {
    var defaultError = { path: null };

    "use strict"
    /**
     * This is a generic object editor that uses json-editor to edit objects.
     * The ui is determined by the html. This supports a load, main, error
     * lifecycle, but it is controlled externally. It can also be put on a
     * dialog named 'dialog', which it will activate when required. It also
     * consideres closing this dialog to be a cancellation and will send its
     * promise with an undefined result, which means cancel the operation.
     */
    function JsonObjectEditor(bindings, context) {
        var currentError = null

        var modeModel = bindings.getModel('mode');
        var titleModel = bindings.getModel('title');
        var errorModel = bindings.getModel('error');
        var formModel = new jsonEditor.create(bindings.getHandle("editorHolder"), {
            schema: context.schema,
            disable_edit_json: true,
            disable_properties: true,
            disable_collapse: true,
            show_errors: "always",
            custom_validators: [
                function (schema, value, path) {
                    if (currentError !== null) {
                        if (path === "root") {
                            return {
                                path: path,
                                message: currentError.message
                            }
                        }

                        if (currentError['errors'] !== undefined) {
                            //walk path to error
                            var pathParts = path.split('.');
                            var errorObject = currentError.errors;
                            for (var i = 1; i < pathParts.length; ++i) { //Skip the root entry
                                errorObject = errorObject[pathParts[i]];
                                if (errorObject === undefined) {
                                    break;
                                }
                            }

                            if (errorObject !== undefined && errorObject !== currentError.errors) {
                                return {
                                    path: path,
                                    message: errorObject
                                };
                            }
                        }
                    }
                    return defaultError;
                }
            ]
        });

        var dialog = bindings.getToggle('dialog');
        dialog.offEvent.add(this, closed);

        var load = bindings.getToggle('load');
        var main = bindings.getToggle('main');
        var error = bindings.getToggle('error');
        var formToggles = new toggles.Group(load, main, error);
        formToggles.activate(main);

        var currentPromise = null;

        function edit(data) {
            currentPromise = new promiseUtils.External();
            titleModel.setData(data);
            modeModel.setData("Edit");
            formModel.setData(data);
            return currentPromise.promise;
        }
        this.edit = edit;
        context.edit = edit;

        function getData() {
            return formModel.getData();
        }
        context.getData = getData;

        function submit(evt) {
            evt.preventDefault();
            if (currentPromise !== null) {
                var data = getData();
                var prom = currentPromise;
                currentPromise = null;
                prom.resolve(data);
            }
        }
        this.submit = submit;

        function closed() {
            if (currentPromise !== null) {
                var prom = currentPromise;
                currentPromise = null;
                prom.resolve();
            }
        }

        context.showMain = function () {
            formToggles.activate(main);
        }

        context.showLoad = function () {
            formToggles.activate(load);
        }

        context.showError = function (err) {
            var errorMessage = "No error message";
            if (err.message !== undefined) {
                errorMessage = err.message;
            }
            errorModel.setData(errorMessage);
            formToggles.activate(error);
            currentError = err;
            formModel.getEditor().onChange();
            main.on();
        }

        context.show = function () {
            dialog.on();
        }

        context.close = function () {
            dialog.off();
        }
    }

    module.exports = JsonObjectEditor;
});<commit_msg>Moved validation function.<commit_after>jsns.define("hr.widgets.jsonobjecteditor", [
    "hr.toggles",
    "hr.plugins.jdorn.json-editor",
    "hr.promiseutils"
],
function (exports, module, toggles, jsonEditor, promiseUtils) {
    var defaultError = { path: null };

    "use strict"
    /**
     * This is a generic object editor that uses json-editor to edit objects.
     * The ui is determined by the html. This supports a load, main, error
     * lifecycle, but it is controlled externally. It can also be put on a
     * dialog named 'dialog', which it will activate when required. It also
     * consideres closing this dialog to be a cancellation and will send its
     * promise with an undefined result, which means cancel the operation.
     */
    function JsonObjectEditor(bindings, context) {
        var currentError = null

        var modeModel = bindings.getModel('mode');
        var titleModel = bindings.getModel('title');
        var errorModel = bindings.getModel('error');
        var formModel = new jsonEditor.create(bindings.getHandle("editorHolder"), {
            schema: context.schema,
            disable_edit_json: true,
            disable_properties: true,
            disable_collapse: true,
            show_errors: "always",
            custom_validators: [
                showCurrentErrorValidator
            ]
        });
        var formEditor = formModel.getEditor();

        var dialog = bindings.getToggle('dialog');
        dialog.offEvent.add(this, closed);

        var load = bindings.getToggle('load');
        var main = bindings.getToggle('main');
        var error = bindings.getToggle('error');
        var formToggles = new toggles.Group(load, main, error);
        formToggles.activate(main);

        var currentPromise = null;

        function edit(data) {
            currentPromise = new promiseUtils.External();
            titleModel.setData(data);
            modeModel.setData("Edit");
            formModel.setData(data);
            return currentPromise.promise;
        }
        this.edit = edit;
        context.edit = edit;

        function getData() {
            return formModel.getData();
        }
        context.getData = getData;

        function submit(evt) {
            evt.preventDefault();
            if (currentPromise !== null) {
                var data = getData();
                var prom = currentPromise;
                currentPromise = null;
                prom.resolve(data);
            }
        }
        this.submit = submit;

        function closed() {
            if (currentPromise !== null) {
                var prom = currentPromise;
                currentPromise = null;
                prom.resolve();
            }
        }

        context.showMain = function () {
            formToggles.activate(main);
        }

        context.showLoad = function () {
            formToggles.activate(load);
        }

        context.showError = function (err) {
            var errorMessage = "No error message";
            if (err.message !== undefined) {
                errorMessage = err.message;
            }
            errorModel.setData(errorMessage);
            formToggles.activate(error);
            currentError = err;
            formEditor.onChange();
            main.on();
        }

        context.show = function () {
            dialog.on();
        }

        context.close = function () {
            dialog.off();
        }

        function showCurrentErrorValidator(schema, value, path) {
            if (currentError !== null) {
                if (path === "root") {
                    return {
                        path: path,
                        message: currentError.message
                    }
                }

                if (currentError['errors'] !== undefined) {
                    //walk path to error
                    var pathParts = path.split('.');
                    var errorObject = currentError.errors;
                    for (var i = 1; i < pathParts.length; ++i) { //Skip the root entry
                        errorObject = errorObject[pathParts[i]];
                        if (errorObject === undefined) {
                            break;
                        }
                    }

                    if (errorObject !== undefined && errorObject !== currentError.errors) {
                        return {
                            path: path,
                            message: errorObject
                        };
                    }
                }
            }
            return defaultError;
        }
    }

    module.exports = JsonObjectEditor;
});<|endoftext|>


<commit_before>const isString = (thing) => thing.toString() === thing;
const isArray = Array.isArray;
const noop = ()=>{};

const parseNum = i => parseInt(i,10);
const arrify = arrable => Array.prototype.slice.call(arrable);
const arrifyLayoutString = (layoutString) => layoutString.charAt(0) === "["
				? layoutString.replace(/\[([0-9,]*)\]/,"$1").split(",").map(parseNum)
				: layoutString.split("").map(parseNum);
const sanitizeLayout = (layout) =>  isArray(layout)? layout : isString(layout)? arrifyLayoutString(layout) : [];
const sanitizeGutter = (gutter) => gutter && (gutter + (isString(gutter) ? "" : "px"));

const generateId = ()=>Math.floor(100000*Math.random()+1).toString();
const el = (element) => {
	if (!element) return [];
	if (isString(element)) return arrify(document.querySelectorAll(element));
	if (element.nodeType) return [element];
	if (element.length) return arrify(element);
}

const createNewStyleSheet = () => {
	const styles = document.createElement("style");
	styles.setAttribute("type","text/css");
	styles.setAttribute("id","jzmn-setphotoset-styles");
	styles.appendChild(document.createTextNode(""));
	document.head.appendChild(styles);

	[	".photoset-container:after {content:'';display:table;clear:both;}",
		".photoset-item { display:block;float:left;margin:0;height:auto;}",
		".photoset-last-column {margin-right:0;}",
		".photoset-first-column {clear:left}",
		".photoset-last-row {margin-bottom:0;}"
	].forEach(rule => styles.sheet.insertRule(rule,styles.sheet.cssRules.length));

	return styles;
}
const groupings = {};
let styles = document.querySelector("#jzmn-setphotoset-styles");
const createStyleSheet = ({grouping, gutter}) => {
	if (!styles) { styles = createNewStyleSheet(); }
	if (gutter && !groupings[grouping]) {
		groupings[grouping] = gutter;
		[
			`.photoset-${grouping} .photoset-item:not(.photoset-last-column) { margin-right: calc(${gutter}); }`,
			`.photoset-${grouping} .photoset-item:not(.photoset-last-row) { margin-bottom: calc(${gutter}); }`
		].forEach(rule=>styles.sheet.insertRule(rule,styles.sheet.cssRules.length));
	}
}
const loadPhotoset = (photoset, {immediate, childItem,childHeight,childWidth}) => {
	return new Promise((resolve,reject) => {
		const items = arrify(photoset.querySelectorAll(childItem));
		const complete = _=> resolve(items);
		let goal = items.length;

		if (immediate) { complete() };

		const incrementLoaded = (evt) => {
			if (evt.target && evt.target.matches(childItem) && --goal === 0) {
				complete();
			}
		}

		items.forEach((img,i)=> { if (img.complete) {
			if (--goal === 0) complete();
		}});
		photoset.addEventListener("load",incrementLoaded,true);
		photoset.addEventListener("error",incrementLoaded,true);
	});
}

const calcAspects = (natural, {childHeight,childWidth}={}) => {
	return (items) => {
		return items.map((item,i)=>{
			if (natural) {
				return item.naturalHeight/item.naturalWidth
			} else {
				const aspect = parseInt(item.getAttribute(childHeight)) / parseInt(item.getAttribute(childWidth))
				return isNan(aspect) ? 1 : aspect;
			}
		})
	}
}

const calcLayout = ({layout,gutter}) => {
	return (aspects) => {
		const numRows = layout.length;
		const widths = [];

		layout.reduce( (rowStart,rowLength,layoutIndex, layoutArray) => {
			const rowEnd = rowStart + rowLength;
			const rowAspects = aspects.slice(rowStart,rowEnd);
			const numItems = rowAspects.length;

			let firstWidth = 0;
			const rowWidths = rowAspects.forEach((currAspect,itemIndex)=>{
				let width = 0;
				if (itemIndex == 0) {
					width = firstWidth = 100/rowAspects.reduce((prev,curr)=>prev + currAspect/curr,0);
				}
				else {
					width =  firstWidth*( rowAspects[0]/currAspect );
				}

				const positioning = {
					firstColumn: itemIndex===0,
					lastColumn: itemIndex ===numItems-1,
					lastRow: layoutIndex=== numRows - 1
				}

				widths.push({width, numItems, positioning});
			});

			return rowEnd;
		},0);

		return widths;
	}
}

const applyLayout = (photoset,{childItem,gutter}) => {
	const items = arrify(photoset.querySelectorAll(childItem));
	return (widths) => {
		widths.forEach(({width,numItems,positioning:{firstColumn,lastColumn,lastRow}},itemIndex)=>{
			const item = items[itemIndex];
			item.classList.add("photoset-item");
			item.classList.remove("photoset-last-column","photoset-last-row","photoset-first-column");
			item.setAttribute("style",`width: ${width}%;` + ( gutter ? `width: calc(${width/100}*(100% - ${numItems - 1}*(${gutter})));` : "" ));
			if (firstColumn) item.classList.add("photoset-first-column");
			if (lastColumn) item.classList.add("photoset-last-column");
			if (lastRow) item.classList.add("photoset-last-row");
		});
	}
	return photoset;
}

const setPhotoset = function(set,{
	layout = null,
	immediate = false,
	childItem = "img",
	childHeight = "height",
	childWidth = "width",
	gutter = 0,
	callback = noop,
	createSheet = true,
	layoutAttribute = "data-layout"
}={},grouping=generateId()) {

	immediate = immediate || childItem != 'img';
	set = el(set);
	gutter = sanitizeGutter(gutter);
	if (createSheet) { createStyleSheet({grouping,gutter}); }

	set.forEach(photoset => {
		layout = sanitizeLayout(layout || photoset.getAttribute(layoutAttribute));
		photoset.classList.add("photoset-loading","photoset-container",`photoset-${grouping}`);

		loadPhotoset(photoset,{ immediate, childItem })
			.then(calcAspects({immediate, childHeight,childWidth}))
			.then(calcLayout({layout}))
			.then(applyLayout(photoset,{childItem,gutter}))
			.then(callback);
	});

	return set;
}

export default setPhotoset;
<commit_msg>Added removal of 'photoset-loading' class<commit_after>const isString = (thing) => thing.toString() === thing;
const isArray = Array.isArray;
const noop = ()=>{};

const parseNum = i => parseInt(i,10);
const arrify = arrable => Array.prototype.slice.call(arrable);
const arrifyLayoutString = (layoutString) => layoutString.charAt(0) === "["
				? layoutString.replace(/\[([0-9,]*)\]/,"$1").split(",").map(parseNum)
				: layoutString.split("").map(parseNum);
const sanitizeLayout = (layout) =>  isArray(layout)? layout : isString(layout)? arrifyLayoutString(layout) : [];
const sanitizeGutter = (gutter) => gutter && (gutter + (isString(gutter) ? "" : "px"));

const generateId = ()=>Math.floor(100000*Math.random()+1).toString();
const el = (element) => {
	if (!element) return [];
	if (isString(element)) return arrify(document.querySelectorAll(element));
	if (element.nodeType) return [element];
	if (element.length) return arrify(element);
}

const createNewStyleSheet = () => {
	const styles = document.createElement("style");
	styles.setAttribute("type","text/css");
	styles.setAttribute("id","jzmn-setphotoset-styles");
	styles.appendChild(document.createTextNode(""));
	document.head.appendChild(styles);

	[	".photoset-container:after {content:'';display:table;clear:both;}",
		".photoset-item { display:block;float:left;margin:0;height:auto;}",
		".photoset-last-column {margin-right:0;}",
		".photoset-first-column {clear:left}",
		".photoset-last-row {margin-bottom:0;}"
	].forEach(rule => styles.sheet.insertRule(rule,styles.sheet.cssRules.length));

	return styles;
}
const groupings = {};
let styles = document.querySelector("#jzmn-setphotoset-styles");
const createStyleSheet = ({grouping, gutter}) => {
	if (!styles) { styles = createNewStyleSheet(); }
	if (gutter && !groupings[grouping]) {
		groupings[grouping] = gutter;
		[
			`.photoset-${grouping} .photoset-item:not(.photoset-last-column) { margin-right: calc(${gutter}); }`,
			`.photoset-${grouping} .photoset-item:not(.photoset-last-row) { margin-bottom: calc(${gutter}); }`
		].forEach(rule=>styles.sheet.insertRule(rule,styles.sheet.cssRules.length));
	}
}
const loadPhotoset = (photoset, {immediate, childItem,childHeight,childWidth}) => {
	return new Promise((resolve,reject) => {
		const items = arrify(photoset.querySelectorAll(childItem));
		const complete = _=> resolve(items);
		let goal = items.length;

		if (immediate) { complete() };

		const incrementLoaded = (evt) => {
			if (evt.target && evt.target.matches(childItem) && --goal === 0) {
				complete();
			}
		}

		items.forEach((img,i)=> { if (img.complete) {
			if (--goal === 0) complete();
		}});
		photoset.addEventListener("load",incrementLoaded,true);
		photoset.addEventListener("error",incrementLoaded,true);
	});
}

const calcAspects = (natural, {childHeight,childWidth}={}) => {
	return (items) => {
		return items.map((item,i)=>{
			if (natural) {
				return item.naturalHeight/item.naturalWidth
			} else {
				const aspect = parseInt(item.getAttribute(childHeight)) / parseInt(item.getAttribute(childWidth))
				return isNan(aspect) ? 1 : aspect;
			}
		})
	}
}

const calcLayout = ({layout,gutter}) => {
	return (aspects) => {
		const numRows = layout.length;
		const widths = [];

		layout.reduce( (rowStart,rowLength,layoutIndex, layoutArray) => {
			const rowEnd = rowStart + rowLength;
			const rowAspects = aspects.slice(rowStart,rowEnd);
			const numItems = rowAspects.length;

			let firstWidth = 0;
			const rowWidths = rowAspects.forEach((currAspect,itemIndex)=>{
				let width = 0;
				if (itemIndex == 0) {
					width = firstWidth = 100/rowAspects.reduce((prev,curr)=>prev + currAspect/curr,0);
				}
				else {
					width =  firstWidth*( rowAspects[0]/currAspect );
				}

				const positioning = {
					firstColumn: itemIndex===0,
					lastColumn: itemIndex ===numItems-1,
					lastRow: layoutIndex=== numRows - 1
				}

				widths.push({width, numItems, positioning});
			});

			return rowEnd;
		},0);

		return widths;
	}
}

const applyLayout = (photoset,{childItem,gutter}) => {
	const items = arrify(photoset.querySelectorAll(childItem));
	return (widths) => {
		widths.forEach(({width,numItems,positioning:{firstColumn,lastColumn,lastRow}},itemIndex)=>{
			const item = items[itemIndex];
			item.classList.add("photoset-item");
			item.classList.remove("photoset-last-column","photoset-last-row","photoset-first-column","photoset-loading");
			item.setAttribute("style",`width: ${width}%;` + ( gutter ? `width: calc(${width/100}*(100% - ${numItems - 1}*(${gutter})));` : "" ));
			if (firstColumn) item.classList.add("photoset-first-column");
			if (lastColumn) item.classList.add("photoset-last-column");
			if (lastRow) item.classList.add("photoset-last-row");
		});
	}
	return photoset;
}

const setPhotoset = function(set,{
	layout = null,
	immediate = false,
	childItem = "img",
	childHeight = "height",
	childWidth = "width",
	gutter = 0,
	callback = noop,
	createSheet = true,
	layoutAttribute = "data-layout"
}={},grouping=generateId()) {

	immediate = immediate || childItem != 'img';
	set = el(set);
	gutter = sanitizeGutter(gutter);
	if (createSheet) { createStyleSheet({grouping,gutter}); }

	set.forEach(photoset => {
		layout = sanitizeLayout(layout || photoset.getAttribute(layoutAttribute));
		photoset.classList.add("photoset-loading","photoset-container",`photoset-${grouping}`);

		loadPhotoset(photoset,{ immediate, childItem })
			.then(calcAspects({immediate, childHeight,childWidth}))
			.then(calcLayout({layout}))
			.then(applyLayout(photoset,{childItem,gutter}))
			.then(callback);
	});

	return set;
}

export default setPhotoset;
<|endoftext|>