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

const SPACE_KEY = 32;
const ENTER_KEY = 13;

function getTouchProps (touch) {
	if (!touch) return {};
	return {
		pageX: touch.pageX,
		pageY: touch.pageY,
		clientX: touch.clientX,
		clientY: touch.clientY
	};
}

var Mixin = {
	propTypes: {
		moveThreshold: React.PropTypes.number,       // pixels to move before cancelling tap
		activeDelay: React.PropTypes.number,         // ms to wait before adding the `-active` class
		pressDelay: React.PropTypes.number,          // ms to wait before detecting a press
		pressMoveThreshold: React.PropTypes.number,  // pixels to move before cancelling press
		preventDefault: React.PropTypes.bool,        // whether to preventDefault on all events
		stopPropagation: React.PropTypes.bool,       // whether to stopPropagation on all events

		onTap: React.PropTypes.func,                 // fires when a tap is detected
		onPress: React.PropTypes.func,               // fires when a press is detected
		onTouchStart: React.PropTypes.func,          // pass-through touch event
		onTouchMove: React.PropTypes.func,           // pass-through touch event
		onTouchEnd: React.PropTypes.func,            // pass-through touch event
		onMouseDown: React.PropTypes.func,           // pass-through mouse event
		onMouseUp: React.PropTypes.func,             // pass-through mouse event
		onMouseMove: React.PropTypes.func,           // pass-through mouse event
		onMouseOut: React.PropTypes.func,            // pass-through mouse event
		onKeyDown: React.PropTypes.func,             // pass-through key event
		onKeyUp: React.PropTypes.func,               // pass-through key event
	},

	getDefaultProps: function () {
		return {
			activeDelay: 0,
			moveThreshold: 100,
			pressDelay: 1000,
			pressMoveThreshold: 5
		};
	},

	getInitialState: function () {
		return {
			isActive: false,
			touchActive: false,
			pinchActive: false
		};
	},

	componentWillUnmount: function () {
		this.cleanupScrollDetection();
		this.cancelPressDetection();
		this.clearActiveTimeout();
	},

	processEvent: function (event) {
		if (this.props.preventDefault) event.preventDefault();
		if (this.props.stopPropagation) event.stopPropagation();
	},

	onTouchStart: function (event) {
		if (this.props.onTouchStart && this.props.onTouchStart(event) === false) return;
		this.processEvent(event);
		window._blockMouseEvents = true;
		if (event.touches.length === 1) {
			this._initialTouch = this._lastTouch = getTouchProps(event.touches[0]);
			this.initScrollDetection();
			this.initPressDetection(event, this.endTouch);
			this._activeTimeout = setTimeout(this.makeActive, this.props.activeDelay);
		} else if (this.onPinchStart &&
				(this.props.onPinchStart || this.props.onPinchMove || this.props.onPinchEnd) &&
				event.touches.length === 2) {
			this.onPinchStart(event);
		}
	},

	makeActive: function () {
		if (!this.isMounted()) return;
		this.clearActiveTimeout();
		this.setState({
			isActive: true
		});
	},

	clearActiveTimeout: function () {
		clearTimeout(this._activeTimeout);
		this._activeTimeout = false;
	},

	initScrollDetection: function () {
		this._scrollPos = { top: 0, left: 0 };
		this._scrollParents = [];
		this._scrollParentPos = [];
		var node = ReactDOM.findDOMNode(this);

		while (node) {
			if (node.scrollHeight > node.offsetHeight || node.scrollWidth > node.offsetWidth) {
				this._scrollParents.push(node);
				this._scrollParentPos.push(node.scrollTop + node.scrollLeft);
				this._scrollPos.top += node.scrollTop;
				this._scrollPos.left += node.scrollLeft;
			}

			node = node.parentNode;
		}
	},

	calculateMovement: function (touch) {
		return {
			x: Math.abs(touch.clientX - this._initialTouch.clientX),
			y: Math.abs(touch.clientY - this._initialTouch.clientY)
		};
	},

	detectScroll: function () {
		var currentScrollPos = { top: 0, left: 0 };
		for (var i = 0; i < this._scrollParents.length; i++) {
			currentScrollPos.top += this._scrollParents[i].scrollTop;
			currentScrollPos.left += this._scrollParents[i].scrollLeft;
		}
		return !(currentScrollPos.top === this._scrollPos.top && currentScrollPos.left === this._scrollPos.left);
	},

	cleanupScrollDetection: function () {
		this._scrollParents = undefined;
		this._scrollPos = undefined;
	},

	initPressDetection: function (event, callback) {
		if (!this.props.onPress) return;
		this._pressTimeout = setTimeout(function () {
			this.props.onPress(event);
			callback();
		}.bind(this), this.props.pressDelay);
	},

	cancelPressDetection: function () {
		clearTimeout(this._pressTimeout);
	},

	onTouchMove: function (event) {
		if (this._initialTouch) {
			this.processEvent(event);

			if (this.detectScroll()) return this.endTouch(event);

			this.props.onTouchMove && this.props.onTouchMove(event);
			this._lastTouch = getTouchProps(event.touches[0]);
			var movement = this.calculateMovement(this._lastTouch);
			if (movement.x > this.props.pressMoveThreshold || movement.y > this.props.pressMoveThreshold) {
				this.cancelPressDetection();
			}
			if (movement.x > this.props.moveThreshold || movement.y > this.props.moveThreshold) {
				if (this.state.isActive) {
					this.setState({
						isActive: false
					});
				} else if (this._activeTimeout) {
					this.clearActiveTimeout();
				}
			} else {
				if (!this.state.isActive && !this._activeTimeout) {
					this.setState({
						isActive: true
					});
				}
			}
		} else if (this._initialPinch && event.touches.length === 2 && this.onPinchMove) {
			this.onPinchMove(event);
			event.preventDefault();
		}
	},

	onTouchEnd: function (event) {
		if (this._initialTouch) {
			this.processEvent(event);
			var afterEndTouch;
			var movement = this.calculateMovement(this._lastTouch);
			if (movement.x <= this.props.moveThreshold && movement.y <= this.props.moveThreshold && this.props.onTap) {
				event.preventDefault();
				afterEndTouch = () => {
					var finalParentScrollPos = this._scrollParents.map(node => node.scrollTop + node.scrollLeft);
					var stoppedMomentumScroll = this._scrollParentPos.some((end, i) => {
						return end !== finalParentScrollPos[i];
					});
					if (!stoppedMomentumScroll) {
						this.props.onTap(event);
					}
				};
			}
			this.endTouch(event, afterEndTouch);
		} else if (this.onPinchEnd && this._initialPinch && (event.touches.length + event.changedTouches.length) === 2) {
			this.onPinchEnd(event);
			event.preventDefault();
		}
	},

	endTouch: function (event, callback) {
		this.cancelPressDetection();
		this.clearActiveTimeout();
		if (event && this.props.onTouchEnd) {
			this.props.onTouchEnd(event);
		}
		this._initialTouch = null;
		this._lastTouch = null;
		if (callback) {
			callback();
		}
		if (this.state.isActive) {
			this.setState({
				isActive: false
			});
		}
	},

	onMouseDown: function (event) {
		if (window._blockMouseEvents) {
			window._blockMouseEvents = false;
			return;
		}
		if (this.props.onMouseDown && this.props.onMouseDown(event) === false) return;
		this.processEvent(event);
		this.initPressDetection(event, this.endMouseEvent);
		this._mouseDown = true;
		this.setState({
			isActive: true
		});
	},

	onMouseMove: function (event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseMove && this.props.onMouseMove(event);
	},

	onMouseUp: function (event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseUp && this.props.onMouseUp(event);
		this.props.onTap && this.props.onTap(event);
		this.endMouseEvent();
	},

	onMouseOut: function (event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseOut && this.props.onMouseOut(event);
		this.endMouseEvent();
	},

	endMouseEvent: function () {
		this.cancelPressDetection();
		this._mouseDown = false;
		this.setState({
			isActive: false
		});
	},

	onKeyUp: function (event) {
		if (!this._keyDown) return;
		this.processEvent(event);
		this.props.onKeyUp && this.props.onKeyUp(event);
		this.props.onTap && this.props.onTap(event);

		this._keyDown = false;
		this.cancelPressDetection();
		this.setState({
			isActive: false
		});
	},

	onKeyDown: function (event) {
		if (this.props.onKeyDown && this.props.onKeyDown(event) === false) return;
		if (event.which !== SPACE_KEY && event.which !== ENTER_KEY) return;

		this.initPressDetection(event, this.endKeyEvent);
		this.processEvent(event);
		this._keyDown = true;
		this.setState({
			isActive: true
		});
	},

	endKeyEvent: function () {
		this.cancelPressDetection();
		this._keyDown = false;
		this.setState({
			isActive: false
		});
	},

	cancelTap: function () {
		this.endTouch();
		this._mouseDown = false;
	},

	handlers: function () {
		return {
			onTouchStart: this.onTouchStart,
			onTouchMove: this.onTouchMove,
			onTouchEnd: this.onTouchEnd,
			onMouseDown: this.onMouseDown,
			onMouseUp: this.onMouseUp,
			onMouseMove: this.onMouseMove,
			onMouseOut: this.onMouseOut,
			onKeyDown: this.onKeyDown,
			onKeyUp: this.onKeyUp,
		};
	}
};

module.exports = Mixin;
<commit_msg>Bailing from onKeyDown handler when key is already down, ref #67<commit_after>var React = require('react');
var ReactDOM = require('react-dom');

const SPACE_KEY = 32;
const ENTER_KEY = 13;

function getTouchProps (touch) {
	if (!touch) return {};
	return {
		pageX: touch.pageX,
		pageY: touch.pageY,
		clientX: touch.clientX,
		clientY: touch.clientY
	};
}

var Mixin = {
	propTypes: {
		moveThreshold: React.PropTypes.number,       // pixels to move before cancelling tap
		activeDelay: React.PropTypes.number,         // ms to wait before adding the `-active` class
		pressDelay: React.PropTypes.number,          // ms to wait before detecting a press
		pressMoveThreshold: React.PropTypes.number,  // pixels to move before cancelling press
		preventDefault: React.PropTypes.bool,        // whether to preventDefault on all events
		stopPropagation: React.PropTypes.bool,       // whether to stopPropagation on all events

		onTap: React.PropTypes.func,                 // fires when a tap is detected
		onPress: React.PropTypes.func,               // fires when a press is detected
		onTouchStart: React.PropTypes.func,          // pass-through touch event
		onTouchMove: React.PropTypes.func,           // pass-through touch event
		onTouchEnd: React.PropTypes.func,            // pass-through touch event
		onMouseDown: React.PropTypes.func,           // pass-through mouse event
		onMouseUp: React.PropTypes.func,             // pass-through mouse event
		onMouseMove: React.PropTypes.func,           // pass-through mouse event
		onMouseOut: React.PropTypes.func,            // pass-through mouse event
		onKeyDown: React.PropTypes.func,             // pass-through key event
		onKeyUp: React.PropTypes.func,               // pass-through key event
	},

	getDefaultProps: function () {
		return {
			activeDelay: 0,
			moveThreshold: 100,
			pressDelay: 1000,
			pressMoveThreshold: 5
		};
	},

	getInitialState: function () {
		return {
			isActive: false,
			touchActive: false,
			pinchActive: false
		};
	},

	componentWillUnmount: function () {
		this.cleanupScrollDetection();
		this.cancelPressDetection();
		this.clearActiveTimeout();
	},

	processEvent: function (event) {
		if (this.props.preventDefault) event.preventDefault();
		if (this.props.stopPropagation) event.stopPropagation();
	},

	onTouchStart: function (event) {
		if (this.props.onTouchStart && this.props.onTouchStart(event) === false) return;
		this.processEvent(event);
		window._blockMouseEvents = true;
		if (event.touches.length === 1) {
			this._initialTouch = this._lastTouch = getTouchProps(event.touches[0]);
			this.initScrollDetection();
			this.initPressDetection(event, this.endTouch);
			this._activeTimeout = setTimeout(this.makeActive, this.props.activeDelay);
		} else if (this.onPinchStart &&
				(this.props.onPinchStart || this.props.onPinchMove || this.props.onPinchEnd) &&
				event.touches.length === 2) {
			this.onPinchStart(event);
		}
	},

	makeActive: function () {
		if (!this.isMounted()) return;
		this.clearActiveTimeout();
		this.setState({
			isActive: true
		});
	},

	clearActiveTimeout: function () {
		clearTimeout(this._activeTimeout);
		this._activeTimeout = false;
	},

	initScrollDetection: function () {
		this._scrollPos = { top: 0, left: 0 };
		this._scrollParents = [];
		this._scrollParentPos = [];
		var node = ReactDOM.findDOMNode(this);

		while (node) {
			if (node.scrollHeight > node.offsetHeight || node.scrollWidth > node.offsetWidth) {
				this._scrollParents.push(node);
				this._scrollParentPos.push(node.scrollTop + node.scrollLeft);
				this._scrollPos.top += node.scrollTop;
				this._scrollPos.left += node.scrollLeft;
			}

			node = node.parentNode;
		}
	},

	calculateMovement: function (touch) {
		return {
			x: Math.abs(touch.clientX - this._initialTouch.clientX),
			y: Math.abs(touch.clientY - this._initialTouch.clientY)
		};
	},

	detectScroll: function () {
		var currentScrollPos = { top: 0, left: 0 };
		for (var i = 0; i < this._scrollParents.length; i++) {
			currentScrollPos.top += this._scrollParents[i].scrollTop;
			currentScrollPos.left += this._scrollParents[i].scrollLeft;
		}
		return !(currentScrollPos.top === this._scrollPos.top && currentScrollPos.left === this._scrollPos.left);
	},

	cleanupScrollDetection: function () {
		this._scrollParents = undefined;
		this._scrollPos = undefined;
	},

	initPressDetection: function (event, callback) {
		if (!this.props.onPress) return;
		this._pressTimeout = setTimeout(function () {
			this.props.onPress(event);
			callback();
		}.bind(this), this.props.pressDelay);
	},

	cancelPressDetection: function () {
		clearTimeout(this._pressTimeout);
	},

	onTouchMove: function (event) {
		if (this._initialTouch) {
			this.processEvent(event);

			if (this.detectScroll()) return this.endTouch(event);

			this.props.onTouchMove && this.props.onTouchMove(event);
			this._lastTouch = getTouchProps(event.touches[0]);
			var movement = this.calculateMovement(this._lastTouch);
			if (movement.x > this.props.pressMoveThreshold || movement.y > this.props.pressMoveThreshold) {
				this.cancelPressDetection();
			}
			if (movement.x > this.props.moveThreshold || movement.y > this.props.moveThreshold) {
				if (this.state.isActive) {
					this.setState({
						isActive: false
					});
				} else if (this._activeTimeout) {
					this.clearActiveTimeout();
				}
			} else {
				if (!this.state.isActive && !this._activeTimeout) {
					this.setState({
						isActive: true
					});
				}
			}
		} else if (this._initialPinch && event.touches.length === 2 && this.onPinchMove) {
			this.onPinchMove(event);
			event.preventDefault();
		}
	},

	onTouchEnd: function (event) {
		if (this._initialTouch) {
			this.processEvent(event);
			var afterEndTouch;
			var movement = this.calculateMovement(this._lastTouch);
			if (movement.x <= this.props.moveThreshold && movement.y <= this.props.moveThreshold && this.props.onTap) {
				event.preventDefault();
				afterEndTouch = () => {
					var finalParentScrollPos = this._scrollParents.map(node => node.scrollTop + node.scrollLeft);
					var stoppedMomentumScroll = this._scrollParentPos.some((end, i) => {
						return end !== finalParentScrollPos[i];
					});
					if (!stoppedMomentumScroll) {
						this.props.onTap(event);
					}
				};
			}
			this.endTouch(event, afterEndTouch);
		} else if (this.onPinchEnd && this._initialPinch && (event.touches.length + event.changedTouches.length) === 2) {
			this.onPinchEnd(event);
			event.preventDefault();
		}
	},

	endTouch: function (event, callback) {
		this.cancelPressDetection();
		this.clearActiveTimeout();
		if (event && this.props.onTouchEnd) {
			this.props.onTouchEnd(event);
		}
		this._initialTouch = null;
		this._lastTouch = null;
		if (callback) {
			callback();
		}
		if (this.state.isActive) {
			this.setState({
				isActive: false
			});
		}
	},

	onMouseDown: function (event) {
		if (window._blockMouseEvents) {
			window._blockMouseEvents = false;
			return;
		}
		if (this.props.onMouseDown && this.props.onMouseDown(event) === false) return;
		this.processEvent(event);
		this.initPressDetection(event, this.endMouseEvent);
		this._mouseDown = true;
		this.setState({
			isActive: true
		});
	},

	onMouseMove: function (event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseMove && this.props.onMouseMove(event);
	},

	onMouseUp: function (event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseUp && this.props.onMouseUp(event);
		this.props.onTap && this.props.onTap(event);
		this.endMouseEvent();
	},

	onMouseOut: function (event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseOut && this.props.onMouseOut(event);
		this.endMouseEvent();
	},

	endMouseEvent: function () {
		this.cancelPressDetection();
		this._mouseDown = false;
		this.setState({
			isActive: false
		});
	},

	onKeyUp: function (event) {
		if (!this._keyDown) return;
		this.processEvent(event);
		this.props.onKeyUp && this.props.onKeyUp(event);
		this.props.onTap && this.props.onTap(event);
		this._keyDown = false;
		this.cancelPressDetection();
		this.setState({
			isActive: false
		});
	},

	onKeyDown: function (event) {
		if (this.props.onKeyDown && this.props.onKeyDown(event) === false) return;
		if (event.which !== SPACE_KEY && event.which !== ENTER_KEY) return;
		if (this._keyDown) return;
		this.initPressDetection(event, this.endKeyEvent);
		this.processEvent(event);
		this._keyDown = true;
		this.setState({
			isActive: true
		});
	},

	endKeyEvent: function () {
		this.cancelPressDetection();
		this._keyDown = false;
		this.setState({
			isActive: false
		});
	},

	cancelTap: function () {
		this.endTouch();
		this._mouseDown = false;
	},

	handlers: function () {
		return {
			onTouchStart: this.onTouchStart,
			onTouchMove: this.onTouchMove,
			onTouchEnd: this.onTouchEnd,
			onMouseDown: this.onMouseDown,
			onMouseUp: this.onMouseUp,
			onMouseMove: this.onMouseMove,
			onMouseOut: this.onMouseOut,
			onKeyDown: this.onKeyDown,
			onKeyUp: this.onKeyUp,
		};
	}
};

module.exports = Mixin;
<|endoftext|>


<commit_before>var cheerio = require('cheerio')
  , request = require('request')
  , options = {
    url: 'http://www.charlestonpourhouse.com/schedule/',
    headers: {
      'User-Agent': 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us)' +
      ' AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7'
    }
  }
  , price = ''
  , time = ''
  , shows = []

function pourHouse(done) {
  request(options, function(err, response, body) {
    var $ = cheerio.load(body)
    $('.event-info-container').each(function(i, elem) {
      var $$ = cheerio.load(elem)
      $$('tr').each(function(t, el) {
        var key = $$(el).find('th').text().trim()
        if(key === 'Cover:') {
          price = $$(el).find('td').text()
        }
        if(key === 'Showtime:') {
          time = $$(el).find('td').text()
        }
      })
      show = {
        description: $$('.eventtitle').text().trim().split('\r').join('').split('\t').join(' '),
        url: $$('.eventtitle').children().attr('href'),
        date: $$('.eventdate').text().trim(),
        price: price,
        time: time
      }
      shows.push(show)
    })
    done(null, shows)
  })
}

module.exports = pourHouse(function(e,r){console.log(r)})
<commit_msg>clean logging<commit_after>var cheerio = require('cheerio')
  , request = require('request')
  , options = {
    url: 'http://www.charlestonpourhouse.com/schedule/',
    headers: {
      'User-Agent': 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us)' +
      ' AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7'
    }
  }
  , price = ''
  , time = ''
  , shows = []

function pourHouse(done) {
  request(options, function(err, response, body) {
    var $ = cheerio.load(body)
    $('.event-info-container').each(function(i, elem) {
      var $$ = cheerio.load(elem)
      $$('tr').each(function(t, el) {
        var key = $$(el).find('th').text().trim()
        if(key === 'Cover:') {
          price = $$(el).find('td').text()
        }
        if(key === 'Showtime:') {
          time = $$(el).find('td').text()
        }
      })
      show = {
        description: $$('.eventtitle').text().trim().split('\r').join('').split('\t').join(' '),
        url: $$('.eventtitle').children().attr('href'),
        date: $$('.eventdate').text().trim(),
        price: price,
        time: time
      }
      shows.push(show)
    })
    done(null, shows)
  })
}

module.exports = pourHouse
<|endoftext|>


<commit_before>import React from 'react'
import styled, { css } from 'styled-components'

import md from 'components/md'
import { Content } from 'components/Layout'

const AlignCenter = styled.div`
  text-align: center;
`

const Badge = styled.img`
  margin: 0 0.5em 3em;
  height: 1.5em;
`

const ExampleButton = styled.button`
  border-radius: 3px;
  padding: 0.25em 1em;
  margin: 0 1em;
  background: transparent;
  color: palevioletred;
  border: 2px solid palevioletred;

  ${p => p.primary && css`
    background: palevioletred;
    color: white;
  `}
`

const SecondButton = styled.button`
  border-radius: 3px;
  padding: 0.25em 1em;
  background: transparent;
  color: palevioletred;
  border: 2px solid palevioletred;
`

const HomepageGettingStarted = () => (
  <Content data-e2e-id="content">
    <AlignCenter>

        <Badge src="/proxy/stars.svg" alt="Stars on GitHub" />

        <Badge src="/proxy/npm-v.svg" alt="Current version" />

      <Badge src="/proxy/downloads.svg" alt="Monthly downloads" />
      <Badge src="/proxy/size.svg" alt="Gzipped size" />

        <Badge alt="Join the community on Spectrum" src="https://withspectrum.github.io/badge/badge.svg" />

    </AlignCenter>

    {md`
      # Getting started
      ## Installation

      To download styled-components run \`npm install --save styled-components\`.
      That's all you need to do, you are now ready to use it in your app! (yep, no build step needed 👌)

      ## Your first styled component

      Let's say you want to create a simple and reusable \`<Button />\` component that you can use throughout your application.
      There should be a normal version and a big and \`primary\` version for the important buttons.
      This is what it should look like when rendered: (this is a live example, click on them!)

      ${
      <AlignCenter>
        <ExampleButton onClick={() => { alert('You clicked the normal button!') }}>Normal button</ExampleButton>
        <ExampleButton primary onClick={() => { alert('You clicked the primary button!') }}>Primary button</ExampleButton>
      </AlignCenter>
      }

      First, let's import styled-components and create a \`styled.button\`:

      \`\`\`jsx
      import styled from 'styled-components';

      const Button = styled.button\`\`;
      \`\`\`

      This \`Button\` variable here is now a React component that you can use like any other React component!
      This unusual backtick syntax is a new JavaScript feature called a tagged template literal.
      You know how you can call functions with parenthesis? (\`myFunc()\`) Well, now you can also call functions with backticks!
      [here is an explanation](/docs/advanced#tagged-template-literals) of how that works exactly.

      If you render our lovely component now (just like any other component: \`<Button />\`) this is what you get:

      ${
      <AlignCenter>
        <button>I'm a <Button />!</button>
      </AlignCenter>
      }

      It renders a button! That's not a very nice button though 😕 we can do better than this,
      let's give it a bit of styling and tickle out the hidden beauty within!

      \`\`\`jsx
      const Button = styled.button\`
        border-radius: 3px;
        padding: 0.25em 1em;
        margin: 0 1em;
        background: transparent;
        color: palevioletred;
        border: 2px solid palevioletred;
      \`;
      \`\`\`

      ${
      <AlignCenter>
        <SecondButton>I'm a styled <Button /></SecondButton>
      </AlignCenter>
      }

      As you can see, styled-components lets you write actual CSS in your JavaScript. This means you can use all
      the features of CSS you use and love, including (but by far not limited to) media queries, all
      pseudo-selectors, nesting, etc. It also binds styles to components, which has some interesting properties.
      (learn more about [the ideas behind styled-components here](/docs/basics#motivation))

      The last step is that we need to define what a primary button looks like.
      To do that we also import \`{ css }\` from \`styled-components\` and interpolate a function into our template literal, which gets passed the props of our component:

      \`\`\`jsx
      import styled, { css } from styled-components

      const Button = styled.button\`
        border-radius: 3px;
        padding: 0.25em 1em;
        margin: 0 1em;
        background: transparent;
        color: palevioletred;
        border: 2px solid palevioletred;

        \${props => props.primary && css\`
          background: palevioletred;
          color: white;
        \`\}
      \`;
      \`\`\`

      All we're saying here is that when the \`primary\` property is set we want to add some more \`css\` to our component,
      in this case change the background and color.

      That's all, we're done! Take a look at our finished component:

      \`\`\`react
      const Button = styled.button\`
        border-radius: 3px;
        padding: 0.25em 1em;
        margin: 0 1em;
        background: transparent;
        color: palevioletred;
        border: 2px solid palevioletred;

        \${props => props.primary && css\`
          background: palevioletred;
          color: white;
        \`\}
      \`;

      render(

          <Button>Normal Button</Button>
          <Button primary>Primary Button</Button>

      );
      \`\`\`

      Nice 😍 That's a live updating editor too, so play around with it a bit to get a feel for what it's like to work with styled-components!

      Once you're done take a look at the [documentation](/docs), specifically the [Getting started](/docs/basics#getting-started) section! Enjoy ✨
    `}
  </Content>
)

export default HomepageGettingStarted
<commit_msg>Add quotes to import<commit_after>import React from 'react'
import styled, { css } from 'styled-components'

import md from 'components/md'
import { Content } from 'components/Layout'

const AlignCenter = styled.div`
  text-align: center;
`

const Badge = styled.img`
  margin: 0 0.5em 3em;
  height: 1.5em;
`

const ExampleButton = styled.button`
  border-radius: 3px;
  padding: 0.25em 1em;
  margin: 0 1em;
  background: transparent;
  color: palevioletred;
  border: 2px solid palevioletred;

  ${p => p.primary && css`
    background: palevioletred;
    color: white;
  `}
`

const SecondButton = styled.button`
  border-radius: 3px;
  padding: 0.25em 1em;
  background: transparent;
  color: palevioletred;
  border: 2px solid palevioletred;
`

const HomepageGettingStarted = () => (
  <Content data-e2e-id="content">
    <AlignCenter>

        <Badge src="/proxy/stars.svg" alt="Stars on GitHub" />

        <Badge src="/proxy/npm-v.svg" alt="Current version" />

      <Badge src="/proxy/downloads.svg" alt="Monthly downloads" />
      <Badge src="/proxy/size.svg" alt="Gzipped size" />

        <Badge alt="Join the community on Spectrum" src="https://withspectrum.github.io/badge/badge.svg" />

    </AlignCenter>

    {md`
      # Getting started
      ## Installation

      To download styled-components run \`npm install --save styled-components\`.
      That's all you need to do, you are now ready to use it in your app! (yep, no build step needed 👌)

      ## Your first styled component

      Let's say you want to create a simple and reusable \`<Button />\` component that you can use throughout your application.
      There should be a normal version and a big and \`primary\` version for the important buttons.
      This is what it should look like when rendered: (this is a live example, click on them!)

      ${
      <AlignCenter>
        <ExampleButton onClick={() => { alert('You clicked the normal button!') }}>Normal button</ExampleButton>
        <ExampleButton primary onClick={() => { alert('You clicked the primary button!') }}>Primary button</ExampleButton>
      </AlignCenter>
      }

      First, let's import styled-components and create a \`styled.button\`:

      \`\`\`jsx
      import styled from 'styled-components';

      const Button = styled.button\`\`;
      \`\`\`

      This \`Button\` variable here is now a React component that you can use like any other React component!
      This unusual backtick syntax is a new JavaScript feature called a tagged template literal.
      You know how you can call functions with parenthesis? (\`myFunc()\`) Well, now you can also call functions with backticks!
      [here is an explanation](/docs/advanced#tagged-template-literals) of how that works exactly.

      If you render our lovely component now (just like any other component: \`<Button />\`) this is what you get:

      ${
      <AlignCenter>
        <button>I'm a <Button />!</button>
      </AlignCenter>
      }

      It renders a button! That's not a very nice button though 😕 we can do better than this,
      let's give it a bit of styling and tickle out the hidden beauty within!

      \`\`\`jsx
      const Button = styled.button\`
        border-radius: 3px;
        padding: 0.25em 1em;
        margin: 0 1em;
        background: transparent;
        color: palevioletred;
        border: 2px solid palevioletred;
      \`;
      \`\`\`

      ${
      <AlignCenter>
        <SecondButton>I'm a styled <Button /></SecondButton>
      </AlignCenter>
      }

      As you can see, styled-components lets you write actual CSS in your JavaScript. This means you can use all
      the features of CSS you use and love, including (but by far not limited to) media queries, all
      pseudo-selectors, nesting, etc. It also binds styles to components, which has some interesting properties.
      (learn more about [the ideas behind styled-components here](/docs/basics#motivation))

      The last step is that we need to define what a primary button looks like.
      To do that we also import \`{ css }\` from \`styled-components\` and interpolate a function into our template literal, which gets passed the props of our component:

      \`\`\`jsx
      import styled, { css } from 'styled-components'

      const Button = styled.button\`
        border-radius: 3px;
        padding: 0.25em 1em;
        margin: 0 1em;
        background: transparent;
        color: palevioletred;
        border: 2px solid palevioletred;

        \${props => props.primary && css\`
          background: palevioletred;
          color: white;
        \`\}
      \`;
      \`\`\`

      All we're saying here is that when the \`primary\` property is set we want to add some more \`css\` to our component,
      in this case change the background and color.

      That's all, we're done! Take a look at our finished component:

      \`\`\`react
      const Button = styled.button\`
        border-radius: 3px;
        padding: 0.25em 1em;
        margin: 0 1em;
        background: transparent;
        color: palevioletred;
        border: 2px solid palevioletred;

        \${props => props.primary && css\`
          background: palevioletred;
          color: white;
        \`\}
      \`;

      render(

          <Button>Normal Button</Button>
          <Button primary>Primary Button</Button>

      );
      \`\`\`

      Nice 😍 That's a live updating editor too, so play around with it a bit to get a feel for what it's like to work with styled-components!

      Once you're done take a look at the [documentation](/docs), specifically the [Getting started](/docs/basics#getting-started) section! Enjoy ✨
    `}
  </Content>
)

export default HomepageGettingStarted
<|endoftext|>


<commit_before>import { FAILED_EXTERNAL_ACTION } from '../constants'

export function failedExternalAction ({ message, shortMessage, exception, action }) {
  if (exception) {
    message = message || (
      (exception['responseJSON'] && (exception.responseJSON.detail || exception.responseJSON.fault && exception.responseJSON.fault.detail))
        ? (exception.responseJSON.detail || exception.responseJSON.fault.detail)
        : (exception['statusText'] || 'UNKNOWN')
      )
    const type = exception['status'] ? exception['status'] : 'ERROR'
    return {
      type: FAILED_EXTERNAL_ACTION,
      payload: {
        message,
        shortMessage,
        type,
        action,
      },
    }
  }

  return {
    type: FAILED_EXTERNAL_ACTION,
    payload: {
      message,
      action,
    },
  }
}

export function loginFailed ({ errorCode, message }) {
  return {
    type: 'LOGIN_FAILED',
    payload: {
      errorCode,
      message,
    },
  }
}
<commit_msg>Error message retrieved from oVirt can be customized<commit_after>import { FAILED_EXTERNAL_ACTION } from '../constants'

function customizeErrorMessage (message) {
  const result = message.replace('Vm ', 'VM ')
  return result
}

export function failedExternalAction ({ message, shortMessage, exception, action }) {
  if (exception) {
    message = message || (
      (exception['responseJSON'] && (exception.responseJSON.detail || exception.responseJSON.fault && exception.responseJSON.fault.detail))
        ? (exception.responseJSON.detail || exception.responseJSON.fault.detail)
        : (exception['statusText'] || 'UNKNOWN')
      )
    message = customizeErrorMessage(message)

    const type = exception['status'] ? exception['status'] : 'ERROR'

    return {
      type: FAILED_EXTERNAL_ACTION,
      payload: {
        message,
        shortMessage,
        type,
        action,
      },
    }
  }

  return {
    type: FAILED_EXTERNAL_ACTION,
    payload: {
      message,
      action,
    },
  }
}

export function loginFailed ({ errorCode, message }) {
  return {
    type: 'LOGIN_FAILED',
    payload: {
      errorCode,
      message,
    },
  }
}
<|endoftext|>


<commit_before>import axios from 'axios';
import Auth from '../utils/Auth';
import { baseUrl } from '../config/config';

const authConfig = () => ({
    'Authorization': `bearer ${Auth.getToken()}`
});

const addGroups = (groups) => ({
    type: 'ADD_GROUPS',
    groups,
});

// GET_GROUPS
export const startGetGroups = () => {
    return (dispatch) => {
        axios.get(`${baseUrl}/api/groups`)
        .then((response) => {
            const groups = response.data;
            groups.map((group) => {
                group.groupId = group._id;
                delete group._id;
                group.cards.map((card) => {
                    card.cardId = card._id;
                    delete card._id;
                });
            });

            dispatch(addGroups(groups));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// ADD_GROUP
const addGroup = (group) => ({
    type: 'ADD_GROUP',
    group,
});

export const startAddGroup = (cardGroupData = {}) => {
    // works only after redux-thunk installed
    return (dispatch) => {
        const { title = 'Group Title', cards = [] } = cardGroupData;
        const cardGroup = { title, cards };
        axios.post(`${baseUrl}/api/groups`, cardGroup, {headers: authConfig()} )
        .then((response) => {
            dispatch(addGroup({
                ...cardGroup,
                groupId:response.data._id,
            }));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// EDIT_GROUP
const editGroup = (groupId, updates) => ({
    type: 'EDIT_GROUP',
    groupId,
    updates,
});

export const startEditGroup = (groupId, updates) => {
    return (dispatch) => {
        axios.post(`${baseUrl}/api/groups/${groupId}`, updates, {headers: authConfig()})
        .then(() => {
            dispatch(editGroup(groupId, updates));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// REMOVE_GROUP
const removeGroup = ({ groupId } = {}) => ({
    type: 'REMOVE_GROUP',
    groupId,
});

export const startRemoveGroup = ({ groupId } = {}) => {
    return (dispatch) => {
        axios.delete(`${baseUrl}/api/groups`, { params: { id: groupId }, headers: authConfig()})
        .then(() => {
            dispatch(removeGroup( { groupId }));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// ADD_CARD
const addCard = (groupId, card) => ({
    type: 'ADD_CARD',
    groupId,
    card,
});

export const startAddCard = (groupId, cardData = {}) => {
    return (dispatch) => {
        const { cardTitle = 'My card', dueDate = 0, description = '' } = cardData;
        const card = { cardTitle, dueDate, description };
        const data = {
            card,
            groupId,
        };
        axios.post(`${baseUrl}/api/cards`, data, {headers: authConfig()} )
        .then((response) => {
            dispatch(addCard(groupId, {
                ...card,
                cardId:response.data._id,
            }));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// EDIT_CARD
const editCard = (cardId, updates) => ({
    type: 'EDIT_CARD',
    cardId,
    updates,
});

export const startEditCard = (cardId, updates) => {
    return (dispatch) => {
        axios.post(`${baseUrl}/api/cards/${cardId}`, updates, {headers: authConfig()})
        .then(() => {
            dispatch(editCard(cardId, updates));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

//MOVE_CARD
export const moveCard = (newGroups) => ({
    type: 'MOVE_CARD',
    newGroups,
});

export const startMoveCard = (lastX, lastY, nextX, nextY) => {
    return (dispatch, getState) => {
        const newGroups = [...getState().groups];
        if (lastX === nextX) {
          newGroups[lastX].cards.splice(nextY, 0, newGroups[lastX].cards.splice(lastY, 1)[0]);
        } else {
          // move element to new place
          newGroups[nextX].cards.splice(nextY, 0, newGroups[lastX].cards[lastY]);
          // delete element from old place
          newGroups[lastX].cards.splice(lastY, 1);
        }
        // return newGroups;
        const newGroupsToServer = [ newGroups[lastX], newGroups[nextX] ].map((group) => {
            return {
                groupId: group.groupId,
                cards: group.cards.map((card) => card.cardId )
            };
        });
        axios.post(`${baseUrl}/api/groups/moveCards`, newGroupsToServer, {headers: authConfig()})
        .then(() => {
            dispatch(moveCard(newGroups));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// REMOVE_CARD
const removeCard = ({ cardId } = {}) => ({
    type: 'REMOVE_CARD',
    cardId,
});

export const startRemoveCard = ({ cardId } = {}) => {
    return (dispatch) => {
        axios.delete(`${baseUrl}/api/cards`, { params: { id: cardId }, headers: authConfig()})
        .then(() => {
            dispatch(removeCard( { cardId }));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};
<commit_msg>remove card ref from group when removing card<commit_after>import axios from 'axios';
import Auth from '../utils/Auth';
import { baseUrl } from '../config/config';

const authConfig = () => ({
    'Authorization': `bearer ${Auth.getToken()}`
});

const addGroups = (groups) => ({
    type: 'ADD_GROUPS',
    groups,
});

// GET_GROUPS
export const startGetGroups = () => {
    return (dispatch) => {
        axios.get(`${baseUrl}/api/groups`)
        .then((response) => {
            const groups = response.data;
            groups.map((group) => {
                group.groupId = group._id;
                delete group._id;
                group.cards.map((card) => {
                    card.cardId = card._id;
                    delete card._id;
                });
            });

            dispatch(addGroups(groups));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// ADD_GROUP
const addGroup = (group) => ({
    type: 'ADD_GROUP',
    group,
});

export const startAddGroup = (cardGroupData = {}) => {
    // works only after redux-thunk installed
    return (dispatch) => {
        const { title = 'Group Title', cards = [] } = cardGroupData;
        const cardGroup = { title, cards };
        axios.post(`${baseUrl}/api/groups`, cardGroup, {headers: authConfig()} )
        .then((response) => {
            dispatch(addGroup({
                ...cardGroup,
                groupId:response.data._id,
            }));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// EDIT_GROUP
const editGroup = (groupId, updates) => ({
    type: 'EDIT_GROUP',
    groupId,
    updates,
});

export const startEditGroup = (groupId, updates) => {
    return (dispatch) => {
        axios.post(`${baseUrl}/api/groups/${groupId}`, updates, {headers: authConfig()})
        .then(() => {
            dispatch(editGroup(groupId, updates));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// REMOVE_GROUP
const removeGroup = ({ groupId } = {}) => ({
    type: 'REMOVE_GROUP',
    groupId,
});

export const startRemoveGroup = ({ groupId } = {}) => {
    return (dispatch) => {
        axios.delete(`${baseUrl}/api/groups`, { params: { id: groupId }, headers: authConfig()})
        .then(() => {
            dispatch(removeGroup( { groupId }));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// ADD_CARD
const addCard = (groupId, card) => ({
    type: 'ADD_CARD',
    groupId,
    card,
});

export const startAddCard = (groupId, cardData = {}) => {
    return (dispatch) => {
        const { cardTitle = 'My card', dueDate = 0, description = '' } = cardData;
        const card = { cardTitle, dueDate, description, groupId, };
        const data = {
            card,
            groupId,
        };
        axios.post(`${baseUrl}/api/cards`, data, {headers: authConfig()} )
        .then((response) => {
            dispatch(addCard(groupId, {
                ...card,
                cardId:response.data._id,
            }));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// EDIT_CARD
const editCard = (cardId, updates) => ({
    type: 'EDIT_CARD',
    cardId,
    updates,
});

export const startEditCard = (cardId, updates) => {
    return (dispatch) => {
        axios.post(`${baseUrl}/api/cards/${cardId}`, updates, {headers: authConfig()})
        .then(() => {
            dispatch(editCard(cardId, updates));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

//MOVE_CARD
export const moveCard = (newGroups) => ({
    type: 'MOVE_CARD',
    newGroups,
});

export const startMoveCard = (lastX, lastY, nextX, nextY) => {
    return (dispatch, getState) => {
        const newGroups = [...getState().groups];
        if (lastX === nextX) {
          newGroups[lastX].cards.splice(nextY, 0, newGroups[lastX].cards.splice(lastY, 1)[0]);
        } else {
          // move element to new place
          newGroups[nextX].cards.splice(nextY, 0, newGroups[lastX].cards[lastY]);
          // delete element from old place
          newGroups[lastX].cards.splice(lastY, 1);
        }
        // return newGroups;
        const newGroupsToServer = [ newGroups[lastX], newGroups[nextX] ].map((group) => {
            return {
                groupId: group.groupId,
                cards: group.cards.map((card) => card.cardId )
            };
        });
        axios.post(`${baseUrl}/api/groups/moveCards`, newGroupsToServer, {headers: authConfig()})
        .then(() => {
            dispatch(moveCard(newGroups));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};

// REMOVE_CARD
const removeCard = ({ cardId } = {}) => ({
    type: 'REMOVE_CARD',
    cardId,
});

export const startRemoveCard = ({ cardId } = {}) => {
    return (dispatch) => {
        axios.delete(`${baseUrl}/api/cards`, { params: { id: cardId }, headers: authConfig()})
        .then(() => {
            dispatch(removeCard( { cardId }));
        })
        .catch((error) => {
            console.log(error);
        });
    };
};
<|endoftext|>


<commit_before>import request from 'superagent'

const url = 'http://localhost:3000'
const proj1 = '/v1/projects'

export const receiveProjects = (projects) => {
  return {
    type: 'RECEIVE_PROJECTS',
    projects: projects.map(project => project.data)
  }
}

export function getAllProjects (projects) {
  return (dispatch) => {
    return request
      .get(`https://crossorigin.me/${url}${proj1}`)
      .end((err, res) => {
        if (err) {
          res.send('Whoops! There was a problem!')
        }
        dispatch(receiveProjects(projects))
      })
  }
}
<commit_msg>added getAllBlogs action<commit_after>import request from 'superagent'

const url = 'http://localhost:3000'
const projV1 = '/v1/projects'
const blogV1 = '/v1/blogs'

export const receiveProjects = (projects) => {
  return {
    type: 'RECEIVE_PROJECTS',
    projects: projects.map(project => project.data)
  }
}

export function getAllProjects (projects) {
  return (dispatch) => {
    request
      .get(`${url}${projV1}`)
      .end((err, res) => {
        if (err) {
          res.send('Whoops! There was a problem!')
        }
        dispatch(receiveProjects(projects))
      })
  }
}

export const getAllBlogs = () => {
  return (dispatch) => {
    request
      .get(`${url}${blogV1}`)
      .end((err, res) => {
        if (err) {
          res.send('Whoops! There was a problem!')
        } else {
          return res.body.data
        }
      })
  }
}
<|endoftext|>


<commit_before>import querystring from 'querystring';
import transformMatch from './transformMatch';
import transformBenchmarks from './transformBenchmarks';
import transformCounts from './transformCounts';
import transformHistograms from './transformHistograms';
import transformTrends from './transformTrends';
import transformRankings from './transformRankings';
import transformPlayerMatches from './transformPlayerMatches';
import action from './action';
import { langs } from '../lang';
import { GITHUB_REPO } from '../config';

export const getMetadata = () => action('metadata', process.env.REACT_APP_API_HOST, 'api/metadata');
export const getMatch = matchId => action('match', process.env.REACT_APP_API_HOST, `api/matches/${matchId}`, {}, transformMatch);
export const getRanking = heroId => action('heroRanking', process.env.REACT_APP_API_HOST, 'api/rankings', { hero_id: heroId });
export const getBenchmark = heroId => action('heroBenchmark', process.env.REACT_APP_API_HOST, 'api/benchmarks', { hero_id: heroId }, transformBenchmarks);
export const getHeroRecentGames = heroId => action('heroRecentGames', process.env.REACT_APP_API_HOST, `api/heroes/${heroId}/matches`);
export const getHeroMatchups = heroId => action('heroMatchups', process.env.REACT_APP_API_HOST, `api/heroes/${heroId}/matchups`);
export const getHeroDurations = heroId => action('heroDurations', process.env.REACT_APP_API_HOST, `api/heroes/${heroId}/durations`);
export const getHeroPlayers = heroId => action('heroPlayers', process.env.REACT_APP_API_HOST, `api/heroes/${heroId}/players`);
export const getProPlayers = () => action('proPlayers', process.env.REACT_APP_API_HOST, 'api/proPlayers');
export const getProMatches = () => action('proMatches', process.env.REACT_APP_API_HOST, 'api/proMatches');
export const getPublicMatches = params => action('publicMatches', process.env.REACT_APP_API_HOST, 'api/publicMatches', params);
export const setSearchQuery = query => dispatch => dispatch(({
  type: 'QUERY/search',
  query,
}));
export const getSearchResult = query => action('search', process.env.REACT_APP_API_HOST, 'api/search', { q: query });
export const getSearchResultAndPros = query => dispatch => Promise.all([
  dispatch(setSearchQuery(query)),
  dispatch(getSearchResult(query)),
  dispatch(getProPlayers()),
  ...(/^\d+$/.test(query) ? [dispatch(getMatch(query))] : []),
]);
export const getDistributions = () => action('distributions', process.env.REACT_APP_API_HOST, 'api/distributions');
export const getPvgnaHeroGuides = () => action('pvgnaGuides', 'https://yasp.pvgna.com', 'yasp');
export const getHeroStats = params => action('heroStats', process.env.REACT_APP_API_HOST, 'api/heroStats', params);
export const getLeagues = () => action('leagues', process.env.REACT_APP_API_HOST, 'api/leagues');
export const getTeams = () => action('teams', process.env.REACT_APP_API_HOST, 'api/teams');
export const getTeam = teamId => action('team', process.env.REACT_APP_API_HOST, `api/teams/${teamId}`);
export const getTeamMatches = teamId => action('teamMatches', process.env.REACT_APP_API_HOST, `api/teams/${teamId}/matches`);
export const getTeamPlayers = teamId => action('teamPlayers', process.env.REACT_APP_API_HOST, `api/teams/${teamId}/players`);
export const getTeamHeroes = teamId => action('teamHeroes', process.env.REACT_APP_API_HOST, `api/teams/${teamId}/heroes`);
export const getRecords = field => action('records', process.env.REACT_APP_API_HOST, `api/records/${field}`);
export const getGithubPulls = merged => action('ghPulls', 'https://api.github.com', 'search/issues', {
  q: `repo:${GITHUB_REPO} type:pr base:production label:release merged:>${merged}`,
  order: 'desc',
  page: 1,
  per_page: 1,
});
export const getPlayer = accountId => action('player', process.env.REACT_APP_API_HOST, `api/players/${accountId}`);
export const getPlayerWinLoss = (accountId, params) => action('playerWinLoss', process.env.REACT_APP_API_HOST, `api/players/${accountId}/wl`, params);
export const getPlayerRecentMatches = (accountId, params) => action('playerRecentMatches', process.env.REACT_APP_API_HOST, `api/players/${accountId}/recentMatches`, params);
export const getPlayerMatches = (accountId, params) => action('playerMatches', process.env.REACT_APP_API_HOST, `api/players/${accountId}/matches`, { ...querystring.parse(params.substring(1)), significant: 0 }, transformPlayerMatches({ ...querystring.parse(params.substring(1)) }));
export const getPlayerPeers = (accountId, params) => action('playerPeers', process.env.REACT_APP_API_HOST, `api/players/${accountId}/peers`, params);
export const getPlayerHeroes = (accountId, params) => action('playerHeroes', process.env.REACT_APP_API_HOST, `api/players/${accountId}/heroes`, params);
export const getPlayerPros = (accountId, params) => action('playerPros', process.env.REACT_APP_API_HOST, `api/players/${accountId}/pros`, params);
export const getPlayerHistograms = (accountId, params, field) => action('playerHistograms', process.env.REACT_APP_API_HOST, `api/players/${accountId}/histograms/${field}`, params, transformHistograms);
export const getPlayerRecords = (accountId, params, field) => action('playerRecords', process.env.REACT_APP_API_HOST, `api/players/${accountId}/matches`, { ...querystring.parse(params.substring(1)), sort: field, limit: 20 });
export const getPlayerTrends = (accountId, params, field) => action('playerTrends', process.env.REACT_APP_API_HOST, `api/players/${accountId}/matches`, { ...querystring.parse(params.substring(1)), limit: 1000, project: [field, 'hero_id', 'start_time'] }, transformTrends(field));
export const getPlayerCounts = (accountId, params) => action('playerCounts', process.env.REACT_APP_API_HOST, `api/players/${accountId}/counts`, params, transformCounts);
export const getPlayerItems = (accountId, params) => action('playerItems', process.env.REACT_APP_API_HOST, `api/players/${accountId}/items`, params);
export const getPlayerWardmap = (accountId, params) => action('playerWardmap', process.env.REACT_APP_API_HOST, `api/players/${accountId}/wardmap`, params);
export const getPlayerWordcloud = (accountId, params) => action('playerWordcloud', process.env.REACT_APP_API_HOST, `api/players/${accountId}/wordcloud`, params);
export const getPlayerTotals = (accountId, params) => action('playerTotals', process.env.REACT_APP_API_HOST, `api/players/${accountId}/totals`, params);
export const getPlayerMmr = (accountId, params) => action('playerMmr', process.env.REACT_APP_API_HOST, `api/players/${accountId}/ratings`, params);
export const getPlayerRankings = (accountId, params) => action('playerRankings', process.env.REACT_APP_API_HOST, `api/players/${accountId}/rankings`, params, transformRankings);
export const getStrings = () => async (dispatch) => {
  const getLang = (lang) => langs.find(item => item.value === lang);
  const userLang = window.navigator.language;
  const defaultLang = getLang(userLang) || langs[0];
  const savedLang = window.localStorage && window.localStorage.getItem('localization');
  const selectedLang = getLang(savedLang) || defaultLang;
  const selData = await import(`../lang/${selectedLang.value}.json`);

  dispatch({ type: 'strings', payload: { ...selData } });
};
export const getAbilities = () => async (dispatch) => {
  dispatch({ type: 'abilities', payload: await import('dotaconstants/build/abilities.json') });
};
export const getHeroAbilities = () => async (dispatch) => {
  dispatch({ type: 'heroAbilities', payload: await import('dotaconstants/build/hero_abilities.json') });
};
export const getNeutralAbilities = () => async (dispatch) => {
  dispatch({ type: 'neutralAbilities', payload: await import('dotaconstants/build/neutral_abilities.json') });
};
export const getAbilityIds = () => async (dispatch) => {
  dispatch({ type: 'abilityIds', payload: await import('dotaconstants/build/ability_ids.json') });
};
export const getScenariosItemTimings = params => action('scenariosItemTimings', process.env.REACT_APP_API_HOST, 'api/scenarios/itemTimings', params);
export const getScenariosLaneRoles = params => action('scenariosLaneRoles', process.env.REACT_APP_API_HOST, 'api/scenarios/laneRoles', params);
export const getScenariosMisc = params => action('scenariosMisc', process.env.REACT_APP_API_HOST, 'api/scenarios/misc', params);
<commit_msg>rewrite get user language from navigator<commit_after>import querystring from 'querystring';
import transformMatch from './transformMatch';
import transformBenchmarks from './transformBenchmarks';
import transformCounts from './transformCounts';
import transformHistograms from './transformHistograms';
import transformTrends from './transformTrends';
import transformRankings from './transformRankings';
import transformPlayerMatches from './transformPlayerMatches';
import action from './action';
import { langs } from '../lang';
import { GITHUB_REPO } from '../config';

export const getMetadata = () => action('metadata', process.env.REACT_APP_API_HOST, 'api/metadata');
export const getMatch = matchId => action('match', process.env.REACT_APP_API_HOST, `api/matches/${matchId}`, {}, transformMatch);
export const getRanking = heroId => action('heroRanking', process.env.REACT_APP_API_HOST, 'api/rankings', { hero_id: heroId });
export const getBenchmark = heroId => action('heroBenchmark', process.env.REACT_APP_API_HOST, 'api/benchmarks', { hero_id: heroId }, transformBenchmarks);
export const getHeroRecentGames = heroId => action('heroRecentGames', process.env.REACT_APP_API_HOST, `api/heroes/${heroId}/matches`);
export const getHeroMatchups = heroId => action('heroMatchups', process.env.REACT_APP_API_HOST, `api/heroes/${heroId}/matchups`);
export const getHeroDurations = heroId => action('heroDurations', process.env.REACT_APP_API_HOST, `api/heroes/${heroId}/durations`);
export const getHeroPlayers = heroId => action('heroPlayers', process.env.REACT_APP_API_HOST, `api/heroes/${heroId}/players`);
export const getProPlayers = () => action('proPlayers', process.env.REACT_APP_API_HOST, 'api/proPlayers');
export const getProMatches = () => action('proMatches', process.env.REACT_APP_API_HOST, 'api/proMatches');
export const getPublicMatches = params => action('publicMatches', process.env.REACT_APP_API_HOST, 'api/publicMatches', params);
export const setSearchQuery = query => dispatch => dispatch(({
  type: 'QUERY/search',
  query,
}));
export const getSearchResult = query => action('search', process.env.REACT_APP_API_HOST, 'api/search', { q: query });
export const getSearchResultAndPros = query => dispatch => Promise.all([
  dispatch(setSearchQuery(query)),
  dispatch(getSearchResult(query)),
  dispatch(getProPlayers()),
  ...(/^\d+$/.test(query) ? [dispatch(getMatch(query))] : []),
]);
export const getDistributions = () => action('distributions', process.env.REACT_APP_API_HOST, 'api/distributions');
export const getPvgnaHeroGuides = () => action('pvgnaGuides', 'https://yasp.pvgna.com', 'yasp');
export const getHeroStats = params => action('heroStats', process.env.REACT_APP_API_HOST, 'api/heroStats', params);
export const getLeagues = () => action('leagues', process.env.REACT_APP_API_HOST, 'api/leagues');
export const getTeams = () => action('teams', process.env.REACT_APP_API_HOST, 'api/teams');
export const getTeam = teamId => action('team', process.env.REACT_APP_API_HOST, `api/teams/${teamId}`);
export const getTeamMatches = teamId => action('teamMatches', process.env.REACT_APP_API_HOST, `api/teams/${teamId}/matches`);
export const getTeamPlayers = teamId => action('teamPlayers', process.env.REACT_APP_API_HOST, `api/teams/${teamId}/players`);
export const getTeamHeroes = teamId => action('teamHeroes', process.env.REACT_APP_API_HOST, `api/teams/${teamId}/heroes`);
export const getRecords = field => action('records', process.env.REACT_APP_API_HOST, `api/records/${field}`);
export const getGithubPulls = merged => action('ghPulls', 'https://api.github.com', 'search/issues', {
  q: `repo:${GITHUB_REPO} type:pr base:production label:release merged:>${merged}`,
  order: 'desc',
  page: 1,
  per_page: 1,
});
export const getPlayer = accountId => action('player', process.env.REACT_APP_API_HOST, `api/players/${accountId}`);
export const getPlayerWinLoss = (accountId, params) => action('playerWinLoss', process.env.REACT_APP_API_HOST, `api/players/${accountId}/wl`, params);
export const getPlayerRecentMatches = (accountId, params) => action('playerRecentMatches', process.env.REACT_APP_API_HOST, `api/players/${accountId}/recentMatches`, params);
export const getPlayerMatches = (accountId, params) => action('playerMatches', process.env.REACT_APP_API_HOST, `api/players/${accountId}/matches`, { ...querystring.parse(params.substring(1)), significant: 0 }, transformPlayerMatches({ ...querystring.parse(params.substring(1)) }));
export const getPlayerPeers = (accountId, params) => action('playerPeers', process.env.REACT_APP_API_HOST, `api/players/${accountId}/peers`, params);
export const getPlayerHeroes = (accountId, params) => action('playerHeroes', process.env.REACT_APP_API_HOST, `api/players/${accountId}/heroes`, params);
export const getPlayerPros = (accountId, params) => action('playerPros', process.env.REACT_APP_API_HOST, `api/players/${accountId}/pros`, params);
export const getPlayerHistograms = (accountId, params, field) => action('playerHistograms', process.env.REACT_APP_API_HOST, `api/players/${accountId}/histograms/${field}`, params, transformHistograms);
export const getPlayerRecords = (accountId, params, field) => action('playerRecords', process.env.REACT_APP_API_HOST, `api/players/${accountId}/matches`, { ...querystring.parse(params.substring(1)), sort: field, limit: 20 });
export const getPlayerTrends = (accountId, params, field) => action('playerTrends', process.env.REACT_APP_API_HOST, `api/players/${accountId}/matches`, { ...querystring.parse(params.substring(1)), limit: 1000, project: [field, 'hero_id', 'start_time'] }, transformTrends(field));
export const getPlayerCounts = (accountId, params) => action('playerCounts', process.env.REACT_APP_API_HOST, `api/players/${accountId}/counts`, params, transformCounts);
export const getPlayerItems = (accountId, params) => action('playerItems', process.env.REACT_APP_API_HOST, `api/players/${accountId}/items`, params);
export const getPlayerWardmap = (accountId, params) => action('playerWardmap', process.env.REACT_APP_API_HOST, `api/players/${accountId}/wardmap`, params);
export const getPlayerWordcloud = (accountId, params) => action('playerWordcloud', process.env.REACT_APP_API_HOST, `api/players/${accountId}/wordcloud`, params);
export const getPlayerTotals = (accountId, params) => action('playerTotals', process.env.REACT_APP_API_HOST, `api/players/${accountId}/totals`, params);
export const getPlayerMmr = (accountId, params) => action('playerMmr', process.env.REACT_APP_API_HOST, `api/players/${accountId}/ratings`, params);
export const getPlayerRankings = (accountId, params) => action('playerRankings', process.env.REACT_APP_API_HOST, `api/players/${accountId}/rankings`, params, transformRankings);
export const getStrings = () => async (dispatch) => {
  const getLang = (lang) => langs.find(item => item.value === lang);
  const savedLang = window.localStorage && window.localStorage.getItem('localization');
  const userLang = window.navigator.language;
  const defaultLang = langs[0];
  const lang = getLang(savedLang) || getLang(userLang) || defaultLang;
  const data = await import(`../lang/${lang.value}.json`);

  dispatch({ type: 'strings', payload: { ...data } });
};
export const getAbilities = () => async (dispatch) => {
  dispatch({ type: 'abilities', payload: await import('dotaconstants/build/abilities.json') });
};
export const getHeroAbilities = () => async (dispatch) => {
  dispatch({ type: 'heroAbilities', payload: await import('dotaconstants/build/hero_abilities.json') });
};
export const getNeutralAbilities = () => async (dispatch) => {
  dispatch({ type: 'neutralAbilities', payload: await import('dotaconstants/build/neutral_abilities.json') });
};
export const getAbilityIds = () => async (dispatch) => {
  dispatch({ type: 'abilityIds', payload: await import('dotaconstants/build/ability_ids.json') });
};
export const getScenariosItemTimings = params => action('scenariosItemTimings', process.env.REACT_APP_API_HOST, 'api/scenarios/itemTimings', params);
export const getScenariosLaneRoles = params => action('scenariosLaneRoles', process.env.REACT_APP_API_HOST, 'api/scenarios/laneRoles', params);
export const getScenariosMisc = params => action('scenariosMisc', process.env.REACT_APP_API_HOST, 'api/scenarios/misc', params);
<|endoftext|>


<commit_before>
// An AttributeHandler object is responsible for updating a particular attribute
// of a particular element.  AttributeHandler subclasses implement
// browser-specific logic for dealing with particular attributes across
// different browsers.
//
// To define a new type of AttributeHandler, use
// `var FooHandler = AttributeHandler.extend({ update: function ... })`
// where the `update` function takes arguments `(element, oldValue, value)`.
// The `element` argument is always the same between calls to `update` on
// the same instance.  `oldValue` and `value` are each either `null` or
// a Unicode string of the type that might be passed to the value argument
// of `setAttribute` (i.e. not an HTML string with character references).
// When an AttributeHandler is installed, an initial call to `update` is
// always made with `oldValue = null`.  The `update` method can access
// `this.name` if the AttributeHandler class is a generic one that applies
// to multiple attribute names.
//
// AttributeHandlers can store custom properties on `this`, as long as they
// don't use the names `element`, `name`, `value`, and `oldValue`.
//
// AttributeHandlers can't influence how attributes appear in rendered HTML,
// only how they are updated after materialization as DOM.

AttributeHandler = function (name, value) {
  this.name = name;
  this.value = value;
};

AttributeHandler.prototype.update = function (element, oldValue, value) {
  if (value === null) {
    if (oldValue !== null)
      element.removeAttribute(this.name);
  } else {
    element.setAttribute(this.name, this.value);
  }
};

// _assign is like _.extend or the upcoming Object.assign.
// Copy src's own, enumerable properties onto tgt and return
// tgt.
var _assign = function (tgt, src) {
  for (var k in src)
    if (src.hasOwnProperty(k))
      tgt[k] = src[k];
  return tgt;
};

// return an array with the falsy elements removed
var _arrayCompact = function (array) {
  var result = [];
  for (var i = 0; i < array.length; i++) {
    var item = array[i];
    if (item)
      result.push(item);
  }
  return result;
};

var _arrayContains = function (array, item) {
  for (var i = 0; i < array.length; i++) {
    if (array[i] === item)
      return true;
  }
  return false;
};

var _arrayWithout = function (array, item) {
  var result = [];
  for (var i = 0; i < array.length; i++) {
    var x = array[i];
    if (x !== item)
      result.push(x);
  }
  return result;
};

AttributeHandler.extend = function (options) {
  var curType = this;
  var subType = function AttributeHandlerSubtype(/*arguments*/) {
    AttributeHandler.apply(this, arguments);
  };
  subType.prototype = new curType;
  subType.extend = curType.extend;
  if (options)
    _assign(subType.prototype, options);
  return subType;
};

// Extended below to support both regular and SVG elements
var BaseClassHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    if (!this.getCurrentValue || !this.setValue)
      throw new Error("Missing methods in subclass of 'BaseClassHandler'");

    var oldClasses = oldValue ? _arrayCompact(oldValue.split(' ')) : [];
    var newClasses = value ? _arrayCompact(value.split(' ')) : [];

    // the current classes on the element, which we will mutate.
    var classes = _arrayCompact(this.getCurrentValue(element).split(' '));

    // optimize this later (to be asymptotically faster) if necessary
    for (var i = 0; i < oldClasses.length; i++) {
      var c = oldClasses[i];
      if (! _arrayContains(newClasses, c))
        classes = _arrayWithout(classes, c);
    }
    for (var i = 0; i < newClasses.length; i++) {
      var c = newClasses[i];
      if ((! _arrayContains(oldClasses, c)) &&
          (! _arrayContains(classes, c)))
        classes.push(c);
    }

    this.setValue(element, classes.join(' '));
  }
});

var ClassHandler = BaseClassHandler.extend({
  // @param rawValue {String}
  getCurrentValue: function (element) {
    return element.className;
  },
  setValue: function (element, className) {
    element.className = className;
  }
});

var SVGClassHandler = BaseClassHandler.extend({
  getCurrentValue: function (element) {
    return element.className.baseVal;
  },
  setValue: function (element, className) {
    element.setAttribute('class', className);
  }
});

var BooleanHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    var focused = this.focused(element);

    if (!focused) {
      var name = this.name;
      if (value == null) {
        if (oldValue != null)
          element[name] = false;
      } else {
        element[name] = true;
      }
    }
  },
  // is the element part of a control which is focused?
  focused: function (element) {
    if (element.tagName === 'INPUT') {
      return element === document.activeElement;

    } else if (element.tagName === 'OPTION') {
      // find the containing SELECT element, on which focus
      // is actually set
      var selectEl = element;
      while (selectEl && selectEl.tagName !== 'SELECT')
        selectEl = selectEl.parentNode;

      if (selectEl)
        return selectEl === document.activeElement;
      else
        return false;
    } else {
      throw new Error("Expected INPUT or OPTION element");
    }
  }
});

var ValueHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    var focused = (element === document.activeElement);

    if (!focused)
      element.value = value;
  }
});

// attributes of the type 'xlink:something' should be set using
// the correct namespace in order to work
var XlinkHandler = AttributeHandler.extend({
  update: function(element, oldValue, value) {
    var NS = 'http://www.w3.org/1999/xlink';
    if (value === null) {
      if (oldValue !== null)
        element.removeAttributeNS(NS, this.name);
    } else {
      element.setAttributeNS(NS, this.name, this.value);
    }
  }
});

// cross-browser version of `instanceof SVGElement`
var isSVGElement = function (elem) {
  return 'ownerSVGElement' in elem;
};

// XXX make it possible for users to register attribute handlers!
makeAttributeHandler = function (elem, name, value) {
  // generally, use setAttribute but certain attributes need to be set
  // by directly setting a JavaScript property on the DOM element.
  if (name === 'class') {
    if (isSVGElement(elem)) {
      return new SVGClassHandler(name, value);
    } else {
      return new ClassHandler(name, value);
    }
  } else if ((elem.tagName === 'OPTION' && name === 'selected') ||
             (elem.tagName === 'INPUT' && name === 'checked')) {
    return new BooleanHandler(name, value);
  } else if ((elem.tagName === 'TEXTAREA' || elem.tagName === 'INPUT')
             && name === 'value') {
    // internally, TEXTAREAs tracks their value in the 'value'
    // attribute just like INPUTs.
    return new ValueHandler(name, value);
  } else if (name.substring(0,6) === 'xlink:') {
    return new XlinkHandler(name.substring(6), value);
  } else {
    return new AttributeHandler(name, value);
  }

  // XXX will need one for 'style' on IE, though modern browsers
  // seem to handle setAttribute ok.
};

ElementAttributesUpdater = function (elem) {
  this.elem = elem;
  this.handlers = {};
};

// Update attributes on `elem` to the dictionary `attrs`, whose
// values are strings.
ElementAttributesUpdater.prototype.update = function(newAttrs) {
  var elem = this.elem;
  var handlers = this.handlers;

  for (var k in handlers) {
    if (! newAttrs.hasOwnProperty(k)) {
      // remove attributes (and handlers) for attribute names
      // that don't exist as keys of `newAttrs` and so won't
      // be visited when traversing it.  (Attributes that
      // exist in the `newAttrs` object but are `null`
      // are handled later.)
      var handler = handlers[k];
      var oldValue = handler.value;
      handler.value = null;
      handler.update(elem, oldValue, null);
      delete handlers[k];
    }
  }

  for (var k in newAttrs) {
    var handler = null;
    var oldValue;
    var value = newAttrs[k];
    if (! handlers.hasOwnProperty(k)) {
      if (value !== null) {
        // make new handler
        handler = makeAttributeHandler(elem, k, value);
        handlers[k] = handler;
        oldValue = null;
      }
    } else {
      handler = handlers[k];
      oldValue = handler.value;
    }
    if (oldValue !== value) {
      handler.value = value;
      handler.update(elem, oldValue, value);
      if (value === null)
        delete handlers[k];
    }
  }
};
<commit_msg>Minor (no-op) change<commit_after>
// An AttributeHandler object is responsible for updating a particular attribute
// of a particular element.  AttributeHandler subclasses implement
// browser-specific logic for dealing with particular attributes across
// different browsers.
//
// To define a new type of AttributeHandler, use
// `var FooHandler = AttributeHandler.extend({ update: function ... })`
// where the `update` function takes arguments `(element, oldValue, value)`.
// The `element` argument is always the same between calls to `update` on
// the same instance.  `oldValue` and `value` are each either `null` or
// a Unicode string of the type that might be passed to the value argument
// of `setAttribute` (i.e. not an HTML string with character references).
// When an AttributeHandler is installed, an initial call to `update` is
// always made with `oldValue = null`.  The `update` method can access
// `this.name` if the AttributeHandler class is a generic one that applies
// to multiple attribute names.
//
// AttributeHandlers can store custom properties on `this`, as long as they
// don't use the names `element`, `name`, `value`, and `oldValue`.
//
// AttributeHandlers can't influence how attributes appear in rendered HTML,
// only how they are updated after materialization as DOM.

AttributeHandler = function (name, value) {
  this.name = name;
  this.value = value;
};

AttributeHandler.prototype.update = function (element, oldValue, value) {
  if (value === null) {
    if (oldValue !== null)
      element.removeAttribute(this.name);
  } else {
    element.setAttribute(this.name, value);
  }
};

// _assign is like _.extend or the upcoming Object.assign.
// Copy src's own, enumerable properties onto tgt and return
// tgt.
var _assign = function (tgt, src) {
  for (var k in src)
    if (src.hasOwnProperty(k))
      tgt[k] = src[k];
  return tgt;
};

// return an array with the falsy elements removed
var _arrayCompact = function (array) {
  var result = [];
  for (var i = 0; i < array.length; i++) {
    var item = array[i];
    if (item)
      result.push(item);
  }
  return result;
};

var _arrayContains = function (array, item) {
  for (var i = 0; i < array.length; i++) {
    if (array[i] === item)
      return true;
  }
  return false;
};

var _arrayWithout = function (array, item) {
  var result = [];
  for (var i = 0; i < array.length; i++) {
    var x = array[i];
    if (x !== item)
      result.push(x);
  }
  return result;
};

AttributeHandler.extend = function (options) {
  var curType = this;
  var subType = function AttributeHandlerSubtype(/*arguments*/) {
    AttributeHandler.apply(this, arguments);
  };
  subType.prototype = new curType;
  subType.extend = curType.extend;
  if (options)
    _assign(subType.prototype, options);
  return subType;
};

// Extended below to support both regular and SVG elements
var BaseClassHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    if (!this.getCurrentValue || !this.setValue)
      throw new Error("Missing methods in subclass of 'BaseClassHandler'");

    var oldClasses = oldValue ? _arrayCompact(oldValue.split(' ')) : [];
    var newClasses = value ? _arrayCompact(value.split(' ')) : [];

    // the current classes on the element, which we will mutate.
    var classes = _arrayCompact(this.getCurrentValue(element).split(' '));

    // optimize this later (to be asymptotically faster) if necessary
    for (var i = 0; i < oldClasses.length; i++) {
      var c = oldClasses[i];
      if (! _arrayContains(newClasses, c))
        classes = _arrayWithout(classes, c);
    }
    for (var i = 0; i < newClasses.length; i++) {
      var c = newClasses[i];
      if ((! _arrayContains(oldClasses, c)) &&
          (! _arrayContains(classes, c)))
        classes.push(c);
    }

    this.setValue(element, classes.join(' '));
  }
});

var ClassHandler = BaseClassHandler.extend({
  // @param rawValue {String}
  getCurrentValue: function (element) {
    return element.className;
  },
  setValue: function (element, className) {
    element.className = className;
  }
});

var SVGClassHandler = BaseClassHandler.extend({
  getCurrentValue: function (element) {
    return element.className.baseVal;
  },
  setValue: function (element, className) {
    element.setAttribute('class', className);
  }
});

var BooleanHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    var focused = this.focused(element);

    if (!focused) {
      var name = this.name;
      if (value == null) {
        if (oldValue != null)
          element[name] = false;
      } else {
        element[name] = true;
      }
    }
  },
  // is the element part of a control which is focused?
  focused: function (element) {
    if (element.tagName === 'INPUT') {
      return element === document.activeElement;

    } else if (element.tagName === 'OPTION') {
      // find the containing SELECT element, on which focus
      // is actually set
      var selectEl = element;
      while (selectEl && selectEl.tagName !== 'SELECT')
        selectEl = selectEl.parentNode;

      if (selectEl)
        return selectEl === document.activeElement;
      else
        return false;
    } else {
      throw new Error("Expected INPUT or OPTION element");
    }
  }
});

var ValueHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    var focused = (element === document.activeElement);

    if (!focused)
      element.value = value;
  }
});

// attributes of the type 'xlink:something' should be set using
// the correct namespace in order to work
var XlinkHandler = AttributeHandler.extend({
  update: function(element, oldValue, value) {
    var NS = 'http://www.w3.org/1999/xlink';
    if (value === null) {
      if (oldValue !== null)
        element.removeAttributeNS(NS, this.name);
    } else {
      element.setAttributeNS(NS, this.name, this.value);
    }
  }
});

// cross-browser version of `instanceof SVGElement`
var isSVGElement = function (elem) {
  return 'ownerSVGElement' in elem;
};

// XXX make it possible for users to register attribute handlers!
makeAttributeHandler = function (elem, name, value) {
  // generally, use setAttribute but certain attributes need to be set
  // by directly setting a JavaScript property on the DOM element.
  if (name === 'class') {
    if (isSVGElement(elem)) {
      return new SVGClassHandler(name, value);
    } else {
      return new ClassHandler(name, value);
    }
  } else if ((elem.tagName === 'OPTION' && name === 'selected') ||
             (elem.tagName === 'INPUT' && name === 'checked')) {
    return new BooleanHandler(name, value);
  } else if ((elem.tagName === 'TEXTAREA' || elem.tagName === 'INPUT')
             && name === 'value') {
    // internally, TEXTAREAs tracks their value in the 'value'
    // attribute just like INPUTs.
    return new ValueHandler(name, value);
  } else if (name.substring(0,6) === 'xlink:') {
    return new XlinkHandler(name.substring(6), value);
  } else {
    return new AttributeHandler(name, value);
  }

  // XXX will need one for 'style' on IE, though modern browsers
  // seem to handle setAttribute ok.
};

ElementAttributesUpdater = function (elem) {
  this.elem = elem;
  this.handlers = {};
};

// Update attributes on `elem` to the dictionary `attrs`, whose
// values are strings.
ElementAttributesUpdater.prototype.update = function(newAttrs) {
  var elem = this.elem;
  var handlers = this.handlers;

  for (var k in handlers) {
    if (! newAttrs.hasOwnProperty(k)) {
      // remove attributes (and handlers) for attribute names
      // that don't exist as keys of `newAttrs` and so won't
      // be visited when traversing it.  (Attributes that
      // exist in the `newAttrs` object but are `null`
      // are handled later.)
      var handler = handlers[k];
      var oldValue = handler.value;
      handler.value = null;
      handler.update(elem, oldValue, null);
      delete handlers[k];
    }
  }

  for (var k in newAttrs) {
    var handler = null;
    var oldValue;
    var value = newAttrs[k];
    if (! handlers.hasOwnProperty(k)) {
      if (value !== null) {
        // make new handler
        handler = makeAttributeHandler(elem, k, value);
        handlers[k] = handler;
        oldValue = null;
      }
    } else {
      handler = handlers[k];
      oldValue = handler.value;
    }
    if (oldValue !== value) {
      handler.value = value;
      handler.update(elem, oldValue, value);
      if (value === null)
        delete handlers[k];
    }
  }
};
<|endoftext|>