<commit_before>/**
 * Room Configuration
 *
 * @param {Room} room
 */
function RoomConfig(room)
{
    BaseRoomConfig.call(this, room);

    this.preset       = this.getDefaultPreset();
    this.customPreset = new CustomPreset();
}

RoomConfig.prototype = Object.create(BaseRoomConfig.prototype);
RoomConfig.prototype.constructor = RoomConfig;

/**
 * Bonus classes
 *
 * @type {Object}
 */
RoomConfig.prototype.bonusClasses = {
    BonusSelfSmall: 'bonus-self-small',
    BonusSelfSlow: 'bonus-self-slow',
    BonusSelfFast: 'bonus-self-fast',
    BonusSelfMaster: 'bonus-self-master',
    BonusEnemySlow: 'bonus-enemy-slow',
    BonusEnemyFast: 'bonus-enemy-fast',
    BonusEnemyBig: 'bonus-enemy-big',
    BonusEnemyInverse: 'bonus-enemy-inverse',
    BonusEnemyStraightAngle: 'bonus-enemy-straight-angle',
    BonusAllBorderless: 'bonus-all-borderless',
    BonusAllColor:'bonus-all-color',
    BonusGameClear: 'bonus-all-clear'
};

/**
 * Variables names
 *
 * @type {Object}
 */
RoomConfig.prototype.variablesNames = {
    bonusRate: 'Quantity'
};

/**
 * Presets
 *
 * @type {Object}
 */
RoomConfig.prototype.presets = [
    new DefaultPreset(),
    new SpeedPreset(),
    new SizePreset(),
    new SoloPreset(),
    new EmptyPreset()
];

/**
 * Get available bonuses
 *
 * @return {Array}
 */
RoomConfig.prototype.getBonuses = function()
{
    var bonuses = [];

    for (var bonus in this.bonuses) {
        if (this.bonuses[bonus]) {
            bonuses.push(bonus);
        }
    }

    return bonuses.sort();
};

/**
 * Set bonus value
 *
 * @param {String} bonus
 * @param {Boolean} value
 *
 * @return {Boolean}
 */
RoomConfig.prototype.setBonus = function(bonus, value)
{
    BaseRoomConfig.prototype.setBonus.call(this, bonus, value);
    this.checkPresets();
};

/**
 * Check preset
 */
RoomConfig.prototype.checkPresets = function()
{
    var bonuses = this.getBonuses(),
        preset;

    for (var i = this.presets.length - 1; i >= 0; i--) {
        preset = this.presets[i];
        if (this.bonusesMatch(preset.bonuses, bonuses)) {
            this.preset = preset;

            return;
        }
    }

    this.preset = this.customPreset;
};

/**
 * Bonuses match
 *
 * @param {Array} listA
 * @param {Array} listB
 *
 * @return {Boolean}
 */
RoomConfig.prototype.bonusesMatch = function(listA, listB)
{
    return listA.length === listB.length && listA.sort().toString() === listB.sort().toString();
};

/**
 * IS default preset
 *
 * @return {Boolean}
 */
RoomConfig.prototype.isDefaultPreset = function()
{
    return this.preset === this.getDefaultPreset();
};

/**
 * Get default preset
 *
 * @return {Preset}
 */
RoomConfig.prototype.getDefaultPreset = function()
{
    return this.presets[0];
};

/**
 * Get custom preset
 *
 * @return {CustomPreset}
 */
RoomConfig.prototype.getCustomPreset = function()
{
    return this.customPreset;
};
<commit_msg>Quickfix<commit_after>/**
 * Room Configuration
 *
 * @param {Room} room
 */
function RoomConfig(room)
{
    BaseRoomConfig.call(this, room);

    this.preset       = this.getDefaultPreset();
    this.customPreset = new CustomPreset();
}

RoomConfig.prototype = Object.create(BaseRoomConfig.prototype);
RoomConfig.prototype.constructor = RoomConfig;

/**
 * Bonus classes
 *
 * @type {Object}
 */
RoomConfig.prototype.bonusClasses = {
    BonusSelfSmall: 'bonus-self-small',
    BonusSelfSlow: 'bonus-self-slow',
    BonusSelfFast: 'bonus-self-fast',
    BonusSelfMaster: 'bonus-self-master',
    BonusEnemySlow: 'bonus-enemy-slow',
    BonusEnemyFast: 'bonus-enemy-fast',
    BonusEnemyBig: 'bonus-enemy-big',
    BonusEnemyInverse: 'bonus-enemy-inverse',
    BonusEnemyStraightAngle: 'bonus-enemy-straight-angle',
    BonusAllBorderless: 'bonus-all-borderless',
    BonusAllColor:'bonus-all-color',
    BonusGameClear: 'bonus-all-clear'
};

/**
 * Variables names
 *
 * @type {Object}
 */
RoomConfig.prototype.variablesNames = {
    bonusRate: 'Quantity'
};

/**
 * Presets
 *
 * @type {Object}
 */
RoomConfig.prototype.presets = [
    new DefaultPreset(),
    new SpeedPreset(),
    new SizePreset(),
    new SoloPreset(),
    new EmptyPreset()
];

/**
 * Get available bonuses
 *
 * @return {Array}
 */
RoomConfig.prototype.getBonuses = function()
{
    var bonuses = [];

    for (var bonus in this.bonuses) {
        if (this.bonuses[bonus]) {
            bonuses.push(bonus);
        }
    }

    return bonuses.sort();
};

/**
 * Set bonus value
 *
 * @param {String} bonus
 * @param {Boolean} value
 *
 * @return {Boolean}
 */
RoomConfig.prototype.setBonus = function(bonus, value)
{
    BaseRoomConfig.prototype.setBonus.call(this, bonus, value);
    this.checkPresets();
};

/**
 * Check preset
 */
RoomConfig.prototype.checkPresets = function()
{
    var bonuses = this.getBonuses(),
        preset;

    for (var i = this.presets.length - 1; i >= 0; i--) {
        preset = this.presets[i];
        if (this.bonusesMatch(preset.bonuses, bonuses)) {
            this.preset = preset;

            return;
        }
    }

    this.preset = this.customPreset;
};

/**
 * Bonuses match
 *
 * @param {Array} listA
 * @param {Array} listB
 *
 * @return {Boolean}
 */
RoomConfig.prototype.bonusesMatch = function(listA, listB)
{
    if (typeof(listA) !== 'object' || typeof(listA) !== 'object') {
        return false;
    }

    return listA.length === listB.length && listA.sort().toString() === listB.sort().toString();
};

/**
 * IS default preset
 *
 * @return {Boolean}
 */
RoomConfig.prototype.isDefaultPreset = function()
{
    return this.preset === this.getDefaultPreset();
};

/**
 * Get default preset
 *
 * @return {Preset}
 */
RoomConfig.prototype.getDefaultPreset = function()
{
    return this.presets[0];
};

/**
 * Get custom preset
 *
 * @return {CustomPreset}
 */
RoomConfig.prototype.getCustomPreset = function()
{
    return this.customPreset;
};
<|endoftext|>


<commit_before>import React from 'react'
import { connect } from 'react-redux'
import Helmet from 'react-helmet'
import { reduxForm, reset } from 'redux-form'

import { forgotPassword } from 'actions/auth'
import { DangerAlert } from 'components/Alert'
import { PageContent } from 'components/Content'
import { EmailField } from 'components/Form'
import { required } from 'components/Form/validators'

class ForgotPassword extends React.Component {
  render() {
    const { error, handleSubmit, submitting, pristine } = this.props
    return (
      <PageContent>
        <Helmet>
          <title>Forgot Password</title>
        </Helmet>

Forgot Password

        {error && <DangerAlert>{error}</DangerAlert>}
        <form onSubmit={handleSubmit(forgotPassword)}>
          <EmailField autoFocus name="email"
                      label="Email Address"
                      validate={[required]}
          />

            <button type="submit"
                    className="btn btn-primary"
                    disabled={pristine || submitting}
            >
              {submitting ? 'Submitting...' : 'Submit'}
            </button>

        </form>
      </PageContent>
    )
  }
}

export default reduxForm({
  form: 'forgotPassword',
  onSubmitSuccess: (_, dispatch) => {
    dispatch(reset('forgotPassword'))
  },
})(ForgotPassword)
<commit_msg>center the forgot password form, for consistency with the login and sign up forms<commit_after>import React from 'react'
import { connect } from 'react-redux'
import Helmet from 'react-helmet'
import { reduxForm, reset } from 'redux-form'

import { forgotPassword } from 'actions/auth'
import { DangerAlert } from 'components/Alert'
import { PageContent } from 'components/Content'
import { EmailField } from 'components/Form'
import { required } from 'components/Form/validators'

class ForgotPassword extends React.Component {
  render() {
    const { error, handleSubmit, submitting, pristine } = this.props
    return (
      <PageContent>
        <Helmet>
          <title>Forgot Password</title>
        </Helmet>

Forgot Password

            {error && <DangerAlert>{error}</DangerAlert>}
            <form onSubmit={handleSubmit(forgotPassword)}>
              <EmailField autoFocus name="email"
                          label="Email Address"
                          className="full-width"
                          validate={[required]}
              />

                <button type="submit"
                        className="btn btn-primary"
                        disabled={pristine || submitting}
                >
                  {submitting ? 'Submitting...' : 'Submit'}
                </button>

            </form>

      </PageContent>
    )
  }
}

export default reduxForm({
  form: 'forgotPassword',
  onSubmitSuccess: (_, dispatch) => {
    dispatch(reset('forgotPassword'))
  },
})(ForgotPassword)
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { withStyles, IconButton } from '@material-ui/core';
import take from 'lodash/take';
import DeleteIcon from '@material-ui/icons/Delete';
import compose from 'recompose/compose';
import { withState } from 'recompose';
import DeleteConnector from './Question/DeleteConnector';
import Router from 'next/router';
import DeleteWarningDialog from './DeleteWarningDialog';

const styles = theme => ({
  root: {
    '&:hover': {
      color: 'inherit',
    },
  },
});

const deleteHandler = (deleteQuestion, question, setSubmitting) => () => {
  setSubmitting(true);
  deleteQuestion({
    variables: {
      id: question.id,
    },
  })
    .then(response => {
      console.log(`Delete Question Mutation response: `); // eslint-disable-line no-console
      console.log(response); // eslint-disable-line no-console
      setSubmitting(false);
      Router.push('/admin/questoes');
    })
    .catch(error => {
      // Something went wrong, such as incorrect password, or no network
      // available, etc.
      console.error(error); // eslint-disable-line no-console
    });
};

const onCancelDelete = (setDeleteWarningOpen, setSubmitting) => () => {
  setSubmitting(false);
  setDeleteWarningOpen(false);
};

/**
 * @param {string} str String to truncate
 */
const truncate = str =>
  take(str.split(' '), 7)
    .join(' ')
    .concat(' [...]');

function SafeDeleteIconButton({
  classes,
  deleteWarningOpen,
  question,
  setDeleteWarningOpen,
  setSubmitting,
  submitting,
  ...otherProps
}) {
  return (
    <DeleteConnector>
      {deleteQuestion => (
        <React.Fragment>
          <IconButton
            className={classes.root}
            disabled={submitting}
            onClick={() => setDeleteWarningOpen(true)}
            {...otherProps}
          >
            <DeleteIcon />
          </IconButton>
          <DeleteWarningDialog
            title={`Excluir “${truncate(question.wording)}“?`}
            content={`A questão “${truncate(question.wording)}” será apagada permanentemente.`}
            isSubmitting={submitting}
            open={deleteWarningOpen}
            onCancel={onCancelDelete(setDeleteWarningOpen, setSubmitting)}
            onSuccess={deleteHandler(deleteQuestion, question, setSubmitting)}
          />
        </React.Fragment>
      )}
    </DeleteConnector>
  );
}

SafeDeleteIconButton.propTypes = {
  classes: PropTypes.object.isRequired,
  deleteWarningOpen: PropTypes.bool.isRequired,
  question: PropTypes.shape({
    id: PropTypes.string.isRequired,
  }).isRequired,
  setDeleteWarningOpen: PropTypes.func.isRequired,
  setSubmitting: PropTypes.func.isRequired,
  submitting: PropTypes.bool.isRequired,
};

export default compose(
  withState('deleteWarningOpen', 'setDeleteWarningOpen', false),
  withState('submitting', 'setSubmitting', false),
  withStyles(styles),
)(SafeDeleteIconButton);
<commit_msg>Refactor truncate function in SafeDeleteIconButton<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { withStyles, IconButton } from '@material-ui/core';
import take from 'lodash/take';
import DeleteIcon from '@material-ui/icons/Delete';
import compose from 'recompose/compose';
import { withState } from 'recompose';
import DeleteConnector from './Question/DeleteConnector';
import Router from 'next/router';
import DeleteWarningDialog from './DeleteWarningDialog';

const styles = theme => ({
  root: {
    '&:hover': {
      color: 'inherit',
    },
  },
});

const deleteHandler = (deleteQuestion, question, setSubmitting) => () => {
  setSubmitting(true);
  deleteQuestion({
    variables: {
      id: question.id,
    },
  })
    .then(response => {
      console.log(`Delete Question Mutation response: `); // eslint-disable-line no-console
      console.log(response); // eslint-disable-line no-console
      setSubmitting(false);
      Router.push('/admin/questoes');
    })
    .catch(error => {
      // Something went wrong, such as incorrect password, or no network
      // available, etc.
      console.error(error); // eslint-disable-line no-console
    });
};

const onCancelDelete = (setDeleteWarningOpen, setSubmitting) => () => {
  setSubmitting(false);
  setDeleteWarningOpen(false);
};

/**
 * Truncates a string to a certain number of words.
 * @param {String} str String to truncate
 * @param {Number} noWords Number of words
 */
const truncate = (str, noWords) =>
  str
    .split(' ')
    .splice(0, noWords)
    .join(' ')
    .concat(' [...]');

function SafeDeleteIconButton({
  classes,
  deleteWarningOpen,
  question,
  setDeleteWarningOpen,
  setSubmitting,
  submitting,
  ...otherProps
}) {
  return (
    <DeleteConnector>
      {deleteQuestion => (
        <React.Fragment>
          <IconButton
            className={classes.root}
            disabled={submitting}
            onClick={() => setDeleteWarningOpen(true)}
            {...otherProps}
          >
            <DeleteIcon />
          </IconButton>
          <DeleteWarningDialog
            title={`Excluir “${truncate(question.wording, 7)}“?`}
            content={`A questão “${truncate(question.wording, 7)}” será apagada permanentemente.`}
            isSubmitting={submitting}
            open={deleteWarningOpen}
            onCancel={onCancelDelete(setDeleteWarningOpen, setSubmitting)}
            onSuccess={deleteHandler(deleteQuestion, question, setSubmitting)}
          />
        </React.Fragment>
      )}
    </DeleteConnector>
  );
}

SafeDeleteIconButton.propTypes = {
  classes: PropTypes.object.isRequired,
  deleteWarningOpen: PropTypes.bool.isRequired,
  question: PropTypes.shape({
    id: PropTypes.string.isRequired,
  }).isRequired,
  setDeleteWarningOpen: PropTypes.func.isRequired,
  setSubmitting: PropTypes.func.isRequired,
  submitting: PropTypes.bool.isRequired,
};

export default compose(
  withState('deleteWarningOpen', 'setDeleteWarningOpen', false),
  withState('submitting', 'setSubmitting', false),
  withStyles(styles),
)(SafeDeleteIconButton);
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { withStyles, IconButton } from '@material-ui/core';
import DeleteIcon from '@material-ui/icons/Delete';
import DeleteConnector from './Question/DeleteConnector';
import Router from 'next/router';

const styles = theme => ({
  root: {
    '&:hover': {
      color: 'inherit',
    },
  },
});

const deleteSubmitHandler = (deleteQuestion, question) => () => {
  deleteQuestion({
    variables: {
      id: question.id,
    },
  })
    .then(response => {
      console.log(`Delete Question Mutation response: `); // eslint-disable-line no-console
      console.log(response); // eslint-disable-line no-console
      Router.push('/admin/questoes');
    })
    .catch(error => {
      // Something went wrong, such as incorrect password, or no network
      // available, etc.
      console.error(error); // eslint-disable-line no-console
    });
};

// TODO: Show a warning dialog for confirmation before deleting
function SafeDeleteIconButton({ classes, question, ...otherProps }) {
  return (
    <DeleteConnector>
      {deleteQuestion => (
        <React.Fragment>
          <IconButton
            className={classes.root}
            onClick={deleteSubmitHandler(deleteQuestion, question)}
            {...otherProps}
          >
            <DeleteIcon />
          </IconButton>
        </React.Fragment>
      )}
    </DeleteConnector>
  );
}

SafeDeleteIconButton.propTypes = {
  classes: PropTypes.object.isRequired,
  question: PropTypes.shape({
    id: PropTypes.string.isRequired,
  }).isRequired,
};

export default withStyles(styles)(SafeDeleteIconButton);
<commit_msg>Add dialog to SafeDeleteIconButton in QuestionDetails<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import {
  withStyles,
  IconButton,
  Dialog,
  DialogTitle,
  DialogContent,
  DialogContentText,
  DialogActions,
  Button,
} from '@material-ui/core';
import take from 'lodash/take';
import DeleteIcon from '@material-ui/icons/Delete';
import compose from 'recompose/compose';
import { withState } from 'recompose';
import DeleteConnector from './Question/DeleteConnector';
import Router from 'next/router';

const styles = theme => ({
  root: {
    '&:hover': {
      color: 'inherit',
    },
  },
  questionWording: {
    fontStyle: 'italic',
  },
});

const deleteSubmitHandler = (deleteQuestion, question, setSubmitting) => () => {
  setSubmitting(true);
  deleteQuestion({
    variables: {
      id: question.id,
    },
  })
    .then(response => {
      console.log(`Delete Question Mutation response: `); // eslint-disable-line no-console
      console.log(response); // eslint-disable-line no-console
      setSubmitting(false);
      Router.push('/admin/questoes');
    })
    .catch(error => {
      // Something went wrong, such as incorrect password, or no network
      // available, etc.
      console.error(error); // eslint-disable-line no-console
    });
};

const openDeleteWarningDialog = setDeleteWarningOpen => () => setDeleteWarningOpen(true);

const onCancelDelete = (setDeleteWarningOpen, setSubmitting) => () => {
  setSubmitting(false);
  setDeleteWarningOpen(false);
};

/**
 * @param {string} str String to truncate
 */
const truncate = str =>
  take(str.split(' '), 7)
    .join(' ')
    .concat(' [...]');

function SafeDeleteIconButton({
  classes,
  deleteWarningOpen,
  question,
  setDeleteWarningOpen,
  setSubmitting,
  submitting,
  ...otherProps
}) {
  return (
    <DeleteConnector>
      {deleteQuestion => (
        <React.Fragment>
          <IconButton
            className={classes.root}
            disabled={submitting}
            onClick={openDeleteWarningDialog(setDeleteWarningOpen)}
            {...otherProps}
          >
            <DeleteIcon />
          </IconButton>
          <Dialog
            open={deleteWarningOpen}
            onClose={onCancelDelete(setDeleteWarningOpen, setSubmitting)}
            aria-labelledby="alert-dialog-title"
            aria-describedby="alert-dialog-description"
          >
            <DialogTitle id="alert-dialog-title">
              {'Excluir '}
              {truncate(question.wording)}
              {' ?'}
            </DialogTitle>
            <DialogContent>
              <DialogContentText id="alert-dialog-description">
                {'A questão '}
                {truncate(question.wording)}
                {' será apagada permanentemente.'}
              </DialogContentText>
            </DialogContent>
            <DialogActions>
              <Button
                disabled={submitting}
                onClick={onCancelDelete(setDeleteWarningOpen, setSubmitting)}
                color="secondary"
              >
                Cancelar
              </Button>
              <Button
                disabled={submitting}
                onClick={deleteSubmitHandler(deleteQuestion, question, setSubmitting)}
                color="secondary"
                autoFocus
              >
                Excluir
              </Button>
            </DialogActions>
          </Dialog>
        </React.Fragment>
      )}
    </DeleteConnector>
  );
}

SafeDeleteIconButton.propTypes = {
  classes: PropTypes.object.isRequired,
  deleteWarningOpen: PropTypes.bool.isRequired,
  question: PropTypes.shape({
    id: PropTypes.string.isRequired,
  }).isRequired,
  setDeleteWarningOpen: PropTypes.func.isRequired,
  setSubmitting: PropTypes.func.isRequired,
  submitting: PropTypes.bool.isRequired,
};

export default compose(
  withState('deleteWarningOpen', 'setDeleteWarningOpen', false),
  withState('submitting', 'setSubmitting', false),
  withStyles(styles),
)(SafeDeleteIconButton);
<|endoftext|>


<commit_before>'use strict';

angular.module('registryApp')
    .controller('RepoCtrl', ['$scope', '$routeParams', '$q', 'Repo', 'App', 'Build', 'Header', function ($scope, $routeParams, $q, Repo, App, Build, Header) {

        Header.setActive('repos');

        $scope.view = {};
        $scope.view.loading = true;
        $scope.view.tab = 'apps';
        $scope.view.repo = null;
        $scope.view.apps = [];
        $scope.view.builds = [];
        $scope.view.resize = false;

        $scope.view.paginator = {
            apps: {
                prev: false,
                next: false,
                page: 1,
                total: 0,
                perPage: 25,
                loading: false
            },
            builds: {
                prev: false,
                next: false,
                page: 1,
                total: 0,
                perPage: 25,
                loading: false
            }
        };

        var repoId = $routeParams.id.replace(/&/g, '/');

        Repo.getRepo(repoId).then(function (repo) {

            $scope.view.repo = repo;

            $q.all([
                App.getApps(0, repoId),
                Build.getBuilds(0, repoId)
            ]).then(function (result) {

                $scope.view.loading = false;

                $scope.view.apps = itemsLoaded(result[0], 'apps');
                $scope.view.builds = itemsLoaded(result[1], 'builds');
            });

        });

        /**
         * Callback when items are loaded
         *
         * @param result
         */
        var itemsLoaded = function (result, tab) {

            $scope.view.paginator[tab].prev = $scope.view.paginator[tab].page > 1;
            $scope.view.paginator[tab].next = ($scope.view.paginator[tab].page * $scope.view.paginator[tab].perPage) < result.total;
            $scope.view.paginator[tab].total = Math.ceil(result.total / $scope.view.paginator[tab].perPage);

            return result.items;

        };

        /**
         * Switch the tab
         * @param tab
         */
        $scope.switchTab = function (tab) {
            $scope.view.tab = tab;
            $scope.view.resize = true;
        };

        /**
         * Go to the next/prev page
         *
         * @param dir
         */
        $scope.goToPage = function(dir) {

            if (!$scope.view.paginator[$scope.view.tab].loading) {

                if (dir === 'prev') {
                    $scope.view.paginator[$scope.view.tab].page -= 1;
                }
                if (dir === 'next') {
                    $scope.view.paginator[$scope.view.tab].page += 1;
                }

                $scope.view.paginator[$scope.view.tab].loading = true;
                var offset = ($scope.view.paginator[$scope.view.tab].page - 1) * $scope.view.paginator[$scope.view.tab].perPage;

                if ($scope.view.tab === 'apps') {
                    App.getApps(offset, repoId).then(function (result) {
                        $scope.view.apps = itemsLoaded(result, 'apps');
                        $scope.view.paginator.apps.loading = false;
                    });
                }

                if ($scope.view.tab === 'builds') {
                    Build.getBuilds(offset, repoId).then(function (result) {
                        $scope.view.builds = itemsLoaded(result, 'builds');
                        $scope.view.paginator.builds.loading = false;
                    });
                }
            }
        };

    }]);
<commit_msg>fix the app filter by repo<commit_after>'use strict';

angular.module('registryApp')
    .controller('RepoCtrl', ['$scope', '$routeParams', '$q', 'Repo', 'App', 'Build', 'Header', function ($scope, $routeParams, $q, Repo, App, Build, Header) {

        Header.setActive('repos');

        $scope.view = {};
        $scope.view.loading = true;
        $scope.view.tab = 'apps';
        $scope.view.repo = null;
        $scope.view.apps = [];
        $scope.view.builds = [];
        $scope.view.resize = false;

        $scope.view.paginator = {
            apps: {
                prev: false,
                next: false,
                page: 1,
                total: 0,
                perPage: 25,
                loading: false
            },
            builds: {
                prev: false,
                next: false,
                page: 1,
                total: 0,
                perPage: 25,
                loading: false
            }
        };

        var repoId = $routeParams.id.replace(/&/g, '/');

        Repo.getRepo(repoId).then(function (repo) {

            $scope.view.repo = repo;

            $q.all([
                App.getApps(0, '', repoId),
                Build.getBuilds(0, repoId)
            ]).then(function (result) {

                $scope.view.loading = false;

                $scope.view.apps = itemsLoaded(result[0], 'apps');
                $scope.view.builds = itemsLoaded(result[1], 'builds');
            });

        });

        /**
         * Callback when items are loaded
         *
         * @param result
         */
        var itemsLoaded = function (result, tab) {

            $scope.view.paginator[tab].prev = $scope.view.paginator[tab].page > 1;
            $scope.view.paginator[tab].next = ($scope.view.paginator[tab].page * $scope.view.paginator[tab].perPage) < result.total;
            $scope.view.paginator[tab].total = Math.ceil(result.total / $scope.view.paginator[tab].perPage);

            return result.items;

        };

        /**
         * Switch the tab
         * @param tab
         */
        $scope.switchTab = function (tab) {
            $scope.view.tab = tab;
            $scope.view.resize = true;
        };

        /**
         * Go to the next/prev page
         *
         * @param dir
         */
        $scope.goToPage = function(dir) {

            if (!$scope.view.paginator[$scope.view.tab].loading) {

                if (dir === 'prev') {
                    $scope.view.paginator[$scope.view.tab].page -= 1;
                }
                if (dir === 'next') {
                    $scope.view.paginator[$scope.view.tab].page += 1;
                }

                $scope.view.paginator[$scope.view.tab].loading = true;
                var offset = ($scope.view.paginator[$scope.view.tab].page - 1) * $scope.view.paginator[$scope.view.tab].perPage;

                if ($scope.view.tab === 'apps') {
                    App.getApps(offset, '', repoId).then(function (result) {
                        $scope.view.apps = itemsLoaded(result, 'apps');
                        $scope.view.paginator.apps.loading = false;
                    });
                }

                if ($scope.view.tab === 'builds') {
                    Build.getBuilds(offset, repoId).then(function (result) {
                        $scope.view.builds = itemsLoaded(result, 'builds');
                        $scope.view.paginator.builds.loading = false;
                    });
                }
            }
        };

    }]);
<|endoftext|>


<commit_before>function date_default_timezone_get () {
    // http://kevin.vanzonneveld.net
    // +   original by: Brett Zamir
    // -    depends on: timezone_abbreviations_list
    // %        note 1: Uses global: php_js to store the default timezone
    // *     example 1: date_default_timezone_get();
    // *     returns 1: 'unknown';

    var tal = {}, abbr = '', i = 0, today = new Date();

	if (this.php_js && this.php_js.default_timezone) {
		return this.php_js.default_timezone;
	}
	tal = timezone_abbreviations_list();
	for (abbr in tal) {
		for (i=0; i < tal[abbr].length; i++) {
			if (tal[abbr][i].offset === -today.getTimezoneOffset()*60) {
				return tal[abbr][i].timezone_id;
			}
		}
	}
	return 'UTC';
}<commit_msg>Allow for timezone to be on ini or ENV for date_default_timezone_get()<commit_after>function date_default_timezone_get () {
    // http://kevin.vanzonneveld.net
    // +   original by: Brett Zamir
    // -    depends on: timezone_abbreviations_list
    // %        note 1: Uses global: php_js to store the default timezone
    // *     example 1: date_default_timezone_get();
    // *     returns 1: 'unknown';

    var tal = {}, abbr = '', i = 0, today = new Date();

	if (this.php_js) {
        if (this.php_js.default_timezone) { // set by date_default_timezone_set
            return this.php_js.default_timezone;
        }
        if (this.php_js.ENV && this.php_js.ENV['TZ']) { // getenv
            return this.php_js.ENV['TZ'];
        }
        if (this.php_js.ini && this.php_js.ini['date.timezone']) { // e.g., if set by init_set()
            return this.php_js.ini['date.timezone'];
        }
    }
    // Get from system
	tal = timezone_abbreviations_list();
	for (abbr in tal) {
		for (i=0; i < tal[abbr].length; i++) {
			if (tal[abbr][i].offset === -today.getTimezoneOffset()*60) {
				return tal[abbr][i].timezone_id;
			}
		}
	}
	return 'UTC';
}<|endoftext|>


<commit_before>import path from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import { optimize } from 'webpack';

const { UglifyJsPlugin } = optimize;

const config = {
  devtool: 'cheap-module-source-map',
  name: 'react-redux-spinner-example',
  entry: [
    './example/index.js'
  ],
  output: {
    path: path.join(__dirname, '..', 'dist-example'),
    filename: 'index.js',
    publicPath: '/'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: [ __dirname, path.join(__dirname, '..', 'src/') ],
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        loader: 'style-loader!css-loader'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      inject: 'head'
    })
  ]
};

if (process.env.NODE_ENV !== 'development') {
  config.plugins.push(new UglifyJsPlugin({
    output: {
      comments: false
    }
  }));
}

module.exports = config;
<commit_msg>Remove publicPath from example<commit_after>import path from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import { optimize } from 'webpack';

const { UglifyJsPlugin } = optimize;

const config = {
  devtool: 'cheap-module-source-map',
  name: 'react-redux-spinner-example',
  entry: [
    './example/index.js'
  ],
  output: {
    path: path.join(__dirname, '..', 'dist-example'),
    filename: 'index.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: [ __dirname, path.join(__dirname, '..', 'src/') ],
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        loader: 'style-loader!css-loader'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      inject: 'head'
    })
  ]
};

if (process.env.NODE_ENV !== 'development') {
  config.plugins.push(new UglifyJsPlugin({
    output: {
      comments: false
    }
  }));
}

module.exports = config;
<|endoftext|>


<commit_before>import React from "react"
import { connect } from "react-redux"
import ReactTooltip from 'react-tooltip'
import { getTranslate } from 'react-localize-redux'
import * as common from "../../utils/common"
import { filterInputNumber } from "../../utils/validators";
import * as limitOrderActions from "../../actions/limitOrderActions"
import * as globalActions from "../../actions/globalActions"
import { TokenSelector } from "../TransactionCommon"
import constants from "../../services/constants"

import { default as _ } from 'underscore';

import { LimitOrderCompareRate } from "../LimitOrder";
import * as converters from "../../utils/converter";

@connect((store, props) => {
  const account = store.account.account
  const translate = getTranslate(store.locale)
  const tokens = store.tokens.tokens
  const limitOrder = store.limitOrder
  const ethereum = store.connection.ethereum

  return {
    translate, limitOrder, tokens, account, ethereum,
    global: store.global

  }
})

export default class LimitOrderForm extends React.Component {

  getEthereumInstance = () => {
    var ethereum = this.props.ethereum
    if (!ethereum){
      ethereum = new EthereumService()
    }
    return ethereum
  }

  fetchCurrentRate = (sourceAmount) => {
    var source = this.props.limitOrder.sourceToken
    var dest = this.props.limitOrder.destToken

    var sourceTokenSymbol = this.props.limitOrder.sourceTokenSymbol
    var isManual = true

    var ethereum = this.getEthereumInstance()
    this.props.dispatch(limitOrderActions.updateRate(ethereum, source, dest, sourceAmount, sourceTokenSymbol, isManual));

  }

  lazyFetchRate = _.debounce(this.fetchCurrentRate, 500)

  handleInputChange = (e, type, referValue) => {
    var value = e.target.value
    var check = filterInputNumber(e, value, referValue)
    if (check) {
      if (value < 0) return
      this.props.dispatch(limitOrderActions.inputChange(type, value));

      if (type === "source"){
        this.lazyFetchRate(value)
      }

      // this.lazyEstimateGas()

      // this.validateRateAndSource(value)
    }
  };

  addSrcAmountByBalancePercentage = (balancePercentage) => {
    const srcTokenSymbol = this.props.limitOrder.sourceTokenSymbol;
    const srcToken = this.props.tokens[srcTokenSymbol];
    const srcTokenBalance = converters.toT(srcToken.balance, srcToken.decimals);

    let sourceAmountByPercentage = srcTokenBalance * (balancePercentage / 100);

    if (!+sourceAmountByPercentage) sourceAmountByPercentage = 0;

    this.props.dispatch(limitOrderActions.inputChange('source', sourceAmountByPercentage));
  };

  // chooseToken = (symbol, address, type) => {
  //   this.props.dispatch(limitOrderActions.selectTokenAsync(symbol, address, type))
  //   var path
  //   if (type === "source") {
  //     path = constants.BASE_HOST + `/${constants.LIMIT_ORDER_CONFIG.path}/` + symbol.toLowerCase() + "-" + this.props.limitOrder.destTokenSymbol.toLowerCase()
  //     this.props.global.analytics.callTrack("trackChooseToken", "from", symbol);
  //   } else {
  //     path = constants.BASE_HOST + `/${constants.LIMIT_ORDER_CONFIG.path}/` + this.props.limitOrder.sourceTokenSymbol.toLowerCase() + "-" + symbol.toLowerCase()
  //     this.props.global.analytics.callTrack("trackChooseToken", "to", symbol);
  //   }

  //   path = common.getPath(path, constants.LIST_PARAMS_SUPPORTED)
  //   this.props.dispatch(globalActions.goToRoute(path))
  //   this.props.dispatch(globalActions.updateTitleWithRate());
  // }

  render() {
    var errorTooltip = ""
    var errorLimitOrder = ""

    return (

        {this.props.account !== false && (

 this.addSrcAmountByBalancePercentage(25)}>25%

 this.addSrcAmountByBalancePercentage(50)}>50%

 this.addSrcAmountByBalancePercentage(80)}>80%

 this.addSrcAmountByBalancePercentage(100)}>100%

        )}

{this.props.translate("transaction.exchange_from") || "From"}:

          <div className={`exchange-content__item exchange-content__item--left select-token`}
          >
            <div className={`input-div-content`}>

                <TokenSelector
                      type="source"
                      focusItem={this.props.limitOrder.sourceTokenSymbol}
                      listItem={this.props.tokens}
                      chooseToken={this.props.chooseToken}
                    />

              <div className={`exchange-content__input-container`}>

                  <div id="limit-order-error-trigger" className="input-tooltip-wrapper" data-tip={`<div>${errorTooltip}</div>`} data-html={true} data-event='click focus' data-for="swap-error" data-scroll-hide="false">
                    <input
                      className={`exchange-content__input`}
                      min="0"
                      step="0.000001"
                      placeholder="0" autoFocus
                      type={this.props.global.isOnMobile ? "number" : "text"} maxLength="50" autoComplete="off"
                      value={this.props.limitOrder.sourceAmount}
                      // onFocus={props.input.sourceAmount.onFocus}
                      // onBlur={props.input.sourceAmount.onBlur}
                      onChange={(e) => this.handleInputChange(e, "source", this.props.limitOrder.sourceAmount)}
                    />

                  {/* {props.account !== false && (
                       <div className={`exchange-content__label exchange-content__label--right trigger-swap-modal ${errorExchange ? "error" : ""}`}>{props.swapBalance}

                     )} */}

            {errorLimitOrder &&
              <ReactTooltip globalEventOff="click" html={true} place="bottom" className="select-token-error" id="swap-error" type="light" />
            }

{this.props.translate("transaction.exchange_to") || "To"}:

            <div className={`input-div-content`}>

                  <TokenSelector
                    type="des"
                    focusItem={this.props.limitOrder.destTokenSymbol}
                    listItem={this.props.tokens}
                    chooseToken={this.props.chooseToken}
                  />

              <div className={`exchange-content__input-container`}>

                  <input
                    className={`exchange-content__input`}
                    step="0.000001"
                    placeholder="0"
                    min="0"
                    type={this.props.global.isOnMobile ? "number" : "text"}
                    maxLength="50"
                    autoComplete="off"
                    value={this.props.limitOrder.destAmount}
                    onChange={(e) => this.handleInputChange(e, "dest", this.props.limitOrder.destAmount)}
                  />

{this.props.translate("transaction.rate_label") || "Rate"}:

            <div className={`input-div-content`}>

                {this.props.limitOrder.sourceTokenSymbol} / {this.props.limitOrder.destTokenSymbol}

                <input
                  className={`exchange-content__input`}
                  step="0.000001"
                  placeholder="0"
                  min="0"
                  type={this.props.global.isOnMobile ? "number" : "text"}
                  maxLength="50"
                  autoComplete="off"
                  value={this.props.limitOrder.triggerRate}
                  onChange={(e) => this.handleInputChange(e, "rate", this.props.limitOrder.triggerRate)}
                />

        <LimitOrderCompareRate />

    )
  }
}
<commit_msg>fix choose dest token<commit_after>import React from "react"
import { connect } from "react-redux"
import ReactTooltip from 'react-tooltip'
import { getTranslate } from 'react-localize-redux'
import * as common from "../../utils/common"
import { filterInputNumber } from "../../utils/validators";
import * as limitOrderActions from "../../actions/limitOrderActions"
import * as globalActions from "../../actions/globalActions"
import { TokenSelector } from "../TransactionCommon"
import constants from "../../services/constants"

import { default as _ } from 'underscore';

import { LimitOrderCompareRate } from "../LimitOrder";
import * as converters from "../../utils/converter";

@connect((store, props) => {
  const account = store.account.account
  const translate = getTranslate(store.locale)
  const tokens = store.tokens.tokens
  const limitOrder = store.limitOrder
  const ethereum = store.connection.ethereum

  return {
    translate, limitOrder, tokens, account, ethereum,
    global: store.global

  }
})

export default class LimitOrderForm extends React.Component {

  getEthereumInstance = () => {
    var ethereum = this.props.ethereum
    if (!ethereum){
      ethereum = new EthereumService()
    }
    return ethereum
  }

  fetchCurrentRate = (sourceAmount) => {
    var source = this.props.limitOrder.sourceToken
    var dest = this.props.limitOrder.destToken

    var sourceTokenSymbol = this.props.limitOrder.sourceTokenSymbol
    var isManual = true

    var ethereum = this.getEthereumInstance()
    this.props.dispatch(limitOrderActions.updateRate(ethereum, source, dest, sourceAmount, sourceTokenSymbol, isManual));

  }

  lazyFetchRate = _.debounce(this.fetchCurrentRate, 500)

  handleInputChange = (e, type, referValue) => {
    var value = e.target.value
    var check = filterInputNumber(e, value, referValue)
    if (check) {
      if (value < 0) return
      this.props.dispatch(limitOrderActions.inputChange(type, value));

      if (type === "source"){
        this.lazyFetchRate(value)
      }

      // this.lazyEstimateGas()

      // this.validateRateAndSource(value)
    }
  };

  addSrcAmountByBalancePercentage = (balancePercentage) => {
    const srcTokenSymbol = this.props.limitOrder.sourceTokenSymbol;
    const srcToken = this.props.tokens[srcTokenSymbol];
    const srcTokenBalance = converters.toT(srcToken.balance, srcToken.decimals);

    let sourceAmountByPercentage = srcTokenBalance * (balancePercentage / 100);

    if (!+sourceAmountByPercentage) sourceAmountByPercentage = 0;

    this.props.dispatch(limitOrderActions.inputChange('source', sourceAmountByPercentage));
  };

  // chooseToken = (symbol, address, type) => {
  //   this.props.dispatch(limitOrderActions.selectTokenAsync(symbol, address, type))
  //   var path
  //   if (type === "source") {
  //     path = constants.BASE_HOST + `/${constants.LIMIT_ORDER_CONFIG.path}/` + symbol.toLowerCase() + "-" + this.props.limitOrder.destTokenSymbol.toLowerCase()
  //     this.props.global.analytics.callTrack("trackChooseToken", "from", symbol);
  //   } else {
  //     path = constants.BASE_HOST + `/${constants.LIMIT_ORDER_CONFIG.path}/` + this.props.limitOrder.sourceTokenSymbol.toLowerCase() + "-" + symbol.toLowerCase()
  //     this.props.global.analytics.callTrack("trackChooseToken", "to", symbol);
  //   }

  //   path = common.getPath(path, constants.LIST_PARAMS_SUPPORTED)
  //   this.props.dispatch(globalActions.goToRoute(path))
  //   this.props.dispatch(globalActions.updateTitleWithRate());
  // }

  render() {
    var errorTooltip = ""
    var errorLimitOrder = ""

    return (

        {this.props.account !== false && (

 this.addSrcAmountByBalancePercentage(25)}>25%

 this.addSrcAmountByBalancePercentage(50)}>50%

 this.addSrcAmountByBalancePercentage(80)}>80%

 this.addSrcAmountByBalancePercentage(100)}>100%

        )}

{this.props.translate("transaction.exchange_from") || "From"}:

          <div className={`exchange-content__item exchange-content__item--left select-token`}
          >
            <div className={`input-div-content`}>

                <TokenSelector
                      type="source"
                      focusItem={this.props.limitOrder.sourceTokenSymbol}
                      listItem={this.props.tokens}
                      chooseToken={this.props.chooseToken}
                    />

              <div className={`exchange-content__input-container`}>

                  <div id="limit-order-error-trigger" className="input-tooltip-wrapper" data-tip={`<div>${errorTooltip}</div>`} data-html={true} data-event='click focus' data-for="swap-error" data-scroll-hide="false">
                    <input
                      className={`exchange-content__input`}
                      min="0"
                      step="0.000001"
                      placeholder="0" autoFocus
                      type={this.props.global.isOnMobile ? "number" : "text"} maxLength="50" autoComplete="off"
                      value={this.props.limitOrder.sourceAmount}
                      // onFocus={props.input.sourceAmount.onFocus}
                      // onBlur={props.input.sourceAmount.onBlur}
                      onChange={(e) => this.handleInputChange(e, "source", this.props.limitOrder.sourceAmount)}
                    />

                  {/* {props.account !== false && (
                       <div className={`exchange-content__label exchange-content__label--right trigger-swap-modal ${errorExchange ? "error" : ""}`}>{props.swapBalance}

                     )} */}

            {errorLimitOrder &&
              <ReactTooltip globalEventOff="click" html={true} place="bottom" className="select-token-error" id="swap-error" type="light" />
            }

{this.props.translate("transaction.exchange_to") || "To"}:

            <div className={`input-div-content`}>

                  <TokenSelector
                    type="dest"
                    focusItem={this.props.limitOrder.destTokenSymbol}
                    listItem={this.props.tokens}
                    chooseToken={this.props.chooseToken}
                  />

              <div className={`exchange-content__input-container`}>

                  <input
                    className={`exchange-content__input`}
                    step="0.000001"
                    placeholder="0"
                    min="0"
                    type={this.props.global.isOnMobile ? "number" : "text"}
                    maxLength="50"
                    autoComplete="off"
                    value={this.props.limitOrder.destAmount}
                    onChange={(e) => this.handleInputChange(e, "dest", this.props.limitOrder.destAmount)}
                  />

{this.props.translate("transaction.rate_label") || "Rate"}:

            <div className={`input-div-content`}>

                {this.props.limitOrder.sourceTokenSymbol} / {this.props.limitOrder.destTokenSymbol}

                <input
                  className={`exchange-content__input`}
                  step="0.000001"
                  placeholder="0"
                  min="0"
                  type={this.props.global.isOnMobile ? "number" : "text"}
                  maxLength="50"
                  autoComplete="off"
                  value={this.props.limitOrder.triggerRate}
                  onChange={(e) => this.handleInputChange(e, "rate", this.props.limitOrder.triggerRate)}
                />

        <LimitOrderCompareRate />

    )
  }
}
<|endoftext|>


<commit_before>import { clearSelection } from '../utils/selection.js'
import { prevent } from '../utils/event.js'

export default {
  props: {
    target: {
      type: [Boolean, String],
      default: true
    },
    noParentEvent: Boolean,
    contextMenu: Boolean
  },

  watch: {
    contextMenu (val) {
      if (this.anchorEl !== void 0) {
        this.__unconfigureAnchorEl(!val)
        this.__configureAnchorEl(val)
      }
    },

    target () {
      if (this.anchorEl !== void 0) {
        this.__unconfigureAnchorEl()
      }

      this.__pickAnchorEl()
    },

    noParentEvent (val) {
      if (this.anchorEl !== void 0) {
        if (val === true) {
          this.__unconfigureAnchorEl()
        }
        else {
          this.__configureAnchorEl()
        }
      }
    }
  },

  methods: {
    __showCondition (evt) {
      // abort with no parent configured or on multi-touch
      if (this.anchorEl === void 0) {
        return false
      }
      if (evt === void 0) {
        return true
      }
      return evt.touches === void 0 || evt.touches.length <= 1
    },

    __contextClick (evt) {
      this.hide(evt)
      this.show(evt)
      prevent(evt)
    },

    __toggleKey (evt) {
      if (evt !== void 0 && evt.keyCode === 13 && evt.qKeyEvent !== true) {
        this.toggle(evt)
      }
    },

    __mobileTouch (evt) {
      this.__mobileCleanup(evt)

      if (this.__showCondition(evt) !== true) {
        return
      }

      this.hide(evt)
      this.anchorEl.classList.add('non-selectable')

      this.touchTimer = setTimeout(() => {
        this.show(evt)
      }, 300)
    },

    __mobileCleanup (evt) {
      this.anchorEl.classList.remove('non-selectable')
      clearTimeout(this.touchTimer)

      if (this.showing === true && evt !== void 0) {
        clearSelection()
        prevent(evt)
      }
    },

    __unconfigureAnchorEl (context = this.contextMenu) {
      if (context === true) {
        if (this.$q.platform.is.mobile) {
          this.anchorEl.removeEventListener('touchstart', this.__mobileTouch)
          ;['touchcancel', 'touchmove', 'touchend'].forEach(evt => {
            this.anchorEl.removeEventListener(evt, this.__mobileCleanup)
          })
        }
        else {
          this.anchorEl.removeEventListener('click', this.hide)
          this.anchorEl.removeEventListener('contextmenu', this.__contextClick)
        }
      }
      else {
        this.anchorEl.removeEventListener('click', this.toggle)
        this.anchorEl.removeEventListener('keyup', this.__toggleKey)
      }
    },

    __configureAnchorEl (context = this.contextMenu) {
      if (this.noParentEvent === true) { return }

      if (context === true) {
        if (this.$q.platform.is.mobile) {
          this.anchorEl.addEventListener('touchstart', this.__mobileTouch)
          ;['touchcancel', 'touchmove', 'touchend'].forEach(evt => {
            this.anchorEl.addEventListener(evt, this.__mobileCleanup)
          })
        }
        else {
          this.anchorEl.addEventListener('click', this.hide)
          this.anchorEl.addEventListener('contextmenu', this.__contextClick)
        }
      }
      else {
        this.anchorEl.addEventListener('click', this.toggle)
        this.anchorEl.addEventListener('keyup', this.__toggleKey)
      }
    },

    __setAnchorEl (el) {
      this.anchorEl = el
      while (this.anchorEl.classList.contains('q-anchor--skip')) {
        this.anchorEl = this.anchorEl.parentNode
      }
      this.__configureAnchorEl()
    },

    __pickAnchorEl () {
      if (this.target && typeof this.target === 'string') {
        const el = document.querySelector(this.target)
        if (el !== null) {
          this.anchorEl = el
          this.__configureAnchorEl()
        }
        else {
          this.anchorEl = void 0
          console.error(`Anchor: target "${this.target}" not found`, this)
        }
      }
      else if (this.target !== false) {
        this.__setAnchorEl(this.parentEl)
      }
      else {
        this.anchorEl = void 0
      }
    }
  },

  created () {
    if (typeof this.__configureScrollTarget === 'function' && typeof this.__unconfigureScrollTarget === 'function') {
      this.$watch('noParentEvent', () => {
        if (this.scrollTarget !== void 0) {
          this.__unconfigureScrollTarget()
          this.__configureScrollTarget()
        }
      })
    }
  },

  mounted () {
    this.parentEl = this.$el.parentNode
    this.__pickAnchorEl()

    if (this.value !== false && this.anchorEl === void 0) {
      this.$emit('input', false)
    }
  },

  beforeDestroy () {
    clearTimeout(this.touchTimer)
    this.__anchorCleanup !== void 0 && this.__anchorCleanup()

    if (this.anchorEl !== void 0) {
      this.__unconfigureAnchorEl()
    }
  }
}
<commit_msg>Update anchor.js<commit_after>import { clearSelection } from '../utils/selection.js'
import { prevent } from '../utils/event.js'

export default {
  props: {
    target: {
      type: [Boolean, String],
      default: true
    },
    noParentEvent: Boolean,
    contextMenu: Boolean
  },

  watch: {
    contextMenu (val) {
      if (this.anchorEl !== void 0) {
        this.__unconfigureAnchorEl(!val)
        this.__configureAnchorEl(val)
      }
    },

    target () {
      if (this.anchorEl !== void 0) {
        this.__unconfigureAnchorEl()
      }

      this.__pickAnchorEl()
    },

    noParentEvent (val) {
      if (this.anchorEl !== void 0) {
        if (val === true) {
          this.__unconfigureAnchorEl()
        }
        else {
          this.__configureAnchorEl()
        }
      }
    }
  },

  methods: {
    __showCondition (evt) {
      // abort with no parent configured or on multi-touch
      if (this.anchorEl === void 0) {
        return false
      }
      if (evt === void 0) {
        return true
      }
      return evt.touches === void 0 || evt.touches.length <= 1
    },

    __contextClick (evt) {
      this.hide(evt)
      this.show(evt)
      prevent(evt)
    },

    __toggleKey (evt) {
      if (evt !== void 0 && evt.keyCode === 13 && evt.qKeyEvent !== true) {
        this.toggle(evt)
      }
    },

    __mobileTouch (evt) {
      this.__mobileCleanup(evt)

      if (this.__showCondition(evt) !== true) {
        return
      }

      this.hide(evt)
      this.anchorEl.classList.add('non-selectable')

      this.touchTimer = setTimeout(() => {
        this.show(evt)
      }, 300)
    },

    __mobileCleanup (evt) {
      this.anchorEl.classList.remove('non-selectable')
      clearTimeout(this.touchTimer)

      if (this.showing === true && evt !== void 0) {
        clearSelection()
        prevent(evt)
      }
    },

    __unconfigureAnchorEl (context = this.contextMenu) {
      if (context === true) {
        if (this.$q.platform.is.mobile) {
          this.anchorEl.removeEventListener('touchstart', this.__mobileTouch)
          ;['touchcancel', 'touchmove', 'touchend'].forEach(evt => {
            this.anchorEl.removeEventListener(evt, this.__mobileCleanup)
          })
        }
        else {
          this.anchorEl.removeEventListener('click', this.hide)
          this.anchorEl.removeEventListener('contextmenu', this.__contextClick)
        }
      }
      else {
        this.anchorEl.removeEventListener('click', this.toggle)
        this.anchorEl.removeEventListener('keyup', this.__toggleKey)
      }
    },

    __configureAnchorEl (context = this.contextMenu) {
      if (this.noParentEvent === true) { return }

      if (context === true) {
        if (this.$q.platform.is.mobile) {
          this.anchorEl.addEventListener('touchstart', this.__mobileTouch)
          ;['touchcancel', 'touchmove', 'touchend'].forEach(evt => {
            this.anchorEl.addEventListener(evt, this.__mobileCleanup)
          })
        }
        else {
          this.anchorEl.addEventListener('click', this.hide)
          this.anchorEl.addEventListener('contextmenu', this.__contextClick)
        }
      }
      else {
        this.anchorEl.addEventListener('click', this.toggle)
        this.anchorEl.addEventListener('keyup', this.__toggleKey)
      }
    },

    __setAnchorEl (el) {
      this.anchorEl = el
      while (this.anchorEl.classList.contains('q-anchor--skip')) {
        this.anchorEl = this.anchorEl.parentNode
      }
      this.__configureAnchorEl()
    },

    __pickAnchorEl () {
      if (this.target && typeof this.target === 'string') {
        const el = document.querySelector(this.target)
        if (el !== null) {
          this.anchorEl = el
          this.__configureAnchorEl()
        }
        else {
          this.anchorEl = void 0
          console.error(`Anchor: target "${this.target}" not found`, this)
        }
      }
      else if (this.target !== false) {
        this.__setAnchorEl(this.parentEl)
      }
      else {
        this.anchorEl = void 0
      }
    }
  },

  created () {
    if (typeof this.__configureScrollTarget === 'function' && typeof this.__unconfigureScrollTarget === 'function') {
      this.noParentEventWatcher = this.$watch('noParentEvent', () => {
        if (this.scrollTarget !== void 0) {
          this.__unconfigureScrollTarget()
          this.__configureScrollTarget()
        }
      })
    }
  },

  mounted () {
    this.parentEl = this.$el.parentNode
    this.__pickAnchorEl()

    if (this.value !== false && this.anchorEl === void 0) {
      this.$emit('input', false)
    }
  },

  beforeDestroy () {
    clearTimeout(this.touchTimer)
    this.noParentEventWatcher !== void 0 && this.noParentEventWatcher()
    this.__anchorCleanup !== void 0 && this.__anchorCleanup()

    if (this.anchorEl !== void 0) {
      this.__unconfigureAnchorEl()
    }
  }
}
<|endoftext|>


<commit_before>(function () {
  var ns = $.namespace("pskl.controller");

  // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE
  var PREVIEW_SIZE = 200;

  ns.AnimatedPreviewController = function (piskelController, container) {
    this.piskelController = piskelController;
    this.container = container;

    this.elapsedTime = 0;
    this.currentIndex = 0;

    this.setFPS(Constants.DEFAULT.FPS);

    var frame = this.piskelController.getCurrentFrame();

    this.renderer = new pskl.rendering.frame.TiledFrameRenderer(this.container);
  };

  ns.AnimatedPreviewController.prototype.init = function () {
    // the oninput event won't work on IE10 unfortunately, but at least will provide a
    // consistent behavior across all other browsers that support the input type range
    // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670
    $("#preview-fps")[0].addEventListener('change', this.onFPSSliderChange.bind(this));
    document.querySelector(".right-column").style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px';

    this.toggleOnionSkinEl = document.querySelector(".preview-toggle-onion-skin");
    this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this));

    pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this));

    $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this));
    $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));

    this.updateZoom_();
    this.updateOnionSkinPreview_();
  };

  ns.AnimatedPreviewController.prototype.onUserSettingsChange_ = function (evt, name, value) {
    if (name == pskl.UserSettings.ONION_SKIN) {
      this.updateOnionSkinPreview_();
    } else {
      this.updateZoom_();
      this.updateContainerDimensions_();
    }
  };

  ns.AnimatedPreviewController.prototype.updateOnionSkinPreview_ = function () {
    var enabledClassname = 'preview-toggle-onion-skin-enabled';
    if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) {
      this.toggleOnionSkinEl.classList.add(enabledClassname);
    } else {
      this.toggleOnionSkinEl.classList.remove(enabledClassname);
    }
  };

  ns.AnimatedPreviewController.prototype.updateZoom_ = function () {
    var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW);
    var zoom = isTiled ? 1 : this.calculateZoom_();
    this.renderer.setZoom(zoom);
  };

  ns.AnimatedPreviewController.prototype.getZoom = function () {
    return this.calculateZoom_();
  };

  ns.AnimatedPreviewController.prototype.getCoordinates = function(x, y) {
    var containerOffset = this.container.offset();
    x = x - containerOffset.left;
    y = y - containerOffset.top;
    var zoom = this.getZoom();
    return {
      x : Math.floor(x / zoom),
      y : Math.floor(y / zoom)
    };
  };

  ns.AnimatedPreviewController.prototype.onFPSSliderChange = function (evt) {
    this.setFPS(parseInt($("#preview-fps")[0].value, 10));
  };

  ns.AnimatedPreviewController.prototype.setFPS = function (fps) {
    if (fps) {
      this.fps = fps;
      $("#preview-fps").val(this.fps);
      $("#display-fps").html(this.fps + " FPS");
    }
  };

  ns.AnimatedPreviewController.prototype.getFPS = function () {
    return this.fps;
  };

  ns.AnimatedPreviewController.prototype.render = function (delta) {
    this.elapsedTime += delta;
    var index = Math.floor(this.elapsedTime / (1000/this.fps));
    if (index != this.currentIndex) {
      this.currentIndex = index;
      if (!this.piskelController.hasFrameAt(this.currentIndex)) {
        this.currentIndex = 0;
        this.elapsedTime = 0;
      }
      var frame = this.piskelController.getFrameAt(this.currentIndex);
      this.renderer.render(frame);
    }
  };

  /**
   * Calculate the preview zoom depending on the framesheet size
   */
  ns.AnimatedPreviewController.prototype.calculateZoom_ = function () {
    var frame = this.piskelController.getCurrentFrame();
    var previewSize = 200,
      hZoom = previewSize / frame.getHeight(),
      wZoom = previewSize / frame.getWidth();

    return Math.min(hZoom, wZoom);
  };

  ns.AnimatedPreviewController.prototype.onFrameSizeChange_ = function () {
    this.updateZoom_();
    this.updateContainerDimensions_();
  };

  ns.AnimatedPreviewController.prototype.updateContainerDimensions_ = function () {
    var containerEl = this.container.get(0);
    var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW);
    var height, width;

    if (isTiled) {
      height = PREVIEW_SIZE;
      width = PREVIEW_SIZE;
    } else {
      var zoom = this.getZoom();
      var frame = this.piskelController.getCurrentFrame();
      height = frame.getHeight() * zoom;
      width = frame.getWidth() * zoom;
    }

    containerEl.style.height = height + "px";
    containerEl.style.width = width + "px";
    containerEl.style.marginTop = ((PREVIEW_SIZE - height) / 2) + "px";
    containerEl.style.marginBottom = ((PREVIEW_SIZE - height) / 2) + "px";
    containerEl.style.marginLeft = ((PREVIEW_SIZE - width) / 2) + "px";
    containerEl.style.marginRight = ((PREVIEW_SIZE - width) / 2) + "px";
  };

  ns.AnimatedPreviewController.prototype.toggleOnionSkin_ = function () {
    var currentValue = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN);
    pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN, !currentValue);
  };
})();<commit_msg>Combining oninput and onchange events for the FPS counter.<commit_after>(function () {
  var ns = $.namespace("pskl.controller");

  // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE
  var PREVIEW_SIZE = 200;

  ns.AnimatedPreviewController = function (piskelController, container) {
    this.piskelController = piskelController;
    this.container = container;

    this.elapsedTime = 0;
    this.currentIndex = 0;

    this.setFPS(Constants.DEFAULT.FPS);

    var frame = this.piskelController.getCurrentFrame();

    this.renderer = new pskl.rendering.frame.TiledFrameRenderer(this.container);
  };

  ns.AnimatedPreviewController.prototype.init = function () {
    // the oninput event won't work on IE10 unfortunately, but at least will provide a
    // consistent behavior across all other browsers that support the input type range
    // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670
    $("#preview-fps").on('input change', this.onFPSSliderChange.bind(this));
    document.querySelector(".right-column").style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px';

    this.toggleOnionSkinEl = document.querySelector(".preview-toggle-onion-skin");
    this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this));

    pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this));

    $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this));
    $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));

    this.updateZoom_();
    this.updateOnionSkinPreview_();
  };

  ns.AnimatedPreviewController.prototype.onUserSettingsChange_ = function (evt, name, value) {
    if (name == pskl.UserSettings.ONION_SKIN) {
      this.updateOnionSkinPreview_();
    } else {
      this.updateZoom_();
      this.updateContainerDimensions_();
    }
  };

  ns.AnimatedPreviewController.prototype.updateOnionSkinPreview_ = function () {
    var enabledClassname = 'preview-toggle-onion-skin-enabled';
    if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) {
      this.toggleOnionSkinEl.classList.add(enabledClassname);
    } else {
      this.toggleOnionSkinEl.classList.remove(enabledClassname);
    }
  };

  ns.AnimatedPreviewController.prototype.updateZoom_ = function () {
    var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW);
    var zoom = isTiled ? 1 : this.calculateZoom_();
    this.renderer.setZoom(zoom);
  };

  ns.AnimatedPreviewController.prototype.getZoom = function () {
    return this.calculateZoom_();
  };

  ns.AnimatedPreviewController.prototype.getCoordinates = function(x, y) {
    var containerOffset = this.container.offset();
    x = x - containerOffset.left;
    y = y - containerOffset.top;
    var zoom = this.getZoom();
    return {
      x : Math.floor(x / zoom),
      y : Math.floor(y / zoom)
    };
  };

  ns.AnimatedPreviewController.prototype.onFPSSliderChange = function (evt) {
    this.setFPS(parseInt($("#preview-fps")[0].value, 10));
  };

  ns.AnimatedPreviewController.prototype.setFPS = function (fps) {
    if (fps) {
      this.fps = fps;
      $("#preview-fps").val(this.fps);
      $("#display-fps").html(this.fps + " FPS");
    }
  };

  ns.AnimatedPreviewController.prototype.getFPS = function () {
    return this.fps;
  };

  ns.AnimatedPreviewController.prototype.render = function (delta) {
    this.elapsedTime += delta;
    var index = Math.floor(this.elapsedTime / (1000/this.fps));
    if (index != this.currentIndex) {
      this.currentIndex = index;
      if (!this.piskelController.hasFrameAt(this.currentIndex)) {
        this.currentIndex = 0;
        this.elapsedTime = 0;
      }
      var frame = this.piskelController.getFrameAt(this.currentIndex);
      this.renderer.render(frame);
    }
  };

  /**
   * Calculate the preview zoom depending on the framesheet size
   */
  ns.AnimatedPreviewController.prototype.calculateZoom_ = function () {
    var frame = this.piskelController.getCurrentFrame();
    var previewSize = 200,
      hZoom = previewSize / frame.getHeight(),
      wZoom = previewSize / frame.getWidth();

    return Math.min(hZoom, wZoom);
  };

  ns.AnimatedPreviewController.prototype.onFrameSizeChange_ = function () {
    this.updateZoom_();
    this.updateContainerDimensions_();
  };

  ns.AnimatedPreviewController.prototype.updateContainerDimensions_ = function () {
    var containerEl = this.container.get(0);
    var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW);
    var height, width;

    if (isTiled) {
      height = PREVIEW_SIZE;
      width = PREVIEW_SIZE;
    } else {
      var zoom = this.getZoom();
      var frame = this.piskelController.getCurrentFrame();
      height = frame.getHeight() * zoom;
      width = frame.getWidth() * zoom;
    }

    containerEl.style.height = height + "px";
    containerEl.style.width = width + "px";
    containerEl.style.marginTop = ((PREVIEW_SIZE - height) / 2) + "px";
    containerEl.style.marginBottom = ((PREVIEW_SIZE - height) / 2) + "px";
    containerEl.style.marginLeft = ((PREVIEW_SIZE - width) / 2) + "px";
    containerEl.style.marginRight = ((PREVIEW_SIZE - width) / 2) + "px";
  };

  ns.AnimatedPreviewController.prototype.toggleOnionSkin_ = function () {
    var currentValue = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN);
    pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN, !currentValue);
  };
})();<|endoftext|>


<commit_before>(function () {
  var ns = $.namespace('pskl.controller.preview');

  // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE
  var PREVIEW_SIZE = 200;
  var RENDER_MINIMUM_DELAY = 300;

  ns.PreviewController = function (piskelController, container) {
    this.piskelController = piskelController;
    this.container = container;

    this.elapsedTime = 0;
    this.currentIndex = 0;

    this.onionSkinShortcut = pskl.service.keyboard.Shortcuts.MISC.ONION_SKIN;

    this.lastRenderTime = 0;
    this.renderFlag = true;

    this.fpsRangeInput = document.querySelector('#preview-fps');
    this.fpsCounterDisplay = document.querySelector('#display-fps');
    this.openPopupPreview = document.querySelector('.open-popup-preview-button');
    this.previewSizeDropdown = document.querySelector('.preview-drop-down');
    this.previewSizes = {
      original: {
        name: 'original',
        zoom: 1,
        button: document.querySelector('.original-size-button'),
        shortcut: pskl.service.keyboard.Shortcuts.MISC.X1_PREVIEW,
        tooltip: 'Original size preview',
        enabled: true
      },
      best: {
        name: 'best',
        zoom: this.calculateZoom_.bind(this, true),
        button: document.querySelector('.best-size-button'),
        shortcut: pskl.service.keyboard.Shortcuts.MISC.BEST_PREVIEW,
        tooltip: 'Biggest round factor size preview',
        enabled: true
      },
      full: {
        name: 'full',
        zoom: this.calculateZoom_.bind(this, false),
        button: document.querySelector('.full-size-button'),
        shortcut: pskl.service.keyboard.Shortcuts.MISC.FULL_PREVIEW,
        tooltip: 'Biggest factor size preview',
        enabled: true
      }
    };
    this.selectedPreviewSize = pskl.UserSettings.get(pskl.UserSettings.PREVIEW_SIZE);
    this.toggleOnionSkinButton = document.querySelector('.preview-toggle-onion-skin');

    this.renderer = new pskl.rendering.frame.BackgroundImageFrameRenderer(this.container);
    this.popupPreviewController = new ns.PopupPreviewController(piskelController);
  };

  ns.PreviewController.prototype.init = function () {
    this.fpsRangeInput.addEventListener('change', this.onFpsRangeInputUpdate_.bind(this));
    this.fpsRangeInput.addEventListener('input', this.onFpsRangeInputUpdate_.bind(this));

    document.querySelector('.right-column').style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px';

    var addEvent = pskl.utils.Event.addEventListener;
    addEvent(this.toggleOnionSkinButton, 'click', this.toggleOnionSkin_, this);
    addEvent(this.openPopupPreview, 'click', this.onOpenPopupPreviewClick_, this);

    var registerShortcut = pskl.app.shortcutService.registerShortcut.bind(pskl.app.shortcutService);
    registerShortcut(this.onionSkinShortcut, this.toggleOnionSkin_.bind(this));

    var onionSkinTooltip = pskl.utils.TooltipFormatter.format('Toggle onion skin', this.onionSkinShortcut);
    this.toggleOnionSkinButton.setAttribute('title', onionSkinTooltip);

    for (var size in this.previewSizes) {
      if (this.previewSizes.hasOwnProperty(size)) {
        var wrapper = this.previewSizes[size];
        addEvent(wrapper.button, 'click', this.onChangePreviewSize_, this, wrapper.name);
        registerShortcut(wrapper.shortcut, this.onChangePreviewSize_.bind(this, wrapper.name));
        var tooltip = pskl.utils.TooltipFormatter.format(wrapper.tooltip, wrapper.shortcut);
        wrapper.button.setAttribute('title', tooltip);
      }
    }

    // TODO : Change the disabled message
    document.querySelector('.preview-disable-overlay').setAttribute('title', 'Widget disabled.');

    $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this));
    $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
    $.subscribe(Events.PISKEL_SAVE_STATE, this.setRenderFlag_.bind(this, true));
    $.subscribe(Events.FPS_CHANGED, this.updateFPS_.bind(this));
    // On PISKEL_RESET, set the render flag and update the FPS input
    $.subscribe(Events.PISKEL_RESET, this.setRenderFlag_.bind(this, true));
    $.subscribe(Events.PISKEL_RESET, this.updateFPS_.bind(this));

    this.updatePreviewSizeButtons_();
    this.popupPreviewController.init();

    this.updateZoom_();
    this.updateOnionSkinPreview_();
    this.selectPreviewSizeButton_();
    this.updateFPS_();
    this.updateMaxFPS_();
    this.updateContainerDimensions_();
  };

  ns.PreviewController.prototype.updatePreviewSizeButtons_ = function () {
    var fullZoom = this.calculateZoom_();
    var bestZoom = Math.floor(fullZoom);
    var seamlessModeEnabled = pskl.UserSettings.get(pskl.UserSettings.SEAMLESS_MODE);
    var shouldDisable = true;

    // Hard-coded options removal
    if (fullZoom < 1) {
      this.togglePreviewWidget_(this.previewSizes.full.name);
    } else if (seamlessModeEnabled || (fullZoom === 1 && bestZoom === 1)) {
      this.togglePreviewWidget_(this.previewSizes.original.name);
    } else { // widget not disabled
      this.togglePreviewWidget_(!shouldDisable);
      if (fullZoom === bestZoom) {
        if (this.togglePreviewSizeButtonState_(this.previewSizes.full, shouldDisable)) {
          this.onChangePreviewSize_(this.previewSizes.best.name);
        }
      } else if (bestZoom === 1) {
        if (this.togglePreviewSizeButtonState_(this.previewSizes.best, shouldDisable)) {
          this.onChangePreviewSize_(this.previewSizes.original.name);
        }
      }
    }

    this.previewSizes.best.button.textContent = Math.floor(fullZoom) + 'x';
  };

  ns.PreviewController.prototype.togglePreviewWidget_ = function (disable) {
    this.previewSizeDropdown.classList.toggle('preview-drop-down-disabled', disable);
    for (var size in this.previewSizes) {
      if (this.previewSizes.hasOwnProperty(size)) {
        this.togglePreviewSizeButtonState_(this.previewSizes[size], disable && size !== disable);
      }
    }
    if (disable) {
      this.onChangePreviewSize_(disable);
    }
  };

  ns.PreviewController.prototype.togglePreviewSizeButtonState_ = function (wrapper, disable) {
    var disabledClassname = 'preview-contextual-action-disabled';
    wrapper.button.classList.toggle(disabledClassname, disable);
    wrapper.enabled = !disable;
    return disable && wrapper.name === this.selectedPreviewSize;
  };

  ns.PreviewController.prototype.onOpenPopupPreviewClick_ = function () {
    this.popupPreviewController.open();
  };

  ns.PreviewController.prototype.onChangePreviewSize_ = function (choice) {
    if (this.previewSizes[choice].enabled) {
      this.selectedPreviewSize = choice;
      pskl.UserSettings.set(pskl.UserSettings.PREVIEW_SIZE, choice);
    }
  };

  ns.PreviewController.prototype.onUserSettingsChange_ = function (evt, name, value) {
    if (name == pskl.UserSettings.ONION_SKIN) {
      this.updateOnionSkinPreview_();
    } else if (name == pskl.UserSettings.MAX_FPS) {
      this.updateMaxFPS_();
    } else if (name === pskl.UserSettings.SEAMLESS_MODE) {
      this.onFrameSizeChange_();
    } else {
      this.updateZoom_();
      this.selectPreviewSizeButton_();
      this.updateContainerDimensions_();
    }
  };

  ns.PreviewController.prototype.updateOnionSkinPreview_ = function () {
    var enabledClassname = 'preview-toggle-onion-skin-enabled';
    var isEnabled = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN);
    this.toggleOnionSkinButton.classList.toggle(enabledClassname, isEnabled);
  };

  ns.PreviewController.prototype.selectPreviewSizeButton_ = function () {
    var enabledClassname = 'size-button-selected';
    var currentlySelected = document.querySelector('.' + enabledClassname);
    if (currentlySelected) {
      currentlySelected.classList.remove(enabledClassname);
    }

    var option = this.previewSizes[this.selectedPreviewSize];
    option.button.classList.add(enabledClassname);
  };

  ns.PreviewController.prototype.updateMaxFPS_ = function () {
    var maxFps = pskl.UserSettings.get(pskl.UserSettings.MAX_FPS);
    this.fpsRangeInput.setAttribute('max', maxFps);
    this.piskelController.setFPS(Math.min(maxFps, this.piskelController.getFPS()));
  };

  ns.PreviewController.prototype.updateZoom_ = function () {
    var chosenPreviewSize = pskl.UserSettings.get(pskl.UserSettings.PREVIEW_SIZE);

    var zoom = this.previewSizes[chosenPreviewSize].zoom;

    this.renderer.setZoom($.isFunction(zoom) ? zoom() : zoom);
    this.setRenderFlag_(true);
  };

  ns.PreviewController.prototype.getZoom = function () {
    return this.calculateZoom_();
  };

  ns.PreviewController.prototype.getCoordinates = function(x, y) {
    var containerOffset = this.container.offset();
    x = x - containerOffset.left;
    y = y - containerOffset.top;
    var zoom = this.getZoom();
    return {
      x : Math.floor(x / zoom),
      y : Math.floor(y / zoom)
    };
  };

  /**
   * Event handler triggered on 'input' or 'change' events.
   */
  ns.PreviewController.prototype.onFpsRangeInputUpdate_ = function (evt) {
    var fps = parseInt(this.fpsRangeInput.value, 10);
    this.piskelController.setFPS(fps);
    // blur only on 'change' events, as blurring on 'input' breaks on Firefox
    if (evt.type === 'change') {
      this.fpsRangeInput.blur();
    }
  };

  ns.PreviewController.prototype.updateFPS_ = function () {
    var fps = this.piskelController.getFPS();
    if (fps !== this.fps) {
      this.fps = fps;
      // reset
      this.fpsRangeInput.value = 0;
      // set proper value
      this.fpsRangeInput.value = this.fps;
      this.fpsCounterDisplay.innerHTML = this.fps + ' FPS';
    }
  };

  ns.PreviewController.prototype.render = function (delta) {
    this.elapsedTime += delta;
    var index = this.getNextIndex_(delta);
    if (this.shouldRender_() || this.currentIndex != index) {
      this.currentIndex = index;
      var frame = pskl.utils.LayerUtils.mergeFrameAt(this.piskelController.getLayers(), index);
      this.renderer.render(frame);
      this.renderFlag = false;
      this.lastRenderTime = Date.now();

      this.popupPreviewController.render(frame);
    }
  };

  ns.PreviewController.prototype.getNextIndex_ = function (delta) {
    if (this.fps === 0) {
      return this.piskelController.getCurrentFrameIndex();
    } else {
      var index = Math.floor(this.elapsedTime / (1000 / this.fps));
      if (!this.piskelController.hasFrameAt(index)) {
        this.elapsedTime = 0;
        index = 0;
      }
      return index;
    }
  };

  /**
   * Calculate the preview zoom depending on the framesheet size
   */
  ns.PreviewController.prototype.calculateZoom_ = function (noFloat) {
    var frame = this.piskelController.getCurrentFrame();
    var hZoom = PREVIEW_SIZE / frame.getHeight();
    var wZoom = PREVIEW_SIZE / frame.getWidth();

    if (noFloat) {
      hZoom = Math.floor(hZoom);
      wZoom = Math.floor(wZoom);
    }

    return Math.min(hZoom, wZoom);
  };

  ns.PreviewController.prototype.onFrameSizeChange_ = function () {
    this.updateZoom_();
    this.updateContainerDimensions_();
    this.updatePreviewSizeButtons_();
  };

  ns.PreviewController.prototype.updateContainerDimensions_ = function () {
    var isSeamless = pskl.UserSettings.get(pskl.UserSettings.SEAMLESS_MODE);
    this.renderer.setRepeated(isSeamless);

    var height, width;

    if (isSeamless) {
      height = PREVIEW_SIZE;
      width = PREVIEW_SIZE;
    } else {
      var zoom = this.getZoom();
      var frame = this.piskelController.getCurrentFrame();
      height = frame.getHeight() * zoom;
      width = frame.getWidth() * zoom;
    }

    var containerEl = this.container.get(0);
    containerEl.style.height = height + 'px';
    containerEl.style.width = width + 'px';

    var horizontalMargin = (PREVIEW_SIZE - height) / 2;
    containerEl.style.marginTop = horizontalMargin + 'px';
    containerEl.style.marginBottom = horizontalMargin + 'px';

    var verticalMargin = (PREVIEW_SIZE - width) / 2;
    containerEl.style.marginLeft = verticalMargin + 'px';
    containerEl.style.marginRight = verticalMargin + 'px';
  };

  ns.PreviewController.prototype.setRenderFlag_ = function (bool) {
    this.renderFlag = bool;
  };

  ns.PreviewController.prototype.shouldRender_ = function () {
    return (this.renderFlag || this.popupPreviewController.renderFlag) &&
            (Date.now() - this.lastRenderTime > RENDER_MINIMUM_DELAY);
  };

  ns.PreviewController.prototype.toggleOnionSkin_ = function () {
    var currentValue = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN);
    pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN, !currentValue);
  };
})();
<commit_msg>update labels for preview size widget<commit_after>(function () {
  var ns = $.namespace('pskl.controller.preview');

  // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE
  var PREVIEW_SIZE = 200;
  var RENDER_MINIMUM_DELAY = 300;

  ns.PreviewController = function (piskelController, container) {
    this.piskelController = piskelController;
    this.container = container;

    this.elapsedTime = 0;
    this.currentIndex = 0;

    this.onionSkinShortcut = pskl.service.keyboard.Shortcuts.MISC.ONION_SKIN;

    this.lastRenderTime = 0;
    this.renderFlag = true;

    this.fpsRangeInput = document.querySelector('#preview-fps');
    this.fpsCounterDisplay = document.querySelector('#display-fps');
    this.openPopupPreview = document.querySelector('.open-popup-preview-button');
    this.previewSizeDropdown = document.querySelector('.preview-drop-down');
    this.previewSizes = {
      original: {
        name: 'original',
        zoom: 1,
        button: document.querySelector('.original-size-button'),
        shortcut: pskl.service.keyboard.Shortcuts.MISC.X1_PREVIEW,
        tooltip: 'Original size preview',
        enabled: true
      },
      best: {
        name: 'best',
        zoom: this.calculateZoom_.bind(this, true),
        button: document.querySelector('.best-size-button'),
        shortcut: pskl.service.keyboard.Shortcuts.MISC.BEST_PREVIEW,
        tooltip: 'Best size preview',
        enabled: true
      },
      full: {
        name: 'full',
        zoom: this.calculateZoom_.bind(this, false),
        button: document.querySelector('.full-size-button'),
        shortcut: pskl.service.keyboard.Shortcuts.MISC.FULL_PREVIEW,
        tooltip: 'Full size preview',
        enabled: true
      }
    };
    this.selectedPreviewSize = pskl.UserSettings.get(pskl.UserSettings.PREVIEW_SIZE);
    this.toggleOnionSkinButton = document.querySelector('.preview-toggle-onion-skin');

    this.renderer = new pskl.rendering.frame.BackgroundImageFrameRenderer(this.container);
    this.popupPreviewController = new ns.PopupPreviewController(piskelController);
  };

  ns.PreviewController.prototype.init = function () {
    this.fpsRangeInput.addEventListener('change', this.onFpsRangeInputUpdate_.bind(this));
    this.fpsRangeInput.addEventListener('input', this.onFpsRangeInputUpdate_.bind(this));

    document.querySelector('.right-column').style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px';

    var addEvent = pskl.utils.Event.addEventListener;
    addEvent(this.toggleOnionSkinButton, 'click', this.toggleOnionSkin_, this);
    addEvent(this.openPopupPreview, 'click', this.onOpenPopupPreviewClick_, this);

    var registerShortcut = pskl.app.shortcutService.registerShortcut.bind(pskl.app.shortcutService);
    registerShortcut(this.onionSkinShortcut, this.toggleOnionSkin_.bind(this));

    var onionSkinTooltip = pskl.utils.TooltipFormatter.format('Toggle onion skin', this.onionSkinShortcut);
    this.toggleOnionSkinButton.setAttribute('title', onionSkinTooltip);

    for (var size in this.previewSizes) {
      if (this.previewSizes.hasOwnProperty(size)) {
        var wrapper = this.previewSizes[size];
        addEvent(wrapper.button, 'click', this.onChangePreviewSize_, this, wrapper.name);
        registerShortcut(wrapper.shortcut, this.onChangePreviewSize_.bind(this, wrapper.name));
        var tooltip = pskl.utils.TooltipFormatter.format(wrapper.tooltip, wrapper.shortcut);
        wrapper.button.setAttribute('title', tooltip);
      }
    }

    // The .preview-disable-overlay is displayed on top of the preview size widget
    document.querySelector('.preview-disable-overlay').setAttribute('title', 'Disabled for seamless mode');

    $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this));
    $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
    $.subscribe(Events.PISKEL_SAVE_STATE, this.setRenderFlag_.bind(this, true));
    $.subscribe(Events.FPS_CHANGED, this.updateFPS_.bind(this));
    // On PISKEL_RESET, set the render flag and update the FPS input
    $.subscribe(Events.PISKEL_RESET, this.setRenderFlag_.bind(this, true));
    $.subscribe(Events.PISKEL_RESET, this.updateFPS_.bind(this));

    this.updatePreviewSizeButtons_();
    this.popupPreviewController.init();

    this.updateZoom_();
    this.updateOnionSkinPreview_();
    this.selectPreviewSizeButton_();
    this.updateFPS_();
    this.updateMaxFPS_();
    this.updateContainerDimensions_();
  };

  ns.PreviewController.prototype.updatePreviewSizeButtons_ = function () {
    var fullZoom = this.calculateZoom_();
    var bestZoom = Math.floor(fullZoom);
    var seamlessModeEnabled = pskl.UserSettings.get(pskl.UserSettings.SEAMLESS_MODE);
    var shouldDisable = true;

    // Hard-coded options removal
    if (fullZoom < 1) {
      this.togglePreviewWidget_(this.previewSizes.full.name);
    } else if (seamlessModeEnabled || (fullZoom === 1 && bestZoom === 1)) {
      this.togglePreviewWidget_(this.previewSizes.original.name);
    } else { // widget not disabled
      this.togglePreviewWidget_(!shouldDisable);
      if (fullZoom === bestZoom) {
        if (this.togglePreviewSizeButtonState_(this.previewSizes.full, shouldDisable)) {
          this.onChangePreviewSize_(this.previewSizes.best.name);
        }
      } else if (bestZoom === 1) {
        if (this.togglePreviewSizeButtonState_(this.previewSizes.best, shouldDisable)) {
          this.onChangePreviewSize_(this.previewSizes.original.name);
        }
      }
    }

    this.previewSizes.best.button.textContent = Math.floor(fullZoom) + 'x';
  };

  ns.PreviewController.prototype.togglePreviewWidget_ = function (disable) {
    this.previewSizeDropdown.classList.toggle('preview-drop-down-disabled', disable);
    for (var size in this.previewSizes) {
      if (this.previewSizes.hasOwnProperty(size)) {
        this.togglePreviewSizeButtonState_(this.previewSizes[size], disable && size !== disable);
      }
    }
    if (disable) {
      this.onChangePreviewSize_(disable);
    }
  };

  ns.PreviewController.prototype.togglePreviewSizeButtonState_ = function (wrapper, disable) {
    var disabledClassname = 'preview-contextual-action-disabled';
    wrapper.button.classList.toggle(disabledClassname, disable);
    wrapper.enabled = !disable;
    return disable && wrapper.name === this.selectedPreviewSize;
  };

  ns.PreviewController.prototype.onOpenPopupPreviewClick_ = function () {
    this.popupPreviewController.open();
  };

  ns.PreviewController.prototype.onChangePreviewSize_ = function (choice) {
    if (this.previewSizes[choice].enabled) {
      this.selectedPreviewSize = choice;
      pskl.UserSettings.set(pskl.UserSettings.PREVIEW_SIZE, choice);
    }
  };

  ns.PreviewController.prototype.onUserSettingsChange_ = function (evt, name, value) {
    if (name == pskl.UserSettings.ONION_SKIN) {
      this.updateOnionSkinPreview_();
    } else if (name == pskl.UserSettings.MAX_FPS) {
      this.updateMaxFPS_();
    } else if (name === pskl.UserSettings.SEAMLESS_MODE) {
      this.onFrameSizeChange_();
    } else {
      this.updateZoom_();
      this.selectPreviewSizeButton_();
      this.updateContainerDimensions_();
    }
  };

  ns.PreviewController.prototype.updateOnionSkinPreview_ = function () {
    var enabledClassname = 'preview-toggle-onion-skin-enabled';
    var isEnabled = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN);
    this.toggleOnionSkinButton.classList.toggle(enabledClassname, isEnabled);
  };

  ns.PreviewController.prototype.selectPreviewSizeButton_ = function () {
    var enabledClassname = 'size-button-selected';
    var currentlySelected = document.querySelector('.' + enabledClassname);
    if (currentlySelected) {
      currentlySelected.classList.remove(enabledClassname);
    }

    var option = this.previewSizes[this.selectedPreviewSize];
    option.button.classList.add(enabledClassname);
  };

  ns.PreviewController.prototype.updateMaxFPS_ = function () {
    var maxFps = pskl.UserSettings.get(pskl.UserSettings.MAX_FPS);
    this.fpsRangeInput.setAttribute('max', maxFps);
    this.piskelController.setFPS(Math.min(maxFps, this.piskelController.getFPS()));
  };

  ns.PreviewController.prototype.updateZoom_ = function () {
    var chosenPreviewSize = pskl.UserSettings.get(pskl.UserSettings.PREVIEW_SIZE);

    var zoom = this.previewSizes[chosenPreviewSize].zoom;

    this.renderer.setZoom($.isFunction(zoom) ? zoom() : zoom);
    this.setRenderFlag_(true);
  };

  ns.PreviewController.prototype.getZoom = function () {
    return this.calculateZoom_();
  };

  ns.PreviewController.prototype.getCoordinates = function(x, y) {
    var containerOffset = this.container.offset();
    x = x - containerOffset.left;
    y = y - containerOffset.top;
    var zoom = this.getZoom();
    return {
      x : Math.floor(x / zoom),
      y : Math.floor(y / zoom)
    };
  };

  /**
   * Event handler triggered on 'input' or 'change' events.
   */
  ns.PreviewController.prototype.onFpsRangeInputUpdate_ = function (evt) {
    var fps = parseInt(this.fpsRangeInput.value, 10);
    this.piskelController.setFPS(fps);
    // blur only on 'change' events, as blurring on 'input' breaks on Firefox
    if (evt.type === 'change') {
      this.fpsRangeInput.blur();
    }
  };

  ns.PreviewController.prototype.updateFPS_ = function () {
    var fps = this.piskelController.getFPS();
    if (fps !== this.fps) {
      this.fps = fps;
      // reset
      this.fpsRangeInput.value = 0;
      // set proper value
      this.fpsRangeInput.value = this.fps;
      this.fpsCounterDisplay.innerHTML = this.fps + ' FPS';
    }
  };

  ns.PreviewController.prototype.render = function (delta) {
    this.elapsedTime += delta;
    var index = this.getNextIndex_(delta);
    if (this.shouldRender_() || this.currentIndex != index) {
      this.currentIndex = index;
      var frame = pskl.utils.LayerUtils.mergeFrameAt(this.piskelController.getLayers(), index);
      this.renderer.render(frame);
      this.renderFlag = false;
      this.lastRenderTime = Date.now();

      this.popupPreviewController.render(frame);
    }
  };

  ns.PreviewController.prototype.getNextIndex_ = function (delta) {
    if (this.fps === 0) {
      return this.piskelController.getCurrentFrameIndex();
    } else {
      var index = Math.floor(this.elapsedTime / (1000 / this.fps));
      if (!this.piskelController.hasFrameAt(index)) {
        this.elapsedTime = 0;
        index = 0;
      }
      return index;
    }
  };

  /**
   * Calculate the preview zoom depending on the framesheet size
   */
  ns.PreviewController.prototype.calculateZoom_ = function (noFloat) {
    var frame = this.piskelController.getCurrentFrame();
    var hZoom = PREVIEW_SIZE / frame.getHeight();
    var wZoom = PREVIEW_SIZE / frame.getWidth();

    if (noFloat) {
      hZoom = Math.floor(hZoom);
      wZoom = Math.floor(wZoom);
    }

    return Math.min(hZoom, wZoom);
  };

  ns.PreviewController.prototype.onFrameSizeChange_ = function () {
    this.updateZoom_();
    this.updateContainerDimensions_();
    this.updatePreviewSizeButtons_();
  };

  ns.PreviewController.prototype.updateContainerDimensions_ = function () {
    var isSeamless = pskl.UserSettings.get(pskl.UserSettings.SEAMLESS_MODE);
    this.renderer.setRepeated(isSeamless);

    var height, width;

    if (isSeamless) {
      height = PREVIEW_SIZE;
      width = PREVIEW_SIZE;
    } else {
      var zoom = this.getZoom();
      var frame = this.piskelController.getCurrentFrame();
      height = frame.getHeight() * zoom;
      width = frame.getWidth() * zoom;
    }

    var containerEl = this.container.get(0);
    containerEl.style.height = height + 'px';
    containerEl.style.width = width + 'px';

    var horizontalMargin = (PREVIEW_SIZE - height) / 2;
    containerEl.style.marginTop = horizontalMargin + 'px';
    containerEl.style.marginBottom = horizontalMargin + 'px';

    var verticalMargin = (PREVIEW_SIZE - width) / 2;
    containerEl.style.marginLeft = verticalMargin + 'px';
    containerEl.style.marginRight = verticalMargin + 'px';
  };

  ns.PreviewController.prototype.setRenderFlag_ = function (bool) {
    this.renderFlag = bool;
  };

  ns.PreviewController.prototype.shouldRender_ = function () {
    return (this.renderFlag || this.popupPreviewController.renderFlag) &&
            (Date.now() - this.lastRenderTime > RENDER_MINIMUM_DELAY);
  };

  ns.PreviewController.prototype.toggleOnionSkin_ = function () {
    var currentValue = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN);
    pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN, !currentValue);
  };
})();
<|endoftext|>


<commit_before><commit_msg>Update catgirl.js to new api<commit_after><|endoftext|>