<commit_before>import { computed } from '@ember/object';
import { isPresent, isBlank, isEmpty } from '@ember/utils';
import Component from '@ember/component';
import layout from '../templates/components/uni-autocomplete';
import KeyCodes from 'ember-cli-uniq/enums/key-codes-type';
import { A } from '@ember/array';
import { capitalize } from '@ember/string';

export default Component.extend({
  classNames: ['uni-autocomplete'],
  layout,
  noResultsComponent: 'uni-autocomplete-no-results',
  options: [],
  value: '',
  showOptions: false,
  hasError: false,
  highlighted: 0,
  maxOptionsToShow: 4,
  autocomplete: 'off',
  noResultsText: 'No results for ',
  placeholderText: '',

  // @deprecated for placeholderText
  placeholder: null,

  onSelected() {},

  // @Required The function must return an array of strings
  searchTextValues: null,

  valueLowerCase: computed('value', function() {
    return this.get('value').toLowerCase();
  }),

  optionsFiltered: computed('value', 'options', {
    get() {
      if (isBlank(this.get('value'))) {
        return [];
      }

      const options = this.options.map((option) => {
        const matchedValues = this.filterFunction(this.searchTextValues, option);
        const { firstObject: text } = matchedValues;
        const { value: currentValue } = option;

        if (isPresent(text) && isPresent(currentValue)) {
            const currentInput = new RegExp(`(${this.value})`, 'gi');
            const matchedOptionText = currentValue.replace(currentInput, '$1');

            return { option, matchedValues, matchedOptionText };
        }

        return { option, matchedValues };
      });

      return A(options.filter(({ matchedValues }) => isPresent(matchedValues)).slice(0, this.get('maxOptionsToShow')));
    },

    set(_, value) {
      return value;
    }
  }),

  autocompleteOption: computed('optionsFiltered', 'highlighted', function() {
    let options = this.get('optionsFiltered');

    return isEmpty(options) ? null : options.objectAt(this.get('highlighted'));
  }),

  onFocusOut() {},

  actions: {
    onSelected(option) {
      this.selectOption(option);
    },

    keyPress(ev) {
      this._handleKeyPress(ev);
    },

    setHighlighted(index) {
      this.set('highlighted', index);
    },

    showOptions() {
      this.set('highlighted', 0);
      this.set('showOptions', true);
    },

    selectHighlightedOption() {
      let highlightedOption = this.get('autocompleteOption');
      if (isPresent(highlightedOption)) {
        this.selectOption(highlightedOption);
      }
    },

    onFocusOut() {
      this.get('onFocusOut')();
    }
  },

  selectOption(option) {
    this.set('value', capitalize(option.matchedValues.get('firstObject')));

    this.get('onSelected')(option);
    this.set('showOptions', false);
  },

  filterFunction(getSearchTextValues, option) {
    const options = getSearchTextValues(option).map((x) => x.toLowerCase());
    const matchedValues = A(options.filter((el) => el.includes(this.get('valueLowerCase'))));

    return matchedValues;
  },

  _handleKeyPress(ev) {
    let { keyCode } = ev;

    if (keyCode === KeyCodes.UP_ARROW || keyCode === KeyCodes.DOWN_ARROW) {
      ev.preventDefault();

      return this._handleKeyUpDown(keyCode === KeyCodes.DOWN_ARROW ? 1 : -1);
    }

    if (keyCode === KeyCodes.ENTER) {
      return this._handleKeyEnter();
    }

    if (keyCode === KeyCodes.ESCAPE) {
      return this._handleKeyESC();
    }

    this.set('highlighted', 0);
    this.get('onSelected')();
  },

  _handleKeyUpDown(increment) {
    let maxOptions = this.get('maxOptionsToShow');
    let highlightedOption = this.get('highlighted') + increment;

    // Allows to do a circular mod with positive and negative values: ((f % n) + n) % n.
    this.set('highlighted', ((highlightedOption % maxOptions) + maxOptions) % maxOptions);
  },

  _handleKeyEnter() {
    this.selectOption(this.get('optionsFiltered').objectAt(this.get('highlighted')));

    this.element.querySelector('input').blur();
  },

  _handleKeyESC() {
    this.set('showOptions', false);

    this.element.querySelector('input').blur();
  }
});
<commit_msg>Fix autocomplete first option bug on enter key event (#318)<commit_after>import { computed } from '@ember/object';
import { isPresent, isBlank, isEmpty } from '@ember/utils';
import Component from '@ember/component';
import layout from '../templates/components/uni-autocomplete';
import KeyCodes from 'ember-cli-uniq/enums/key-codes-type';
import { A } from '@ember/array';
import { capitalize } from '@ember/string';

export default Component.extend({
  classNames: ['uni-autocomplete'],
  layout,
  noResultsComponent: 'uni-autocomplete-no-results',
  options: [],
  value: '',
  showOptions: false,
  hasError: false,
  highlighted: 0,
  maxOptionsToShow: 4,
  autocomplete: 'off',
  noResultsText: 'No results for ',
  placeholderText: '',

  // @deprecated for placeholderText
  placeholder: null,

  onSelected() {},

  // @Required The function must return an array of strings
  searchTextValues: null,

  valueLowerCase: computed('value', function() {
    return this.get('value').toLowerCase();
  }),

  optionsFiltered: computed('value', 'options', {
    get() {
      if (isBlank(this.get('value'))) {
        return [];
      }

      const options = this.options.map((option) => {
        const matchedValues = this.filterFunction(this.searchTextValues, option);
        const { firstObject: text } = matchedValues;
        const { value: currentValue } = option;

        if (isPresent(text) && isPresent(currentValue)) {
            const currentInput = new RegExp(`(${this.value})`, 'gi');
            const matchedOptionText = currentValue.replace(currentInput, '$1');

            return { option, matchedValues, matchedOptionText };
        }

        return { option, matchedValues };
      });

      return A(options.filter(({ matchedValues }) => isPresent(matchedValues)).slice(0, this.get('maxOptionsToShow')));
    },

    set(_, value) {
      return value;
    }
  }),

  autocompleteOption: computed('optionsFiltered', 'highlighted', function() {
    let options = this.get('optionsFiltered');

    return isEmpty(options) ? null : options.objectAt(this.get('highlighted'));
  }),

  onFocusOut() {},

  actions: {
    onSelected(option) {
      this.selectOption(option);
    },

    keyPress(ev) {
      this._handleKeyPress(ev);
    },

    setHighlighted(index) {
      this.set('highlighted', index);
    },

    showOptions() {
      this.set('highlighted', 0);
      this.set('showOptions', true);
    },

    selectHighlightedOption() {
      let highlightedOption = this.get('autocompleteOption');
      if (isPresent(highlightedOption)) {
        this.selectOption(highlightedOption);
      }
    },

    onFocusOut() {
      this.get('onFocusOut')();
    }
  },

  selectOption(option) {
    this.set('value', capitalize(option.matchedValues.get('firstObject')));

    this.get('onSelected')(option);
    this.set('showOptions', false);
  },

  filterFunction(getSearchTextValues, option) {
    const options = getSearchTextValues(option).map((x) => x.toLowerCase());
    const matchedValues = A(options.filter((el) => el.includes(this.get('valueLowerCase'))));

    return matchedValues;
  },

  _handleKeyPress(ev) {
    let { keyCode } = ev;

    if (keyCode === KeyCodes.UP_ARROW || keyCode === KeyCodes.DOWN_ARROW) {
      ev.preventDefault();

      return this._handleKeyUpDown(keyCode === KeyCodes.DOWN_ARROW ? 1 : -1);
    }

    if (keyCode === KeyCodes.ENTER) {
      return this._handleKeyEnter();
    }

    if (keyCode === KeyCodes.ESCAPE) {
      return this._handleKeyESC();
    }

    this.set('highlighted', 0);
    this.get('onSelected')();
  },

  _handleKeyUpDown(increment) {
    let maxOptions = this.get('maxOptionsToShow');
    let highlightedOption = this.get('highlighted') + increment;

    // Allows to do a circular mod with positive and negative values: ((f % n) + n) % n.
    this.set('highlighted', ((highlightedOption % maxOptions) + maxOptions) % maxOptions);
  },

  _handleKeyEnter() {
    this.element.querySelector('input').blur();
  },

  _handleKeyESC() {
    this.set('showOptions', false);

    this.element.querySelector('input').blur();
  }
});
<|endoftext|>


<commit_before>import DOM from 'ember-lifeline/mixins/dom';
import Mixin from 'ember-metal/mixin';
import run from 'ember-runloop';

export default Mixin.create(DOM, {

  minHeight: 50,

  minWidth: 50,

  width: null,

  height: null,

  didInsertElement() {
    this._super(...arguments);

    if (this.get('width') === null) {
      this.addEventListener(window, `resize.${ this.elementId }`, this.didResize);
      run.scheduleOnce('afterRender', this, this.measureDimensions);
    }
  },

  didResize() {
    run.throttle(this, this.measureDimensions, 16);
  },

  /**
   * Calculates dimensions of this container. This forces the browser to calculate
   * styles, which is slow, so don't do this too often or you'll create jank.
   *
   * @public
   */
  measureDimensions() {
    if (!this.element) {
      return;
    }

    run.scheduleOnce('afterRender', this, () => {
      let { minWidth, minHeight } = this.getProperties('minWidth', 'minHeight');

      let rect = this.element.getBoundingClientRect();
      this.setProperties({
        width: Math.max(rect.width, minWidth),
        height: Math.max(rect.height, minHeight)
      });
    });
  }

});
<commit_msg>Use native event handling<commit_after>import Mixin from 'ember-metal/mixin';
import run from 'ember-runloop';

export default Mixin.create({

  minHeight: 50,

  minWidth: 50,

  width: null,

  height: null,

  didInsertElement() {
    this._super(...arguments);

    if (this.get('width') === null) {
      window.addEventListener(`resize.${ this.elementId }`, this.didResize.bind(this));
      run.scheduleOnce('render', this, this.measureDimensions);
    }
  },

  willRemoveElement() {
    window.removeEventListener(`resize.${ this.elementId }`, this.didResize);
  },

  didResize() {
    run.throttle(this, this.measureDimensions, 16);
  },

  /**
   * Calculates dimensions of this container. This forces the browser to calculate
   * styles, which is slow, so don't do this too often or you'll create jank.
   *
   * @public
   */
  measureDimensions() {
    if (!this.element) {
      return;
    }

    run.scheduleOnce('afterRender', this, () => {
      let { minWidth, minHeight } = this.getProperties('minWidth', 'minHeight');

      let rect = this.element.getBoundingClientRect();
      this.setProperties({
        width: Math.max(rect.width, minWidth),
        height: Math.max(rect.height, minHeight)
      });
    });
  }

});
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import qs from 'qs';
import { document } from 'global';
import styled from '@emotion/styled';
import copy from 'copy-to-clipboard';

import { Placeholder, TabWrapper, TabsState, ActionBar, ActionButton } from '@storybook/components';

import Types from './types';
import PropForm from './PropForm';

const getTimestamp = () => +new Date();

const DEFAULT_GROUP_ID = 'ALL';

const PanelWrapper = styled.div({
  height: '100%',
  overflow: 'auto',
  width: '100%',
});

export default class Panel extends PureComponent {
  constructor(props) {
    super(props);
    this.state = { knobs: {} };
    this.options = {};

    this.lastEdit = getTimestamp();
    this.loadedFromUrl = false;
  }

  componentDidMount() {
    const { channel, api } = this.props;
    channel.on('addon:knobs:setKnobs', this.setKnobs);
    channel.on('addon:knobs:setOptions', this.setOptions);

    this.stopListeningOnStory = api.onStory(() => {
      this.setState({ knobs: {} });
      channel.emit('addon:knobs:reset');
    });
  }

  componentWillUnmount() {
    const { channel } = this.props;

    channel.removeListener('addon:knobs:setKnobs', this.setKnobs);
    this.stopListeningOnStory();
  }

  setOptions = (options = { timestamps: false }) => {
    this.options = options;
  };

  setKnobs = ({ knobs, timestamp }) => {
    const queryParams = {};
    const { api, channel } = this.props;

    if (!this.options.timestamps || !timestamp || this.lastEdit <= timestamp) {
      Object.keys(knobs).forEach(name => {
        const knob = knobs[name];
        // For the first time, get values from the URL and set them.
        if (!this.loadedFromUrl) {
          const urlValue = api.getQueryParam(`knob-${name}`);
          if (urlValue !== undefined) {
            // If the knob value present in url
            knob.value = Types[knob.type].deserialize(urlValue);
            channel.emit('addon:knobs:knobChange', knob);
          }
        }

        // set all knobsquery params to be deleted from URL
        queryParams[`knob-${name}`] = null;
      });

      api.setQueryParams(queryParams);
      this.setState({ knobs });

      this.loadedFromUrl = true;
    }
  };

  reset = () => {
    const { channel } = this.props;

    channel.emit('addon:knobs:reset');
  };

  copy = () => {
    const { location } = document;
    const query = qs.parse(location.search.replace('?', ''));
    const { knobs } = this.state;

    Object.entries(knobs).forEach(([name, knob]) => {
      query[`knob-${name}`] = Types[knob.type].serialize(knob.value);
    });

    copy(`${location.origin + location.pathname}?${qs.stringify(query)}`);

    // TODO: show some notification of this
  };

  emitChange = changedKnob => {
    const { channel } = this.props;

    channel.emit('addon:knobs:knobChange', changedKnob);
  };

  handleChange = changedKnob => {
    this.lastEdit = getTimestamp();
    const { knobs } = this.state;
    const { name } = changedKnob;
    const newKnobs = { ...knobs };
    newKnobs[name] = {
      ...newKnobs[name],
      ...changedKnob,
    };

    this.setState({ knobs: newKnobs }, this.emitChange(changedKnob));
  };

  handleClick = knob => {
    const { channel } = this.props;

    channel.emit('addon:knobs:knobClick', knob);
  };

  render() {
    const { knobs } = this.state;
    const { active } = this.props;

    if (!active) {
      return null;
    }

    const groups = {};
    const groupIds = [];

    let knobsArray = Object.keys(knobs).filter(key => knobs[key].used);

    knobsArray
      .filter(key => knobs[key].groupId)
      .forEach(key => {
        const knobKeyGroupId = knobs[key].groupId;
        groupIds.push(knobKeyGroupId);
        groups[knobKeyGroupId] = {
          render: ({ active: groupActive, selected }) => (
            <TabWrapper active={groupActive || selected === DEFAULT_GROUP_ID}>
              <PropForm
                knobs={knobsArray.filter(knob => knob.groupId === knobKeyGroupId)}
                onFieldChange={this.handleChange}
                onFieldClick={this.handleClick}
              />
            </TabWrapper>
          ),
          title: knobKeyGroupId,
        };
      });

    groups[DEFAULT_GROUP_ID] = {
      render: () => null,
      title: DEFAULT_GROUP_ID,
    };

    knobsArray = knobsArray.map(key => knobs[key]);

    if (knobsArray.length === 0) {
      return <Placeholder>NO KNOBS</Placeholder>;
    }

    return (
      <PanelWrapper>
        {groupIds.length > 0 ? (
          <TabsState>
            {Object.entries(groups).map(([k, v]) => (

                {v.render}

            ))}
          </TabsState>
        ) : (
          <PropForm
            knobs={knobsArray}
            onFieldChange={this.handleChange}
            onFieldClick={this.handleClick}
          />
        )}
        <ActionBar>
          <ActionButton onClick={this.copy}>COPY</ActionButton>
          <ActionButton onClick={this.reset}>RESET</ActionButton>
        </ActionBar>
      </PanelWrapper>
    );
  }
}

Panel.propTypes = {
  active: PropTypes.bool.isRequired,
  onReset: PropTypes.object, // eslint-disable-line
  channel: PropTypes.shape({
    emit: PropTypes.func,
    on: PropTypes.func,
    removeListener: PropTypes.func,
  }).isRequired,
  api: PropTypes.shape({
    onStory: PropTypes.func,
    getQueryParam: PropTypes.func,
    setQueryParams: PropTypes.func,
  }).isRequired,
};
<commit_msg>chore: Merged remote<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import qs from 'qs';
import { document } from 'global';
import styled from '@emotion/styled';
import copy from 'copy-to-clipboard';

import { Placeholder, TabWrapper, TabsState, ActionBar, ActionButton } from '@storybook/components';

import Types from './types';
import PropForm from './PropForm';

const getTimestamp = () => +new Date();

const DEFAULT_GROUP_ID = 'ALL';

const PanelWrapper = styled.div({
  height: '100%',
  overflow: 'auto',
  width: '100%',
});

export default class Panel extends PureComponent {
  constructor(props) {
    super(props);
    this.state = { knobs: {} };
    this.options = {};

    this.lastEdit = getTimestamp();
    this.loadedFromUrl = false;
  }

  componentDidMount() {
    const { channel, api } = this.props;
    channel.on('addon:knobs:setKnobs', this.setKnobs);
    channel.on('addon:knobs:setOptions', this.setOptions);

    this.stopListeningOnStory = api.onStory(() => {
      this.setState({ knobs: {} });
      channel.emit('addon:knobs:reset');
    });
  }

  componentWillUnmount() {
    const { channel } = this.props;

    channel.removeListener('addon:knobs:setKnobs', this.setKnobs);
    this.stopListeningOnStory();
  }

  setOptions = (options = { timestamps: false }) => {
    this.options = options;
  };

  setKnobs = ({ knobs, timestamp }) => {
    const queryParams = {};
    const { api, channel } = this.props;

    if (!this.options.timestamps || !timestamp || this.lastEdit <= timestamp) {
      Object.keys(knobs).forEach(name => {
        const knob = knobs[name];
        // For the first time, get values from the URL and set them.
        if (!this.loadedFromUrl) {
          const urlValue = api.getQueryParam(`knob-${name}`);
          if (urlValue !== undefined) {
            // If the knob value present in url
            knob.value = Types[knob.type].deserialize(urlValue);
            channel.emit('addon:knobs:knobChange', knob);
          }
        }

        // set all knobsquery params to be deleted from URL
        queryParams[`knob-${name}`] = null;
      });

      api.setQueryParams(queryParams);
      this.setState({ knobs });

      this.loadedFromUrl = true;
    }
  };

  reset = () => {
    const { channel } = this.props;

    channel.emit('addon:knobs:reset');
  };

  copy = () => {
    const { location } = document;
    const query = qs.parse(location.search.replace('?', ''));
    const { knobs } = this.state;

    Object.entries(knobs).forEach(([name, knob]) => {
      query[`knob-${name}`] = Types[knob.type].serialize(knob.value);
    });

    copy(`${location.origin + location.pathname}?${qs.stringify(query)}`);

    // TODO: show some notification of this
  };

  emitChange = changedKnob => {
    const { channel } = this.props;

    channel.emit('addon:knobs:knobChange', changedKnob);
  };

  handleChange = changedKnob => {
    this.lastEdit = getTimestamp();
    const { knobs } = this.state;
    const { name } = changedKnob;
    const newKnobs = { ...knobs };
    newKnobs[name] = {
      ...newKnobs[name],
      ...changedKnob,
    };

    this.setState({ knobs: newKnobs }, this.emitChange(changedKnob));
  };

  handleClick = knob => {
    const { channel } = this.props;

    channel.emit('addon:knobs:knobClick', knob);
  };

  render() {
    const { knobs } = this.state;
    const { active } = this.props;

    if (!active) {
      return null;
    }

    const groups = {};
    const groupIds = [];

    let knobsArray = Object.keys(knobs).filter(key => knobs[key].used);

    knobsArray
      .filter(key => knobs[key].groupId)
      .forEach(key => {
        const knobKeyGroupId = knobs[key].groupId;
        groupIds.push(knobKeyGroupId);
        groups[knobKeyGroupId] = {
          render: ({ active: groupActive, selected }) => (
            <TabWrapper active={groupActive || selected === DEFAULT_GROUP_ID}>
              <PropForm
                knobs={knobsArray.filter(knob => knob.groupId === knobKeyGroupId)}
                onFieldChange={this.handleChange}
                onFieldClick={this.handleClick}
              />
            </TabWrapper>
          ),
          title: knobKeyGroupId,
        };
      });

    groups[DEFAULT_GROUP_ID] = {
      render: () => null,
      title: DEFAULT_GROUP_ID,
    };

    knobsArray = knobsArray.map(key => knobs[key]);

    if (knobsArray.length === 0) {
      return <Placeholder>NO KNOBS</Placeholder>;
    }

    return (
      <PanelWrapper>
        {groupIds.length > 0 ? (
          <TabsState>
            {Object.entries(groups).map(([k, v]) => (

                {v.render}

            ))}
          </TabsState>
        ) : (
          <PropForm
            knobs={knobsArray}
            onFieldChange={this.handleChange}
            onFieldClick={this.handleClick}
          />
        )}
        <ActionBar>
          <ActionButton onClick={this.copy}>COPY</ActionButton>
          <ActionButton onClick={this.reset}>RESET</ActionButton>
        </ActionBar>
      </PanelWrapper>
    );
  }
}

Panel.propTypes = {
  active: PropTypes.bool.isRequired,
  onReset: PropTypes.object, // eslint-disable-line
  channel: PropTypes.shape({
    emit: PropTypes.func,
    on: PropTypes.func,
    removeListener: PropTypes.func,
  }).isRequired,
  api: PropTypes.shape({
    onStory: PropTypes.func,
    getQueryParam: PropTypes.func,
    setQueryParams: PropTypes.func,
  }).isRequired,
};
<|endoftext|>


<commit_before>require.config({
  paths: {
    underscore: '../../libs/underscore/underscore'
  },
  shim: {
    underscore: {
      exports: '_'
    }
  }
});
define(['underscore'], function (_) {
  /**
   *  this is the default uri object, you can customize
   *  it by passing a uri object to the getInstance method.
   */
  var uri = {};
  uri.defaultOptions = {
    scheme: 'http',
    host: 'isondev.net',
    parameterBase: '?'
  };
  uri.componentsOrder = ['scheme', 'username', 'password', 'host', 'port', 'path', 'parameterBase'];
  uri.schema = {
    __placeholder: '(^.^)',
    scheme: '(^.^)://',
    username: '(^.^)',
    password: ':(^.^)@',
    host: '(^.^)',
    port: ':(^.^)',
    path: '/(^.^)',
    parameterBase: '/(^.^)'
  };

  /**
   *  this is the default user options, you can customize
   *  this by passing a new object into make function
   */
  var defaultOptions = {
    rows: 20,
    start: 0,
    query: 'This is my query',
    dataType: 'json'
  };

  /**
   * The actual code for the query builder
   */
  var getInstance = function (uriOpts, schema) {
    var _this = this;
    this.schema = schema;
    this.uriOptions = {};

    this.queryString = '';
    this.options = {};
    this.templatePlaceholder = schema.__placeholder || '(^.^)';

    function makeUriComponents () {
      if ( typeof uriOpts === 'string') {
        return uriOpts;
      }
      var output = '';
      var uriOptions = extend({}, uri.defaultOptions, uriOpts);
      _.each(uri.componentsOrder, function (component) {
        if (uriOptions[component]) {
          output += uri.schema[component].
              replace(uri.schema.__placeholder, uriOptions[component]);
        }
      });
      return output;
    }

    function isValidTemplate(tmpl) {
      if ( _.isString(tmpl) && tmpl.search(_this.templatePlaceholder) ) {
        return true;
      } else if ( _.isObject(tmpl) && _.isObject(tmpl.types) ) {
        return true;
      }
      return false;
    }

    function makeSingleParameter(template, opt) {
      if ( _.isString(template) ) {
        return template.replace(_this.templatePlaceholder, opt);
      } else if ( _.isObject(template) ) {
        if (opt.value) {
          return template.types[opt.type].replace(_this.templatePlaceholder, opt.value);
        }
      }
      throw new Error('none standard template passed in.');
    }

    function makeParameters () {
      var output = [];
      var opts = extend({}, defaultOptions, _this.options );
      _.each(_this.options, function (opt, parameter) {
        if (opt) {
          var template = _this.schema[parameter];
          if (isValidTemplate(template)) {
            output.push(makeSingleParameter(template, opt));
          } else {
            throw new Error('none standard template found in your schema!');
          }
        }
      });
      return output.join('&');
    }

    function makeQuery (opt) {
      _this.options = extend({}, _this.options, opt);
      _this.queryString = '';
      _this.queryString += makeUriComponents();
      _this.queryString += makeParameters();
      return encodeURI(_this.queryString);
    }

    function resetOptions () {
      _this.options = {};
      return this;
    }

    function extend(){
      for(var i=1; i<arguments.length; i++)
      for(var key in arguments[i])
      if(arguments[i].hasOwnProperty(key))
        arguments[0][key] = arguments[i][key];
      return arguments[0];
    }

    return {
      make: makeQuery,
      reset: resetOptions
    };
  };

  return {getInstance: getInstance};
});
<commit_msg>all each statements implemented with pure js<commit_after>require.config({
  paths: {
    underscore: '../../libs/underscore/underscore'
  },
  shim: {
    underscore: {
      exports: '_'
    }
  }
});
define(['underscore'], function (_) {
  /**
   *  this is the default uri object, you can customize
   *  it by passing a uri object to the getInstance method.
   */
  var uri = {};
  uri.defaultOptions = {
    scheme: 'http',
    host: 'isondev.net',
    parameterBase: '?'
  };
  uri.componentsOrder = ['scheme', 'username', 'password', 'host', 'port', 'path', 'parameterBase'];
  uri.schema = {
    __placeholder: '(^.^)',
    scheme: '(^.^)://',
    username: '(^.^)',
    password: ':(^.^)@',
    host: '(^.^)',
    port: ':(^.^)',
    path: '/(^.^)',
    parameterBase: '/(^.^)'
  };

  /**
   *  this is the default user options, you can customize
   *  this by passing a new object into make function
   */
  var defaultOptions = {
    rows: 20,
    start: 0,
    query: 'This is my query',
    dataType: 'json'
  };

  /**
   * The actual code for the query builder
   */
  var getInstance = function (uriOpts, schema) {
    var _this = this;
    this.schema = schema;
    this.uriOptions = {};

    this.queryString = '';
    this.options = {};
    this.templatePlaceholder = schema.__placeholder || '(^.^)';

    function makeUriComponents () {
      if ( typeof uriOpts === 'string') {
        return uriOpts;
      }
      var output = '';
      var uriOptions = extend({}, uri.defaultOptions, uriOpts);
      for( var i = 0; i <= uri.componentsOrder.length; i++) {
        var component = uri.componentsOrder[i];
        if (uriOptions[component]) {
          output += uri.schema[component].
              replace(uri.schema.__placeholder, uriOptions[component]);
        }
      }
      return output;
    }

    function isValidTemplate(tmpl) {
      if ( _.isString(tmpl) && tmpl.search(_this.templatePlaceholder) ) {
        return true;
      } else if ( _.isObject(tmpl) && _.isObject(tmpl.types) ) {
        return true;
      }
      return false;
    }

    function makeSingleParameter(template, opt) {
      if ( _.isString(template) ) {
        return template.replace(_this.templatePlaceholder, opt);
      } else if ( _.isObject(template) ) {
        if (opt.value) {
          return template.types[opt.type].replace(_this.templatePlaceholder, opt.value);
        }
      }
      throw new Error('none standard template passed in.');
    }

    function makeParameters () {
      var output = [];
      var opts = extend({}, defaultOptions, _this.options );
      for ( var parameter in _this.options) {
        if (_this.options.hasOwnProperty(parameter)) {
          opt = _this.options[parameter];
          if (opt) {
            var template = _this.schema[parameter];
            if (isValidTemplate(template)) {
              output.push(makeSingleParameter(template, opt));
            } else {
              throw new Error('none standard template found in your schema!');
            }
          }
        }
      }
      return output.join('&');
    }

    function makeQuery (opt) {
      _this.options = extend({}, _this.options, opt);
      _this.queryString = '';
      _this.queryString += makeUriComponents();
      _this.queryString += makeParameters();
      return encodeURI(_this.queryString);
    }

    function resetOptions () {
      _this.options = {};
      return this;
    }

    function extend(){
      for(var i=1; i<arguments.length; i++)
      for(var key in arguments[i])
      if(arguments[i].hasOwnProperty(key))
        arguments[0][key] = arguments[i][key];
      return arguments[0];
    }

    return {
      make: makeQuery,
      reset: resetOptions
    };
  };

  return {getInstance: getInstance};
});
<|endoftext|>


<commit_before>import { globalStore } from '../listener';
import { findMirrorExitId, findStartExitId } from '../engines/strape';
import {
  EXIT_STRATEGY_MIRROR,
  EXIT_STRATEGY_START,
  EXIT_STRATEGY_MEMORY,
  BINDER_TYPE,
} from '../constants';

export const NAME = '@@keys';
export const ACTIVE_KEYBINDER = [NAME, '/ACTIVE_KEYBINDER'].join('');
export const ADD_KEYBINDER_TO_STORE = [NAME, '/ADD_KEYBINDER_TO_STORE'].join('');
export const UPDATE_SELECTED_KEY = [NAME, '/UPDATE_SELECTED_KEY'].join('');
export const UPDATE_BINDER_STATE = [NAME, '/UPDATE_BINDER_STATE'].join('');

export function clone(obj) {
  const cloneObject = {};
  for (const property in obj) {
    if (typeof obj[property] === 'object') {
      cloneObject[property] = clone(obj[property]);
    } else if (typeof obj[property] !== 'function') {
      cloneObject[property] = obj[property];
    }
  }
  return cloneObject;
}

export function bindersKeys(newState) {
  const keys = Object.keys(newState);
  keys.splice(keys.indexOf('current'), 1);
  return keys;
}

export function _activeKeyBinder(binderId, id, memory = false) {
  if (globalStore.dispatch) {
    const newState = clone(globalStore.getState()[NAME]);
    for (const key of bindersKeys(newState)) {
      newState[key].active = false;
    }
    if (bindersKeys(newState).some(key => key === binderId)) {
      newState[binderId].active = true;
      if (!memory) {
        newState[binderId].selectedId =
          newState[binderId].elements && newState[binderId].elements[0].id;
      } else {
        newState[binderId].selectedId = id || newState[binderId].selectedId;
      }
      newState.current = {
        selectedId: newState[binderId].selectedId,
        binderId: binderId,
      };
      globalStore.dispatch({
        type: ACTIVE_KEYBINDER,
        state: newState,
      });
    }
  }
}

export function addKeyBinderToStore(binderId, active) {
  if (globalStore.dispatch) {
    const newState = clone(globalStore.getState()[NAME]);
    if (!bindersKeys(newState).some(key => key === binderId)) {
      newState[binderId] = {};
      newState[binderId].id = binderId;
      newState[binderId].active = active;
      globalStore.dispatch({
        type: ADD_KEYBINDER_TO_STORE,
        state: newState,
      });
    }
    if (active) {
      _activeKeyBinder(binderId,
        newState[binderId].elements && newState[binderId].elements[0].id);
    }
  }
}

export function _updateBinderState(binderId, binderState) {
  if (globalStore.dispatch) {
    const newState = clone(globalStore.getState()[NAME]);
    newState[binderId] = { ...newState[binderId], ...binderState };
    if (newState[binderId].active) {
      newState.current = {
        selectedId: binderState.selectedId,
        binderId: binderId,
      };
    }
    globalStore.dispatch({
      type: UPDATE_BINDER_STATE,
      state: newState,
    });
  }
}

export function enterStrape(strategy, callback, nextElId, children, dom) {
  switch (strategy) {
    case EXIT_STRATEGY_MIRROR:
      _activeKeyBinder(callback,
        findMirrorExitId(document.getElementById(nextElId), children), true);
      break;
    case EXIT_STRATEGY_START:
      _activeKeyBinder(callback, findStartExitId(children, dom), true);
      break;
    case EXIT_STRATEGY_MEMORY:
      _activeKeyBinder(callback, null, true);
      break;
    default:
      _activeKeyBinder(callback);
      break;
  }
}

export function enterBinder(strategy, callback) {
  switch (strategy) {
    case EXIT_STRATEGY_MEMORY:
      _activeKeyBinder(callback, null, true);
      break;
    default:
      _activeKeyBinder(callback);
      break;
  }
}

export function enter(callback, nextElId) {
  if (typeof callback === 'string') {
    const nextBinderState = globalStore.getState()[NAME][callback] || {};
    const strategy = nextBinderState.enterStrategy;
    if (nextBinderState.type === BINDER_TYPE) {
      enterBinder(strategy, callback);
    } else {
      const dom = document.getElementById(callback) || document;
      const children = [].slice.call(dom.querySelectorAll(nextBinderState.wChildren));
      enterStrape(strategy, callback, nextElId, children, dom);
    }
  } else {
    callback();
  }
}

export function updateSelectedId(binderId, selectedId, marginLeft) {
  if (globalStore.dispatch) {
    const newState = clone(globalStore.getState()[NAME]);
    newState[binderId].selectedId = selectedId;
    newState[binderId].marginLeft = marginLeft;
    newState.current.selectedId = selectedId;
    globalStore.dispatch({
      type: UPDATE_SELECTED_KEY,
      state: newState,
    });
  }
}
<commit_msg>Actions: Functions depends on the prop position to set the correct top or left<commit_after>import { globalStore } from '../listener';
import { findMirrorExitId, findStartExitId } from '../engines/strape';
import {
  EXIT_STRATEGY_MIRROR,
  EXIT_STRATEGY_START,
  EXIT_STRATEGY_MEMORY,
  BINDER_TYPE,
} from '../constants';

export const NAME = '@@keys';
export const ACTIVE_KEYBINDER = [NAME, '/ACTIVE_KEYBINDER'].join('');
export const ADD_KEYBINDER_TO_STORE = [NAME, '/ADD_KEYBINDER_TO_STORE'].join('');
export const UPDATE_SELECTED_KEY = [NAME, '/UPDATE_SELECTED_KEY'].join('');
export const UPDATE_BINDER_STATE = [NAME, '/UPDATE_BINDER_STATE'].join('');

export function clone(obj) {
  const cloneObject = {};
  for (const property in obj) {
    if (typeof obj[property] === 'object') {
      cloneObject[property] = clone(obj[property]);
    } else if (typeof obj[property] !== 'function') {
      cloneObject[property] = obj[property];
    }
  }
  return cloneObject;
}

export function bindersKeys(newState) {
  const keys = Object.keys(newState);
  keys.splice(keys.indexOf('current'), 1);
  return keys;
}

export function _activeKeyBinder(binderId, id, memory = false) {
  if (globalStore.dispatch) {
    const newState = clone(globalStore.getState()[NAME]);
    for (const key of bindersKeys(newState)) {
      newState[key].active = false;
    }
    if (bindersKeys(newState).some(key => key === binderId)) {
      newState[binderId].active = true;
      if (!memory) {
        newState[binderId].selectedId =
          newState[binderId].elements && newState[binderId].elements[0].id;
      } else {
        newState[binderId].selectedId = id || newState[binderId].selectedId;
      }
      newState.current = {
        selectedId: newState[binderId].selectedId,
        binderId: binderId,
      };
      globalStore.dispatch({
        type: ACTIVE_KEYBINDER,
        state: newState,
      });
    }
  }
}

export function addKeyBinderToStore(binderId, active) {
  if (globalStore.dispatch) {
    const newState = clone(globalStore.getState()[NAME]);
    if (!bindersKeys(newState).some(key => key === binderId)) {
      newState[binderId] = {};
      newState[binderId].id = binderId;
      newState[binderId].active = active;
      globalStore.dispatch({
        type: ADD_KEYBINDER_TO_STORE,
        state: newState,
      });
    }
    if (active) {
      _activeKeyBinder(binderId,
        newState[binderId].elements && newState[binderId].elements[0].id);
    }
  }
}

export function _updateBinderState(binderId, binderState) {
  if (globalStore.dispatch) {
    const newState = clone(globalStore.getState()[NAME]);
    newState[binderId] = { ...newState[binderId], ...binderState };
    if (newState[binderId].active) {
      newState.current = {
        selectedId: binderState.selectedId,
        binderId: binderId,
      };
    }
    globalStore.dispatch({
      type: UPDATE_BINDER_STATE,
      state: newState,
    });
  }
}

export function enterStrape(position, strategy, callback, nextElId, children, dom) {
  let moved;
  position ? moved ='top' : moved = 'left';
  switch (strategy) {
    case EXIT_STRATEGY_MIRROR:
      _activeKeyBinder(callback,
        findMirrorExitId(document.getElementById(nextElId), children, moved), true);
      break;
    case EXIT_STRATEGY_START:
      _activeKeyBinder(callback, findStartExitId(children, dom, moved), true)
      break;
    case EXIT_STRATEGY_MEMORY:
      _activeKeyBinder(callback, null, true);
      break;
    default:
      _activeKeyBinder(callback);
      break;
  }
}

export function enterBinder(strategy, callback) {
  switch (strategy) {
    case EXIT_STRATEGY_MEMORY:
      _activeKeyBinder(callback, null, true);
      break;
    default:
      _activeKeyBinder(callback);
      break;
  }
}

export function enter(callback, nextElId) {
  if (typeof callback === 'string') {
    const nextBinderState = globalStore.getState()[NAME][callback] || {};
    const strategy = nextBinderState.enterStrategy;
    const position = nextBinderState.position;
    if (nextBinderState.type === BINDER_TYPE) {
      enterBinder(strategy, callback);
    } else {
      const dom = document.getElementById(callback) || document;
      const children = [].slice.call(dom.querySelectorAll(nextBinderState.wChildren));
      enterStrape(position, strategy, callback, nextElId, children, dom);
    }
  } else {
    callback();
  }
}

export function updateSelectedId(binderId, selectedId, marginLeft, marginTop) {
  if (globalStore.dispatch) {
    const newState = clone(globalStore.getState()[NAME]);
    newState[binderId].selectedId = selectedId;
    newState[binderId].marginLeft = marginLeft;
    newState[binderId].marginTop = marginTop;
    newState.current.selectedId = selectedId;
    globalStore.dispatch({
      type: UPDATE_SELECTED_KEY,
      state: newState,
    });
  }
}
<|endoftext|>


<commit_before>import Globalize from "globalize";

const second = 1e3;
const minute = 6e4;
const hour = 36e5;
const day = 864e5;
// const week = 6048e5;
// const month = 2592e6;

function defineCachedGetter(obj, prop, get) {
  defineGetter(obj, prop, function() {
    if (!this._[prop]) {
      this._[prop] = get.call(this);
    }
    return this._[prop];
  });
}

function defineGetter(obj, prop, get) {
  Object.defineProperty(obj, prop, {get});
}

function startOf(date, unit) {
  date = new Date(date.getTime());
  switch (unit) {
    case "year": date.setMonth(0);
    // falls through
    case "month": date.setDate(1);
    // falls through
    case "day": date.setHours(0);
    // falls through
    case "hour": date.setMinutes(0);
    // falls through
    case "minute": date.setSeconds(0);
    // falls through
    case "second": date.setMilliseconds(0);
  }
  return date;
}

export default class RelativeTime {
  constructor() {
    this.formatters = RelativeTime.initializeFormatters(...arguments);
  }

  format(date, {unit = "best-fit"} = {}) {
    var formatters = this.formatters;
    var now = new Date();
    var diff = {
      _: {},
      ms: date.getTime() - now.getTime(),
      years: date.getFullYear() - now.getFullYear()
    };
    var round = Math[diff.ms > 0 ? "floor" : "ceil"];

    defineCachedGetter(diff, "months", function() {
      return this.years * 12 + date.getMonth() - now.getMonth();
    });
    defineCachedGetter(diff, "days", function() {
      return round((startOf(date, "day") - startOf(now, "day")) / day);
    });
    defineCachedGetter(diff, "hours", function() {
      return round((startOf(date, "hour") - startOf(now, "hour")) / hour);
    });
    defineCachedGetter(diff, "minutes", function() {
      return round((startOf(date, "minute") - startOf(now, "minute")) / minute);
    });
    defineCachedGetter(diff, "seconds", function() {
      return round((startOf(date, "second") - startOf(now, "second")) / second);
    });

    var absDiff = {
      _: {}
    };

    defineGetter(absDiff, "years", function() {
      return Math.abs(diff.years);
    });
    defineGetter(absDiff, "months", function() {
      return Math.abs(diff.months);
    });
    defineGetter(absDiff, "days", function() {
      return Math.abs(diff.days);
    });
    defineGetter(absDiff, "hours", function() {
      return Math.abs(diff.hours);
    });
    defineGetter(absDiff, "minutes", function() {
      return Math.abs(diff.minutes);
    });
    defineGetter(absDiff, "seconds", function() {
      return Math.abs(diff.seconds);
    });

    if (unit === "best-fit") {
      unit = RelativeTime.bestFit(absDiff);
    }

    switch(unit) {
      case "year": return formatters.year(diff.years);
      case "month": return formatters.month(diff.months);
      // case "week": return formatters.week(diff.weeks);
      case "day": return formatters.day(diff.days);
      case "hour": return formatters.hour(diff.hours);
      case "minute": return formatters.minute(diff.minutes);
      default: return formatters.second(diff.seconds);
    }
  }
}

RelativeTime.bestFit = function(absDiff) {
  let threshold = this.threshold;
  switch(true) {
    case absDiff.years > 0 && absDiff.months >= threshold.month: return "year";
    case absDiff.months > 0 && absDiff.days >= threshold.day: return "month";
    // case absDiff.months > 0 && absDiff.weeks >= threshold.week: return "month";
    // case absDiff.weeks > 0 && absDiff.days >= threshold.day: return "week";
    case absDiff.days > 0 && absDiff.hours >= threshold.hour: return "day";
    case absDiff.hours > 0 && absDiff.minutes >= threshold.minute: return "hour";
    case absDiff.minutes > 0 && absDiff.seconds >= threshold.second: return "minute";
    default: return "second";
  }
};

RelativeTime.threshold = {
  month: 3, // at least 3 months before using year.
  // week: 4, // at least 4 weeks before using month.
  day: 7, // at least 7 days before using month.
  hour: 7, // at least 7 hours before using day.
  minute: 60, // at least 60 minutes before using hour.
  second: 60 // at least 60 seconds before using minute.
};

// TODO: Remove redundancy. The only reason this code is that ugly is to get
// supported by globalize-compiler (which reads the static formatters).
RelativeTime.initializeFormatters = function(globalize) {
  if (globalize) {
    return {
      second: globalize.relativeTimeFormatter("second"),
      minute: globalize.relativeTimeFormatter("minute"),
      hour: globalize.relativeTimeFormatter("hour"),
      day: globalize.relativeTimeFormatter("day"),
      month: globalize.relativeTimeFormatter("month"),
      year: globalize.relativeTimeFormatter("year")
    };
  }
  return {
    second: Globalize.relativeTimeFormatter("second"),
    minute: Globalize.relativeTimeFormatter("minute"),
    hour: Globalize.relativeTimeFormatter("hour"),
    day: Globalize.relativeTimeFormatter("day"),
    month: Globalize.relativeTimeFormatter("month"),
    year: Globalize.relativeTimeFormatter("year")
  };
};
<commit_msg>Increase unit if > threshold (not >=)<commit_after>import Globalize from "globalize";

const second = 1e3;
const minute = 6e4;
const hour = 36e5;
const day = 864e5;
// const week = 6048e5;
// const month = 2592e6;

function defineCachedGetter(obj, prop, get) {
  defineGetter(obj, prop, function() {
    if (!this._[prop]) {
      this._[prop] = get.call(this);
    }
    return this._[prop];
  });
}

function defineGetter(obj, prop, get) {
  Object.defineProperty(obj, prop, {get});
}

function startOf(date, unit) {
  date = new Date(date.getTime());
  switch (unit) {
    case "year": date.setMonth(0);
    // falls through
    case "month": date.setDate(1);
    // falls through
    case "day": date.setHours(0);
    // falls through
    case "hour": date.setMinutes(0);
    // falls through
    case "minute": date.setSeconds(0);
    // falls through
    case "second": date.setMilliseconds(0);
  }
  return date;
}

export default class RelativeTime {
  constructor() {
    this.formatters = RelativeTime.initializeFormatters(...arguments);
  }

  format(date, {unit = "best-fit"} = {}) {
    var formatters = this.formatters;
    var now = new Date();
    var diff = {
      _: {},
      ms: date.getTime() - now.getTime(),
      years: date.getFullYear() - now.getFullYear()
    };
    var round = Math[diff.ms > 0 ? "floor" : "ceil"];

    defineCachedGetter(diff, "months", function() {
      return this.years * 12 + date.getMonth() - now.getMonth();
    });
    defineCachedGetter(diff, "days", function() {
      return round((startOf(date, "day") - startOf(now, "day")) / day);
    });
    defineCachedGetter(diff, "hours", function() {
      return round((startOf(date, "hour") - startOf(now, "hour")) / hour);
    });
    defineCachedGetter(diff, "minutes", function() {
      return round((startOf(date, "minute") - startOf(now, "minute")) / minute);
    });
    defineCachedGetter(diff, "seconds", function() {
      return round((startOf(date, "second") - startOf(now, "second")) / second);
    });

    var absDiff = {
      _: {}
    };

    defineGetter(absDiff, "years", function() {
      return Math.abs(diff.years);
    });
    defineGetter(absDiff, "months", function() {
      return Math.abs(diff.months);
    });
    defineGetter(absDiff, "days", function() {
      return Math.abs(diff.days);
    });
    defineGetter(absDiff, "hours", function() {
      return Math.abs(diff.hours);
    });
    defineGetter(absDiff, "minutes", function() {
      return Math.abs(diff.minutes);
    });
    defineGetter(absDiff, "seconds", function() {
      return Math.abs(diff.seconds);
    });

    if (unit === "best-fit") {
      unit = RelativeTime.bestFit(absDiff);
    }

    switch(unit) {
      case "year": return formatters.year(diff.years);
      case "month": return formatters.month(diff.months);
      // case "week": return formatters.week(diff.weeks);
      case "day": return formatters.day(diff.days);
      case "hour": return formatters.hour(diff.hours);
      case "minute": return formatters.minute(diff.minutes);
      default: return formatters.second(diff.seconds);
    }
  }
}

RelativeTime.bestFit = function(absDiff) {
  let threshold = this.threshold;
  switch(true) {
    case absDiff.years > 0 && absDiff.months > threshold.month: return "year";
    case absDiff.months > 0 && absDiff.days > threshold.day: return "month";
    // case absDiff.months > 0 && absDiff.weeks > threshold.week: return "month";
    // case absDiff.weeks > 0 && absDiff.days > threshold.day: return "week";
    case absDiff.days > 0 && absDiff.hours > threshold.hour: return "day";
    case absDiff.hours > 0 && absDiff.minutes > threshold.minute: return "hour";
    case absDiff.minutes > 0 && absDiff.seconds > threshold.second: return "minute";
    default: return "second";
  }
};

RelativeTime.threshold = {
  month: 2, // at least 2 months before using year.
  // week: 4, // at least 4 weeks before using month.
  day: 6, // at least 6 days before using month.
  hour: 6, // at least 6 hours before using day.
  minute: 59, // at least 59 minutes before using hour.
  second: 59 // at least 59 seconds before using minute.
};

// TODO: Remove redundancy. The only reason this code is that ugly is to get
// supported by globalize-compiler (which reads the static formatters).
RelativeTime.initializeFormatters = function(globalize) {
  if (globalize) {
    return {
      second: globalize.relativeTimeFormatter("second"),
      minute: globalize.relativeTimeFormatter("minute"),
      hour: globalize.relativeTimeFormatter("hour"),
      day: globalize.relativeTimeFormatter("day"),
      month: globalize.relativeTimeFormatter("month"),
      year: globalize.relativeTimeFormatter("year")
    };
  }
  return {
    second: Globalize.relativeTimeFormatter("second"),
    minute: Globalize.relativeTimeFormatter("minute"),
    hour: Globalize.relativeTimeFormatter("hour"),
    day: Globalize.relativeTimeFormatter("day"),
    month: Globalize.relativeTimeFormatter("month"),
    year: Globalize.relativeTimeFormatter("year")
  };
};
<|endoftext|>


<commit_before>/* eslint no-console: [0] */
'use strict'

const Service = require('trails/service')
const csvParser = require('babyparse')
const _ = require('lodash')
const shortid = require('shortid')
const fs = require('fs')
const COLLECTION_UPLOAD = require('../utils/enums').COLLECTION_UPLOAD

/**
 * @module CollectionCsvService
 * @description Collection Csv Service
 */
module.exports = class CollectionCsvService extends Service {
  /**
   *
   * @param file
   * @returns {Promise}
   */
  collectionCsv(file) {
    // TODO validate csv
    console.time('csv')
    const uploadID = shortid.generate()
    const ProxyEngineService = this.app.services.ProxyEngineService
    const errors = []
    return new Promise((resolve, reject)=>{
      const options = {
        header: true,
        dynamicTyping: true,
        step: (results, parser) => {
          // console.log(parser)
          // console.log('Row data:', results.data)
          // TODO handle errors
          // console.log('Row errors:', results.errors)
          parser.pause()
          return this.csvCollectionRow(results.data[0], uploadID)
            .then(row => {
              parser.resume()
            })
            .catch(err => {
              this.app.log.error('ROW ERROR',err)
              errors.push(err.message)
              parser.resume()
            })
        },
        complete: (results, file) => {
          console.timeEnd('csv')
          // console.log('Parsing complete:', results, file)
          results.upload_id = uploadID
          ProxyEngineService.count('CollectionUpload', { where: { upload_id: uploadID }})
            .then(count => {
              results.collections = count
              results.errors = errors
              // Publish the event
              ProxyEngineService.publish('collection_upload.complete', results)
              return resolve(results)
            })
            // TODO handle this more gracefully
            .catch(err => {
              return reject(err)
            })
        },
        error: (err, file) => {
          return reject(err)
        }
      }
      const fileString = fs.readFileSync(file, 'utf8')
      // Parse the CSV/TSV
      csvParser.parse(fileString, options)
    })
  }

  /**
   *
   * @param row
   * @param uploadID
   */
  csvCollectionRow(row, uploadID) {
    // console.log(row)
    const CollectionUpload = this.app.orm.CollectionUpload
    const values = _.values(COLLECTION_UPLOAD)
    const keys = _.keys(COLLECTION_UPLOAD)
    const upload = {
      upload_id: uploadID,
      options: {}
    }

    _.each(row, (data, key) => {
      if (data === '') {
        row[key] = null
      }
    })

    row = _.omitBy(row, _.isNil)

    if (_.isEmpty(row)) {
      return Promise.resolve({})
    }

    _.each(row, (data, key) => {
      if (data !== '') {
        const i = values.indexOf(key.replace(/^\s+|\s+$/g, ''))
        const k = keys[i]
        if (i > -1 && k) {
          if (k == 'discount_product_include') {
            upload[k] = data.split(',').map(discount => {
              return discount.trim()
            })
          }
          else if (k == 'discount_product_exclude') {
            upload[k] = data.split(',').map(discount => {
              return discount.trim()
            })
          }
          else if (k == 'collections') {
            upload[k] = data.split(',').map(collection => {
              return collection.trim()
            })
          }
          else if (k == 'images') {
            upload[k] = data.split(',').map(images => {
              return images.trim()
            })
          }
          else if (k == 'images_alt') {
            upload[k] = data.split(',').map(images => {
              return images.trim()
            })
          }
          else {
            upload[k] = data
          }
        }
      }
    })

    // Map images
    upload.images = _.map(upload.images, (image, index) => {
      return {
        src: image,
        alt: upload.images_alt ? upload.images_alt[index] : ''
      }
    })

    // upload.images = _.omitBy(upload.images, _.isNil)

    const newCollection = CollectionUpload.build(upload)
    return newCollection.save()
  }

  /**
   *
   * @param uploadId
   * @returns {Promise}
   */
  processCollectionUpload(uploadId) {
    const CollectionUpload = this.app.orm.CollectionUpload
    let collectionsTotal = 0
    const errors = []
    return CollectionUpload.batch({
      where: {
        upload_id: uploadId
      }
    }, collections => {

      const Sequelize = this.app.orm.Collection.sequelize

      return Sequelize.Promise.mapSeries(collections, collection => {

        const create = {
          title: collection.title,
          handle: collection.handle,
          body: collection.body,
          primary_purpose: collection.primary_purpose,
          position: collection.position,
          sort_order: collection.sort_order,
          published: collection.published,
          tax_rate: collection.tax_rate,
          tax_percentage: collection.tax_percentage,
          tax_type: collection.tax_type,
          tax_name: collection.tax_name,
          discount_scope: collection.discount_scope,
          discount_type: collection.discount_type,
          discount_rate: collection.discount_rate,
          discount_percentage: collection.discount_percentage,
          discount_product_include: collection.discount_product_include,
          discount_product_exclude: collection.discount_product_exclude,
          collections: collection.collections,
          images: collection.images
        }
        return this.app.services.CollectionService.add(create)
          .then(() => {
            collectionsTotal++
            return
          })
          .catch(err => {
            errors.push(`${collection.handle}: ${err.message}`)
            return err
          })
      })
    })
      .then(() => {
        return CollectionUpload.destroy({where: {upload_id: uploadId }})
          .catch(err => {
            errors.push(err.message)
            return err
          })
      })
      .then(destroyed => {
        const results = {
          upload_id: uploadId,
          collections: collectionsTotal,
          errors: errors
        }
        this.app.services.ProxyEngineService.publish('collection_process.complete', results)
        return results
      })
  }
}

<commit_msg>fix collection handles on uploads<commit_after>/* eslint no-console: [0] */
'use strict'

const Service = require('trails/service')
const csvParser = require('babyparse')
const _ = require('lodash')
const shortid = require('shortid')
const fs = require('fs')
const COLLECTION_UPLOAD = require('../utils/enums').COLLECTION_UPLOAD

/**
 * @module CollectionCsvService
 * @description Collection Csv Service
 */
module.exports = class CollectionCsvService extends Service {
  /**
   *
   * @param file
   * @returns {Promise}
   */
  collectionCsv(file) {
    // TODO validate csv
    console.time('csv')
    const uploadID = shortid.generate()
    const ProxyEngineService = this.app.services.ProxyEngineService
    const errors = []
    return new Promise((resolve, reject)=>{
      const options = {
        header: true,
        dynamicTyping: true,
        step: (results, parser) => {
          // console.log(parser)
          // console.log('Row data:', results.data)
          // TODO handle errors
          // console.log('Row errors:', results.errors)
          parser.pause()
          return this.csvCollectionRow(results.data[0], uploadID)
            .then(row => {
              parser.resume()
            })
            .catch(err => {
              this.app.log.error('ROW ERROR',err)
              errors.push(err.message)
              parser.resume()
            })
        },
        complete: (results, file) => {
          console.timeEnd('csv')
          // console.log('Parsing complete:', results, file)
          results.upload_id = uploadID
          ProxyEngineService.count('CollectionUpload', { where: { upload_id: uploadID }})
            .then(count => {
              results.collections = count
              results.errors = errors
              // Publish the event
              ProxyEngineService.publish('collection_upload.complete', results)
              return resolve(results)
            })
            // TODO handle this more gracefully
            .catch(err => {
              return reject(err)
            })
        },
        error: (err, file) => {
          return reject(err)
        }
      }
      const fileString = fs.readFileSync(file, 'utf8')
      // Parse the CSV/TSV
      csvParser.parse(fileString, options)
    })
  }

  /**
   *
   * @param row
   * @param uploadID
   */
  csvCollectionRow(row, uploadID) {
    // console.log(row)
    const CollectionUpload = this.app.orm.CollectionUpload
    const values = _.values(COLLECTION_UPLOAD)
    const keys = _.keys(COLLECTION_UPLOAD)
    const upload = {
      upload_id: uploadID,
      options: {}
    }

    _.each(row, (data, key) => {
      if (data === '') {
        row[key] = null
      }
    })

    row = _.omitBy(row, _.isNil)

    if (_.isEmpty(row)) {
      return Promise.resolve({})
    }

    _.each(row, (data, key) => {
      if (data !== '') {
        const i = values.indexOf(key.replace(/^\s+|\s+$/g, ''))
        const k = keys[i]
        if (i > -1 && k) {
          if (k == 'handle') {
            upload[k] = this.app.services.ProxyCartService.safeHandle(data)
          }
          else if (k == 'title') {
            upload[k] = data.toString().trim()
          }
          else if (k == 'discount_product_include') {
            upload[k] = data.split(',').map(discount => {
              return discount.trim()
            })
          }
          else if (k == 'discount_product_exclude') {
            upload[k] = data.split(',').map(discount => {
              return discount.trim()
            })
          }
          else if (k == 'collections') {
            upload[k] = data.split(',').map(collection => {
              return collection.trim()
            })
          }
          else if (k == 'images') {
            upload[k] = data.split(',').map(images => {
              return images.trim()
            })
          }
          else if (k == 'images_alt') {
            upload[k] = data.split(',').map(images => {
              return images.trim()
            })
          }
          else {
            upload[k] = data
          }
        }
      }
    })

    // Map images
    upload.images = _.map(upload.images, (image, index) => {
      return {
        src: image,
        alt: upload.images_alt ? upload.images_alt[index] : ''
      }
    })

    // upload.images = _.omitBy(upload.images, _.isNil)

    const newCollection = CollectionUpload.build(upload)
    return newCollection.save()
  }

  /**
   *
   * @param uploadId
   * @returns {Promise}
   */
  processCollectionUpload(uploadId) {
    const CollectionUpload = this.app.orm.CollectionUpload
    let collectionsTotal = 0
    const errors = []
    return CollectionUpload.batch({
      where: {
        upload_id: uploadId
      }
    }, collections => {

      const Sequelize = this.app.orm.Collection.sequelize

      return Sequelize.Promise.mapSeries(collections, collection => {

        const create = {
          title: collection.title,
          handle: collection.handle,
          body: collection.body,
          primary_purpose: collection.primary_purpose,
          position: collection.position,
          sort_order: collection.sort_order,
          published: collection.published,
          tax_rate: collection.tax_rate,
          tax_percentage: collection.tax_percentage,
          tax_type: collection.tax_type,
          tax_name: collection.tax_name,
          discount_scope: collection.discount_scope,
          discount_type: collection.discount_type,
          discount_rate: collection.discount_rate,
          discount_percentage: collection.discount_percentage,
          discount_product_include: collection.discount_product_include,
          discount_product_exclude: collection.discount_product_exclude,
          collections: collection.collections,
          images: collection.images
        }
        return this.app.services.CollectionService.add(create)
          .then(() => {
            collectionsTotal++
            return
          })
          .catch(err => {
            errors.push(`${collection.handle}: ${err.message}`)
            return err
          })
      })
    })
      .then(() => {
        return CollectionUpload.destroy({where: {upload_id: uploadId }})
          .catch(err => {
            errors.push(err.message)
            return err
          })
      })
      .then(destroyed => {
        const results = {
          upload_id: uploadId,
          collections: collectionsTotal,
          errors: errors
        }
        this.app.services.ProxyEngineService.publish('collection_process.complete', results)
        return results
      })
  }
}

<|endoftext|>


<commit_before>/**
 * /api/services/PhaseDurationService.js
 *
 * Phase duration service.
 */
"use strict";

var async = require("async");
var moment = require("moment-timezone");

/**
 * Method to write task phase duration data to database.
 *
 * @param   {sails.model.task}  task    Task object
 */
exports.write = function(task) {
    /**
     * Fetch needed data for phase duration write. Basically we need following data:
     *  - Phase data of current task
     *  - Latest duration row
     *
     * Those are fetched parallel and after that
     */
    async.parallel(
        {
            /**
             * Fetch task phase data.
             *
             * @param   {Function}  callback    Function to call after job is done.
             */
            phase: function(callback) {
                DataService.getPhase(task.phaseId, callback);
            },

            /**
             * Job to fetch latest "open" phase duration row.
             *
             * @param   {Function}  callback    Function to call after job is done.
             */
            current: function(callback) {
                PhaseDuration
                    .findOne()
                    .where({
                        taskId: task.id,
                        open: true
                    })
                    .sort("id DESC")
                    .done(callback);
            }
        },

        /**
         * Main callback function which is called after all parallel jobs are done.
         *
         * @param   {Error|null}    error
         * @param   {{}}            data
         */
        function(error, data) {
            if (error) {
                sails.log.error(error);
            } else {
                // We have existing row AND task phase is changed, so close existing duration row
                if (data.current && data.current.phaseId !== task.phaseId) {
                    durationEnd(data.current);
                }

                // New phase is not yet "done" and duration data not yet exist OR task phase is changed => create new row
                if (!data.phase.isDone && (!data.current || data.current.phaseId !== task.phaseId)) {
                    durationStart();
                }
            }
        }
    );

    /**
     * Private function to start new task duration. This will just
     * add new row to 'PhaseDuration' table with current task data.
     */
    function durationStart() {
        PhaseDuration
            .create({
                taskId: task.id,
                phaseId: task.phaseId,
                timeStart: new Date()
            })
            .done(function(error, row) {
                if (error) {
                    sails.log.error(error);
                }
            });
    }

    /**
     * Private function to end specified task duration row.
     *
     * @param   {{}}    current
     */
    function durationEnd(current) {
        // Set required data for updated object
        current.open = false;
        current.timeEnd = new Date();
        current.duration = moment(current.timeEnd).diff(current.timeStartObject(), "seconds");

        // Save object
        current.save(function(error) {
            if (error) {
                sails.log.error(error);
            }
        });
    }
};

/**
 * Method to remove existing phase duration rows.
 *
 * @param   {{}}    where   Where conditions
 */
exports.remove = function(where) {
    PhaseDuration
        .destroy(where)
        .done(function(error, data) {
            if (error) {
                sails.log.error(error);
            }
        });
};<commit_msg>Refactored service code.<commit_after>/**
 * /api/services/PhaseDurationService.js
 *
 * Phase duration service.
 */
"use strict";

var async = require("async");
var moment = require("moment-timezone");

/**
 * Method to write task phase duration data to database.
 *
 * @param   {sails.model.task}  task    Task object
 */
exports.write = function(task) {
    /**
     * Fetch needed data for phase duration write. Basically we need following data:
     *  - Phase data of current task
     *  - Latest duration row
     *
     * Those are fetched parallel and after that
     */
    async.parallel(
        {
            // Fetch task phase data
            phase: function(callback) {
                DataService.getPhase(task.phaseId, callback);
            },

            // fetch latest "open" phase duration row.
            current: function(callback) {
                DataService.getPhaseDuration({taskId: task.id, open: true}, callback, true);
            }
        },

        /**
         * Main callback function which is called after all parallel jobs are done.
         *
         * @param   {null|Error}    error
         * @param   {{
         *              phase: sails.model.phase,
         *              current: sails.model.phaseDuration
         *          }}              data
         */
        function(error, data) {
            if (error) {
                sails.log.error(__filename + ":" + __line + " [Failed to fetch necessary data for phase duration service]");
                sails.log.error(error);
            } else {
                // We have existing row AND task phase is changed, so close existing duration row
                if (data.current && data.current.phaseId !== task.phaseId) {
                    durationEnd(data.current);
                }

                // New phase is not yet "done" and duration data not yet exist OR task phase is changed => create new row
                if (!data.phase.isDone && (!data.current || data.current.phaseId !== task.phaseId)) {
                    durationStart();
                }
            }
        }
    );

    /**
     * Private function to start new task duration. This will just add new row to
     * 'PhaseDuration' table with current task data.
     */
    function durationStart() {
        PhaseDuration
            .create({
                taskId: task.id,
                phaseId: task.phaseId,
                timeStart: new Date()
            })
            .exec(function(error) {
                if (error) {
                    sails.log.error(__filename + ":" + __line + " [Failed to insert new phase duration row]");
                    sails.log.error(error);
                }
            });
    }

    /**
     * Private function to end specified task duration row.
     *
     * @param   {sails.model.phaseDuration} current
     */
    function durationEnd(current) {
        // Set required data for updated object
        current.open = false;
        current.timeEnd = new Date();
        current.duration = moment(current.timeEnd).diff(current.timeStartObject(), "seconds");

        // Save object
        current.save(function(error) {
            if (error) {
                sails.log.error(__filename + ":" + __line + " [Failed to update phase duration row]");
                sails.log.error(error);
            }
        });
    }
};

/**
 * Method to remove existing phase duration rows.
 *
 * @param   {{}}    where   Where conditions
 */
exports.remove = function(where) {
    PhaseDuration
        .destroy(where)
        .exec(function(error) {
            if (error) {
                sails.log.error(__filename + ":" + __line + " [Failed to delete phase duration row]");
                sails.log.error(error);
            }
        });
};
<|endoftext|>


<commit_before>/*

  Live action types

  LIVE.SHOW
    show live bar

  LIVE.HIDE
    hide live bar

  LIVE.FLOAT
    float live bar for special cases

*/
import reducer from "./reducer"
import { addReducer } from "../utilities"

addReducer({
  live: reducer
})

export default {
  set: ({ isLive, embedCode }) => ({ type: "LIVE.SET", isLive, embedCode }),
  reset: () => ({ type: "LIVE.RESET" }),
  show: () => ({ type: "LIVE.SHOW" }),
  hide: () => ({ type: "LIVE.HIDE" }),
  float: () => ({ type: "LIVE.FLOAT" }),
  unfloat: () => ({ type: "LIVE.UNFLOAT" }),
}
<commit_msg>update live reducer docs<commit_after>/*

  Live action types

  LIVE.SET
    set live status and embed code

  LIVE.RESET
    reset live status and embed code

  LIVE.SHOW
    show live bar

  LIVE.HIDE
    hide live bar

  LIVE.FLOAT
    float live bar for special cases

*/
import reducer from "./reducer"
import { addReducer } from "../utilities"

addReducer({
  live: reducer
})

export default {
  set: ({ isLive, embedCode }) => ({ type: "LIVE.SET", isLive, embedCode }),
  reset: () => ({ type: "LIVE.RESET" }),
  show: () => ({ type: "LIVE.SHOW" }),
  hide: () => ({ type: "LIVE.HIDE" }),
  float: () => ({ type: "LIVE.FLOAT" }),
  unfloat: () => ({ type: "LIVE.UNFLOAT" }),
}
<|endoftext|>


<commit_before>var deadline = 'July 9 2016 15:30:00 GMT+01:00';

function getRemainingTime(endTime) {
    var now = new Date();
    var time = Date.parse(endTime) - Date.parse(now);
    var seconds = Math.floor((time/1000)%60);
    var minutes = Math.floor((time/(1000*60))%60);
    var hours = Math.floor((time/(1000*60*60))%24);
    var days = Math.floor(time/(1000*60*60*24));

    return {
        'total'  : time,
        'days'   : days,
        'hours'  : hours,
        'minutes': minutes,
        'seconds': seconds
    };
}

function initializeClock(id, endTime) {
    var clock       = document.getElementById(id);
    var daysSpan    = clock.querySelector('.days');
    var hoursSpan   = clock.querySelector('.hours');
    var minutesSpan = clock.querySelector('.minutes');
    var secondsSpan = clock.querySelector('.seconds');

    function updateClock() {
        var time = getRemainingTime(endTime);
        daysSpan.innerHTML    = time.days;
        hoursSpan.innerHTML   = ('0'+time.hours).slice(-2);
        minutesSpan.innerHTML = ('0'+time.minutes).slice(-2);
        secondsSpan.innerHTML = ('0'+time.seconds).slice(-2);

        return time;
    }

    time = updateClock();

    if (time.total <= 0) {
        return;
    }

    var timeInterval = setInterval(
        function () {
            var time = updateClock();

            if (time.total <= 0) {
                clearInterval(timeInterval);
            }
        },
        1000
    );
}

start = function () {
    initializeClock('countdown', deadline);
};

window.onload = start;
<commit_msg>Summer time makes me change wedding time<commit_after>var deadline = 'July 9 2016 14:30:00 GMT+01:00';

function getRemainingTime(endTime) {
    var now = new Date();
    var time = Date.parse(endTime) - Date.parse(now);
    var seconds = Math.floor((time/1000)%60);
    var minutes = Math.floor((time/(1000*60))%60);
    var hours = Math.floor((time/(1000*60*60))%24);
    var days = Math.floor(time/(1000*60*60*24));

    return {
        'total'  : time,
        'days'   : days,
        'hours'  : hours,
        'minutes': minutes,
        'seconds': seconds
    };
}

function initializeClock(id, endTime) {
    var clock       = document.getElementById(id);
    var daysSpan    = clock.querySelector('.days');
    var hoursSpan   = clock.querySelector('.hours');
    var minutesSpan = clock.querySelector('.minutes');
    var secondsSpan = clock.querySelector('.seconds');

    function updateClock() {
        var time = getRemainingTime(endTime);
        daysSpan.innerHTML    = time.days;
        hoursSpan.innerHTML   = ('0'+time.hours).slice(-2);
        minutesSpan.innerHTML = ('0'+time.minutes).slice(-2);
        secondsSpan.innerHTML = ('0'+time.seconds).slice(-2);

        return time;
    }

    time = updateClock();

    if (time.total <= 0) {
        return;
    }

    var timeInterval = setInterval(
        function () {
            var time = updateClock();

            if (time.total <= 0) {
                clearInterval(timeInterval);
            }
        },
        1000
    );
}

start = function () {
    initializeClock('countdown', deadline);
};

window.onload = start;
<|endoftext|>


<commit_before>import angular from 'angular'
import gql from 'graphql-tag';
import { ApolloClient, createNetworkInterface } from 'apollo-client';
import {SubscriptionClient, addGraphQLSubscriptions} from 'subscriptions-transport-ws';

class ApolloWrapperService {
    // static $inject =
    /*@ngInject*/
    constructor($http) {
        this.$http = $http;
        let networkInterface = createNetworkInterface({uri: 'http://localhost:8080/graphql'});
        // Create WebSocket client
        const wsClient = new SubscriptionClient(`ws://localhost:8090/`, {
            reconnect: true,
            // connectionParams: {
            //     // Pass any arguments you want for initialization
            // }
        });
        const networkInterfaceWithSubscriptions = addGraphQLSubscriptions(
            networkInterface,
            wsClient
        );
        this.client = new ApolloClient({
            networkInterface: networkInterfaceWithSubscriptions
        });

        this.clientSubscription = this.client.subscribe({
                query: gql`
                    subscription onCarUpdated{
                        carUpdated {
                            name
                        }
                    }`,
                variables: {},
                // operationName: 'carUpdated'
            })
        // this.client.subscribe({
        //     query: gql`
        //         subscription onCarUpdated{
        //             carUpdated {
        //                 name
        //             }
        //         }`,
        //     variables: {},
        //     // operationName: 'carUpdated'
        // }).subscribe({
        //     next(data) {
        //         console.log('Got data- ', data);
        //     },
        //     error(err) {
        //         console.log('Error- ', err);
        //     }
        // });
    }

    getAllCars() {
        return this.client.query({
            query: gql`
                query car{
                    car{
                        _id
                        name
                    }
                }`
        })
    }

    addNewCar (car) {
        let quatedName = '"' + car.name + '"';
        return this.client.mutate({
            mutation: gql`
                mutation {
                    updateCar(currName : "", newName : ${quatedName}) {
                        name
                    }
                }
            `,
        })
    }

    editCar (previousName, currentName) {
        let prevQuatedName = '"' + previousName + '"';
        let currentQuatedName = '"' + currentName + '"';
        return this.client.mutate({
            mutation: gql`
                mutation {
                    updateCar(currName : ${prevQuatedName}, newName : ${currentQuatedName}) {
                        name
                    }
                }
            `,
        })
    }
    deleteCar (name) {
        let quatedName = '"' + name + '"';
        return this.client.mutate({
            mutation: gql`
                mutation {
                    deleteCar(name : ${quatedName}) {
                        _id
                        name
                    }
                }
            `,
        })
    }

    subscribeToCars() {
        return this.clientSubscription
    }

}

export default ApolloWrapperService<commit_msg>CLeaning code<commit_after>import angular from 'angular'
import gql from 'graphql-tag';
import { ApolloClient, createNetworkInterface } from 'apollo-client';
import {SubscriptionClient, addGraphQLSubscriptions} from 'subscriptions-transport-ws';

class ApolloWrapperService {
    // static $inject =
    /*@ngInject*/
    constructor($http) {
        this.$http = $http;
        let networkInterface = createNetworkInterface({uri: 'http://localhost:8080/graphql'});
        // Create WebSocket client
        const wsClient = new SubscriptionClient(`ws://localhost:8090/`, {
            reconnect: true,
            // connectionParams: {
            //     // Pass any arguments you want for initialization
            // }
        });
        const networkInterfaceWithSubscriptions = addGraphQLSubscriptions(
            networkInterface,
            wsClient
        );
        this.client = new ApolloClient({
            networkInterface: networkInterfaceWithSubscriptions
        });

        this.clientSubscription = this.client.subscribe({
                query: gql`
                    subscription onCarUpdated{
                        carUpdated {
                            name
                        }
                    }`,
                variables: {},
                // operationName: 'carUpdated'
            })
    }

    getAllCars() {
        return this.client.query({
            query: gql`
                query car{
                    car{
                        _id
                        name
                    }
                }`
        })
    }

    addNewCar (car) {
        let quatedName = '"' + car.name + '"';
        return this.client.mutate({
            mutation: gql`
                mutation {
                    updateCar(currName : "", newName : ${quatedName}) {
                        name
                    }
                }
            `,
        })
    }

    editCar (previousName, currentName) {
        let prevQuatedName = '"' + previousName + '"';
        let currentQuatedName = '"' + currentName + '"';
        return this.client.mutate({
            mutation: gql`
                mutation {
                    updateCar(currName : ${prevQuatedName}, newName : ${currentQuatedName}) {
                        name
                    }
                }
            `,
        })
    }
    deleteCar (name) {
        let quatedName = '"' + name + '"';
        return this.client.mutate({
            mutation: gql`
                mutation {
                    deleteCar(name : ${quatedName}) {
                        _id
                        name
                    }
                }
            `,
        })
    }

    subscribeToCars() {
        return this.clientSubscription
    }

}

export default ApolloWrapperService<|endoftext|>


<commit_before>App.addChild('Backer', _.extend({
  el: 'form#backer_form',

  events: {
    'change #backer_value' : 'resetReward',
    'click input[type=radio]' : 'clickReward',
    'click #backer_anonymous' : 'clickAnonymous',
    'change #backer_credits' : 'checkCredits'
  },

  checkCredits: function(event){
    if(event.currentTarget.checked && parseInt(this.credits.val()) < parseInt(this.value.val())) {
      this.value.val(this.credits.val());
      this.resetReward();
    }
  },

  clickAnonymous: function(){
    $('#anonymous_warning').fadeToggle();
  },

  clickReward: function(event){
    var option = this.$(event.currentTarget);
    this.selectReward(option);
    this.value.val(this.reward().minimum_value);
  },

  reward: function(){
    var $reward = this.$('input[type=radio]:checked');
    if($reward.length > 0){
      return _.find(this.rewards, function(r){ return r.id == $reward.val() });
    }
  },

  selectReward: function(reward){
    this.choices.removeClass('selected');
    reward.prop('checked', true);
    reward.parents('.choice:first').addClass('selected')
  },

  resetReward: function(event){
    var reward = this.reward();
    if(reward){
      var value = this.value.val();
      if(!(/^(\d+)$/.test(value)) || (parseInt(value) < reward.minimum_value)){
        this.selectReward(this.$('#backer_reward_id'));
      }
    }
  },

  activate: function(){
    this.value = this.$('#backer_value');
    this.rewards = this.value.data('rewards');
    this.choices = this.$('li.choice');
    this.credits = this.$('#credits');
    this.selectReward(this.$('input[type=radio]:checked'));
    this.setupForm();
  }
}, Skull.Form));

<commit_msg>Update the back amount only if < minimum award<commit_after>App.addChild('Backer', _.extend({
  el: 'form#backer_form',

  events: {
    'change #backer_value' : 'resetReward',
    'click input[type=radio]' : 'clickReward',
    'click #backer_anonymous' : 'clickAnonymous',
    'change #backer_credits' : 'checkCredits'
  },

  checkCredits: function(event){
    if(event.currentTarget.checked && parseInt(this.credits.val()) < parseInt(this.value.val())) {
      this.value.val(this.credits.val());
      this.resetReward();
    }
  },

  clickAnonymous: function(){
    $('#anonymous_warning').fadeToggle();
  },

  clickReward: function(event){
    var option = this.$(event.currentTarget);
    this.selectReward(option);

    if ((this.value.val() == '') || (parseFloat(this.value.val()) < parseFloat(this.reward().minimum_value))) {
      this.value.val(this.reward().minimum_value)
    }
  },

  reward: function(){
    var $reward = this.$('input[type=radio]:checked');
    if($reward.length > 0){
      return _.find(this.rewards, function(r){ return r.id == $reward.val() });
    }
  },

  selectReward: function(reward){
    this.choices.removeClass('selected');
    reward.prop('checked', true);
    reward.parents('.choice:first').addClass('selected')
  },

  resetReward: function(event){
    var reward = this.reward();
    if(reward){
      var value = this.value.val();
      if(!(/^(\d+)$/.test(value)) || (parseInt(value) < reward.minimum_value)){
        this.selectReward(this.$('#backer_reward_id'));
      }
    }
  },

  activate: function(){
    this.value = this.$('#backer_value');
    this.rewards = this.value.data('rewards');
    this.choices = this.$('li.choice');
    this.credits = this.$('#credits');
    this.selectReward(this.$('input[type=radio]:checked'));
    this.setupForm();
  }
}, Skull.Form));
<|endoftext|>


<commit_before>var App = App || {};
App.Waypoints = App.Waypoints || { items: [] }

App.Attraction = function(attrData){
  this.attrData = attrData;
  this.init();
}

App.Attraction.prototype.init = function(){
  this.createMarker()
  this.createListItem();
}

App.Attraction.prototype.createMarker = function() {
  var latitude = this.attrData.longlat.coordinates[1];
  var longitude = this.attrData.longlat.coordinates[0];
  var coords = new google.maps.LatLng(latitude, longitude);

  this.marker = new MarkerObject(coords, this);
}

App.Attraction.prototype.createListItem = function() {
    // contruct the li
    this.$listItem = $(this.buildListItem());

    // apend to the end of the list
    $('#attraction-list').append(this.$listItem);

    this.setListItemListeners();
  }

App.Attraction.prototype.buildListItem = function() {

  var li = $('
' + this.attrData.name + "
")
  var add_button = $('<button class="add-button">Add to Trip</button>')
  var close_button = $('<button class="remove-button">X</button>')

  return li.append(add_button).append(close_button)
}

App.Attraction.prototype.setListItemListeners = function(){
  var self = this;

  // Set a listener that will handle list item clicks
  $(this.$listItem).on('click', function(event){
    event.preventDefault();

    $('li.active').removeClass('active')
    self.$listItem.addClass('active')

    // move map marker and color marker
    mapObject.map.panTo(self.marker.marker.getPosition());
    self.marker.changeMarkerColor();
  });

  // Set a listener that will handle list item "add button "
  $(this.$listItem).on('click', '.add-button', function(event) {
    event.preventDefault();

    self.$listItem.addClass('saved')
    route.addWaypoint(self);
  });

  // Set a listener that will handle list item "add button "
  $(this.$listItem).on('click', '.remove-button', function(event) {
    event.preventDefault();

    // hide DOM element
    self.$listItem.hide();

    // hide marker object's marker
    self.marker.marker.setMap(null);

    // find index of the attraction if it is saved as a waypoint
    route.removeWaypoint(self);
  });
}

App.Attraction.prototype.onMarkerClicked = function() {
  // move the list item to top
  this.$listItem.remove();
  $('#attraction-list').prepend(this.$listItem);
  this.setListItemListeners()

  // set clicked list-item to active state
  $('li.active').removeClass('active')
  this.$listItem.addClass('active')
  // this.$listItem.css('background-color', 'purple')
}

App.Waypoints.getYelpData = function() {
  yelps = [];
  for(var i=0; i < this.items.length; ++i ) {
    yelps.push(this.items[i].attrData);
  }
  return yelps;
}

// $(function() {
//   $('#attraction-list').on('click', '.add-button', function(event){
//     event.preventDefault();

//     var thisAttraction = $(this).closest("li").data("attraction");
//     thisAttraction.setAsWaypoint();
//   });

// });
<commit_msg>removing a list item is not animated<commit_after>var App = App || {};
App.Waypoints = App.Waypoints || { items: [] }

App.Attraction = function(attrData){
  this.attrData = attrData;
  this.init();
}

App.Attraction.prototype.init = function(){
  this.createMarker()
  this.createListItem();
}

App.Attraction.prototype.createMarker = function() {
  var latitude = this.attrData.longlat.coordinates[1];
  var longitude = this.attrData.longlat.coordinates[0];
  var coords = new google.maps.LatLng(latitude, longitude);

  this.marker = new MarkerObject(coords, this);
}

App.Attraction.prototype.createListItem = function() {
    // contruct the li
    this.$listItem = $(this.buildListItem());

    // apend to the end of the list
    $('#attraction-list').append(this.$listItem);

    this.setListItemListeners();
  }

App.Attraction.prototype.buildListItem = function() {

  var li = $('
' + this.attrData.name + "
")
  var add_button = $('<button class="add-button">Add to Trip</button>')
  var close_button = $('<button class="remove-button">X</button>')

  return li.append(add_button).append(close_button)
}

App.Attraction.prototype.setListItemListeners = function(){
  var self = this;

  // Set a listener that will handle list item clicks
  $(this.$listItem).on('click', function(event){
    event.preventDefault();

    $('li.active').removeClass('active')
    self.$listItem.addClass('active')

    // move map marker and color marker
    mapObject.map.panTo(self.marker.marker.getPosition());
    self.marker.changeMarkerColor();
  });

  // Set a listener that will handle list item "add button "
  $(this.$listItem).on('click', '.add-button', function(event) {
    event.preventDefault();

    self.$listItem.addClass('saved')
    route.addWaypoint(self);
  });

  // Set a listener that will handle list item "add button "
  $(this.$listItem).on('click', '.remove-button', function(event) {
    event.preventDefault();

    // hide DOM element
    self.$listItem.hide(400);

    // hide marker object's marker
    self.marker.marker.setMap(null);

    // find index of the attraction if it is saved as a waypoint
    route.removeWaypoint(self);
  });
}

App.Attraction.prototype.onMarkerClicked = function() {
  // move the list item to top
  this.$listItem.remove();
  $('#attraction-list').prepend(this.$listItem);
  this.setListItemListeners()

  // set clicked list-item to active state
  $('li.active').removeClass('active')
  this.$listItem.addClass('active')
  // this.$listItem.css('background-color', 'purple')
}

App.Waypoints.getYelpData = function() {
  yelps = [];
  for(var i=0; i < this.items.length; ++i ) {
    yelps.push(this.items[i].attrData);
  }
  return yelps;
}

// $(function() {
//   $('#attraction-list').on('click', '.add-button', function(event){
//     event.preventDefault();

//     var thisAttraction = $(this).closest("li").data("attraction");
//     thisAttraction.setAsWaypoint();
//   });

// });
<|endoftext|>


<commit_before>function ImageEdit (opts) {
  var attribute = opts.attribute || 'picture'

  this.opts = opts
  this.fileEl = $('#file_' + attribute)
  this.previewEl = $('#preview_' + attribute).attr('src', opts.url)
  this.rotateEl = $('#rotate_' + attribute)
  this.zoomInEl = $('#zoom_in_' + attribute)
  this.zoomOutEl = $('#zoom_out_' + attribute)
  this.base64El = $('#' + opts.resource + '_base64_' + attribute)
  this.readFile = this.readFile.bind(this)
  this.initFileOnChange = this.initFileOnChange.bind(this)
  this.initCroppie = this.initCroppie.bind(this)
  this.updateResult = this.updateResult.bind(this)
}

ImageEdit.prototype.readFile = function (input) {
  if (input.files && input.files[0]) {
    var file = input.files[0]
    var reader = new FileReader()
    this.fileType = file.type

    reader.onload = function (_) {
      this.previewEl[0].src = reader.result
      this.initCroppie()
    }.bind(this)

    reader.readAsDataURL(file)
  }
}

ImageEdit.prototype.initFileOnChange = function () {
  var imageEdit = this
  this.readFile(this.fileEl[0])
  this.fileEl.on('change', function () {
    imageEdit.previewEl.attr('src', null)
    imageEdit.readFile(this)
    if (imageEdit.cropper) {
      imageEdit.cropper.destroy()
    }
  })
}

ImageEdit.prototype.initCroppie = function () {
  if (!this.previewEl[0].src) {
    return
  }
  this.cropper = new Cropper(this.previewEl[0], {
    zoomable: !!this.opts.showzoomer,
    autoCrop: false,
    autoCropArea: 1,
    aspectRatio: this.opts.enableresize ? NaN : this.opts.width / this.opts.height,
    ready: function () {
      var canvas = this.cropper.initialCanvasData
      this.cropper.zoomTo(
        canvas.width / (canvas.naturalWidth), {
          x: canvas.width / 2,
          y: canvas.height / 2
        }
      ).crop()
      this.updateResult()
    }.bind(this)
  })
  this.previewEl[0].addEventListener('cropend', this.updateResult)
  this.rotateEl.parent().on('click', function () {
    this.cropper.rotate(-90)
    this.updateResult()
  }.bind(this))
  this.zoomInEl.parent().on('click', function () {
    this.cropper.zoom(0.1)
    this.updateResult()
  }.bind(this))
  this.zoomOutEl.parent().on('click', function () {
    this.cropper.zoom(-0.1)
    this.updateResult()
  }.bind(this))
}

ImageEdit.prototype.updateResult = function () {
  var canvas = this.cropper.getCroppedCanvas()
  if (canvas) {
    this.base64El.val(canvas.toDataURL(this.fileType))
  }
}

$(document).ready(function () {
  $('.image-edit-upload').each(function (_, upload) {
    var imageEdit = new ImageEdit($(upload).data('imageedit'))
    imageEdit.initFileOnChange()
    imageEdit.initCroppie()
  })
})
<commit_msg>Update image on mousewheel zoom<commit_after>function ImageEdit (opts) {
  var attribute = opts.attribute || 'picture'

  this.opts = opts
  this.fileEl = $('#file_' + attribute)
  this.previewEl = $('#preview_' + attribute).attr('src', opts.url)
  this.rotateEl = $('#rotate_' + attribute)
  this.zoomInEl = $('#zoom_in_' + attribute)
  this.zoomOutEl = $('#zoom_out_' + attribute)
  this.base64El = $('#' + opts.resource + '_base64_' + attribute)
  this.readFile = this.readFile.bind(this)
  this.initFileOnChange = this.initFileOnChange.bind(this)
  this.initCroppie = this.initCroppie.bind(this)
  this.updateResult = this.updateResult.bind(this)
}

ImageEdit.prototype.readFile = function (input) {
  if (input.files && input.files[0]) {
    var file = input.files[0]
    var reader = new FileReader()
    this.fileType = file.type

    reader.onload = function (_) {
      this.previewEl[0].src = reader.result
      this.initCroppie()
    }.bind(this)

    reader.readAsDataURL(file)
  }
}

ImageEdit.prototype.initFileOnChange = function () {
  var imageEdit = this
  this.readFile(this.fileEl[0])
  this.fileEl.on('change', function () {
    imageEdit.previewEl.attr('src', null)
    imageEdit.readFile(this)
    if (imageEdit.cropper) {
      imageEdit.cropper.destroy()
    }
  })
}

ImageEdit.prototype.initCroppie = function () {
  if (!this.previewEl[0].src) {
    return
  }
  this.cropper = new Cropper(this.previewEl[0], {
    zoomable: !!this.opts.showzoomer,
    autoCrop: false,
    autoCropArea: 1,
    aspectRatio: this.opts.enableresize ? NaN : this.opts.width / this.opts.height,
    ready: function () {
      var canvas = this.cropper.initialCanvasData
      this.cropper.zoomTo(
        canvas.width / (canvas.naturalWidth), {
          x: canvas.width / 2,
          y: canvas.height / 2
        }
      ).crop()
      this.updateResult()
    }.bind(this)
  })
  this.previewEl[0].addEventListener('cropend', this.updateResult)
  this.previewEl[0].addEventListener('zoom', this.updateResult)
  this.rotateEl.parent().on('click', function () {
    this.cropper.rotate(-90)
    this.updateResult()
  }.bind(this))
  this.zoomInEl.parent().on('click', function () {
    this.cropper.zoom(0.1)
  }.bind(this))
  this.zoomOutEl.parent().on('click', function () {
    this.cropper.zoom(-0.1)
  }.bind(this))
}

ImageEdit.prototype.updateResult = function () {
  var canvas = this.cropper.getCroppedCanvas()
  if (canvas) {
    this.base64El.val(canvas.toDataURL(this.fileType))
  }
}

$(document).ready(function () {
  $('.image-edit-upload').each(function (_, upload) {
    var imageEdit = new ImageEdit($(upload).data('imageedit'))
    imageEdit.initFileOnChange()
    imageEdit.initCroppie()
  })
})
<|endoftext|>