<commit_before>// @flow weak

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { createStyleSheet } from 'jss-theme-reactor';
import withStyles from '../styles/withStyles';
import Textarea from './Textarea';

export function isDirty(obj, SSR = false) {
  return (
    obj &&
    ((obj.value && obj.value.toString().length) ||
      (SSR && obj.defaultValue && obj.defaultValue.toString().length)) > 0
  );
}

export const styleSheet = createStyleSheet('MuiInput', theme => {
  const placeholder = {
    color: 'currentColor',
    opacity: theme.palette.type === 'light' ? 0.42 : 0.5,
  };
  const placeholderForm = {
    opacity: 0,
    transition: theme.transitions.create('opacity', {
      duration: theme.transitions.duration.shorter,
      easing: theme.transitions.easing.ease,
    }),
  };
  const placeholderFormFocus = {
    opacity: theme.palette.type === 'light' ? 0.42 : 0.5,
  };

  return {
    root: {
      // Mimics the default input display property used by browsers for an input.
      display: 'inline-block',
      position: 'relative',
      fontFamily: theme.typography.fontFamily,
      color: theme.palette.input.inputText,
    },
    formControl: {
      'label + &': {
        marginTop: theme.spacing.unit * 2,
      },
    },
    inkbar: {
      '&:after': {
        backgroundColor: theme.palette.primary[theme.palette.type === 'light' ? 'A700' : 'A200'],
        left: 0,
        bottom: 0,
        // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
        content: '""',
        height: 2,
        position: 'absolute',
        right: 0,
        transform: 'scaleX(0)',
        transition: theme.transitions.create('transform', {
          duration: theme.transitions.duration.shorter,
          easing: theme.transitions.easing.easeOut,
        }),
      },
      '&$focused:after': {
        transform: 'scaleX(1)',
      },
    },
    error: {
      '&:after': {
        backgroundColor: theme.palette.error.A400,
        transform: 'scaleX(1)', // error is always underlined in red
      },
    },
    input: {
      font: 'inherit',
      color: 'currentColor',
      // slight alteration to spec spacing to match visual spec result
      padding: `${theme.spacing.unit - 1}px 0`,
      border: 0,
      display: 'block',
      boxSizing: 'content-box',
      verticalAlign: 'middle',
      background: 'none',
      margin: 0, // Reset for Safari
      width: '100%',
      '&::-webkit-input-placeholder': placeholder,
      '&::-moz-placeholder': placeholder, // Firefox 19+
      '&:-ms-input-placeholder': placeholder, // IE 11
      '&::-ms-input-placeholder': placeholder, // Edge
      '&:focus': {
        outline: 0,
      },
      '&::-webkit-search-decoration': {
        // Remove the padding when type=search.
        appearance: 'none',
      },
      'label + $formControl > &': {
        '&::-webkit-input-placeholder': placeholderForm,
        '&::-moz-placeholder': placeholderForm, // Firefox 19+
        '&:-ms-input-placeholder': placeholderForm, // IE 11
        '&::-ms-input-placeholder': placeholderForm, // Edge
        '&:focus::-webkit-input-placeholder': placeholderFormFocus,
        '&:focus::-moz-placeholder': placeholderFormFocus, // Firefox 19+
        '&:focus:-ms-input-placeholder': placeholderFormFocus, // IE 11
        '&:focus::-ms-input-placeholder': placeholderFormFocus, // Edge
      },
    },
    inputDense: {
      paddingTop: `${theme.spacing.unit / 2}px`,
    },
    disabled: {
      color: theme.palette.text.disabled,
    },
    focused: {},
    underline: {
      paddingBottom: 2,
      '&:before': {
        backgroundColor: theme.palette.input.bottomLine,
        left: 0,
        bottom: 0,
        // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
        content: '""',
        height: 1,
        position: 'absolute',
        right: 0,
        transition: theme.transitions.create('backgroundColor', {
          duration: theme.transitions.duration.shorter,
          easing: theme.transitions.easing.ease,
        }),
      },
      '&:hover:not($disabled):before': {
        backgroundColor: theme.palette.text.primary,
        height: 2,
      },
      '&$disabled:before': {
        background: 'transparent',
        backgroundImage: `linear-gradient(to right, ${theme.palette.input
          .bottomLine} 33%, transparent 0%)`,
        backgroundPosition: 'left top',
        backgroundRepeat: 'repeat-x',
        backgroundSize: '5px 1px',
      },
    },
    multiline: {
      padding: `${theme.spacing.unit - 2}px 0 ${theme.spacing.unit + 1}px`,
    },
    inputDisabled: {
      opacity: 1, // Reset iOS opacity
    },
    inputSingleline: {
      height: '1em',
      appearance: 'textfield', // Improve type search style.
    },
    inputMultiline: {
      resize: 'none',
      padding: 0,
    },
    fullWidth: {
      width: '100%',
    },
  };
});

type DefaultProps = {
  disableUnderline: boolean,
  fullWidth: boolean,
  multiline: boolean,
  type: string,
};

type Props = DefaultProps & {
  /**
   * @ignore
   */
  autoComplete?: boolean,
  /**
   * @ignore
   */
  autoFocus?: boolean,
  /**
   * Useful to extend the style applied to components.
   */
  classes: Object,
  /**
   * The CSS class name of the wrapper element.
   */
  className?: string,
  /**
   * The component used for the root node.
   * Either a string to use a DOM element or a component.
   * It's an `input` by default.
   */
  component?: string | Function,
  /**
   * The default input value, useful when not controlling the component.
   */
  defaultValue?: string | number,
  /**
   * @ignore
   */
  disabled?: boolean,
  /**
   * If `true`, the input will not have an underline.
   */
  disableUnderline?: boolean,
  /**
   * If `true`, the input will indicate an error. This is normally obtained via context from
   * FormControl.
   */
  error?: boolean,
  /**
   * If `true`, the input will take up the full width of its container.
   */
  fullWidth?: boolean,
  /*
   * @ignore
   */
  id?: string,
  /**
   * Properties applied to the `input` element.
   */
  inputProps?: Object,
  /**
   * Use that property to pass a ref callback to the native input component.
   */
  inputRef?: Function,
  /**
   * If `dense`, will adjust vertical spacing. This is normally obtained via context from
   * FormControl.
   */
  margin?: 'dense',
  /**
   * If `true`, a textarea element will be rendered.
   */
  multiline?: boolean,
  /**
   * @ignore
   */
  name?: string,
  /**
   * @ignore
   */
  onBlur?: Function,
  /**
   * @ignore
   */
  onChange?: Function,
  /**
   * @ignore
   */
  onClean?: Function,
  /**
   * @ignore
   */
  onDirty?: Function,
  /**
   * @ignore
   */
  onFocus?: Function,
  /**
   * @ignore
   */
  onKeyDown?: Function,
  /**
   * @ignore
   */
  onKeyUp?: Function,
  /**
   * @ignore
   */
  placeholder?: string,
  /**
   * Number of rows to display when multiline option is set to true.
   */
  rows?: string | number,
  /**
   * Maxium number of rows to display when multiline option is set to true.
   */
  rowsMax?: string | number,
  /**
   * Type of the input element. It should be a valid HTML5 input type.
   */
  type?: string,
  /**
   * The input value, required for a controlled component.
   */
  value?: string | number,
};

type State = {
  focused: boolean,
};

class Input extends Component<DefaultProps, Props, State> {
  static muiName = 'Input';
  static defaultProps = {
    disableUnderline: false,
    fullWidth: false,
    multiline: false,
    type: 'text',
  };
  static contextTypes = {
    muiFormControl: PropTypes.object,
  };
  state = {
    focused: false,
  };

  componentWillMount() {
    if (this.isControlled()) {
      this.checkDirty(this.props);
    }
  }

  componentDidMount() {
    if (!this.isControlled()) {
      this.checkDirty(this.input);
    }
  }

  componentWillUpdate(nextProps) {
    if (this.isControlled()) {
      this.checkDirty(nextProps);
    } // else performed in the onChange
  }

  // Holds the input reference
  input = null;

  handleFocus = event => {
    this.setState({ focused: true });
    if (this.props.onFocus) {
      this.props.onFocus(event);
    }
  };

  handleBlur = event => {
    this.setState({ focused: false });
    if (this.props.onBlur) {
      this.props.onBlur(event);
    }
  };

  handleChange = event => {
    if (!this.isControlled()) {
      this.checkDirty(this.input);
    } // else perform in the willUpdate
    if (this.props.onChange) {
      this.props.onChange(event);
    }
  };

  handleRefInput = node => {
    this.input = node;
    if (this.props.inputRef) {
      this.props.inputRef(node);
    }
  };

  handleRefTextarea = node => {
    this.input = node;
    if (this.props.inputRef) {
      this.props.inputRef(node);
    }
  };

  isControlled() {
    return typeof this.props.value === 'string';
  }

  checkDirty(obj) {
    const { muiFormControl } = this.context;

    if (isDirty(obj)) {
      if (muiFormControl && muiFormControl.onDirty) {
        muiFormControl.onDirty();
      }
      if (this.props.onDirty) {
        this.props.onDirty();
      }
      return;
    }

    if (muiFormControl && muiFormControl.onClean) {
      muiFormControl.onClean();
    }
    if (this.props.onClean) {
      this.props.onClean();
    }
  }

  render() {
    const {
      autoComplete,
      autoFocus,
      classes,
      className: classNameProp,
      component,
      defaultValue,
      disabled: disabledProp,
      disableUnderline,
      error: errorProp,
      fullWidth,
      id,
      inputProps: inputPropsProp,
      inputRef,
      margin: marginProp,
      multiline,
      onBlur,
      onFocus,
      onChange,
      onClean,
      onDirty,
      onKeyDown,
      onKeyUp,
      placeholder,
      name,
      rows,
      rowsMax,
      type,
      value,
      ...other
    } = this.props;

    const { muiFormControl } = this.context;

    let disabled = disabledProp;
    let error = errorProp;
    let margin = marginProp;

    if (muiFormControl) {
      if (typeof disabled === 'undefined') {
        disabled = muiFormControl.disabled;
      }

      if (typeof error === 'undefined') {
        error = muiFormControl.error;
      }

      if (typeof margin === 'undefined') {
        margin = muiFormControl.margin;
      }
    }

    const className = classNames(
      classes.root,
      {
        [classes.disabled]: disabled,
        [classes.error]: error,
        [classes.fullWidth]: fullWidth,
        [classes.focused]: this.state.focused,
        [classes.formControl]: muiFormControl,
        [classes.inkbar]: !disableUnderline,
        [classes.multiline]: multiline,
        [classes.underline]: !disableUnderline,
      },
      classNameProp,
    );

    const inputClassName = classNames(classes.input, {
      [classes.inputDisabled]: disabled,
      [classes.inputSingleline]: !multiline,
      [classes.inputMultiline]: multiline,
      [classes.inputDense]: margin === 'dense',
    });

    const required = muiFormControl && muiFormControl.required === true;

    let InputComponent = 'input';
    let inputProps = {
      ref: this.handleRefInput,
      ...inputPropsProp,
    };

    if (component) {
      inputProps = {
        rowsMax,
        ...inputProps,
      };
      InputComponent = component;
    } else if (multiline) {
      if (rows && !rowsMax) {
        inputProps = {
          ...inputProps,
        };
        InputComponent = 'textarea';
      } else {
        inputProps = {
          rowsMax,
          textareaRef: this.handleRefTextarea,
          ...inputProps,
          ref: null,
        };
        InputComponent = Textarea;
      }
    }

    return (
      <div className={className} {...other}>
        <InputComponent
          autoComplete={autoComplete}
          autoFocus={autoFocus}
          className={inputClassName}
          onBlur={this.handleBlur}
          onFocus={this.handleFocus}
          onChange={this.handleChange}
          onKeyUp={onKeyUp}
          onKeyDown={onKeyDown}
          disabled={disabled}
          aria-required={required ? true : undefined}
          value={value}
          id={id}
          name={name}
          defaultValue={defaultValue}
          placeholder={placeholder}
          type={type}
          rows={rows}
          {...inputProps}
        />
      </div>
    );
  }
}

export default withStyles(styleSheet)(Input);
<commit_msg>[Input] use numeric in css<commit_after>// @flow weak

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { createStyleSheet } from 'jss-theme-reactor';
import withStyles from '../styles/withStyles';
import Textarea from './Textarea';

export function isDirty(obj, SSR = false) {
  return (
    obj &&
    ((obj.value && obj.value.toString().length) ||
      (SSR && obj.defaultValue && obj.defaultValue.toString().length)) > 0
  );
}

export const styleSheet = createStyleSheet('MuiInput', theme => {
  const placeholder = {
    color: 'currentColor',
    opacity: theme.palette.type === 'light' ? 0.42 : 0.5,
  };
  const placeholderForm = {
    opacity: 0,
    transition: theme.transitions.create('opacity', {
      duration: theme.transitions.duration.shorter,
      easing: theme.transitions.easing.ease,
    }),
  };
  const placeholderFormFocus = {
    opacity: theme.palette.type === 'light' ? 0.42 : 0.5,
  };

  return {
    root: {
      // Mimics the default input display property used by browsers for an input.
      display: 'inline-block',
      position: 'relative',
      fontFamily: theme.typography.fontFamily,
      color: theme.palette.input.inputText,
    },
    formControl: {
      'label + &': {
        marginTop: theme.spacing.unit * 2,
      },
    },
    inkbar: {
      '&:after': {
        backgroundColor: theme.palette.primary[theme.palette.type === 'light' ? 'A700' : 'A200'],
        left: 0,
        bottom: 0,
        // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
        content: '""',
        height: 2,
        position: 'absolute',
        right: 0,
        transform: 'scaleX(0)',
        transition: theme.transitions.create('transform', {
          duration: theme.transitions.duration.shorter,
          easing: theme.transitions.easing.easeOut,
        }),
      },
      '&$focused:after': {
        transform: 'scaleX(1)',
      },
    },
    error: {
      '&:after': {
        backgroundColor: theme.palette.error.A400,
        transform: 'scaleX(1)', // error is always underlined in red
      },
    },
    input: {
      font: 'inherit',
      color: 'currentColor',
      // slight alteration to spec spacing to match visual spec result
      padding: `${theme.spacing.unit - 1}px 0`,
      border: 0,
      display: 'block',
      boxSizing: 'content-box',
      verticalAlign: 'middle',
      background: 'none',
      margin: 0, // Reset for Safari
      width: '100%',
      '&::-webkit-input-placeholder': placeholder,
      '&::-moz-placeholder': placeholder, // Firefox 19+
      '&:-ms-input-placeholder': placeholder, // IE 11
      '&::-ms-input-placeholder': placeholder, // Edge
      '&:focus': {
        outline: 0,
      },
      '&::-webkit-search-decoration': {
        // Remove the padding when type=search.
        appearance: 'none',
      },
      'label + $formControl > &': {
        '&::-webkit-input-placeholder': placeholderForm,
        '&::-moz-placeholder': placeholderForm, // Firefox 19+
        '&:-ms-input-placeholder': placeholderForm, // IE 11
        '&::-ms-input-placeholder': placeholderForm, // Edge
        '&:focus::-webkit-input-placeholder': placeholderFormFocus,
        '&:focus::-moz-placeholder': placeholderFormFocus, // Firefox 19+
        '&:focus:-ms-input-placeholder': placeholderFormFocus, // IE 11
        '&:focus::-ms-input-placeholder': placeholderFormFocus, // Edge
      },
    },
    inputDense: {
      paddingTop: theme.spacing.unit / 2,
    },
    disabled: {
      color: theme.palette.text.disabled,
    },
    focused: {},
    underline: {
      paddingBottom: 2,
      '&:before': {
        backgroundColor: theme.palette.input.bottomLine,
        left: 0,
        bottom: 0,
        // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
        content: '""',
        height: 1,
        position: 'absolute',
        right: 0,
        transition: theme.transitions.create('backgroundColor', {
          duration: theme.transitions.duration.shorter,
          easing: theme.transitions.easing.ease,
        }),
      },
      '&:hover:not($disabled):before': {
        backgroundColor: theme.palette.text.primary,
        height: 2,
      },
      '&$disabled:before': {
        background: 'transparent',
        backgroundImage: `linear-gradient(to right, ${theme.palette.input
          .bottomLine} 33%, transparent 0%)`,
        backgroundPosition: 'left top',
        backgroundRepeat: 'repeat-x',
        backgroundSize: '5px 1px',
      },
    },
    multiline: {
      padding: `${theme.spacing.unit - 2}px 0 ${theme.spacing.unit + 1}px`,
    },
    inputDisabled: {
      opacity: 1, // Reset iOS opacity
    },
    inputSingleline: {
      height: '1em',
      appearance: 'textfield', // Improve type search style.
    },
    inputMultiline: {
      resize: 'none',
      padding: 0,
    },
    fullWidth: {
      width: '100%',
    },
  };
});

type DefaultProps = {
  disableUnderline: boolean,
  fullWidth: boolean,
  multiline: boolean,
  type: string,
};

type Props = DefaultProps & {
  /**
   * @ignore
   */
  autoComplete?: boolean,
  /**
   * @ignore
   */
  autoFocus?: boolean,
  /**
   * Useful to extend the style applied to components.
   */
  classes: Object,
  /**
   * The CSS class name of the wrapper element.
   */
  className?: string,
  /**
   * The component used for the root node.
   * Either a string to use a DOM element or a component.
   * It's an `input` by default.
   */
  component?: string | Function,
  /**
   * The default input value, useful when not controlling the component.
   */
  defaultValue?: string | number,
  /**
   * @ignore
   */
  disabled?: boolean,
  /**
   * If `true`, the input will not have an underline.
   */
  disableUnderline?: boolean,
  /**
   * If `true`, the input will indicate an error. This is normally obtained via context from
   * FormControl.
   */
  error?: boolean,
  /**
   * If `true`, the input will take up the full width of its container.
   */
  fullWidth?: boolean,
  /*
   * @ignore
   */
  id?: string,
  /**
   * Properties applied to the `input` element.
   */
  inputProps?: Object,
  /**
   * Use that property to pass a ref callback to the native input component.
   */
  inputRef?: Function,
  /**
   * If `dense`, will adjust vertical spacing. This is normally obtained via context from
   * FormControl.
   */
  margin?: 'dense',
  /**
   * If `true`, a textarea element will be rendered.
   */
  multiline?: boolean,
  /**
   * @ignore
   */
  name?: string,
  /**
   * @ignore
   */
  onBlur?: Function,
  /**
   * @ignore
   */
  onChange?: Function,
  /**
   * @ignore
   */
  onClean?: Function,
  /**
   * @ignore
   */
  onDirty?: Function,
  /**
   * @ignore
   */
  onFocus?: Function,
  /**
   * @ignore
   */
  onKeyDown?: Function,
  /**
   * @ignore
   */
  onKeyUp?: Function,
  /**
   * @ignore
   */
  placeholder?: string,
  /**
   * Number of rows to display when multiline option is set to true.
   */
  rows?: string | number,
  /**
   * Maxium number of rows to display when multiline option is set to true.
   */
  rowsMax?: string | number,
  /**
   * Type of the input element. It should be a valid HTML5 input type.
   */
  type?: string,
  /**
   * The input value, required for a controlled component.
   */
  value?: string | number,
};

type State = {
  focused: boolean,
};

class Input extends Component<DefaultProps, Props, State> {
  static muiName = 'Input';
  static defaultProps = {
    disableUnderline: false,
    fullWidth: false,
    multiline: false,
    type: 'text',
  };
  static contextTypes = {
    muiFormControl: PropTypes.object,
  };
  state = {
    focused: false,
  };

  componentWillMount() {
    if (this.isControlled()) {
      this.checkDirty(this.props);
    }
  }

  componentDidMount() {
    if (!this.isControlled()) {
      this.checkDirty(this.input);
    }
  }

  componentWillUpdate(nextProps) {
    if (this.isControlled()) {
      this.checkDirty(nextProps);
    } // else performed in the onChange
  }

  // Holds the input reference
  input = null;

  handleFocus = event => {
    this.setState({ focused: true });
    if (this.props.onFocus) {
      this.props.onFocus(event);
    }
  };

  handleBlur = event => {
    this.setState({ focused: false });
    if (this.props.onBlur) {
      this.props.onBlur(event);
    }
  };

  handleChange = event => {
    if (!this.isControlled()) {
      this.checkDirty(this.input);
    } // else perform in the willUpdate
    if (this.props.onChange) {
      this.props.onChange(event);
    }
  };

  handleRefInput = node => {
    this.input = node;
    if (this.props.inputRef) {
      this.props.inputRef(node);
    }
  };

  handleRefTextarea = node => {
    this.input = node;
    if (this.props.inputRef) {
      this.props.inputRef(node);
    }
  };

  isControlled() {
    return typeof this.props.value === 'string';
  }

  checkDirty(obj) {
    const { muiFormControl } = this.context;

    if (isDirty(obj)) {
      if (muiFormControl && muiFormControl.onDirty) {
        muiFormControl.onDirty();
      }
      if (this.props.onDirty) {
        this.props.onDirty();
      }
      return;
    }

    if (muiFormControl && muiFormControl.onClean) {
      muiFormControl.onClean();
    }
    if (this.props.onClean) {
      this.props.onClean();
    }
  }

  render() {
    const {
      autoComplete,
      autoFocus,
      classes,
      className: classNameProp,
      component,
      defaultValue,
      disabled: disabledProp,
      disableUnderline,
      error: errorProp,
      fullWidth,
      id,
      inputProps: inputPropsProp,
      inputRef,
      margin: marginProp,
      multiline,
      onBlur,
      onFocus,
      onChange,
      onClean,
      onDirty,
      onKeyDown,
      onKeyUp,
      placeholder,
      name,
      rows,
      rowsMax,
      type,
      value,
      ...other
    } = this.props;

    const { muiFormControl } = this.context;

    let disabled = disabledProp;
    let error = errorProp;
    let margin = marginProp;

    if (muiFormControl) {
      if (typeof disabled === 'undefined') {
        disabled = muiFormControl.disabled;
      }

      if (typeof error === 'undefined') {
        error = muiFormControl.error;
      }

      if (typeof margin === 'undefined') {
        margin = muiFormControl.margin;
      }
    }

    const className = classNames(
      classes.root,
      {
        [classes.disabled]: disabled,
        [classes.error]: error,
        [classes.fullWidth]: fullWidth,
        [classes.focused]: this.state.focused,
        [classes.formControl]: muiFormControl,
        [classes.inkbar]: !disableUnderline,
        [classes.multiline]: multiline,
        [classes.underline]: !disableUnderline,
      },
      classNameProp,
    );

    const inputClassName = classNames(classes.input, {
      [classes.inputDisabled]: disabled,
      [classes.inputSingleline]: !multiline,
      [classes.inputMultiline]: multiline,
      [classes.inputDense]: margin === 'dense',
    });

    const required = muiFormControl && muiFormControl.required === true;

    let InputComponent = 'input';
    let inputProps = {
      ref: this.handleRefInput,
      ...inputPropsProp,
    };

    if (component) {
      inputProps = {
        rowsMax,
        ...inputProps,
      };
      InputComponent = component;
    } else if (multiline) {
      if (rows && !rowsMax) {
        inputProps = {
          ...inputProps,
        };
        InputComponent = 'textarea';
      } else {
        inputProps = {
          rowsMax,
          textareaRef: this.handleRefTextarea,
          ...inputProps,
          ref: null,
        };
        InputComponent = Textarea;
      }
    }

    return (
      <div className={className} {...other}>
        <InputComponent
          autoComplete={autoComplete}
          autoFocus={autoFocus}
          className={inputClassName}
          onBlur={this.handleBlur}
          onFocus={this.handleFocus}
          onChange={this.handleChange}
          onKeyUp={onKeyUp}
          onKeyDown={onKeyDown}
          disabled={disabled}
          aria-required={required ? true : undefined}
          value={value}
          id={id}
          name={name}
          defaultValue={defaultValue}
          placeholder={placeholder}
          type={type}
          rows={rows}
          {...inputProps}
        />
      </div>
    );
  }
}

export default withStyles(styleSheet)(Input);
<|endoftext|>


<commit_before>var _ = require('underscore');
var bcrypt = require('bcrypt-nodejs');
var FieldType = require('../Type');
var util = require('util');

/**
 * password FieldType Constructor
 * @extends Field
 * @api public
 */
function password (list, path, options) {
	this._nativeType = String;
	this._underscoreMethods = ['format', 'compare'];
	this._fixedSize = 'full';
	// You can't sort on password fields
	options.nosort = true;
	options.nofilter = true; // TODO: remove this when 0.4 is merged
	this.workFactor = options.workFactor || 10;
	password.super_.call(this, list, path, options);
}
util.inherits(password, FieldType);

/**
 * Registers the field on the List's Mongoose Schema.
 *
 * Adds ...
 *
 * @api public
 */
password.prototype.addToSchema = function () {
	var field = this;
	var schema = this.list.schema;
	var needs_hashing = '__' + field.path + '_needs_hashing';

	this.paths = {
		confirm: this.options.confirmPath || this._path.append('_confirm'),
		hash: this.options.hashPath || this._path.append('_hash'),
	};

	schema.path(this.path, _.defaults({
		type: String,
		set: function (newValue) {
			this[needs_hashing] = true;
			return newValue;
		},
	}, this.options));

	schema.virtual(this.paths.hash).set(function (newValue) {
		this.set(field.path, newValue);
		this[needs_hashing] = false;
	});

	schema.pre('save', function (next) {
		if (!this.isModified(field.path) || !this[needs_hashing]) {
			return next();
		}
		if (!this.get(field.path)) {
			this.set(field.path, undefined);
			return next();
		}
		var item = this;
		bcrypt.genSalt(field.workFactor, function (err, salt) {
			if (err) {
				return next(err);
			}
			bcrypt.hash(item.get(field.path), salt, function () {}, function (err, hash) {
				if (err) {
					return next(err);
				}
				// override the cleartext password with the hashed one
				item.set(field.path, hash);
				next();
			});
		});
	});
	this.bindUnderscoreMethods();
};

/**
 * Add filters to a query
 */
password.prototype.addFilterToQuery = function (filter, query) {
	query = query || {};
	query[this.path] = (filter.exists) ? { $ne: null } : null;
	return query;
};

/**
 * Formats the field value
 *
 * Password fields are always formatted as a random no. of asterisks,
 * because the saved hash should never be displayed nor the length
 * of the actual password hinted at.
 *
 * @api public
 */
password.prototype.format = function (item) {
	if (!item.get(this.path)) return '';
	var len = Math.round(Math.random() * 4) + 6;
	var stars = '';
	for (var i = 0; i < len; i++) stars += '*';
	return stars;
};

/**
 * Compares
 *
 * @api public
 */
password.prototype.compare = function (item, candidate, callback) {
	if (typeof callback !== 'function') throw new Error('Password.compare() requires a callback function.');
	var value = item.get(this.path);
	if (!value) return callback(null, false);
	bcrypt.compare(candidate, item.get(this.path), callback);
};

/**
 * Asynchronously confirms that the provided password is valid
 */
password.prototype.validateInput = function (data, callback) {
	var detail;
	var result = true;
	var confirmValue = this.getValueFromData(data, '_confirm');
	var passwordValue = this.getValueFromData(data);
	if (passwordValue !== undefined && confirmValue !== undefined && passwordValue !== confirmValue) {
		result = false;
		detail = 'passwords must match';
	}
	// TODO: we could support a password complexity option (or regexp) here
	process.nextTick(function () { callback(result, detail); });
};

/**
 * Asynchronously confirms that the provided password is valid
 */
password.prototype.validateRequiredInput = function (item, data, callback) {
	var hashValue = this.getValueFromData(data, '_hash');
	var passwordValue = this.getValueFromData(data);
	var result = hashValue || passwordValue ? true : false;
	if (!result && passwordValue === undefined && hashValue === undefined && item.get(this.path)) result = true;
	process.nextTick(function () { callback(result); });
};

/**
 * If password fields are required, check that either a value has been
 * provided or already exists in the field.
 *
 * Otherwise, input is always considered valid, as providing an empty
 * value will not change the password.
 *
 * Deprecated
 */
password.prototype.inputIsValid = function (data, required, item) {
	if (data[this.path] && this.paths.confirm in data) {
		return data[this.path] === data[this.paths.confirm] ? true : false;
	}
	if (data[this.path] || data[this.paths.hash] || (item && item.get(this.path))) return true;
	return required ? false : true;
};

/**
 * Updates the value for this field in the item from a data object
 *
 * Will accept either the field path, or paths.hash to bypass bcrypt
 *
 * @api public
 */
password.prototype.updateItem = function (item, data, callback) {
	var hashValue = this.getValueFromData(data, '_hash');
	var passwordValue = this.getValueFromData(data);
	if (passwordValue !== undefined) {
		item.set(this.path, passwordValue);
	} else if (hashValue !== undefined) {
		item.set(this.paths.hash, hashValue);
	}
	process.nextTick(callback);
};

/* Export Field Type */
module.exports = password;
<commit_msg>Using keystone-utils .defer for consistency in PasswordType<commit_after>var _ = require('underscore');
var bcrypt = require('bcrypt-nodejs');
var FieldType = require('../Type');
var util = require('util');
var utils = require('keystone-utils');

/**
 * password FieldType Constructor
 * @extends Field
 * @api public
 */
function password (list, path, options) {
	this._nativeType = String;
	this._underscoreMethods = ['format', 'compare'];
	this._fixedSize = 'full';
	// You can't sort on password fields
	options.nosort = true;
	options.nofilter = true; // TODO: remove this when 0.4 is merged
	this.workFactor = options.workFactor || 10;
	password.super_.call(this, list, path, options);
}
util.inherits(password, FieldType);

/**
 * Registers the field on the List's Mongoose Schema.
 *
 * Adds ...
 *
 * @api public
 */
password.prototype.addToSchema = function () {
	var field = this;
	var schema = this.list.schema;
	var needs_hashing = '__' + field.path + '_needs_hashing';

	this.paths = {
		confirm: this.options.confirmPath || this._path.append('_confirm'),
		hash: this.options.hashPath || this._path.append('_hash'),
	};

	schema.path(this.path, _.defaults({
		type: String,
		set: function (newValue) {
			this[needs_hashing] = true;
			return newValue;
		},
	}, this.options));

	schema.virtual(this.paths.hash).set(function (newValue) {
		this.set(field.path, newValue);
		this[needs_hashing] = false;
	});

	schema.pre('save', function (next) {
		if (!this.isModified(field.path) || !this[needs_hashing]) {
			return next();
		}
		if (!this.get(field.path)) {
			this.set(field.path, undefined);
			return next();
		}
		var item = this;
		bcrypt.genSalt(field.workFactor, function (err, salt) {
			if (err) {
				return next(err);
			}
			bcrypt.hash(item.get(field.path), salt, function () {}, function (err, hash) {
				if (err) {
					return next(err);
				}
				// override the cleartext password with the hashed one
				item.set(field.path, hash);
				next();
			});
		});
	});
	this.bindUnderscoreMethods();
};

/**
 * Add filters to a query
 */
password.prototype.addFilterToQuery = function (filter, query) {
	query = query || {};
	query[this.path] = (filter.exists) ? { $ne: null } : null;
	return query;
};

/**
 * Formats the field value
 *
 * Password fields are always formatted as a random no. of asterisks,
 * because the saved hash should never be displayed nor the length
 * of the actual password hinted at.
 *
 * @api public
 */
password.prototype.format = function (item) {
	if (!item.get(this.path)) return '';
	var len = Math.round(Math.random() * 4) + 6;
	var stars = '';
	for (var i = 0; i < len; i++) stars += '*';
	return stars;
};

/**
 * Compares
 *
 * @api public
 */
password.prototype.compare = function (item, candidate, callback) {
	if (typeof callback !== 'function') throw new Error('Password.compare() requires a callback function.');
	var value = item.get(this.path);
	if (!value) return callback(null, false);
	bcrypt.compare(candidate, item.get(this.path), callback);
};

/**
 * Asynchronously confirms that the provided password is valid
 */
password.prototype.validateInput = function (data, callback) {
	var detail;
	var result = true;
	var confirmValue = this.getValueFromData(data, '_confirm');
	var passwordValue = this.getValueFromData(data);
	if (passwordValue !== undefined && confirmValue !== undefined && passwordValue !== confirmValue) {
		result = false;
		detail = 'passwords must match';
	}
	// TODO: we could support a password complexity option (or regexp) here
	utils.defer(callback, result, detail);
};

/**
 * Asynchronously confirms that the provided password is valid
 */
password.prototype.validateRequiredInput = function (item, data, callback) {
	var hashValue = this.getValueFromData(data, '_hash');
	var passwordValue = this.getValueFromData(data);
	var result = hashValue || passwordValue ? true : false;
	if (!result && passwordValue === undefined && hashValue === undefined && item.get(this.path)) result = true;
	utils.defer(callback, result);
};

/**
 * If password fields are required, check that either a value has been
 * provided or already exists in the field.
 *
 * Otherwise, input is always considered valid, as providing an empty
 * value will not change the password.
 *
 * Deprecated
 */
password.prototype.inputIsValid = function (data, required, item) {
	if (data[this.path] && this.paths.confirm in data) {
		return data[this.path] === data[this.paths.confirm] ? true : false;
	}
	if (data[this.path] || data[this.paths.hash] || (item && item.get(this.path))) return true;
	return required ? false : true;
};

/**
 * Updates the value for this field in the item from a data object
 *
 * Will accept either the field path, or paths.hash to bypass bcrypt
 *
 * @api public
 */
password.prototype.updateItem = function (item, data, callback) {
	var hashValue = this.getValueFromData(data, '_hash');
	var passwordValue = this.getValueFromData(data);
	if (passwordValue !== undefined) {
		item.set(this.path, passwordValue);
	} else if (hashValue !== undefined) {
		item.set(this.paths.hash, hashValue);
	}
	process.nextTick(callback);
};

/* Export Field Type */
module.exports = password;
<|endoftext|>


<commit_before>
mi2JS.addCompClass('base/CalendarWidget', 'Base', '<-TEMPLATE->',

// component initializer function that defines constructor and adds methods to the prototype
function(proto, superProto, comp, superComp){

	var mi2 = mi2JS; // minimizer friendly

	proto.construct = function(el, parent){
		// template is not pased because it will be used only if no inline template is defined
		superProto.construct.call(this, el, parent);
		this.dayOffset = 1;

		this.addClass('CalendarWidget');
	};

	proto.initChildren = function(){
		superProto.initChildren.call(this);

		this.listen(this.dayGrid.el,'mousedown','on_dayClick');

		this.year.trackChanges();
		this.month.trackChanges();

		this.listen(this.month,'change','on_selectChange');
		this.listen(this.year,'change','on_selectChange');

		this.date = new Date();

		this.initElements();
		var l = [this.done.el, this.year.el, this.month.el, this.today.el, this.done.el, this.clear.el];

		this.listen(this.el,'mousedown',function(evt){
			for(var i=0; i<l.length; i++) if(evt.target == l[i]) return;
			this.done.el.focus();
		});

		for(var i=0; i<l.length; i++){
			this.listen(l[i],'focus','fireFocus');
			this.listen(l[i],'blur','fireBlur');
		}

	};

	proto.fireFocus = function(evt){
		this.fireEvent({name:'focus',domEvent:evt});
	};

	proto.fireBlur = function(evt){
		this.fireEvent({name:'blur',domEvent:evt});
	};

	proto.initElements = function(){
		// Date.getDay:  0 = Sunday
		var tr = mi2.addTag(this.dayNames.el,'TR');
		var names = this.dayNames.el.getAttribute('names').split(',');
		for(var i=0; i<7; i++){
			var wd = (i+this.dayOffset)%7;
			mi2.addTag(tr, {tag:'TH',attr:{'class':'day'+wd,html:names[wd]}});
		}
		this.days = [];
		for(var r=0; r<6; r++){
			tr = mi2.addTag(this.dayGrid.el,'TR');
			for(var c=0; c<7; c++){
				this.days.push(mi2.addTag(tr,'TD'));
			}
		}

	};

	proto.on_selectChange = function(evt){
		this.setDate(this.year.getValue(), this.month.getValue());
	};

	proto.setDate = function(year,month,day){
		var d = this.date;
		if(!d) d = new Date(0,0,0,0,0,0,0);
		this.update(new Date(
			year || d.getFullYear(),
			// month can be zero so same trick can not be used like for year
			typeof(month) !== 'undefined' ? month : d.getMonth(),
			day || d.getDate(),
			d.getHours(),
			d.getMinutes(),
			d.getSeconds()
		));
	};

	proto.update = function(date){
		this.date = date;
		var now = new Date();
		if(!date ) date = now;

		var m1 = new Date(date.getFullYear(), date.getMonth(),1);
		var offset = (m1.getDay()-this.dayOffset+7)%7;
		if(offset === 0) offset = 7;
		var first = new Date(m1.getFullYear(), m1.getMonth(),1 - offset);
		var count = this.days.length;
		for(var i=0; i<count; i++){
			var td = this.days[i];
			var day = td.date = new Date(first.getFullYear(), first.getMonth(),first.getDate()+i);
			if(i<offset){
				td.className='prevMonth';
			}else if(day.getMonth() != date.getMonth()){
				td.className='nextMonth';
			}else{
				td.className='curMonth';

				if( this.date &&
					day.getDate() == date.getDate() &&
					day.getMonth() == date.getMonth())
					td.className += ' selected';

				if(day.getFullYear() == now.getFullYear() &&
					day.getMonth() == now.getMonth() &&
					day.getDate() == now.getDate())
					td.className += ' today';

			}
			td.className += ' day'+day.getDay();
			td.innerHTML = day.getDate();
		}

		var year = date.getFullYear();
		years = [];
		for(var i=year-5; i<year+5; i++){
			years.push(''+i);
		}
		this.year.setConfig(years);
		this.year.setValue(year);
		this.month.setValue(date.getMonth());

	};

	proto.on_dayClick = function(evt){
		var td = evt.target;
		if(td.tagName != 'TD') return;

		var d = td.date;
		this.setDate( d.getFullYear(), d.getMonth(), d.getDate() );
		this.on_done();
	};

	proto.on_done = function(evt){
		var date = this.date;
		if(evt && evt.action == 'clear') date = null;
		this.fireEvent({name:'dateSelected', widget: this, date:date, fireTo:'parent'});
	};

	proto.on_today = function(evt){
		var d = new Date();
		this.setDate( d.getFullYear(), d.getMonth(), d.getDate() );
		this.on_done();
	};

});
<commit_msg>bugfix, missing day names<commit_after>
mi2JS.addCompClass('base/CalendarWidget', 'Base', '<-TEMPLATE->',

// component initializer function that defines constructor and adds methods to the prototype
function(proto, superProto, comp, superComp){

	var mi2 = mi2JS; // minimizer friendly

	proto.construct = function(el, parent){
		// template is not pased because it will be used only if no inline template is defined
		superProto.construct.call(this, el, parent);
		this.dayOffset = 1;

		this.addClass('CalendarWidget');
	};

	proto.initChildren = function(){
		superProto.initChildren.call(this);

		this.listen(this.dayGrid.el,'mousedown','on_dayClick');

		this.year.trackChanges();
		this.month.trackChanges();

		this.listen(this.month,'change','on_selectChange');
		this.listen(this.year,'change','on_selectChange');

		this.date = new Date();

		this.initElements();
		var l = [this.done.el, this.year.el, this.month.el, this.today.el, this.done.el, this.clear.el];

		this.listen(this.el,'mousedown',function(evt){
			for(var i=0; i<l.length; i++) if(evt.target == l[i]) return;
			this.done.el.focus();
		});

		for(var i=0; i<l.length; i++){
			this.listen(l[i],'focus','fireFocus');
			this.listen(l[i],'blur','fireBlur');
		}

	};

	proto.fireFocus = function(evt){
		this.fireEvent({name:'focus',domEvent:evt});
	};

	proto.fireBlur = function(evt){
		this.fireEvent({name:'blur',domEvent:evt});
	};

	proto.initElements = function(){
		// Date.getDay:  0 = Sunday
		var tr = mi2.addTag(this.dayNames.el,'TR');
		var names = this.dayNames.el.getAttribute('names').split(',');
		for(var i=0; i<7; i++){
			var wd = (i+this.dayOffset)%7;
			mi2.addTag(tr, {tag:'TH',attr:{'class':'day'+wd},html:names[wd]});
		}
		this.days = [];
		for(var r=0; r<6; r++){
			tr = mi2.addTag(this.dayGrid.el,'TR');
			for(var c=0; c<7; c++){
				this.days.push(mi2.addTag(tr,'TD'));
			}
		}

	};

	proto.on_selectChange = function(evt){
		this.setDate(this.year.getValue(), this.month.getValue());
	};

	proto.setDate = function(year,month,day){
		var d = this.date;
		if(!d) d = new Date(0,0,0,0,0,0,0);
		this.update(new Date(
			year || d.getFullYear(),
			// month can be zero so same trick can not be used like for year
			typeof(month) !== 'undefined' ? month : d.getMonth(),
			day || d.getDate(),
			d.getHours(),
			d.getMinutes(),
			d.getSeconds()
		));
	};

	proto.update = function(date){
		this.date = date;
		var now = new Date();
		if(!date ) date = now;

		var m1 = new Date(date.getFullYear(), date.getMonth(),1);
		var offset = (m1.getDay()-this.dayOffset+7)%7;
		if(offset === 0) offset = 7;
		var first = new Date(m1.getFullYear(), m1.getMonth(),1 - offset);
		var count = this.days.length;
		for(var i=0; i<count; i++){
			var td = this.days[i];
			var day = td.date = new Date(first.getFullYear(), first.getMonth(),first.getDate()+i);
			if(i<offset){
				td.className='prevMonth';
			}else if(day.getMonth() != date.getMonth()){
				td.className='nextMonth';
			}else{
				td.className='curMonth';

				if( this.date &&
					day.getDate() == date.getDate() &&
					day.getMonth() == date.getMonth())
					td.className += ' selected';

				if(day.getFullYear() == now.getFullYear() &&
					day.getMonth() == now.getMonth() &&
					day.getDate() == now.getDate())
					td.className += ' today';

			}
			td.className += ' day'+day.getDay();
			td.innerHTML = day.getDate();
		}

		var year = date.getFullYear();
		years = [];
		for(var i=year-5; i<year+5; i++){
			years.push(''+i);
		}
		this.year.setConfig(years);
		this.year.setValue(year);
		this.month.setValue(date.getMonth());

	};

	proto.on_dayClick = function(evt){
		var td = evt.target;
		if(td.tagName != 'TD') return;

		var d = td.date;
		this.setDate( d.getFullYear(), d.getMonth(), d.getDate() );
		this.on_done();
	};

	proto.on_done = function(evt){
		var date = this.date;
		if(evt && evt.action == 'clear') date = null;
		this.fireEvent({name:'dateSelected', widget: this, date:date, fireTo:'parent'});
	};

	proto.on_today = function(evt){
		var d = new Date();
		this.setDate( d.getFullYear(), d.getMonth(), d.getDate() );
		this.on_done();
	};

});
<|endoftext|>


<commit_before>var React = require('react');
var ReactDOM = require('react-dom');

var ResizableComponent = React.createClass({displayName: "ResizableComponent",
	getInitialState: function() {
		return {
			// Mouse events
			mouseHeldDown: false,
			originalY: 0,
			originalX: 0,

			// Dimensions of box
			direction: this.props.direction,
			initialBoxHeight: this.props.height,
			initialBoxWidth: this.props.width,
			boxHeight: this.props.height,
			boxWidth: this.props.width,
			minHeight: this.props.options.minHeight ? this.props.options.minHeight : this.props.height,
			minWidth: this.props.options.minWidth ? this.props.options.minWidth : this.props.width,
			maxHeight: this.props.options.maxHeight ? this.props.options.maxHeight : Infinity,
			maxWidth: this.props.options.maxWidth ? this.props.options.maxWidth : Infinity,
			lockAspectRatio: this.props.options.lockAspectRatio ? this.props.options.lockAspectRatio : false,

			// Stepping of resizing
			step: this.props.options.step ? this.props.options.step : 1,
			currStepY: 0,
			currStepX: 0,
			steppingMargin: this.props.steppingMargin,
			originalBoxWidth: this.props.width,
			originalBoxHeight: this.props.height,

			// Width of resizable handle
			cursorMargin: this.props.options.cursorMargin ? this.props.options.cursorMargin : this.props.cursorMargin,

			// Ghost Resizing
			allowGhostResize: this.props.options.allowGhostResize ? this.props.options.allowGhostResize : false
		};
	},

	propTypes: {
		children: React.PropTypes.element.isRequired,
		direction: React.PropTypes.oneOf(['s', 'e', 'se']),

		// Dimensions
		width: React.PropTypes.number,
		height: React.PropTypes.number,

		// Styling
		cssStyles: React.PropTypes.object,
		ghostCssStyles: React.PropTypes.object,

		// Callbacks
		onStartResize: React.PropTypes.func,
		onStopResize: React.PropTypes.func,
		onEachStep: React.PropTypes.func,
		onDuringResize: React.PropTypes.func,

		// Other options
		options: React.PropTypes.object
	},

	getDefaultProps: function() {
		return {
			options: {},
			direction: 's',

			height: 50,
			width: 250,

			steppingMargin: 20,
			cursorMargin: 10
		};
	},

	componentDidMount: function() {
	    var _this = this;
	    var parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[0].name;
	    var parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[0].value;

	    // Attaches event listeners to parent div
	    document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mousemove', (e) => {
	      _this._resizeDiv(e);
	    });
	    document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mouseup', (e) => {
	      _this._stopDrag(e);
	    });
	    document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mouseleave', (e) => {
	      _this._stopDrag(e);
	    });
	},

	_startDrag: function(e) {
		this.makeParentHighlightable(false);
		this.setState({
			mouseHeldDown: true,
			originalY: e.clientY,
			originalX: e.clientX
		}, function() {
			if (this.props.onStartResize) this.props.onStartResize(
				(this.state.boxWidth - this.state.originalBoxWidth) / this.state.step,
				(this.state.boxHeight - this.state.originalBoxHeight) / this.state.step
			);
		});
	},

	_stopDrag: function(e) {
    	this.makeParentHighlightable(true);
		// Only invoke onStopResize if this component has started resizing
		if (this.state.mouseHeldDown && this.props.onStopResize) {
			this.props.onStopResize(
				(this.state.boxWidth - this.state.originalBoxWidth) / this.state.step,
				(this.state.boxHeight - this.state.originalBoxHeight) / this.state.step
			);
		}
		if (!this.state.allowGhostResize) {
			this.setState({
				mouseHeldDown: false,
				initialBoxHeight: this.state.boxHeight,
				initialBoxWidth: this.state.boxWidth
			});
		} else {
			// Ghost resizing
			// Change the dimensions back to the original
			this.setState({
				mouseHeldDown: false,
				boxHeight: this.state.originalBoxHeight,
				boxWidth: this.state.originalBoxWidth
			});
		}

	},

	_resizeDiv: function(e) {
		if (this.state.mouseHeldDown) {
			var distanceY = e.clientY - this.state.originalY;
			var distanceX = e.clientX - this.state.originalX;

			var newHeight = this.state.initialBoxHeight + distanceY;
			var newWidth = this.state.initialBoxWidth + distanceX;

			var steppingRemainderY = distanceY % this.state.step;
			var steppingRemainderX = distanceX % this.state.step;

			// NOTE: For checking whether the new dimensions violates the minimum constraints,
			// The steeping margin is given as allowance so that the box can be re-sized to the smallest
			// dimension smoothly.
			var heightCanChange = newHeight >= (this.state.minHeight - this.state.steppingMargin)
				&& newHeight <= (this.state.maxHeight + this.state.steppingMargin) // newHeight is below maxHeight
				&& steppingRemainderY <= this.state.steppingMargin // A little allowance is given for stepping
				&& this.state.direction.indexOf('s') > -1;

			var widthCanChange = newWidth >= (this.state.minWidth - this.state.steppingMargin)
				&& newWidth <= (this.state.maxWidth + this.state.steppingMargin)
				&& steppingRemainderX <= this.state.steppingMargin
				&& this.state.direction.indexOf('e') > -1;

			// If new dimensions are indeed lesser than the minimum constraint or greater than the maximum constraint,
			// set the dimension to the minimum/maximum respectively
			newHeight = newHeight - steppingRemainderY;
			newWidth = newWidth - steppingRemainderX;
			if (newHeight < this.state.minHeight) newHeight = this.state.minHeight;
			if (newWidth < this.state.minWidth) newWidth = this.state.minWidth;
			if (newHeight > this.state.maxHeight) newHeight = this.state.maxHeight;
			if (newWidth > this.state.maxWidth) newWidth = this.state.maxWidth;

			// If lockAspectRatio is true, we programatically calculate the width
			if (this.state.direction === 'se' && this.state.lockAspectRatio) {
				var aspectRatio = this.state.originalBoxHeight / this.state.originalBoxWidth;
				newWidth = newHeight / aspectRatio;
			}

			this.setState({
				boxHeight: heightCanChange ? newHeight : this.state.boxHeight,
				boxWidth: widthCanChange ? newWidth : this.state.boxWidth
			}, function() {

				// Callback for onDuringResize
				// Not called when step is active
				if (this.props.onDuringResize && this.state.step === 1) {
					this.props.onDuringResize(this.state.boxWidth,
					this.state.boxHeight);
				}

				// Callback for onEachStep
				// Only when step size has changed, then we invoke to callback
				if ((this.state.boxHeight !== this.state.currStepY || this.state.boxWidth !== this.state.currStepX)
					&& this.props.onEachStep && this.state.step > 1) {
					this.props.onEachStep(
						(this.state.boxWidth - this.state.originalBoxWidth) / this.state.step,
						(this.state.boxHeight - this.state.originalBoxHeight) / this.state.step
					);
					this.setState({
						currStepY: this.state.boxHeight,
						currStepX: this.state.boxWidth
					});
				}

			});

    	}
	},

	// Styles the resize handler according to the direction given
	getResizeHandlerStyle: function() {
		var resizeHandlerStyle = {};

		if (this.state.direction === 's') {
			resizeHandlerStyle = {
				width: this.state.boxWidth + 'px',
				height: this.state.cursorMargin + 'px',
				cursor: 's-resize',
				position: 'absolute',
				bottom: '0px',
				left: '0px'
			};
		}

		if (this.state.direction === 'e') {
			resizeHandlerStyle = {
				width: this.state.cursorMargin + 'px',
				height: this.state.boxHeight + 'px',
				cursor: 'e-resize',
				position: 'absolute',
				bottom: '0px',
				right: '0px'
			};
		}

		if (this.state.direction === 'se') {
			resizeHandlerStyle = {
				width: this.state.cursorMargin + 'px',
				height: this.state.cursorMargin + 'px',
				cursor: 'se-resize',
				position: 'absolute',
				bottom: '0px',
				right: '0px'
			};
		}

		return resizeHandlerStyle;
	},

	// Helper function to make the all components in parent non-highlight-able
	makeParentHighlightable: function(highlight) {
		var _this = this;
		var parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[0].name;
		var parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[0].value;

		// Attaches event listeners to parent div
		document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.userSelect = highlight ? 'all' : 'none';
		document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.mozUserSelect = highlight ? 'all' : 'none';
		document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.webkitUserSelect = highlight ? 'all' : 'none';
	},

	render: function() {
		var outerDivStyle = {
			backgroundColor: 'transparent',
			width: (!this.state.allowGhostResize) ? this.state.boxWidth + 'px' : this.state.originalBoxWidth,
			height: (!this.state.allowGhostResize) ? this.state.boxHeight + 'px' : this.state.originalBoxHeight,
			cursor: 'default',
			position: 'relative'
		};

		// Merge in any custom styles and overwrite existing styles (if any)
		if (this.props.cssStyles) {
			var customStyles = this.props.cssStyles;
			for (var prop in customStyles) outerDivStyle[prop] = customStyles[prop];
		}

    	var resizeHandlerStyle = this.getResizeHandlerStyle();

		// For ghostResizing
		var highlightDiv;
		if (this.state.allowGhostResize) {
			var ghostDivStyles = {
				zIndex: '1',
				display: this.state.mouseHeldDown ? 'block' : 'none',
				backgroundColor: '#000000',
				opacity: '0.3',
				width: this.state.boxWidth + 'px',
				height: this.state.boxHeight + 'px',
				cursor: 'default',
				position: 'absolute',
				top: '0px',
				left: '0px'
			};
			if (this.props.ghostCssStyles) {
				var css = this.props.ghostCssStyles
				for (var prop in css) ghostDivStyles[prop] = css[prop];
			}
			highlightDiv = React.createElement("div", {className: "ghostDiv", style: ghostDivStyles})
		}

		return React.createElement("div", {className: "outer-box-container", style: outerDivStyle},
			highlightDiv,
			React.createElement("div", {className: "resize-handler", style: resizeHandlerStyle, onMouseDown: this._startDrag}),
			this.props.children
		);
	}
});

module.exports = ResizableComponent;
<commit_msg>Delete ResizableComponent.js<commit_after><|endoftext|>


<commit_before>var chokidar = require('chokidar');
var exec = require('child_process').exec;
var fs = require('fs');
var gui = require('nw.gui');
var notifier = require('node-notifier');
var os = require('os');
var path = require('path');

var Settings = require('./js/settings');
var Services = require('./js/services');

process.on('uncaughtException', function(err) {
  console.log('Caught exception: ', err);
  window.alert('There was an uncaught exception.');
});

function Pussh() {
    this.settings = new Settings();
    this.name = gui.App.manifest.name;
    this.version = gui.App.manifest.version;
    this.window = gui.Window.get();
    this.tink = new Audio('aud/ts-tink.ogg');

    this.services = new Services(this);

    this.watch();
    this.launchAtStartup();
    this.setupTray();
    this.buildTrayMenu(false);
}

Pussh.prototype.setupTray = function() {
    // create status item
    this.tray = new gui.Tray({
        icon: path.join(process.cwd(), 'Resources', 'img', 'menu-icon@2x.png'),
        alticon: path.join(process.cwd(), 'Resources', 'img', 'menu-alt-icon@2x.png')
    });
}

Pussh.prototype.buildTrayMenu = function(lastURL) {
    var _self = this;

    var menu = new gui.Menu();

    // add the last url
    if (lastURL) {
        menu.append(new gui.MenuItem({
            label: lastURL,
            click: function() {
                _self.copyToClipboard(lastURL);
            }
        }));
    }

    // open settings
    menu.append(new gui.MenuItem({
        label: 'Settings',
        click: function() {
            var settingsWindow = gui.Window.open('settings-window.html', {
                "focus": true,
                "toolbar": true,
                "width": 800,
                "height": 600
            });
        }
    }));

    // quit app
    menu.append(new gui.MenuItem({
        label: 'Quit '+this.name,
        click: function() {
            gui.App.quit();
        }
    }));

    _self.tray.menu = menu;

    var nativeMenuBar = new gui.Menu({ type: "menubar" });
    nativeMenuBar.createMacBuiltin(this.name);
    this.window.menu = nativeMenuBar;
}

// TODO: Watching for screenshots works on OSX, but what about Windows/*nix
Pussh.prototype.watch = function() {
    var _self = this;

    var desktopFolder = path.join(process.env['HOME'], 'Desktop');

    var watcher = chokidar.watch(desktopFolder, {ignored: function(file) {
        return /\./.test(file) ? false : true;
    }, persistent: true, ignoreInitial: true, interval: 200});

    watcher.on('add', function(file) {
        exec('/usr/bin/mdls --raw --name kMDItemIsScreenCapture "'+file+'"', function(error, stdout) {
            if(error) return;

            if(!parseInt(stdout)) return; // 1 = screenshot, 0 = not a screenshot

            console.log('Uploading %s', file);

            file = _self.moveToTemp(file);

            _self.upload(file);
        });
    });
}

Pussh.prototype.launchAtStartup = function() {
    if(this.settings.get('launchAtStartup') === true) {
        switch(os.platform()) {
            case 'win32':
                // TODO
                break;
            case 'darwin':
                var pathToExecutable = path.join(process.execPath, '../../../../../../').replace(/\/$/, '');
                exec('osascript -e \'tell application "System Events" to make login item at end with properties {path:"'+pathToExecutable+'", hidden:false}\'');
                break;
            case 'linux':
                // TODO
                break;
            default:
                return;
        }
    } else {
        switch(os.platform()) {
            case 'win32':
                // TODO
                break;
            case 'darwin':
                exec('osascript -e \'tell application "System Events" to delete login item "'+this.name+'"\'');
                break;
            case 'linux':
                // TODO
                break;
            default:
                return;
        }
    }
}

// Uploads a new file
// TODO: Tray icon status change to uploading
Pussh.prototype.upload = function(file) {
    var _self = this;

    var selectedService = _self.settings.get('selectedService');

    file = this.randomizeFilename(file);
    file = this.prefixFilename(file);

    if(_self.settings.get('enableNotifications')) {
        notifier.notify({
            title: 'Pussh',
            message: 'Pussh has initiated a screenshot upload.',
            icon: os.platform() !== 'darwin' ? path.join(process.cwd(), 'Resources', 'img', 'icon.png') : undefined,
            sender: 'com.intel.nw'
        });
    }

    // set status icon to active
    _self.tray.icon = path.join(process.cwd(), 'Resources', 'img', 'menu-active-icon@2x.png');

    this.resize(file, function() {
        _self.services.get(selectedService).upload(file, function(url) {
            _self.trash(file);
            _self.copyToClipboard(url);

            if(_self.settings.get('audioNotifications')) {
                _self.tink.load();
                _self.tink.play();
            }

            if(_self.settings.get('openBrowser')) {
                gui.Shell.openExternal(url);
            }

            // set status icon to complete for 3 seconds
            _self.tray.icon = path.join(process.cwd(), 'Resources', 'img', 'menu-done-icon@2x.png');
            setTimeout(function() {
                _self.tray.icon = path.join(process.cwd(), 'Resources', 'img', 'menu-icon@2x.png');
            }, 3000);

            _self.buildTrayMenu(url);
        });
    });
}

Pussh.prototype.moveToTemp = function(file) {
    var tmpFile;

    switch(os.platform()) {
        case 'win32':
            tmpFile = path.join(process.env['TEMP'], path.basename(file));
            break;
        case 'darwin':
            tmpFile = path.join(process.env['TMPDIR'], path.basename(file));
            break;
        case 'linux':
            tmpFile = path.join('/tmp', path.basename(file));
            break;
        default:
            return;
    }

    fs.writeFileSync(tmpFile, fs.readFileSync(file));
    return tmpFile;
}

// Trash file after upload
Pussh.prototype.trash = function(file) {
    var _self = this;

    if(_self.settings.get('sendToTrash') === false) return;

    var trashFolder;

    switch(os.platform()) {
        case 'win32':
            trashFolder = path.join(process.env['SystemRoot'], '$Recycle.bin', process.env['SID']);
            break;
        case 'darwin':
            trashFolder = path.join(process.env['HOME'], '.Trash');
            break;
        case 'linux':
            trashFolder = path.join(process.env['HOME'], '.local', 'share', 'Trash');
            break;
        default:
            return;
    }

    // We could just delete the file, but what if the user wants it back
    fs.rename(file, path.join(trashFolder, path.basename(file)));
}

Pussh.prototype.randomizeFilename = function(file) {
    if(this.settings.get('randomizeFilenames') === false) return file;

    var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    var newName = "";

    for(var i=0; i < this.settings.get('randomizeFilenamesLength'); i++) {
        newName += characters.charAt(Math.floor(Math.random()*characters.length));
    }

    newName += path.extname(file); // Append file extension

    var newFile = path.join(path.dirname(file), newName);
    fs.renameSync(file, newFile);
    return newFile;
}

Pussh.prototype.prefixFilename = function(file) {
    if(!this.settings.get('prefixFilenames').length) return file;

    var newName = this.settings.get('prefixFilenames')+path.basename(file);

    var newFile = path.join(path.dirname(file), newName);
    fs.renameSync(file, newFile);
    return newFile;
}

// Retina screens cause issues, so we give the option to resize
Pussh.prototype.resize = function(file, callback) {
    var _self = this;

    if(os.platform() !== 'darwin' || _self.settings.get('retinaResize') === false) return callback();

    exec('/usr/bin/sips -g dpiWidth -g pixelWidth "'+file+'"', function(error, stdout) {
        if(error) return callback();

        var lines = stdout.split('\n');

        var dpiWidth = parseFloat(lines[1].split(':')[1].trim());
        var pixelWidth = parseInt(lines[2].split(':')[1].trim());

        if(parseInt(dpiWidth) === 72) return callback();

        var newWidth = Math.round((72 / dpiWidth) * pixelWidth);

        exec('/usr/bin/sips --resampleWidth '+newWidth+' "'+file+'"', function(error, stdout) {
            callback();
        });
    });
}

// Copy url to clipboard after upload
Pussh.prototype.copyToClipboard = function(url) {
    var _self = this;

    var clipboard = gui.Clipboard.get();
    clipboard.set(url);

    if(_self.settings.get('enableNotifications')) {
        notifier.notify({
            title: 'Pussh',
            message: 'The screenshot URL has been copied to your clipboard.',
            icon: os.platform() !== 'darwin' ? path.join(process.cwd(), 'Resources', 'img', 'icon.png') : undefined,
            sender: 'com.intel.nw'
        });
    }
}

global.Pussh = new Pussh();
<commit_msg>Switch to not using regexes Don't show toolbar on settings page<commit_after>var chokidar = require('chokidar');
var exec = require('child_process').exec;
var fs = require('fs');
var gui = require('nw.gui');
var notifier = require('node-notifier');
var os = require('os');
var path = require('path');

var Settings = require('./js/settings');
var Services = require('./js/services');

process.on('uncaughtException', function(err) {
  console.log('Caught exception: ', err);
  window.alert('There was an uncaught exception.');
});

function Pussh() {
    this.settings = new Settings();
    this.name = gui.App.manifest.name;
    this.version = gui.App.manifest.version;
    this.window = gui.Window.get();
    this.tink = new Audio('aud/ts-tink.ogg');

    this.services = new Services(this);

    this.watch();
    this.launchAtStartup();
    this.setupTray();
    this.buildTrayMenu(false);
}

Pussh.prototype.setupTray = function() {
    // create status item
    this.tray = new gui.Tray({
        icon: path.join(process.cwd(), 'Resources', 'img', 'menu-icon@2x.png'),
        alticon: path.join(process.cwd(), 'Resources', 'img', 'menu-alt-icon@2x.png')
    });
}

Pussh.prototype.buildTrayMenu = function(lastURL) {
    var _self = this;

    var menu = new gui.Menu();

    // add the last url
    if (lastURL) {
        menu.append(new gui.MenuItem({
            label: lastURL,
            click: function() {
                _self.copyToClipboard(lastURL);
            }
        }));
    }

    // open settings
    menu.append(new gui.MenuItem({
        label: 'Settings',
        click: function() {
            var settingsWindow = gui.Window.open('settings-window.html', {
                "focus": true,
                "toolbar": false,
                "width": 800,
                "height": 600
            });
        }
    }));

    // quit app
    menu.append(new gui.MenuItem({
        label: 'Quit '+this.name,
        click: function() {
            gui.App.quit();
        }
    }));

    _self.tray.menu = menu;

    var nativeMenuBar = new gui.Menu({ type: "menubar" });
    nativeMenuBar.createMacBuiltin(this.name);
    this.window.menu = nativeMenuBar;
}

// TODO: Watching for screenshots works on OSX, but what about Windows/*nix
Pussh.prototype.watch = function() {
    var _self = this;

    var desktopFolder = path.join(process.env['HOME'], 'Desktop');

    var watcher = chokidar.watch(desktopFolder, {ignored: function(file) {
        return (file === desktopFolder || file.indexOf('.') > -1) ? false : true;
    }, persistent: true, ignoreInitial: true, interval: 200});

    watcher.on('add', function(file) {
        exec('/usr/bin/mdls --raw --name kMDItemIsScreenCapture "'+file+'"', function(error, stdout) {
            if(error) return;

            if(!parseInt(stdout)) return; // 1 = screenshot, 0 = not a screenshot

            console.log('Uploading %s', file);

            file = _self.moveToTemp(file);

            _self.upload(file);
        });
    });
}

Pussh.prototype.launchAtStartup = function() {
    if(this.settings.get('launchAtStartup') === true) {
        switch(os.platform()) {
            case 'win32':
                // TODO
                break;
            case 'darwin':
                var pathToExecutable = path.join(process.execPath, '../../../../../../').replace(/\/$/, '');
                exec('osascript -e \'tell application "System Events" to make login item at end with properties {path:"'+pathToExecutable+'", hidden:false}\'');
                break;
            case 'linux':
                // TODO
                break;
            default:
                return;
        }
    } else {
        switch(os.platform()) {
            case 'win32':
                // TODO
                break;
            case 'darwin':
                exec('osascript -e \'tell application "System Events" to delete login item "'+this.name+'"\'');
                break;
            case 'linux':
                // TODO
                break;
            default:
                return;
        }
    }
}

// Uploads a new file
// TODO: Tray icon status change to uploading
Pussh.prototype.upload = function(file) {
    var _self = this;

    var selectedService = _self.settings.get('selectedService');

    file = this.randomizeFilename(file);
    file = this.prefixFilename(file);

    if(_self.settings.get('enableNotifications')) {
        notifier.notify({
            title: 'Pussh',
            message: 'Pussh has initiated a screenshot upload.',
            icon: os.platform() !== 'darwin' ? path.join(process.cwd(), 'Resources', 'img', 'icon.png') : undefined,
            sender: 'com.intel.nw'
        });
    }

    // set status icon to active
    _self.tray.icon = path.join(process.cwd(), 'Resources', 'img', 'menu-active-icon@2x.png');

    this.resize(file, function() {
        _self.services.get(selectedService).upload(file, function(url) {
            _self.trash(file);
            _self.copyToClipboard(url);

            if(_self.settings.get('audioNotifications')) {
                _self.tink.load();
                _self.tink.play();
            }

            if(_self.settings.get('openBrowser')) {
                gui.Shell.openExternal(url);
            }

            // set status icon to complete for 3 seconds
            _self.tray.icon = path.join(process.cwd(), 'Resources', 'img', 'menu-done-icon@2x.png');
            setTimeout(function() {
                _self.tray.icon = path.join(process.cwd(), 'Resources', 'img', 'menu-icon@2x.png');
            }, 3000);

            _self.buildTrayMenu(url);
        });
    });
}

Pussh.prototype.moveToTemp = function(file) {
    var tmpFile;

    switch(os.platform()) {
        case 'win32':
            tmpFile = path.join(process.env['TEMP'], path.basename(file));
            break;
        case 'darwin':
            tmpFile = path.join(process.env['TMPDIR'], path.basename(file));
            break;
        case 'linux':
            tmpFile = path.join('/tmp', path.basename(file));
            break;
        default:
            return;
    }

    fs.writeFileSync(tmpFile, fs.readFileSync(file));
    return tmpFile;
}

// Trash file after upload
Pussh.prototype.trash = function(file) {
    var _self = this;

    if(_self.settings.get('sendToTrash') === false) return;

    var trashFolder;

    switch(os.platform()) {
        case 'win32':
            trashFolder = path.join(process.env['SystemRoot'], '$Recycle.bin', process.env['SID']);
            break;
        case 'darwin':
            trashFolder = path.join(process.env['HOME'], '.Trash');
            break;
        case 'linux':
            trashFolder = path.join(process.env['HOME'], '.local', 'share', 'Trash');
            break;
        default:
            return;
    }

    // We could just delete the file, but what if the user wants it back
    fs.rename(file, path.join(trashFolder, path.basename(file)));
}

Pussh.prototype.randomizeFilename = function(file) {
    if(this.settings.get('randomizeFilenames') === false) return file;

    var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    var newName = "";

    for(var i=0; i < this.settings.get('randomizeFilenamesLength'); i++) {
        newName += characters.charAt(Math.floor(Math.random()*characters.length));
    }

    newName += path.extname(file); // Append file extension

    var newFile = path.join(path.dirname(file), newName);
    fs.renameSync(file, newFile);
    return newFile;
}

Pussh.prototype.prefixFilename = function(file) {
    if(!this.settings.get('prefixFilenames').length) return file;

    var newName = this.settings.get('prefixFilenames')+path.basename(file);

    var newFile = path.join(path.dirname(file), newName);
    fs.renameSync(file, newFile);
    return newFile;
}

// Retina screens cause issues, so we give the option to resize
Pussh.prototype.resize = function(file, callback) {
    var _self = this;

    if(os.platform() !== 'darwin' || _self.settings.get('retinaResize') === false) return callback();

    exec('/usr/bin/sips -g dpiWidth -g pixelWidth "'+file+'"', function(error, stdout) {
        if(error) return callback();

        var lines = stdout.split('\n');

        var dpiWidth = parseFloat(lines[1].split(':')[1].trim());
        var pixelWidth = parseInt(lines[2].split(':')[1].trim());

        if(parseInt(dpiWidth) === 72) return callback();

        var newWidth = Math.round((72 / dpiWidth) * pixelWidth);

        exec('/usr/bin/sips --resampleWidth '+newWidth+' "'+file+'"', function(error, stdout) {
            callback();
        });
    });
}

// Copy url to clipboard after upload
Pussh.prototype.copyToClipboard = function(url) {
    var _self = this;

    var clipboard = gui.Clipboard.get();
    clipboard.set(url);

    if(_self.settings.get('enableNotifications')) {
        notifier.notify({
            title: 'Pussh',
            message: 'The screenshot URL has been copied to your clipboard.',
            icon: os.platform() !== 'darwin' ? path.join(process.cwd(), 'Resources', 'img', 'icon.png') : undefined,
            sender: 'com.intel.nw'
        });
    }
}

global.Pussh = new Pussh();
<|endoftext|>


<commit_before>const _ = require("lodash");
const CarouselClass = require("../src/carousel");
const ViewportDetect = require("viewport-detection-es6");

function createCarousel() {
  let carouselInner = document.createElement("div");
  let carouselOuter = document.createElement("div");

  carouselInner.className = "carousel-inner";
  carouselOuter.id = "carousel";

  carouselOuter.appendChild(carouselInner);

  createCarouselItems(carouselInner);

  document.body.appendChild(carouselOuter);

  return carouselOuter;
}

function createCarouselImageContainers(item, i) {
  let dataURLDesktop, dataURLMobile, dataURLTablet;
  let carouselImageContainer = document.createElement("div");

  carouselImageContainer.className = "carousel-image-container";

  dataURLDesktop = "desktop.jpg";

  if(i % 2) {
    dataURLMobile = "null";
    dataURLTablet = "null";
  } else {
    dataURLMobile = "mobile.jpg";
    dataURLTablet = "tablet.jpg";
  }

  carouselImageContainer.setAttribute("data-mobile", dataURLMobile);
  carouselImageContainer.setAttribute("data-tablet", dataURLTablet);
  carouselImageContainer.setAttribute("data-desktop", dataURLDesktop);

  carouselImageContainer.style.backgroundImage = "url('" + dataURLDesktop + "')";

  createCarouselOverlays(carouselImageContainer, i);

  item.appendChild(carouselImageContainer);
}

function createCarouselItems(carouselInner, items = 2) {
  let item;
  let range = _.range(1, (items + 1));

  _.forEach(range, (i) => {
    item = document.createElement("div");
    item.className = "carousel-item";

    createCarouselImageContainers(item, i);

    carouselInner.appendChild(item);
  });
}

function createCarouselOverlays(carouselImageContainer, i) {
  let carouselOverlay = document.createElement("div");
  let a = document.createElement("a");
  let subtitle = document.createElement("h3");
  let title = document.createElement("h2");

  carouselOverlay.className = "carousel-overlay";

  if(i % 2) {
    a.href = "http://www.bobdylan.com";
    a.innerHTML = "Bob Dylan";
    title.innerHTML = "Bob Dylan's official website"
    subtitle.innerHTML = "Blind boy grunt"

  } else {
    a.href = "http://www.paulsimon.com";
    a.innerHTML = "Paul Simon";
    title.innerHTML = "Paul Simon's official website"
    subtitle.innerHTML = "He's a tiny little showbiz man"
  }

  carouselOverlay.appendChild(title);
  carouselOverlay.appendChild(subtitle);
  carouselOverlay.appendChild(a);

  carouselImageContainer.appendChild(carouselOverlay);
}

describe("carousel", () => {
  let c, carousel, viewport;

  beforeEach(() => {
    c = createCarousel();
    viewport = new ViewportDetect();

    carousel = new CarouselClass({
      element: c,
      autoPlay: false,
      itemClass: "carousel-item"
    }, false);
  });

  it("should exist", () => {
    expect(carousel).toBeDefined();
  });

  describe("render function", () => {
    beforeEach(() => {
      spyOn(carousel, "_getItems");
      spyOn(carousel, "_setDefaultSelected");

      carousel.render();
    });

    it("should call the _getItems function", () => {
      expect(carousel._getItems).toHaveBeenCalled();
    });

    it("should call the _setDefaultSelected function", () => {
      expect(carousel._setDefaultSelected).toHaveBeenCalled();
    });
  });

  describe("_init function", () => {
    beforeEach(() => {
      spyOn(carousel, "render");

      carousel._init();
    });

    it("should set this.animating to false", () => {
      expect(carousel.animating).toBeFalsy();
    });

    it("should set this.eventManager to the _manageListeners function", () => {
      expect(carousel.eventManager.addListener).toBeDefined();
      expect(carousel.eventManager.removeAll).toBeDefined();
    });

    it("should set this.hasDataURLs to false", () => {
      expect(carousel.hasDataURLs).toBeFalsy();
    });

    it("should set this.itemActive to 0", () => {
      expect(carousel.itemActive).toEqual(0);
    });

    it("should set this.items to be an empty array", () => {
      expect(carousel.items.length).toEqual(0);
    });

    it("should call the render function", () => {
      expect(carousel.render).toHaveBeenCalled();
    });
  });

  describe("_initViewport function", () => {
    beforeEach(() => {
      spyOn(viewport, "trackSize");
      spyOn(viewport, "getDevice").and.returnValue("bollocks");
    });

    it("should set this.device to the viewport.getDevice function", () => {
      carousel._initViewport();

      expect(carousel.device).toEqual("bollocks");
    });

    // Ade, why is this failing? I'm confused!
    // it("should call the setBodyClasses function", () => {
    //   expect(viewport.trackSize).toHaveBeenCalled();
    // });
  });
});<commit_msg>Whoops<commit_after>const _ = require("lodash");
const CarouselClass = require("../src/carousel");
const ViewportDetect = require("viewport-detection-es6");

function createCarousel() {
  let carouselInner = document.createElement("div");
  let carouselOuter = document.createElement("div");

  carouselInner.className = "carousel-inner";
  carouselOuter.id = "carousel";

  carouselOuter.appendChild(carouselInner);

  createCarouselItems(carouselInner);

  document.body.appendChild(carouselOuter);

  return carouselOuter;
}

function createCarouselImageContainers(item, i) {
  let dataURLDesktop, dataURLMobile, dataURLTablet;
  let carouselImageContainer = document.createElement("div");

  carouselImageContainer.className = "carousel-image-container";

  dataURLDesktop = "desktop.jpg";

  if(i % 2) {
    dataURLMobile = "null";
    dataURLTablet = "null";
  } else {
    dataURLMobile = "mobile.jpg";
    dataURLTablet = "tablet.jpg";
  }

  carouselImageContainer.setAttribute("data-mobile", dataURLMobile);
  carouselImageContainer.setAttribute("data-tablet", dataURLTablet);
  carouselImageContainer.setAttribute("data-desktop", dataURLDesktop);

  carouselImageContainer.style.backgroundImage = "url('" + dataURLDesktop + "')";

  createCarouselOverlays(carouselImageContainer, i);

  item.appendChild(carouselImageContainer);
}

function createCarouselItems(carouselInner, items = 2) {
  let item;
  let range = _.range(1, (items + 1));

  _.forEach(range, (i) => {
    item = document.createElement("div");
    item.className = "carousel-item";

    createCarouselImageContainers(item, i);

    carouselInner.appendChild(item);
  });
}

function createCarouselOverlays(carouselImageContainer, i) {
  let carouselOverlay = document.createElement("div");
  let a = document.createElement("a");
  let subtitle = document.createElement("h3");
  let title = document.createElement("h2");

  carouselOverlay.className = "carousel-overlay";

  if(i % 2) {
    a.href = "http://www.bobdylan.com";
    a.innerHTML = "Bob Dylan";
    title.innerHTML = "Bob Dylan's official website"
    subtitle.innerHTML = "Blind boy grunt"

  } else {
    a.href = "http://www.paulsimon.com";
    a.innerHTML = "Paul Simon";
    title.innerHTML = "Paul Simon's official website"
    subtitle.innerHTML = "He's a tiny little showbiz man"
  }

  carouselOverlay.appendChild(title);
  carouselOverlay.appendChild(subtitle);
  carouselOverlay.appendChild(a);

  carouselImageContainer.appendChild(carouselOverlay);
}

describe("carousel", () => {
  let c, carousel, viewport;

  beforeEach(() => {
    c = createCarousel();
    viewport = new ViewportDetect();

    carousel = new CarouselClass({
      element: c,
      autoPlay: false,
      itemClass: "carousel-item"
    }, false);
  });

  it("should exist", () => {
    expect(carousel).toBeDefined();
  });

  describe("render function", () => {
    beforeEach(() => {
      spyOn(carousel, "_getItems");
      spyOn(carousel, "_setDefaultSelected");

      carousel.render();
    });

    it("should call the _getItems function", () => {
      expect(carousel._getItems).toHaveBeenCalled();
    });

    it("should call the _setDefaultSelected function", () => {
      expect(carousel._setDefaultSelected).toHaveBeenCalled();
    });
  });

  describe("_init function", () => {
    beforeEach(() => {
      spyOn(carousel, "render");

      carousel._init();
    });

    it("should set this.animating to false", () => {
      expect(carousel.animating).toBeFalsy();
    });

    it("should set this.eventManager to the _manageListeners function", () => {
      expect(carousel.eventManager.addListener).toBeDefined();
      expect(carousel.eventManager.removeAll).toBeDefined();
    });

    it("should set this.hasDataURLs to false", () => {
      expect(carousel.hasDataURLs).toBeFalsy();
    });

    it("should set this.itemActive to 0", () => {
      expect(carousel.itemActive).toEqual(0);
    });

    it("should set this.items to be an empty array", () => {
      expect(carousel.items.length).toEqual(0);
    });

    it("should call the render function", () => {
      expect(carousel.render).toHaveBeenCalled();
    });
  });

  describe("_initViewport function", () => {
    beforeEach(() => {
      spyOn(viewport, "trackSize");
      spyOn(viewport, "getDevice").and.returnValue("bollocks");
    });

    it("should set this.device to the viewport.getDevice function", () => {
      carousel._initViewport();

      expect(carousel.device).toEqual("bollocks");
    });

    // Ade, why is this failing? I'm confused!
    // it("should call the viewport.trackSize function", () => {
    //   expect(viewport.trackSize).toHaveBeenCalled();
    // });
  });
});<|endoftext|>


<commit_before>'use strict';

require('comfychair/jasmine');
var comfy = require('comfychair');
var chan = require('../index');

var merge = function() {
  var args = Array.prototype.slice.call(arguments);
  var result = args.every(Array.isArray) ? [] : {};
  var i, obj, key;
  for (i in args) {
    obj = args[i];
    for (key in obj)
      result[key] = obj[key];
  }
  return result;
};

function model(type) {
  var _transitions = {
    init: function(state, arg) {
      return {
        state: {
          count  : 0,
          buffer : [],
          bsize  : arg,
          pullers: [],
          pushers: [],
          closed : false
        }
      };
    },
    push: function(state, val) {
      var h = state.count + 1;
      state = state.merge({ count: h });

      if (state.closed) {
        return {
          state : state,
          output: [[h, false]]
        };
      } else if (state.pullers.length > 0) {
        return {
          state : merge(state, { pullers: state.pullers.slice(1) }),
          output: [[state.pullers[0], val], [h, true]]
        };
      } else if (state.bsize > state.buffer.length) {
        return {
          state : merge(state, { buffer: state.buffer.concat([val]) }),
          output: [[h, true]]
        };
      } else {
        return {
          state : merge(state, { pushers: state.pushers.concat([[h, val]]) }),
          output: []
        };
      }
    },
    pull: function(state) {
      var h = state.count + 1;
      state = state.merge({ count: h });

      if (state.buffer.length > 0) {
        if (state.pushers.length > 0) {
          return {
            state: state.merge({
              buffer : state.buffer.slice(1).concat(state.pushers[0][1]),
              pushers: state.pushers.slice(1)
            }),
            output: [[state.pushers[0][0], true], [h, state.buffer[0]]]
          };
        } else {
          return {
            state: state.merge({
              buffer: state.buffer.slice(1)
            }),
            output: [[h, state.buffer[0]]]
          };
        }
      } else if (state.closed) {
        return {
          state : state,
          output: [[h, undefined]]
        };
      } else if (state.pushers.length > 0) {
        return {
          state : merge(state, { pushers: state.pushers.slice(1) }),
          output: [[state.pushers[0][0], true], [h, state.pushers[0][1]]]
        };
      } else {
        return {
          state : merge(state, { pullers: state.pullers.concat([h]) }),
          output: []
        };
      }
    },
    close: function(state) {
      return {
        state: state.merge({
          buffer : [],
          pullers: [],
          pushers: [],
          closed : true
        }),
        output: [].concat(
          state.pushers.map(function(p) { return [p[0], false]; }),
          state.pullers.map(function(p) { return [p, undefined]; }))
      };
    }
  };

  var _hasArgument = function(command) {
    return ['init', 'push'].indexOf(command) >= 0;
  };

  return {
    commands: function() {
      var cmds = Object.keys(this._transitions).slice();
      cmds.splice(cmds.indexOf('init'), 1);
      return cmds;
    },
    randomArgs: function(command, size) {
      if (this._hasArgument(command))
        return [comfy.randomInt(0, size)];
      else
        return [];
    },

    shrinkArgs: function(command, args) {
      if (this._hasArgument(command) && args[0] > 0)
        return [[args[0] - 1]];
      else
        return [];
    },

    apply: function(state, command, args) {
      return this._transitions[command].apply(null, [state].concat(args));
    }
  };
};
<commit_msg>finish generative test for basic channel functionality<commit_after>'use strict';

require('comfychair/jasmine');
var comfy = require('comfychair');
var chan = require('../index');

var merge = function() {
  var args = Array.prototype.slice.call(arguments);
  var result = args.every(Array.isArray) ? [] : {};
  var i, obj, key;
  for (i in args) {
    obj = args[i];
    for (key in obj)
      result[key] = obj[key];
  }
  return result;
};

var model = function() {
  var _transitions = {
    init: function(state, arg) {
      return {
        state: {
          count  : 0,
          buffer : [],
          bsize  : arg,
          pullers: [],
          pushers: [],
          closed : false
        }
      };
    },
    push: function(state, val) {
      var h = state.count + 1;
      state = merge(state, { count: h });

      if (state.closed) {
        return {
          state : state,
          output: [[h, false]]
        };
      } else if (state.pullers.length > 0) {
        return {
          state : merge(state, { pullers: state.pullers.slice(1) }),
          output: [[state.pullers[0], val], [h, true]]
        };
      } else if (state.bsize > state.buffer.length) {
        return {
          state : merge(state, { buffer: state.buffer.concat([val]) }),
          output: [[h, true]]
        };
      } else {
        return {
          state : merge(state, { pushers: state.pushers.concat([[h, val]]) }),
          output: []
        };
      }
    },
    pull: function(state) {
      var h = state.count + 1;
      state = merge(state, { count: h });

      if (state.buffer.length > 0) {
        if (state.pushers.length > 0) {
          return {
            state: merge(state, {
              buffer : state.buffer.slice(1).concat(state.pushers[0][1]),
              pushers: state.pushers.slice(1)
            }),
            output: [[state.pushers[0][0], true], [h, state.buffer[0]]]
          };
        } else {
          return {
            state: merge(state, {
              buffer: state.buffer.slice(1)
            }),
            output: [[h, state.buffer[0]]]
          };
        }
      } else if (state.closed) {
        return {
          state : state,
          output: [[h, undefined]]
        };
      } else if (state.pushers.length > 0) {
        return {
          state : merge(state, { pushers: state.pushers.slice(1) }),
          output: [[state.pushers[0][0], true], [h, state.pushers[0][1]]]
        };
      } else {
        return {
          state : merge(state, { pullers: state.pullers.concat([h]) }),
          output: []
        };
      }
    },
    close: function(state) {
      return {
        state: merge(state, {
          pullers: [],
          pushers: [],
          closed : true
        }),
        output: [].concat(
          state.pushers.map(function(p) { return [p[0], false]; }),
          state.pullers.map(function(p) { return [p, undefined]; }))
      };
    }
  };

  var _hasArgument = function(command) {
    return ['init', 'push'].indexOf(command) >= 0;
  };

  return {
    commands: function() {
      var cmds = Object.keys(_transitions).slice();
      cmds.splice(cmds.indexOf('init'), 1);
      return cmds;
    },
    randomArgs: function(command, size) {
      if (_hasArgument(command))
        return [comfy.randomInt(0, size)];
      else
        return [];
    },

    shrinkArgs: function(command, args) {
      if (_hasArgument(command) && args[0] > 0)
        return [[args[0] - 1]];
      else
        return [];
    },

    apply: function(state, command, args) {
      var result =_transitions[command].apply(null, [state].concat(args));
      return {
        state : result.state,
        output: JSON.stringify(result.output)
      };
    }
  };
};

var handler = function(buffer, n) {
  var _isResolved = false;

  return {
    resolve: function(val) {
      _isResolved = true;
      buffer.push([n, val]);
    },
    reject: function(err) {
      _isResolved = true;
      buffer.push([n, err]);
    },
    isResolved: function() {
      return _isResolved;
    }
  };
};

var implementation = function() {
  return {
    apply: function(command, args) {
      if (command == 'init') {
        this._buffer = [];
        this._count = 0;
        this._channel = chan.chan(args[0]);
      } else {
        if (command != 'close')
          this._count += 1;

        var h = handler(this._buffer, this._count);
        if (command == 'push')
          this._channel.requestPush(args[0], h);
        else if (command == 'pull')
          this._channel.requestPull(h);
        else
          this._channel.close();

        var result = this._buffer.slice();
        this._buffer.splice(0, this._buffer.length);
        return JSON.stringify(result);
      }
    }
  };
};

describe('a channel', function() {
  it('conforms to the channel model', function() {
    expect(implementation()).toConformTo(model());
  });
});
<|endoftext|>


<commit_before>// ==UserScript==
// @author      Jan Kaiser
// @name        Imgur redirect to image
// @namespace   https://github.com/Azlond/Imgur-redirect-to-image
// @include     https://imgur.com/*
// @include     http://imgur.com/*
// @exclude     https://imgur.com/about
// @exclude     http://imgur.com/about
// @exclude     https://imgur.com/privacy
// @exclude     http://imgur.com/privacy
// @version     1.2
// @grant       none
// run-at       document-start
// ==/UserScript==

var URL = window.location + ""; // current URL
var path;
if (URL.charAt(5) === ":") { // HTTPS
	path = URL.slice(18, URL.length); //strip the https://imgur.com/
} else { // HTTP
	path = URL.slice(17, URL.length); //strip the http://imgur.com/
}
if (path.charAt(path.length - 1) === "/") { //strip the path of a potential slash "/" at the end
	path = path.slice(0, path.length - 1);
}
if (path.length === 5 || path.length === 7) { //hacky workaround, imageIDs appear to be either 5 or 7 characters long
	if (!(/\?+|\//.test(path))) { // see if the path contains "?" or "/", just in case
		try { // try to catch potential errors
			var linkElements = document.getElementsByTagName("link"); // collect all <link>-elements from the source code
			for (var i = 0; i < linkElements.length; i++) { // go through all object we just collected
				var element = linkElements[i]; // current link object
				if (element.rel == "image_src") { // if the current objects rel-attribute equals image_src, we have found the link to the image
					window.location = element.href; // redirect the current window to the image
				}
			}
		} catch (e) {
			console.log("If this script throws an error, please report it to me at the github location of this script at:");
			console.log("https://github.com/Azlond/Imgur-redirect-to-image");
			console.log("The error message is: " + e);
			console.log("Thank you.");
		}
	}
}
<commit_msg>gifv-support, changes for better loading times<commit_after>// ==UserScript==
// @author      Jan Kaiser
// @name        Imgur redirect to image
// @namespace   https://github.com/Azlond/Imgur-redirect-to-image
// @include     https://imgur.com/*
// @include     http://imgur.com/*
// @exclude     https://imgur.com/about
// @exclude     http://imgur.com/about
// @exclude     https://imgur.com/privacy
// @exclude     http://imgur.com/privacy
// @version     1.3
// @grant       GM_xmlhttpRequest
// @run-at      document-start
// ==/UserScript==

var URL = window.location + ""; // current URL
var path;
if (URL.charAt(5) === ":") { // HTTPS
	path = URL.slice(18, URL.length); //strip the https://imgur.com/
} else { // HTTP
	path = URL.slice(17, URL.length); //strip the http://imgur.com/
}
if (path.charAt(path.length - 1) === "/") { //strip the path of a potential slash "/" at the end
	path = path.slice(0, path.length - 1);
}
if (path.length === 5 || path.length === 7) { //hacky workaround, imageIDs appear to be either 5 or 7 characters long
	if (!(/\?+|\//.test(path))) { // see if the path contains "?" or "/", just in case
		GM_xmlhttpRequest({
		  method: "GET", //GET-Request for source code of image-site.
		  url: "https://www.imgur.com/" + path, // needed so we can use @run-at document-start
		  onload: function(response) {
			document = response.responseText; // set document = requested source code
			var link;
			var linkElements = document.getElementsByTagName("link"); // collect all <link>-elements from the source code
			if (linkElements[linkElements.length - 1].rel == "image_src") { // the last link-element contains the image_src
				link = linkElements[linkElements.length - 1].href; // set link to the image source
			}

			if (link === undefined) { // if link is undefined, we're dealing with a gifv
				link = "https://i.imgur.com/" + path + ".gifv"; // build gifv link, set link-variable;
			}
			window.location = link; // redirect the current window to the image
		  }
		});
	}
}
<|endoftext|>


<commit_before>describe("groupBy", function() {
  ensureLaziness(function() { Lazy(people).groupBy(Person.getGender); });

  it("groups the collection by a specified selector function", function() {
    var byGender = Lazy(people).groupBy(Person.getGender).toArray();
    expect(byGender).toEqual([
      ["M", [david, adam, daniel]],
      ["F", [mary, lauren, happy]]
    ]);
  });

  testAllSequenceTypes(
    "uses a 'pluck'-style callback when a string is passed instead of a function",

    [
      { foo: 1, bar: 1 },
      { foo: 2, bar: 2 },
      { foo: 1, bar: 3 }
    ],

    function(sequence) {
      expect(sequence.groupBy('foo').toObject()).toEqual({
        '1': [
          { foo: 1, bar: 1 },
          { foo: 1, bar: 3 }
        ],
        '2': [
          { foo: 2, bar: 2 }
        ]
      });
    }
  );
});
<commit_msg>added test for async groupBy<commit_after>describe("groupBy", function() {
  ensureLaziness(function() { Lazy(people).groupBy(Person.getGender); });

  it("groups the collection by a specified selector function", function() {
    var byGender = Lazy(people).groupBy(Person.getGender).toArray();
    expect(byGender).toEqual([
      ["M", [david, adam, daniel]],
      ["F", [mary, lauren, happy]]
    ]);
  });

  it("groups the collection by a specified selector function for async sequences", function() {
    var byGender;
    var done = false;
    var handle = Lazy(people).async().groupBy(Person.getGender).toArray();
    waitsFor(function() { return done; });
    handle.onComplete(function(result) {
      byGender = result;
      done = true;
    });
    runs(function() {
      expect(byGender).toEqual([
        ["M", [david, adam, daniel]],
        ["F", [mary, lauren, happy]]
      ]);
    });
  });

  testAllSequenceTypes(
    "uses a 'pluck'-style callback when a string is passed instead of a function",

    [
      { foo: 1, bar: 1 },
      { foo: 2, bar: 2 },
      { foo: 1, bar: 3 }
    ],

    function(sequence) {
      expect(sequence.groupBy('foo').toObject()).toEqual({
        '1': [
          { foo: 1, bar: 1 },
          { foo: 1, bar: 3 }
        ],
        '2': [
          { foo: 2, bar: 2 }
        ]
      });
    }
  );
});
<|endoftext|>