<commit_before>/**
 * Created by huangxinghui on 2015/5/18.
 */

var $ = require('jquery');
var _ = require('underscore');
var Widget = require('../widget');
var plugin = require('../plugin');
var transition = require('../transition');
var $document = require('../document');
var TRANSITION_DURATION = 150;

var ToolTip = Widget.extend({
    options: {
        animation: true,
        placement: 'top',
        template: '

',
        trigger: 'hover',
        title: '',
        html: false,
        container: false
    },

    _create: function () {
        this.enabled = true;

        var triggers = this.options.trigger.split(' ');

        if (triggers.indexOf('click') >= 0) {
            this._on({
                'click': 'openHandler'
            });

            this._on($document, {
                'click': 'closeHandler'
            });
        }

        if (triggers.indexOf('hover') >= 0) {
            this.onUs = false;
            this.outTimeout = null;

            this._on({
                'mouseenter': 'enter',
                'mouseleave': 'leave'
            });

            this._on(this.tip(), {
                'mouseenter': 'enter',
                'mouseleave': 'leave'
            });
        }

        this.fixTitle();
    },

    openHandler: function (e) {
        this.toggle(e);
        event.preventDefault();
    },

    closeHandler: function () {
        if (!this.isOpened()) {
            return;
        }

        // Clicking inside tips
        var tips = this.tip()[0];
        if (event.target === tips || tips.contains(event.target)) {
            return;
        }

        var element = this.$element[0];
        // Clicking target
        if (event.target === element || element.contains(event.target)) {
            return;
        }

        this.hide(event);
    },

    enter: function (e) {
        this.onUs = true;
        this.show();
    },

    leave: function (e) {
        var that = this;
        this.onUs = false;

        if (typeof this.outTimeout !== 'undefined') {
            clearTimeout(this.outTimeout);
        }

        this.outTimeout = setTimeout(function () {
            if (!that.onUs)
                that.hide();
            that.outTimeout = null;
        }, 50);
    },

    show: function () {
        if (this.isOpened()) return;

        if (this.hasContent() && this.enabled) {
            this.trigger('beforeShow');

            var that = this;

            var $tip = this.tip();

            var tipId = _.uniqueId(this.widgetName);

            this.setContent();
            $tip.attr('id', tipId);
            this.$element.attr('aria-describedby', tipId);

            if (this.options.animation) $tip.addClass('fade');

            var placement = typeof this.options.placement == 'function' ?
                this.options.placement.call(this, $tip[0], this.$element[0]) :
                this.options.placement;

            var autoToken = /\s?auto?\s?/i;
            var autoPlace = autoToken.test(placement);
            if (autoPlace) placement = placement.replace(autoToken, '') || 'top';

            $tip
                .detach()
                .css({top: 0, left: 0, display: 'block'})
                .addClass(placement);

            this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element);

            var pos = this.getPosition();
            var actualWidth = $tip[0].offsetWidth;
            var actualHeight = $tip[0].offsetHeight;

            if (autoPlace) {
                var orgPlacement = placement;
                var $container = this.options.container ? $(this.options.container) : this.$element.parent();
                var containerDim = this.getPosition($container);

                placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' :
                    placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' :
                        placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' :
                            placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' :
                                placement;

                $tip
                    .removeClass(orgPlacement)
                    .addClass(placement);
            }

            var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight);

            this.applyPlacement(calculatedOffset, placement);

            var complete = function () {
                that.trigger('show');
            };

            $.support.transition && this.$tip.hasClass('fade') ?
                $tip
                    .one(transition, complete)
                    .emulateTransitionEnd(TRANSITION_DURATION) :
                complete();
        }
    },

    applyPlacement: function (offset, placement) {
        var $tip = this.tip();
        var height = $tip[0].offsetHeight;

        // manually read margins because getBoundingClientRect includes difference
        var marginTop = parseInt($tip.css('margin-top'), 10);
        var marginLeft = parseInt($tip.css('margin-left'), 10);

        // we must check for NaN for ie 8/9
        if (isNaN(marginTop))  marginTop = 0;
        if (isNaN(marginLeft)) marginLeft = 0;

        offset.top = offset.top + marginTop;
        offset.left = offset.left + marginLeft;

        // $.fn.offset doesn't round pixel values
        // so we use setOffset directly with our own function B-0
        $.offset.setOffset($tip[0], $.extend({
            using: function (props) {
                $tip.css({
                    top: Math.round(props.top),
                    left: Math.round(props.left)
                })
            }
        }, offset), 0);

        $tip.addClass('in');

        // check to see if placing tip in new offset caused the tip to resize itself
        var actualHeight = $tip[0].offsetHeight;

        if (/top/.test(placement) && actualHeight != height) {
            offset.top = offset.top + height - actualHeight
        }

        $tip.offset(offset);
    },

    setContent: function () {
        var $tip = this.tip();
        var title = this.getTitle();

        $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title);
        $tip.removeClass('fade in top bottom left right');
    },

    hide: function () {
        if (!this.isOpened()) return;

        var that = this;
        var $tip = this.tip();

        function complete() {
            $tip.detach();
            that.$element
                .removeAttr('aria-describedby');
            that.trigger('hide');
        }

        this.trigger('beforeHide');

        $tip.removeClass('in');

        $.support.transition && this.$tip.hasClass('fade') ?
            $tip
                .one(transition.eventType, complete)
                .emulateTransitionEnd(TRANSITION_DURATION) :
            complete();

        return this;
    },

    fixTitle: function () {
        var $e = this.$element;
        if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
            $e.attr('data-original-title', $e.attr('title') || '').attr('title', '');
        }
    },

    hasContent: function () {
        return this.getTitle();
    },

    getPosition: function ($element) {
        $element = $element || this.$element;

        var el = $element[0];
        var isBody = el.tagName == 'BODY';

        var elRect = el.getBoundingClientRect();
        if (elRect.width == null) {
            // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
            elRect = $.extend({}, elRect, {width: elRect.right - elRect.left, height: elRect.bottom - elRect.top})
        }
        var elOffset = isBody ? {top: 0, left: 0} : $element.offset();
        var scroll = {scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop()}
        var outerDims = isBody ? {width: $(window).width(), height: $(window).height()} : null;

        return $.extend({}, elRect, scroll, outerDims, elOffset);
    },

    getCalculatedOffset: function (placement, pos, actualWidth, actualHeight) {
        var offset;
        switch (placement) {
            case 'bottom':
                offset = {
                    top: pos.top + pos.height,
                    left: pos.left + pos.width / 2 - actualWidth / 2
                };
                break;
            case 'top':
                offset = {
                    top: pos.top - actualHeight,
                    left: pos.left + pos.width / 2 - actualWidth / 2
                };
                break;
            case 'left':
                offset = {
                    top: pos.top + pos.height / 2 - actualHeight / 2,
                    left: pos.left - actualWidth
                };
                break;
            case 'right':
                offset = {
                    top: pos.top + pos.height / 2 - actualHeight / 2,
                    left: pos.left + pos.width
                };
                break;
            case 'bottom-left':
                offset = {
                    top: pos.top + pos.height,
                    left: pos.left + pos.width - actualWidth
                };
                break;
            case 'bottom-right':
                offset = {
                    top: pos.top + pos.height,
                    left: pos.left
                };
                break;
            case 'top-left':
                offset = {
                    top: pos.top - actualHeight,
                    left: pos.left + pos.width - actualWidth
                };
                break;
            case 'top-right':
                offset = {
                    top: pos.top - actualHeight,
                    left: pos.left
                };
                break;
        }

        return offset;
    },

    getTitle: function () {
        var title;
        var $e = this.$element;
        var o = this.options;

        title = $e.attr('data-original-title')
        || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title);

        return title;
    },

    tip: function () {
        if (!this.$tip) {
            this.$tip = $(this.options.template);
        }
        return this.$tip;
    },

    arrow: function () {
        return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'));
    },

    enable: function () {
        this.enabled = true;
    },

    disable: function () {
        this.enabled = false;
    },

    toggle: function (e) {
        this.isOpened() ? this.leave(e) : this.enter(e);
    },

    isOpened: function () {
        return this.tip().hasClass('in');
    }
});

plugin('tooltip', ToolTip);

module.exports = ToolTip;<commit_msg>change tooltip toggle<commit_after>/**
 * Created by huangxinghui on 2015/5/18.
 */

var $ = require('jquery');
var _ = require('underscore');
var Widget = require('../widget');
var plugin = require('../plugin');
var transition = require('../transition');
var $document = require('../document');
var TRANSITION_DURATION = 150;

var ToolTip = Widget.extend({
    options: {
        animation: true,
        placement: 'top',
        template: '

',
        trigger: 'hover',
        title: '',
        html: false,
        container: false
    },

    _create: function () {
        this.enabled = true;

        var triggers = this.options.trigger.split(' ');

        if (triggers.indexOf('click') >= 0) {
            this._on({
                'click': 'openHandler'
            });

            this._on($document, {
                'click': 'closeHandler'
            });
        }

        if (triggers.indexOf('hover') >= 0) {
            this.onUs = false;
            this.outTimeout = null;

            this._on({
                'mouseenter': 'enter',
                'mouseleave': 'leave'
            });

            this._on(this.tip(), {
                'mouseenter': 'enter',
                'mouseleave': 'leave'
            });
        }

        this.fixTitle();
    },

    openHandler: function (e) {
        this.toggle(e);
        event.preventDefault();
    },

    closeHandler: function () {
        if (!this.isOpened()) {
            return;
        }

        // Clicking inside tips
        var tips = this.tip()[0];
        if (event.target === tips || tips.contains(event.target)) {
            return;
        }

        var element = this.$element[0];
        // Clicking target
        if (event.target === element || element.contains(event.target)) {
            return;
        }

        this.hide();
    },

    enter: function (e) {
        this.onUs = true;
        this.show();
    },

    leave: function (e) {
        var that = this;
        this.onUs = false;

        if (typeof this.outTimeout !== 'undefined') {
            clearTimeout(this.outTimeout);
        }

        this.outTimeout = setTimeout(function () {
            if (!that.onUs)
                that.hide();
            that.outTimeout = null;
        }, 50);
    },

    show: function () {
        if (this.isOpened()) return;

        if (this.hasContent() && this.enabled) {
            this.trigger('beforeShow');

            var that = this;

            var $tip = this.tip();

            var tipId = _.uniqueId(this.widgetName);

            this.setContent();
            $tip.attr('id', tipId);
            this.$element.attr('aria-describedby', tipId);

            if (this.options.animation) $tip.addClass('fade');

            var placement = typeof this.options.placement == 'function' ?
                this.options.placement.call(this, $tip[0], this.$element[0]) :
                this.options.placement;

            var autoToken = /\s?auto?\s?/i;
            var autoPlace = autoToken.test(placement);
            if (autoPlace) placement = placement.replace(autoToken, '') || 'top';

            $tip
                .detach()
                .css({top: 0, left: 0, display: 'block'})
                .addClass(placement);

            this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element);

            var pos = this.getPosition();
            var actualWidth = $tip[0].offsetWidth;
            var actualHeight = $tip[0].offsetHeight;

            if (autoPlace) {
                var orgPlacement = placement;
                var $container = this.options.container ? $(this.options.container) : this.$element.parent();
                var containerDim = this.getPosition($container);

                placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' :
                    placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' :
                        placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' :
                            placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' :
                                placement;

                $tip
                    .removeClass(orgPlacement)
                    .addClass(placement);
            }

            var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight);

            this.applyPlacement(calculatedOffset, placement);

            var complete = function () {
                that.trigger('show');
            };

            $.support.transition && this.$tip.hasClass('fade') ?
                $tip
                    .one(transition, complete)
                    .emulateTransitionEnd(TRANSITION_DURATION) :
                complete();
        }
    },

    applyPlacement: function (offset, placement) {
        var $tip = this.tip();
        var height = $tip[0].offsetHeight;

        // manually read margins because getBoundingClientRect includes difference
        var marginTop = parseInt($tip.css('margin-top'), 10);
        var marginLeft = parseInt($tip.css('margin-left'), 10);

        // we must check for NaN for ie 8/9
        if (isNaN(marginTop))  marginTop = 0;
        if (isNaN(marginLeft)) marginLeft = 0;

        offset.top = offset.top + marginTop;
        offset.left = offset.left + marginLeft;

        // $.fn.offset doesn't round pixel values
        // so we use setOffset directly with our own function B-0
        $.offset.setOffset($tip[0], $.extend({
            using: function (props) {
                $tip.css({
                    top: Math.round(props.top),
                    left: Math.round(props.left)
                })
            }
        }, offset), 0);

        $tip.addClass('in');

        // check to see if placing tip in new offset caused the tip to resize itself
        var actualHeight = $tip[0].offsetHeight;

        if (/top/.test(placement) && actualHeight != height) {
            offset.top = offset.top + height - actualHeight
        }

        $tip.offset(offset);
    },

    setContent: function () {
        var $tip = this.tip();
        var title = this.getTitle();

        $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title);
        $tip.removeClass('fade in top bottom left right');
    },

    hide: function () {
        if (!this.isOpened()) return;

        var that = this;
        var $tip = this.tip();

        function complete() {
            $tip.detach();
            that.$element
                .removeAttr('aria-describedby');
            that.trigger('hide');
        }

        this.trigger('beforeHide');

        $tip.removeClass('in');

        $.support.transition && this.$tip.hasClass('fade') ?
            $tip
                .one(transition.eventType, complete)
                .emulateTransitionEnd(TRANSITION_DURATION) :
            complete();

        return this;
    },

    fixTitle: function () {
        var $e = this.$element;
        if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
            $e.attr('data-original-title', $e.attr('title') || '').attr('title', '');
        }
    },

    hasContent: function () {
        return this.getTitle();
    },

    getPosition: function ($element) {
        $element = $element || this.$element;

        var el = $element[0];
        var isBody = el.tagName == 'BODY';

        var elRect = el.getBoundingClientRect();
        if (elRect.width == null) {
            // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
            elRect = $.extend({}, elRect, {width: elRect.right - elRect.left, height: elRect.bottom - elRect.top})
        }
        var elOffset = isBody ? {top: 0, left: 0} : $element.offset();
        var scroll = {scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop()}
        var outerDims = isBody ? {width: $(window).width(), height: $(window).height()} : null;

        return $.extend({}, elRect, scroll, outerDims, elOffset);
    },

    getCalculatedOffset: function (placement, pos, actualWidth, actualHeight) {
        var offset;
        switch (placement) {
            case 'bottom':
                offset = {
                    top: pos.top + pos.height,
                    left: pos.left + pos.width / 2 - actualWidth / 2
                };
                break;
            case 'top':
                offset = {
                    top: pos.top - actualHeight,
                    left: pos.left + pos.width / 2 - actualWidth / 2
                };
                break;
            case 'left':
                offset = {
                    top: pos.top + pos.height / 2 - actualHeight / 2,
                    left: pos.left - actualWidth
                };
                break;
            case 'right':
                offset = {
                    top: pos.top + pos.height / 2 - actualHeight / 2,
                    left: pos.left + pos.width
                };
                break;
            case 'bottom-left':
                offset = {
                    top: pos.top + pos.height,
                    left: pos.left + pos.width - actualWidth
                };
                break;
            case 'bottom-right':
                offset = {
                    top: pos.top + pos.height,
                    left: pos.left
                };
                break;
            case 'top-left':
                offset = {
                    top: pos.top - actualHeight,
                    left: pos.left + pos.width - actualWidth
                };
                break;
            case 'top-right':
                offset = {
                    top: pos.top - actualHeight,
                    left: pos.left
                };
                break;
        }

        return offset;
    },

    getTitle: function () {
        var title;
        var $e = this.$element;
        var o = this.options;

        title = $e.attr('data-original-title')
        || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title);

        return title;
    },

    tip: function () {
        if (!this.$tip) {
            this.$tip = $(this.options.template);
        }
        return this.$tip;
    },

    arrow: function () {
        return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'));
    },

    enable: function () {
        this.enabled = true;
    },

    disable: function () {
        this.enabled = false;
    },

    toggle: function (e) {
        this.isOpened() ? this.hide() : this.show();
    },

    isOpened: function () {
        return this.tip().hasClass('in');
    }
});

plugin('tooltip', ToolTip);

module.exports = ToolTip;<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { search } from '../actions/user'
import { setSearchInput, searchAction } from '../actions/search'
import NightlifeButton from './NightlifeButton'

class TopBar extends React.Component {
  constructor(props){
    super(props)
    this.onSubmit = this.onSubmit.bind(this)
    this.setInputUpdate = this.setInputUpdate.bind(this)
  }
  onSubmit(event) {
    event.preventDefault()
    this.props.search(this.props.locationText, this.props.token)
  }

  setInputUpdate(event) {
    this.props.setLocationInput(event.target.value)
  }

  render() {
    return (

          Nightlife Bar Attendance

          See which bars are popular tonight!

          <form onSubmit={this.onSubmit}>

              <input
                id="bar-search"
                className="nightlife-input"
                placeholder="Location"
                onChange={this.setInputUpdate}
              />

              <NightlifeButton onClick={this.onSubmit}>
                Search
              </NightlifeButton>

          </form>

    )
  }
}

TopBar.propTypes = {
  search: PropTypes.func,
  setLocationInput: PropTypes.func,
  locationText: PropTypes.string
}

const mapDispatchToProps = (dispatch) => {
  return {
    search: (location, token) => dispatch(searchAction(location, token)),
    setLocationInput: (location) => dispatch(setSearchInput(location)),
  }
}

const mapStateToProps = (state) => {
  return {
    locationText: state.search.locationInput,
    token: state.userLogin.token
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(TopBar)
<commit_msg>removed broken import<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { setSearchInput, searchAction } from '../actions/search'
import NightlifeButton from './NightlifeButton'

class TopBar extends React.Component {
  constructor(props){
    super(props)
    this.onSubmit = this.onSubmit.bind(this)
    this.setInputUpdate = this.setInputUpdate.bind(this)
  }
  onSubmit(event) {
    event.preventDefault()
    this.props.search(this.props.locationText, this.props.token)
  }

  setInputUpdate(event) {
    this.props.setLocationInput(event.target.value)
  }

  render() {
    return (

          Nightlife Bar Attendance

          See which bars are popular tonight!

          <form onSubmit={this.onSubmit}>

              <input
                id="bar-search"
                className="nightlife-input"
                placeholder="Location"
                onChange={this.setInputUpdate}
              />

              <NightlifeButton onClick={this.onSubmit}>
                Search
              </NightlifeButton>

          </form>

    )
  }
}

TopBar.propTypes = {
  search: PropTypes.func,
  setLocationInput: PropTypes.func,
  locationText: PropTypes.string
}

const mapDispatchToProps = (dispatch) => {
  return {
    search: (location, token) => dispatch(searchAction(location, token)),
    setLocationInput: (location) => dispatch(setSearchInput(location)),
  }
}

const mapStateToProps = (state) => {
  return {
    locationText: state.search.locationInput,
    token: state.userLogin.token
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(TopBar)
<|endoftext|>


<commit_before>import mediumZoom from 'medium-zoom';

export default function () {
  mediumZoom('.container img', {
    margin: 24,
  });
}
<commit_msg>Increase zoom threshold<commit_after>import mediumZoom from 'medium-zoom';

export default function () {
  return mediumZoom('.container img', {
    margin: 24,
    scrollOffset: 60,
  });
}
<|endoftext|>


<commit_before>import Button from './Button'

const theme = {
  default: {
    button: {
      className: 'Button--default'
    },
    spinner: {
      bgcolor: '#ddd',
      forecolor: 'transparent'
    }
  },
  primary: {
    button: {
      className: 'Button--primary'
    },
    spinner: {
      bgcolor: 'rgba(255, 255, 255, .4)',
      forecolor: '#fff'
    }
  },
  caution: {
    button: {
      className: 'Button--caution'
    },
    spinner: {
      bgcolor: 'rgba(255, 255, 255, .4)',
      forecolor: '#fff'
    }
  }
}

;(opt => {
  Object.keys(opt).forEach(name => {
    Button[name] = opt[name]
  })
})({
  props: {
    // 字体大小
    fontSize: {
      type: String,
      default: '12px'
    },
    // 宽
    width: {
      type: String,
      default: ''
    },
    // 高
    height: {
      type: String,
      default: ''
    },
    // 圆角
    radius: {
      type: String,
      default: '3px'
    },
    // 主题
    theme: {
      type: String,
      default: 'default'
    },
    // 禁用
    disabled: undefined,
    // loading
    loading: {
      type: Boolean,
      default: false
    }
  },

  computed: {
    classes() {
      return {
        Button: true,
        disabled: typeof this.disabled !== 'undefined' || this.loading,
        ['Button--' + this.theme]: true
      }
    },

    style() {
      return {
        width: this.width,
        height: this.height,
        'border-radius': this.radius,
        'font-size': this.fontSize
      }
    },

    size() {
      return parseInt(this.fontSize) + 1
    },

    bgcolor() {
      const config = theme[this.theme]
      return config.spinner.bgcolor
    },

    forecolor() {
      const config = theme[this.theme]
      return config.spinner.forecolor
    }
  },

  methods: {
    handleClick() {
      if (!this.loading) {
        this.$emit('click')
      }
    }
  }
})

export function config(name, conf) {
  theme[name] = conf
}

export default { component: Button, config }
<commit_msg>feat(Button): redefine the disabled prop as a Boolean type<commit_after>import Button from './Button'

const theme = {
  default: {
    button: {
      className: 'Button--default'
    },
    spinner: {
      bgcolor: '#ddd',
      forecolor: 'transparent'
    }
  },
  primary: {
    button: {
      className: 'Button--primary'
    },
    spinner: {
      bgcolor: 'rgba(255, 255, 255, .4)',
      forecolor: '#fff'
    }
  },
  caution: {
    button: {
      className: 'Button--caution'
    },
    spinner: {
      bgcolor: 'rgba(255, 255, 255, .4)',
      forecolor: '#fff'
    }
  }
}

;(opt => {
  Object.keys(opt).forEach(name => {
    Button[name] = opt[name]
  })
})({
  props: {
    // 字体大小
    fontSize: {
      type: String,
      default: '12px'
    },
    // 宽
    width: {
      type: String,
      default: ''
    },
    // 高
    height: {
      type: String,
      default: ''
    },
    // 圆角
    radius: {
      type: String,
      default: '3px'
    },
    // 主题
    theme: {
      type: String,
      default: 'default'
    },
    // 禁用
    disabled: {
      type: Boolean,
      default: false
    },
    // loading
    loading: {
      type: Boolean,
      default: false
    }
  },

  computed: {
    classes() {
      return {
        Button: true,
        disabled: this.disabled || this.loading,
        ['Button--' + this.theme]: true
      }
    },

    style() {
      return {
        width: this.width,
        height: this.height,
        'border-radius': this.radius,
        'font-size': this.fontSize
      }
    },

    size() {
      return parseInt(this.fontSize) + 1
    },

    bgcolor() {
      const config = theme[this.theme]
      return config.spinner.bgcolor
    },

    forecolor() {
      const config = theme[this.theme]
      return config.spinner.forecolor
    }
  },

  methods: {
    handleClick() {
      if (!this.loading && !this.disabled) {
        this.$emit('click')
      }
    }
  }
})

export function config(name, conf) {
  theme[name] = conf
}

export default { component: Button, config }
<|endoftext|>


<commit_before>const { authenticate } = require('@feathersjs/authentication');

const globalHooks = require('../../../hooks');
const { canRead } = require('../utils/filePermissionHelper');

const restrictToCurrentUser = (hook) => {
	const { params: { account: { userId } }, result: { data: files } } = hook;
	const permissionPromises = files.map((f) => canRead(userId, f)
		.then(() => f)
		.catch(() => undefined));

	return Promise.all(permissionPromises)
		.then((allowedFiles) => {
			hook.result.data = allowedFiles;
			return hook;
		});
};

exports.before = {
	all: [authenticate('jwt')],
	find: [globalHooks.hasPermission('FILESTORAGE_VIEW')],
	get: [globalHooks.hasPermission('FILESTORAGE_VIEW')],
	create: [globalHooks.hasPermission('FILESTORAGE_CREATE')],
	update: [globalHooks.hasPermission('FILESTORAGE_EDIT')],
	patch: [globalHooks.hasPermission('FILESTORAGE_EDIT')],
	remove: [globalHooks.hasPermission('FILESTORAGE_REMOVE')],
};

exports.after = {
	all: [],
	find: [restrictToCurrentUser],
	get: [],
	create: [],
	update: [],
	patch: [],
	remove: [],
};
<commit_msg>Remove request tokens from service responses<commit_after>const { authenticate } = require('@feathersjs/authentication');
const { discard } = require('feathers-hooks-common');

const globalHooks = require('../../../hooks');
const { canRead } = require('../utils/filePermissionHelper');

const restrictToCurrentUser = (hook) => {
	const { params: { account: { userId } }, result: { data: files } } = hook;
	const permissionPromises = files.map((f) => canRead(userId, f)
		.then(() => f)
		.catch(() => undefined));

	return Promise.all(permissionPromises)
		.then((allowedFiles) => {
			hook.result.data = allowedFiles;
			return hook;
		});
};

exports.before = {
	all: [authenticate('jwt')],
	find: [globalHooks.hasPermission('FILESTORAGE_VIEW')],
	get: [globalHooks.hasPermission('FILESTORAGE_VIEW')],
	create: [globalHooks.hasPermission('FILESTORAGE_CREATE')],
	update: [globalHooks.hasPermission('FILESTORAGE_EDIT')],
	patch: [globalHooks.hasPermission('FILESTORAGE_EDIT')],
	remove: [globalHooks.hasPermission('FILESTORAGE_REMOVE')],
};

exports.after = {
	all: [discard('securityCheck.requestToken', 'thumbnailRequestToken')],
	find: [restrictToCurrentUser],
	get: [],
	create: [],
	update: [],
	patch: [],
	remove: [],
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Array of categories allowed to be scrobbled.
 * @type {Array}
 */
const allowedCategories = [];

/**
 * "Video Id=Category" map.
 * @type {Map}
 */
const categoryCache = new Map();

/**
 * CSS selector of video element. It's common for both players.
 * @type {String}
 */
const videoSelector = '.html5-main-video';

const chapterNameSelector = '.html5-video-player .ytp-chapter-title-content';
const videoTitleSelector = '.html5-video-player .ytp-title-link';
const channelNameSelector = '#top-row .ytd-channel-name a';
const videoDescriptionSelector = '#meta-contents #description';

// Dummy category indicates an actual category is being fetched
const categoryPending = 'YT_DUMMY_CATEGORY_PENDING';
// Fallback value in case when we cannot fetch a category.
const categoryUnknown = 'YT_DUMMY_CATEGORY_UNKNOWN';

const categoryMusic = 'Music';
const categoryEntertainment = 'Entertainment';

let currentVideoDescription = null;
let artistTrackFromDescription = null;

const trackInfoGetters = [
	getTrackInfoFromDescription,
	getTrackInfoFromChapters,
	getTrackInfoFromTitle,
];

readConnectorOptions();
setupEventListener();

Connector.playerSelector = '#content';

Connector.getTrackInfo = () => {
	let trackInfo = null;

	for (const getter of trackInfoGetters) {
		trackInfo = getter();
		if (Util.isArtistTrackEmpty(trackInfo)) {
			continue;
		}

		return trackInfo;
	}

	return trackInfo;
};

Connector.getTimeInfo = () => {
	const videoElement = document.querySelector(videoSelector);
	if (videoElement && !areChaptersAvailable()) {
		const { currentTime, duration } = videoElement;

		return { currentTime, duration };
	}

	return null;
};

Connector.isPlaying = () => {
	return $('.html5-video-player').hasClass('playing-mode');
};

Connector.getUniqueID = () => {
	if (areChaptersAvailable()) {
		return null;
	}

	return getVideoId();
};

Connector.isScrobblingAllowed = () => {
	if ($('.ad-showing').length > 0) {
		return false;
	}

	// Workaround to prevent scrobbling the video opened in a background tab.
	const videoElement = document.querySelector(videoSelector);
	if (videoElement && videoElement.currentTime < 1) {
		return false;
	}

	if (allowedCategories.length === 0) {
		return true;
	}

	const videoCategory = getVideoCategory();
	if (!videoCategory) {
		return false;
	}

	if (videoCategory === categoryUnknown) {
		return true;
	}

	return allowedCategories.includes(videoCategory);
};

Connector.applyFilter(MetadataFilter.getYoutubeFilter());

function setupEventListener() {
	$(videoSelector).on('timeupdate', Connector.onStateChanged);
}

function areChaptersAvailable() {
	return Util.getTextFromSelectors(chapterNameSelector);
}

function getVideoId() {
	/*
	 * ytd-watch-flexy element contains ID of a first played video
	 * if the miniplayer is visible, so we should check
	 * if URL of a current video in miniplayer is accessible.
	 */
	const miniPlayerVideoUrl = Util.getAttrFromSelectors(
		'ytd-miniplayer[active] [selected] a',
		'href'
	);
	if (miniPlayerVideoUrl) {
		return Util.getYtVideoIdFromUrl(miniPlayerVideoUrl);
	}

	return Util.getAttrFromSelectors('ytd-watch-flexy', 'video-id');
}

function getVideoCategory() {
	const videoId = getVideoId();

	if (!videoId) {
		return null;
	}

	if (categoryCache.has(videoId)) {
		return categoryCache.get(videoId);
	}

	/*
	 * Add dummy category for videoId to prevent
	 * fetching category multiple times.
	 */
	categoryCache.set(videoId, categoryPending);

	fetchCategoryName(videoId)
		.then((category) => {
			console.log(`Fetched category for ${videoId}: ${category}`);
			categoryCache.set(videoId, category);
		})
		.catch((err) => {
			Util.debugLog(
				`Failed to fetch category for ${videoId}: ${err}`,
				'warn'
			);
			categoryCache.set(videoId, categoryUnknown);
		});

	return null;
}

async function fetchCategoryName(videoId) {
	const videoUrl = `https://youtube.com/watch?v=${videoId}`;

	try {
		/*
		 * Category info is not available via DOM API, so we should search it
		 * in a page source.
		 *
		 * But we cannot use `document.documentElement.outerHtml`, since it
		 * is not updated on video change.
		 */
		const response = await fetch(videoUrl);
		const rawHtml = await response.text();

		const categoryMatch = rawHtml.match(/"category":"(.+?)"/);
		if (categoryMatch !== null) {
			return categoryMatch[1];
		}
	} catch (e) {
		// Do nothing
	}

	return categoryUnknown;
}

/**
 * Asynchronously read connector options.
 */
async function readConnectorOptions() {
	if (await Util.getOption('YouTube', 'scrobbleMusicOnly')) {
		allowedCategories.push(categoryMusic);
	}
	if (await Util.getOption('YouTube', 'scrobbleEntertainmentOnly')) {
		allowedCategories.push(categoryEntertainment);
	}
	Util.debugLog(`Allowed categories: ${allowedCategories.join(', ')}`);
}

function getVideoDescription() {
	return Util.getTextFromSelectors(videoDescriptionSelector);
}

function getTrackInfoFromDescription() {
	const description = getVideoDescription();
	if (currentVideoDescription === description) {
		return artistTrackFromDescription;
	}

	currentVideoDescription = description;
	artistTrackFromDescription = Util.parseYtVideoDescription(description);

	return artistTrackFromDescription;
}

function getTrackInfoFromChapters() {
	return Util.splitArtistTrack(
		Util.getTextFromSelectors(chapterNameSelector)
	);
}

function getTrackInfoFromTitle() {
	let { artist, track } = Util.processYtVideoTitle(
		Util.getTextFromSelectors(videoTitleSelector)
	);
	if (!artist) {
		artist = Util.getTextFromSelectors(channelNameSelector);
	}

	return { artist, track };
}
<commit_msg>Use `Util.debugLog` in youtube connector<commit_after>'use strict';

/**
 * Array of categories allowed to be scrobbled.
 * @type {Array}
 */
const allowedCategories = [];

/**
 * "Video Id=Category" map.
 * @type {Map}
 */
const categoryCache = new Map();

/**
 * CSS selector of video element. It's common for both players.
 * @type {String}
 */
const videoSelector = '.html5-main-video';

const chapterNameSelector = '.html5-video-player .ytp-chapter-title-content';
const videoTitleSelector = '.html5-video-player .ytp-title-link';
const channelNameSelector = '#top-row .ytd-channel-name a';
const videoDescriptionSelector = '#meta-contents #description';

// Dummy category indicates an actual category is being fetched
const categoryPending = 'YT_DUMMY_CATEGORY_PENDING';
// Fallback value in case when we cannot fetch a category.
const categoryUnknown = 'YT_DUMMY_CATEGORY_UNKNOWN';

const categoryMusic = 'Music';
const categoryEntertainment = 'Entertainment';

let currentVideoDescription = null;
let artistTrackFromDescription = null;

const trackInfoGetters = [
	getTrackInfoFromDescription,
	getTrackInfoFromChapters,
	getTrackInfoFromTitle,
];

readConnectorOptions();
setupEventListener();

Connector.playerSelector = '#content';

Connector.getTrackInfo = () => {
	let trackInfo = null;

	for (const getter of trackInfoGetters) {
		trackInfo = getter();
		if (Util.isArtistTrackEmpty(trackInfo)) {
			continue;
		}

		return trackInfo;
	}

	return trackInfo;
};

Connector.getTimeInfo = () => {
	const videoElement = document.querySelector(videoSelector);
	if (videoElement && !areChaptersAvailable()) {
		const { currentTime, duration } = videoElement;

		return { currentTime, duration };
	}

	return null;
};

Connector.isPlaying = () => {
	return $('.html5-video-player').hasClass('playing-mode');
};

Connector.getUniqueID = () => {
	if (areChaptersAvailable()) {
		return null;
	}

	return getVideoId();
};

Connector.isScrobblingAllowed = () => {
	if ($('.ad-showing').length > 0) {
		return false;
	}

	// Workaround to prevent scrobbling the video opened in a background tab.
	const videoElement = document.querySelector(videoSelector);
	if (videoElement && videoElement.currentTime < 1) {
		return false;
	}

	if (allowedCategories.length === 0) {
		return true;
	}

	const videoCategory = getVideoCategory();
	if (!videoCategory) {
		return false;
	}

	if (videoCategory === categoryUnknown) {
		return true;
	}

	return allowedCategories.includes(videoCategory);
};

Connector.applyFilter(MetadataFilter.getYoutubeFilter());

function setupEventListener() {
	$(videoSelector).on('timeupdate', Connector.onStateChanged);
}

function areChaptersAvailable() {
	return Util.getTextFromSelectors(chapterNameSelector);
}

function getVideoId() {
	/*
	 * ytd-watch-flexy element contains ID of a first played video
	 * if the miniplayer is visible, so we should check
	 * if URL of a current video in miniplayer is accessible.
	 */
	const miniPlayerVideoUrl = Util.getAttrFromSelectors(
		'ytd-miniplayer[active] [selected] a',
		'href'
	);
	if (miniPlayerVideoUrl) {
		return Util.getYtVideoIdFromUrl(miniPlayerVideoUrl);
	}

	return Util.getAttrFromSelectors('ytd-watch-flexy', 'video-id');
}

function getVideoCategory() {
	const videoId = getVideoId();

	if (!videoId) {
		return null;
	}

	if (categoryCache.has(videoId)) {
		return categoryCache.get(videoId);
	}

	/*
	 * Add dummy category for videoId to prevent
	 * fetching category multiple times.
	 */
	categoryCache.set(videoId, categoryPending);

	fetchCategoryName(videoId)
		.then((category) => {
			Util.debugLog(`Fetched category for ${videoId}: ${category}`);
			categoryCache.set(videoId, category);
		})
		.catch((err) => {
			Util.debugLog(
				`Failed to fetch category for ${videoId}: ${err}`,
				'warn'
			);
			categoryCache.set(videoId, categoryUnknown);
		});

	return null;
}

async function fetchCategoryName(videoId) {
	const videoUrl = `https://youtube.com/watch?v=${videoId}`;

	try {
		/*
		 * Category info is not available via DOM API, so we should search it
		 * in a page source.
		 *
		 * But we cannot use `document.documentElement.outerHtml`, since it
		 * is not updated on video change.
		 */
		const response = await fetch(videoUrl);
		const rawHtml = await response.text();

		const categoryMatch = rawHtml.match(/"category":"(.+?)"/);
		if (categoryMatch !== null) {
			return categoryMatch[1];
		}
	} catch (e) {
		// Do nothing
	}

	return categoryUnknown;
}

/**
 * Asynchronously read connector options.
 */
async function readConnectorOptions() {
	if (await Util.getOption('YouTube', 'scrobbleMusicOnly')) {
		allowedCategories.push(categoryMusic);
	}
	if (await Util.getOption('YouTube', 'scrobbleEntertainmentOnly')) {
		allowedCategories.push(categoryEntertainment);
	}
	Util.debugLog(`Allowed categories: ${allowedCategories.join(', ')}`);
}

function getVideoDescription() {
	return Util.getTextFromSelectors(videoDescriptionSelector);
}

function getTrackInfoFromDescription() {
	const description = getVideoDescription();
	if (currentVideoDescription === description) {
		return artistTrackFromDescription;
	}

	currentVideoDescription = description;
	artistTrackFromDescription = Util.parseYtVideoDescription(description);

	return artistTrackFromDescription;
}

function getTrackInfoFromChapters() {
	return Util.splitArtistTrack(
		Util.getTextFromSelectors(chapterNameSelector)
	);
}

function getTrackInfoFromTitle() {
	let { artist, track } = Util.processYtVideoTitle(
		Util.getTextFromSelectors(videoTitleSelector)
	);
	if (!artist) {
		artist = Util.getTextFromSelectors(channelNameSelector);
	}

	return { artist, track };
}
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { IndexLink } from 'react-router';
import { LinkContainer } from 'react-router-bootstrap';
import Navbar from 'react-bootstrap/lib/Navbar';
import Nav from 'react-bootstrap/lib/Nav';
import NavItem from 'react-bootstrap/lib/NavItem';
import Helmet from 'react-helmet';
import { isLoaded as isInfoLoaded, load as loadInfo } from 'redux/modules/info';
import { isLoaded as isAuthLoaded, load as loadAuth, logout } from 'redux/modules/auth';
import { InfoBar } from 'components';
import { push } from 'react-router-redux';
import config from '../../config';
import { asyncConnect } from 'redux-async-connect';
import cookie from 'react-cookie';

import { getUser } from '../../redux/actions/getUserActions';

@asyncConnect([{
  promise: ({store: {dispatch, getState}}) => {
    const promises = [];

    if (!isInfoLoaded(getState())) {
      promises.push(dispatch(loadInfo()));
    }
    if (!isAuthLoaded(getState())) {
      promises.push(dispatch(loadAuth()));
    }

    return Promise.all(promises);
  }
}])

@connect((store) => {
  return {
    registerNewUserState: store.registerNewUser.user,
    getUserState: store.getUser.user,
  };
})

export default class App extends Component {
    state = {
      //userEmail: cookie.load('ck_email'),
      navExpanded: false
    }

    static propTypes = {
      children: PropTypes.object.isRequired,
      user: PropTypes.object,
      logout: PropTypes.func.isRequired,
      pushState: PropTypes.func.isRequired
    };

    static contextTypes = {
      store: PropTypes.object.isRequired
    };

    componentWillMount() {
      console.log("component componentDidMount ----------------");
      this.props.dispatch(getUser(cookie.load('ck_activation'), cookie.load('ck_email'), cookie.load('ck_pw'), cookie.load('ck_uuid')));
    }

    componentWillReceiveProps(nextProps) {
      console.log("component componentWillReceiveProps ----------------");
      if (!this.props.user && nextProps.user) {
        // login
        this.props.pushState('/loginSuccess');
      } else if (this.props.user && !nextProps.user) {
        // logout
        this.props.pushState('/');
      }
    }

    onNavItemClick = () => {
      this.setState({ navExpanded: false });
    }
    onNavbarToggle = () => {
      this.setState({ navExpanded: ! this.state.navExpanded });
    }
    handleLogout = (event) => {
      event.preventDefault();
      this.props.logout();
    }

    render() {
      const styles = require('./App.scss');
      const {userEmail} = null;
      const { registerNewUserState, getUserState } = this.props;

      /*var userIsRegistered = 0;
      if(userEmail !== undefined){
        userIsRegistered = 1;
      } else{
        userIsRegistered = 2;
      }
      if(registerNewUserState.email !== null){
        userIsRegistered = 1;
      }
      if(getUserState.activation !== null){
        userIsRegistered = 1;
      }*/

      //console.log('userIsRegistered: ' + userIsRegistered + ' ,cookie.load(ck_email): ' + userEmail + ', registerNewUserState.email: '+registerNewUserState.email);

      return (

          <Helmet {...config.app.head}/>

          <Navbar fixedTop expanded={ this.state.navExpanded } onToggle={ this.onNavbarToggle }>
            <Navbar.Header>
              <Navbar.Brand>
                <IndexLink to="/" activeStyle={{color: '#d52b1e'}}>

                    {config.app.title}

                </IndexLink>
              </Navbar.Brand>
              <Navbar.Toggle/>
            </Navbar.Header>
            { getUserState.activation === true ?
            <Navbar.Collapse>

                  <LinkContainer to="/community">
                    <NavItem eventKey={1} onClick={ this.onNavItemClick }>Community</NavItem>
                  </LinkContainer>
                  <LinkContainer to="/registrieren0">
                    <NavItem eventKey={2} onClick={ this.onNavItemClick }>Mein Profil</NavItem>
                  </LinkContainer>
                  <LinkContainer to="/kontakt">
                    <NavItem eventKey={3} onClick={ this.onNavItemClick }>Kontakt</NavItem>
                  </LinkContainer>
                  <LinkContainer to="/registrieren1">
                    <NavItem eventKey={4} onClick={ this.onNavItemClick }>Logout</NavItem>
                  </LinkContainer>

            </Navbar.Collapse>
            : null }
            { getUserState.activation !== true ?
            <Navbar.Collapse>

                    <LinkContainer to="/community">
                      <NavItem eventKey={1} onClick={ this.onNavItemClick }>Community</NavItem>
                    </LinkContainer>
                    <LinkContainer to="/registrieren">
                      <NavItem eventKey={2} onClick={ this.onNavItemClick }>Mitglied werden</NavItem>
                    </LinkContainer>
                    <LinkContainer to="/kontakt">
                      <NavItem eventKey={3} onClick={ this.onNavItemClick }>Kontakt</NavItem>
                    </LinkContainer>
                    <LinkContainer to="/registrieren1">
                      <NavItem eventKey={4} onClick={ this.onNavItemClick }>Login</NavItem>
                    </LinkContainer>

            </Navbar.Collapse>
            : null }
          </Navbar>

            {this.props.children}

          <InfoBar/>

            Copyright { new Date().getFullYear() } | Swiss React Community | React, Redux, Flux, React Native | Swiss-react.ch

      );
    }
  }
<commit_msg>persistent data v4.3<commit_after>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { IndexLink } from 'react-router';
import { LinkContainer } from 'react-router-bootstrap';
import Navbar from 'react-bootstrap/lib/Navbar';
import Nav from 'react-bootstrap/lib/Nav';
import NavItem from 'react-bootstrap/lib/NavItem';
import Helmet from 'react-helmet';
import { isLoaded as isInfoLoaded, load as loadInfo } from 'redux/modules/info';
import { isLoaded as isAuthLoaded, load as loadAuth, logout } from 'redux/modules/auth';
import { InfoBar } from 'components';
import { push } from 'react-router-redux';
import config from '../../config';
import { asyncConnect } from 'redux-async-connect';
import cookie from 'react-cookie';

import { getUser } from '../../redux/actions/getUserActions';

@asyncConnect([{
  promise: ({store: {dispatch, getState}}) => {
    const promises = [];

    if (!isInfoLoaded(getState())) {
      promises.push(dispatch(loadInfo()));
    }
    if (!isAuthLoaded(getState())) {
      promises.push(dispatch(loadAuth()));
    }

    return Promise.all(promises);
  }
}])

@connect((store) => {
  return {
    registerNewUserState: store.registerNewUser.user,
    getUserState: store.getUser.user,
  };
})

export default class App extends Component {
    state = {
      navExpanded: false
    }

    static propTypes = {
      children: PropTypes.object.isRequired,
      user: PropTypes.object,
      logout: PropTypes.func.isRequired,
      pushState: PropTypes.func.isRequired
    };

    static contextTypes = {
      store: PropTypes.object.isRequired
    };

    componentWillMount() {
      console.log("component componentDidMount ----------------");
      this.props.dispatch(getUser(cookie.load('ck_activation'), cookie.load('ck_email'), cookie.load('ck_pw'), cookie.load('ck_uuid')));
    }

    componentWillReceiveProps(nextProps) {
      console.log("component componentWillReceiveProps ----------------");
      if (!this.props.user && nextProps.user) {
        // login
        this.props.pushState('/loginSuccess');
      } else if (this.props.user && !nextProps.user) {
        // logout
        this.props.pushState('/');
      }
    }

    onNavItemClick = () => {
      this.setState({ navExpanded: false });
    }
    onNavbarToggle = () => {
      this.setState({ navExpanded: ! this.state.navExpanded });
    }
    handleLogout = (event) => {
      event.preventDefault();
      this.props.logout();
    }

    render() {
      const styles = require('./App.scss');
      const {userEmail} = null;
      const { registerNewUserState, getUserState } = this.props;

      return (

          <Helmet {...config.app.head}/>

          <Navbar fixedTop expanded={ this.state.navExpanded } onToggle={ this.onNavbarToggle }>
            <Navbar.Header>
              <Navbar.Brand>
                <IndexLink to="/" activeStyle={{color: '#d52b1e'}}>

                    {config.app.title}

                </IndexLink>
              </Navbar.Brand>
              <Navbar.Toggle/>
            </Navbar.Header>
            { getUserState.activation === true ?
            <Navbar.Collapse>

                  <LinkContainer to="/community">
                    <NavItem eventKey={1} onClick={ this.onNavItemClick }>Community</NavItem>
                  </LinkContainer>
                  <LinkContainer to="/registrieren0">
                    <NavItem eventKey={2} onClick={ this.onNavItemClick }>Mein Profil</NavItem>
                  </LinkContainer>
                  <LinkContainer to="/kontakt">
                    <NavItem eventKey={3} onClick={ this.onNavItemClick }>Kontakt</NavItem>
                  </LinkContainer>
                  <LinkContainer to="/registrieren1">
                    <NavItem eventKey={4} onClick={ this.onNavItemClick }>Logout</NavItem>
                  </LinkContainer>

            </Navbar.Collapse>
            : null }
            { getUserState.activation !== true ?
            <Navbar.Collapse>

                    <LinkContainer to="/community">
                      <NavItem eventKey={1} onClick={ this.onNavItemClick }>Community</NavItem>
                    </LinkContainer>
                    <LinkContainer to="/registrieren">
                      <NavItem eventKey={2} onClick={ this.onNavItemClick }>Mitglied werden</NavItem>
                    </LinkContainer>
                    <LinkContainer to="/kontakt">
                      <NavItem eventKey={3} onClick={ this.onNavItemClick }>Kontakt</NavItem>
                    </LinkContainer>
                    <LinkContainer to="/registrieren1">
                      <NavItem eventKey={4} onClick={ this.onNavItemClick }>Login</NavItem>
                    </LinkContainer>

            </Navbar.Collapse>
            : null }
          </Navbar>

            {this.props.children}

          <InfoBar/>

            Copyright { new Date().getFullYear() } | Swiss React Community | React, Redux, Flux, React Native | Swiss-react.ch

      );
    }
  }
<|endoftext|>


<commit_before>(function() {

zeit.cms.declare_namespace('zeit.content.article.html');

zeit.content.article.html.to_xml = function(tree) {
    var steps = [
        wrap_toplevel_children_in_p,
        translate_tags,
        kill_empty_p,
        replace_double_br_with_p,
        escape_missing_href,
    ];

    // XXX dropping unknown tags but keeping their text is still implemented on
    // the server side (see zeit.content.article.paragraph), because there'we
    // can utilize lxml.html.clean there which additionally cleans up any cruft
    // (handy for, say, pastes from MS Word). But from an architecture point of
    // view this too should be done as a step here.

    forEach(steps, function(step) {
        step(tree);
    });
    return tree;
};

zeit.content.article.html.change_tag = function(element, new_name) {
    var new_element = MochiKit.DOM.swapDOM(
        element,
        MochiKit.DOM.createDOM(new_name));
    while (element.firstChild) {
        new_element.appendChild(element.firstChild);
    }
};

// conversion steps

function translate_tags(tree) {
    var mapping = {
        'b': 'strong',
        'i': 'em',
        'div': 'p',
        'h3': 'intertitle',
    };

    forEach(tree.childNodes, function(el) {
        if (tag(el) in mapping) {
            zeit.content.article.html.change_tag(el, mapping[tag(el)]);
        }
        translate_tags(el);
    });
};

function kill_empty_p(tree) {
    forEach(tree.childNodes, function(el) {
        if (tag(el) == 'p' && ! el.hasChildNodes()) {
            MochiKit.DOM.removeElement(el);
        } else {
            kill_empty_p(el);
        }
    });
};

function replace_double_br_with_p(tree) {
    forEach(tree.childNodes, function(el) {
        var sibling = nextSiblingElement(el);
        if (! (tag(el) == 'br' && tag(sibling) == 'br')) {
            replace_double_br_with_p(el);
            return;
        }

        var p = MochiKit.DOM.createDOM('p')
        if (tag(sibling.nextSibling) == el.TEXT_NODE) {
            p.appendChild(sibling.nextSibling);
        }
        MochiKit.DOM.removeElement(el);
        MochiKit.DOM.swapDOM(sibling, p);
    });
};

function escape_missing_href(tree) {
    forEach(tree.childNodes, function(el) {
        if (tag(el) != 'a') {
            escape_missing_href(el);
            return;
        }

        if (! el.hasAttribute('href')) {
            el.setAttribute('href', '#');
        }
    });
};

function wrap_toplevel_children_in_p(tree) {
    var collect = [];

    var wrap_in_p = function(items) {
        var p = MochiKit.DOM.createDOM('p')
        while (items.length) {
            p.appendChild(items.shift());
        }
        return p;
    };

    forEach(tree.childNodes, function(el) {
        if (el.nodeType == el.TEXT_NODE || display(el) == 'inline') {
            collect.push(el);
        } else {
            if (collect.length) {
                MochiKit.DOM.insertSiblingNodesBefore(el, wrap_in_p(collect));
            }
        }
    });

    if (collect.length) {
        tree.appendChild(wrap_in_p(collect));
    }
};

// helper functions

function tag(element) {
    if (MochiKit.Base.isNull(element)) {
        return null;
    }
    if (element.nodeType != element.ELEMENT_NODE) {
        return element.nodeType;
    }
    return element.nodeName.toLowerCase();
};

function nextSiblingElement(element) {
    var el = element.nextSibling;
    while (el) {
        if (el.nodeType == el.ELEMENT_NODE) {
            return el;
        }
        el = el.nextSibling;
    }
    return null;
};

function display(element) {
    if (element.nodeType != element.ELEMENT_NODE) {
        return null;
    }
    return MochiKit.Style.getStyle(element, 'display')
}

})();<commit_msg>whitespace<commit_after>(function() {

zeit.cms.declare_namespace('zeit.content.article.html');

zeit.content.article.html.to_xml = function(tree) {
    var steps = [
        wrap_toplevel_children_in_p,
        translate_tags,
        kill_empty_p,
        replace_double_br_with_p,
        escape_missing_href,
    ];

    // XXX dropping unknown tags but keeping their text is still implemented on
    // the server side (see zeit.content.article.paragraph), because there'we
    // can utilize lxml.html.clean there which additionally cleans up any cruft
    // (handy for, say, pastes from MS Word). But from an architecture point of
    // view this too should be done as a step here.

    forEach(steps, function(step) {
        step(tree);
    });
    return tree;
};

zeit.content.article.html.change_tag = function(element, new_name) {
    var new_element = MochiKit.DOM.swapDOM(
        element, MochiKit.DOM.createDOM(new_name));
    while (element.firstChild) {
        new_element.appendChild(element.firstChild);
    }
};

// conversion steps

function translate_tags(tree) {
    var mapping = {
        'b': 'strong',
        'i': 'em',
        'div': 'p',
        'h3': 'intertitle',
    };

    forEach(tree.childNodes, function(el) {
        if (tag(el) in mapping) {
            zeit.content.article.html.change_tag(el, mapping[tag(el)]);
        }
        translate_tags(el);
    });
};

function kill_empty_p(tree) {
    forEach(tree.childNodes, function(el) {
        if (tag(el) == 'p' && ! el.hasChildNodes()) {
            MochiKit.DOM.removeElement(el);
        } else {
            kill_empty_p(el);
        }
    });
};

function replace_double_br_with_p(tree) {
    forEach(tree.childNodes, function(el) {
        var sibling = nextSiblingElement(el);
        if (! (tag(el) == 'br' && tag(sibling) == 'br')) {
            replace_double_br_with_p(el);
            return;
        }

        var p = MochiKit.DOM.createDOM('p')
        if (tag(sibling.nextSibling) == el.TEXT_NODE) {
            p.appendChild(sibling.nextSibling);
        }
        MochiKit.DOM.removeElement(el);
        MochiKit.DOM.swapDOM(sibling, p);
    });
};

function escape_missing_href(tree) {
    forEach(tree.childNodes, function(el) {
        if (tag(el) != 'a') {
            escape_missing_href(el);
            return;
        }

        if (! el.hasAttribute('href')) {
            el.setAttribute('href', '#');
        }
    });
};

function wrap_toplevel_children_in_p(tree) {
    var collect = [];

    var wrap_in_p = function(items) {
        var p = MochiKit.DOM.createDOM('p')
        while (items.length) {
            p.appendChild(items.shift());
        }
        return p;
    };

    forEach(tree.childNodes, function(el) {
        if (el.nodeType == el.TEXT_NODE || display(el) == 'inline') {
            collect.push(el);
        } else {
            if (collect.length) {
                MochiKit.DOM.insertSiblingNodesBefore(el, wrap_in_p(collect));
            }
        }
    });

    if (collect.length) {
        tree.appendChild(wrap_in_p(collect));
    }
};

// helper functions

function tag(element) {
    if (MochiKit.Base.isNull(element)) {
        return null;
    }
    if (element.nodeType != element.ELEMENT_NODE) {
        return element.nodeType;
    }
    return element.nodeName.toLowerCase();
};

function nextSiblingElement(element) {
    var el = element.nextSibling;
    while (el) {
        if (el.nodeType == el.ELEMENT_NODE) {
            return el;
        }
        el = el.nextSibling;
    }
    return null;
};

function display(element) {
    if (element.nodeType != element.ELEMENT_NODE) {
        return null;
    }
    return MochiKit.Style.getStyle(element, 'display')
}

})();<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { IndexLink } from 'react-router';
import { LinkContainer } from 'react-router-bootstrap';
import Navbar from 'react-bootstrap/lib/Navbar';
import Nav from 'react-bootstrap/lib/Nav';
import NavItem from 'react-bootstrap/lib/NavItem';
import Helmet from 'react-helmet';
import { isLoaded as isInfoLoaded, load as loadInfo } from 'redux/modules/info';
import { isLoaded as isAuthLoaded, load as loadAuth, logout } from 'redux/modules/auth';
import { InfoBar } from 'components';
import { push } from 'react-router-redux';
import config from '../../config';
import { asyncConnect } from 'redux-async-connect';

@asyncConnect([{
  promise: ({store: {dispatch, getState}}) => {
    const promises = [];

    if (!isInfoLoaded(getState())) {
      promises.push(dispatch(loadInfo()));
    }
    if (!isAuthLoaded(getState())) {
      promises.push(dispatch(loadAuth()));
    }

    return Promise.all(promises);
  }
}])
@connect(
  state => ({user: state.auth.user}),
  {logout, pushState: push})

  export default class App extends Component {
    static propTypes = {
      children: PropTypes.object.isRequired,
      user: PropTypes.object,
      logout: PropTypes.func.isRequired,
      pushState: PropTypes.func.isRequired
    };

    static contextTypes = {
      store: PropTypes.object.isRequired
    };

    state = {
      navExpanded: false,
      loginStatus: false,
      loginUsername: false
    }

    componentWillMount() {
      console.log( window.localStorage.getItem('ls_username') );
    }

    componentWillReceiveProps(nextProps) {
      if (!this.props.user && nextProps.user) {
        // login
        this.props.pushState('/loginSuccess');
      } else if (this.props.user && !nextProps.user) {
        // logout
        this.props.pushState('/');
      }
    }

    onNavItemClick = () => {
      this.setState({ navExpanded: false });
    }
    onNavbarToggle = () => {
      this.setState({ navExpanded: ! this.state.navExpanded });
    }
    handleLogout = (event) => {
      event.preventDefault();
      this.props.logout();
    };

    render() {
      const {user, loginStatus, loginUsername} = this.state;
      const styles = require('./App.scss');

      return (

          <Helmet {...config.app.head}/>
          <Navbar fixedTop expanded={ this.state.navExpanded } onToggle={ this.onNavbarToggle }>
            <Navbar.Header>
              <Navbar.Brand>
                <IndexLink to="/" activeStyle={{color: '#d52b1e'}}>

                  {config.app.title}
                </IndexLink>
              </Navbar.Brand>
              <Navbar.Toggle/>
            </Navbar.Header>

            <Navbar.Collapse>

                <LinkContainer to="/community">
                  <NavItem eventKey={1} onClick={ this.onNavItemClick }>Community</NavItem>
                </LinkContainer>
                <LinkContainer to="/registrieren">
                  <NavItem eventKey={2} onClick={ this.onNavItemClick }>Mitglied werden</NavItem>
                </LinkContainer>
                <LinkContainer to="/kontakt">
                  <NavItem eventKey={3} onClick={ this.onNavItemClick }>Kontakt</NavItem>
                </LinkContainer>

            </Navbar.Collapse>
          </Navbar>

            {this.props.children}

          <InfoBar/>

            Copyright 2016 | Swiss React Community | React, Redux, Flux, React Native | Swiss-react.ch

      );
    }
  }
<commit_msg>consolelog test 11<commit_after>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { IndexLink } from 'react-router';
import { LinkContainer } from 'react-router-bootstrap';
import Navbar from 'react-bootstrap/lib/Navbar';
import Nav from 'react-bootstrap/lib/Nav';
import NavItem from 'react-bootstrap/lib/NavItem';
import Helmet from 'react-helmet';
import { isLoaded as isInfoLoaded, load as loadInfo } from 'redux/modules/info';
import { isLoaded as isAuthLoaded, load as loadAuth, logout } from 'redux/modules/auth';
import { InfoBar } from 'components';
import { push } from 'react-router-redux';
import config from '../../config';
import { asyncConnect } from 'redux-async-connect';

@asyncConnect([{
  promise: ({store: {dispatch, getState}}) => {
    const promises = [];

    if (!isInfoLoaded(getState())) {
      promises.push(dispatch(loadInfo()));
    }
    if (!isAuthLoaded(getState())) {
      promises.push(dispatch(loadAuth()));
    }

    return Promise.all(promises);
  }
}])
@connect(
  state => ({user: state.auth.user}),
  {logout, pushState: push})

  export default class App extends Component {
    static propTypes = {
      children: PropTypes.object.isRequired,
      user: PropTypes.object,
      logout: PropTypes.func.isRequired,
      pushState: PropTypes.func.isRequired
    };

    static contextTypes = {
      store: PropTypes.object.isRequired
    };

    state = {
      navExpanded: false
    }

    componentWillMount() {
      console.log('aa '+window.localStorage.getItem('ls_username'));
    }

    componentWillReceiveProps(nextProps) {
      if (!this.props.user && nextProps.user) {
        // login
        this.props.pushState('/loginSuccess');
      } else if (this.props.user && !nextProps.user) {
        // logout
        this.props.pushState('/');
      }
    }

    onNavItemClick = () => {
      this.setState({ navExpanded: false });
    }
    onNavbarToggle = () => {
      this.setState({ navExpanded: ! this.state.navExpanded });
    }
    handleLogout = (event) => {
      event.preventDefault();
      this.props.logout();
    };

    render() {
      const {user} = this.state;
      const styles = require('./App.scss');

      return (

          <Helmet {...config.app.head}/>
          <Navbar fixedTop expanded={ this.state.navExpanded } onToggle={ this.onNavbarToggle }>
            <Navbar.Header>
              <Navbar.Brand>
                <IndexLink to="/" activeStyle={{color: '#d52b1e'}}>

                  {config.app.title}
                </IndexLink>
              </Navbar.Brand>
              <Navbar.Toggle/>
            </Navbar.Header>

            <Navbar.Collapse>

                <LinkContainer to="/community">
                  <NavItem eventKey={1} onClick={ this.onNavItemClick }>Community</NavItem>
                </LinkContainer>
                <LinkContainer to="/registrieren">
                  <NavItem eventKey={2} onClick={ this.onNavItemClick }>Mitglied werden</NavItem>
                </LinkContainer>
                <LinkContainer to="/kontakt">
                  <NavItem eventKey={3} onClick={ this.onNavItemClick }>Kontakt</NavItem>
                </LinkContainer>

            </Navbar.Collapse>
          </Navbar>

            {this.props.children}

          <InfoBar/>

            Copyright 2016 | Swiss React Community | React, Redux, Flux, React Native | Swiss-react.ch

      );
    }
  }
<|endoftext|>


<commit_before>/**
 * @author gyb(mocheer)
 * @email mocheer@foxmail.com
 * @since 2016.3.24
 */
import React, { Component, PropTypes } from 'react'
import classNames from 'classnames'
import draggable from '../../libs/draggable'
/**
 *
 */
export default class Draggable extends Component {
    /**
     * 渲染
     */
    render() {
        let { props } = this,
            { disable, children } = props;
        if (!disable) {
            let drag = component => {
                component.ref = node => {
                    node && draggable(node)
                }
            }
            T.isArray(children) ? children.forEach(drag) : drag(children)
        }
        return children
    }
}<commit_msg>update<commit_after>/**
 * @author gyb(mocheer)
 * @email mocheer@foxmail.com
 * @since 2016.3.24
 */
import React, { Component, PropTypes } from 'react'
import classNames from 'classnames'
import draggable from '../../libs/draggable'
/**
 *
 */
export default class Draggable extends Component {
    /**
    * 渲染
    */
    render() {
        let { props } = this,
            { disable, children, parent } = props;
        if (!disable) {
            let drag = component => {
                component.ref = node => {
                    let handle;
                    if (node && parent) {
                        handle = node;
                        node = node.parentNode;
                    }
                    node && draggable(node, handle)
                }
            }
            T.isArray(children) ? children.forEach(drag) : drag(children)
        }
        return children
    }
}<|endoftext|>


<commit_before>
import Entity from './entity';

const RG = require('./rg');
RG.Component = require('./component');
RG.Brain = require('./brain.virtual');
RG.Brain.Player = require('./brain.player');
RG.Inv = require('./inv');
RG.Spell = require('./spell');
RG.Time = require('./time');
const Mixin = require('./mixin');

RG.Actor = {};

const ACTOR_NO_ACTION = Object.freeze(() => {});
const EMPTY_ARGS = Object.freeze({});
const SPEED_COEFF = RG.BASE_SPEED * RG.ACTION_DUR;

class BaseActor extends Mixin.Locatable(Mixin.Typed(Entity)) {

    constructor(name) { // {{{2
        super({propType: RG.TYPE_ACTOR, type: null});
        this._name = name;
        this.add(new RG.Component.Action());
    }

    isPlayer() {return false;}

    setName(name) {this._name = name;}
    getName() {return this._name;}

    getBrain() {return this._brain;}

    setBrain(brain) {
        this._brain = brain;
        this._brain.setActor(this);
    }

    getSpeed() {
        return RG.BASE_SPEED;
    }

    /* Returns the next action for this actor.*/
    nextAction(obj) {
        // Use actor brain to determine the action
        const cb = this._brain.decideNextAction(obj);
        let action = null;

        if (cb !== null) {
            const duration = Math.round(SPEED_COEFF / this.getSpeed());
            action = new RG.Time.Action(duration, cb, EMPTY_ARGS);
        }
        else {
            action = new RG.Time.Action(0, ACTOR_NO_ACTION, EMPTY_ARGS);
        }

        if (this._brain.hasOwnProperty('energy')) {
            action.energy = this._brain.energy;
        }
        action.actor = this;
        return action;
    }

    /* Serializes the virtual actor. */
    toJSON() {
        let levelID = null;
        if (this.getLevel()) {
            levelID = this.getLevel().getID();
        }
        const obj = {
            id: this.getID(),
            name: this.getName(),
            type: this.getType(),
            levelID,
            brain: this._brain.toJSON()
        };

        obj.components = RG.Component.compsToJSON(this);

        if (obj.type === null) {
            RG.err('Actor.Virtual', 'toJSON',
                `Type null for ${JSON.stringify(obj)}`);
        }

        return obj;
    }

}
RG.Actor.Base = BaseActor;

/* Virtual actor can be used to spawn more entities or for AI-like effects
 * inside a level. */
class VirtualActor extends BaseActor {

    constructor(name) { // {{{2
        super(name);
        this._brain = new RG.Brain.Virtual(this);
    }

}
RG.Actor.Virtual = VirtualActor;

/* Object representing a game actor who takes actions.  */
class RGActorRogue extends BaseActor {
    constructor(name) { // {{{2
        super(name);

        this._brain = new RG.Brain.Rogue(this);
        this._brain.getMemory().addEnemyType('player');

        this._invEq = new RG.Inv.Inventory(this);
        this._maxWeight = 10.0;

        // Components for this entity
        this.add(new RG.Component.Experience());
        this.add(new RG.Component.Combat());
        this.add(new RG.Component.Stats());
        this.add(new RG.Component.Health(50));

        const perception = new RG.Component.Perception();
        perception.setFOVRange(RG.NPC_FOV_RANGE);
        this.add(new RG.Component.Perception());

    }

    /* Returns true if actor is a player.*/
    isPlayer() {
        return this.has('Player') || this.has('PlayerControlled');
    }

    getFOVRange() {
        let range = this.get('Perception').getFOVRange();
        if (this.has('EagleEye')) {range += 2;}
        return range;
    }

    setFOVRange(range) {
        this.get('Perception').setFOVRange(range);
    }

    //---------------------------------
    // Brain-related methods
    //---------------------------------

    addEnemy(actor) {this._brain.addEnemy(actor);}
    addFriend(actor) {this._brain.addFriend(actor);}

    isEnemy(actor) {
        return this._brain.getMemory().isEnemy(actor);
    }

    isFriend(actor) {
        return this._brain.getMemory().isFriend(actor);
    }

    //---------------------------------
    // Equipment related methods
    //---------------------------------

    getInvEq() { return this._invEq; }

    /* Returns weapon that is wielded by the actor.*/
    getWeapon() {return this._invEq.getWeapon();}

    /* Returns weapon that is wielded by the actor.*/
    getMissileWeapon() {
        return this._invEq.getMissileWeapon();
    }

    /* Returns missile equipped by the player.*/
    getMissile() {
        return this._invEq.getEquipment().getItem('missile');
    }

    getEquipAttack() {
        let att = this._invEq.getEquipment().getAttack();
        if (this.has('Skills')) {
            att += this.get('Skills').getLevel('Melee');
        }
        return att;
    }

    getEquipDefense() {
        let def = this._invEq.getEquipment().getDefense();
        if (this.has('Skills')) {
            def += this.get('Skills').getLevel('Shields');
        }
        return def;
    }

    getEquipProtection() {
        return this._invEq.getEquipment().getProtection();
    }

    getShieldDefense() {
        const shield = this._invEq.getEquipment().getEquipped('shield');
        let bonus = 0;
        if (shield) {
            bonus = shield.getDefense();
            if (this.has('Skills')) {
                bonus += this.get('Skills').getLevel('Shields');
            }
        }
        return bonus;
    }

    setActorClass(classObj) {
        this._actorClass = classObj;
    }

    getActorClass() {
        return this._actorClass;
    }

    setBook(book) {
        this._spellbook = book;
    }

    getBook() {
        return this._spellbook;
    }

    /* Returns carrying capacity of the actor.*/
    getMaxWeight() {
        const statStr = this.get('Stats').getStrength();
        const eqStr = this._invEq.getEquipment().getStrength();
        return 2 * statStr + 2 * eqStr + this._maxWeight;
    }

    /* Marks actor as player. Cannot unset player.*/
    setIsPlayer(isPlayer) {
        if (isPlayer) {
            this._brain = new RG.Brain.Player(this);
            if (!this.has('StatsMods')) {
                this.add(new RG.Component.StatsMods());
            }
            if (!this.has('CombatMods')) {
                this.add(new RG.Component.CombatMods());
            }
            this.add(new RG.Component.Player());
            this.add(new RG.Component.SpellPower());
        }
        else {
            RG.err('Actor.Rogue', 'setIsPlayer',
                'Actor cannot be changed from player to mob.');
        }
    }

    /* Used when controlling other actors with the "real player" actor .*/
    setPlayerCtrl(isPlayer) {
        if (isPlayer) {
            this.add(new RG.Component.PlayerControlled());
            this._actualBrain = this._brain;
            this._brain = new RG.Brain.Player(this);
            if (!this.has('StatsMods')) {
                this.add(new RG.Component.StatsMods());
            }
            if (!this.has('CombatMods')) {
                this.add(new RG.Component.CombatMods());
            }
            this.add(new RG.Component.Possessed());
        }
        else {
            this.remove('PlayerControlled');
            this.remove('StatsMods');
            this.remove('CombatMods');
            this.remove('Possessed');
            this._brain = this._actualBrain;
            delete this._actualBrain;
        }
    }

    /* Returns the cell where this actor is located at.*/
    getCell() {
        const x = this.getX();
        const y = this.getY();
        const level = this.getLevel();
        if (level) {
            return level.getMap().getCell(x, y);
        }
        return null;
    }

    isInLevel(level) {
        if (this.getLevel()) {
            return this.getLevel().getID() === level.getID();
        }
        return false;
    }

    toJSON() {
        let levelID = null;
        if (this.getLevel()) {
            levelID = this.getLevel().getID();
        }
        const obj = {
            id: this.getID(),
            name: this.getName(),
            type: this.getType(),
            x: this.getX(),
            y: this.getY(),
            fovRange: this.getFOVRange(),
            levelID,
            inventory: this.getInvEq().getInventory().toJSON(),
            equipment: this.getInvEq().getEquipment().toJSON(),
            brain: this._brain.toJSON()
        };

        obj.components = RG.Component.compsToJSON(this);

        if (obj.type === null) {
            RG.err('Actor.Rogue', 'toJSON',
                `Type null for ${JSON.stringify(obj)}`);
        }

        if (this._spellbook) {
            obj.spellbook = this._spellbook.toJSON();
        }
        if (this.has('Player')) {
            obj.isPlayer = true;
        }
        if (this._actualBrain) {
            obj.brain = this._actualBrain.toJSON();
        }

        return obj;
    }

    //---------------------------------
    // Combat-related methods
    //---------------------------------

    getAttack() {
        let attack = this.get('Combat').getAttack();
        attack += this.getEquipAttack();
        attack += this._addFromCompList('CombatMods', 'getAttack');
        attack += Math.floor(this.getAccuracy() / 2);
        return attack;
    }

    getDefense() {
        let defense = this.get('Combat').getDefense();
        defense += this.getEquipDefense();
        defense += this._addFromCompList('CombatMods', 'getDefense');
        defense += Math.floor(this.getAgility() / 2);
        return defense;
    }

    getProtection() {
        let protection = this.get('Combat').getProtection();
        protection += this.getEquipProtection();
        protection += this._addFromCompList('CombatMods', 'getProtection');
        return protection;
    }

    getDamage() {
        let damage = this.get('Combat').rollDamage();
        const weapon = this.getWeapon();
        if (weapon) {
            damage = RG.getItemDamage(weapon);
        }
        const strength = this.getStrength();
        damage += RG.strengthToDamage(strength);
        damage += this._addFromCompList('CombatMods', 'getDamage');
        return damage;

    }

    getCombatBonus(funcName) {
        return this._addFromCompList('CombatMods', funcName);
    }

    _addFromCompList(compType, func) {
        const compList = this.getList(compType);
        if (compList.length > 0) {
            return compList.reduce((acc, val) => {
                return acc + val[func]();
            }, 0);
        }
        return 0;
    }

    //-------------------------------------------------------------
    // Stats-related methods (these take eq and boosts into account
    //-------------------------------------------------------------

    getAccuracy() {
        let acc = this.get('Stats').getAccuracy();
        acc += this.getInvEq().getEquipment().getAccuracy();
        acc += this._addFromCompList('StatsMods', 'getAccuracy');
        return acc;
    }

    getAgility() {
        let agi = this.get('Stats').getAgility();
        agi += this.getInvEq().getEquipment().getAgility();
        agi += this._addFromCompList('StatsMods', 'getAgility');
        return agi;
    }

    getStrength() {
        let str = this.get('Stats').getStrength();
        str += this.getInvEq().getEquipment().getStrength();
        str += this._addFromCompList('StatsMods', 'getStrength');
        return str;
    }

    getWillpower() {
        let wil = this.get('Stats').getWillpower();
        wil += this.getInvEq().getEquipment().getWillpower();
        wil += this._addFromCompList('StatsMods', 'getWillpower');
        return wil;
    }

    getSpeed() {
        let speed = this.get('Stats').getSpeed();
        speed += this.getInvEq().getEquipment().getSpeed();
        speed += this._addFromCompList('StatsMods', 'getSpeed');
        return speed;
    }

    getPerception() {
        let per = this.get('Stats').getPerception();
        per += this.getInvEq().getEquipment().getPerception();
        per += this._addFromCompList('StatsMods', 'getPerception');
        return per;
    }

    getMagic() {
        let mag = this.get('Stats').getMagic();
        mag += this.getInvEq().getEquipment().getMagic();
        mag += this._addFromCompList('StatsMods', 'getMagic');
        return mag;
    }

    /* Returns bonuses applied to given stat. */
    getStatBonus(funcName) {
        return this._addFromCompList('StatsMods', funcName);
    }
}

RG.Actor.Rogue = RGActorRogue;

/* Spirit actors. They have Ethereal component and cannot be attacked, but they
 * can be captured by SpiritGem-objects.*/
class RGActorSpirit extends RGActorRogue {

    constructor(name) {
        super(name);
        this.setType('spirit');
        this.add(new RG.Component.Ethereal());
        this.setBrain(new RG.Brain.Spirit(this));
    }

}

RG.Actor.Spirit = RGActorSpirit;

module.exports = RG.Actor;
<commit_msg>Added 3 required functions to actor base class.<commit_after>
import Entity from './entity';

const RG = require('./rg');
RG.Component = require('./component');
RG.Brain = require('./brain.virtual');
RG.Brain.Player = require('./brain.player');
RG.Inv = require('./inv');
RG.Spell = require('./spell');
RG.Time = require('./time');
const Mixin = require('./mixin');

RG.Actor = {};

const ACTOR_NO_ACTION = Object.freeze(() => {});
const EMPTY_ARGS = Object.freeze({});
const SPEED_COEFF = RG.BASE_SPEED * RG.ACTION_DUR;

class BaseActor extends Mixin.Locatable(Mixin.Typed(Entity)) {

    constructor(name) { // {{{2
        super({propType: RG.TYPE_ACTOR, type: null});
        this._name = name;
        this.add(new RG.Component.Action());
    }

    isPlayer() {return false;}
    isEnemy() {return false;}
    addEnemy() {/* No implementation here */}

    setName(name) {this._name = name;}
    getName() {return this._name;}

    getBrain() {return this._brain;}

    setBrain(brain) {
        this._brain = brain;
        this._brain.setActor(this);
    }

    getSpeed() {
        return RG.BASE_SPEED;
    }

    getEquipProtection() {return 0;}

    /* Returns the next action for this actor.*/
    nextAction(obj) {
        // Use actor brain to determine the action
        const cb = this._brain.decideNextAction(obj);
        let action = null;

        if (cb !== null) {
            const duration = Math.round(SPEED_COEFF / this.getSpeed());
            action = new RG.Time.Action(duration, cb, EMPTY_ARGS);
        }
        else {
            action = new RG.Time.Action(0, ACTOR_NO_ACTION, EMPTY_ARGS);
        }

        if (this._brain.hasOwnProperty('energy')) {
            action.energy = this._brain.energy;
        }
        action.actor = this;
        return action;
    }

    /* Serializes the virtual actor. */
    toJSON() {
        let levelID = null;
        if (this.getLevel()) {
            levelID = this.getLevel().getID();
        }
        const obj = {
            id: this.getID(),
            name: this.getName(),
            type: this.getType(),
            levelID,
            brain: this._brain.toJSON()
        };

        obj.components = RG.Component.compsToJSON(this);

        if (obj.type === null) {
            RG.err('Actor.Virtual', 'toJSON',
                `Type null for ${JSON.stringify(obj)}`);
        }

        return obj;
    }

}
RG.Actor.Base = BaseActor;

/* Virtual actor can be used to spawn more entities or for AI-like effects
 * inside a level. */
class VirtualActor extends BaseActor {

    constructor(name) { // {{{2
        super(name);
        this._brain = new RG.Brain.Virtual(this);
    }

}
RG.Actor.Virtual = VirtualActor;

/* Object representing a game actor who takes actions.  */
class RGActorRogue extends BaseActor {
    constructor(name) { // {{{2
        super(name);

        this._brain = new RG.Brain.Rogue(this);
        this._brain.getMemory().addEnemyType('player');

        this._invEq = new RG.Inv.Inventory(this);
        this._maxWeight = 10.0;

        // Components for this entity
        this.add(new RG.Component.Experience());
        this.add(new RG.Component.Combat());
        this.add(new RG.Component.Stats());
        this.add(new RG.Component.Health(50));

        const perception = new RG.Component.Perception();
        perception.setFOVRange(RG.NPC_FOV_RANGE);
        this.add(new RG.Component.Perception());

    }

    /* Returns true if actor is a player.*/
    isPlayer() {
        return this.has('Player') || this.has('PlayerControlled');
    }

    getFOVRange() {
        let range = this.get('Perception').getFOVRange();
        if (this.has('EagleEye')) {range += 2;}
        return range;
    }

    setFOVRange(range) {
        this.get('Perception').setFOVRange(range);
    }

    //---------------------------------
    // Brain-related methods
    //---------------------------------

    addEnemy(actor) {this._brain.addEnemy(actor);}
    addFriend(actor) {this._brain.addFriend(actor);}

    isEnemy(actor) {
        return this._brain.getMemory().isEnemy(actor);
    }

    isFriend(actor) {
        return this._brain.getMemory().isFriend(actor);
    }

    //---------------------------------
    // Equipment related methods
    //---------------------------------

    getInvEq() { return this._invEq; }

    /* Returns weapon that is wielded by the actor.*/
    getWeapon() {return this._invEq.getWeapon();}

    /* Returns weapon that is wielded by the actor.*/
    getMissileWeapon() {
        return this._invEq.getMissileWeapon();
    }

    /* Returns missile equipped by the player.*/
    getMissile() {
        return this._invEq.getEquipment().getItem('missile');
    }

    getEquipAttack() {
        let att = this._invEq.getEquipment().getAttack();
        if (this.has('Skills')) {
            att += this.get('Skills').getLevel('Melee');
        }
        return att;
    }

    getEquipDefense() {
        let def = this._invEq.getEquipment().getDefense();
        if (this.has('Skills')) {
            def += this.get('Skills').getLevel('Shields');
        }
        return def;
    }

    getEquipProtection() {
        return this._invEq.getEquipment().getProtection();
    }

    getShieldDefense() {
        const shield = this._invEq.getEquipment().getEquipped('shield');
        let bonus = 0;
        if (shield) {
            bonus = shield.getDefense();
            if (this.has('Skills')) {
                bonus += this.get('Skills').getLevel('Shields');
            }
        }
        return bonus;
    }

    setActorClass(classObj) {
        this._actorClass = classObj;
    }

    getActorClass() {
        return this._actorClass;
    }

    setBook(book) {
        this._spellbook = book;
    }

    getBook() {
        return this._spellbook;
    }

    /* Returns carrying capacity of the actor.*/
    getMaxWeight() {
        const statStr = this.get('Stats').getStrength();
        const eqStr = this._invEq.getEquipment().getStrength();
        return 2 * statStr + 2 * eqStr + this._maxWeight;
    }

    /* Marks actor as player. Cannot unset player.*/
    setIsPlayer(isPlayer) {
        if (isPlayer) {
            this._brain = new RG.Brain.Player(this);
            if (!this.has('StatsMods')) {
                this.add(new RG.Component.StatsMods());
            }
            if (!this.has('CombatMods')) {
                this.add(new RG.Component.CombatMods());
            }
            this.add(new RG.Component.Player());
            this.add(new RG.Component.SpellPower());
        }
        else {
            RG.err('Actor.Rogue', 'setIsPlayer',
                'Actor cannot be changed from player to mob.');
        }
    }

    /* Used when controlling other actors with the "real player" actor .*/
    setPlayerCtrl(isPlayer) {
        if (isPlayer) {
            this.add(new RG.Component.PlayerControlled());
            this._actualBrain = this._brain;
            this._brain = new RG.Brain.Player(this);
            if (!this.has('StatsMods')) {
                this.add(new RG.Component.StatsMods());
            }
            if (!this.has('CombatMods')) {
                this.add(new RG.Component.CombatMods());
            }
            this.add(new RG.Component.Possessed());
        }
        else {
            this.remove('PlayerControlled');
            this.remove('StatsMods');
            this.remove('CombatMods');
            this.remove('Possessed');
            this._brain = this._actualBrain;
            delete this._actualBrain;
        }
    }

    /* Returns the cell where this actor is located at.*/
    getCell() {
        const x = this.getX();
        const y = this.getY();
        const level = this.getLevel();
        if (level) {
            return level.getMap().getCell(x, y);
        }
        return null;
    }

    isInLevel(level) {
        if (this.getLevel()) {
            return this.getLevel().getID() === level.getID();
        }
        return false;
    }

    toJSON() {
        let levelID = null;
        if (this.getLevel()) {
            levelID = this.getLevel().getID();
        }
        const obj = {
            id: this.getID(),
            name: this.getName(),
            type: this.getType(),
            x: this.getX(),
            y: this.getY(),
            fovRange: this.getFOVRange(),
            levelID,
            inventory: this.getInvEq().getInventory().toJSON(),
            equipment: this.getInvEq().getEquipment().toJSON(),
            brain: this._brain.toJSON()
        };

        obj.components = RG.Component.compsToJSON(this);

        if (obj.type === null) {
            RG.err('Actor.Rogue', 'toJSON',
                `Type null for ${JSON.stringify(obj)}`);
        }

        if (this._spellbook) {
            obj.spellbook = this._spellbook.toJSON();
        }
        if (this.has('Player')) {
            obj.isPlayer = true;
        }
        if (this._actualBrain) {
            obj.brain = this._actualBrain.toJSON();
        }

        return obj;
    }

    //---------------------------------
    // Combat-related methods
    //---------------------------------

    getAttack() {
        let attack = this.get('Combat').getAttack();
        attack += this.getEquipAttack();
        attack += this._addFromCompList('CombatMods', 'getAttack');
        attack += Math.floor(this.getAccuracy() / 2);
        return attack;
    }

    getDefense() {
        let defense = this.get('Combat').getDefense();
        defense += this.getEquipDefense();
        defense += this._addFromCompList('CombatMods', 'getDefense');
        defense += Math.floor(this.getAgility() / 2);
        return defense;
    }

    getProtection() {
        let protection = this.get('Combat').getProtection();
        protection += this.getEquipProtection();
        protection += this._addFromCompList('CombatMods', 'getProtection');
        return protection;
    }

    getDamage() {
        let damage = this.get('Combat').rollDamage();
        const weapon = this.getWeapon();
        if (weapon) {
            damage = RG.getItemDamage(weapon);
        }
        const strength = this.getStrength();
        damage += RG.strengthToDamage(strength);
        damage += this._addFromCompList('CombatMods', 'getDamage');
        return damage;

    }

    getCombatBonus(funcName) {
        return this._addFromCompList('CombatMods', funcName);
    }

    _addFromCompList(compType, func) {
        const compList = this.getList(compType);
        if (compList.length > 0) {
            return compList.reduce((acc, val) => {
                return acc + val[func]();
            }, 0);
        }
        return 0;
    }

    //-------------------------------------------------------------
    // Stats-related methods (these take eq and boosts into account
    //-------------------------------------------------------------

    getAccuracy() {
        let acc = this.get('Stats').getAccuracy();
        acc += this.getInvEq().getEquipment().getAccuracy();
        acc += this._addFromCompList('StatsMods', 'getAccuracy');
        return acc;
    }

    getAgility() {
        let agi = this.get('Stats').getAgility();
        agi += this.getInvEq().getEquipment().getAgility();
        agi += this._addFromCompList('StatsMods', 'getAgility');
        return agi;
    }

    getStrength() {
        let str = this.get('Stats').getStrength();
        str += this.getInvEq().getEquipment().getStrength();
        str += this._addFromCompList('StatsMods', 'getStrength');
        return str;
    }

    getWillpower() {
        let wil = this.get('Stats').getWillpower();
        wil += this.getInvEq().getEquipment().getWillpower();
        wil += this._addFromCompList('StatsMods', 'getWillpower');
        return wil;
    }

    getSpeed() {
        let speed = this.get('Stats').getSpeed();
        speed += this.getInvEq().getEquipment().getSpeed();
        speed += this._addFromCompList('StatsMods', 'getSpeed');
        return speed;
    }

    getPerception() {
        let per = this.get('Stats').getPerception();
        per += this.getInvEq().getEquipment().getPerception();
        per += this._addFromCompList('StatsMods', 'getPerception');
        return per;
    }

    getMagic() {
        let mag = this.get('Stats').getMagic();
        mag += this.getInvEq().getEquipment().getMagic();
        mag += this._addFromCompList('StatsMods', 'getMagic');
        return mag;
    }

    /* Returns bonuses applied to given stat. */
    getStatBonus(funcName) {
        return this._addFromCompList('StatsMods', funcName);
    }
}

RG.Actor.Rogue = RGActorRogue;

/* Spirit actors. They have Ethereal component and cannot be attacked, but they
 * can be captured by SpiritGem-objects.*/
class RGActorSpirit extends RGActorRogue {

    constructor(name) {
        super(name);
        this.setType('spirit');
        this.add(new RG.Component.Ethereal());
        this.setBrain(new RG.Brain.Spirit(this));
    }

}

RG.Actor.Spirit = RGActorSpirit;

module.exports = RG.Actor;
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));<commit_msg>remove ununsed service worker import<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import GraphiQL from 'graphiql';
import fetch from 'isomorphic-fetch';

import 'graphiql/graphiql.css';
import './index.css';

function graphQLFetcher(graphQLParams) {
  return fetch('https://www.graphqlhub.com/graphql', {
    method: 'post',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(graphQLParams),
  }).then(response => response.json());
}

ReactDOM.render(<GraphiQL fetcher={graphQLFetcher} />, document.body);
<commit_msg>Change URL of index.js<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import GraphiQL from 'graphiql';
import fetch from 'isomorphic-fetch';

import 'graphiql/graphiql.css';
import './index.css';

function graphQLFetcher(graphQLParams) {
  return fetch('http://localhost:8080/graphql', {
    method: 'post',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(graphQLParams),
  }).then(response => response.json());
}

ReactDOM.render(<GraphiQL fetcher={graphQLFetcher} />, document.body);
<|endoftext|>