<commit_before>import { BaseComponent } from '../base/Base';
import Choices from 'choices.js';
import Formio from '../../formio';
import _each from 'lodash/each';
import _get from 'lodash/get';
import _isEmpty from 'lodash/isEmpty';
import _isArray from 'lodash/isArray';
export class SelectComponent extends BaseComponent {
  constructor(component, options, data) {
    super(component, options, data);

    // If they wish to refresh on a value, then add that here.
    if (this.component.refreshOn) {
      this.on('change', (event) => {
        if (this.component.refreshOn === 'data') {
          this.updateItems();
        }
        else if (event.changed.component.key === this.component.refreshOn) {
          this.updateItems();
        }
      });
    }
  }

  elementInfo() {
    let info = super.elementInfo();
    info.type = 'select';
    info.changeEvent = 'change';
    return info;
  }

  createWrapper() {
    return false;
  }

  itemTemplate(data) {
    return this.component.template ? this.interpolate(this.component.template, {item: data}) : data.label;
  }

  itemValue(data) {
    return this.component.valueProperty ? _get(data, this.component.valueProperty) : data;
  }

  setItems(items) {
    if (!this.choices) {
      return;
    }
    this.choices._clearChoices();

    // If they provided select values, then we need to get them instead.
    if (this.component.selectValues) {
      items = _get(items, this.component.selectValues);
    }

    // Iterate through each of the items.
    _each(items, (item) => {

      // Add the choice to the select list.
      this.choices._addChoice(this.itemValue(item), this.itemTemplate(item));
    });

    // If a value is provided, then select it.
    if (this.value) {
      this.setValue(this.value, true);
    }
  }

  loadItems(url, input, headers, options) {
    let query = (this.component.dataSrc === 'url') ? {} : {
      limit: 100,
      skip: 0
    };

    // Allow for url interpolation.
    url = this.interpolate(url, {
      data: this.data,
      formioBase: Formio.getBaseUrl()
    });

    // Add search capability.
    if (this.component.searchField && input) {
      query[this.component.searchField] = input;
    }

    // Add filter capability
    if (this.component.filter) {
      let filter = this.interpolate(this.component.filter, {data: this.data});
      url += ((url.indexOf('?') === -1) ? '?' : '&') + filter;
    }

    // If they wish to return only some fields.
    if (this.component.selectFields) {
      query.select = this.component.selectFields;
    }

    if (!_isEmpty(query)) {
      // Add the query string.
      url += '?' + Formio.serialize(query);
    }

    // Make the request.
    Formio.request(url, null, null, headers, options)
      .then((response) => this.setItems(response))
      .catch((err) => {
        this.events.emit('formio.error', err);
        console.warn('Unable to load resources for ' + this.component.key);
      })
  }

  updateItems() {
    switch(this.component.dataSrc) {
      case 'values':
        this.component.valueProperty = 'value';
        this.setItems(this.component.data.values);
        break;
      case 'json':
        try {
          if (typeof this.component.data.json == 'string') {
            this.setItems(JSON.parse(this.component.data.json));
          }
          else {
            this.setItems(this.component.data.json);
          }
        }
        catch (err) {
          console.warn('Unable to parse JSON for ' + this.component.key);
        }
        break;
      case 'resource':
        try {
          this.loadItems(Formio.getProjectUrl() + '/form/' + this.component.data.resource + '/submission');
        }
        catch (err) {
          console.warn('Unable to load resources for ' + this.component.key);
        }
        break;
      case 'url':
        this.loadItems(this.component.data.url, null, new Headers(), {
          noToken: true
        });
        break;
    }
  }

  addInput(input, container) {
    super.addInput(input, container, true);
    if (this.component.multiple) {
      input.setAttribute('multiple', true);
    }
    var self = this;
    this.choices = new Choices(input, {
      placeholder: !!this.component.placeholder,
      placeholderValue: this.component.placeholder,
      removeItemButton: true,
      itemSelectText: '',
      classNames: {
        containerOuter: 'choices form-group formio-choices',
        containerInner: 'form-control'
      }
    });
    if (this.disabled) {
      this.choices.disable();
    }
    this.updateItems();
  }

  set disabled(disabled) {
    super.disabled = disabled;
    if (!this.choices) {
      return;
    }
    if (disabled) {
      this.choices.disable();
    }
    else {
      this.choices.enable();
    }
  }

  getValue() {
    if (!this.choices) {
      return;
    }
    return this.choices.getValue(true);
  }

  setValue(value, flags) {
    flags = this.getFlags.apply(this, arguments);
    this.value = value;
    if (value && this.choices) {
      if (this.choices.store) {
        // Search for the choice.
        const choices = this.choices.store.getChoices();
        const foundChoice = choices.find((choice) => {
          // For resources we may have two different instances of the same resource
          // Unify them so we don't have two copies of the same thing in the dropdown
          // and so the correct resource gets selected in the first place
          if (choice.value._id && value._id && choice.value._id === value._id) {
            value = choice.value;
          }
          return choice.value === value;
        });

        // If it is not found, then add it.
        if (!foundChoice) {
          this.choices._addChoice(this.itemValue(value), this.itemTemplate(value));
        }
      }

      // Now set the value.
      this.choices.setValueByChoice(_isArray(value) ? value : [value]);
    }
    this.updateValue(flags);
  }

  /**
   * Check if a component is eligible for multiple validation
   *
   * @return {boolean}
   */
  validateMultiple(value) {
    // Select component will contain one input when flagged as multiple.
    return false;
  }

  /**
   * Ouput this select dropdown as a string value.
   * @return {*}
   */
  asString(value) {
    value = value || this.getValue();
    value = (typeof value !== 'object') ? {label: value} : value;
    return this.itemTemplate(value);
  }

  destroy() {
    if (this.choices) {
      this.choices.destroy();
    }
  }
}
<commit_msg>Implemented the clearOnRefresh configuration.<commit_after>import { BaseComponent } from '../base/Base';
import Choices from 'choices.js';
import Formio from '../../formio';
import _each from 'lodash/each';
import _get from 'lodash/get';
import _isEmpty from 'lodash/isEmpty';
import _isArray from 'lodash/isArray';
export class SelectComponent extends BaseComponent {
  constructor(component, options, data) {
    super(component, options, data);

    // If they wish to refresh on a value, then add that here.
    if (this.component.refreshOn) {
      this.on('change', (event) => {
        if (this.component.refreshOn === 'data') {
          this.refreshItems();
        }
        else if (event.changed.component.key === this.component.refreshOn) {
          this.refreshItems();
        }
      });
    }
  }

  refreshItems() {
    this.updateItems();
    if (this.component.clearOnRefresh) {
      this.setValue(null);
    }
  }

  elementInfo() {
    let info = super.elementInfo();
    info.type = 'select';
    info.changeEvent = 'change';
    return info;
  }

  createWrapper() {
    return false;
  }

  itemTemplate(data) {
    return this.component.template ? this.interpolate(this.component.template, {item: data}) : data.label;
  }

  itemValue(data) {
    return this.component.valueProperty ? _get(data, this.component.valueProperty) : data;
  }

  setItems(items) {
    if (!this.choices) {
      return;
    }
    this.choices._clearChoices();

    // If they provided select values, then we need to get them instead.
    if (this.component.selectValues) {
      items = _get(items, this.component.selectValues);
    }

    // Iterate through each of the items.
    _each(items, (item) => {

      // Add the choice to the select list.
      this.choices._addChoice(this.itemValue(item), this.itemTemplate(item));
    });

    // If a value is provided, then select it.
    if (this.value) {
      this.setValue(this.value, true);
    }
  }

  loadItems(url, input, headers, options) {
    let query = (this.component.dataSrc === 'url') ? {} : {
      limit: 100,
      skip: 0
    };

    // Allow for url interpolation.
    url = this.interpolate(url, {
      data: this.data,
      formioBase: Formio.getBaseUrl()
    });

    // Add search capability.
    if (this.component.searchField && input) {
      query[this.component.searchField] = input;
    }

    // Add filter capability
    if (this.component.filter) {
      let filter = this.interpolate(this.component.filter, {data: this.data});
      url += ((url.indexOf('?') === -1) ? '?' : '&') + filter;
    }

    // If they wish to return only some fields.
    if (this.component.selectFields) {
      query.select = this.component.selectFields;
    }

    if (!_isEmpty(query)) {
      // Add the query string.
      url += '?' + Formio.serialize(query);
    }

    // Make the request.
    Formio.request(url, null, null, headers, options)
      .then((response) => this.setItems(response))
      .catch((err) => {
        this.events.emit('formio.error', err);
        console.warn('Unable to load resources for ' + this.component.key);
      })
  }

  updateItems() {
    switch(this.component.dataSrc) {
      case 'values':
        this.component.valueProperty = 'value';
        this.setItems(this.component.data.values);
        break;
      case 'json':
        try {
          if (typeof this.component.data.json == 'string') {
            this.setItems(JSON.parse(this.component.data.json));
          }
          else {
            this.setItems(this.component.data.json);
          }
        }
        catch (err) {
          console.warn('Unable to parse JSON for ' + this.component.key);
        }
        break;
      case 'resource':
        try {
          this.loadItems(Formio.getProjectUrl() + '/form/' + this.component.data.resource + '/submission');
        }
        catch (err) {
          console.warn('Unable to load resources for ' + this.component.key);
        }
        break;
      case 'url':
        this.loadItems(this.component.data.url, null, new Headers(), {
          noToken: true
        });
        break;
    }
  }

  addInput(input, container) {
    super.addInput(input, container, true);
    if (this.component.multiple) {
      input.setAttribute('multiple', true);
    }
    var self = this;
    this.choices = new Choices(input, {
      placeholder: !!this.component.placeholder,
      placeholderValue: this.component.placeholder,
      removeItemButton: true,
      itemSelectText: '',
      classNames: {
        containerOuter: 'choices form-group formio-choices',
        containerInner: 'form-control'
      }
    });
    if (this.disabled) {
      this.choices.disable();
    }
    this.updateItems();
  }

  set disabled(disabled) {
    super.disabled = disabled;
    if (!this.choices) {
      return;
    }
    if (disabled) {
      this.choices.disable();
    }
    else {
      this.choices.enable();
    }
  }

  getValue() {
    if (!this.choices) {
      return;
    }
    return this.choices.getValue(true);
  }

  setValue(value, flags) {
    flags = this.getFlags.apply(this, arguments);
    this.value = value;
    if (this.choices) {
      if (value && this.choices.store) {
        // Search for the choice.
        const choices = this.choices.store.getChoices();
        const foundChoice = choices.find((choice) => {
          // For resources we may have two different instances of the same resource
          // Unify them so we don't have two copies of the same thing in the dropdown
          // and so the correct resource gets selected in the first place
          if (choice.value._id && value._id && choice.value._id === value._id) {
            value = choice.value;
          }
          return choice.value === value;
        });

        // If it is not found, then add it.
        if (!foundChoice) {
          this.choices._addChoice(this.itemValue(value), this.itemTemplate(value));
        }
      }

      // Now set the value.
      if (value) {
        this.choices.setValueByChoice(_isArray(value) ? value : [value]);
      }
      else {
        this.choices.removeActiveItems();
      }
    }
    this.updateValue(flags);
  }

  /**
   * Check if a component is eligible for multiple validation
   *
   * @return {boolean}
   */
  validateMultiple(value) {
    // Select component will contain one input when flagged as multiple.
    return false;
  }

  /**
   * Ouput this select dropdown as a string value.
   * @return {*}
   */
  asString(value) {
    value = value || this.getValue();
    value = (typeof value !== 'object') ? {label: value} : value;
    return this.itemTemplate(value);
  }

  destroy() {
    if (this.choices) {
      this.choices.destroy();
    }
  }
}
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import ReactSelect from 'react-select';
import PropTypes from 'prop-types';
import { IconCloseBadgedSmallFilled, IconChevronDownSmallOutline } from '@teamleader/ui-icons';
import Box, { omitBoxProps, pickBoxProps } from '../box';
import Icon from '../icon';
import ValidationText from '../validationText';
import { COLOR } from '../../constants';
import theme from './theme.css';
import cx from 'classnames';

class Select extends PureComponent {
  getClearIndicatorStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      color: inverse ? COLOR.TEAL.LIGHTEST : COLOR.TEAL.DARK,
      '&:hover': {
        color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      },
      cursor: 'pointer',
      svg: {
        height: '14px',
        width: '14px',
      },
    };
  };

  getControlStyles = (base, { isDisabled, isFocused }) => {
    const { error, inverse, size } = this.props;

    const commonStyles = {
      ...base,
      minHeight: size === 'small' ? '30px' : size === 'medium' ? '36px' : '48px',
    };

    if (inverse) {
      return {
        ...commonStyles,
        backgroundColor: isDisabled ? COLOR.TEAL.DARK : COLOR.TEAL.NORMAL,
        '&:hover': {
          borderColor: error ? COLOR.RUBY.LIGHT : COLOR.TEAL.LIGHT,
        },
        borderColor: error
          ? COLOR.RUBY.LIGHT
          : isFocused
            ? COLOR.TEAL.LIGHT
            : isDisabled
              ? COLOR.TEAL.DARK
              : COLOR.TEAL.NORMAL,
        boxShadow: error ? `0 0 0 1px ${COLOR.RUBY.LIGHT}` : isFocused ? `0 0 0 1px ${COLOR.TEAL.LIGHT}` : 'none',
      };
    }

    return {
      ...commonStyles,
      backgroundColor: isDisabled ? COLOR.NEUTRAL.NORMAL : COLOR.NEUTRAL.LIGHTEST,
      '&:hover': {
        borderColor: error ? COLOR.RUBY.DARK : COLOR.NEUTRAL.DARKEST,
      },
      borderColor: error
        ? COLOR.RUBY.DARK
        : isFocused
          ? COLOR.NEUTRAL.DARKEST
          : isDisabled
            ? COLOR.NEUTRAL.NORMAL
            : COLOR.NEUTRAL.DARK,
      boxShadow: error ? `0 0 0 1px ${COLOR.RUBY.DARK}` : isFocused ? `0 0 0 1px ${COLOR.NEUTRAL.DARKEST}` : 'none',
    };
  };

  getGroupStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      borderBottomColor: inverse ? COLOR.TEAL.LIGHT : COLOR.NEUTRAL.NORMAL,
      borderBottomStyle: 'solid',
      borderBottomWidth: '1px',
      '&:last-child': {
        borderWidth: 0,
      },
    };
  };

  getGroupHeadingStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      fontSize: '12px',
      fontWeight: '700',
      letterSpacing: '0.6px',
      padding: '0 6px',
    };
  };

  getInput = base => {
    const { size, value } = this.props;

    return {
      ...base,
      marginLeft: value && value.length === 0 && size !== 'large' ? '6px' : '2px',
    };
  };

  getMenuStyles = base => ({
    ...base,
    backgroundColor: this.props.inverse ? COLOR.TEAL.NORMAL : COLOR.NEUTRAL.LIGHTEST,
    zIndex: 300,
  });

  getMultiValueStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      borderColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.NORMAL,
      borderStyle: 'solid',
      borderWidth: '1px',
      borderRadius: '4px',
      margin: '1px',
    };
  };

  getMultiValueLabelStyles = base => {
    const { inverse, size } = this.props;

    return {
      ...base,
      backgroundColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.LIGHT,
      borderRadius: 0,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      fontFamily: 'Inter-UI-Medium',
      fontSize: size === 'small' ? '12px' : '14px',
      lineHeight: size === 'small' ? '1' : '18px',
      padding: size === 'large' ? '9px' : '6px',
    };
  };

  getMultiValueRemoveStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      backgroundColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.LIGHT,
      borderRadius: 0,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      '&:hover': {
        backgroundColor: inverse ? COLOR.TEAL.DARKEST : COLOR.NEUTRAL.NORMAL,
        color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      },
      paddingLeft: '6px',
      paddingRight: '6px',
      transition: 'background-color .35s cubic-bezier(.4, 0, .2, 1)',
    };
  };

  getOptionStyles = (base, { isDisabled, isFocused, isSelected }) => {
    const commonStyles = {
      ...base,
      padding: '8px 12px',
    };

    if (this.props.inverse) {
      return {
        ...commonStyles,
        color: isDisabled ? COLOR.TEAL.LIGHT : isFocused ? COLOR.TEAL.DARK : COLOR.NEUTRAL.LIGHTEST,
        backgroundColor: isFocused ? COLOR.TEAL.LIGHT : isSelected ? COLOR.TEAL.DARK : COLOR.TEAL.NORMAL,
        '&:active': {
          backgroundColor: isDisabled ? COLOR.TEAL.NORMAL : COLOR.TEAL.DARK,
        },
      };
    }

    return {
      ...commonStyles,
      color: isDisabled ? COLOR.NEUTRAL.DARK : isSelected && !isFocused ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARK,
      backgroundColor: isFocused ? COLOR.NEUTRAL.NORMAL : isSelected ? COLOR.NEUTRAL.DARKEST : COLOR.NEUTRAL.LIGHTEST,
      '&:active': {
        backgroundColor: isDisabled ? COLOR.NEUTRAL.LIGHTEST : COLOR.NEUTRAL.NORMAL,
      },
    };
  };

  getPlaceholderStyles = (base, { isDisabled, isMulti }) => {
    const { inverse, size } = this.props;

    const commonStyles = {
      ...base,
      marginLeft: isMulti && size !== 'large' ? '6px' : '2px',
      marginRight: isMulti && size !== 'large' ? '6px' : '2px',
    };

    if (inverse) {
      return {
        ...commonStyles,
        color: isDisabled ? COLOR.TEAL.NORMAL : COLOR.TEAL.LIGHT,
      };
    }

    return {
      ...commonStyles,
      color: COLOR.NEUTRAL.DARKEST,
    };
  };

  getSingleValueStyles = base => ({
    ...base,
    color: this.props.inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
  });

  getValueContainerStyles = (base, { isMulti }) => {
    const { size } = this.props;

    return {
      ...base,
      minHeight: size === 'small' ? '28px' : size === 'medium' ? '34px' : '46px',
      padding: isMulti && size !== 'large' ? '0' : '0 4px',
    };
  };

  getStyles = () => ({
    clearIndicator: this.getClearIndicatorStyles,
    control: this.getControlStyles,
    group: this.getGroupStyles,
    groupHeading: this.getGroupHeadingStyles,
    input: this.getInput,
    menu: this.getMenuStyles,
    multiValue: this.getMultiValueStyles,
    multiValueLabel: this.getMultiValueLabelStyles,
    multiValueRemove: this.getMultiValueRemoveStyles,
    option: this.getOptionStyles,
    placeholder: this.getPlaceholderStyles,
    singleValue: this.getSingleValueStyles,
    valueContainer: this.getValueContainerStyles,
  });

  getClearIndicator = () => ({ innerProps }) => {
    const { inverse } = this.props;

    return (
      <Icon color={inverse ? 'teal' : 'neutral'} display="flex" tint={inverse ? 'lightest' : 'darkest'} {...innerProps}>
        <IconCloseBadgedSmallFilled />
      </Icon>
    );
  };

  getDropDownIndicator = () => () => {
    const { inverse } = this.props;

    return (
      <Icon
        alignItems="center"
        className={theme['dropdown-indicator']}
        color={inverse ? 'teal' : 'neutral'}
        display="flex"
        justifyContent="center"
        tint={inverse ? 'lightest' : 'darkest'}
      >
        <IconChevronDownSmallOutline />
      </Icon>
    );
  };

  render() {
    const { components, error, inverse, helpText, size, ...otherProps } = this.props;

    const boxProps = pickBoxProps(otherProps);
    const restProps = omitBoxProps(otherProps);

    const wrapperClassnames = cx(theme[`is-${size}`], {
      [theme['has-error']]: error,
      [theme['is-inverse']]: inverse,
    });

    return (
      <Box className={wrapperClassnames} {...boxProps}>
        <ReactSelect
          className={theme['select']}
          components={{
            ClearIndicator: this.getClearIndicator(),
            DropdownIndicator: this.getDropDownIndicator(),
            IndicatorSeparator: null,
            ...components,
          }}
          styles={this.getStyles()}
          {...restProps}
        />
        <ValidationText error={error} help={helpText} inverse={inverse} />
      </Box>
    );
  }
}

Select.propTypes = {
  /** Override default components with your own. Pass an object with correct the key and its replacing component */
  components: PropTypes.object,
  /** The text string/element to use as error message below the input. */
  error: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
  /** The text string to use as help text below the input. */
  helpText: PropTypes.string,
  /** Boolean indicating whether the select should render as inverse. */
  inverse: PropTypes.bool,
  /** Size of the input element. */
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  /** Selected option value(s) */
  value: PropTypes.oneOfType([PropTypes.object, PropTypes.array, PropTypes.func]),
};

Select.defaultProps = {
  inverse: false,
  size: 'medium',
};

export default Select;
<commit_msg>Add 'creatable' prop and set its default value to false<commit_after>import React, { PureComponent } from 'react';
import ReactSelect from 'react-select';
import PropTypes from 'prop-types';
import { IconCloseBadgedSmallFilled, IconChevronDownSmallOutline } from '@teamleader/ui-icons';
import Box, { omitBoxProps, pickBoxProps } from '../box';
import Icon from '../icon';
import ValidationText from '../validationText';
import { COLOR } from '../../constants';
import theme from './theme.css';
import cx from 'classnames';

class Select extends PureComponent {
  getClearIndicatorStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      color: inverse ? COLOR.TEAL.LIGHTEST : COLOR.TEAL.DARK,
      '&:hover': {
        color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      },
      cursor: 'pointer',
      svg: {
        height: '14px',
        width: '14px',
      },
    };
  };

  getControlStyles = (base, { isDisabled, isFocused }) => {
    const { error, inverse, size } = this.props;

    const commonStyles = {
      ...base,
      minHeight: size === 'small' ? '30px' : size === 'medium' ? '36px' : '48px',
    };

    if (inverse) {
      return {
        ...commonStyles,
        backgroundColor: isDisabled ? COLOR.TEAL.DARK : COLOR.TEAL.NORMAL,
        '&:hover': {
          borderColor: error ? COLOR.RUBY.LIGHT : COLOR.TEAL.LIGHT,
        },
        borderColor: error
          ? COLOR.RUBY.LIGHT
          : isFocused
            ? COLOR.TEAL.LIGHT
            : isDisabled
              ? COLOR.TEAL.DARK
              : COLOR.TEAL.NORMAL,
        boxShadow: error ? `0 0 0 1px ${COLOR.RUBY.LIGHT}` : isFocused ? `0 0 0 1px ${COLOR.TEAL.LIGHT}` : 'none',
      };
    }

    return {
      ...commonStyles,
      backgroundColor: isDisabled ? COLOR.NEUTRAL.NORMAL : COLOR.NEUTRAL.LIGHTEST,
      '&:hover': {
        borderColor: error ? COLOR.RUBY.DARK : COLOR.NEUTRAL.DARKEST,
      },
      borderColor: error
        ? COLOR.RUBY.DARK
        : isFocused
          ? COLOR.NEUTRAL.DARKEST
          : isDisabled
            ? COLOR.NEUTRAL.NORMAL
            : COLOR.NEUTRAL.DARK,
      boxShadow: error ? `0 0 0 1px ${COLOR.RUBY.DARK}` : isFocused ? `0 0 0 1px ${COLOR.NEUTRAL.DARKEST}` : 'none',
    };
  };

  getGroupStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      borderBottomColor: inverse ? COLOR.TEAL.LIGHT : COLOR.NEUTRAL.NORMAL,
      borderBottomStyle: 'solid',
      borderBottomWidth: '1px',
      '&:last-child': {
        borderWidth: 0,
      },
    };
  };

  getGroupHeadingStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      fontSize: '12px',
      fontWeight: '700',
      letterSpacing: '0.6px',
      padding: '0 6px',
    };
  };

  getInput = base => {
    const { size, value } = this.props;

    return {
      ...base,
      marginLeft: value && value.length === 0 && size !== 'large' ? '6px' : '2px',
    };
  };

  getMenuStyles = base => ({
    ...base,
    backgroundColor: this.props.inverse ? COLOR.TEAL.NORMAL : COLOR.NEUTRAL.LIGHTEST,
    zIndex: 300,
  });

  getMultiValueStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      borderColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.NORMAL,
      borderStyle: 'solid',
      borderWidth: '1px',
      borderRadius: '4px',
      margin: '1px',
    };
  };

  getMultiValueLabelStyles = base => {
    const { inverse, size } = this.props;

    return {
      ...base,
      backgroundColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.LIGHT,
      borderRadius: 0,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      fontFamily: 'Inter-UI-Medium',
      fontSize: size === 'small' ? '12px' : '14px',
      lineHeight: size === 'small' ? '1' : '18px',
      padding: size === 'large' ? '9px' : '6px',
    };
  };

  getMultiValueRemoveStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      backgroundColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.LIGHT,
      borderRadius: 0,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      '&:hover': {
        backgroundColor: inverse ? COLOR.TEAL.DARKEST : COLOR.NEUTRAL.NORMAL,
        color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      },
      paddingLeft: '6px',
      paddingRight: '6px',
      transition: 'background-color .35s cubic-bezier(.4, 0, .2, 1)',
    };
  };

  getOptionStyles = (base, { isDisabled, isFocused, isSelected }) => {
    const commonStyles = {
      ...base,
      padding: '8px 12px',
    };

    if (this.props.inverse) {
      return {
        ...commonStyles,
        color: isDisabled ? COLOR.TEAL.LIGHT : isFocused ? COLOR.TEAL.DARK : COLOR.NEUTRAL.LIGHTEST,
        backgroundColor: isFocused ? COLOR.TEAL.LIGHT : isSelected ? COLOR.TEAL.DARK : COLOR.TEAL.NORMAL,
        '&:active': {
          backgroundColor: isDisabled ? COLOR.TEAL.NORMAL : COLOR.TEAL.DARK,
        },
      };
    }

    return {
      ...commonStyles,
      color: isDisabled ? COLOR.NEUTRAL.DARK : isSelected && !isFocused ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARK,
      backgroundColor: isFocused ? COLOR.NEUTRAL.NORMAL : isSelected ? COLOR.NEUTRAL.DARKEST : COLOR.NEUTRAL.LIGHTEST,
      '&:active': {
        backgroundColor: isDisabled ? COLOR.NEUTRAL.LIGHTEST : COLOR.NEUTRAL.NORMAL,
      },
    };
  };

  getPlaceholderStyles = (base, { isDisabled, isMulti }) => {
    const { inverse, size } = this.props;

    const commonStyles = {
      ...base,
      marginLeft: isMulti && size !== 'large' ? '6px' : '2px',
      marginRight: isMulti && size !== 'large' ? '6px' : '2px',
    };

    if (inverse) {
      return {
        ...commonStyles,
        color: isDisabled ? COLOR.TEAL.NORMAL : COLOR.TEAL.LIGHT,
      };
    }

    return {
      ...commonStyles,
      color: COLOR.NEUTRAL.DARKEST,
    };
  };

  getSingleValueStyles = base => ({
    ...base,
    color: this.props.inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
  });

  getValueContainerStyles = (base, { isMulti }) => {
    const { size } = this.props;

    return {
      ...base,
      minHeight: size === 'small' ? '28px' : size === 'medium' ? '34px' : '46px',
      padding: isMulti && size !== 'large' ? '0' : '0 4px',
    };
  };

  getStyles = () => ({
    clearIndicator: this.getClearIndicatorStyles,
    control: this.getControlStyles,
    group: this.getGroupStyles,
    groupHeading: this.getGroupHeadingStyles,
    input: this.getInput,
    menu: this.getMenuStyles,
    multiValue: this.getMultiValueStyles,
    multiValueLabel: this.getMultiValueLabelStyles,
    multiValueRemove: this.getMultiValueRemoveStyles,
    option: this.getOptionStyles,
    placeholder: this.getPlaceholderStyles,
    singleValue: this.getSingleValueStyles,
    valueContainer: this.getValueContainerStyles,
  });

  getClearIndicator = () => ({ innerProps }) => {
    const { inverse } = this.props;

    return (
      <Icon color={inverse ? 'teal' : 'neutral'} display="flex" tint={inverse ? 'lightest' : 'darkest'} {...innerProps}>
        <IconCloseBadgedSmallFilled />
      </Icon>
    );
  };

  getDropDownIndicator = () => () => {
    const { inverse } = this.props;

    return (
      <Icon
        alignItems="center"
        className={theme['dropdown-indicator']}
        color={inverse ? 'teal' : 'neutral'}
        display="flex"
        justifyContent="center"
        tint={inverse ? 'lightest' : 'darkest'}
      >
        <IconChevronDownSmallOutline />
      </Icon>
    );
  };

  render() {
    const { components, error, inverse, helpText, size, ...otherProps } = this.props;

    const boxProps = pickBoxProps(otherProps);
    const restProps = omitBoxProps(otherProps);

    const wrapperClassnames = cx(theme[`is-${size}`], {
      [theme['has-error']]: error,
      [theme['is-inverse']]: inverse,
    });

    return (
      <Box className={wrapperClassnames} {...boxProps}>
        <ReactSelect
          className={theme['select']}
          components={{
            ClearIndicator: this.getClearIndicator(),
            DropdownIndicator: this.getDropDownIndicator(),
            IndicatorSeparator: null,
            ...components,
          }}
          styles={this.getStyles()}
          {...restProps}
        />
        <ValidationText error={error} help={helpText} inverse={inverse} />
      </Box>
    );
  }
}

Select.propTypes = {
  /** Override default components with your own. Pass an object with correct the key and its replacing component */
  components: PropTypes.object,
  /** If true, it*/
  creatable: PropTypes.bool,
  /** The text string/element to use as error message below the input. */
  error: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
  /** The text string to use as help text below the input. */
  helpText: PropTypes.string,
  /** Boolean indicating whether the select should render as inverse. */
  inverse: PropTypes.bool,
  /** Size of the input element. */
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  /** Selected option value(s) */
  value: PropTypes.oneOfType([PropTypes.object, PropTypes.array, PropTypes.func]),
};

Select.defaultProps = {
  creatable: false,
  inverse: false,
  size: 'medium',
};

export default Select;
<|endoftext|>


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

    Socrata.query({
        $select: "location,coordinates,crash_date,day_of_week",
        $limit: Socrata.limit
    }, function (err, result) {

        var data, dimensions, monthNames, dayOfWeekNames, baseLayer,
            clusterLayer, map, updateActiveSectionFilters, redraw,
            chartColor, charts;

     // Hide loader and show map.
        $("#loader").hide();
     // leaflet doesn't work with display: none
        $("#mainframe").css("visibility", "visible");
     // visibility: hidden on mainframe doesn't reach collapse
        $(".collapse.in").css("visibility", "visible");

     // Filter out accidents without location. Socrata doesn't seem
     // to understand `$where=coordinates IS NOT NULL`.
        result = result.filter(function (trafficAccident) {
            return trafficAccident.hasOwnProperty("coordinates");
        });

     // Add data to Crossfilter.
        data = crossfilter(result);

     // Create dimensions (charts and dimensions share the same name).
        dimensions = {};

        dimensions.coordinates = data.dimension(function (record) {
            return [record.coordinates.latitude, record.coordinates.longitude];
        });

        dimensions.year = data.dimension(function (record) {
            var date;
            date = new Date(record.crash_date);
            return date.getFullYear();
        });

        monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
        dimensions.month = data.dimension(function (record) {
            var date;
            date = new Date(record.crash_date);
            return date.getMonth();
        });

        dimensions.day = data.dimension(function (record) {
            var date;
            date = new Date(record.crash_date);
            return date.getDate();
        });

        dayOfWeekNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
        dimensions.dayOfWeek = data.dimension(function (record) {
         // Reformat for sorting.
            return dayOfWeekNames.indexOf(record.day_of_week);
        });

     // Prepare map.
        baseLayer = L.tileLayer('http://{s}.{base}.maps.cit.api.here.com/maptile/2.1/maptile/{mapID}/normal.day/{z}/{x}/{y}/256/png8?app_id={app_id}&app_code={app_code}', {
            attribution: 'Map © 1987-2014 HERE',
            subdomains: '1234',
            mapID: 'newest',
            app_id: 'oBrjPtnB5CZNkvOVmmqw',
            app_code: 'TPBtO9fTES--LhkVo5sKeA',
            base: 'base',
            minZoom: 0,
            maxZoom: 20
        });

        clusterLayer = L.markerClusterGroup({
            singleMarkerMode: true
        });

        map = L.map("map", {
            center: L.latLng(33.5250, -86.8130),
            zoom: 12,
            minZoom: 10,
            layers: [baseLayer, clusterLayer]
        });

        updateActiveSectionFilters = function () {
            $(".active-filters").each(function () {
                var filters, section, sectionCharts;
                filters = [];
                section = $(this).data("filter-section");
                if (section === "date") {
                    sectionCharts = {
                        year: "Year",
                        month: "Month",
                        day: "Day",
                        dayOfWeek: "Day of Week"
                    };
                }
                Object.keys(sectionCharts).forEach(function (chartName) {
                    var chart;
                    chart = charts[chartName];
                    if (chart.hasFilter() === true) {
                        filters.push(sectionCharts[chartName] + ": " + chart.filters().join(", "));
                    }
                });
                if (filters.length > 0) {
                    $(this).html(" | " + filters.join("; "));
                } else {
                    $(this).html("");
                }
            });
        };

        redraw = function () {
            clusterLayer.clearLayers();
            dimensions.coordinates.top(Infinity).forEach(function (record) {
                var mark;
                mark = L.marker([record.coordinates.latitude, record.coordinates.longitude]);
                clusterLayer.addLayer(mark);
            });
        };

        chartColor = d3.scale.ordinal().range(["#44afe1"]);

     // Prepare charts (charts and dimensions share the same name).
        charts = {};

        charts.year = dc.pieChart("#year-selector");
        charts.year.dimension(dimensions.year)
                   .group(dimensions.year.group())
                   .title(function (d) {
                       return d.value;
                    })
                   .colors(chartColor)
                   .on("filtered", function () {
                       updateActiveSectionFilters();
                       redraw();
                    });

        charts.month = dc.rowChart("#month-selector");
        charts.month.height(336)
                    .dimension(dimensions.month)
                    .group(dimensions.month.group())
                    .elasticX(true)
                    .label(function (d) {
                        return monthNames[d.key].substr(0, 3);
                     })
                    .title(function (d) {
                        return d.value;
                     })
                    .colors(chartColor)
                    .margins({
                        top: 0,
                        left: 5,
                        bottom: 30,
                        right: 10
                     })
                    .on("filtered", function () {
                        updateActiveSectionFilters();
                        redraw();
                     });
        charts.month.xAxis().ticks(4);

        charts.day = dc.rowChart("#day-selector");
        charts.day.height(868)
                  .dimension(dimensions.day)
                  .group(dimensions.day.group())
                  .elasticX(true)
                  .label(function (d) {
                      return d.key;
                   })
                  .title(function (d) {
                      return d.value;
                   })
                  .colors(chartColor)
                  .margins({
                      top: 0,
                      left: 5,
                      bottom: 30,
                      right: 10
                   })
                  .on("filtered", function () {
                      updateActiveSectionFilters();
                      redraw();
                   });
        charts.day.xAxis().ticks(4);

        charts.dayOfWeek = dc.rowChart("#day-of-week-selector");
        charts.dayOfWeek.dimension(dimensions.dayOfWeek)
                        .group(dimensions.dayOfWeek.group())
                        .elasticX(true)
                        .label(function (d) {
                            return dayOfWeekNames[d.key].substr(0, 3);
                         })
                        .title(function (d) {
                            return d.value;
                         })
                        .colors(chartColor)
                        .margins({
                            top: 0,
                            left: 5,
                            bottom: 30,
                            right: 10
                         })
                        .on("filtered", function () {
                            updateActiveSectionFilters();
                            redraw();
                         });
        charts.dayOfWeek.xAxis().ticks(4);

     // Prepare reset buttons.
        $(".chart a").on("click", function () {
            var chart;
            chart = $(this).data("chart");
            charts[chart].filterAll();
            dc.redrawAll();
        });

        redraw();
        dc.renderAll();

    });

}());
<commit_msg>Start with 2014 because clustering markers is slow.<commit_after>(function () {
    "use strict";

    Socrata.query({
        $select: "location,coordinates,crash_date,day_of_week",
        $limit: Socrata.limit
    }, function (err, result) {

        var data, dimensions, monthNames, dayOfWeekNames, baseLayer,
            clusterLayer, map, updateActiveSectionFilters, redraw,
            chartColor, charts;

     // Hide loader and show map.
        $("#loader").hide();
     // leaflet doesn't work with display: none
        $("#mainframe").css("visibility", "visible");
     // visibility: hidden on mainframe doesn't reach collapse
        $(".collapse.in").css("visibility", "visible");

     // Filter out accidents without location. Socrata doesn't seem
     // to understand `$where=coordinates IS NOT NULL`.
        result = result.filter(function (trafficAccident) {
            return trafficAccident.hasOwnProperty("coordinates");
        });

     // Add data to Crossfilter.
        data = crossfilter(result);

     // Create dimensions (charts and dimensions share the same name).
        dimensions = {};

        dimensions.coordinates = data.dimension(function (record) {
            return [record.coordinates.latitude, record.coordinates.longitude];
        });

        dimensions.year = data.dimension(function (record) {
            var date;
            date = new Date(record.crash_date);
            return date.getFullYear();
        });

        monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
        dimensions.month = data.dimension(function (record) {
            var date;
            date = new Date(record.crash_date);
            return date.getMonth();
        });

        dimensions.day = data.dimension(function (record) {
            var date;
            date = new Date(record.crash_date);
            return date.getDate();
        });

        dayOfWeekNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
        dimensions.dayOfWeek = data.dimension(function (record) {
         // Reformat for sorting.
            return dayOfWeekNames.indexOf(record.day_of_week);
        });

     // Prepare map.
        baseLayer = L.tileLayer('http://{s}.{base}.maps.cit.api.here.com/maptile/2.1/maptile/{mapID}/normal.day/{z}/{x}/{y}/256/png8?app_id={app_id}&app_code={app_code}', {
            attribution: 'Map © 1987-2014 HERE',
            subdomains: '1234',
            mapID: 'newest',
            app_id: 'oBrjPtnB5CZNkvOVmmqw',
            app_code: 'TPBtO9fTES--LhkVo5sKeA',
            base: 'base',
            minZoom: 0,
            maxZoom: 20
        });

        clusterLayer = L.markerClusterGroup({
            singleMarkerMode: true
        });

        map = L.map("map", {
            center: L.latLng(33.5250, -86.8130),
            zoom: 12,
            minZoom: 10,
            layers: [baseLayer, clusterLayer]
        });

        updateActiveSectionFilters = function () {
            $(".active-filters").each(function () {
                var filters, section, sectionCharts;
                filters = [];
                section = $(this).data("filter-section");
                if (section === "date") {
                    sectionCharts = {
                        year: "Year",
                        month: "Month",
                        day: "Day",
                        dayOfWeek: "Day of Week"
                    };
                }
                Object.keys(sectionCharts).forEach(function (chartName) {
                    var chart;
                    chart = charts[chartName];
                    if (chart.hasFilter() === true) {
                        filters.push(sectionCharts[chartName] + ": " + chart.filters().join(", "));
                    }
                });
                if (filters.length > 0) {
                    $(this).html(" | " + filters.join("; "));
                } else {
                    $(this).html("");
                }
            });
        };

        redraw = function () {
            clusterLayer.clearLayers();
            dimensions.coordinates.top(Infinity).forEach(function (record) {
                var mark;
                mark = L.marker([record.coordinates.latitude, record.coordinates.longitude]);
                clusterLayer.addLayer(mark);
            });
        };

        chartColor = d3.scale.ordinal().range(["#44afe1"]);

     // Prepare charts (charts and dimensions share the same name).
        charts = {};

        charts.year = dc.pieChart("#year-selector");
        charts.year.dimension(dimensions.year)
                   .group(dimensions.year.group())
                   .title(function (d) {
                       return d.value;
                    })
                   .colors(chartColor)
                   .on("filtered", function () {
                       updateActiveSectionFilters();
                       redraw();
                    });

        charts.month = dc.rowChart("#month-selector");
        charts.month.height(336)
                    .dimension(dimensions.month)
                    .group(dimensions.month.group())
                    .elasticX(true)
                    .label(function (d) {
                        return monthNames[d.key].substr(0, 3);
                     })
                    .title(function (d) {
                        return d.value;
                     })
                    .colors(chartColor)
                    .margins({
                        top: 0,
                        left: 5,
                        bottom: 30,
                        right: 10
                     })
                    .on("filtered", function () {
                        updateActiveSectionFilters();
                        redraw();
                     });
        charts.month.xAxis().ticks(4);

        charts.day = dc.rowChart("#day-selector");
        charts.day.height(868)
                  .dimension(dimensions.day)
                  .group(dimensions.day.group())
                  .elasticX(true)
                  .label(function (d) {
                      return d.key;
                   })
                  .title(function (d) {
                      return d.value;
                   })
                  .colors(chartColor)
                  .margins({
                      top: 0,
                      left: 5,
                      bottom: 30,
                      right: 10
                   })
                  .on("filtered", function () {
                      updateActiveSectionFilters();
                      redraw();
                   });
        charts.day.xAxis().ticks(4);

        charts.dayOfWeek = dc.rowChart("#day-of-week-selector");
        charts.dayOfWeek.dimension(dimensions.dayOfWeek)
                        .group(dimensions.dayOfWeek.group())
                        .elasticX(true)
                        .label(function (d) {
                            return dayOfWeekNames[d.key].substr(0, 3);
                         })
                        .title(function (d) {
                            return d.value;
                         })
                        .colors(chartColor)
                        .margins({
                            top: 0,
                            left: 5,
                            bottom: 30,
                            right: 10
                         })
                        .on("filtered", function () {
                            updateActiveSectionFilters();
                            redraw();
                         });
        charts.dayOfWeek.xAxis().ticks(4);

     // Prepare reset buttons.
        $(".chart a").on("click", function () {
            var chart;
            chart = $(this).data("chart");
            charts[chart].filterAll();
            dc.redrawAll();
        });

     // Start with 2014 because clustering markers is slow.
        charts.year.filter(2014);

        redraw();
        dc.renderAll();

    });

}());
<|endoftext|>


<commit_before>define(function (require) {

  var Marionette = require('marionette');
  var ModuleView = require('wasabi.cms.package/components/module-dialog/views/ModuleView');

  return Marionette.CollectionView.extend({

    className: 'modules row',

    childView: ModuleView,

    initialize: function(options) {
      this.$contentContainer = options.$contentContainer;
      this.moduleDialogModel = options.moduleDialogModel;
      this.moduleDialogModel.on('change', this.render);
    },

    filter: function(child, index, collection) {
      var search = this.moduleDialogModel.get('search');
      var group = this.moduleDialogModel.get('group');

      if (search === '' && group === null) {
        return true;
      } else if (search !== '' && group === null) {
        if (child.get('name').toLowerCase().indexOf(search.toLowerCase()) > 0) {
          return true;
        }
      } else if (search === '' && group !== null) {
        if (child.get('group') === group) {
          return true;
        }
      } else if (search !== '' && group !== null) {
        if (child.get('name').toLowerCase().indexOf(search.toLowerCase()) > 0 && child.get('group') === group) {
          return true;
        }
      }

      return false;
    },

    onRender: function() {
      this.$contentContainer.append(this.$el)
    }

  });

});
<commit_msg>fix module dialog input filter<commit_after>define(function (require) {

  var Marionette = require('marionette');
  var ModuleView = require('wasabi.cms.package/components/module-dialog/views/ModuleView');

  return Marionette.CollectionView.extend({

    className: 'modules row',

    childView: ModuleView,

    initialize: function(options) {
      this.$contentContainer = options.$contentContainer;
      this.moduleDialogModel = options.moduleDialogModel;
      this.moduleDialogModel.on('change', this.render);
    },

    filter: function(child, index, collection) {
      var search = this.moduleDialogModel.get('search');
      var group = this.moduleDialogModel.get('group');

      if (search === '' && group === null) {
        return true;
      } else if (search !== '' && group === null) {
        if (child.get('name').toLowerCase().indexOf(search.toLowerCase()) !== -1) {
          return true;
        }
      } else if (search === '' && group !== null) {
        if (child.get('group') === group) {
          return true;
        }
      } else if (search !== '' && group !== null) {
        if (child.get('name').toLowerCase().indexOf(search.toLowerCase()) !== -1 && child.get('group') === group) {
          return true;
        }
      }

      return false;
    },

    onRender: function() {
      this.$contentContainer.append(this.$el)
    }

  });

});
<|endoftext|>


<commit_before>import Nav from '../ui/nav'
import Link from '../ui/link'
import Grid from '../ui/grid'
import Hexagon from '../ui/hexagon'

const Footer = () => (

      <Hexagon width={18} fill='#05a5b4' position={{bottom: '90px', left: '-40px'}} />
      <Hexagon width={48} fill='#b4f1d9' position={{bottom: '90px', right: '15%'}} />
      <Hexagon width={78} fill='#b4f1d9' position={{bottom: '-20px', left: '20%'}} opacity='.5' />
      <Hexagon width={32} fill='#b4f1d9' position={{top: '40px', right: '-5%'}} />
      <Hexagon width={32} fill='#05a5b4' position={{bottom: '-20px', right: '-8%'}} />

      <Grid wrap>

Company

            <Link to="/terms-of-service">
              Terms of Service
            </Link>
            <Link to="/privacy-policy">
              Privacy Policy
            </Link>
            <Link to="/privacy-shield">
              Privacy Shield
            </Link>

Product

            <Link to="/features">
              Features
            </Link>
            <Link to="/pricing">
              Plans & Pricing
            </Link>
            Help & Status

Resources

            Quickstart
            Documentation
            Libraries

        {/*

For developers

            iOS developers
            Android developers
            Web developers
            React developers

 */}
        {/*

More

            For Investors
            For Enterprise
            Our team
            Case studies

 */}

Connect

            Twitter
            Github
            Facebook
            LinkedIn
            Dribbble
            Contact us

      </Grid>

© 2017 by Syncano. All rights reserved.

)

export default Footer
<commit_msg>fix(component): invalid PS link<commit_after>import Nav from '../ui/nav'
import Link from '../ui/link'
import Grid from '../ui/grid'
import Hexagon from '../ui/hexagon'

const Footer = () => (

      <Hexagon width={18} fill='#05a5b4' position={{bottom: '90px', left: '-40px'}} />
      <Hexagon width={48} fill='#b4f1d9' position={{bottom: '90px', right: '15%'}} />
      <Hexagon width={78} fill='#b4f1d9' position={{bottom: '-20px', left: '20%'}} opacity='.5' />
      <Hexagon width={32} fill='#b4f1d9' position={{top: '40px', right: '-5%'}} />
      <Hexagon width={32} fill='#05a5b4' position={{bottom: '-20px', right: '-8%'}} />

      <Grid wrap>

Company

            <Link to="/terms-of-service">
              Terms of Service
            </Link>
            <Link to="/privacy-policy">
              Privacy Policy
            </Link>

              Privacy Shield

Product

            <Link to="/features">
              Features
            </Link>
            <Link to="/pricing">
              Plans & Pricing
            </Link>
            Help & Status

Resources

            Quickstart
            Documentation
            Libraries

        {/*

For developers

            iOS developers
            Android developers
            Web developers
            React developers

 */}
        {/*

More

            For Investors
            For Enterprise
            Our team
            Case studies

 */}

Connect

            Twitter
            Github
            Facebook
            LinkedIn
            Dribbble
            Contact us

      </Grid>

© 2017 by Syncano. All rights reserved.

)

export default Footer
<|endoftext|>


<commit_before>(function(analyzer) {
	var colors = ['#FF812D', '#FFD100', '#81D733'];

	function extractPartialData(dataSeries, key) {
		var array = new Array();
		for (var i = 0; i < dataSeries.length; i++) {
			array.push(dataSeries[i][key]);
		}
		return array;
	};

	function colorizeBars(dataSeries) {
		var array = new Array();
		for (var i = 0; i < dataSeries.length; i++) {
			array.push({'y':dataSeries[i], 'color':colors[i]});
		}
		return array;
	}

	analyzer.showRenderingPerformace = function(divId, dataSeries) {
		$('#' + divId).highcharts({
	        chart: {
	            type: 'bar',
	            width: 800
	        },
	        title: {
	            text: 'Rendering Performance Test Result'
	        },
	        xAxis: {
	            categories: extractPartialData(dataSeries, 'name'),
	            title: {
	                text: null
	            }
	        },
	        yAxis: {
	            min: 0,
	            title: {
	                text: 'Time (miliseconds)',
	                align: 'high'
	            },
	            labels: {
	                overflow: 'justify'
	            }
	        },
	        plotOptions: {
	            bar: {
	                dataLabels: {
	                    enabled: true
	                }
	            }
	        },
	        credits: {
	            enabled: false
	        },
	        series: [{
	            name: 'Rendering',
	            data: colorizeBars(extractPartialData(dataSeries, 'grade'))
	        }]
	    });
	};

	analyzer.showUX = function(divId, dataSeries) {
		$('#' + divId).highcharts({
	        chart: {
	            type: 'bar',
	            width: 800
	        },
	        title: {
	            text: 'Developer Experience'
	        },
	        xAxis: {
	            categories: extractPartialData(dataSeries, 'name'),
	            title: {
	                text: null
	            }
	        },
	        yAxis: {
	            min: 0,
	            title: {
	                text: 'DX Grade [0 - 10]',
	                align: 'high'
	            },
	            labels: {
	                overflow: 'justify'
	            }
	        },
	        plotOptions: {
	            bar: {
	                dataLabels: {
	                    enabled: true
	                }
	            }
	        },
	        credits: {
	            enabled: false
	        },
	        series: [{
	            name: 'Developer Experience',
	            data: colorizeBars(extractPartialData(dataSeries, 'usability'))
	        }]
	    });
	};
})(window.analyzer = window.analyzer || {});<commit_msg>Use 'Impression Grade'<commit_after>(function(analyzer) {
	var colors = ['#FF812D', '#FFD100', '#81D733'];

	function extractPartialData(dataSeries, key) {
		var array = new Array();
		for (var i = 0; i < dataSeries.length; i++) {
			array.push(dataSeries[i][key]);
		}
		return array;
	};

	function colorizeBars(dataSeries) {
		var array = new Array();
		for (var i = 0; i < dataSeries.length; i++) {
			array.push({'y':dataSeries[i], 'color':colors[i]});
		}
		return array;
	}

	analyzer.showRenderingPerformace = function(divId, dataSeries) {
		$('#' + divId).highcharts({
	        chart: {
	            type: 'bar',
	            width: 800
	        },
	        title: {
	            text: 'Rendering Performance Test Result'
	        },
	        xAxis: {
	            categories: extractPartialData(dataSeries, 'name'),
	            title: {
	                text: null
	            }
	        },
	        yAxis: {
	            min: 0,
	            title: {
	                text: 'Time (miliseconds)',
	                align: 'high'
	            },
	            labels: {
	                overflow: 'justify'
	            }
	        },
	        plotOptions: {
	            bar: {
	                dataLabels: {
	                    enabled: true
	                }
	            }
	        },
	        credits: {
	            enabled: false
	        },
	        series: [{
	            name: 'Rendering',
	            data: colorizeBars(extractPartialData(dataSeries, 'grade'))
	        }]
	    });
	};

	analyzer.showUX = function(divId, dataSeries) {
		$('#' + divId).highcharts({
	        chart: {
	            type: 'bar',
	            width: 800
	        },
	        title: {
	            text: 'Developer Experience'
	        },
	        xAxis: {
	            categories: extractPartialData(dataSeries, 'name'),
	            title: {
	                text: null
	            }
	        },
	        yAxis: {
	            min: 0,
	            title: {
	                text: 'Impression Grade [0 - 10]',
	                align: 'high'
	            },
	            labels: {
	                overflow: 'justify'
	            }
	        },
	        plotOptions: {
	            bar: {
	                dataLabels: {
	                    enabled: true
	                }
	            }
	        },
	        credits: {
	            enabled: false
	        },
	        series: [{
	            name: 'Developer Experience',
	            data: colorizeBars(extractPartialData(dataSeries, 'usability'))
	        }]
	    });
	};
})(window.analyzer = window.analyzer || {});<|endoftext|>


<commit_before>export { Bounds, ScaleTranslate };

/**
 * Describe the [ lower, upper ] bounds of a floating-point value
 *
 * @member {number} lower
 *   The lower bound of the range.
 *
 * @member {number} upper
 *   The upper bound of the range.
 *
 * @member {number} difference
 *   The distance between lower and upper.
 */
class Bounds {

  constructor( lower, upper ) {
    this.lower = Math.min( lower, upper ); // Confirm ( lower <= upper ).
    this.upper = Math.max( lower, upper );
  }

  get difference() {
    let difference = this.upper - this.lower;
    return difference;
  }

  /**
   * Confirm:
   *   - Every element is not NaN. (If it is, become 0.)
   *   - Every element is between [ lower, upper ].
   *
   * @param {Float32Array} source
   *   The source Float32Array.
   *
   * @return {Float32Array}
   *   Return a copy of source. Every element (float32):
   *     - If ( Number.isNaN( element ) == true ), let it become 0.
   *     - Otherwise, Math.max( lower, Math.min( element, upper ) ).
   */
  Float32Array_RestrictedClone( sourceArray ) {
    let resultArray = new Float32Array( sourceArray.length );
    for ( let i = 0; i < sourceArray.length; ++i ) {
      let element = sourceArray[ i ];
      if ( !Number.isNaN( element ) ) {
        resultArray[ i ] = Math.max( this.lower, Math.min( element, this.upper ) );
      } // If NaN, let it become 0. (Just do nothing, because Float32Array is initialized to zero by default.)
    }
    return resultArray;
  }

  /**
   * @param {Bounds} aBounds
   *   Multiply this Bounds by aBounds.
   *
   * @return {Bounds}
   *   Return this (modified) object which is multiplied by aBounds.
   */
  set_multiply_Bounds( aBounds ) {
    this.lower *= aBounds.lower;
    this.upper *= aBounds.upper;
    return this;
  }

  /**
   * @param {number} aLower
   *   Multiply this Bounds.lower by aLower.
   *
   * @param {number} aUpper
   *   Multiply this Bounds.upper by aUpper.
   *
   * @return {Bounds}
   *   Return this (modified) object which is multiplied by Bounds [ aLower, aUpper ].
   */
  set_multiply_LowerUpper( aLower, aUpper ) {
    this.lower *= aLower;
    this.upper *= aUpper;
    return this;
  }

//!!! ...unfinished... (2021/12/09) When to use?
//   /**
//    * @param {number} N
//    *   The multiplier of this.lower and this.upper.
//    *
//    * @return {Bounds}
//    *   Return this (modified) object whose this.lower and this.upper are multiplied by N.
//    */
//   set_multiply_N( N ) {
//     this.lower *= N;
//     this.upper *= N;
//     return this;
//   }

  /**
   * @param {Bounds} aBounds
   *   Add this Bounds by aBounds.
   *
   * @return {Bounds}
   *   Return this (modified) object which is added by aBounds.
   */
  set_add_Bounds( aBounds ) {
    this.lower += aBounds.lower;
    this.upper += aBounds.upper;
    return this;
  }

  /**
   * @param {number} aLower
   *   Add this Bounds.lower by aLower.
   *
   * @param {number} aUpper
   *   Add this Bounds.upper by aUpper.
   *
   * @return {Bounds}
   *   Return this (modified) object which is added by Bounds [ aLower, aUpper ].
   */
  set_add_LowerUpper( aLower, aUpper ) {
    this.lower += aLower;
    this.upper += aUpper;
    return this;
  }

  /**
   * @param {Bounds} aBounds
   *   The multiplicand (i.e. first) Bounds.
   *
   * @param {Bounds} bBounds
   *   The multiplier (i.e. second) Bounds.
   *
   * @param {number} N
   *   How many times to repeat the multiplying.
   *
   * @return {Bounds}
   *   Return newly created object representing the sumed Bounds of repeating N times of multiplying aBounds by bBounds.
   */
  static new_Bounds_multiply_Bounds_repeat_N( aBounds, bBounds, N ) {
    let lower = ( aBounds.lower * bBounds.lower ) * N;
    let upper = ( aBounds.upper * bBounds.upper ) * N;
    return new Bounds( lower, upper );
  }

//!!! ...unfinished... (2021/12/09)

}

/**
 * Describe a scale (i.e. multiplier) value, and then a translate (i.e. offset; bias) value after the scale.
 *
 */
class ScaleTranslate {

  constructor( scale, translate ) {
    this.scale = scale;
    this.translate = translate;
  }

  /**
   * Set this.scale and this.translate for mapping values from source bounds to target bounds.
   *
   * @param {Bounds} source
   *   The range of the source value.
   *
   * @param {Bounds} target
   *   The range of the target value.
   */
  setBy_FromTo( source, target ) {
    // Suppose x is a value inside the source range. y is the corresponding value inside the target range.
    //
    //   y = target.lower + ( target.difference * ( x - source.lower ) / source.difference )
    //     = target.lower + ( ( ( target.difference * x ) - ( target.difference * source.lower ) ) / source.difference )
    //     = target.lower + ( ( ( target.difference * x ) / source.difference ) - ( ( target.difference * source.lower ) / source.difference ) )
    //     = target.lower + ( ( ( target.difference / source.difference ) * x ) - ( ( target.difference * source.lower ) / source.difference ) )
    //     = target.lower + ( ( target.difference / source.difference ) * x ) - ( ( target.difference * source.lower ) / source.difference )
    //     = ( ( target.difference / source.difference ) * x ) + ( target.lower - ( ( target.difference * source.lower ) / source.difference ) )
    //     = ( scale * x ) + translate
    //
    // Got:
    //   scale = ( target.difference / source.difference )
    //   translate = ( target.lower - ( ( target.difference * source.lower ) / source.difference ) )
    //             = ( target.lower - ( ( target.difference / source.difference ) * source.lower ) )
    //             = ( target.lower - ( scale * source.lower ) )
    //
    // For example:
    //   - from [ 2, 12 ] to [ -3, -1 ]
    //   - scale  = 0.2
    //   - translate = -3.4
    //
    this.scale = ( target.difference / source.difference );
    this.translate = ( target.lower - ( this.scale * source.lower ) );
  }

  /**
   * @param {Bounds} source
   *   The range of the source value.
   *
   * @param {Bounds} target
   *   The range of the target value.
   *
   * @return {ScaleTranslate}
   *   Create and return { scale, translate } for mapping values from sourceMinMax to targetMinMax.
   */
  static createBy_FromTo( source, target ) {
    // (Please see ScaleTranslate.setBy_FromTo().)
    let scale = ( target.difference / source.difference );
    let translate = ( target.lower - ( scale * source.lower ) );
    let result = new ScaleTranslate( scale, translate );
    return result;
  }

}

<commit_msg>Update FloatValue.js<commit_after>export { Bounds, ScaleTranslate };

/**
 * Describe the [ lower, upper ] bounds of a floating-point value
 *
 * @member {number} lower
 *   The lower bound of the range.
 *
 * @member {number} upper
 *   The upper bound of the range.
 *
 * @member {number} difference
 *   The distance between lower and upper.
 */
class Bounds {

  constructor( lower, upper ) {
    this.lower = Math.min( lower, upper ); // Confirm ( lower <= upper ).
    this.upper = Math.max( lower, upper );
  }

  get difference() {
    let difference = this.upper - this.lower;
    return difference;
  }

  /**
   * Confirm:
   *   - Every element is not NaN. (If it is, become 0.)
   *   - Every element is between [ lower, upper ].
   *
   * @param {Float32Array} source
   *   The source Float32Array.
   *
   * @return {Float32Array}
   *   Return a copy of source. Every element (float32):
   *     - If ( Number.isNaN( element ) == true ), let it become 0.
   *     - Otherwise, Math.max( lower, Math.min( element, upper ) ).
   */
  Float32Array_RestrictedClone( sourceArray ) {
    let resultArray = new Float32Array( sourceArray.length );
    for ( let i = 0; i < sourceArray.length; ++i ) {
      let element = sourceArray[ i ];
      if ( !Number.isNaN( element ) ) {
        resultArray[ i ] = Math.max( this.lower, Math.min( element, this.upper ) );
      } // If NaN, let it become 0. (Just do nothing, because Float32Array is initialized to zero by default.)
    }
    return resultArray;
  }

  /**
   * @return {Bounds}
   *   Return newly created object which is a copy of this Bounds.
   */
  clone() {
    return new Bounds( this.lower, this.upper );
  }

  /**
   * @param {Bounds} aBounds
   *   Multiply this Bounds by aBounds.
   *
   * @return {Bounds}
   *   Return this (modified) object which is multiplied by aBounds.
   */
  set_multiply_Bounds( aBounds ) {
    this.lower *= aBounds.lower;
    this.upper *= aBounds.upper;
    return this;
  }

  /**
   * @param {number} aLower
   *   Multiply this Bounds.lower by aLower.
   *
   * @param {number} aUpper
   *   Multiply this Bounds.upper by aUpper.
   *
   * @return {Bounds}
   *   Return this (modified) object which is multiplied by Bounds [ aLower, aUpper ].
   */
  set_multiply_LowerUpper( aLower, aUpper ) {
    this.lower *= aLower;
    this.upper *= aUpper;
    return this;
  }

  /**
   * @param {number} N
   *   The multiplier of this.lower and this.upper.
   *
   * @return {Bounds}
   *   Return this (modified) object which is the same as repeating N times this.set_add_Bounds( this ).
   */
  set_multiply_N( N ) {
    this.lower *= N;
    this.upper *= N;
    return this;
  }

  /**
   * @param {Bounds} aBounds
   *   Add this Bounds by aBounds.
   *
   * @return {Bounds}
   *   Return this (modified) object which is added by aBounds.
   */
  set_add_Bounds( aBounds ) {
    this.lower += aBounds.lower;
    this.upper += aBounds.upper;
    return this;
  }

  /**
   * @param {number} aLower
   *   Add this Bounds.lower by aLower.
   *
   * @param {number} aUpper
   *   Add this Bounds.upper by aUpper.
   *
   * @return {Bounds}
   *   Return this (modified) object which is added by Bounds [ aLower, aUpper ].
   */
  set_add_LowerUpper( aLower, aUpper ) {
    this.lower += aLower;
    this.upper += aUpper;
    return this;
  }

  /**
   * @param {Bounds} aBounds
   *   The multiplicand (i.e. first) Bounds.
   *
   * @param {Bounds} bBounds
   *   The multiplier (i.e. second) Bounds.
   *
   * @param {number} N
   *   How many times to repeat the multiplying.
   *
   * @return {Bounds}
   *   Return newly created object representing the sumed Bounds of repeating N times of multiplying aBounds by bBounds.
   */
  static new_Bounds_multiply_Bounds_repeat_N( aBounds, bBounds, N ) {
    let lower = ( aBounds.lower * bBounds.lower ) * N;
    let upper = ( aBounds.upper * bBounds.upper ) * N;
    return new Bounds( lower, upper );

    // The same as:
    //return aBounds.clone().set_multiply_Bounds( bBounds ).set_multiply_N( N );
  }

//!!! ...unfinished... (2021/12/09)

}

/**
 * Describe a scale (i.e. multiplier) value, and then a translate (i.e. offset; bias) value after the scale.
 *
 */
class ScaleTranslate {

  constructor( scale, translate ) {
    this.scale = scale;
    this.translate = translate;
  }

  /**
   * Set this.scale and this.translate for mapping values from source bounds to target bounds.
   *
   * @param {Bounds} source
   *   The range of the source value.
   *
   * @param {Bounds} target
   *   The range of the target value.
   */
  setBy_FromTo( source, target ) {
    // Suppose x is a value inside the source range. y is the corresponding value inside the target range.
    //
    //   y = target.lower + ( target.difference * ( x - source.lower ) / source.difference )
    //     = target.lower + ( ( ( target.difference * x ) - ( target.difference * source.lower ) ) / source.difference )
    //     = target.lower + ( ( ( target.difference * x ) / source.difference ) - ( ( target.difference * source.lower ) / source.difference ) )
    //     = target.lower + ( ( ( target.difference / source.difference ) * x ) - ( ( target.difference * source.lower ) / source.difference ) )
    //     = target.lower + ( ( target.difference / source.difference ) * x ) - ( ( target.difference * source.lower ) / source.difference )
    //     = ( ( target.difference / source.difference ) * x ) + ( target.lower - ( ( target.difference * source.lower ) / source.difference ) )
    //     = ( scale * x ) + translate
    //
    // Got:
    //   scale = ( target.difference / source.difference )
    //   translate = ( target.lower - ( ( target.difference * source.lower ) / source.difference ) )
    //             = ( target.lower - ( ( target.difference / source.difference ) * source.lower ) )
    //             = ( target.lower - ( scale * source.lower ) )
    //
    // For example:
    //   - from [ 2, 12 ] to [ -3, -1 ]
    //   - scale  = 0.2
    //   - translate = -3.4
    //
    this.scale = ( target.difference / source.difference );
    this.translate = ( target.lower - ( this.scale * source.lower ) );
  }

  /**
   * @param {Bounds} source
   *   The range of the source value.
   *
   * @param {Bounds} target
   *   The range of the target value.
   *
   * @return {ScaleTranslate}
   *   Create and return { scale, translate } for mapping values from sourceMinMax to targetMinMax.
   */
  static createBy_FromTo( source, target ) {
    // (Please see ScaleTranslate.setBy_FromTo().)
    let scale = ( target.difference / source.difference );
    let translate = ( target.lower - ( scale * source.lower ) );
    let result = new ScaleTranslate( scale, translate );
    return result;
  }

}

<|endoftext|>


<commit_before>var BPromise = require("bluebird");
var devip    = require("dev-ip");
var fs       = require("fs");
var R        = require("ramda");

var getIp = function () {
    return R.find(function (ip) {
        return (
            ip.slice(0, 3) === "192" ||
            ip.slice(0, 2) === "10"
        );
    }, devip());
};

function getEnvirnomentVariables () {
    return {
        READ_BACKEND_ENDPOINT: process.env.READ_BACKEND_ENDPOINT || `ws://${getIp()}:3000/websocket`,
        WRITE_API_ENDPOINT: process.env.WRITE_API_ENDPOINT || getIp() + ":3000"
    };
}

BPromise.resolve()
    .then(() => {
        const variables = getEnvirnomentVariables();
        var env = Object.keys(variables)
            .map(key => `${key}=${variables[key]}`)
            .join("\n");
        fs.writeFileSync(".env", env, "utf8");
    });
<commit_msg>add test endpoint on config<commit_after>var BPromise = require("bluebird");
var devip    = require("dev-ip");
var fs       = require("fs");
var R        = require("ramda");

var getIp = function () {
    return R.find(function (ip) {
        return (
            ip.slice(0, 3) === "192" ||
            ip.slice(0, 2) === "10"
        );
    }, devip());
};

function getEnvirnomentVariables () {

        // READ_BACKEND_ENDPOINT: "wss://iwwa-back-development.innowatio-aws.com/websocket",
        // WRITE_API_ENDPOINT: "iwwa-write-api-development.eu-west-1.elasticbeanstalk.com"

    return {
        READ_BACKEND_ENDPOINT: process.env.READ_BACKEND_ENDPOINT || `ws://${getIp()}:3000/websocket`,
        WRITE_API_ENDPOINT: process.env.WRITE_API_ENDPOINT || getIp() + ":3000"
    };
}

BPromise.resolve()
    .then(() => {
        const variables = getEnvirnomentVariables();
        var env = Object.keys(variables)
            .map(key => `${key}=${variables[key]}`)
            .join("\n");
        fs.writeFileSync(".env", env, "utf8");
    });
<|endoftext|>


<commit_before>/** @ignore */
const apiKey = require('../../config/config.json').YOUTUBEAPIKEY;
const ytPI         = require('simple-youtube-api');
const videoFetcher = new ytPI(apiKey);
const sf = require('snekfetch');
async function fetchSongData(client, msg, toSearch) {

  /**
  * @param {String} toSearch Getting the right video to play
  * @param {String} apiKey getting access to the data
  * @returns {Promise}
  * @returns {Error}
  */

  let data = await sf.get(`https://www.googleapis.com/youtube/v3/search?part=id&type=video&q=` + encodeURIComponent(toSearch) + '&key=' + apiKey);
  try {
    return(data.body.items[0].id.videoId);
  } catch (e) {
    msg.reply('We could not find the current song.');
  }
}

module.exports = fetchSongData;
<commit_msg>Code style<commit_after>/** @ignore */
const apiKey          = require('../../config/config.json').YOUTUBEAPIKEY;
const ytPI            = require('simple-youtube-api');
const videoFetcher    = new ytPI(apiKey);
const sf              = require('snekfetch');
const p               = require('simple-youtube-api');
const playListFetcher = new p(require('../config/config.json').YOUTUBEAPIKEY);

async function fetchSongData(client, msg, toSearch) {

  /**
  * @param {String} toSearch Getting the right video to play
  * @param {String} apiKey getting access to the data
  * @returns {Promise}
  * @returns {Error}
  */

  let data = await sf.get(`https://www.googleapis.com/youtube/v3/search?part=id&type=video&q=` + encodeURIComponent(toSearch) + '&key=' + apiKey);
  try {
    return(data.body.items[0].id.videoId);
  } catch (e) {
    msg.reply('We could not find the current song.');
  }
}

module.exports = fetchSongData;
<|endoftext|>


<commit_before>"use strict";
var CSLEDIT = CSLEDIT || {};

CSLEDIT.ConditionalPropertyPanel = function (element, node, executeCommand) {
	var that = this;

	this.element = element;
	this.node = new CSLEDIT.CslNode(node);
	this.node.children = []; // not interested in the children

	// any / none / all selector
	this.matchSelect = $('<select></select>');
	$.each(CSLEDIT.schema.attributes('choose/if').match.values, function (i, value) {
		that.matchSelect.append('<option>' + value.value + '</option>');
	});

	// generate mainOptions from the schema
	this.mainOptions = {};
	$.each(this.attributeUi, function (attribute, ui) {
		var mainOptionProperties = that.mainOptions[ui.mainOption] || [];

		mainOptionProperties.push({
			attribute: attribute,
			subOption: ui.subOption
		});
		that.mainOptions[ui.mainOption] = mainOptionProperties;
	});

	// mainOption selector (document type / variable / date / locator / ...)
	this.mainOptionSelect = $('<select></select>');
	$.each(this.mainOptions, function (mainOption, properties) {
		that.mainOptionSelect.append('<option>' + mainOption + '</option>');
	});

	this.setup();
};

CSLEDIT.ConditionalPropertyPanel.prototype.attributeValue = function () {
	var values = [];
	$.each(this.valueControls, function (i, valueControl) {
		values.push(valueControl.val());
	});
	return values.join(" ");
};

CSLEDIT.ConditionalPropertyPanel.prototype.removeDuplicateOptions = function () {
	var that = this,
		selectedValues = this.attributeValue().split(" "),
		processedValues = [],
		availableValues;

	// remove currently selcted values from availableValues
	availableValues = this.possibleValues(this.currentAttribute);
	$.each(selectedValues, function (i, value) {
		var index = availableValues.indexOf(value);
		if (index !== -1) {
			availableValues.splice(index, 1);
		}
	});

	// remove duplicate values
	$.each(this.valueControls, function (i, valueControl) {
		var $this = $(this),
			value = $this.val();

		// check if it's a duplicate
		if (processedValues.indexOf(value) !== -1) {
			if (availableValues.length === 0) {
				// no more available values, set processedValues and setup again
				that.node.setAttr(that.currentAttribute, processedValues.join(" "));
				executeCommand('amendNode', [that.node.cslId, that.node]);
				that.setup();
				return;
			} else {
				// give it a new value
				value = availableValues.pop();
				$this.val(value);
				selectedValues.push(value);
			}
		}
		processedValues.push(value);
	});

	// remove currently selected values from other controls options
	$.each(this.valueControls, function (i, valueControl) {
		var $this = $(this);

		// remove all except current val
		$this.find('option[value!="' + $this.val() + '"]').remove();

		// add back the other available options
		$.each(availableValues, function (i, option) {
			$this.append('<option>' + option + '</option>');
		});
	});
};

CSLEDIT.ConditionalPropertyPanel.prototype.attributeUi = {
	"disambiguate" : {
		mainOption: "Citations are disambiguated"
	},
	"variable" : {
		mainOption: "The variable",
		subOption: "is present"
	},
	"is-numeric" : {
		mainOption: "The variable",
		subOption: "is a number"
	},
	"is-uncertain-date" : {
		mainOption: "The date",
		subOption: "is uncertain"
	},
	"locator" : {
		mainOption: "The locator subtype",
		subOption: "is present"
	},
	"position" : {
		mainOption: "The position is"
	},
	"type" : {
		mainOption: "The document type is"
	}
};

CSLEDIT.ConditionalPropertyPanel.prototype.possibleValues = function (attribute) {
	// get possible values from schema
	var possibleValues = [];
	$.each(CSLEDIT.schema.choices("choose/if"), function (i, attributes) {
		if (attributes.hasOwnProperty(attribute)) {
			$.each(attributes[attribute].values, function (i2, possibleValue) {
				if (possibleValue.type === "value") {
					possibleValues.push(possibleValue.value);
				}
			});
			return false;
		}
	});
	return possibleValues;
};

CSLEDIT.ConditionalPropertyPanel.prototype.availableValues = function () {
	var availableValues = this.possibleValues(this.currentAttribute),
		selectedValues = this.attributeValue();

	// remove currently selcted values from availableValues
	$.each(this.attributeValue().split(" "), function (i, value) {
		var index = availableValues.indexOf(value);
		if (index !== -1) {
			availableValues.splice(index, 1);
		}
	});
	return availableValues;
};
CSLEDIT.ConditionalPropertyPanel.prototype.setup = function () {
	var that = this,
		mainOption;

	// set mainOptionSelect value
	$.each(this.node.attributes, function (i, attribute) {
		if (attribute.enabled) {
			var attributeProperty = that.attributeUi[attribute.key];
			if (typeof attributeProperty !== "undefined") {
				console.log("attr = " + attribute.key);
				mainOption = attributeProperty.mainOption;
				that.mainOptionSelect.val(mainOption);
			}
		}
	});

	// set matchSelect value
	this.matchSelect.val(this.node.getAttr('match') ||
			CSLEDIT.schema.attributes("choose/if").match.defaultValue);

	if (typeof mainOption === "undefined") {
		// should show at least one attribute value, so create one
		// NOTE: this is slightly strange behaviour for a view
		//       but should never happen - only after loading an
		//       invalid style

		this.node.setAttr("type", "article");
		this.node.setAttr("match", "any");
		executeCommand('amendNode', [this.node.cslId, this.node]);
		this.setup();
		return;
	}

	// create subOptionControl
	if (this.mainOptions[mainOption].length > 1) {
		this.subOptionControl = $('<select></select>');
		$.each(this.mainOptions[mainOption], function (i, properties) {
			that.subOptionControl.append($('<option>' + properties.subOption + '</option>'));
			if (that.node.hasAttr(properties.attribute)) {
				that.subOptionControl.val(properties.subOption);
				that.currentAttribute = properties.attribute;
			}
		});
	} else {
		this.subOptionControl = $('');
		$.each(this.mainOptions[mainOption], function (i, properties) {
			that.subOptionControl.append(properties.subOption);
			that.currentAttribute = properties.attribute;
		});
	}

	// create valueControls
	this.valueControls = [];
	$.each(this.node.getAttr(this.currentAttribute).split(" "), function (i, value) {
		var valueControl = $('<select class="valueSelect"></select>');
		$.each(that.possibleValues(that.currentAttribute), function (i, possibleValue) {
			valueControl.append('<option>' + possibleValue + '</option>');
		});
		valueControl.val(value);
		that.valueControls.push(valueControl);
	});

	this.drawControls();

	this.removeDuplicateOptions();

	// event handlers
	this.mainOptionSelect.on('change', function () {
		console.log("change");
		that.currentAttribute = null;
		$.each(that.attributeUi, function (attribute, ui) {
			if (that.currentAttribute === null && ui.mainOption === that.mainOptionSelect.val()) {
				that.node.setAttrEnabled(attribute, true, that.possibleValues(attribute)[0]);
				that.currentAttribute = attribute;
			} else {
				that.node.setAttrEnabled(attribute, false);
			}
		});
		console.log('currentAttr = ' + that.currentAttribute);
		executeCommand('amendNode', [that.node.cslId, that.node]);
		that.setup();
	});

	if (this.subOptionControl.is('select')) {
		this.subOptionControl.on('change', function () {
			// when changing a sub-option, keep the space-separated value list the same
			var currentAttributeValue = that.attributeValue();
			$.each(that.attributeUi, function (attribute, ui) {
				if (ui.mainOption === that.mainOptionSelect.val() &&
						ui.subOption === that.subOptionControl.val()) {
					that.node.setAttr(attribute, currentAttributeValue);
					that.currentAttribute = attribute;
				} else {
					that.node.setAttrEnabled(attribute, false);
				}
			});
			executeCommand('amendNode', [that.node.cslId, that.node]);
		});
	}

	this.element.find('select.valueSelect').on('change', function () {
		that.removeDuplicateOptions();
		that.node.setAttr(that.currentAttribute, that.attributeValue());
		executeCommand('amendNode', [that.node.cslId, that.node]);
	});

	this.element.find('button.addValue').on('click', function () {
		if (that.availableValues().length === 0) {
			alert("No more available values");
			return;
		}
		that.node.setAttr(that.currentAttribute, that.attributeValue() + " " +
			that.availableValues()[0]);
		executeCommand('amendNode', [that.node.cslId, that.node]);
		that.setup();
	});

	this.element.find('button.deleteValue').on('click', function (event) {
		var index = that.element.find('button.deleteValue').index(event.target),
			valueList = that.node.getAttr(that.currentAttribute).split(" ");

		console.log("index = " + index);
		console.log("value list = " + valueList.join(", "));

		valueList.splice(index, 1);
		console.log("value list after = " + valueList.join(", "));

		that.node.setAttr(that.currentAttribute, valueList.join(" "));
		executeCommand('amendNode', [that.node.cslId, that.node]);
		that.setup();
	});

	this.matchSelect.on('change', function () {
		that.node.setAttr('match', that.matchSelect.val());
		executeCommand('amendNode', [that.node.cslId, that.node]);
		that.setup();
	});
};

CSLEDIT.ConditionalPropertyPanel.prototype.drawControls = function () {
	var that = this,
		table = $('
<col class="c1" /><col class="c2" />' +
				'<col class="c3" /><col class="c4" /><col class="c5" />
'),
		valueSeparator,
		matchValue = this.node.getAttr('match') ||
			CSLEDIT.schema.attributes("choose/if").match.defaultValue;

	this.element.children().remove();

	this.element.append($('

').
			append(this.node.name + ' ').
			append(this.matchSelect).
			append(' of the following conditions are met'));

	if (matchValue === "all") {
		valueSeparator = 'and';
	} else {
		valueSeparator = 'or';
	}

	$.each(this.valueControls, function (i, valueControl) {
		var row = $('

');

		if (i === 0) {
			row.append($('	').append(that.mainOptionSelect));
		} else {
			row.append('	');
		}

		if (that.node.getAttr('disambiguate') === "true") {
			row.append($('	'));
		} else {
			row.append($('	').append(valueControl));

			if (i === that.valueControls.length - 1) {
				row.append($('	').append(that.subOptionControl));
			} else {
				row.append($('' + valueSeparator + '	'));
			}
			row.append('<button class="deleteValue">-</button>	');
			if (that.valueControls.length === 1) {
				row.find('button.deleteValue').css({visibility:"hidden"});
			}

			if (i === that.valueControls.length - 1) {
				row.append('<button class="addValue">+</button>	');
			} else {
				row.append('	');
			}
		}
		table.append(row);
	});

	this.element.append(table);
};
<commit_msg>half way through fixing the conditional property panel to allow specifying conditions on different types.<commit_after>"use strict";
var CSLEDIT = CSLEDIT || {};

CSLEDIT.ConditionalPropertyPanel = function (element, node, executeCommand) {
	var that = this;

	this.element = element;
	this.node = new CSLEDIT.CslNode(node);
	this.node.children = []; // not interested in the children
	this.executeCommand = executeCommand;
	this.conditions = [];

	// any / none / all selector
	this.matchSelect = $('<select></select>');
	$.each(CSLEDIT.schema.attributes('choose/if').match.values, function (i, value) {
		that.matchSelect.append('<option>' + value.value + '</option>');
	});

	// generate mainOptions from the schema
	this.mainOptions = {};
	$.each(this.attributeUi, function (attribute, ui) {
		var mainOptionProperties = that.mainOptions[ui.mainOption] || [];

		mainOptionProperties.push({
			attribute: attribute,
			subOption: ui.subOption
		});
		that.mainOptions[ui.mainOption] = mainOptionProperties;
	});

	this.setup();
};

CSLEDIT.ConditionalPropertyPanel.prototype.attributeValue = function (attribute) {
	var that = this,
		values = [];
	$.each(this.valueControls, function (i, valueControl) {
		if (that.conditions[i].attribute === attribute) {
			values.push(valueControl.val());
		}
	});
	return values.join(" ");
};

CSLEDIT.ConditionalPropertyPanel.prototype.removeDuplicateOptions = function () {
	var that = this;

	$.each(that.node.attributes, function (attrIndex, attribute) {
		var selectedValues = that.attributeValue(attribute.key).split(" "),
			processedValues = [],
			availableValues;

		if (attribute.key !== "match") {
			// remove currently selcted values from availableValues
			availableValues = that.possibleValues(attribute.key);
			$.each(selectedValues, function (i, value) {
				var index = availableValues.indexOf(value);
				if (index !== -1) {
					availableValues.splice(index, 1);
				}
			});

			// remove duplicate values
			$.each(that.valueControls, function (i, valueControl) {
				if (that.conditions[i].attribute === attribute.key) {
					var $this = $(this),
						value = $this.val();

					// check if it's a duplicate
					if (processedValues.indexOf(value) !== -1) {
						if (availableValues.length === 0) {
							// no more available values, set processedValues and setup again
							that.node.setAttr(attribute.key, processedValues.join(" "));
							that.executeCommand('amendNode', [that.node.cslId, that.node]);
							that.setup();
							return;
						} else {
							// give it a new value
							value = availableValues.pop();
							$this.val(value);
							selectedValues.push(value);
						}
					}
					processedValues.push(value);
				}
			});

			console.log("removing selected values from " + that.valueControls.length);
			// remove currently selected values from other controls options
			$.each(that.valueControls, function (i, valueControl) {
				if (that.conditions[i].attribute === attribute.key) {
					var $this = $(this);

					// remove all except current val
					$this.find('option[value!="' + $this.val() + '"]').remove();

					//console.log("adding available options: " + availableOptions.length);

					// add back the other available options
					$.each(availableValues, function (i, option) {
						$this.append('<option>' + option + '</option>');
					});
				}
			});
		}
	});
};

CSLEDIT.ConditionalPropertyPanel.prototype.attributeUi = {
	"disambiguate" : {
		mainOption: "Citations are disambiguated"
	},
	"variable" : {
		mainOption: "The variable",
		subOption: "is present"
	},
	"is-numeric" : {
		mainOption: "The variable",
		subOption: "is a number"
	},
	"is-uncertain-date" : {
		mainOption: "The date",
		subOption: "is uncertain"
	},
	"locator" : {
		mainOption: "The locator subtype",
		subOption: "is present"
	},
	"position" : {
		mainOption: "The position is"
	},
	"type" : {
		mainOption: "The document type is"
	}
};

CSLEDIT.ConditionalPropertyPanel.prototype.possibleValues = function (attribute) {
	// get possible values from schema
	var possibleValues = [];
	$.each(CSLEDIT.schema.choices("choose/if"), function (i, attributes) {
		if (attributes.hasOwnProperty(attribute)) {
			$.each(attributes[attribute].values, function (i2, possibleValue) {
				if (possibleValue.type === "value") {
					possibleValues.push(possibleValue.value);
				}
			});
			return false;
		}
	});

	// for MLZ schema which doesn't put the values in choices
	if (possibleValues.length === 0 && attribute in CSLEDIT.schema.attributes("choose/if")) {
		$.each(CSLEDIT.schema.attributes("choose/if")[attribute].values, function (i, possibleValue) {
			if (possibleValue.type === "value") {
				possibleValues.push(possibleValue.value);
			}
		});
	};

	return possibleValues;
};

CSLEDIT.ConditionalPropertyPanel.prototype.availableValues = function () {
	var availableValues = this.possibleValues(this.currentAttribute),
		selectedValues = this.attributeValue();

	// remove currently selcted values from availableValues
	$.each(this.attributeValue().split(" "), function (i, value) {
		var index = availableValues.indexOf(value);
		if (index !== -1) {
			availableValues.splice(index, 1);
		}
	});
	return availableValues;
};
CSLEDIT.ConditionalPropertyPanel.prototype.setup = function () {
	var that = this;

	this.conditions = [];

	$.each(this.node.attributes, function (i, attribute) {
		if (attribute.key !== "match" && attribute.enabled) {
			$.each(attribute.value.split(" "), function (i, value) {
				that.conditions.push({
					attribute : attribute.key,
					value : value
				});
			});
		}
	});

	// set matchSelect value
	this.matchSelect.val(this.node.getAttr('match') ||
			CSLEDIT.schema.attributes("choose/if").match.defaultValue);

	if (this.conditions.length === 0) {
		// should show at least one attribute value, so create one
		// NOTE: this is slightly strange behaviour for a view
		//       but should never happen - only after loading an
		//       invalid style

		this.node.setAttr("type", "article");
		this.node.setAttr("match", "any");
		that.executeCommand('amendNode', [this.node.cslId, this.node]);
		this.setup();
		return;
	}

	this.mainOptionControls = [];
	this.valueControls = [];
	this.subOptionControls = [];
	$.each(that.conditions, function (i, condition) {
		var mainOption,
			mainOptionControl,
			valueControl,
			subOptionControl;

		// create mainOption
		mainOptionControl = $('<select></select>');
		$.each(that.mainOptions, function (mainOption, properties) {
			mainOptionControl.append('<option>' + mainOption + '</option>');
		});
		mainOption = that.attributeUi[condition.attribute].mainOption;
		mainOptionControl.val(mainOption);
		that.mainOptionControls.push(mainOptionControl);

		// create subOptionControl
		if (that.mainOptions[mainOption].length > 1) {
			subOptionControl = $('<select></select>');
			$.each(that.mainOptions[mainOption], function (i, properties) {
				subOptionControl.append($('<option>' + properties.subOption + '</option>'));
				if (condition.attribute === properties.attribute) {
					subOptionControl.val(properties.subOption);
				}
			});
		} else {
			subOptionControl = $('');
			$.each(that.mainOptions[mainOption], function (i, properties) {
				subOptionControl.append(properties.subOption);
			});
		}
		that.subOptionControls.push(subOptionControl);

		// create value control
		valueControl = $('<select class="valueSelect"></select>');
		$.each(that.possibleValues(condition.attribute), function (i, possibleValue) {
			valueControl.append('<option>' + possibleValue + '</option>');
		});
		valueControl.val(condition.value);
		that.valueControls.push(valueControl);
	});

	this.drawControls();

	this.removeDuplicateOptions();
/*
	// event handlers
	this.mainOptionSelect.on('change', function () {
		console.log("change");
		that.currentAttribute = null;
		$.each(that.attributeUi, function (attribute, ui) {
			if (that.currentAttribute === null && ui.mainOption === that.mainOptionSelect.val()) {
				that.node.setAttrEnabled(attribute, true, that.possibleValues(attribute)[0]);
				that.currentAttribute = attribute;
			} else {
				that.node.setAttrEnabled(attribute, false);
			}
		});
		console.log('currentAttr = ' + that.currentAttribute);
		that.executeCommand('amendNode', [that.node.cslId, that.node]);
		that.setup();
	});

	if (this.subOptionControl.is('select')) {
		this.subOptionControl.on('change', function () {
			// when changing a sub-option, keep the space-separated value list the same
			var currentAttributeValue = that.attributeValue();
			$.each(that.attributeUi, function (attribute, ui) {
				if (ui.mainOption === that.mainOptionSelect.val() &&
						ui.subOption === that.subOptionControl.val()) {
					that.node.setAttr(attribute, currentAttributeValue);
					that.currentAttribute = attribute;
				} else {
					that.node.setAttrEnabled(attribute, false);
				}
			});
			that.executeCommand('amendNode', [that.node.cslId, that.node]);
		});
	}

	this.element.find('select.valueSelect').on('change', function () {
		that.removeDuplicateOptions();
		that.node.setAttr(that.currentAttribute, that.attributeValue());
		that.executeCommand('amendNode', [that.node.cslId, that.node]);
	});

	this.element.find('button.addValue').on('click', function () {
		if (that.availableValues().length === 0) {
			alert("No more available values");
			return;
		}
		that.node.setAttr(that.currentAttribute, that.attributeValue() + " " +
			that.availableValues()[0]);
		that.executeCommand('amendNode', [that.node.cslId, that.node]);
		that.setup();
	});

	this.element.find('button.deleteValue').on('click', function (event) {
		var index = that.element.find('button.deleteValue').index(event.target),
			valueList = that.node.getAttr(that.currentAttribute).split(" ");

		console.log("index = " + index);
		console.log("value list = " + valueList.join(", "));

		valueList.splice(index, 1);
		console.log("value list after = " + valueList.join(", "));

		that.node.setAttr(that.currentAttribute, valueList.join(" "));
		that.executeCommand('amendNode', [that.node.cslId, that.node]);
		that.setup();
	});

	this.matchSelect.on('change', function () {
		that.node.setAttr('match', that.matchSelect.val());
		that.executeCommand('amendNode', [that.node.cslId, that.node]);
		that.setup();
	});*/
};

CSLEDIT.ConditionalPropertyPanel.prototype.drawControls = function () {
	var that = this,
		table = $('
<col class="c1" /><col class="c2" />' +
				'<col class="c3" /><col class="c4" /><col class="c5" />
'),
		valueSeparator,
		matchValue = this.node.getAttr('match') ||
			CSLEDIT.schema.attributes("choose/if").match.defaultValue;

	this.element.children().remove();

	this.element.append($('

').
			append(this.node.name + ' ').
			append(this.matchSelect).
			append(' of the following conditions are met'));

	if (matchValue === "all") {
		valueSeparator = 'and';
	} else {
		valueSeparator = 'or';
	}

	$.each(this.valueControls, function (i, valueControl) {
		var row = $('

');

		row.append($('	').append(that.mainOptionControls[i]));

//		if (that.node.getAttr('disambiguate') === "true") {
//			row.append($('	'));
//		} else {
			row.append($('	').append(valueControl));

			row.append($('	').append(that.subOptionControls[i]));
			row.append($('' + valueSeparator + '	'));

			row.append('<button class="deleteValue">-</button>	');
			if (that.valueControls.length === 1) {
				row.find('button.deleteValue').css({visibility:"hidden"});
			}

			if (i === that.valueControls.length - 1) {
				row.append('<button class="addValue">+</button>	');
			} else {
				row.append('	');
			}
//		}
		table.append(row);
	});

	this.element.append(table);
};
<|endoftext|>