<commit_before>var settingsText;
var settingsText__difficulty;
var settingsText__sound;
var settingsText__colour;
var pauseCalledPreviously = false;
let pausedText;

function mainMenu() {
    DontPanic.background = DontPanic.game.add.image(0, -40, 'home_background');
    DontPanic.startButton = DontPanic.game.add.button(DontPanic.game.world.centerX, DontPanic.game.world.centerY - 120, 'startButton', startGame, this);
    DontPanic.startButton.anchor.set(0.5);
    DontPanic.settingsButton = DontPanic.game.add.button(DontPanic.game.world.centerX, DontPanic.game.world.centerY - 60, 'settingsButton', settingsMenu, this);
    DontPanic.settingsButton.anchor.set(0.5);
}

function settingsMenu() {
    DontPanic.game.world.removeAll(); //this might not be a good idea as all game assets will need to be loaded back in again?
    DontPanic.game.add.image(0, 0, 'background1');
    settingsText = DontPanic.game.add.group();

    const currentSettings = getCurrentSettings();

    addText(DontPanic.game.world.centerX, 75, "Settings", config.style.fontSize_title, false, "", false);

    settingsText__difficulty = DontPanic.game.add.group();
    addText(DontPanic.game.world.centerX, 175, "Difficulty", config.style.fontSize_heading);
    addText(DontPanic.game.world.centerX * 0.75, 220, "Easy", config.style.fontSize_default,  true, "difficulty", currentSettings.easy);
    addText(DontPanic.game.world.centerX * 1.25, 220, "Hard", config.style.fontSize_default,  true, "difficulty", !currentSettings.easy);

    settingsText__sound = DontPanic.game.add.group();
    addText(DontPanic.game.world.centerX, 290, "Sound", config.style.fontSize_heading);
    addText(DontPanic.game.world.centerX * 0.75, 335, "On", config.style.fontSize_default, true, "sound", currentSettings.soundOn);
    addText(DontPanic.game.world.centerX * 1.25, 335, "Off", config.style.fontSize_default,  true, "sound", !currentSettings.soundOn);

    settingsText__colour = DontPanic.game.add.group();
    addText(DontPanic.game.world.centerX, 405, "Ship Colour", config.style.fontSize_heading);
    addText(DontPanic.game.world.centerX * 0.75, 450, "Red", config.style.fontSize_default, true, "colour", currentSettings.red);
    addText(DontPanic.game.world.centerX * 1.25, 450, "Blue", config.style.fontSize_default, true, "colour", !currentSettings.red);

    addText(DontPanic.game.world.centerX, 550, "Play", config.style.fontSize_default, true, "play");

    settingsText.add(settingsText__difficulty);
    settingsText.add(settingsText__sound);
    settingsText.add(settingsText__colour);
}

function addText(x, y, string, size, clickevent, category, selected) {
  var textOb = DontPanic.game.add.text(x, y, string, {
    font: `${size} ${config.style.font}`,
  });
  textOb.anchor.setTo(0.5);
  textOb.align = 'center';
  textOb.fill = config.style.textColour;
  textOb.fontSize = size;
  textOb.padding.set(16, 16);
  textOb.inputEnabled = true;
  textOb.input.useHandCursor = clickevent;
  addCategorySpecifics(textOb, category);
  if (selected) {
    colourText(textOb);
  }
  return textOb;
}

function addCategorySpecifics(textOb, category) {
  switch (category) {
    case "difficulty":
      settingsText__difficulty.add(textOb);
      textOb.events.onInputDown.add(difficultyListener, this);
      break;
    case "sound":
      settingsText__sound.add(textOb);
      textOb.events.onInputDown.add(soundListener, this);
      break;
    case "colour":
      settingsText__colour.add(textOb);
      textOb.events.onInputDown.add(colourListener, this);
      break;
    case "play":
      settingsText.add(textOb);
      textOb.events.onInputDown.add(startGame, this);
      break;
    default: ;
  }
}

function getCurrentSettings() {
  const currentSettings = {};
  currentSettings["easy"] = (config.currentLevel == "easy") ?  true : false;
  currentSettings["soundOn"] = config.soundOn;
  currentSettings["red"] = (config.playerColour == "red") ?  true : false;
  return currentSettings;
}

function difficultyListener(input) {
  let previousSelection = config.currentLevel;
  config.currentLevel = input["_text"].toLowerCase();
  if (config.currentLevel != previousSelection) {
    for (var i = 0; i < settingsText__difficulty.children.length; i++) {
      colourText(settingsText__difficulty.children[i]);
    }
  }
  getCurrentSettings();
}

function soundListener(input) {
  let previousSelection = config.soundOn; //true or false
  config.soundOn = (input["_text"].toLowerCase() == "on") ?  true : false;
  if (config.soundOn != previousSelection) {
    for (var i = 0; i < settingsText__sound.children.length; i++) {
      colourText(settingsText__sound.children[i]);
    }
  }
  getCurrentSettings();
}

function colourListener(input) {
  let previousSelection = config.playerColour;
  config.playerColour = input["_text"].toLowerCase();
  if (config.playerColour != previousSelection) {
    for (var i = 0; i < settingsText__colour.children.length; i++) {
      colourText(settingsText__colour.children[i]);
    }
  }
  getCurrentSettings();
}

function colourText(text) {
  if (text['style']['fill'] == config.style.textColour_highlight) {
    text.fill = config.style.textColour;
    text.strokeThickness = 0;
  } else {
    text.fill = config.style.textColour_highlight;
    text.stroke = config.style.textColour_highlightOutline;
    text.strokeThickness = 3;
  }
}

function playAgainMenu() {
  DontPanic.game.gameOver.destroy();
  DontPanic.game.camera.resetFX();
  const restartButton = DontPanic.game.add.button(DontPanic.game.world.centerX, DontPanic.game.world.centerY, 'playAgainButton', startGame, this);
  restartButton.anchor.set(0.5);
  const settingsButton = DontPanic.game.add.button(DontPanic.game.world.centerX, DontPanic.game.world.centerY + 100, 'settingsButton', settingsMenu, this);
  settingsButton.anchor.set(0.5);
  if (DontPanic.newBestScore) {
    const bestDistanceText = addText(DontPanic.game.world.centerX, 190, `New Best Distance!!\n${DontPanic.bestDistance}`, config.style.fontSize_bestDistance);
  } else {
    const bestDistanceText = addText(DontPanic.game.world.centerX, 190, `Best Distance: ${DontPanic.bestDistance}`, config.style.fontSize_bestDistance);
  }
}

function pauseMenu() {
  if (!DontPanic.game.paused) {
    console.log('calling first one');
    paused = DontPanic.game.add.group();
    pausedText = addText(DontPanic.game.world.centerX, 190, 'Paused', config.style.fontSize_title);
    paused.add(pausedText);
    console.log(pausedText);
    DontPanic.game.paused = true;
    settingsButton = DontPanic.game.add.button(DontPanic.game.world.centerX, DontPanic.game.world.centerY, 'settingsButton', settingsMenu, this);
    settingsButton.anchor.set(0.5);
    settingsButton.input.useHandCursor = true;
    paused.add(settingsButton);
    DontPanic.pauseButton.loadTexture('playIcon');
  } else {
    console.log(pausedText);
    paused.kill();
    DontPanic.game.paused = false;
    DontPanic.pauseButton.loadTexture('pauseIcon');
  }
}
<commit_msg>tidy up pause menu<commit_after>var settingsText;
var settingsText__difficulty;
var settingsText__sound;
var settingsText__colour;

function mainMenu() {
    DontPanic.background = DontPanic.game.add.image(0, -40, 'home_background');
    DontPanic.startButton = DontPanic.game.add.button(DontPanic.game.world.centerX, DontPanic.game.world.centerY - 120, 'startButton', startGame, this);
    DontPanic.startButton.anchor.set(0.5);
    DontPanic.settingsButton = DontPanic.game.add.button(DontPanic.game.world.centerX, DontPanic.game.world.centerY - 60, 'settingsButton', settingsMenu, this);
    DontPanic.settingsButton.anchor.set(0.5);
}

function settingsMenu() {
    DontPanic.game.world.removeAll(); //this might not be a good idea as all game assets will need to be loaded back in again?
    DontPanic.game.add.image(0, 0, 'background1');
    settingsText = DontPanic.game.add.group();

    const currentSettings = getCurrentSettings();

    addText(DontPanic.game.world.centerX, 75, "Settings", config.style.fontSize_title, false, "", false);

    settingsText__difficulty = DontPanic.game.add.group();
    addText(DontPanic.game.world.centerX, 175, "Difficulty", config.style.fontSize_heading);
    addText(DontPanic.game.world.centerX * 0.75, 220, "Easy", config.style.fontSize_default,  true, "difficulty", currentSettings.easy);
    addText(DontPanic.game.world.centerX * 1.25, 220, "Hard", config.style.fontSize_default,  true, "difficulty", !currentSettings.easy);

    settingsText__sound = DontPanic.game.add.group();
    addText(DontPanic.game.world.centerX, 290, "Sound", config.style.fontSize_heading);
    addText(DontPanic.game.world.centerX * 0.75, 335, "On", config.style.fontSize_default, true, "sound", currentSettings.soundOn);
    addText(DontPanic.game.world.centerX * 1.25, 335, "Off", config.style.fontSize_default,  true, "sound", !currentSettings.soundOn);

    settingsText__colour = DontPanic.game.add.group();
    addText(DontPanic.game.world.centerX, 405, "Ship Colour", config.style.fontSize_heading);
    addText(DontPanic.game.world.centerX * 0.75, 450, "Red", config.style.fontSize_default, true, "colour", currentSettings.red);
    addText(DontPanic.game.world.centerX * 1.25, 450, "Blue", config.style.fontSize_default, true, "colour", !currentSettings.red);

    addText(DontPanic.game.world.centerX, 550, "Play", config.style.fontSize_default, true, "play");

    settingsText.add(settingsText__difficulty);
    settingsText.add(settingsText__sound);
    settingsText.add(settingsText__colour);
}

function addText(x, y, string, size, clickevent, category, selected) {
  var textOb = DontPanic.game.add.text(x, y, string, {
    font: `${size} ${config.style.font}`,
  });
  textOb.anchor.setTo(0.5);
  textOb.align = 'center';
  textOb.fill = config.style.textColour;
  textOb.fontSize = size;
  textOb.padding.set(16, 16);
  textOb.inputEnabled = true;
  textOb.input.useHandCursor = clickevent;
  addCategorySpecifics(textOb, category);
  if (selected) {
    colourText(textOb);
  }
  return textOb;
}

function addCategorySpecifics(textOb, category) {
  switch (category) {
    case "difficulty":
      settingsText__difficulty.add(textOb);
      textOb.events.onInputDown.add(difficultyListener, this);
      break;
    case "sound":
      settingsText__sound.add(textOb);
      textOb.events.onInputDown.add(soundListener, this);
      break;
    case "colour":
      settingsText__colour.add(textOb);
      textOb.events.onInputDown.add(colourListener, this);
      break;
    case "play":
      settingsText.add(textOb);
      textOb.events.onInputDown.add(startGame, this);
      break;
    default: ;
  }
}

function getCurrentSettings() {
  const currentSettings = {};
  currentSettings["easy"] = (config.currentLevel == "easy") ?  true : false;
  currentSettings["soundOn"] = config.soundOn;
  currentSettings["red"] = (config.playerColour == "red") ?  true : false;
  return currentSettings;
}

function difficultyListener(input) {
  let previousSelection = config.currentLevel;
  config.currentLevel = input["_text"].toLowerCase();
  if (config.currentLevel != previousSelection) {
    for (var i = 0; i < settingsText__difficulty.children.length; i++) {
      colourText(settingsText__difficulty.children[i]);
    }
  }
  getCurrentSettings();
}

function soundListener(input) {
  let previousSelection = config.soundOn; //true or false
  config.soundOn = (input["_text"].toLowerCase() == "on") ?  true : false;
  if (config.soundOn != previousSelection) {
    for (var i = 0; i < settingsText__sound.children.length; i++) {
      colourText(settingsText__sound.children[i]);
    }
  }
  getCurrentSettings();
}

function colourListener(input) {
  let previousSelection = config.playerColour;
  config.playerColour = input["_text"].toLowerCase();
  if (config.playerColour != previousSelection) {
    for (var i = 0; i < settingsText__colour.children.length; i++) {
      colourText(settingsText__colour.children[i]);
    }
  }
  getCurrentSettings();
}

function colourText(text) {
  if (text['style']['fill'] == config.style.textColour_highlight) {
    text.fill = config.style.textColour;
    text.strokeThickness = 0;
  } else {
    text.fill = config.style.textColour_highlight;
    text.stroke = config.style.textColour_highlightOutline;
    text.strokeThickness = 3;
  }
}

function playAgainMenu() {
  DontPanic.game.gameOver.destroy();
  DontPanic.game.camera.resetFX();
  const restartButton = DontPanic.game.add.button(DontPanic.game.world.centerX, DontPanic.game.world.centerY, 'playAgainButton', startGame, this);
  restartButton.anchor.set(0.5);
  const settingsButton = DontPanic.game.add.button(DontPanic.game.world.centerX, DontPanic.game.world.centerY + 100, 'settingsButton', settingsMenu, this);
  settingsButton.anchor.set(0.5);
  if (DontPanic.newBestScore) {
    const bestDistanceText = addText(DontPanic.game.world.centerX, 190, `New Best Distance!!\n${DontPanic.bestDistance}`, config.style.fontSize_bestDistance);
  } else {
    const bestDistanceText = addText(DontPanic.game.world.centerX, 190, `Best Distance: ${DontPanic.bestDistance}`, config.style.fontSize_bestDistance);
  }
}

function pauseMenu() {
  if (!DontPanic.game.paused) {
    DontPanic.game.paused = true;
    DontPanic.paused = DontPanic.game.add.group();
    let pausedText = addText(DontPanic.game.world.centerX, 190, 'Paused', config.style.fontSize_title);
    let settingsButton = DontPanic.settingsButton;
    settingsButton.y = DontPanic.game.world.centerY;
    DontPanic.paused.add(pausedText);
    DontPanic.paused.add(settingsButton);
    DontPanic.pauseButton.loadTexture('playIcon');
  } else {
    DontPanic.paused.kill();
    DontPanic.game.paused = false;
    DontPanic.pauseButton.loadTexture('pauseIcon');
  }
}
<|endoftext|>


<commit_before>export default Ember.View.extend({
  templateName: 'user/username',
  classNames: ['user-preferences'],

  _focusUsername: function() {
    Em.run.schedule('afterRender', function() {
      $('#change_username').focus();
    });
  }.on('didInsertElement'),

  keyDown: function(e) {
    if (e.keyCode === 13) {
      if (!this.get('controller').get('saveDisabled')) {
        return this.get('controller').changeUsername();
      } else {
        e.preventDefault();
        return false;
      }
    }
  }
});
<commit_msg>FIX: Enter to change username was broken<commit_after>export default Ember.View.extend({
  templateName: 'user/username',
  classNames: ['user-preferences'],

  _focusUsername: function() {
    Em.run.schedule('afterRender', function() {
      $('#change_username').focus();
    });
  }.on('didInsertElement'),

  keyDown: function(e) {
    if (e.keyCode === 13) {
      if (!this.get('controller').get('saveDisabled')) {
        return this.get('controller').send('changeUsername');
      } else {
        e.preventDefault();
        return false;
      }
    }
  }
});
<|endoftext|>


<commit_before>import React, { Component, Fragment } from 'react';
import { PropTypes as Types } from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { Message, WithTranslations } from 'retranslate';
import { Link } from 'react-router';

import { Loader, ErrorMessage } from '../common';
import PensionFundTable from './../onboardingFlow/selectSources/pensionFundTable';
import PendingExchangesTable from './pendingExchangeTable';
import ReturnComparison, { actions as returnComparisonActions } from '../returnComparison';
import getReturnComparisonStartDateOptions from '../returnComparison/options';
import Select from './Select';
import UpdateUserForm from './updateUserForm';
import { updateUser } from '../common/user/actions';

const noop = () => null;

export const TOTAL_CAPITAL = 3388309;

export class AccountPage extends Component {
  constructor(props) {
    super(props);

    const options = getReturnComparisonStartDateOptions();
    const returnComparisonStartDate = options[0].value;

    this.state = {
      options,
      returnComparisonStartDate,
    };

    this.onReturnComparisonStartDateChange = this.onReturnComparisonStartDateChange.bind(this);
  }

  onReturnComparisonStartDateChange(date) {
    this.props.getReturnComparisonForStartDate(date);
    this.setState({ returnComparisonStartDate: date });
  }

  render() {
    const {
      currentBalanceFunds,
      loadingCurrentBalance,
      initialCapital,
      memberNumber,
      conversion,
      pendingExchanges,
      loadingPendingExchanges,
      returnComparison,
      loadingReturnComparison,
      returnComparisonError,
      saveUser,
      error,
    } = this.props;
    const { returnComparisonStartDate, options } = this.state;

    const pendingExchangesSection = loadingPendingExchanges ? (
      <Loader className="align-middle mt-5" />
    ) : (
      pendingExchanges.length > 0 && (

            <Message>pending.exchanges.lead</Message>

          <PendingExchangesTable pendingExchanges={pendingExchanges} />

      )
    );

    const returnComparisonSection = !returnComparisonError && (

              <Message>returnComparison.title</Message>

            <WithTranslations>
              {({ translate }) => (
                <Select
                  options={options.map(option => ({ ...option, label: translate(option.label) }))}
                  selected={returnComparisonStartDate}
                  onChange={this.onReturnComparisonStartDateChange}
                />
              )}
            </WithTranslations>

        <ReturnComparison
          actualPercentage={returnComparison.actualPercentage}
          estonianPercentage={returnComparison.estonianPercentage}
          marketPercentage={returnComparison.marketPercentage}
          loading={loadingReturnComparison}
        />

    );

    return (
      <Fragment>

          {memberNumber ? (
            <Message params={{ memberNumber }}>account.member.statement</Message>
          ) : (

              <Message>account.non.member.statement</Message>{' '}

                <Message>login.join.tuleva</Message>

          )}{' '}
          {initialCapital ? (
            <Message
              params={{
                initialCapital: initialCapital.amount,
                currentCapital: (TOTAL_CAPITAL * initialCapital.ownershipFraction).toFixed(2),
              }}
            >
              account.initial-capital.statement
            </Message>
          ) : (
            ''
          )}

            {currentBalanceFunds && currentBalanceFunds.length === 0 ? (
              <Message>account.second.pillar.missing</Message>
            ) : (
              ''
            )}

        {conversion && conversion.transfersComplete && conversion.selectionComplete ? (

            <Message>account.converted.user.statement</Message>

        ) : (
          ''
        )}
        {error ? <ErrorMessage errors={error.body} /> : ''}

            <Message className="mb-4 lead">select.sources.current.status</Message>

          {currentBalanceFunds && currentBalanceFunds.length > 0 && (

              <Link className="btn btn-primary mb-3" to="/steps/select-sources">
                <Message>change.my.pension.fund</Message>
              </Link>

          )}

        {loadingCurrentBalance ? (
          <Loader className="align-middle" />
        ) : (
          <PensionFundTable funds={currentBalanceFunds} />
        )}

        {pendingExchangesSection}
        {returnComparisonSection}

            <Message>update.user.details.title</Message>

          <UpdateUserForm onSubmit={saveUser} />

      </Fragment>
    );
  }
}

AccountPage.propTypes = {
  currentBalanceFunds: Types.arrayOf(Types.shape({})),
  loadingCurrentBalance: Types.bool,
  pendingExchanges: Types.arrayOf(Types.shape({})),
  loadingPendingExchanges: Types.bool,
  returnComparison: Types.shape({
    actualPercentage: Types.number,
    estonianPercentage: Types.number,
    marketPercentage: Types.number,
  }),
  returnComparisonError: Types.shape({}),
  loadingReturnComparison: Types.bool,
  getReturnComparisonForStartDate: Types.func,
  initialCapital: Types.shape({}),
  memberNumber: Types.number,
  conversion: Types.shape({}),
  saveUser: Types.func,
  error: Types.shape({}),
};

AccountPage.defaultProps = {
  currentBalanceFunds: [],
  loadingCurrentBalance: false,
  pendingExchanges: [],
  loadingPendingExchanges: false,
  returnComparison: {},
  returnComparisonError: null,
  loadingReturnComparison: false,
  getReturnComparisonForStartDate: noop,
  initialCapital: {},
  memberNumber: null,
  conversion: {},
  error: null,
  saveUser: noop,
};

const mapStateToProps = state => ({
  currentBalanceFunds: state.exchange.sourceFunds !== null ? state.exchange.sourceFunds : [],
  loadingCurrentBalance: state.exchange.loadingSourceFunds,
  pendingExchanges: state.exchange.pendingExchanges,
  loadingPendingExchanges: state.exchange.loadingPendingExchanges,
  returnComparison: state.returnComparison,
  loadingReturnComparison: state.returnComparison.loading,
  returnComparisonError: state.returnComparison.error,
  initialCapital: state.account.initialCapital,
  memberNumber: (state.login.user || {}).memberNumber,
  conversion: state.login.userConversion,
  error: state.exchange.error,
});
const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      saveUser: updateUser,
      getReturnComparisonForStartDate: returnComparisonActions.getReturnComparisonForStartDate,
    },
    dispatch,
  );

const withRedux = connect(
  mapStateToProps,
  mapDispatchToProps,
);

export default withRedux(AccountPage);
<commit_msg>update total capital<commit_after>import React, { Component, Fragment } from 'react';
import { PropTypes as Types } from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { Message, WithTranslations } from 'retranslate';
import { Link } from 'react-router';

import { Loader, ErrorMessage } from '../common';
import PensionFundTable from './../onboardingFlow/selectSources/pensionFundTable';
import PendingExchangesTable from './pendingExchangeTable';
import ReturnComparison, { actions as returnComparisonActions } from '../returnComparison';
import getReturnComparisonStartDateOptions from '../returnComparison/options';
import Select from './Select';
import UpdateUserForm from './updateUserForm';
import { updateUser } from '../common/user/actions';

const noop = () => null;

export const TOTAL_CAPITAL = 3475072;

export class AccountPage extends Component {
  constructor(props) {
    super(props);

    const options = getReturnComparisonStartDateOptions();
    const returnComparisonStartDate = options[0].value;

    this.state = {
      options,
      returnComparisonStartDate,
    };

    this.onReturnComparisonStartDateChange = this.onReturnComparisonStartDateChange.bind(this);
  }

  onReturnComparisonStartDateChange(date) {
    this.props.getReturnComparisonForStartDate(date);
    this.setState({ returnComparisonStartDate: date });
  }

  render() {
    const {
      currentBalanceFunds,
      loadingCurrentBalance,
      initialCapital,
      memberNumber,
      conversion,
      pendingExchanges,
      loadingPendingExchanges,
      returnComparison,
      loadingReturnComparison,
      returnComparisonError,
      saveUser,
      error,
    } = this.props;
    const { returnComparisonStartDate, options } = this.state;

    const pendingExchangesSection = loadingPendingExchanges ? (
      <Loader className="align-middle mt-5" />
    ) : (
      pendingExchanges.length > 0 && (

            <Message>pending.exchanges.lead</Message>

          <PendingExchangesTable pendingExchanges={pendingExchanges} />

      )
    );

    const returnComparisonSection = !returnComparisonError && (

              <Message>returnComparison.title</Message>

            <WithTranslations>
              {({ translate }) => (
                <Select
                  options={options.map(option => ({ ...option, label: translate(option.label) }))}
                  selected={returnComparisonStartDate}
                  onChange={this.onReturnComparisonStartDateChange}
                />
              )}
            </WithTranslations>

        <ReturnComparison
          actualPercentage={returnComparison.actualPercentage}
          estonianPercentage={returnComparison.estonianPercentage}
          marketPercentage={returnComparison.marketPercentage}
          loading={loadingReturnComparison}
        />

    );

    return (
      <Fragment>

          {memberNumber ? (
            <Message params={{ memberNumber }}>account.member.statement</Message>
          ) : (

              <Message>account.non.member.statement</Message>{' '}

                <Message>login.join.tuleva</Message>

          )}{' '}
          {initialCapital ? (
            <Message
              params={{
                initialCapital: initialCapital.amount,
                currentCapital: (TOTAL_CAPITAL * initialCapital.ownershipFraction).toFixed(2),
              }}
            >
              account.initial-capital.statement
            </Message>
          ) : (
            ''
          )}

            {currentBalanceFunds && currentBalanceFunds.length === 0 ? (
              <Message>account.second.pillar.missing</Message>
            ) : (
              ''
            )}

        {conversion && conversion.transfersComplete && conversion.selectionComplete ? (

            <Message>account.converted.user.statement</Message>

        ) : (
          ''
        )}
        {error ? <ErrorMessage errors={error.body} /> : ''}

            <Message className="mb-4 lead">select.sources.current.status</Message>

          {currentBalanceFunds && currentBalanceFunds.length > 0 && (

              <Link className="btn btn-primary mb-3" to="/steps/select-sources">
                <Message>change.my.pension.fund</Message>
              </Link>

          )}

        {loadingCurrentBalance ? (
          <Loader className="align-middle" />
        ) : (
          <PensionFundTable funds={currentBalanceFunds} />
        )}

        {pendingExchangesSection}
        {returnComparisonSection}

            <Message>update.user.details.title</Message>

          <UpdateUserForm onSubmit={saveUser} />

      </Fragment>
    );
  }
}

AccountPage.propTypes = {
  currentBalanceFunds: Types.arrayOf(Types.shape({})),
  loadingCurrentBalance: Types.bool,
  pendingExchanges: Types.arrayOf(Types.shape({})),
  loadingPendingExchanges: Types.bool,
  returnComparison: Types.shape({
    actualPercentage: Types.number,
    estonianPercentage: Types.number,
    marketPercentage: Types.number,
  }),
  returnComparisonError: Types.shape({}),
  loadingReturnComparison: Types.bool,
  getReturnComparisonForStartDate: Types.func,
  initialCapital: Types.shape({}),
  memberNumber: Types.number,
  conversion: Types.shape({}),
  saveUser: Types.func,
  error: Types.shape({}),
};

AccountPage.defaultProps = {
  currentBalanceFunds: [],
  loadingCurrentBalance: false,
  pendingExchanges: [],
  loadingPendingExchanges: false,
  returnComparison: {},
  returnComparisonError: null,
  loadingReturnComparison: false,
  getReturnComparisonForStartDate: noop,
  initialCapital: {},
  memberNumber: null,
  conversion: {},
  error: null,
  saveUser: noop,
};

const mapStateToProps = state => ({
  currentBalanceFunds: state.exchange.sourceFunds !== null ? state.exchange.sourceFunds : [],
  loadingCurrentBalance: state.exchange.loadingSourceFunds,
  pendingExchanges: state.exchange.pendingExchanges,
  loadingPendingExchanges: state.exchange.loadingPendingExchanges,
  returnComparison: state.returnComparison,
  loadingReturnComparison: state.returnComparison.loading,
  returnComparisonError: state.returnComparison.error,
  initialCapital: state.account.initialCapital,
  memberNumber: (state.login.user || {}).memberNumber,
  conversion: state.login.userConversion,
  error: state.exchange.error,
});
const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      saveUser: updateUser,
      getReturnComparisonForStartDate: returnComparisonActions.getReturnComparisonForStartDate,
    },
    dispatch,
  );

const withRedux = connect(
  mapStateToProps,
  mapDispatchToProps,
);

export default withRedux(AccountPage);
<|endoftext|>


<commit_before>// @flow

import OfflinePlugin from 'offline-plugin';
import BaseFeature from '../BaseFeature';
import type WebpackConfigBuilder from '../WebpackConfigBuilder';
import frameworkConfig from '../../../shared/framework-config';

export default class ServiceWorkerFeature extends BaseFeature {

  loadAfter() {
    return '*';
  }

  getFeatureName() {
    return 'service-worker';
  }

  getDescription() {
    return 'Enable service worker';
  }

  isDefaultEnabled() {
    return true;
  }

  visit(config: WebpackConfigBuilder) {

    if (this.isServer()) {
      return;
    }

    const serviceWorkerEntry = frameworkConfig['service-worker'];

    const options: Object = {
      appShell: '/index.html',
      relativePaths: false,
      events: true,

      // TODO: autoUpdate option?

      // this is applied before any match in `caches` section
      excludes: [
        '**/*.gz',
        '**/*.br',
        '**/*.map',
        '**/*.LICENSE',
      ],

      // Removes warning for about `additional` section usage
      safeToUseOptionalCaches: true,

      AppCache: false,
      ServiceWorker: {
      },
    };

    if (serviceWorkerEntry) {
      options.ServiceWorker.entry = serviceWorkerEntry;
    }

    if (this.isProd()) {

      // only enable cache in prod
      Object.assign(options, {
        caches: {
          main: [':rest:'],

          // All chunks marked as `additional`, loaded after main section
          // and do not prevent SW to install. Change to `optional` if
          // do not want them to be preloaded at all (cached only when first loaded)
          additional: ['*.chunk.js', ':externals:'],
        },
      });
    } else {
      Object.assign(options, {
        caches: {},
      });
    }

    config.injectPlugins([
      new OfflinePlugin(options),
    ]);
  }
}
<commit_msg>fix: properly dispatch service-worker lifecycle events<commit_after>// @flow

import OfflinePlugin from 'offline-plugin';
import BaseFeature from '../BaseFeature';
import type WebpackConfigBuilder from '../WebpackConfigBuilder';
import frameworkConfig from '../../../shared/framework-config';

export default class ServiceWorkerFeature extends BaseFeature {

  loadAfter() {
    return '*';
  }

  getFeatureName() {
    return 'service-worker';
  }

  getDescription() {
    return 'Enable service worker';
  }

  isDefaultEnabled() {
    return true;
  }

  visit(config: WebpackConfigBuilder) {

    if (this.isServer()) {
      return;
    }

    const serviceWorkerEntry = frameworkConfig['service-worker'];

    const options: Object = {
      appShell: '/index.html',
      relativePaths: false,

      // this is applied before any match in `caches` section
      excludes: [
        '**/*.gz',
        '**/*.br',
        '**/*.map',
        '**/*.LICENSE',
        'loadable-stats.json',
      ],

      // Removes warning for about `additional` section usage
      safeToUseOptionalCaches: true,

      AppCache: false,
      ServiceWorker: {
        events: true,
      },
    };

    if (serviceWorkerEntry) {
      options.ServiceWorker.entry = serviceWorkerEntry;
    }

    if (this.isProd()) {

      // only enable cache in prod
      Object.assign(options, {
        caches: {
          main: [':rest:'],

          // All chunks marked as `additional`, loaded after main section
          // and do not prevent SW to install. Change to `optional` if
          // do not want them to be preloaded at all (cached only when first loaded)
          additional: ['*.chunk.js', ':externals:'],
        },
      });
    } else {
      Object.assign(options, {
        caches: {},
      });
    }

    config.injectPlugins([
      new OfflinePlugin(options),
    ]);
  }
}
<|endoftext|>


<commit_before>var test = require('tape');
var Person = require('../js/person');

test('person constructor', t => {
    var p = new Person(0, 0);
    t.equal(p.px, 0, 'x position');
    t.equal(p.py, 0, 'y position');
    t.equal(p.xv, 0, 'x velocity');
    t.equal(p.yv, 0, 'y velocity');
    t.equal(p.onG, false, 'is on ground');
    t.equal(p.c, '#ffffff', 'colour is default white');
    t.end();
});

test('person move', t => {
    var p = new Person(0, 0);
    t.equal(p.px, 0, 'x position before moving');
    t.equal(p.py, 0, 'y position before moving');
    p.xv = 10;
    p.yv = 10;
    p.move();
    t.equal(p.px, 10, 'x position after moving');
    t.equal(p.py, 10, 'y position after moving');
    t.end();
});
<commit_msg>add more move test cases<commit_after>var test = require('tape');
var Person = require('../js/person');

test('person constructor', t => {
    var p = new Person(0, 0);
    t.equal(p.px, 0, 'x position');
    t.equal(p.py, 0, 'y position');
    t.equal(p.xv, 0, 'x velocity');
    t.equal(p.yv, 0, 'y velocity');
    t.equal(p.onG, false, 'is on ground');
    t.equal(p.c, '#ffffff', 'colour is default white');
    t.end();
});

test('person move positive x / positive y', t => {
    var p = new Person(0, 0);
    t.equal(p.px, 0, 'x position before moving');
    t.equal(p.py, 0, 'y position before moving');
    p.xv = 10;
    p.yv = 10;
    p.move();
    t.equal(p.px, 10, 'x position after moving');
    t.equal(p.py, 10, 'y position after moving');
    t.end();
});

test('person move positive x / negative y', t => {
    var p = new Person(0, 0);
    t.equal(p.px, 0, 'x position before moving');
    t.equal(p.py, 0, 'y position before moving');
    p.xv = 10;
    p.yv = -10;
    p.move();
    t.equal(p.px, 10, 'x position after moving');
    t.equal(p.py, -10, 'y position after moving');
    t.end();
});

test('person move negative x / positive y', t => {
    var p = new Person(0, 0);
    t.equal(p.px, 0, 'x position before moving');
    t.equal(p.py, 0, 'y position before moving');
    p.xv = -10;
    p.yv = 10;
    p.move();
    t.equal(p.px, -10, 'x position after moving');
    t.equal(p.py, 10, 'y position after moving');
    t.end();
});

test('person move negative x / negative y', t => {
    var p = new Person(0, 0);
    t.equal(p.px, 0, 'x position before moving');
    t.equal(p.py, 0, 'y position before moving');
    p.xv = -10;
    p.yv = -10;
    p.move();
    t.equal(p.px, -10, 'x position after moving');
    t.equal(p.py, -10, 'y position after moving');
    t.end();
});
<|endoftext|>


<commit_before>var featuresAttributeListConfiguratorLabel = {
    'attribute': OpenLayers.i18n('Attributes'),
    'showInList': OpenLayers.i18n('Show in list'),
    'showInPopup': OpenLayers.i18n('Show in popup'),
    'apply': OpenLayers.i18n('Apply'),
    'noLayer': OpenLayers.i18n('No layer selected'),
    'noAttributes': OpenLayers.i18n('Layer have no attributes')
};

gbi.widgets = gbi.widgets || {};

gbi.widgets.FeatureAttributesListConfigurator = function(thematicalVector, options) {
    if(!(thematicalVector instanceof gbi.widgets.ThematicalVector)) {
        return;
    }
    var self = this;
    var defaults = {
        element: 'featureattributelistconfigurator',
        mode: 'exact',
        initOnly: false
    }
    this.options = $.extend({}, defaults, options);
    this.thematicalVector = thematicalVector
    this.editor = thematicalVector.editor;
    this.activeLayer = this.editor.layerManager.active();

    $(gbi).on('gbi.layermanager.layer.active', function(event, layer) {
        self.activeLayer = layer;
        if(self.activeLayer) {
            self._registerLayerEvents(self.activeLayer);
            self.attributes = self.activeLayer.featuresAttributes() || [];
        } else {
            self.attributes = [];
        }
        self.render();
    });
    if(this.activeLayer) {
        this._registerLayerEvents(this.activeLayer);
        this.attributes = this.activeLayer.featuresAttributes() || [];
    } else {
        this.attributes = [];
    }
    if(!this.options.initOnly) {
        self.render();
    }
};
gbi.widgets.FeatureAttributesListConfigurator.prototype = {
    render: function() {
        var self = this;
        var element = $('#' + this.options.element);
        element.empty();

        if(!this.activeLayer) {
            element.append($('
' + featuresAttributeListConfiguratorLabel.noLayer + '
'));
            return;
        }

        element.append(tmpl(
            gbi.widgets.FeatureAttributesListConfigurator.template, {
                attributes: self.attributes || []
            }
        ));

        var listAttributes = self.activeLayer ? self.activeLayer.listAttributes() : [];
        var popupAttributes = self.activeLayer ? self.activeLayer.popupAttributes() : [];

        if(listAttributes) {
            element.find('.list-attribute').each(function(idx, elm) {
                elm = $(elm);
                elm.change(function() {
                    self._restrictAttributes(elm, '.list-attribute', 5)
                })
                if($.inArray(elm.val(), listAttributes) != -1) {
                    elm.attr('checked', 'checked');
                }

            })
        }

        if(popupAttributes) {
            element.find('.popup-attribute').each(function(idx, elm) {
                elm = $(elm);
                elm.change(function() {
                    self._restrictAttributes(elm, '.popup-attribute', 5)
                });
                if($.inArray(elm.val(), popupAttributes) != -1) {
                    elm.attr('checked', 'checked');
                }
            })
        }

        element.find('#sortable').sortable();

        $('#setListAttributes').click(function() {
            var listAttributes = [];
            var popupAttributes = [];
            $.each(self.element.find('.list-attribute:checked'), function(idx, checkbox) {
                listAttributes.push(checkbox.value);
            });
            $.each(self.element.find('.popup-attribute:checked'), function(idx, checkbox) {
                popupAttributes.push(checkbox.value);
            });
            self.activeLayer.listAttributes(listAttributes);
            self.activeLayer.popupAttributes(popupAttributes);
            if(self.activeLayer instanceof gbi.Layers.Couch) {
                self.activeLayer._saveGBIData();
            }
        })
    },
    _registerLayerEvents: function(layer) {
        var self = this;
        if(layer instanceof gbi.Layers.SaveableVector && !layer.loaded) {
            $(layer).on('gbi.layer.couch.loadFeaturesEnd', function() {
                self.attributes = layer.featuresAttributes() || [];
                self.render();
            });
        }
        $(layer).on('gbi.layer.vector.featureAttributeChanged', function() {
            self.attributes = layer.featuresAttributes() || [];
            self.render();
        });
    },
    _restrictAttributes: function(elm, selector, max) {
        var self = this;
        var count = self.element.find(selector + ':checked').length;
        if(count > max) {
            elm.removeAttr('checked');
            console.log('Only ' + max + ' or less attributes can be selected')
        }
    }
};

gbi.widgets.FeatureAttributesListConfigurator.template = '\
    <% if(attributes.length == 0) { %>\

' + featuresAttributeListConfiguratorLabel.noAttributes + '
\
    <% } else { %>\

\

\

\
                     	\
                    ' + featuresAttributeListConfiguratorLabel.attribute + '	\
                    ' + featuresAttributeListConfiguratorLabel.showInList + '	\
                    ' + featuresAttributeListConfiguratorLabel.showInPopup + '	\

\

\

\
                <% for(var a_key in attributes) { %>\

\
                        	\
                        <%=attributes[a_key]%>	\
                        <input type="checkbox" class="list-attribute" value="<%=attributes[a_key]%>" />	\
                        <input type="checkbox" class="popup-attribute" value="<%=attributes[a_key]%>" />	\

\
                <% } %>\

\

\

\
            <button id="setListAttributes" class="btn btn-small">' + featuresAttributeListConfiguratorLabel.apply + '</button>\

\
    <% } %>\
';
<commit_msg>Fixed typo<commit_after>var featuresAttributeListConfiguratorLabel = {
    'attributes': OpenLayers.i18n('Attributes'),
    'showInList': OpenLayers.i18n('Show in list'),
    'showInPopup': OpenLayers.i18n('Show in popup'),
    'apply': OpenLayers.i18n('Apply'),
    'noLayer': OpenLayers.i18n('No layer selected'),
    'noAttributes': OpenLayers.i18n('Layer have no attributes')
};

gbi.widgets = gbi.widgets || {};

gbi.widgets.FeatureAttributesListConfigurator = function(thematicalVector, options) {
    if(!(thematicalVector instanceof gbi.widgets.ThematicalVector)) {
        return;
    }
    var self = this;
    var defaults = {
        element: 'featureattributelistconfigurator',
        mode: 'exact',
        initOnly: false
    }
    this.options = $.extend({}, defaults, options);
    this.thematicalVector = thematicalVector
    this.editor = thematicalVector.editor;
    this.activeLayer = this.editor.layerManager.active();

    $(gbi).on('gbi.layermanager.layer.active', function(event, layer) {
        self.activeLayer = layer;
        if(self.activeLayer) {
            self._registerLayerEvents(self.activeLayer);
            self.attributes = self.activeLayer.featuresAttributes() || [];
        } else {
            self.attributes = [];
        }
        self.render();
    });
    if(this.activeLayer) {
        this._registerLayerEvents(this.activeLayer);
        this.attributes = this.activeLayer.featuresAttributes() || [];
    } else {
        this.attributes = [];
    }
    if(!this.options.initOnly) {
        self.render();
    }
};
gbi.widgets.FeatureAttributesListConfigurator.prototype = {
    render: function() {
        var self = this;
        var element = $('#' + this.options.element);
        element.empty();

        if(!this.activeLayer) {
            element.append($('
' + featuresAttributeListConfiguratorLabel.noLayer + '
'));
            return;
        }

        element.append(tmpl(
            gbi.widgets.FeatureAttributesListConfigurator.template, {
                attributes: self.attributes || []
            }
        ));

        var listAttributes = self.activeLayer ? self.activeLayer.listAttributes() : [];
        var popupAttributes = self.activeLayer ? self.activeLayer.popupAttributes() : [];

        if(listAttributes) {
            element.find('.list-attribute').each(function(idx, elm) {
                elm = $(elm);
                elm.change(function() {
                    self._restrictAttributes(elm, '.list-attribute', 5)
                })
                if($.inArray(elm.val(), listAttributes) != -1) {
                    elm.attr('checked', 'checked');
                }

            })
        }

        if(popupAttributes) {
            element.find('.popup-attribute').each(function(idx, elm) {
                elm = $(elm);
                elm.change(function() {
                    self._restrictAttributes(elm, '.popup-attribute', 5)
                });
                if($.inArray(elm.val(), popupAttributes) != -1) {
                    elm.attr('checked', 'checked');
                }
            })
        }

        element.find('#sortable').sortable();

        $('#setListAttributes').click(function() {
            var listAttributes = [];
            var popupAttributes = [];
            $.each(self.element.find('.list-attribute:checked'), function(idx, checkbox) {
                listAttributes.push(checkbox.value);
            });
            $.each(self.element.find('.popup-attribute:checked'), function(idx, checkbox) {
                popupAttributes.push(checkbox.value);
            });
            self.activeLayer.listAttributes(listAttributes);
            self.activeLayer.popupAttributes(popupAttributes);
            if(self.activeLayer instanceof gbi.Layers.Couch) {
                self.activeLayer._saveGBIData();
            }
        })
    },
    _registerLayerEvents: function(layer) {
        var self = this;
        if(layer instanceof gbi.Layers.SaveableVector && !layer.loaded) {
            $(layer).on('gbi.layer.couch.loadFeaturesEnd', function() {
                self.attributes = layer.featuresAttributes() || [];
                self.render();
            });
        }
        $(layer).on('gbi.layer.vector.featureAttributeChanged', function() {
            self.attributes = layer.featuresAttributes() || [];
            self.render();
        });
    },
    _restrictAttributes: function(elm, selector, max) {
        var self = this;
        var count = self.element.find(selector + ':checked').length;
        if(count > max) {
            elm.removeAttr('checked');
            console.log('Only ' + max + ' or less attributes can be selected')
        }
    }
};

gbi.widgets.FeatureAttributesListConfigurator.template = '\
    <% if(attributes.length == 0) { %>\

' + featuresAttributeListConfiguratorLabel.noAttributes + '
\
    <% } else { %>\

\

\

\
                     	\
                    ' + featuresAttributeListConfiguratorLabel.attributes + '	\
                    ' + featuresAttributeListConfiguratorLabel.showInList + '	\
                    ' + featuresAttributeListConfiguratorLabel.showInPopup + '	\

\

\

\
                <% for(var a_key in attributes) { %>\

\
                        	\
                        <%=attributes[a_key]%>	\
                        <input type="checkbox" class="list-attribute" value="<%=attributes[a_key]%>" />	\
                        <input type="checkbox" class="popup-attribute" value="<%=attributes[a_key]%>" />	\

\
                <% } %>\

\

\

\
            <button id="setListAttributes" class="btn btn-small">' + featuresAttributeListConfiguratorLabel.apply + '</button>\

\
    <% } %>\
';
<|endoftext|>


<commit_before>/**
 * @module neue/modal
 * Show/hide modals. Link should have `.js-modal-link` class, and
 * it's `href` should point to the hash of the modal. By convention, the
 * modal ID should be prefixed with `modal--` like so:
 *
 * @example
 * //
 *
 */

define(function(require) {
  "use strict";

  var $ = window.jQuery;
  var Modernizr = window.Modernizr;
  var Events = require("./events");

  // We can only have one modal open at a time; we track that here.
  var modalIsOpen = false;

  // The modal container (including background overlay).
  var $modal = null;

  // The content of the modal.
  var $modalContent = null;

  // Reference to current modal source
  var $reference = null;

  // Whether this modal can be closed by the user
  var closeable = false;

  // Return a boolean if modal is open or not
  var isOpen = function() {
    return modalIsOpen;
  };

  // Click handler for opening a new modal
  var _openHandler = function(event) {
    event.preventDefault();
    var href = "";

    if( $(this).data("cached-modal") ) {
      // Preferred method: We load the modal specified in the `data-cached-modal` attribute.
      // This allows `href` to act as a backup if JS is disabled. For example,
      // `<a class="js-modal-link" data-cached-modal="#modal--faq" href="faq.html">Click</a>`
      // would open a modal with the contents of `<div id="modal--faq"></div>`.
      href = $($(this).data("cached-modal"));
    } else if ( event.target.hash.charAt(0) === "#"  ) {
      // We find the modal based on the ID in the link"s `href`. For example,
      // `<a class="js-modal-link" href="#modal--faq">Click me</a>` would open
      // `<div id="modal--faq"></div>`.
      href = $(event.target.hash);
    } else {
      // @TODO: We should handle AJAX loading things in.
    }

    open(href);
  };

  /**
   * Open a new modal
   * @param {jQuery}  $el                 Element that will be placed inside the modal.
   * @param {boolean} [options.animated=true]     Use animation for opening the modal.
   * @param {boolean} [options.closeButton]       Override `data-modal-close` attribute.
   * @param {boolean} [options.skipForm]          Override `data-modal-skip-form` attribute.
   */
  var open = function($el, options) {
    // Default arguments
    options = options || {};
    options.animated = typeof options.animated !== "undefined" ? options.animated : true;
    options.closeButton = typeof options.closeButton !== "undefined" ? options.closeButton : $el.attr("data-modal-close");
    options.skipForm = typeof options.skipForm !== "undefined" ? options.skipForm : $el.attr("data-modal-skip-form");

    var id = $el.attr("id");
    if(id) {
      // Save ID of modal for future reference
      $reference = "#" + id;

      // Set URL hash in the browser
      window.location.hash = "#" + id;
    } else {
      $reference = "";
    }

    // If Google Analytics is set up, we fire an event to track that a
    // modal has been opened.
    if(typeof(_gaq) !== "undefined" && _gaq !== null) {
      _gaq.push(["_trackEvent", "Modal", "Open", $reference, null, true]);
    }

    if( !modalIsOpen ) {
      // create modal in DOM
      $modal = $("

");
      $modalContent = $("

");
      $modal.append($modalContent);
      $modalContent.html( $el.html() );

      // set up overlay and show modal
      $("body").addClass("modal-open");
      $("body").append($modal);

      if(options.animated && Modernizr.cssanimations) {
        $modal.addClass("fade-in");
        $modalContent.addClass("fade-in-up");
      }

      // copy classes from modal source
      $modalContent.removeClass();
      $modalContent.addClass("modal-content");
      $modalContent.addClass( $el.attr("class") );

      $modal.show();

      // Bind events to close Modal
      $modal.on("click", ".js-close-modal", _closeHandler);
      $modal.on("click", _closeHandler);

      modalIsOpen = true;

      //  **This fixes an issue with `position:fixed` and the virtual keyboard
      //  on Mobile Safari.** Since this is a browser bug, we're forced to use
      //  browser-detection here, and should look into removing this as soon
      //  as this is fixed in the future. Yes, it is gross.
      if(  /iPhone|iPad|iPod/i.test(window.navigator.userAgent) ) {
        setTimeout(function () {
          $modal.css({ "position": "absolute", "overflow": "visible", "height": $(document).height() + "px" });
          $modalContent.css({ "margin-top": $(document).scrollTop() + "px" });
        }, 0);
      }
    } else {
      // modal is already open, so just replace current content
      $modalContent.removeClass();
      $modalContent.addClass("modal-content");
      $modalContent.addClass( $el.attr("class") );
      $modalContent.html( $($el).html() );
    }

    // We add a "close" button programmatically
    // @param [data-modal-close=true]
    switch (options.closeButton) {
      case "skip":
        // Add a skip button, which delegates to the submitting the form with the given ID
        var $skipForm = $( options.skipForm );
        var $skipLink = $("skip");
        $modalContent.prepend( $skipLink );
        $skipLink.on("click", function(event) {
          event.preventDefault();
          $skipForm.submit();
        });
        closeable = false; // cannot close modal by clicking background
        break;

      case "yes":
      case "true":
      case "1":
        $modalContent.prepend("×");
        closeable = true;
        break;
      default:
        closeable = false;
    }

    var closeClass = $el.attr("data-modal-close-class");
    if(closeClass) {
      $modalContent.find(".js-close-modal").addClass(closeClass);
    }

    // We provide an event that other modules can hook into to perform custom functionality when
    // a modal opens (such as preparing things that are added to the DOM, etc.)
    Events.publish("Modal:opened", $modalContent);

    // If Drupal has some messages on the screen, move them inside the modal
    // @TODO: We need a better solution for this.
    var $messages = $(".messages");
    var $messagesClone = $modalContent.find(".js-messages-clone");
    if($messagesClone && $messages.length ) {
      $messagesClone.addClass("modal-messages");
      $messagesClone.html( $messages[0].outerHTML );
      $messagesClone.find(".js-close-message").remove();
    }
  };

  var _closeHandler = function(event) {
    // Don't let the event bubble.
    if(event.target !== this) {
      return;
    }

    // Only close on clicking overlay if this modal has a "x" close button
    if(!closeable) {
      return;
    }

    // Override default link behavior.
    event.preventDefault();

    close();
  };

  /**
   * Close the active modal.
   * @param {boolean} [animated=true] Use animation for closing the modal.
   */
  var close = function(animated) {
    // Default arguments
    animated = typeof animated !== "undefined" ? animated : true;

    // Remove URL hash for modal from browser
    if(window.location.hash === $reference) {
      window.location.hash = "/";
    }

    // If Google Analytics is set up, we fire an event to track that a
    // modal has been closed.
    if(typeof(_gaq) !== "undefined" && _gaq !== null) {
      _gaq.push(["_trackEvent", "Modal", "Close", $reference, null, true]);
    }

    if(animated && Modernizr.cssanimations) {
      $modalContent.addClass("fade-out-down");
      $modal.addClass("fade-out");

      $("body").removeClass("modal-open");

      $modal.one("webkitAnimationEnd oanimationend msAnimationEnd animationend", function() {
        $modal.remove();
        modalIsOpen = false;
      });
    } else {
      $("body").removeClass("modal-open");
      $modal.remove();
      modalIsOpen = false;
    }
  };

  $(document).ready(function() {
    // Attach modal handler to `.js-modal-link` elements on click
    $("body").on("click", ".js-modal-link", _openHandler);

    //If there's a hash in the URL, let's check if its a modal and load it
    var hash = window.location.hash;
    if(hash && hash !== "#/" && $(hash) && $(hash).attr("type") === "text/cached-modal" ) {
      open($(hash), false);
    }

    // Close modal events are bound on modal initialization.
  });

  // Return public API for controlling modals
  return {
    isOpen: isOpen,
    open: open,
    close: close
  };

});
<commit_msg>Fixes 'js-modal-close' links to work on old-style modals again.<commit_after>/**
 * @module neue/modal
 * Show/hide modals. Link should have `.js-modal-link` class, and
 * it's `href` should point to the hash of the modal. By convention, the
 * modal ID should be prefixed with `modal--` like so:
 *
 * @example
 * //
 *
 */

define(function(require) {
  "use strict";

  var $ = window.jQuery;
  var Modernizr = window.Modernizr;
  var Events = require("./events");

  // We can only have one modal open at a time; we track that here.
  var modalIsOpen = false;

  // The modal container (including background overlay).
  var $modal = null;

  // The content of the modal.
  var $modalContent = null;

  // Reference to current modal source
  var $reference = null;

  // Whether this modal can be closed by the user
  var closeable = false;

  // Return a boolean if modal is open or not
  var isOpen = function() {
    return modalIsOpen;
  };

  // Click handler for opening a new modal
  var _openHandler = function(event) {
    event.preventDefault();
    var href = "";

    if( $(this).data("cached-modal") ) {
      // Preferred method: We load the modal specified in the `data-cached-modal` attribute.
      // This allows `href` to act as a backup if JS is disabled. For example,
      // `<a class="js-modal-link" data-cached-modal="#modal--faq" href="faq.html">Click</a>`
      // would open a modal with the contents of `<div id="modal--faq"></div>`.
      href = $($(this).data("cached-modal"));
    } else if ( event.target.hash.charAt(0) === "#"  ) {
      // We find the modal based on the ID in the link"s `href`. For example,
      // `<a class="js-modal-link" href="#modal--faq">Click me</a>` would open
      // `<div id="modal--faq"></div>`.
      href = $(event.target.hash);
    } else {
      // @TODO: We should handle AJAX loading things in.
    }

    open(href);
  };

  /**
   * Open a new modal
   * @param {jQuery}  $el                 Element that will be placed inside the modal.
   * @param {boolean} [options.animated=true]     Use animation for opening the modal.
   * @param {boolean} [options.closeButton]       Override `data-modal-close` attribute.
   * @param {boolean} [options.skipForm]          Override `data-modal-skip-form` attribute.
   */
  var open = function($el, options) {
    // Default arguments
    options = options || {};
    options.animated = typeof options.animated !== "undefined" ? options.animated : true;
    options.closeButton = typeof options.closeButton !== "undefined" ? options.closeButton : $el.attr("data-modal-close");
    options.skipForm = typeof options.skipForm !== "undefined" ? options.skipForm : $el.attr("data-modal-skip-form");

    var id = $el.attr("id");
    if(id) {
      // Save ID of modal for future reference
      $reference = "#" + id;

      // Set URL hash in the browser
      window.location.hash = "#" + id;
    } else {
      $reference = "";
    }

    // If Google Analytics is set up, we fire an event to track that a
    // modal has been opened.
    if(typeof(_gaq) !== "undefined" && _gaq !== null) {
      _gaq.push(["_trackEvent", "Modal", "Open", $reference, null, true]);
    }

    if( !modalIsOpen ) {
      // create modal in DOM
      $modal = $("

");
      $modalContent = $("

");
      $modal.append($modalContent);
      $modalContent.html( $el.html() );

      // set up overlay and show modal
      $("body").addClass("modal-open");
      $("body").append($modal);

      if(options.animated && Modernizr.cssanimations) {
        $modal.addClass("fade-in");
        $modalContent.addClass("fade-in-up");
      }

      // copy classes from modal source
      $modalContent.removeClass();
      $modalContent.addClass("modal-content");
      $modalContent.addClass( $el.attr("class") );

      $modal.show();

      // Bind events to close Modal
      $modal.on("click", ".js-close-modal", _closeHandler);
      $modal.on("click", _closeHandler);

      modalIsOpen = true;

      //  **This fixes an issue with `position:fixed` and the virtual keyboard
      //  on Mobile Safari.** Since this is a browser bug, we're forced to use
      //  browser-detection here, and should look into removing this as soon
      //  as this is fixed in the future. Yes, it is gross.
      if(  /iPhone|iPad|iPod/i.test(window.navigator.userAgent) ) {
        setTimeout(function () {
          $modal.css({ "position": "absolute", "overflow": "visible", "height": $(document).height() + "px" });
          $modalContent.css({ "margin-top": $(document).scrollTop() + "px" });
        }, 0);
      }
    } else {
      // modal is already open, so just replace current content
      $modalContent.removeClass();
      $modalContent.addClass("modal-content");
      $modalContent.addClass( $el.attr("class") );
      $modalContent.html( $($el).html() );
    }

    // We add a "close" button programmatically
    // @param [data-modal-close=true]
    switch (options.closeButton) {
      case "skip":
        // Add a skip button, which delegates to the submitting the form with the given ID
        var $skipForm = $( options.skipForm );
        var $skipLink = $("skip");
        $modalContent.prepend( $skipLink );
        $skipLink.on("click", function(event) {
          event.preventDefault();
          $skipForm.submit();
        });
        closeable = false; // cannot close modal by clicking background
        break;

      case "yes":
      case "true":
      case "1":
        $modalContent.prepend("×");
        closeable = true;
        break;
      default:
        closeable = false;
    }

    var closeClass = $el.attr("data-modal-close-class");
    if(closeClass) {
      $modalContent.find(".js-close-modal").addClass(closeClass);
    }

    // We provide an event that other modules can hook into to perform custom functionality when
    // a modal opens (such as preparing things that are added to the DOM, etc.)
    Events.publish("Modal:opened", $modalContent);

    // If Drupal has some messages on the screen, move them inside the modal
    // @TODO: We need a better solution for this.
    var $messages = $(".messages");
    var $messagesClone = $modalContent.find(".js-messages-clone");
    if($messagesClone && $messages.length ) {
      $messagesClone.addClass("modal-messages");
      $messagesClone.html( $messages[0].outerHTML );
      $messagesClone.find(".js-close-message").remove();
    }
  };

  var _closeHandler = function(event) {
    // Don't let the event bubble.
    if(event.target !== this) {
      return;
    }

    // Only close on clicking overlay if this modal has a "x" close button
    if( $(this).hasClass("js-close-modal") || closeable ) {
      // Override default link behavior.
      event.preventDefault();
      close();
    }
  };

  /**
   * Close the active modal.
   * @param {boolean} [animated=true] Use animation for closing the modal.
   */
  var close = function(animated) {
    // Default arguments
    animated = typeof animated !== "undefined" ? animated : true;

    // Remove URL hash for modal from browser
    if(window.location.hash === $reference) {
      window.location.hash = "/";
    }

    // If Google Analytics is set up, we fire an event to track that a
    // modal has been closed.
    if(typeof(_gaq) !== "undefined" && _gaq !== null) {
      _gaq.push(["_trackEvent", "Modal", "Close", $reference, null, true]);
    }

    if(animated && Modernizr.cssanimations) {
      $modalContent.addClass("fade-out-down");
      $modal.addClass("fade-out");

      $("body").removeClass("modal-open");

      $modal.one("webkitAnimationEnd oanimationend msAnimationEnd animationend", function() {
        $modal.remove();
        modalIsOpen = false;
      });
    } else {
      $("body").removeClass("modal-open");
      $modal.remove();
      modalIsOpen = false;
    }
  };

  $(document).ready(function() {
    // Attach modal handler to `.js-modal-link` elements on click
    $("body").on("click", ".js-modal-link", _openHandler);

    //If there's a hash in the URL, let's check if its a modal and load it
    var hash = window.location.hash;
    if(hash && hash !== "#/" && $(hash) && $(hash).attr("type") === "text/cached-modal" ) {
      open($(hash), false);
    }

    // Close modal events are bound on modal initialization.
  });

  // Return public API for controlling modals
  return {
    isOpen: isOpen,
    open: open,
    close: close
  };

});
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { compose, graphql } from 'react-apollo';
import { connect } from 'react-redux';
import moment from 'moment';
import FontIcon from 'material-ui/FontIcon';
import camelCase from 'camelcase';

import ActionSettingsForm from 'components/ActionSettingsForm';
import Link from 'components/Link';

import formWrapper from 'lib/formWrapper';

import {
  validateString,
  validateState,
  validateZipcode,
  validateStartEndTimes,
} from 'lib/validateComponentForms';

import CampaignQuery from 'schemas/queries/CampaignQuery.graphql';
import ActionQuery from 'schemas/queries/ActionQuery.graphql';

import EditActionMutation from 'schemas/mutations/EditActionMutation.graphql';

import s from 'styles/Organize.scss';

const WrappedActionSettingsForm = formWrapper(ActionSettingsForm);

class ManageActionSettings extends Component {
  static propTypes = {
    campaign: PropTypes.object,
    action: PropTypes.object,
    graphqlLoading: PropTypes.bool.isRequired,
    editActionMutation: PropTypes.func.isRequired,
    // eslint-disable-next-line react/no-unused-prop-types
    campaignId: PropTypes.string.isRequired,
    // eslint-disable-next-line react/no-unused-prop-types
    actionId: PropTypes.string.isRequired,
  }

  static defaultProps = {
    action: undefined,
    campaign: undefined,
  }

  constructor(props) {
    super(props);

    const initialState = {
      formData: {
        title: '',
        internalTitle: '',
        virtual: false,
        locationName: '',
        streetAddress: '',
        streetAddress2: '',
        city: '',
        state: '',
        zipcode: '',
        locationNotes: '',
        ongoing: false,
        date: undefined,
        startTime: undefined,
        endTime: undefined,
        activities: [],
        tags: [],
      },
    };

    this.state = Object.assign({}, initialState);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.action && !nextProps.graphqlLoading) {
      // Just camel-casing property keys and checking for null
      const action = Object.assign(...Object.keys(nextProps.action).map((k) => {
        if (nextProps.action[k] !== null) {
          return { [camelCase(k)]: nextProps.action[k] };
        }
        return undefined;
      }));

      // Handle date/time
      const newDateTimes = {
        date: action.startTime && moment(action.startTime).isValid() ? moment(action.startTime).toDate() : undefined,
        startTime: action.startTime && moment(action.startTime).isValid() ? moment(action.startTime).toDate() : undefined,
        endTime: action.endTime && moment(action.endTime).isValid() ? moment(action.endTime).toDate() : undefined,
      };

      delete action.startTime;
      delete action.endTime;

      this.setState(prevState => ({
        formData: Object.assign({}, prevState.formData, newDateTimes),
      }));

      Object.keys(action).forEach((k) => {
        if (!Object.keys(this.state.formData).includes(camelCase(k))) {
          delete action[k];
        }
      });

      this.setState(prevState => ({
        formData: Object.assign({}, prevState.formData, action),
      }));
    }
  }

  defaultErrorText = {
    titleErrorText: null,
    streetAddressErrorText: null,
    locationNameErrorText: null,
    locationNotesErrorText: null,
    websiteUrlErrorText: null,
    phoneNumberErrorText: null,
    cityErrorText: null,
    stateErrorText: null,
    zipcodeErrorText: null,
    dateErrorText: null,
    startTimeErrorText: null,
    endTimeErrorText: null,
  }

  formSubmit = async (data) => {
    // A little hackish to avoid an annoying rerender with previous form data
    // If I could figure out how to avoid keeping state here
    // w/ the componentWillReceiveProps/apollo/graphql then
    // I might not need this
    this.setState({
      formData: Object.assign({}, data),
    });

    const formData = Object.assign({}, data);

    if (formData.ongoing) {
      formData.startTime = null;
      formData.endTime = null;
    } else {
      const startTime = moment(formData.date);
      startTime.minutes(moment(formData.startTime).minutes());
      startTime.hours(moment(formData.startTime).hours());

      const timeDiff = moment(formData.endTime).diff(moment(formData.startTime));

      const endTime = moment(startTime).add(timeDiff, 'milliseconds');

      formData.startTime = startTime.format();
      formData.endTime = endTime.format();
    }

    delete formData.date;

    formData.activities = formData.activities.map(activity => (activity.id));

    formData.id = this.props.action.id;

    try {
      await this.props.editActionMutation({
        variables: {
          data: formData,
        },
        // TODO: decide between refetch and update
        refetchQueries: ['ActionQuery', 'SearchActionsQuery'],
      });

      return { success: true, message: 'Changes Saved' };
    } catch (e) {
      console.error(e);
      return { success: false, message: e.message };
    }
  }

  render() {
    if (this.props.action && this.props.campaign) {
      const { formSubmit, defaultErrorText } = this;
      const { action, campaign } = this.props;
      const { formData } = this.state;

      const baseActionUrl = `/organize/${campaign.slug}/opportunity/${action.slug}`;

      const validators = [
        (component) => { validateString(component, 'title', 'titleErrorText', 'Opportunity Name is Required'); },
        (component) => { validateString(component, 'internalTitle', 'internalTitleErrorText', 'Internal Name is Required'); },
        (component) => { component.state.formData.virtual || validateState(component); },
        (component) => { component.state.formData.virtual || validateZipcode(component); },
        (component) => { component.state.formData.ongoing || validateStartEndTimes(component); },
      ];

      return (

          <Link to={`${baseActionUrl}`}>

              <FontIcon
                className={['material-icons', s.backArrow].join(' ')}
              >arrow_back</FontIcon>
              {action.title}

          </Link>

Settings

          <WrappedActionSettingsForm
            initialState={formData}
            initialErrors={defaultErrorText}
            validators={validators}
            submit={formSubmit}
            campaignTitle={campaign.title}
            submitText="Save Changes"
          />

      );
    }
    return null;
  }
}

const withActionQuery = graphql(ActionQuery, {
  options: ownProps => ({
    variables: {
      search: {
        id: ownProps.actionId,
      },
    },
    fetchPolicy: 'cache-and-network',
  }),
  props: ({ data }) => ({
    action: data.action,
  }),
});

const withCampaignQuery = graphql(CampaignQuery, {
  options: ownProps => ({
    variables: {
      search: {
        id: ownProps.campaignId,
      },
    },
  }),
  props: ({ data }) => ({
    campaign: data.campaign,
    graphqlLoading: data.loading,
  }),
});

export default compose(
  connect(),
  withActionQuery,
  withCampaignQuery,
  graphql(EditActionMutation, { name: 'editActionMutation' }),
)(ManageActionSettings);
<commit_msg>Fixing *very* strange bug where backtick/string template with only one variable seems to have broken react parsing.<commit_after>import React, { Component, PropTypes } from 'react';
import { compose, graphql } from 'react-apollo';
import { connect } from 'react-redux';
import moment from 'moment';
import FontIcon from 'material-ui/FontIcon';
import camelCase from 'camelcase';

import ActionSettingsForm from 'components/ActionSettingsForm';
import Link from 'components/Link';

import formWrapper from 'lib/formWrapper';

import {
  validateString,
  validateState,
  validateZipcode,
  validateStartEndTimes,
} from 'lib/validateComponentForms';

import CampaignQuery from 'schemas/queries/CampaignQuery.graphql';
import ActionQuery from 'schemas/queries/ActionQuery.graphql';

import EditActionMutation from 'schemas/mutations/EditActionMutation.graphql';

import s from 'styles/Organize.scss';

const WrappedActionSettingsForm = formWrapper(ActionSettingsForm);

class ManageActionSettings extends Component {
  static propTypes = {
    campaign: PropTypes.object,
    action: PropTypes.object,
    graphqlLoading: PropTypes.bool.isRequired,
    editActionMutation: PropTypes.func.isRequired,
    // eslint-disable-next-line react/no-unused-prop-types
    campaignId: PropTypes.string.isRequired,
    // eslint-disable-next-line react/no-unused-prop-types
    actionId: PropTypes.string.isRequired,
  }

  static defaultProps = {
    action: undefined,
    campaign: undefined,
  }

  constructor(props) {
    super(props);

    const initialState = {
      formData: {
        title: '',
        internalTitle: '',
        virtual: false,
        locationName: '',
        streetAddress: '',
        streetAddress2: '',
        city: '',
        state: '',
        zipcode: '',
        locationNotes: '',
        ongoing: false,
        date: undefined,
        startTime: undefined,
        endTime: undefined,
        activities: [],
        tags: [],
      },
    };

    this.state = Object.assign({}, initialState);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.action && !nextProps.graphqlLoading) {
      // Just camel-casing property keys and checking for null
      const action = Object.assign(...Object.keys(nextProps.action).map((k) => {
        if (nextProps.action[k] !== null) {
          return { [camelCase(k)]: nextProps.action[k] };
        }
        return undefined;
      }));

      // Handle date/time
      const newDateTimes = {
        date: action.startTime && moment(action.startTime).isValid() ? moment(action.startTime).toDate() : undefined,
        startTime: action.startTime && moment(action.startTime).isValid() ? moment(action.startTime).toDate() : undefined,
        endTime: action.endTime && moment(action.endTime).isValid() ? moment(action.endTime).toDate() : undefined,
      };

      delete action.startTime;
      delete action.endTime;

      this.setState(prevState => ({
        formData: Object.assign({}, prevState.formData, newDateTimes),
      }));

      Object.keys(action).forEach((k) => {
        if (!Object.keys(this.state.formData).includes(camelCase(k))) {
          delete action[k];
        }
      });

      this.setState(prevState => ({
        formData: Object.assign({}, prevState.formData, action),
      }));
    }
  }

  defaultErrorText = {
    titleErrorText: null,
    streetAddressErrorText: null,
    locationNameErrorText: null,
    locationNotesErrorText: null,
    websiteUrlErrorText: null,
    phoneNumberErrorText: null,
    cityErrorText: null,
    stateErrorText: null,
    zipcodeErrorText: null,
    dateErrorText: null,
    startTimeErrorText: null,
    endTimeErrorText: null,
  }

  formSubmit = async (data) => {
    // A little hackish to avoid an annoying rerender with previous form data
    // If I could figure out how to avoid keeping state here
    // w/ the componentWillReceiveProps/apollo/graphql then
    // I might not need this
    this.setState({
      formData: Object.assign({}, data),
    });

    const formData = Object.assign({}, data);

    if (formData.ongoing) {
      formData.startTime = null;
      formData.endTime = null;
    } else {
      const startTime = moment(formData.date);
      startTime.minutes(moment(formData.startTime).minutes());
      startTime.hours(moment(formData.startTime).hours());

      const timeDiff = moment(formData.endTime).diff(moment(formData.startTime));

      const endTime = moment(startTime).add(timeDiff, 'milliseconds');

      formData.startTime = startTime.format();
      formData.endTime = endTime.format();
    }

    delete formData.date;

    formData.activities = formData.activities.map(activity => (activity.id));

    formData.id = this.props.action.id;

    try {
      await this.props.editActionMutation({
        variables: {
          data: formData,
        },
        // TODO: decide between refetch and update
        refetchQueries: ['ActionQuery', 'SearchActionsQuery'],
      });

      return { success: true, message: 'Changes Saved' };
    } catch (e) {
      console.error(e);
      return { success: false, message: e.message };
    }
  }

  render() {
    if (this.props.action && this.props.campaign) {
      const { formSubmit, defaultErrorText } = this;
      const { action, campaign } = this.props;
      const { formData } = this.state;

      const baseActionUrl = `/organize/${campaign.slug}/opportunity/${action.slug}`;

      const validators = [
        (component) => { validateString(component, 'title', 'titleErrorText', 'Opportunity Name is Required'); },
        (component) => { validateString(component, 'internalTitle', 'internalTitleErrorText', 'Internal Name is Required'); },
        (component) => { component.state.formData.virtual || validateState(component); },
        (component) => { component.state.formData.virtual || validateZipcode(component); },
        (component) => { component.state.formData.ongoing || validateStartEndTimes(component); },
      ];

      return (

          <Link to={baseActionUrl}>

              <FontIcon
                className={['material-icons', s.backArrow].join(' ')}
              >arrow_back</FontIcon>
              {action.title}

          </Link>

Settings

          <WrappedActionSettingsForm
            initialState={formData}
            initialErrors={defaultErrorText}
            validators={validators}
            submit={formSubmit}
            campaignTitle={campaign.title}
            submitText="Save Changes"
          />

      );
    }
    return null;
  }
}

const withActionQuery = graphql(ActionQuery, {
  options: ownProps => ({
    variables: {
      search: {
        id: ownProps.actionId,
      },
    },
    fetchPolicy: 'cache-and-network',
  }),
  props: ({ data }) => ({
    action: data.action,
  }),
});

const withCampaignQuery = graphql(CampaignQuery, {
  options: ownProps => ({
    variables: {
      search: {
        id: ownProps.campaignId,
      },
    },
  }),
  props: ({ data }) => ({
    campaign: data.campaign,
    graphqlLoading: data.loading,
  }),
});

export default compose(
  connect(),
  withActionQuery,
  withCampaignQuery,
  graphql(EditActionMutation, { name: 'editActionMutation' }),
)(ManageActionSettings);
<|endoftext|>


<commit_before>
'use strict'

// Require

const fs = require( 'fs' )
const path = require( 'path' )
const { isExternal, isFile } = require( './is' )

/**
 * Append styles and scripts and symbol to HTML code.
 *
 * @param {String} code
 * @param {Object} page
 * @param {Object} task
 *
 * @return {String}
 */

module.exports = function ( code, page, task ) {

	const { paths, config, store, isDev, mainBundle } = task

	const withGap = /(\s+)?(<!--(\s+)?GAP:([\w]+)(\s+)?-->)/gi
	const comment = /(\s+)?(<!--(\s+)?BEMGO:([\w]+)(\s+)?-->)/gi
	const pattern = /@(async|defer)/gi
	const newLine = /(?:\r\n|\r|\n)/g
	const version = !isDev && config.build.addVersions ? `?v=${Date.now()}` : ''
	const favicons = []
	const arrays = {
		scripts: [],
		styles: [],
	}

	if ( isDev ) {

		page.styles.unshift( `${mainBundle}.css` )
		page.scripts.push( `${mainBundle}.js` )

	} else {

		const bundles = config.build.bundles
		const style = ( bundles.includes( 'css' ) ? page.name : mainBundle ) + '.min.css'
		const script = ( bundles.includes( 'js' ) ? page.name : mainBundle ) + '.min.js'

		if ( isFile( path.join( paths._styles, style ) ) ) page.styles.unshift( style )
		if ( isFile( path.join( paths._scripts, script ) ) ) page.scripts.push( script )

	}

	// Prepare scripts

	page.scripts.forEach( src => {

		let script = '<script src="[src]"[attr]></script>'
		let attrs = ''

		if ( /@async/gi.test( src ) ) attrs += ' async'
		if ( /@defer/gi.test( src ) ) attrs += ' defer'

		if ( !isExternal( src ) ) src = `${config.build.HTMLRoot}${config.dist.scripts}/${src}`

		script = script.replace( '[src]', src.replace( pattern, '' ) + ( isExternal( src ) ? '' : version ) ).replace( '[attr]', attrs )

		if ( arrays.scripts.indexOf( script ) === -1 ) arrays.scripts.push( script )
	})

	// Prepare styles

	page.styles.forEach( href => {

		let style = '<link rel="stylesheet" href="[href]">'

		if ( !isExternal( href ) ) href = `${config.build.HTMLRoot}${config.dist.styles}/${href}`

		style = style.replace( '[href]', href.replace( pattern, '' ) + ( isExternal( href ) ? '' : version ) )

		if ( arrays.styles.indexOf( style ) === -1 ) arrays.styles.push( style )
	})

	// Prepare favicons

	if ( !isDev ) {

		const head = {
			favicon: 'favicon.ico',
			favicon16: 'favicon-16x16.png',
			favicon32: 'favicon-32x32.png',
			manifest: 'manifest.json',
			browserconfig: 'browserconfig.xml',
			apple: 'apple-touch-icon.png',
			pinned: 'safari-pinned-tab.svg',
		}

		if ( isFile( path.join( paths._favicons, head.browserconfig ) ) )
			favicons.push( `<meta name="msapplication-config" content="${config.build.HTMLRoot}${config.dist.favicons}/${head.browserconfig}">` )

		if ( isFile( path.join( paths._favicons, head.favicon ) ) )
			favicons.push( `<link rel="shortcut icon" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.favicon}" type="image/x-icon">` )

		if ( isFile( path.join( paths._favicons, head.favicon16 ) ) )
			favicons.push( `<link rel="icon" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.favicon16}" sizes="16x16" type="image/png">` )

		if ( isFile( path.join( paths._favicons, head.favicon32 ) ) )
			favicons.push( `<link rel="icon" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.favicon32}" sizes="32x32" type="image/png">` )

		if ( isFile( path.join( paths._favicons, head.apple ) ) )
			favicons.push( `<link rel="apple-touch-icon" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.apple}" sizes="180x180">` )

		if ( isFile( path.join( paths._favicons, head.pinned ) ) )
			favicons.push( `<link rel="mask-icon" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.pinned}" color="${config.app && config.app.safariPinnedTab || '#424b5f'}">` )

		if ( isFile( path.join( paths._favicons, head.manifest ) ) )
			favicons.push( `<link rel="manifest" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.manifest}">` )

	}

	// Inject

	let injected = code

	injected = injected.replace( comment, ( str, indent, com, space, name ) => {

		indent = '\n' + indent.replace( newLine, '' )
		name = name.trim().toLowerCase()

		let instead = ''

		if ( arrays[name] && arrays[name].length > 0 ) {
			instead = indent + arrays[name].join( indent )
		}

		if ( name === 'symbol' ) {
			instead = indent + ( store.svg || com )
		}

		if ( name === 'favicons' ) {
			instead = indent + favicons.join( indent )
		}

		return instead

	})

	// Add gap

	injected = injected.replace( withGap, ( str, indent, com, space, name ) => {

		indent = '\n\n\n' + indent.replace( newLine, '' )

		return indent + `<!-- ${name.trim()} -->`

	})

	// Replace paths

	injected = injected.replace( /(,|'|"|`| )@([\w-]+)/gi, ( str, quote, block ) => {

		const paths = {
			styles: config.dist.styles,
			symbol: path.join( config.dist.symbol, 'symbol.svg' ),
			scripts: config.dist.scripts,
			static: config.dist.static,
			favicons: config.dist.favicons,
		}

		const dist = paths[block] || `${paths.static}/${block}`

		return `${quote}${config.build.HTMLRoot}${dist}`
	})

	return injected

}

<commit_msg>Fix err when no indent before comment<commit_after>
'use strict'

// Require

const fs = require( 'fs' )
const path = require( 'path' )
const { isExternal, isFile } = require( './is' )

/**
 * Append styles and scripts and symbol to HTML code.
 *
 * @param {String} code
 * @param {Object} page
 * @param {Object} task
 *
 * @return {String}
 */

module.exports = function ( code, page, task ) {

	const { paths, config, store, isDev, mainBundle } = task

	const withGap = /(\s+)?(<!--(\s+)?GAP:([\w]+)(\s+)?-->)/gi
	const comment = /(\s+)?(<!--(\s+)?BEMGO:([\w]+)(\s+)?-->)/gi
	const pattern = /@(async|defer)/gi
	const newLine = /(?:\r\n|\r|\n)/g
	const version = !isDev && config.build.addVersions ? `?v=${Date.now()}` : ''
	const favicons = []
	const arrays = {
		scripts: [],
		styles: [],
	}

	if ( isDev ) {

		page.styles.unshift( `${mainBundle}.css` )
		page.scripts.push( `${mainBundle}.js` )

	} else {

		const bundles = config.build.bundles
		const style = ( bundles.includes( 'css' ) ? page.name : mainBundle ) + '.min.css'
		const script = ( bundles.includes( 'js' ) ? page.name : mainBundle ) + '.min.js'

		if ( isFile( path.join( paths._styles, style ) ) ) page.styles.unshift( style )
		if ( isFile( path.join( paths._scripts, script ) ) ) page.scripts.push( script )

	}

	// Prepare scripts

	page.scripts.forEach( src => {

		let script = '<script src="[src]"[attr]></script>'
		let attrs = ''

		if ( /@async/gi.test( src ) ) attrs += ' async'
		if ( /@defer/gi.test( src ) ) attrs += ' defer'

		if ( !isExternal( src ) ) src = `${config.build.HTMLRoot}${config.dist.scripts}/${src}`

		script = script.replace( '[src]', src.replace( pattern, '' ) + ( isExternal( src ) ? '' : version ) ).replace( '[attr]', attrs )

		if ( arrays.scripts.indexOf( script ) === -1 ) arrays.scripts.push( script )
	})

	// Prepare styles

	page.styles.forEach( href => {

		let style = '<link rel="stylesheet" href="[href]">'

		if ( !isExternal( href ) ) href = `${config.build.HTMLRoot}${config.dist.styles}/${href}`

		style = style.replace( '[href]', href.replace( pattern, '' ) + ( isExternal( href ) ? '' : version ) )

		if ( arrays.styles.indexOf( style ) === -1 ) arrays.styles.push( style )
	})

	// Prepare favicons

	if ( !isDev ) {

		const head = {
			favicon: 'favicon.ico',
			favicon16: 'favicon-16x16.png',
			favicon32: 'favicon-32x32.png',
			manifest: 'manifest.json',
			browserconfig: 'browserconfig.xml',
			apple: 'apple-touch-icon.png',
			pinned: 'safari-pinned-tab.svg',
		}

		if ( isFile( path.join( paths._favicons, head.browserconfig ) ) )
			favicons.push( `<meta name="msapplication-config" content="${config.build.HTMLRoot}${config.dist.favicons}/${head.browserconfig}">` )

		if ( isFile( path.join( paths._favicons, head.favicon ) ) )
			favicons.push( `<link rel="shortcut icon" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.favicon}" type="image/x-icon">` )

		if ( isFile( path.join( paths._favicons, head.favicon16 ) ) )
			favicons.push( `<link rel="icon" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.favicon16}" sizes="16x16" type="image/png">` )

		if ( isFile( path.join( paths._favicons, head.favicon32 ) ) )
			favicons.push( `<link rel="icon" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.favicon32}" sizes="32x32" type="image/png">` )

		if ( isFile( path.join( paths._favicons, head.apple ) ) )
			favicons.push( `<link rel="apple-touch-icon" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.apple}" sizes="180x180">` )

		if ( isFile( path.join( paths._favicons, head.pinned ) ) )
			favicons.push( `<link rel="mask-icon" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.pinned}" color="${config.app && config.app.safariPinnedTab || '#424b5f'}">` )

		if ( isFile( path.join( paths._favicons, head.manifest ) ) )
			favicons.push( `<link rel="manifest" href="${config.build.HTMLRoot}${config.dist.favicons}/${head.manifest}">` )

	}

	// Inject

	let injected = code

	injected = injected.replace( comment, ( str, indent, com, space, name ) => {

		if ( !indent ) indent = ''

		indent = '\n' + indent.replace( newLine, '' )
		name = name.trim().toLowerCase()

		let instead = ''

		if ( arrays[name] && arrays[name].length > 0 ) {
			instead = indent + arrays[name].join( indent )
		}

		if ( name === 'symbol' ) {
			instead = indent + ( store.svg || com )
		}

		if ( name === 'favicons' ) {
			instead = indent + favicons.join( indent )
		}

		return instead

	})

	// Add gap

	injected = injected.replace( withGap, ( str, indent, com, space, name ) => {

		if ( !indent ) indent = ''

		indent = '\n\n\n' + indent.replace( newLine, '' )

		return indent + `<!-- ${name.trim()} -->`

	})

	// Replace paths

	injected = injected.replace( /(,|'|"|`| )@([\w-]+)/gi, ( str, quote, block ) => {

		const paths = {
			styles: config.dist.styles,
			symbol: path.join( config.dist.symbol, 'symbol.svg' ),
			scripts: config.dist.scripts,
			static: config.dist.static,
			favicons: config.dist.favicons,
		}

		const dist = paths[block] || `${paths.static}/${block}`

		return `${quote}${config.build.HTMLRoot}${dist}`
	})

	return injected

}

<|endoftext|>


<commit_before>#!/usr/bin/env node

var assert = require('assert');
var pagination = require('pagination');
var SearchPaginator = pagination.SearchPaginator;

var objectList = [
  { name: 'Taro', age: 11 },
  { name: 'Jiro', age: 12 },
  { name: 'Saburo', age: 13 },
  { name: 'Shiro', age: 14 },
  { name: 'Goro', age: 15 },
];

var paginator, paginated;

paginator = new SearchPaginator({
  totalResult: objectList.length,
  rowsPerPage: 2,
  current: 1,
});
paginated = paginator.getPaginationData();

console.log(paginated);
assert.strictEqual(paginated.pageCount, 3);
assert.strictEqual(paginated.fromResult, 1);
assert.strictEqual(paginated.toResult, 2);
assert.strictEqual(paginated.previous, null);
assert.strictEqual(paginated.next, 2);
assert.strictEqual(paginated.first, null);
assert.strictEqual(paginated.last, 3);
<commit_msg>Update a sample of pagination<commit_after>#!/usr/bin/env node

var assert = require('assert');
var pagination = require('pagination');
var SearchPaginator = pagination.SearchPaginator;

var objectList = [
  { name: 'Taro', age: 11 },
  { name: 'Jiro', age: 12 },
  { name: 'Saburo', age: 13 },
  { name: 'Shiro', age: 14 },
  { name: 'Goro', age: 15 },
];

var paginator, paginated;

//
// basic usage
//
paginator = new SearchPaginator({
  totalResult: objectList.length,
  rowsPerPage: 2,
  current: 1,
});
paginated = paginator.getPaginationData();

//console.log(paginated);
assert.strictEqual(paginated.pageCount, 3);
assert.strictEqual(paginated.fromResult, 1);
assert.strictEqual(paginated.toResult, 2);
assert.strictEqual(paginated.previous, null);
assert.strictEqual(paginated.next, 2);
assert.strictEqual(paginated.first, null);
assert.strictEqual(paginated.last, 3);

//
// set current page number to out of range
//
paginator = new SearchPaginator({
  totalResult: objectList.length,
  rowsPerPage: 2,
  current: 100,
});
paginated = paginator.getPaginationData();
assert.strictEqual(paginated.current, 3);  // Not overflow

paginator = new SearchPaginator({
  totalResult: objectList.length,
  rowsPerPage: 2,
  current: -100,
});
paginated = paginator.getPaginationData();
assert.strictEqual(paginated.current, -100);  // Overflow!
<|endoftext|>


<commit_before>//require can.jquery-all

(function(can) {

can.Model.Cacheable("CMS.Models.Program", {
  root_object : "program"
  , root_collection : "programs"
  , findAll : "/api/programs?company_controls_first=true"
  , findOne : "/api/programs/{id}"
  , create : "POST /api/programs"
  , init : function() {
    this.validatePresenceOf("title");
    this._super.apply(this, arguments);
  }
}, {});

can.Model.Cacheable("CMS.Models.Directive", {
  root_object : "directive"
  , root_collection : "directives"
  , findAll : "/api/directives"
  , findOne : "/api/directives/{id}"
  , create : "POST /api/directives"
}, {
  init : function() {
    this._super && this._super.apply(this, arguments);
    var that = this;
    this.attr("descendant_sections", can.compute(function() {
      return that.attr("sections").concat(can.reduce(that.sections, function(a, b) {
        return a.concat(can.makeArray(b.descendant_sections()));
      }, []));
    }));
    this.attr("descendant_sections_count", can.compute(function() {
      return that.attr("descendant_sections")().length;
    }));
  }
  , lowercase_kind : function() { return this.kind.toLowerCase(); }

});

CMS.Models.Directive("CMS.Models.Regulation", {
  findAll : "/api/directives?meta_kind=regulation"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "regulation"
    }
  }
}, {});

CMS.Models.Directive("CMS.Models.Policy", {
  findAll : "/api/directives?meta_kind=policy"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "policy"
    }
  }
}, {});

CMS.Models.Directive("CMS.Models.Contract", {
  findAll : "/api/directives?meta_kind=contract"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "contract"
    }
  }
}, {});

can.Model.Cacheable("CMS.Models.OrgGroup", {
  root_object : "org_group"
  , root_collection : "org_groups"
  , findAll : "/api/org_groups"
}, {});

can.Model.Cacheable("CMS.Models.Project", {
  root_object : "project"
  , root_collection : "projects"
  , findAll : "/api/projects"
}, {});

can.Model.Cacheable("CMS.Models.Facility", {
  root_object : "facility"
  , root_collection : "facilities"
  , findAll : "/api/facilities"
}, {});

can.Model.Cacheable("CMS.Models.Product", {
  root_object : "product"
  , root_collection : "products"
  , findAll : "/api/products"
}, {});

can.Model.Cacheable("CMS.Models.DataAsset", {
  root_object : "data_asset"
  , root_collection : "data_assets"
  , findAll : "/api/data_assets"
}, {});

can.Model.Cacheable("CMS.Models.Market", {
  root_object : "market"
  , root_collection : "markets"
  , findAll : "/api/markets"
}, {});

can.Model.Cacheable("CMS.Models.RiskyAttribute", {
  root_object : "risky_attribute"
  , root_collection : "risky_attributes"
  , findAll : "/api/risky_attributes"
}, {});

can.Model.Cacheable("CMS.Models.Risk", {
  root_object : "risk"
  , root_collection : "risks"
  , findAll : function(params) {
    var root_object =  this.root_object
    , root_collection = this.root_collection;
    return $.ajax({
      url : "/api/risks"
      , type : "get"
      , data : params
      , dataType : "json"
    }).then(function(risks) {
      if(risks[root_collection + "_collection"]) {
        risks = risks[root_collection + "_collection"];
      }
      if(risks[root_collection]) {
        risks = risks[root_collection];
      }

      can.each(risks, function(r) {
        if(r[root_object]) {
          r = r[root_object];
        }
        if(r.hasOwnProperty("trigger")) {
          r.risk_trigger = r.trigger;
          delete r.trigger;
        }
      });
      return risks;
    });
  }
}, {});

can.Model.Cacheable("CMS.Models.Help", {
  root_object : "help"
  , findAll : "GET /api/help"
  , findOne : "GET /api/help/{id}"
  , update : "PUT /api/help/{id}"
}, {});

})(this.can);<commit_msg>Adding rest of simple models' create methods<commit_after>//require can.jquery-all

(function(can) {

can.Model.Cacheable("CMS.Models.Program", {
  root_object : "program"
  , root_collection : "programs"
  , findAll : "/api/programs?company_controls_first=true"
  , findOne : "/api/programs/{id}"
  , create : "POST /api/programs"
  , init : function() {
    this.validatePresenceOf("title");
    this._super.apply(this, arguments);
  }
}, {});

can.Model.Cacheable("CMS.Models.Directive", {
  root_object : "directive"
  , root_collection : "directives"
  , findAll : "/api/directives"
  , findOne : "/api/directives/{id}"
  , create : "POST /api/directives"
}, {
  init : function() {
    this._super && this._super.apply(this, arguments);
    var that = this;
    this.attr("descendant_sections", can.compute(function() {
      return that.attr("sections").concat(can.reduce(that.sections, function(a, b) {
        return a.concat(can.makeArray(b.descendant_sections()));
      }, []));
    }));
    this.attr("descendant_sections_count", can.compute(function() {
      return that.attr("descendant_sections")().length;
    }));
  }
  , lowercase_kind : function() { return this.kind.toLowerCase(); }

});

CMS.Models.Directive("CMS.Models.Regulation", {
  findAll : "/api/directives?meta_kind=regulation"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "regulation"
    }
  }
}, {});

CMS.Models.Directive("CMS.Models.Policy", {
  findAll : "/api/directives?meta_kind=policy"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "policy"
    }
  }
}, {});

CMS.Models.Directive("CMS.Models.Contract", {
  findAll : "/api/directives?meta_kind=contract"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "contract"
    }
  }
}, {});

can.Model.Cacheable("CMS.Models.OrgGroup", {
  root_object : "org_group"
  , root_collection : "org_groups"
  , findAll : "/api/org_groups"
  , create : "POST /api/org_groups"
}, {});

can.Model.Cacheable("CMS.Models.Project", {
  root_object : "project"
  , root_collection : "projects"
  , findAll : "/api/projects"
  , create : "POST /api/projects"
}, {});

can.Model.Cacheable("CMS.Models.Facility", {
  root_object : "facility"
  , root_collection : "facilities"
  , findAll : "/api/facilities"
  , create : "POST /api/facilities"
}, {});

can.Model.Cacheable("CMS.Models.Product", {
  root_object : "product"
  , root_collection : "products"
  , findAll : "/api/products"
  , create : "POST /api/products"
}, {});

can.Model.Cacheable("CMS.Models.DataAsset", {
  root_object : "data_asset"
  , root_collection : "data_assets"
  , findAll : "/api/data_assets"
  , create : "POST /api/data_assets"
}, {});

can.Model.Cacheable("CMS.Models.Market", {
  root_object : "market"
  , root_collection : "markets"
  , findAll : "/api/markets"
  , create : "POST /api/markets"
}, {});

can.Model.Cacheable("CMS.Models.RiskyAttribute", {
  root_object : "risky_attribute"
  , root_collection : "risky_attributes"
  , findAll : "/api/risky_attributes"
  , create : "POST /api/risky_attributes"
}, {});

can.Model.Cacheable("CMS.Models.Risk", {
  root_object : "risk"
  , root_collection : "risks"
  , findAll : function(params) {
    var root_object =  this.root_object
    , root_collection = this.root_collection;
    return $.ajax({
      url : "/api/risks"
      , type : "get"
      , data : params
      , dataType : "json"
    }).then(function(risks) {
      if(risks[root_collection + "_collection"]) {
        risks = risks[root_collection + "_collection"];
      }
      if(risks[root_collection]) {
        risks = risks[root_collection];
      }

      can.each(risks, function(r) {
        if(r[root_object]) {
          r = r[root_object];
        }
        if(r.hasOwnProperty("trigger")) {
          r.risk_trigger = r.trigger;
          delete r.trigger;
        }
      });
      return risks;
    });
  }
  , create : function(params) {
    params[trigger] = params[risk_trigger];
    return $.ajax({
      type : "POST"
      , url : "/api/risks"
      , data : params
      , dataType : "json"
    });
  }
}, {});

can.Model.Cacheable("CMS.Models.Help", {
  root_object : "help"
  , findAll : "GET /api/help"
  , findOne : "GET /api/help/{id}"
  , update : "PUT /api/help/{id}"
}, {});

})(this.can);<|endoftext|>