<commit_before>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import transitions from '../styles/transitions';
import DropDownArrow from '../svg-icons/navigation/arrow-drop-down';
import Menu from '../Menu/Menu';
import ClearFix from '../internal/ClearFix';
import Popover from '../Popover/Popover';
import PopoverAnimationVertical from '../Popover/PopoverAnimationVertical';
import keycode from 'keycode';
import Events from '../utils/events';
import IconButton from '../IconButton';
import propTypes from '../utils/propTypes';

function getStyles(props, context) {
  const {disabled} = props;
  const spacing = context.muiTheme.baseTheme.spacing;
  const palette = context.muiTheme.baseTheme.palette;
  const accentColor = context.muiTheme.dropDownMenu.accentColor;
  return {
    control: {
      cursor: disabled ? 'not-allowed' : 'pointer',
      height: '100%',
      position: 'relative',
      width: '100%',
    },
    icon: {
      fill: accentColor,
      position: 'absolute',
      right: spacing.desktopGutterLess,
      top: (spacing.iconSize - 24) / 2 + spacing.desktopGutterMini / 2,
    },
    iconChildren: {
      fill: 'inherit',
    },
    label: {
      color: disabled ? palette.disabledColor : palette.textColor,
      height: `${spacing.desktopToolbarHeight}px`,
      lineHeight: `${spacing.desktopToolbarHeight}px`,
      overflow: 'hidden',
      opacity: 1,
      position: 'relative',
      paddingLeft: spacing.desktopGutter,
      paddingRight: spacing.iconSize * 2 + spacing.desktopGutterMini,
      textOverflow: 'ellipsis',
      top: 0,
      whiteSpace: 'nowrap',
    },
    labelWhenOpen: {
      opacity: 0,
      top: (spacing.desktopToolbarHeight / 8),
    },
    root: {
      display: 'inline-block',
      fontSize: spacing.desktopDropDownMenuFontSize,
      height: spacing.desktopSubheaderHeight,
      fontFamily: context.muiTheme.baseTheme.fontFamily,
      outline: 'none',
      position: 'relative',
      transition: transitions.easeOut(),
    },
    rootWhenOpen: {
      opacity: 1,
    },
    underline: {
      borderTop: `solid 1px ${accentColor}`,
      bottom: 1,
      left: 0,
      margin: `-1px ${spacing.desktopGutter}px`,
      right: 0,
      position: 'absolute',
    },
  };
}

class DropDownMenu extends Component {
  static muiName = 'DropDownMenu';

  // The nested styles for drop-down-menu are modified by toolbar and possibly
  // other user components, so it will give full access to its js styles rather
  // than just the parent.
  static propTypes = {
    /**
     * This is the point on the anchor that the popover's
     * `targetOrigin` will attach to.
     * Options:
     * vertical: [top, center, bottom]
     * horizontal: [left, middle, right].
     */
    anchorOrigin: propTypes.origin,
    /**
     * If true, the popover will apply transitions when
     * it gets added to the DOM.
     */
    animated: PropTypes.bool,
    /**
     * Override the default animation component used.
     */
    animation: PropTypes.func,
    /**
     * The width will automatically be set according to the items inside the menu.
     * To control this width in css instead, set this prop to `false`.
     */
    autoWidth: PropTypes.bool,
    /**
     * The `MenuItem`s to populate the `Menu` with. If the `MenuItems` have the
     * prop `label` that value will be used to render the representation of that
     * item within the field.
     */
    children: PropTypes.node,
    /**
     * The css class name of the root element.
     */
    className: PropTypes.string,
    /**
     * Disables the menu.
     */
    disabled: PropTypes.bool,
    /**
     * Overrides default `SvgIcon` dropdown arrow component.
     */
    iconButton: PropTypes.node,
    /**
     * Overrides the styles of icon element.
     */
    iconStyle: PropTypes.object,
    /**
     * Overrides the styles of label when the `DropDownMenu` is inactive.
     */
    labelStyle: PropTypes.object,
    /**
     * The style object to use to override underlying list style.
     */
    listStyle: PropTypes.object,
    /**
     * The maximum height of the `Menu` when it is displayed.
     */
    maxHeight: PropTypes.number,
    /**
     * Override the inline-styles of menu items.
     */
    menuItemStyle: PropTypes.object,
    /**
     * Overrides the styles of `Menu` when the `DropDownMenu` is displayed.
     */
    menuStyle: PropTypes.object,
    /**
     * If true, `value` must be an array and the menu will support
     * multiple selections.
     */
    multiple: PropTypes.bool,
    /**
     * Callback function fired when a menu item is clicked, other than the one currently selected.
     *
     * @param {object} event TouchTap event targeting the menu item that was clicked.
     * @param {number} key The index of the clicked menu item in the `children` collection.
     * @param {any} value If `multiple` is true, the menu's `value`
     * array with either the menu item's `value` added (if
     * it wasn't already selected) or omitted (if it was already selected).
     * Otherwise, the `value` of the menu item.
     */
    onChange: PropTypes.func,
    /**
     * Callback function fired when the menu is closed.
     */
    onClose: PropTypes.func,
    /**
     * Set to true to have the `DropDownMenu` automatically open on mount.
     */
    openImmediately: PropTypes.bool,
    /**
     * Override the inline-styles of selected menu items.
     */
    selectedMenuItemStyle: PropTypes.object,
    /**
     * Callback function fired when a menu item is clicked, other than the one currently selected.
     *
     * @param {any} value If `multiple` is true, the menu's `value`
     * array with either the menu item's `value` added (if
     * it wasn't already selected) or omitted (if it was already selected).
     * Otherwise, the `value` of the menu item.
     */
    selectionRenderer: PropTypes.func,
    /**
     * Override the inline-styles of the root element.
     */
    style: PropTypes.object,
    /**
     * This is the point on the popover which will attach to
     * the anchor's origin.
     * Options:
     * vertical: [top, center, bottom]
     * horizontal: [left, middle, right].
     */
    targetOrigin: propTypes.origin,
    /**
     * Overrides the inline-styles of the underline.
     */
    underlineStyle: PropTypes.object,
    /**
     * If `multiple` is true, an array of the `value`s of the selected
     * menu items. Otherwise, the `value` of the selected menu item.
     * If provided, the menu will be a controlled component.
     */
    value: PropTypes.any,
  };

  static defaultProps = {
    animated: true,
    autoWidth: true,
    disabled: false,
    iconButton: <DropDownArrow />,
    openImmediately: false,
    maxHeight: 500,
    multiple: false,
    anchorOrigin: {
      vertical: 'top',
      horizontal: 'left',
    },
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  state = {
    open: false,
  };

  componentDidMount() {
    if (this.props.autoWidth) {
      this.setWidth();
    }
    if (this.props.openImmediately) {
      // TODO: Temporary fix to make openImmediately work with popover.
      /* eslint-disable react/no-did-mount-set-state */
      setTimeout(() => this.setState({
        open: true,
        anchorEl: this.rootNode,
      }), 0);
      /* eslint-enable react/no-did-mount-set-state */
    }
  }

  componentWillReceiveProps() {
    if (this.props.autoWidth) {
      this.setWidth();
    }
  }

  rootNode = undefined;
  arrowNode = undefined;

  /**
   * This method is deprecated but still here because the TextField
   * need it in order to work. TODO: That will be addressed later.
   */
  getInputNode() {
    const rootNode = this.rootNode;

    rootNode.focus = () => {
      if (!this.props.disabled) {
        this.setState({
          open: !this.state.open,
          anchorEl: this.rootNode,
        });
      }
    };

    return rootNode;
  }

  setWidth() {
    const el = this.rootNode;
    if (!this.props.style || !this.props.style.hasOwnProperty('width')) {
      el.style.width = 'auto';
    }
  }

  handleTouchTapControl = (event) => {
    event.preventDefault();
    if (!this.props.disabled) {
      this.setState({
        open: !this.state.open,
        anchorEl: this.rootNode,
      });
    }
  };

  handleRequestCloseMenu = () => {
    this.close(false);
  };

  handleEscKeyDownMenu = () => {
    this.close(true);
  };

  handleKeyDown = (event) => {
    switch (keycode(event)) {
      case 'up':
      case 'down':
      case 'space':
      case 'enter':
        event.preventDefault();
        this.setState({
          open: true,
          anchorEl: this.rootNode,
        });
        break;
    }
  };

  handleItemTouchTap = (event, child, index) => {
    if (this.props.multiple) {
      if (!this.state.open) {
        this.setState({open: true});
      }
    } else {
      event.persist();
      this.setState({
        open: false,
      }, () => {
        if (this.props.onChange) {
          this.props.onChange(event, index, child.props.value);
        }

        this.close(Events.isKeyboard(event));
      });
    }
  };

  handleChange = (event, value) => {
    if (this.props.multiple && this.props.onChange) {
      this.props.onChange(event, undefined, value);
    }
  };

  close = (isKeyboard) => {
    this.setState({
      open: false,
    }, () => {
      if (this.props.onClose) {
        this.props.onClose();
      }

      if (isKeyboard) {
        const dropArrow = this.arrowNode;
        const dropNode = ReactDOM.findDOMNode(dropArrow);
        dropNode.focus();
        dropArrow.setKeyboardFocus(true);
      }
    });
  }

  render() {
    const {
      animated,
      animation,
      autoWidth,
      multiple,
      children,
      className,
      disabled,
      iconStyle,
      labelStyle,
      listStyle,
      maxHeight,
      menuStyle: menuStyleProp,
      selectionRenderer,
      onClose, // eslint-disable-line no-unused-vars
      openImmediately, // eslint-disable-line no-unused-vars
      menuItemStyle,
      selectedMenuItemStyle,
      style,
      underlineStyle,
      value,
      iconButton,
      anchorOrigin,
      targetOrigin,
      ...other
    } = this.props;
    const {
      anchorEl,
      open,
    } = this.state;

    const {prepareStyles} = this.context.muiTheme;
    const styles = getStyles(this.props, this.context);

    let displayValue = '';
    if (!multiple) {
      React.Children.forEach(children, (child) => {
        if (child && value === child.props.value) {
          if (selectionRenderer) {
            displayValue = selectionRenderer(value);
          } else {
            // This will need to be improved (in case primaryText is a node)
            displayValue = child.props.label || child.props.primaryText;
          }
        }
      });
    } else {
      const values = [];
      React.Children.forEach(children, (child) => {
        if (child && value && value.includes(child.props.value)) {
          if (selectionRenderer) {
            values.push(child.props.value);
          } else {
            values.push(child.props.label || child.props.primaryText);
          }
        }
      });

      displayValue = [];
      if (selectionRenderer) {
        displayValue = selectionRenderer(values);
      } else {
        displayValue = values.join(', ');
      }
    }

    let menuStyle;
    if (anchorEl && !autoWidth) {
      menuStyle = Object.assign({
        width: anchorEl.clientWidth,
      }, menuStyleProp);
    } else {
      menuStyle = menuStyleProp;
    }

    return (

 {
          this.rootNode = node;
        }}
        className={className}
        style={prepareStyles(Object.assign({}, styles.root, open && styles.rootWhenOpen, style))}
      >
        <ClearFix style={styles.control} onTouchTap={this.handleTouchTapControl}>

            {displayValue}

          <IconButton
            disabled={disabled}
            onKeyDown={this.handleKeyDown}
            ref={(node) => {
              this.arrowNode = node;
            }}
            style={Object.assign({}, styles.icon, iconStyle)}
            iconStyle={styles.iconChildren}
          >
            {iconButton}
          </IconButton>

        </ClearFix>
        <Popover
          anchorOrigin={anchorOrigin}
          targetOrigin={targetOrigin}
          anchorEl={anchorEl}
          animation={animation || PopoverAnimationVertical}
          open={open}
          animated={animated}
          onRequestClose={this.handleRequestCloseMenu}
        >
          <Menu
            multiple={multiple}
            maxHeight={maxHeight}
            desktop={true}
            value={value}
            onEscKeyDown={this.handleEscKeyDownMenu}
            style={menuStyle}
            listStyle={listStyle}
            onItemTouchTap={this.handleItemTouchTap}
            onChange={this.handleChange}
            menuItemStyle={menuItemStyle}
            selectedMenuItemStyle={selectedMenuItemStyle}
          >
            {children}
          </Menu>
        </Popover>

    );
  }
}

export default DropDownMenu;
<commit_msg>[DropDownMenu] Pass autoWidth property to Menu component (#6632)<commit_after>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import transitions from '../styles/transitions';
import DropDownArrow from '../svg-icons/navigation/arrow-drop-down';
import Menu from '../Menu/Menu';
import ClearFix from '../internal/ClearFix';
import Popover from '../Popover/Popover';
import PopoverAnimationVertical from '../Popover/PopoverAnimationVertical';
import keycode from 'keycode';
import Events from '../utils/events';
import IconButton from '../IconButton';
import propTypes from '../utils/propTypes';

function getStyles(props, context) {
  const {disabled} = props;
  const spacing = context.muiTheme.baseTheme.spacing;
  const palette = context.muiTheme.baseTheme.palette;
  const accentColor = context.muiTheme.dropDownMenu.accentColor;
  return {
    control: {
      cursor: disabled ? 'not-allowed' : 'pointer',
      height: '100%',
      position: 'relative',
      width: '100%',
    },
    icon: {
      fill: accentColor,
      position: 'absolute',
      right: spacing.desktopGutterLess,
      top: (spacing.iconSize - 24) / 2 + spacing.desktopGutterMini / 2,
    },
    iconChildren: {
      fill: 'inherit',
    },
    label: {
      color: disabled ? palette.disabledColor : palette.textColor,
      height: `${spacing.desktopToolbarHeight}px`,
      lineHeight: `${spacing.desktopToolbarHeight}px`,
      overflow: 'hidden',
      opacity: 1,
      position: 'relative',
      paddingLeft: spacing.desktopGutter,
      paddingRight: spacing.iconSize * 2 + spacing.desktopGutterMini,
      textOverflow: 'ellipsis',
      top: 0,
      whiteSpace: 'nowrap',
    },
    labelWhenOpen: {
      opacity: 0,
      top: (spacing.desktopToolbarHeight / 8),
    },
    root: {
      display: 'inline-block',
      fontSize: spacing.desktopDropDownMenuFontSize,
      height: spacing.desktopSubheaderHeight,
      fontFamily: context.muiTheme.baseTheme.fontFamily,
      outline: 'none',
      position: 'relative',
      transition: transitions.easeOut(),
    },
    rootWhenOpen: {
      opacity: 1,
    },
    underline: {
      borderTop: `solid 1px ${accentColor}`,
      bottom: 1,
      left: 0,
      margin: `-1px ${spacing.desktopGutter}px`,
      right: 0,
      position: 'absolute',
    },
  };
}

class DropDownMenu extends Component {
  static muiName = 'DropDownMenu';

  // The nested styles for drop-down-menu are modified by toolbar and possibly
  // other user components, so it will give full access to its js styles rather
  // than just the parent.
  static propTypes = {
    /**
     * This is the point on the anchor that the popover's
     * `targetOrigin` will attach to.
     * Options:
     * vertical: [top, center, bottom]
     * horizontal: [left, middle, right].
     */
    anchorOrigin: propTypes.origin,
    /**
     * If true, the popover will apply transitions when
     * it gets added to the DOM.
     */
    animated: PropTypes.bool,
    /**
     * Override the default animation component used.
     */
    animation: PropTypes.func,
    /**
     * The width will automatically be set according to the items inside the menu.
     * To control this width in css instead, set this prop to `false`.
     */
    autoWidth: PropTypes.bool,
    /**
     * The `MenuItem`s to populate the `Menu` with. If the `MenuItems` have the
     * prop `label` that value will be used to render the representation of that
     * item within the field.
     */
    children: PropTypes.node,
    /**
     * The css class name of the root element.
     */
    className: PropTypes.string,
    /**
     * Disables the menu.
     */
    disabled: PropTypes.bool,
    /**
     * Overrides default `SvgIcon` dropdown arrow component.
     */
    iconButton: PropTypes.node,
    /**
     * Overrides the styles of icon element.
     */
    iconStyle: PropTypes.object,
    /**
     * Overrides the styles of label when the `DropDownMenu` is inactive.
     */
    labelStyle: PropTypes.object,
    /**
     * The style object to use to override underlying list style.
     */
    listStyle: PropTypes.object,
    /**
     * The maximum height of the `Menu` when it is displayed.
     */
    maxHeight: PropTypes.number,
    /**
     * Override the inline-styles of menu items.
     */
    menuItemStyle: PropTypes.object,
    /**
     * Overrides the styles of `Menu` when the `DropDownMenu` is displayed.
     */
    menuStyle: PropTypes.object,
    /**
     * If true, `value` must be an array and the menu will support
     * multiple selections.
     */
    multiple: PropTypes.bool,
    /**
     * Callback function fired when a menu item is clicked, other than the one currently selected.
     *
     * @param {object} event TouchTap event targeting the menu item that was clicked.
     * @param {number} key The index of the clicked menu item in the `children` collection.
     * @param {any} value If `multiple` is true, the menu's `value`
     * array with either the menu item's `value` added (if
     * it wasn't already selected) or omitted (if it was already selected).
     * Otherwise, the `value` of the menu item.
     */
    onChange: PropTypes.func,
    /**
     * Callback function fired when the menu is closed.
     */
    onClose: PropTypes.func,
    /**
     * Set to true to have the `DropDownMenu` automatically open on mount.
     */
    openImmediately: PropTypes.bool,
    /**
     * Override the inline-styles of selected menu items.
     */
    selectedMenuItemStyle: PropTypes.object,
    /**
     * Callback function fired when a menu item is clicked, other than the one currently selected.
     *
     * @param {any} value If `multiple` is true, the menu's `value`
     * array with either the menu item's `value` added (if
     * it wasn't already selected) or omitted (if it was already selected).
     * Otherwise, the `value` of the menu item.
     */
    selectionRenderer: PropTypes.func,
    /**
     * Override the inline-styles of the root element.
     */
    style: PropTypes.object,
    /**
     * This is the point on the popover which will attach to
     * the anchor's origin.
     * Options:
     * vertical: [top, center, bottom]
     * horizontal: [left, middle, right].
     */
    targetOrigin: propTypes.origin,
    /**
     * Overrides the inline-styles of the underline.
     */
    underlineStyle: PropTypes.object,
    /**
     * If `multiple` is true, an array of the `value`s of the selected
     * menu items. Otherwise, the `value` of the selected menu item.
     * If provided, the menu will be a controlled component.
     */
    value: PropTypes.any,
  };

  static defaultProps = {
    animated: true,
    autoWidth: true,
    disabled: false,
    iconButton: <DropDownArrow />,
    openImmediately: false,
    maxHeight: 500,
    multiple: false,
    anchorOrigin: {
      vertical: 'top',
      horizontal: 'left',
    },
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  state = {
    open: false,
  };

  componentDidMount() {
    if (this.props.autoWidth) {
      this.setWidth();
    }
    if (this.props.openImmediately) {
      // TODO: Temporary fix to make openImmediately work with popover.
      /* eslint-disable react/no-did-mount-set-state */
      setTimeout(() => this.setState({
        open: true,
        anchorEl: this.rootNode,
      }), 0);
      /* eslint-enable react/no-did-mount-set-state */
    }
  }

  componentWillReceiveProps() {
    if (this.props.autoWidth) {
      this.setWidth();
    }
  }

  rootNode = undefined;
  arrowNode = undefined;

  /**
   * This method is deprecated but still here because the TextField
   * need it in order to work. TODO: That will be addressed later.
   */
  getInputNode() {
    const rootNode = this.rootNode;

    rootNode.focus = () => {
      if (!this.props.disabled) {
        this.setState({
          open: !this.state.open,
          anchorEl: this.rootNode,
        });
      }
    };

    return rootNode;
  }

  setWidth() {
    const el = this.rootNode;
    if (!this.props.style || !this.props.style.hasOwnProperty('width')) {
      el.style.width = 'auto';
    }
  }

  handleTouchTapControl = (event) => {
    event.preventDefault();
    if (!this.props.disabled) {
      this.setState({
        open: !this.state.open,
        anchorEl: this.rootNode,
      });
    }
  };

  handleRequestCloseMenu = () => {
    this.close(false);
  };

  handleEscKeyDownMenu = () => {
    this.close(true);
  };

  handleKeyDown = (event) => {
    switch (keycode(event)) {
      case 'up':
      case 'down':
      case 'space':
      case 'enter':
        event.preventDefault();
        this.setState({
          open: true,
          anchorEl: this.rootNode,
        });
        break;
    }
  };

  handleItemTouchTap = (event, child, index) => {
    if (this.props.multiple) {
      if (!this.state.open) {
        this.setState({open: true});
      }
    } else {
      event.persist();
      this.setState({
        open: false,
      }, () => {
        if (this.props.onChange) {
          this.props.onChange(event, index, child.props.value);
        }

        this.close(Events.isKeyboard(event));
      });
    }
  };

  handleChange = (event, value) => {
    if (this.props.multiple && this.props.onChange) {
      this.props.onChange(event, undefined, value);
    }
  };

  close = (isKeyboard) => {
    this.setState({
      open: false,
    }, () => {
      if (this.props.onClose) {
        this.props.onClose();
      }

      if (isKeyboard) {
        const dropArrow = this.arrowNode;
        const dropNode = ReactDOM.findDOMNode(dropArrow);
        dropNode.focus();
        dropArrow.setKeyboardFocus(true);
      }
    });
  }

  render() {
    const {
      animated,
      animation,
      autoWidth,
      multiple,
      children,
      className,
      disabled,
      iconStyle,
      labelStyle,
      listStyle,
      maxHeight,
      menuStyle: menuStyleProp,
      selectionRenderer,
      onClose, // eslint-disable-line no-unused-vars
      openImmediately, // eslint-disable-line no-unused-vars
      menuItemStyle,
      selectedMenuItemStyle,
      style,
      underlineStyle,
      value,
      iconButton,
      anchorOrigin,
      targetOrigin,
      ...other
    } = this.props;
    const {
      anchorEl,
      open,
    } = this.state;

    const {prepareStyles} = this.context.muiTheme;
    const styles = getStyles(this.props, this.context);

    let displayValue = '';
    if (!multiple) {
      React.Children.forEach(children, (child) => {
        if (child && value === child.props.value) {
          if (selectionRenderer) {
            displayValue = selectionRenderer(value);
          } else {
            // This will need to be improved (in case primaryText is a node)
            displayValue = child.props.label || child.props.primaryText;
          }
        }
      });
    } else {
      const values = [];
      React.Children.forEach(children, (child) => {
        if (child && value && value.includes(child.props.value)) {
          if (selectionRenderer) {
            values.push(child.props.value);
          } else {
            values.push(child.props.label || child.props.primaryText);
          }
        }
      });

      displayValue = [];
      if (selectionRenderer) {
        displayValue = selectionRenderer(values);
      } else {
        displayValue = values.join(', ');
      }
    }

    let menuStyle;
    if (anchorEl && !autoWidth) {
      menuStyle = Object.assign({
        width: anchorEl.clientWidth,
      }, menuStyleProp);
    } else {
      menuStyle = menuStyleProp;
    }

    return (

 {
          this.rootNode = node;
        }}
        className={className}
        style={prepareStyles(Object.assign({}, styles.root, open && styles.rootWhenOpen, style))}
      >
        <ClearFix style={styles.control} onTouchTap={this.handleTouchTapControl}>

            {displayValue}

          <IconButton
            disabled={disabled}
            onKeyDown={this.handleKeyDown}
            ref={(node) => {
              this.arrowNode = node;
            }}
            style={Object.assign({}, styles.icon, iconStyle)}
            iconStyle={styles.iconChildren}
          >
            {iconButton}
          </IconButton>

        </ClearFix>
        <Popover
          anchorOrigin={anchorOrigin}
          targetOrigin={targetOrigin}
          anchorEl={anchorEl}
          animation={animation || PopoverAnimationVertical}
          open={open}
          animated={animated}
          onRequestClose={this.handleRequestCloseMenu}
        >
          <Menu
            multiple={multiple}
            maxHeight={maxHeight}
            desktop={true}
            value={value}
            onEscKeyDown={this.handleEscKeyDownMenu}
            style={menuStyle}
            listStyle={listStyle}
            onItemTouchTap={this.handleItemTouchTap}
            onChange={this.handleChange}
            menuItemStyle={menuItemStyle}
            selectedMenuItemStyle={selectedMenuItemStyle}
            autoWidth={autoWidth}
            width={!autoWidth && menuStyle ? menuStyle.width : null}
          >
            {children}
          </Menu>
        </Popover>

    );
  }
}

export default DropDownMenu;
<|endoftext|>


<commit_before>'use strict';

// MODULES //

var tape = require( 'tape' );
var deepGet = require( './../lib/index.js' );

// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof deepGet, 'function', 'main export is a function' );
	t.end();
});

tape( 'should export a factory function', function test( t ) {
	t.equal( typeof deepGet.factory, 'function', 'exports a factory function' );
	t.end();
});

tape( 'the function returns `undefined` if provided a non-object or null', function test( t ) {
	var values = [
		'5',
		5,
		null,
		undefined,
		NaN,
		true,
		function(){}
	];

	for ( var i = 0; i < values.length; i++ ) {
		t.equal( deepGet( values[ i ], 'a.b.c' ), undefined, 'returns undefined' );
	}
	t.end();
});

tape( 'the function throws an error if provided a key path argument which is not either a string primitive or a key array', function test( t ) {
	var values;
	var i;

	values = [
		5,
		null,
		undefined,
		NaN,
		true,
		{},
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws when provided a ' + ( typeof values[i] ) );
	}
	t.end();

	function badValue( value ) {
		return function() {
			deepGet( {'a':5}, value );
		};
	}
});

tape( 'the function throws an error if provided an options argument which is not an object', function test( t ) {
	var values;
	var i;

	values = [
		'5',
		5,
		null,
		NaN,
		true,
		undefined,
		[],
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws when provided a ' + ( typeof values[i] ) );
	}
	t.end();

	function badValue( value ) {
		return function() {
			deepGet( {'a':5}, 'a', value );
		};
	}
});

tape( 'the function throws an error if provided an invalid option', function test( t ) {
	var values;
	var i;

	values = [
		5,
		null,
		true,
		NaN,
		{},
		undefined,
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws when provided a ' + ( typeof values[i] ) );
	}
	t.end();

	function badValue( value ) {
		return function() {
			deepGet( {'a':5}, 'a', {
				'sep': value
			});
		};
	}
});

tape( 'the function deep gets', function test( t ) {
	var obj, actual, expected;

	obj = { 'a': { 'b': 999 } };

	// String path:
	actual = deepGet( obj, 'a.b' );
	expected = 999;

	t.strictEqual( actual, expected );

	// String path with custom separator:
	actual = deepGet( obj, 'a/b', {
		'sep': '/'
	});
	expected = 999;

	t.strictEqual( actual, expected );

	// Array path:
	actual = deepGet( obj, ['a','b'] );
	expected = 999;

	t.strictEqual( actual, expected );

	// Non-existent path:
	actual = deepGet( obj, ['a','c'] );
	expected = undefined;

	t.strictEqual( actual, expected );
	t.end();
});
<commit_msg>Rename test description<commit_after>'use strict';

// MODULES //

var tape = require( 'tape' );
var deepGet = require( './../lib/index.js' );

// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof deepGet, 'function', 'main export is a function' );
	t.end();
});

tape( 'the function exports a factory function', function test( t ) {
	t.equal( typeof deepGet.factory, 'function', 'exports a factory function' );
	t.end();
});

tape( 'the function returns `undefined` if provided a non-object or null', function test( t ) {
	var values = [
		'5',
		5,
		null,
		undefined,
		NaN,
		true,
		function(){}
	];

	for ( var i = 0; i < values.length; i++ ) {
		t.equal( deepGet( values[ i ], 'a.b.c' ), undefined, 'returns undefined' );
	}
	t.end();
});

tape( 'the function throws an error if provided a key path argument which is not either a string primitive or a key array', function test( t ) {
	var values;
	var i;

	values = [
		5,
		null,
		undefined,
		NaN,
		true,
		{},
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws when provided a ' + ( typeof values[i] ) );
	}
	t.end();

	function badValue( value ) {
		return function() {
			deepGet( {'a':5}, value );
		};
	}
});

tape( 'the function throws an error if provided an options argument which is not an object', function test( t ) {
	var values;
	var i;

	values = [
		'5',
		5,
		null,
		NaN,
		true,
		undefined,
		[],
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws when provided a ' + ( typeof values[i] ) );
	}
	t.end();

	function badValue( value ) {
		return function() {
			deepGet( {'a':5}, 'a', value );
		};
	}
});

tape( 'the function throws an error if provided an invalid option', function test( t ) {
	var values;
	var i;

	values = [
		5,
		null,
		true,
		NaN,
		{},
		undefined,
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws when provided a ' + ( typeof values[i] ) );
	}
	t.end();

	function badValue( value ) {
		return function() {
			deepGet( {'a':5}, 'a', {
				'sep': value
			});
		};
	}
});

tape( 'the function deep gets', function test( t ) {
	var obj, actual, expected;

	obj = { 'a': { 'b': 999 } };

	// String path:
	actual = deepGet( obj, 'a.b' );
	expected = 999;

	t.strictEqual( actual, expected );

	// String path with custom separator:
	actual = deepGet( obj, 'a/b', {
		'sep': '/'
	});
	expected = 999;

	t.strictEqual( actual, expected );

	// Array path:
	actual = deepGet( obj, ['a','b'] );
	expected = 999;

	t.strictEqual( actual, expected );

	// Non-existent path:
	actual = deepGet( obj, ['a','c'] );
	expected = undefined;

	t.strictEqual( actual, expected );
	t.end();
});
<|endoftext|>


<commit_before>'use strict';
var models = require('../../models');
var sessionStore = require('../../app').sessionStore;
var Promise = require('rsvp').Promise;

module.exports = function (data, callbackToStripe) {
  if (isCanceled(data)) {

    var removeProStatus = function(customer){
      sessionStore.destroyByName(customer.user);
      return models.user.setProAccount(customer.user, false);
    };

    var sendStripe200 = callbackToStripe.bind(null, null);

    models.customer.setActive(data.customer, false)
      .then(removeProStatus)
      //.then(removeTeamStatus)
      .then(sendStripe200)
      .catch(callbackToStripe);

  } else {
    callbackToStripe(null);
  }
};

function isCanceled(obj) {
  return obj.status ? obj.status === 'canceled' : isCanceled(obj.data || obj.object);
}
function removeProStatusFromDB (customer) {
  return new Promise(function(reject, resolve) {
    models.user.setProAccount(customer.user, false, function(err) {
      if (err) {
        return reject(err);
      }
      resolve(customer);
    });
  });
}

function removeProStatusFromSession (customer) {
  return sessionStore.set(customer.name, false);
}
<commit_msg>Reshuffle check for cancelled, improves readability<commit_after>'use strict';
var models = require('../../models');
var sessionStore = require('../../app').sessionStore;
var Promise = require('rsvp').Promise;

module.exports = function (data, callbackToStripe) {
  var sendStripe200 = callbackToStripe.bind(null, null);

  if (!isCanceled(data)) {
    return sendStripe200();
  }

  models.customer.setActive(data.customer, false)
    .then(removeProStatusFromDB)
    .then(removeProStatusFromSession)
    .then(sendStripe200)
    .catch(callbackToStripe);

};

function isCanceled(obj) {
  return obj.status ? obj.status === 'canceled' : isCanceled(obj.data || obj.object);
}
function removeProStatusFromDB (customer) {
  return new Promise(function(reject, resolve) {
    models.user.setProAccount(customer.user, false, function(err) {
      if (err) {
        return reject(err);
      }
      resolve(customer);
    });
  });
}

function removeProStatusFromSession (customer) {
  return sessionStore.set(customer.name, false);
}
<|endoftext|>


<commit_before>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the “License”);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// <https://apache.org/licenses/LICENSE-2.0>.
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an “AS IS” BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const { DateTime } = require('luxon');
const he = require('he');
const markdownIt = require('markdown-it');
const markdownItAnchor = require('markdown-it-anchor');
const markdownItAttrs = require('markdown-it-attrs');
const markdownItFootnote = require('markdown-it-footnote');
const pluginRss = require('@11ty/eleventy-plugin-rss');
const pluginSyntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight');

const installPrismLanguages = require('./prism-languages.js');

const markdownItConfig = {
  html: true,
  breaks: true,
  linkify: true,
};
const markdownItAnchorConfig = {
  permalink: true,
  permalinkClass: 'bookmark',
  permalinkSymbol: '#',
};

const md = markdownIt(markdownItConfig)
  .use(markdownItFootnote)
  .use(markdownItAttrs)
  .use(markdownItAnchor, markdownItAnchorConfig);

module.exports = function(eleventyConfig) {
  eleventyConfig.addPlugin(pluginRss);
  eleventyConfig.addPlugin(pluginSyntaxHighlight, {
    init: function({ Prism }) {
      installPrismLanguages(Prism);
    },
  });

  eleventyConfig.addLayoutAlias('post', 'layouts/post.njk');

  eleventyConfig.addFilter('readableDate', (dateObj) => {
    return DateTime.fromJSDate(dateObj).toFormat('dd LLLL yyyy');
  });

  // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
  eleventyConfig.addFilter('htmlDateString', (dateObj) => {
    return DateTime.fromJSDate(dateObj).toFormat('yyyy-LL-dd');
  });

  eleventyConfig.addFilter('markdown', (string) => {
    return md.renderInline(string);
  });

  eleventyConfig.addFilter('decodeHtmlEntities', (string) => {
    return he.decode(string);
  });

  // Match Firebase’s `cleanUrls` setting.
  eleventyConfig.addFilter('clean', (path) => {
    if (path === '/') return path;
    if (path === 'https://v8.dev/') return path;
    if (path.endsWith('/')) return path.slice(0, -1);
    return path;
  });

  // Get the first `n` elements of a collection.
  eleventyConfig.addFilter('head', (array, n) => {
    return array.slice(0, n);
  });

  // Create a collection for blog posts only.
  eleventyConfig.addCollection('posts', (collection) => {
    return collection.getFilteredByGlob('src/blog/*.md')
                     .sort((a, b) => b.date - a.date);
  });

  // Treat `*.md` files as Markdown.
  eleventyConfig.setLibrary('md', md);

  eleventyConfig.addCollection('tagList', (collection) => {
    const set = new Set();
    for (const item of collection.getAllSorted()) {
      if ('tags' in item.data) {
        const tags = item.data.tags;
        if (typeof tags === 'string') {
          tags = [tags];
        }
        for (const tag of tags) {
          set.add(tag);
        }
      }
    }
    return [...set].sort();
  });

  // Copy assets that don’t require a build step.
  eleventyConfig.addPassthroughCopy('src/favicon.ico');
  eleventyConfig.addPassthroughCopy('src/robots.txt');
  eleventyConfig.addPassthroughCopy('src/_img');

  return {
    templateFormats: [
      'md',
      'njk',
      'html',
    ],

    pathPrefix: '/',

    markdownTemplateEngine: 'liquid',
    htmlTemplateEngine: 'njk',
    dataTemplateEngine: 'njk',
    passthroughFileCopy: true,
    dir: {
      input: 'src',
      includes: '_includes',
      data: '_data',
      output: 'dist',
    },
  };
};
<commit_msg>Improve consistency<commit_after>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the “License”);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// <https://apache.org/licenses/LICENSE-2.0>.
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an “AS IS” BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const { DateTime } = require('luxon');
const he = require('he');
const markdownIt = require('markdown-it');
const markdownItAnchor = require('markdown-it-anchor');
const markdownItAttrs = require('markdown-it-attrs');
const markdownItFootnote = require('markdown-it-footnote');
const pluginRss = require('@11ty/eleventy-plugin-rss');
const pluginSyntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight');

const installPrismLanguages = require('./prism-languages.js');

const markdownItConfig = {
  html: true,
  breaks: true,
  linkify: true,
};
const markdownItAnchorConfig = {
  permalink: true,
  permalinkClass: 'bookmark',
  permalinkSymbol: '#',
};

const md = markdownIt(markdownItConfig)
  .use(markdownItFootnote)
  .use(markdownItAttrs)
  .use(markdownItAnchor, markdownItAnchorConfig);

module.exports = (eleventyConfig) => {
  eleventyConfig.addPlugin(pluginRss);
  eleventyConfig.addPlugin(pluginSyntaxHighlight, {
    init({ Prism }) {
      installPrismLanguages(Prism);
    },
  });

  eleventyConfig.addLayoutAlias('post', 'layouts/post.njk');

  eleventyConfig.addFilter('readableDate', (dateObj) => {
    return DateTime.fromJSDate(dateObj).toFormat('dd LLLL yyyy');
  });

  // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
  eleventyConfig.addFilter('htmlDateString', (dateObj) => {
    return DateTime.fromJSDate(dateObj).toFormat('yyyy-LL-dd');
  });

  eleventyConfig.addFilter('markdown', (string) => {
    return md.renderInline(string);
  });

  eleventyConfig.addFilter('decodeHtmlEntities', (string) => {
    return he.decode(string);
  });

  // Match Firebase’s `cleanUrls` setting.
  eleventyConfig.addFilter('clean', (path) => {
    if (path === '/') return path;
    if (path === 'https://v8.dev/') return path;
    if (path.endsWith('/')) return path.slice(0, -1);
    return path;
  });

  // Get the first `n` elements of a collection.
  eleventyConfig.addFilter('head', (array, n) => {
    return array.slice(0, n);
  });

  // Create a collection for blog posts only.
  eleventyConfig.addCollection('posts', (collection) => {
    return collection.getFilteredByGlob('src/blog/*.md')
                     .sort((a, b) => b.date - a.date);
  });

  // Treat `*.md` files as Markdown.
  eleventyConfig.setLibrary('md', md);

  eleventyConfig.addCollection('tagList', (collection) => {
    const set = new Set();
    for (const item of collection.getAllSorted()) {
      if ('tags' in item.data) {
        const tags = item.data.tags;
        if (typeof tags === 'string') {
          tags = [tags];
        }
        for (const tag of tags) {
          set.add(tag);
        }
      }
    }
    return [...set].sort();
  });

  // Copy assets that don’t require a build step.
  eleventyConfig.addPassthroughCopy('src/favicon.ico');
  eleventyConfig.addPassthroughCopy('src/robots.txt');
  eleventyConfig.addPassthroughCopy('src/_img');

  return {
    templateFormats: [
      'md',
      'njk',
      'html',
    ],

    pathPrefix: '/',

    markdownTemplateEngine: 'liquid',
    htmlTemplateEngine: 'njk',
    dataTemplateEngine: 'njk',
    passthroughFileCopy: true,
    dir: {
      input: 'src',
      includes: '_includes',
      data: '_data',
      output: 'dist',
    },
  };
};
<|endoftext|>


<commit_before>module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
    ecmaFeatures: {
      legacyDecorators: true,
    },
  },
  plugins: ['ember', 'prettier', 'import-helpers'],
  extends: ['eslint:recommended', 'plugin:ember/recommended', 'plugin:prettier/recommended'],
  env: {
    browser: true,
  },
  rules: {
    // it's fine to use `return` without a value and rely on the implicit `undefined` return value
    'getter-return': 'off',

    'prettier/prettier': 'error',

    'ember/no-empty-attrs': 'off',
    'ember/no-get': 'off',
    'ember/require-computed-property-dependencies': 'off',

    'import-helpers/order-imports': [
      'error',
      {
        newlinesBetween: 'always',
        groups: [
          // Node.js built-in modules
          '/^(assert|async_hooks|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|http2|https|inspector|module|net|os|path|perf_hooks|process|punycode|querystring|readline|repl|stream|string_decoder|timers|tls|trace_events|tty|url|util|v8|vm|zli)/',
          // Testing modules
          ['/^(qunit|ember-qunit|@ember/test-helpers|ember-exam|htmlbars-inline-precompile)$/', '/^ember-exam\\//'],
          // Ember.js modules
          ['/^@(ember|ember-data|glimmer)\\//', '/^(ember|ember-data|rsvp)$/', '/^ember-data\\//'],
          ['module'],
          [`/^${require('./package.json').name}\\//`],
          ['parent', 'sibling', 'index'],
        ],
        alphabetize: { order: 'asc', ignoreCase: true },
      },
    ],
  },
  overrides: [
    // node files
    {
      files: [
        '.eslintrc.js',
        '.template-lintrc.js',
        'ember-cli-build.js',
        'fastboot.js',
        'testem.js',
        'blueprints/*/index.js',
        'config/**/*.js',
        'lib/*/index.js',
        'server/**/*.js',
      ],
      parserOptions: {
        sourceType: 'script',
        ecmaVersion: 2018,
      },
      env: {
        browser: false,
        node: true,
      },
    },
  ],
};
<commit_msg>ESLint: Enable `ember/no-classic-classes` rule<commit_after>module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
    ecmaFeatures: {
      legacyDecorators: true,
    },
  },
  plugins: ['ember', 'prettier', 'import-helpers'],
  extends: ['eslint:recommended', 'plugin:ember/recommended', 'plugin:prettier/recommended'],
  env: {
    browser: true,
  },
  rules: {
    // it's fine to use `return` without a value and rely on the implicit `undefined` return value
    'getter-return': 'off',

    'prettier/prettier': 'error',

    'ember/no-classic-classes': 'error',
    'ember/no-empty-attrs': 'off',
    'ember/no-get': 'off',
    'ember/require-computed-property-dependencies': 'off',

    'import-helpers/order-imports': [
      'error',
      {
        newlinesBetween: 'always',
        groups: [
          // Node.js built-in modules
          '/^(assert|async_hooks|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|http2|https|inspector|module|net|os|path|perf_hooks|process|punycode|querystring|readline|repl|stream|string_decoder|timers|tls|trace_events|tty|url|util|v8|vm|zli)/',
          // Testing modules
          ['/^(qunit|ember-qunit|@ember/test-helpers|ember-exam|htmlbars-inline-precompile)$/', '/^ember-exam\\//'],
          // Ember.js modules
          ['/^@(ember|ember-data|glimmer)\\//', '/^(ember|ember-data|rsvp)$/', '/^ember-data\\//'],
          ['module'],
          [`/^${require('./package.json').name}\\//`],
          ['parent', 'sibling', 'index'],
        ],
        alphabetize: { order: 'asc', ignoreCase: true },
      },
    ],
  },
  overrides: [
    // node files
    {
      files: [
        '.eslintrc.js',
        '.template-lintrc.js',
        'ember-cli-build.js',
        'fastboot.js',
        'testem.js',
        'blueprints/*/index.js',
        'config/**/*.js',
        'lib/*/index.js',
        'server/**/*.js',
      ],
      parserOptions: {
        sourceType: 'script',
        ecmaVersion: 2018,
      },
      env: {
        browser: false,
        node: true,
      },
    },
  ],
};
<|endoftext|>


<commit_before>module.exports = {
  root: true,
  env: {
    es6: true,
    node: true,
    'jest/globals': true,
  },
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint', 'jest', 'prettier'],
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/eslint-recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:jest/recommended',
    'prettier/@typescript-eslint',
    'plugin:prettier/recommended',
  ],
  rules: {
    'prettier/prettier': 'error',
  },
  overrides: [
    {
      files: ['*.js'],
      rules: {
        '@typescript-eslint/no-var-requires': 'off',
        '@typescript-eslint/explicit-function-return-type': 'off',
      },
    },
  ],
};
<commit_msg>eslint: add reportUnusedDisableDirectives (#596)<commit_after>module.exports = {
  root: true,
  env: {
    es6: true,
    node: true,
    'jest/globals': true,
  },
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint', 'jest', 'prettier'],
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/eslint-recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:jest/recommended',
    'prettier/@typescript-eslint',
    'plugin:prettier/recommended',
  ],
  rules: {
    'prettier/prettier': 'error',
  },
  overrides: [
    {
      files: ['*.js'],
      rules: {
        '@typescript-eslint/no-var-requires': 'off',
        '@typescript-eslint/explicit-function-return-type': 'off',
      },
    },
  ],
  reportUnusedDisableDirectives: true,
};
<|endoftext|>


<commit_before>// @flow
import {combineReducers} from 'redux'
import {routerReducer} from 'react-router-redux'

import type {State as AuthState} from 'reducers/auth'
import type {State as LayoutState} from 'reducers/layout'
import type {State as EntitiesPostsState} from 'reducers/posts'
import type {State as EntitiesUsersState} from 'reducers/users'

import {layout} from './layout'
import {posts} from './posts'
import {users} from './users'
import {auth} from './auth'

// Root reducer
export default combineReducers({
	layout,
	me: combineReducers({auth}),
	entities: combineReducers({
		posts,
		users
	}),
	routing: routerReducer
})

export type GlobalState = {layout: LayoutState} & {me: {auth: AuthState}} & {
		entities: {posts: EntitiesPostsState, users: EntitiesUsersState}
	}
<commit_msg>feat(reducers): remove posts, users reducers from `combineReducers`<commit_after>// @flow
import {combineReducers} from 'redux'
import {routerReducer} from 'react-router-redux'

import type {State as AuthState} from 'reducers/auth'
import type {State as LayoutState} from 'reducers/layout'
import type {State as EntitiesLinksState} from 'reducers/links'

import {layout} from './layout'
import {links} from './links'
import {auth} from './auth'

// Root reducer
export default combineReducers({
	layout,
	me: combineReducers({auth}),
	entities: combineReducers({
		links
	}),
	routing: routerReducer
})

export type GlobalState = {layout: LayoutState} & {me: {auth: AuthState}} & {
		entities: {links: EntitiesLinksState}
	}
<|endoftext|>


<commit_before>/*!
 * jQuery idleTimer plugin
 * version 0.8.092209
 * by Paul Irish.
 *   http://github.com/paulirish/yui-misc/tree/
 * MIT license

 * adapted from YUI idle timer by nzakas:
 *   http://github.com/nzakas/yui-misc/
*/
/*
 * Copyright (c) 2009 Nicholas C. Zakas
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

 // API available in <= v0.8
 /*******************************

 // idleTimer() takes an optional argument that defines the idle timeout
 // timeout is in milliseconds; defaults to 30000
 $.idleTimer(10000);

 $(document).bind("idle.idleTimer", function(){
    // function you want to fire when the user goes idle
 });

 $(document).bind("active.idleTimer", function(){
  // function you want to fire when the user becomes active again
 });

 // pass the string 'destroy' to stop the timer
 $.idleTimer('destroy');

 // you can query if the user is idle or not with data()
 $.data(document,'idleTimer');  // 'idle'  or 'active'

 // you can get time elapsed since user when idle/active
 $.idleTimer('getElapsedTime'); // time since state change in ms

 ********/

 // API available in >= v0.9
 /*************************

 // bind to specific elements, allows for multiple timer instances
 $(elem).idleTimer(timeout|'destroy'|'getElapsedTime');
 $.data(elem,'idleTimer');  // 'idle'  or 'active'

 // it's a good idea to stay off of document, where the old API ones are held.

 ********/

(function($){

$.idleTimer = function f(newTimeout){

    //$.idleTimer.tId = -1     //timeout ID

    var idle    = false,        //indicates if the user is idle
        enabled = true,        //indicates if the idle timer is enabled
        timeout = 30000,        //the amount of time (ms) before the user is considered idle
        events  = 'mousemove keydown DOMMouseScroll mousewheel mousedown', // activity is one of these events
      //f.olddate = undefined, // olddate used for getElapsedTime. stored on the function

    /* (intentionally not documented)
     * Toggles the idle state and fires an appropriate event.
     * @return {void}
     */
    toggleIdleState = function(){

        //toggle the state
        idle = !idle;

        // reset timeout counter
        f.olddate = +new Date;

        //fire appropriate event
        $(document).trigger(  $.data(document,'idleTimer', idle ? "idle" : "active" )  + '.idleTimer');
    },

    /**
     * Stops the idle timer. This removes appropriate event handlers
     * and cancels any pending timeouts.
     * @return {void}
     * @method stop
     * @static
     */
    stop = function(){

        //set to disabled
        enabled = false;

        //clear any pending timeouts
        clearTimeout($.idleTimer.tId);

        //detach the event handlers
        $(document).unbind('.idleTimer');
    },

    /* (intentionally not documented)
     * Handles a user event indicating that the user isn't idle.
     * @param {Event} event A DOM2-normalized event object.
     * @return {void}
     */
    handleUserEvent = function(){

        //clear any existing timeout
        clearTimeout($.idleTimer.tId);

        //if the idle timer is enabled
        if (enabled){

            //if it's idle, that means the user is no longer idle
            if (idle){
                toggleIdleState();
            }

            //set a new timeout
            $.idleTimer.tId = setTimeout(toggleIdleState, timeout);

        }
     };

    /**
     * Starts the idle timer. This adds appropriate event handlers
     * and starts the first timeout.
     * @param {int} newTimeout (Optional) A new value for the timeout period in ms.
     * @return {void}
     * @method $.idleTimer
     * @static
     */

    f.olddate = f.olddate || +new Date;

    //assign a new timeout if necessary
    if (typeof newTimeout == "number"){
        timeout = newTimeout;
    } else if (newTimeout === 'destroy') {
        stop();
        return this;
    } else if (newTimeout === 'getElapsedTime'){
        return (+new Date) - f.olddate;
    }

    //assign appropriate event handlers
    $(document).bind($.trim((events+' ').split(' ').join('.idleTimer ')),handleUserEvent);

    //set a timeout to toggle state
    $.idleTimer.tId = setTimeout(toggleIdleState, timeout);

    // assume the user is active for the first x seconds.
    $.data(document,'idleTimer',"active");

}; // end of $.idleTimer()

$.fn.idleTimer = function(){

  $.idleTimer()

  return this;
}

})(jQuery);<commit_msg>first pass at the js..<commit_after>/*!
 * jQuery idleTimer plugin
 * version 0.8.092209
 * by Paul Irish.
 *   http://github.com/paulirish/yui-misc/tree/
 * MIT license

 * adapted from YUI idle timer by nzakas:
 *   http://github.com/nzakas/yui-misc/
*/
/*
 * Copyright (c) 2009 Nicholas C. Zakas
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

 // API available in <= v0.8
 /*******************************

 // idleTimer() takes an optional argument that defines the idle timeout
 // timeout is in milliseconds; defaults to 30000
 $.idleTimer(10000);

 $(document).bind("idle.idleTimer", function(){
    // function you want to fire when the user goes idle
 });

 $(document).bind("active.idleTimer", function(){
  // function you want to fire when the user becomes active again
 });

 // pass the string 'destroy' to stop the timer
 $.idleTimer('destroy');

 // you can query if the user is idle or not with data()
 $.data(document,'idleTimer');  // 'idle'  or 'active'

 // you can get time elapsed since user when idle/active
 $.idleTimer('getElapsedTime'); // time since state change in ms

 ********/

 // API available in >= v0.9
 /*************************

 // bind to specific elements, allows for multiple timer instances
 $(elem).idleTimer(timeout|'destroy'|'getElapsedTime');
 $.data(elem,'idleTimer');  // 'idle'  or 'active'

 // it's a good idea to stay off of document, where the old API ones are held.

 ********/

(function($){

$.idleTimer = function f(newTimeout, elem){

    //$.idleTimer.tId = -1     //timeout ID

    var idle    = false,        //indicates if the user is idle
        enabled = true,        //indicates if the idle timer is enabled
        timeout = 30000,        //the amount of time (ms) before the user is considered idle
        events  = 'mousemove keydown DOMMouseScroll mousewheel mousedown'; // activity is one of these events
  //    f.olddate = undefined, // olddate used for getElapsedTime. stored on the function

    elem = elem || document;

    /* (intentionally not documented)
     * Toggles the idle state and fires an appropriate event.
     * @return {void}
     */
    var toggleIdleState = function(){

        //toggle the state
        idle = !idle;

        // reset timeout counter
        f.olddate = +new Date;

        //fire appropriate event
        $(elem).trigger(  $.data(elem,'idleTimer', idle ? "idle" : "active" )  + '.idleTimer');
    },

    /**
     * Stops the idle timer. This removes appropriate event handlers
     * and cancels any pending timeouts.
     * @return {void}
     * @method stop
     * @static
     */
    stop = function(){

        //set to disabled
        enabled = false;

        //clear any pending timeouts
        clearTimeout($.idleTimer.tId);

        //detach the event handlers
        $(elem).unbind('.idleTimer');
    },

    /* (intentionally not documented)
     * Handles a user event indicating that the user isn't idle.
     * @param {Event} event A DOM2-normalized event object.
     * @return {void}
     */
    handleUserEvent = function(){

        //clear any existing timeout
        clearTimeout($.idleTimer.tId);

        //if the idle timer is enabled
        if (enabled){

            //if it's idle, that means the user is no longer idle
            if (idle){
                toggleIdleState();
            }

            //set a new timeout
            $.idleTimer.tId = setTimeout(toggleIdleState, timeout);

        }
     };

    /**
     * Starts the idle timer. This adds appropriate event handlers
     * and starts the first timeout.
     * @param {int} newTimeout (Optional) A new value for the timeout period in ms.
     * @return {void}
     * @method $.idleTimer
     * @static
     */

    f.olddate = f.olddate || +new Date;

    //assign a new timeout if necessary
    if (typeof newTimeout == "number"){
        timeout = newTimeout;
    } else if (newTimeout === 'destroy') {
        stop();
        return this;
    } else if (newTimeout === 'getElapsedTime'){
        return (+new Date) - f.olddate;
    }

    //assign appropriate event handlers
    $(elem).bind($.trim((events+' ').split(' ').join('.idleTimer ')),handleUserEvent);

    //set a timeout to toggle state
    $.idleTimer.tId = setTimeout(toggleIdleState, timeout);

    // assume the user is active for the first x seconds.
    $.data(elem,'idleTimer',"active");

}; // end of $.idleTimer()

$.fn.idleTimer = function(newTimeout){

  this[0] && $.idleTimer(newTimeout,this[0]);

  return this;
}

})(jQuery);<|endoftext|>


<commit_before>// @flow

import * as React from 'react'
import {View, StyleSheet} from 'react-native'
import * as c from '../components/colors'

export const GrabberBar = () => (
	<View>
		<View style={styles.grabber} />
	</View>
)

const styles = StyleSheet.create({
	grabber: {
		backgroundColor: c.iosGray,
		borderRadius: 4,
		height: 4,
		width: 30,
		alignSelf: 'center',
		marginBottom: 1,
		marginTop: 6,
	},
})
<commit_msg>make gabber larger<commit_after>// @flow

import * as React from 'react'
import {View, StyleSheet} from 'react-native'
import * as c from '../components/colors'

export const GrabberBar = () => (
	<View>
		<View style={styles.grabber} />
	</View>
)

const styles = StyleSheet.create({
	grabber: {
		backgroundColor: c.iosGray,
		borderRadius: 4,
		height: 6,
		width: 40,
		alignSelf: 'center',
		marginBottom: 1,
		marginTop: 6,
	},
})
<|endoftext|>


<commit_before>module.exports = {

	//---------------------------------------------------------------------
	// Editor Extension Name
	//
	// This is the name of the editor extension displayed in the editor.
	//---------------------------------------------------------------------

	name: "DBM Dashboard",

	//---------------------------------------------------------------------
	// Is Command Extension
	//
	// Must be true to appear in "command" context menu.
	// This means each "command" will hold its own copy of this data.
	//---------------------------------------------------------------------

	isCommandExtension: false,

	//---------------------------------------------------------------------
	// Is Event Extension
	//
	// Must be true to appear in "event" context menu.
	// This means each "event" will hold its own copy of this data.
	//---------------------------------------------------------------------

	isEventExtension: false,

	//---------------------------------------------------------------------
	// Is Editor Extension
	//
	// Must be true to appear in the main editor context menu.
	// This means there will only be one copy of this data per project.
	//---------------------------------------------------------------------

	isEditorExtension: true,

	//---------------------------------------------------------------------
	// Extension Fields
	//
	// These are the fields for the extension. These fields are customized
	// by creating elements with corresponding IDs in the HTML. These
	// are also the names of the fields stored in the command's/event's JSON data.
	//---------------------------------------------------------------------

	fields: [
		"port", "clientSecret", "callbackURL", "owner", "supportServer"
	],

	//---------------------------------------------------------------------
	// Default Fields
	//
	// The default values of the fields.
	//---------------------------------------------------------------------

	defaultFields: {
		port: require('../extensions/dbm_dashboard_extension/config.json').port,
		clientSecret: require('../extensions/dbm_dashboard_extension/config.json').clientSecret,
		callbackURL: require('../extensions/dbm_dashboard_extension/config.json').callbackURL,
		owner: require('../extensions/dbm_dashboard_extension/config.json').owner,
		supportServer: require('../extensions/dbm_dashboard_extension/config.json').supportServer
	},

	//---------------------------------------------------------------------
	// Extension Dialog Size
	//
	// Returns the size of the extension dialog.
	//---------------------------------------------------------------------

	size: function () {
		return {
			width: 700,
			height: 540
		};
	},

	//---------------------------------------------------------------------
	// Extension HTML
	//
	// This function returns a string containing the HTML used for
	// the context menu dialog.
	//---------------------------------------------------------------------

	html: function (data, DBM) {
		return `

						Extension Info:

						Version: 1.0.0

						Created by: Great Plains Modding

					Port:

					<input type="text" value="${data.port}" class="round" style="padding-bottom: 3px;" id="port">

					clientSecret:

					<input type="text" value="${data.clientSecret}" class="round" id="clientSecret">

					callbackURL:

					<input type="text" value="${data.callbackURL}" class="round" id="callbackURL">

					Owner ID:

					<input type="text" value="${data.owner}" class="round" id="owner">

					supportServer:

					<input type="text" value="${data.supportServer}" class="round" id="supportServer">

`
	},

	//---------------------------------------------------------------------
	// Extension Dialog Init Code
	//
	// When the HTML is first applied to the extension dialog, this code
	// is also run. This helps add modifications or setup reactionary
	// functions for the DOM elements.
	//---------------------------------------------------------------------

	init: function () {

	},

	//---------------------------------------------------------------------
	// Extension Dialog Close Code
	//
	// When the dialog is closed, this is called. Use it to save the data.
	//---------------------------------------------------------------------

	close: function (document, data) {
		data.port = String(document.getElementById("port").value);
		data.clientSecret = String(document.getElementById("clientSecret").value);
		data.callbackURL = String(document.getElementById("callbackURL").value);
		data.owner = String(document.getElementById("owner").value);
		data.supportServer = String(document.getElementById("supportServer").value);

		try {
			const config = require('./dbm_dashboard_extension/config.json');
			const dashboardConfigPath = require("path").join(__dirname, "../extensions", "dbm_dashboard_extension", "config.json");
			const configNew = {
				port: data.port,
				isBotSharded: false,
				tokenSecret: Math.random().toString(36).substr(2),
				clientSecret: data.clientSecret,
				callbackURL: data.callbackURL,
				owner: data.owner,
				inviteLink: "/dashboard/@me",
				supportServer: data.supportServer,
				introText: config.introText,
				footerText: config.footerText,
				theme: "default",
				isGlitch: config.isGlitch
			};

			configNew.featureOne = config.featureOne;
			configNew.featureTwo = config.featureTwo;
			configNew.featureThree = config.featureThree;
			configNew.featureFour = config.featureFour;
			configNew.navItems = config.navItems;

			let settings = JSON.stringify(configNew);
			require("fs").writeFileSync(dashboardConfigPath, settings, "utf8");
		} catch (error) {
			require("fs").writeFileSync("dashboard-errors.txt", error, "utf8");
		};
	},

	//---------------------------------------------------------------------
	// Extension On Load
	//
	// If an extension has a function for "load", it will be called
	// whenever the editor loads data.
	//
	// The "DBM" parameter is the global variable. Store loaded data within it.
	//---------------------------------------------------------------------

	load: function (DBM, projectLoc) {

	},

	//---------------------------------------------------------------------
	// Extension On Save
	//
	// If an extension has a function for "save", it will be called
	// whenever the editor saves data.
	//
	// The "data" parameter contains all data. Use this to modify
	// the data that is saved. The properties correspond to the
	// data file names:
	//
	//  - data.commands
	//  - data.settings
	// etc...
	//---------------------------------------------------------------------

	save: function (DBM, data, projectLoc) {

	},

	//---------------------------------------------------------------------
	// Editor Extension Bot Mod
	//
	// Upon initialization of the bot, this code is run. Using the bot's
	// DBM namespace, one can add/modify existing functions if necessary.
	// In order to reduce conflictions between mods, be sure to alias
	// functions you wish to overwrite.
	//
	// This is absolutely necessary for editor extensions since it
	// allows us to setup modifications for the necessary functions
	// we want to change.
	//
	// The client object can be retrieved from: `const bot = DBM.Bot.bot;`
	// Classes can be retrieved also using it: `const { Actions, Event } = DBM;`
	//---------------------------------------------------------------------

	mod: function (DBM) {
		let devMode = false
		DBM.lastPage = new Map();
		DBM.actionsExecuted = new Map();

		const {
			dashboardConfig,
			ready
		} = require('../extensions/dbm_dashboard_extension/functions');
		const config = dashboardConfig()

		// Mini module handler
		const path = require("path");
		moduleRequire = function (packageName) {
			if (config.isGlitch) {
				const nodeModulesPath = path.join(__dirname, "../node_modules", packageName);
				return require(nodeModulesPath)
			} else {
				const nodeModulesPath = path.join(__dirname, "dbm_dashboard_extension", "node_modules", packageName);
				return require(nodeModulesPath)
			}
		};

		const express = moduleRequire('express'),
			{ fs, readdirSync } = require("fs"),
			chalk = moduleRequire('chalk'),
			bodyParser = moduleRequire('body-parser'),
			cookieParser = moduleRequire('cookie-parser'),
			ejs = moduleRequire('ejs'),
			Strategy = moduleRequire('passport-discord').Strategy,
			session = moduleRequire('express-session'),
			passport = moduleRequire('passport');

		var app = express();
		app.themes = new Map();
		app.routes = new Map();
		app.actions = new Map();

		// Pulls all of the files from actions to be used as mods!
		readdirSync('./extensions/dbm_dashboard_extension/actions').forEach(dir => {
			const actions = readdirSync(`./extensions/dbm_dashboard_extension/actions/${dir}/`).filter(file => file.endsWith('.js'));
			for (let file of actions) {
				let pull = require(`../extensions/dbm_dashboard_extension/actions/${dir}/${file}`);
				app.actions.set(pull.name, pull);
				if (devMode) console.log(chalk.green(`Successfully loaded ${pull.name}`))
			}
		});

		// Route handler
		readdirSync('./extensions/dbm_dashboard_extension/actions').forEach(dir => {
			const actions = readdirSync(`./extensions/dbm_dashboard_extension/actions/${dir}/`).filter(file => file.endsWith('.js'));
			for (let file of actions) {
				let pull = require(`../extensions/dbm_dashboard_extension/actions/${dir}/${file}`);
				if (pull.routeMod) {
					app.routes.set(pull.name, pull);
					if (devMode) console.log(chalk.green(`Successfully loaded ${pull.name}`))
				}
			}
		});

		// Themes who??
		readdirSync('./extensions/dbm_dashboard_extension/public/themes').forEach(dir => {
			const themes = readdirSync(`./extensions/dbm_dashboard_extension/public/themes/${dir}/`).filter(file => file.endsWith('.css'));
			for (let file of themes) {
				app.themes.set(dir, `/themes/${dir}/${file}`);
				if (devMode) console.log(chalk.green(`Successfully loaded ${file}`));
			}
		})

		// We wait for the bot to be ready so these dmb nerds dont break it
		DBM.Bot.onReady = function () {
			const client = DBM.Bot.bot;
			let scopes = ['identify', 'guilds'];
			//
			// Define the express server settings
			app.set('view engine', 'ejs');
			app.use(express.static(path.join(__dirname, '/dbm_dashboard_extension/public')));
			app.set('views', path.join(__dirname, '/dbm_dashboard_extension/views'));
			app.use(cookieParser(config.tokenSecret));
			app.use(session({
				secret: config.tokenSecret,
				resave: false,
				saveUninitialized: false
			}));
			app.use(bodyParser.urlencoded({
				extended: true
			}));
			app.use(passport.initialize());
			app.use(passport.session());
			passport.serializeUser(function (user, done) {
				done(null, user);
			});
			passport.deserializeUser(function (obj, done) {
				done(null, obj);
			});

			passport.use(new Strategy({
				clientID: DBM.Bot.bot.user.id,
				clientSecret: config.clientSecret,
				callbackURL: config.callbackURL,
				scope: scopes
			}, (accessToken, refreshToken, profile, done) => {
				process.nextTick(() => {
					return done(null, profile);
				});
			}));

			app.get('/login', passport.authenticate('discord', {
				scope: scopes
			}), function (req, res) {});

			app.get('/dashboard/callback',
				passport.authenticate('discord', {
					failureRedirect: '/dashboard/@me'
				}),
				function (req, res) {
					adminCommandExecuted(req, false)
					dashboardCommandExecuted(req, false)
					if (req.user.id == config.owner) return res.redirect('/dashboard/admin');
					res.redirect('/dashboard/@me');
				}
			);

			if (app.routes) {
				app.routes.forEach(data => {
					if (data.routeUrl) {
						app.get(data.routeUrl, function (req, res) {
							res.render('customRoute', {
								custom: data.html(app, config, DBM, dashboardConfig, DBM.Bot.bot, req, res)
							});
							data.run(app, config, DBM, dashboardConfig, DBM.Bot.bot)
						})
					} else {
						data.run(app, config, DBM, dashboardConfig, DBM.Bot.bot)
					}
				})
			}

			function checkAuth(req, res, next) {
				if (req.isAuthenticated()) {
					return next()
				}
				res.redirect('/login');
			}

			function checkAuthOwner(req, res, next) {
				if (req.isAuthenticated()) {
					if (req.user.id == config.owner) {
						next();
					} else res.redirect('/dashboard/@me');
				} else res.redirect('/login');
			}

			function adminCommandExecuted(req, commandExecuted) {
				let data = {
					adminCommandExecuted: commandExecuted
				}
				DBM.actionsExecuted.set(req.user.id, data);
			};

			function dashboardCommandExecuted(req, dashboardCommandExecuted) {
				let data = {
					dashboardCommandExecuted: dashboardCommandExecuted
				}
				DBM.actionsExecuted.set(req.user.id, data);
			};

			function theme() {
				let theme = app.themes.get(config.theme);
				return theme
			}

			async function sections() {
				let actions = app.actions;
				let section = []
				await actions.forEach(action => {
					if (!section.includes(action.section)) {
						section.push(action.section)
					}
				});
			}

			app.listen(config.port, () => ready());
		};
	}
};
<commit_msg>Update dbm_dashboard_extension.js<commit_after>module.exports = {

	//---------------------------------------------------------------------
	// Editor Extension Name
	//
	// This is the name of the editor extension displayed in the editor.
	//---------------------------------------------------------------------

	name: "DBM Dashboard",

	//---------------------------------------------------------------------
	// Is Command Extension
	//
	// Must be true to appear in "command" context menu.
	// This means each "command" will hold its own copy of this data.
	//---------------------------------------------------------------------

	isCommandExtension: false,

	//---------------------------------------------------------------------
	// Is Event Extension
	//
	// Must be true to appear in "event" context menu.
	// This means each "event" will hold its own copy of this data.
	//---------------------------------------------------------------------

	isEventExtension: false,

	//---------------------------------------------------------------------
	// Is Editor Extension
	//
	// Must be true to appear in the main editor context menu.
	// This means there will only be one copy of this data per project.
	//---------------------------------------------------------------------

	isEditorExtension: true,

	//---------------------------------------------------------------------
	// Extension Fields
	//
	// These are the fields for the extension. These fields are customized
	// by creating elements with corresponding IDs in the HTML. These
	// are also the names of the fields stored in the command's/event's JSON data.
	//---------------------------------------------------------------------

	fields: [
		"port", "clientSecret", "callbackURL", "owner", "supportServer"
	],

	//---------------------------------------------------------------------
	// Default Fields
	//
	// The default values of the fields.
	//---------------------------------------------------------------------

	defaultFields: {
		port: require('../extensions/dbm_dashboard_extension/config.json').port,
		clientSecret: require('../extensions/dbm_dashboard_extension/config.json').clientSecret,
		callbackURL: require('../extensions/dbm_dashboard_extension/config.json').callbackURL,
		owner: require('../extensions/dbm_dashboard_extension/config.json').owner,
		supportServer: require('../extensions/dbm_dashboard_extension/config.json').supportServer
	},

	//---------------------------------------------------------------------
	// Extension Dialog Size
	//
	// Returns the size of the extension dialog.
	//---------------------------------------------------------------------

	size: function () {
		return {
			width: 700,
			height: 540
		};
	},

	//---------------------------------------------------------------------
	// Extension HTML
	//
	// This function returns a string containing the HTML used for
	// the context menu dialog.
	//---------------------------------------------------------------------

	html: function (data, DBM) {
		return `

						Extension Info:

						Version: 1.0.0

						Created by: Great Plains Modding

					Port:

					<input type="text" value="${data.port}" class="round" style="padding-bottom: 3px;" id="port">

					clientSecret:

					<input type="text" value="${data.clientSecret}" class="round" id="clientSecret">

					callbackURL:

					<input type="text" value="${data.callbackURL}" class="round" id="callbackURL">

					Owner ID:

					<input type="text" value="${data.owner}" class="round" id="owner">

					supportServer:

					<input type="text" value="${data.supportServer}" class="round" id="supportServer">

`
	},

	//---------------------------------------------------------------------
	// Extension Dialog Init Code
	//
	// When the HTML is first applied to the extension dialog, this code
	// is also run. This helps add modifications or setup reactionary
	// functions for the DOM elements.
	//---------------------------------------------------------------------

	init: function () {

	},

	//---------------------------------------------------------------------
	// Extension Dialog Close Code
	//
	// When the dialog is closed, this is called. Use it to save the data.
	//---------------------------------------------------------------------

	close: function (document, data) {
		data.port = String(document.getElementById("port").value);
		data.clientSecret = String(document.getElementById("clientSecret").value);
		data.callbackURL = String(document.getElementById("callbackURL").value);
		data.owner = String(document.getElementById("owner").value);
		data.supportServer = String(document.getElementById("supportServer").value);

		try {
			const config = require('./dbm_dashboard_extension/config.json');
			const dashboardConfigPath = require("path").join(__dirname, "../extensions", "dbm_dashboard_extension", "config.json");
			const configNew = {
				port: data.port,
				isBotSharded: false,
				tokenSecret: Math.random().toString(36).substr(2),
				clientSecret: data.clientSecret,
				callbackURL: data.callbackURL,
				owner: data.owner,
				inviteLink: "/dashboard/@me",
				supportServer: data.supportServer,
				introText: config.introText,
				footerText: config.footerText,
				theme: "default",
				isGlitch: config.isGlitch
			};

			configNew.featureOne = config.featureOne;
			configNew.featureTwo = config.featureTwo;
			configNew.featureThree = config.featureThree;
			configNew.featureFour = config.featureFour;
			configNew.navItems = config.navItems;

			let settings = JSON.stringify(configNew);
			require("fs").writeFileSync(dashboardConfigPath, settings, "utf8");
		} catch (error) {
			require("fs").writeFileSync("dashboard-errors.txt", error, "utf8");
		};
	},

	//---------------------------------------------------------------------
	// Extension On Load
	//
	// If an extension has a function for "load", it will be called
	// whenever the editor loads data.
	//
	// The "DBM" parameter is the global variable. Store loaded data within it.
	//---------------------------------------------------------------------

	load: function (DBM, projectLoc) {

	},

	//---------------------------------------------------------------------
	// Extension On Save
	//
	// If an extension has a function for "save", it will be called
	// whenever the editor saves data.
	//
	// The "data" parameter contains all data. Use this to modify
	// the data that is saved. The properties correspond to the
	// data file names:
	//
	//  - data.commands
	//  - data.settings
	// etc...
	//---------------------------------------------------------------------

	save: function (DBM, data, projectLoc) {

	},

	//---------------------------------------------------------------------
	// Editor Extension Bot Mod
	//
	// Upon initialization of the bot, this code is run. Using the bot's
	// DBM namespace, one can add/modify existing functions if necessary.
	// In order to reduce conflictions between mods, be sure to alias
	// functions you wish to overwrite.
	//
	// This is absolutely necessary for editor extensions since it
	// allows us to setup modifications for the necessary functions
	// we want to change.
	//
	// The client object can be retrieved from: `const bot = DBM.Bot.bot;`
	// Classes can be retrieved also using it: `const { Actions, Event } = DBM;`
	//---------------------------------------------------------------------

	mod: function (DBM) {
		let devMode = false
		DBM.lastPage = new Map();
		DBM.actionsExecuted = new Map();

		const {
			dashboardConfig,
			ready
		} = require('../extensions/dbm_dashboard_extension/functions');
		const config = dashboardConfig()

		// Mini module handler
		const path = require("path");
		moduleRequire = function (packageName) {
			if (config.isGlitch) {
				const nodeModulesPath = path.join(__dirname, "../node_modules", packageName);
				return require(nodeModulesPath)
			} else {
				const nodeModulesPath = path.join(__dirname, "dbm_dashboard_extension", "node_modules", packageName);
				return require(nodeModulesPath)
			}
		};

		const express = moduleRequire('express'),
			{
				fs,
				readdirSync
			} = require("fs"),
			chalk = moduleRequire('chalk'),
			bodyParser = moduleRequire('body-parser'),
			cookieParser = moduleRequire('cookie-parser'),
			ejs = moduleRequire('ejs'),
			Strategy = moduleRequire('passport-discord').Strategy,
			session = moduleRequire('express-session'),
			passport = moduleRequire('passport');

		var app = express();
		app.themes = new Map();
		app.routes = new Map();
		app.actions = new Map();

		// Pulls all of the files from actions to be used as mods!
		readdirSync('./extensions/dbm_dashboard_extension/actions').forEach(dir => {
			const actions = readdirSync(`./extensions/dbm_dashboard_extension/actions/${dir}/`).filter(file => file.endsWith('.js'));
			for (let file of actions) {
				let pull = require(`../extensions/dbm_dashboard_extension/actions/${dir}/${file}`);
				app.actions.set(pull.name, pull);
				if (devMode) console.log(chalk.green(`Successfully loaded ${pull.name}`))
			}
		});

		// Route handler
		readdirSync('./extensions/dbm_dashboard_extension/actions').forEach(dir => {
			const actions = readdirSync(`./extensions/dbm_dashboard_extension/actions/${dir}/`).filter(file => file.endsWith('.js'));
			for (let file of actions) {
				let pull = require(`../extensions/dbm_dashboard_extension/actions/${dir}/${file}`);
				if (pull.routeMod) {
					app.routes.set(pull.name, pull);
					if (devMode) console.log(chalk.green(`Successfully loaded ${pull.name}`))
				}
			}
		});

		// Themes who??
		readdirSync('./extensions/dbm_dashboard_extension/public/themes').forEach(dir => {
			const themes = readdirSync(`./extensions/dbm_dashboard_extension/public/themes/${dir}/`).filter(file => file.endsWith('.css'));
			for (let file of themes) {
				app.themes.set(dir, `/themes/${dir}/${file}`);
				if (devMode) console.log(chalk.green(`Successfully loaded ${file}`));
			}
		})

		// We wait for the bot to be ready so these dmb nerds dont break it
		DBM.DashboardOnReady = DBM.Bot.onReady || {};

		DBM.Bot.onReady = function () {
			const client = DBM.Bot.bot;
			let scopes = ['identify', 'guilds'];
			//
			// Define the express server settings
			app.set('view engine', 'ejs');
			app.use(express.static(path.join(__dirname, '/dbm_dashboard_extension/public')));
			app.set('views', path.join(__dirname, '/dbm_dashboard_extension/views'));
			app.use(cookieParser(config.tokenSecret));
			app.use(session({
				secret: config.tokenSecret,
				resave: false,
				saveUninitialized: false
			}));
			app.use(bodyParser.urlencoded({
				extended: true
			}));
			app.use(passport.initialize());
			app.use(passport.session());
			passport.serializeUser(function (user, done) {
				done(null, user);
			});
			passport.deserializeUser(function (obj, done) {
				done(null, obj);
			});

			passport.use(new Strategy({
				clientID: DBM.Bot.bot.user.id,
				clientSecret: config.clientSecret,
				callbackURL: config.callbackURL,
				scope: scopes
			}, (accessToken, refreshToken, profile, done) => {
				process.nextTick(() => {
					return done(null, profile);
				});
			}));

			app.get('/login', passport.authenticate('discord', {
				scope: scopes
			}), function (req, res) {});

			app.get('/dashboard/callback',
				passport.authenticate('discord', {
					failureRedirect: '/dashboard/@me'
				}),
				function (req, res) {
					adminCommandExecuted(req, false)
					dashboardCommandExecuted(req, false)
					if (req.user.id == config.owner) return res.redirect('/dashboard/admin');
					res.redirect('/dashboard/@me');
				}
			);

			if (app.routes) {
				app.routes.forEach(data => {
					if (data.routeUrl) {
						app.get(data.routeUrl, function (req, res) {
							res.render('customRoute', {
								custom: data.html(app, config, DBM, dashboardConfig, DBM.Bot.bot, req, res)
							});
							data.run(app, config, DBM, dashboardConfig, DBM.Bot.bot)
						})
					} else {
						data.run(app, config, DBM, dashboardConfig, DBM.Bot.bot)
					}
				})
			}

			function checkAuth(req, res, next) {
				if (req.isAuthenticated()) {
					return next()
				}
				res.redirect('/login');
			}

			function checkAuthOwner(req, res, next) {
				if (req.isAuthenticated()) {
					if (req.user.id == config.owner) {
						next();
					} else res.redirect('/dashboard/@me');
				} else res.redirect('/login');
			}

			function adminCommandExecuted(req, commandExecuted) {
				let data = {
					adminCommandExecuted: commandExecuted
				}
				DBM.actionsExecuted.set(req.user.id, data);
			};

			function dashboardCommandExecuted(req, dashboardCommandExecuted) {
				let data = {
					dashboardCommandExecuted: dashboardCommandExecuted
				}
				DBM.actionsExecuted.set(req.user.id, data);
			};

			function theme() {
				let theme = app.themes.get(config.theme);
				return theme
			}

			async function sections() {
				let actions = app.actions;
				let section = []
				await actions.forEach(action => {
					if (!section.includes(action.section)) {
						section.push(action.section)
					}
				});
			}

			app.listen(config.port, () => ready());
			DBM.DashboardOnReady.apply(this, arguments);
		};
	}
};
<|endoftext|>


<commit_before>module.exports = {
  extends: 'airbnb',
};
<commit_msg>Allow jsx in .js files<commit_after>module.exports = {
  extends: 'airbnb',
  rules: {
    'react/jsx-filename-extension': ['error', { extensions: ['.js'] }],
  },
};
<|endoftext|>


<commit_before>const javascriptSettings = {
  files: ['*.js'],
  extends: [
    'standard',
    'plugin:jest/recommended'
  ],
  rules: {
    'no-else-return': ['error', { allowElseIf: false }],
    'no-var': 'warn',
    'one-var': 'off',
    'space-before-function-paren': ['error', 'never'],
    semi: ['error', 'always']
  },
}

const typescriptSettings = {
  files: ['*.ts'],
  extends: ['standard-with-typescript'],
  parserOptions: {
    project: './tsconfig.json'
  },
  rules: {
    'no-else-return': ['error', { allowElseIf: false }],
    'no-var': 'warn',
    'one-var': 'off',
    'space-before-function-paren': ['error', 'never'],
    semi: ['error', 'always'],
    '@typescript-eslint/member-delimiter-style': [
      'error',
      {
        multiline: {
          delimiter: 'semi',
          requireLast: true
        },
        singleline: {
          delimiter: 'semi',
          requireLast: false
        }
      }
    ]
  }
}

module.exports = {
  plugins: ['jest'],
  overrides: [
    javascriptSettings,
    typescriptSettings
  ]
}
<commit_msg>Fix override for semi after base changed (#1270)<commit_after>const javascriptSettings = {
  files: ['*.js'],
  extends: [
    'standard',
    'plugin:jest/recommended'
  ],
  rules: {
    'no-else-return': ['error', { allowElseIf: false }],
    'no-var': 'warn',
    'one-var': 'off',
    'space-before-function-paren': ['error', 'never'],
    'semi': ['error', 'always']
  },
}

const typescriptSettings = {
  files: ['*.ts'],
  extends: ['standard-with-typescript'],
  parserOptions: {
    project: './tsconfig.json'
  },
  rules: {
    'no-else-return': ['error', { allowElseIf: false }],
    'no-var': 'warn',
    'one-var': 'off',
    'space-before-function-paren': ['error', 'never'],
    'semi': 'off',
    '@typescript-eslint/semi': ['error', 'always'],
    '@typescript-eslint/member-delimiter-style': [
      'error',
      {
        multiline: {
          delimiter: 'semi',
          requireLast: true
        },
        singleline: {
          delimiter: 'semi',
          requireLast: false
        }
      }
    ]
  }
}

module.exports = {
  plugins: ['jest'],
  overrides: [
    javascriptSettings,
    typescriptSettings
  ]
}
<|endoftext|>


<commit_before>/* eslint-env node */
module.exports = {
	root: true,

	// Based on the recommended rules
	extends: "eslint:recommended",

	// Default environments
	env: {
		es6: false,
		browser: true,
		jquery: true
	},

	// Globals
	globals: {
		// Libs
		"Handlebars": false,
		"luga": false,
		// App
		"jsBack": true
	},

	parserOptions: {
		ecmaFeatures: {
			// Enable let and const
			blockBindings: true
		}
	},

	rules: {
		"camelcase": ["error"],
		"eqeqeq": ["error"],

		"indent": [
			"error",
			"tab",
			{"SwitchCase": 1}
		],

		"new-cap": ["warn"],

		"no-array-constructor": ["error"],
		"no-bitwise": ["error"],
		"no-console": ["warn"],
		"no-caller": ["error"],
		"no-extend-native": ["error"],
		"no-implicit-globals": ["error"],
		"no-multi-assign": ["error"],
		"no-new-func": ["error"],
		"no-new-object": ["error"],
		"no-new-wrappers": ["error"],
		"no-param-reassign": ["warn"],
		"no-proto": ["error"],
		"no-return-assign": ["error", "always"],
		"no-sequences": ["error"],
		"no-shadow": ["warn"],
		"no-ternary": ["warn"],
		"no-undef": ["error"],
		"no-underscore-dangle": ["error"],
		"no-unused-vars": ["error", {"vars": "all", "args": "none", "ignoreRestSiblings": false}],
		"no-void": ["error"],
		"no-with": ["error"],

		"quotes": [
			"error",
			"double"
		],

		"semi": ["error"],

		// Strict at function level (at least)
		"strict": [
			"error",
			"function"
		],

		// New features, we se "const" always if not possible use "let"
		"prefer-const": ["warn"],

		// JSDoc
		"require-jsdoc": ["warn"],
		"valid-jsdoc": [
			"warn",
			{
				prefer: {
					// Use the right string instead of the left one
					"returns": "return",
					"arg": "param",
					"argument": "param",
					"class": "constructor",
					"virtual": "abstract"
				},
				preferType: {
					// Use the right string instead of the left one
					'object': 'Object',
					'Number': 'Number',
					'String': 'String',
					'Boolean': 'Boolean'
				},

				// If and only if the function or method has a return statement (this option value does apply to constructors)
				requireReturn: false,
				requireReturnType: true,
				requireParamDescription: false,
				requireReturnDescription: false
			}
		]
	}
};<commit_msg>Updated ESLint config<commit_after>/* eslint-env node */
module.exports = {
	root: true,

	// Based on the recommended rules
	extends: "eslint:recommended",

	// Default environments
	env: {
		es6: false,
		browser: true,
		jquery: true
	},

	// Globals
	globals: {
		// Libs
		"Handlebars": false,
		"luga": false,
		// App
		"jsBack": true
	},

	parserOptions: {
		ecmaFeatures: {
			// Enable let and const
			blockBindings: true
		}
	},

	rules: {
		"camelcase": ["error"],
		"eqeqeq": ["error"],

		"indent": [
			"error",
			"tab",
			{"SwitchCase": 1}
		],

		"new-cap": ["warn"],

		"no-array-constructor": ["error"],
		"no-bitwise": ["error"],
		"no-console": ["warn"],
		"no-caller": ["error"],
		"no-extend-native": ["error"],
		"no-implicit-globals": ["error"],
		"no-multi-assign": ["error"],
		"no-new-func": ["error"],
		"no-new-object": ["error"],
		"no-new-wrappers": ["error"],
		"no-param-reassign": ["warn"],
		"no-proto": ["error"],
		"no-return-assign": ["error", "always"],
		"no-sequences": ["error"],
		"no-shadow": ["warn"],
		"no-ternary": ["warn"],
		"no-undef": ["error"],
		"no-underscore-dangle": ["error"],
		"no-unused-vars": ["error", {"vars": "all", "args": "none", "ignoreRestSiblings": false}],
		"no-void": ["error"],
		"no-with": ["error"],

		"quotes": [
			"error",
			"double"
		],

		"semi": ["error"],

		// Strict at function level (at least)
		"strict": [
			"error",
			"function"
		],

		// New features, we se "const" always if not possible use "let"
		"prefer-const": ["warn"],

		// JSDoc
		"require-jsdoc": ["warn"],
		"valid-jsdoc": [
			"warn",
			{
				prefer: {
					// Use the right string instead of the left one
					"returns": "return",
					"arg": "param",
					"argument": "param",
					"class": "constructor",
					"virtual": "abstract"
				},
				preferType: {
					// Use the right string instead of the left one
					'object': 'Object',
					'boolean': 'Boolean',
					'number': 'Number',
					'string': 'String',
					'array': 'Array'
				},

				// If and only if the function or method has a return statement (this option value does apply to constructors)
				requireReturn: false,
				requireReturnType: true,
				requireParamDescription: false,
				requireReturnDescription: false
			}
		]
	}
};<|endoftext|>


<commit_before>module.exports = {
    "parserOptions": {
        "ecmaVersion": 8
    },
    "extends": "google",
    "rules": {
        "arrow-parens": ["warn", "as-needed"],
        "camelcase": [1, {
            "properties": "never"
        }],
        "comma-dangle": ["warn", "never"],
        "curly": 0,
        "default-case": 0,
        "eol-last": 0,
        "indent": ["error", 4],
        "max-len": 0,
        "new-cap": 1,
        "no-console": 2,
        "no-extend-native": 0,
        "no-loop-func": 1,
        "no-unused-vars": 1,
        "no-var": 2,
        "no-warning-comments": 1,
        "prefer-const": 1,
        "quotes": ["error", "double"],
        "require-jsdoc": 0
    }
};<commit_msg>Fix linting rules<commit_after>module.exports = {
    "parserOptions": {
        "ecmaVersion": 8
    },
    "extends": "google",
    "env": {
        "node": true,
        "es6": true
    },
    "rules": {
        "arrow-parens": ["warn", "as-needed"],
        "camelcase": [1, {
            "properties": "never"
        }],
        "comma-dangle": ["warn", "never"],
        "curly": 0,
        "default-case": 0,
        "eol-last": 0,
        "indent": ["error", 4],
        "max-len": 0,
        "new-cap": 1,
        "no-console": 2,
        "no-extend-native": 0,
        "no-loop-func": 1,
        "no-undef": "error",
        "no-unused-vars": 1,
        "no-var": 2,
        "no-warning-comments": 1,
        "prefer-const": 1,
        "quotes": ["error", "double"],
        "require-jsdoc": 0
    }
};<|endoftext|>


<commit_before>module.exports = {
    parserOptions: {
        ecmaVersion: 6,
        sourceType: "module",
        ecmaFeatures: {
        }
    },
    rules: {
        "max-len": ["warn", {
            code: 90,
            ignoreComments: true,
        }],
        curly: ["error", "multi-line"],
        "require-jsdoc": ["warn"],
        "valid-jsdoc": ["warn"],
    }
}
<commit_msg>Add exceptions to eslintrc for JSDoc<commit_after>module.exports = {
    parserOptions: {
        ecmaVersion: 6,
        sourceType: "module",
        ecmaFeatures: {
        }
    },
    rules: {
        "max-len": ["warn", {
            code: 90,
            ignoreComments: true,
        }],
        curly: ["error", "multi-line"],
        "require-jsdoc": ["warn", {
            require: {
                FunctionDeclaration: false,
            }
        }],
        "valid-jsdoc": ["warn", {
            requireParamDescription: false,
            requireReturn: false,
            requireReturnDescription: false,
        }],
    }
}
<|endoftext|>


<commit_before>module.exports = {
  root: true,
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: 'module'
  },
  plugins: [
    'ember'
  ],
  extends: [
    'eslint:recommended',
    'plugin:ember/recommended'
  ],
  env: {
    browser: true
  },
  rules: {
  },
  overrides: [
    // node files
    {
      files: [
        'index.js',
        'testem.js',
        'ember-cli-build.js',
        'config/**/*.js',
        'tests/dummy/config/**/*.js'
      ],
      excludedFiles: [
        'app/**',
        'addon/**',
        'tests/dummy/app/**'
      ],
      parserOptions: {
        sourceType: 'script',
        ecmaVersion: 2015
      },
      env: {
        browser: false,
        node: true
      },
      plugins: ['node'],
      rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, {
        // add your custom rules and overrides for node files here
      })
    },

    // test files
    {
      files: ['tests/**/*.js'],
      excludedFiles: ['tests/dummy/**/*.js'],
      env: {
        embertest: true
      }
    }
  ]
};
<commit_msg>Change lint errors to warnings<commit_after>module.exports = {
  root: true,
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: 'module'
  },
  plugins: [
    'ember'
  ],
  extends: [
    'eslint:recommended',
    'plugin:ember/recommended'
  ],
  env: {
    browser: true
  },
  rules: {
    'no-console': 'warn'
  },
  overrides: [
    // node files
    {
      files: [
        'index.js',
        'testem.js',
        'ember-cli-build.js',
        'config/**/*.js',
        'tests/dummy/config/**/*.js'
      ],
      excludedFiles: [
        'app/**',
        'addon/**',
        'tests/dummy/app/**'
      ],
      parserOptions: {
        sourceType: 'script',
        ecmaVersion: 2015
      },
      env: {
        browser: false,
        node: true
      },
      plugins: ['node'],
      rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, {
        // add your custom rules and overrides for node files here
      })
    },

    // test files
    {
      files: ['tests/**/*.js'],
      excludedFiles: ['tests/dummy/**/*.js'],
      env: {
        embertest: true
      },
      rules: {
        'ember/new-module-imports': 'warn'
      }
    }
  ]
};
<|endoftext|>