<commit_before>const React = require('react');
const { Container } = require('elemental');
const xhr = require('xhr');
const { plural } = require('../utils');
const Footer = require('../components/Footer');
const PrimaryNavigation = require('../components/PrimaryNavigation');
const MobileNavigation = require('../components/MobileNavigation');

const ICON_TAGS_BOOK = ['books', 'posts', 'blog', 'blog-posts', 'stories', 'news-stories', 'content'];
const ICON_TAGS_BRIEFCASE = ['businesses', 'companies', 'listings', 'organizations', 'partners'];
const ICON_TAGS_CALENDAR = ['events', 'dates'];
const ICON_TAGS_CLOCK = ['classes', 'hours', 'times'];
const ICON_TAGS_FILE_MEDIA = ['gallery', 'galleries', 'images', 'photos', 'pictures'];
const ICON_TAGS_FILE_TEXT = ['attachments', 'docs', 'documents', 'files'];
const ICON_TAGS_LOCATION = ['locations', 'markers', 'places'];
const ICON_TAGS_MAIL = ['emails', 'enquiries'];
const ICON_TAGS_MEGAPHONE = ['broadcasts', 'jobs', 'talks'];
const ICON_TAGS_ORGANIZATION = ['contacts', 'customers', 'groups', 'members', 'people', 'speakers', 'teams', 'users'];
const ICON_TAGS_PACKAGE = ['boxes', 'items', 'packages', 'parcels'];
const ICON_TAGS_TAG = ['tags'];

var listsByKey = {};
Keystone.lists.forEach((list) => {
	listsByKey[list.key] = list;
});

var ListTile = React.createClass({
	propTypes: {
		count: React.PropTypes.string,
		href: React.PropTypes.string,
		label: React.PropTypes.string,
	},
	render () {
		return (

{this.props.label}

{this.props.count}

		);
	},
});

var View = React.createClass({

	displayName: 'HomeView',

	getInitialState () {
		return {
			counts: {}
		};
	},

	componentDidMount () {
		this.loadCounts();
	},

	loadCounts () {
		xhr({
			url: '/keystone/api/counts'
		}, (err, resp, body) => {
			try {
				body = JSON.parse(body);
			} catch(e) {
				console.log('Error parsing results json:', e, body);
				return;
			}
			if (body && body.counts) {
				if (!this.isMounted()) return;
				this.setState({
					counts: body.counts
				});
			}
		});
	},

	renderFlatNav () {
		let lists = this.props.navLists.map((list) => {
			var href = list.external ? list.path : '/keystone/' + list.path;
			return <ListTile key={list.path} label={list.label} href={href} count={plural(this.state.counts[list.key], '* Item', '* Items')} />;
		});

		return
{lists}
;
	},

	renderGroupedNav () {
		return (

				{this.props.navSections.map((navSection) => {
					var headingIconClass = 'dashboard-group__heading-icon octicon octicon-';

					if (ICON_TAGS_BRIEFCASE.indexOf(navSection.key) !== -1) { headingIconClass += 'briefcase'; }
					else if (ICON_TAGS_BOOK.indexOf(navSection.key) !== -1) { headingIconClass += 'book'; }
					else if (ICON_TAGS_CALENDAR.indexOf(navSection.key) !== -1) { headingIconClass += 'calendar'; }
					else if (ICON_TAGS_CLOCK.indexOf(navSection.key) !== -1) { headingIconClass += 'clock'; }
					else if (ICON_TAGS_FILE_MEDIA.indexOf(navSection.key) !== -1) { headingIconClass += 'file-media'; }
					else if (ICON_TAGS_FILE_TEXT.indexOf(navSection.key) !== -1) { headingIconClass += 'file-text'; }
					else if (ICON_TAGS_LOCATION.indexOf(navSection.key) !== -1) { headingIconClass += 'location'; }
					else if (ICON_TAGS_MAIL.indexOf(navSection.key) !== -1) { headingIconClass += 'mail'; }
					else if (ICON_TAGS_MEGAPHONE.indexOf(navSection.key) !== -1) { headingIconClass += 'megaphone'; }
					else if (ICON_TAGS_ORGANIZATION.indexOf(navSection.key) !== -1) { headingIconClass += 'organization'; }
					else if (ICON_TAGS_PACKAGE.indexOf(navSection.key) !== -1) { headingIconClass += 'package'; }
					else if (ICON_TAGS_TAG.indexOf(navSection.key) !== -1) { headingIconClass += 'tag'; }
					else { headingIconClass += 'primitive-dot'; }

					return (

								{navSection.label}

								{navSection.lists.map((list) => {
									var href = list.external ? list.path : '/keystone/' + list.path;
									return <ListTile key={list.path} label={list.label} href={href} count={plural(this.state.counts[list.key], '* Item', '* Items')} />;
								})}

					);
				})}
				{() => {
					if (!this.props.orphanedLists.length) return;
					return (

								Other

								{this.props.orphanedLists.map((list) => {
									var href = list.external ? list.path : '/keystone/' + list.path;
									return <ListTile key={list.path} label={list.label} href={href} count={plural(this.state.counts[list.key], '* Item', '* Items')} />;
								})}

					);
				}()}

		);
	},

	render () {
		return (

					<MobileNavigation
						brand={Keystone.brand}
						currentSectionKey="dashboard"
						sections={Keystone.nav.sections}
						signoutUrl={Keystone.signoutUrl}
						/>
					<PrimaryNavigation
						brand={Keystone.brand}
						currentSectionKey="dashboard"
						sections={Keystone.nav.sections}
						signoutUrl={Keystone.signoutUrl}
						/>

					<Container>

{this.props.brand}

							{this.props.navIsFlat ? this.renderFlatNav() : this.renderGroupedNav()}

					</Container>

		);
	}

});

React.render(<View
		brand={Keystone.brand}
		navIsFlat={Keystone.nav.flat}
		navLists={Keystone.lists}
		navSections={Keystone.nav.sections}
		orphanedLists={Keystone.orphanedLists}
	/>, document.getElementById('home-view'));
<commit_msg>home view: move keystone vars to properties on the view component<commit_after>const React = require('react');
const { Container } = require('elemental');
const xhr = require('xhr');
const { plural } = require('../utils');
const Footer = require('../components/Footer');
const MobileNavigation = require('../components/MobileNavigation');
const PrimaryNavigation = require('../components/PrimaryNavigation');

const ICON_TAGS_BOOK = ['books', 'posts', 'blog', 'blog-posts', 'stories', 'news-stories', 'content'];
const ICON_TAGS_BRIEFCASE = ['businesses', 'companies', 'listings', 'organizations', 'partners'];
const ICON_TAGS_CALENDAR = ['events', 'dates'];
const ICON_TAGS_CLOCK = ['classes', 'hours', 'times'];
const ICON_TAGS_FILE_MEDIA = ['gallery', 'galleries', 'images', 'photos', 'pictures'];
const ICON_TAGS_FILE_TEXT = ['attachments', 'docs', 'documents', 'files'];
const ICON_TAGS_LOCATION = ['locations', 'markers', 'places'];
const ICON_TAGS_MAIL = ['emails', 'enquiries'];
const ICON_TAGS_MEGAPHONE = ['broadcasts', 'jobs', 'talks'];
const ICON_TAGS_ORGANIZATION = ['contacts', 'customers', 'groups', 'members', 'people', 'speakers', 'teams', 'users'];
const ICON_TAGS_PACKAGE = ['boxes', 'items', 'packages', 'parcels'];
const ICON_TAGS_TAG = ['tags'];

var listsByKey = {};
Keystone.lists.forEach((list) => {
	listsByKey[list.key] = list;
});

var ListTile = React.createClass({
	propTypes: {
		count: React.PropTypes.string,
		href: React.PropTypes.string,
		label: React.PropTypes.string,
	},
	render () {
		return (

{this.props.label}

{this.props.count}

		);
	},
});

var View = React.createClass({

	displayName: 'HomeView',

	getInitialState () {
		return {
			counts: {}
		};
	},

	componentDidMount () {
		this.loadCounts();
	},

	loadCounts () {
		xhr({
			url: '/keystone/api/counts'
		}, (err, resp, body) => {
			try {
				body = JSON.parse(body);
			} catch(e) {
				console.log('Error parsing results json:', e, body);
				return;
			}
			if (body && body.counts) {
				if (!this.isMounted()) return;
				this.setState({
					counts: body.counts
				});
			}
		});
	},

	renderFlatNav () {
		let lists = this.props.navLists.map((list) => {
			var href = list.external ? list.path : '/keystone/' + list.path;
			return <ListTile key={list.path} label={list.label} href={href} count={plural(this.state.counts[list.key], '* Item', '* Items')} />;
		});

		return
{lists}
;
	},

	renderGroupedNav () {
		return (

				{this.props.navSections.map((navSection) => {
					var headingIconClass = 'dashboard-group__heading-icon octicon octicon-';

					if (ICON_TAGS_BRIEFCASE.indexOf(navSection.key) !== -1) { headingIconClass += 'briefcase'; }
					else if (ICON_TAGS_BOOK.indexOf(navSection.key) !== -1) { headingIconClass += 'book'; }
					else if (ICON_TAGS_CALENDAR.indexOf(navSection.key) !== -1) { headingIconClass += 'calendar'; }
					else if (ICON_TAGS_CLOCK.indexOf(navSection.key) !== -1) { headingIconClass += 'clock'; }
					else if (ICON_TAGS_FILE_MEDIA.indexOf(navSection.key) !== -1) { headingIconClass += 'file-media'; }
					else if (ICON_TAGS_FILE_TEXT.indexOf(navSection.key) !== -1) { headingIconClass += 'file-text'; }
					else if (ICON_TAGS_LOCATION.indexOf(navSection.key) !== -1) { headingIconClass += 'location'; }
					else if (ICON_TAGS_MAIL.indexOf(navSection.key) !== -1) { headingIconClass += 'mail'; }
					else if (ICON_TAGS_MEGAPHONE.indexOf(navSection.key) !== -1) { headingIconClass += 'megaphone'; }
					else if (ICON_TAGS_ORGANIZATION.indexOf(navSection.key) !== -1) { headingIconClass += 'organization'; }
					else if (ICON_TAGS_PACKAGE.indexOf(navSection.key) !== -1) { headingIconClass += 'package'; }
					else if (ICON_TAGS_TAG.indexOf(navSection.key) !== -1) { headingIconClass += 'tag'; }
					else { headingIconClass += 'primitive-dot'; }

					return (

								{navSection.label}

								{navSection.lists.map((list) => {
									var href = list.external ? list.path : '/keystone/' + list.path;
									return <ListTile key={list.path} label={list.label} href={href} count={plural(this.state.counts[list.key], '* Item', '* Items')} />;
								})}

					);
				})}
				{() => {
					if (!this.props.orphanedLists.length) return;
					return (

								Other

								{this.props.orphanedLists.map((list) => {
									var href = list.external ? list.path : '/keystone/' + list.path;
									return <ListTile key={list.path} label={list.label} href={href} count={plural(this.state.counts[list.key], '* Item', '* Items')} />;
								})}

					);
				}()}

		);
	},

	render () {
		return (

					<MobileNavigation
						brand={this.props.brand}
						currentSectionKey="dashboard"
						sections={this.props.nav.sections}
						signoutUrl={this.props.signoutUrl}
						/>
					<PrimaryNavigation
						brand={this.props.brand}
						currentSectionKey="dashboard"
						sections={this.props.nav.sections}
						signoutUrl={this.props.signoutUrl}
						/>

					<Container>

{this.props.brand}

							{this.props.navIsFlat ? this.renderFlatNav() : this.renderGroupedNav()}

					</Container>

		);
	}

});

React.render(
	<View
		appversion={Keystone.appversion}
		backUrl={Keystone.backUrl}
		brand={Keystone.brand}
		nav={Keystone.nav}
		navIsFlat={Keystone.nav.flat}
		navLists={Keystone.lists}
		navSections={Keystone.nav.sections}
		orphanedLists={Keystone.orphanedLists}
		signoutUrl={Keystone.signoutUrl}
		User={Keystone.User}
		user={Keystone.user}
		version={Keystone.version}
	/>,
	document.getElementById('home-view')
);
<|endoftext|>


<commit_before>import React from 'react'
import Swipeable from 'react-swipeable'

// const buttonStyles = {
//   border: '1px solid #eee',
//   borderRadius: 3,
//   backgroundColor: '#FFFFFF',
//   cursor: 'pointer',
//   fontSize: 15,
//   padding: '3px 10px',
// }

const cyan600 = '#00acc1'
const cyan600T = 'rgba(0, 172, 193, 0.9)'
const red600 = '#e53935'
const base = 4
const basis = 100 / base
const blockSize = basis - 2
const removeSize = blockSize / 5

const orderStyles = {
  display: 'flex',
  flexWrap: 'nowrap',
  // margin: '1px 0',
  margin: 0,
  // lineHeight: '40px',
  fontSize: `${base}vw`,
  transform: `translateX(-${blockSize - 1}em)`,
  transitionDuration: '0.3s',
  lineHeight: '4em',
  width: '300%',
  boxSizing: 'border-box',
}

const block = {
  boxSizing: 'border-box',
  width: `${blockSize}em`,
  padding: '0 .5em',
}

// & > *
// width 100%

const infoStyles = {
  ...block,
  // flex: 'auto',
  transitionDuration: '0.3s',
  border: '.2em solid',
  borderColor: 'transparent',
  alignItems: 'center',
  justifyContent: 'space-between',
  display: 'flex',
}

const titleStyles = {
  lineHeight: '1em',
  // display: 'inline-block',
}

const removingOrderStyles = {
  transform: `translateX(-${blockSize + removeSize - 2}em)`,
}

const commentingOrderStyles = {
  transform: 'translateX(0em)',
}

const removingInfoStyles = {
  borderColor: red600,
}

const commentingInfoStyles = {
  // borderColor: cyan600,
  color: 'rgba(0,0,0,0)',
  // fontSize: '0.5em',
  // alignItems: 'flex-start',
  // '-webkit-filter': 'blur(2px)',
}
  // .title
  //   text-transform capitalize
  // .price
  //   float right

const removeStyles = {
  // flex: '1 1 10rem',
  width: `${removeSize}em`,
  transitionDuration: '0.3s',
  textAlign: 'center',
  backgroundColor: red600,
  color: red600,
  cursor: 'pointer',
}
  // &:active
  // &:hover
  //   color white
  //   flex 1 30px

const commentStyles = {
  // flex: '1',
  ...block,
  padding: '.5em 1em',
  transitionDuration: '0.3s',
  backgroundColor: cyan600,
  // overflow: 'hidden',
}

const commentLabelStyles = {
  // backgroundColor: cyan600T,
  // backgroundColor: 'transparent',
  // opacity: '0',
  color: 'rgba(255,255,255,0.6)',
  lineHeight: '1.1em',
  // border: 'none',
  paddingBottom: '.5em',
  fontSize: '.8em',
  width: '100%',
  // display: 'inline-block',
}

const commentFieldStyles = {
  // backgroundColor: cyan600T,
  backgroundColor: 'transparent',
  // opacity: '0',
  color: 'white',
  border: 'none',
  boxSizing: 'border-box',
  lineHeight: '1.1em',
  fontSize: 'inherit',
  width: '100%',
  wordBreak: 'break-all',
  textAlign: 'justify',
  // display: 'inline-block',
}

const commentBlockStyles = {
  // position: 'absolute',
  // width: '80vw',
  height: '100%',
  backgroundColor: cyan600T,
  display: 'flex',
  flexDirection: 'column',
  alignItems: 'center',
  justifyContent: 'space-around',
  // left: '-100vw',
  transitionDuration: '0.3s',
}

const commentBlockActiveStyles = {
  left: '0vw',
}
// &:hover
//   flex 1 300px
//   .comment-field
//     opacity 1
//

const ACTION_DELTA = 100

class Item extends React.Component {
  constructor(...args) {
    super(...args)
    this.state = {
      rightPan: 0,
      leftPan: 0,
      removing: false,
      commenting: false,
      wasActive: false,
    }

    this.swipingLeft = this.swipingLeft.bind(this)
    this.swipingRight = this.swipingRight.bind(this)
    this.handleSwipeEnd = this.handleSwipeEnd.bind(this)
  }

  calcP(delta, max) {
    const p = ACTION_DELTA - Math.max(0, ACTION_DELTA - delta)
    return Math.round(p / ACTION_DELTA * max)
  }

  swipingLeft(e, rightPan) {
    const max = 15
    const percent = this.calcP(rightPan, max)

    // console.log('swiping', p, this.state.rightPan, rightPan, percent)
    if (this.state.rightPan === percent) return

    if (this.state.commenting) {
      this.refs.comment.blur()
    }

    this.setState({
      leftPan: 0,
      rightPan: percent,
      removing: percent === max,
      commenting: false,
      wasActive: this.state.commenting || this.state.wasActive,
    })
    // this.setState({ rightPan: Math.min(150, this.state.rightPan + rightPan) })
  }

  swipingRight(e, leftPan) {
    if (this.state.commenting) return

    const max = 15
    const percent = this.calcP(leftPan, max)
    // console.log('swiping', e, leftPan)
    // this.setState({ rightPan: Math.max(20, this.state.rightPan - leftPan) })
    if (this.state.leftPan === percent) return

    this.setState({
      leftPan: percent,
      rightPan: 0,
      removing: false,
      commenting: percent === max,
    })
  }

  handleSwipeEnd() {
    if (this.state.removing && !this.state.wasActive) {
      this.props.remove(this.props.pos)
    }

    if (this.state.commenting) {
      this.refs.comment.focus()
    }

    this.setState({
      rightPan: 0,
      // leftPan: this.state.commenting ? this.state.leftPan : 0,
      leftPan: 0,
      // commenting: false,
      removing: false,
      wasActive: false,
    })
  }

  render() {
    const { price, title } = this.props
    const orderStylesR = {
      ...orderStyles,
      ...(this.state.removing ? removingOrderStyles : {}),
      ...(this.state.commenting ? commentingOrderStyles : {}),
    }

    const itemStyles = {
      ...infoStyles,
      ...(this.state.removing ? removingInfoStyles : {}),
      ...(this.state.commenting ? commentingInfoStyles : {}),
    }

    const commentItemStyles = {
      ...commentBlockStyles,
      ...(this.state.commenting ? commentBlockActiveStyles : {}),
    }
// style={{ ...commentStyles, flexBasis: `${this.state.leftPan}%` }}
// style={{ ...commentStyles, flexBasis: `${'0'}%` }}
// style={{ ...removeStyles, flexBasis: `${this.state.rightPan}%` }}
    return (
      <Swipeable
        onSwipingLeft={this.swipingLeft}
        onSwipingRight={this.swipingRight}
        /* onSwipingUp={this.swipingUp}
        onSwipingDown={this.swipingDown}
        onSwipingLeft={this.swipingLeft}
        onSwipedUp={this.swipedUp}
        onSwipedRight={this.swipedRight}
        onSwipedDown={this.swipedDown}
        onSwipedLeft={this.swipedLeft}*/
        onSwiped={this.handleSwipeEnd}
        preventDefaultTouchmoveEvent
        className="order" style={orderStylesR}
      >

            comment

            {`${title} ${title} ${title}`}

          {title}
          {price}

x

      </Swipeable>
    )
  }
}

Item.propTypes = {
  title: React.PropTypes.string,
  price: React.PropTypes.number,
  pos: React.PropTypes.number,
  remove: React.PropTypes.function,
}

export default Item
<commit_msg>test2.4<commit_after>import React from 'react'
import Swipeable from 'react-swipeable'

// const buttonStyles = {
//   border: '1px solid #eee',
//   borderRadius: 3,
//   backgroundColor: '#FFFFFF',
//   cursor: 'pointer',
//   fontSize: 15,
//   padding: '3px 10px',
// }

const cyan600 = '#00acc1'
const cyan600T = 'rgba(0, 172, 193, 0.9)'
const red600 = '#e53935'
const base = 4
const basis = 100 / base
const blockSize = basis - 2
const removeSize = blockSize / 5

const orderStyles = {
  display: 'flex',
  flexWrap: 'nowrap',
  // margin: '1px 0',
  margin: 0,
  // lineHeight: '40px',
  fontSize: `${base}vw`,
  transform: `translateX(-${blockSize - 1}em)`,
  transitionDuration: '0.3s',
  lineHeight: '3em',
  width: '300%',
  boxSizing: 'border-box',
}

const block = {
  boxSizing: 'border-box',
  width: `${blockSize}em`,
  padding: '0 .5em',
}

// & > *
// width 100%

const infoStyles = {
  ...block,
  // flex: 'auto',
  transitionDuration: '0.3s',
  border: '.2em solid',
  borderColor: 'transparent',
  alignItems: 'center',
  justifyContent: 'space-between',
  display: 'flex',
}

const titleStyles = {
  lineHeight: '1em',
  // display: 'inline-block',
}

const removingOrderStyles = {
  transform: `translateX(-${blockSize + removeSize - 2}em)`,
}

const commentingOrderStyles = {
  transform: 'translateX(0em)',
}

const removingInfoStyles = {
  borderColor: red600,
}

const commentingInfoStyles = {
  // borderColor: cyan600,
  color: 'rgba(0,0,0,0)',
  // fontSize: '0.5em',
  // alignItems: 'flex-start',
  // '-webkit-filter': 'blur(2px)',
}
  // .title
  //   text-transform capitalize
  // .price
  //   float right

const removeStyles = {
  // flex: '1 1 10rem',
  width: `${removeSize}em`,
  transitionDuration: '0.3s',
  textAlign: 'center',
  backgroundColor: red600,
  color: red600,
  cursor: 'pointer',
}
  // &:active
  // &:hover
  //   color white
  //   flex 1 30px

const commentStyles = {
  // flex: '1',
  ...block,
  padding: '.5em 1em',
  transitionDuration: '0.3s',
  backgroundColor: cyan600,
  // overflow: 'hidden',
}

const commentLabelStyles = {
  // backgroundColor: cyan600T,
  // backgroundColor: 'transparent',
  // opacity: '0',
  color: 'rgba(255,255,255,0.6)',
  lineHeight: '1.1em',
  // border: 'none',
  paddingBottom: '.5em',
  fontSize: '.8em',
  width: '100%',
  // display: 'inline-block',
}

const commentFieldStyles = {
  // backgroundColor: cyan600T,
  backgroundColor: 'transparent',
  // opacity: '0',
  color: 'white',
  border: 'none',
  boxSizing: 'border-box',
  lineHeight: '1.1em',
  fontSize: 'inherit',
  width: '100%',
  overflow: 'hidden',
  maxHeight: '1em',
  wordBreak: 'break-all',
  textAlign: 'justify',
  transitionDuration: '.3s',
  transitionDelay: '.1s',
  // display: 'inline-block',
}

const commentFieldActiveStyles = {
  maxHeight: '10em',
}

const commentBlockStyles = {
  // position: 'absolute',
  // width: '80vw',
  height: '100%',
  backgroundColor: cyan600T,
  display: 'flex',
  flexDirection: 'column',
  alignItems: 'center',
  justifyContent: 'space-around',
  // left: '-100vw',
  transitionDuration: '0.3s',
}

// const commentBlockActiveStyles = {
//   left: '0vw',
// }
// &:hover
//   flex 1 300px
//   .comment-field
//     opacity 1
//

const ACTION_DELTA = 100

class Item extends React.Component {
  constructor(...args) {
    super(...args)
    this.state = {
      rightPan: 0,
      leftPan: 0,
      removing: false,
      commenting: false,
      wasActive: false,
    }

    this.swipingLeft = this.swipingLeft.bind(this)
    this.swipingRight = this.swipingRight.bind(this)
    this.handleSwipeEnd = this.handleSwipeEnd.bind(this)
  }

  calcP(delta, max) {
    const p = ACTION_DELTA - Math.max(0, ACTION_DELTA - delta)
    return Math.round(p / ACTION_DELTA * max)
  }

  swipingLeft(e, rightPan) {
    const max = 15
    const percent = this.calcP(rightPan, max)

    // console.log('swiping', p, this.state.rightPan, rightPan, percent)
    if (this.state.rightPan === percent) return

    if (this.state.commenting) {
      this.refs.comment.blur()
    }

    this.setState({
      leftPan: 0,
      rightPan: percent,
      removing: percent === max,
      commenting: false,
      wasActive: this.state.commenting || this.state.wasActive,
    })
    // this.setState({ rightPan: Math.min(150, this.state.rightPan + rightPan) })
  }

  swipingRight(e, leftPan) {
    if (this.state.commenting) return

    const max = 15
    const percent = this.calcP(leftPan, max)
    // console.log('swiping', e, leftPan)
    // this.setState({ rightPan: Math.max(20, this.state.rightPan - leftPan) })
    if (this.state.leftPan === percent) return

    this.setState({
      leftPan: percent,
      rightPan: 0,
      removing: false,
      commenting: percent === max,
    })
  }

  handleSwipeEnd() {
    if (this.state.removing && !this.state.wasActive) {
      this.props.remove(this.props.pos)
    }

    if (this.state.commenting) {
      this.refs.comment.focus()
    }

    this.setState({
      rightPan: 0,
      // leftPan: this.state.commenting ? this.state.leftPan : 0,
      leftPan: 0,
      // commenting: false,
      removing: false,
      wasActive: false,
    })
  }

  render() {
    const { price, title } = this.props
    const orderStylesR = {
      ...orderStyles,
      ...(this.state.removing ? removingOrderStyles : {}),
      ...(this.state.commenting ? commentingOrderStyles : {}),
    }

    const itemStyles = {
      ...infoStyles,
      ...(this.state.removing ? removingInfoStyles : {}),
      ...(this.state.commenting ? commentingInfoStyles : {}),
    }

    // const commentItemStyles = {
    //   ...commentBlockStyles,
    //   ...(this.state.commenting ? commentBlockActiveStyles : {}),
    // }

    const commentFieldStylesR = {
      ...commentFieldStyles,
      ...(this.state.commenting ? commentFieldActiveStyles : {}),
    }
// style={{ ...commentStyles, flexBasis: `${this.state.leftPan}%` }}
// style={{ ...commentStyles, flexBasis: `${'0'}%` }}
// style={{ ...removeStyles, flexBasis: `${this.state.rightPan}%` }}
    return (
      <Swipeable
        onSwipingLeft={this.swipingLeft}
        onSwipingRight={this.swipingRight}
        /* onSwipingUp={this.swipingUp}
        onSwipingDown={this.swipingDown}
        onSwipingLeft={this.swipingLeft}
        onSwipedUp={this.swipedUp}
        onSwipedRight={this.swipedRight}
        onSwipedDown={this.swipedDown}
        onSwipedLeft={this.swipedLeft}*/
        onSwiped={this.handleSwipeEnd}
        preventDefaultTouchmoveEvent
        className="order" style={orderStylesR}
      >

            comment

            {`${title} ${title} ${title}`}

          {title}
          {price}

x

      </Swipeable>
    )
  }
}

Item.propTypes = {
  title: React.PropTypes.string,
  price: React.PropTypes.number,
  pos: React.PropTypes.number,
  remove: React.PropTypes.function,
}

export default Item
<|endoftext|>


<commit_before>var moment = require('moment');
var sqlite3 = require('sqlite3').verbose();

var getDives = function (dbPath) {
  var promise = new Promise(function (resolve, reject) {
    var db = new sqlite3.Database(dbPath);
    var dives = [];

    db.all('SELECT DiveId, StartTime, Duration, Mode, MaxDepth, Note, BottomTemperature, DiveNumberInSerie, Source FROM Dive ORDER BY StartTime DESC', function (err, rows) {
      rows.forEach(function (row) {
        row.Selected = false;
        row.StartDate = moment((row.StartTime - 621355968000000000)/10000).utcOffset(0).format('DD.MM.YYYY');
        row.StartTime = moment((row.StartTime - 621355968000000000)/10000).utcOffset(0).format('HH:mm');
        row.Duration = moment.utc(0).add(row.Duration, 's').format('HH:mm:ss');
        row.MaxDepth = Math.round(row.MaxDepth);
        dives.push(row);
      });

      //console.log(JSON.stringify(rows, null, '  '));
      resolve(dives);
    });

    db.close();
  });

  return promise;
}

var saveDive = function (dbPath, dive) {
  var db = new sqlite3.Database(dbPath);
  db.serialize(function () {
    var stmt = db.prepare('UPDATE Dive SET Mode = (?) WHERE DiveId = (?)');
    stmt.run(dive.Mode, dive.DiveId);
    stmt.finalize();
  });
  db.close();
}

module.exports.getDives = getDives;
module.exports.saveDive = saveDive;
<commit_msg>Add ModeType and StartDateTime to returned dive object<commit_after>var moment = require('moment');
var sqlite3 = require('sqlite3').verbose();

var getDives = function (dbPath) {
  var promise = new Promise(function (resolve, reject) {
    var db = new sqlite3.Database(dbPath);
    var dives = [];

    db.all('SELECT DiveId, StartTime, Duration, Mode, MaxDepth, AvgDepth, Note, BottomTemperature, DiveNumberInSerie, Source FROM Dive ORDER BY StartTime DESC', function (err, rows) {
      rows.forEach(function (row) {
        row.Selected = false;
        row.StartDateTime = moment((row.StartTime - 621355968000000000)/10000).utcOffset(0);
        row.StartDate = moment((row.StartTime - 621355968000000000)/10000).utcOffset(0).format('DD.MM.YYYY');
        row.StartTime = moment((row.StartTime - 621355968000000000)/10000).utcOffset(0).format('HH:mm');
        row.Duration = moment.utc(0).add(row.Duration, 's').format('HH:mm:ss');
        row.MaxDepth = row.MaxDepth;

        if (row.Source == null) {
          row.Source = '';
        }

        if (row.AvgDepth == null) {
          row.AvgDepth = 0;
        }

        switch (row.Mode) {
          case 0:
            row.ModeType = 'Air';
            break;
          case 1:
            row.ModeType = 'Nitrox';
            break;
          case 2:
            row.ModeType = 'Gauge';
            break;
          case 3:
            row.ModeType = 'Free';
            break;
        }

        dives.push(row);
      });

      //console.log(JSON.stringify(rows, null, '  '));
      resolve(dives);
    });

    db.close();
  });

  return promise;
}

var saveDive = function (dbPath, dive) {
  var db = new sqlite3.Database(dbPath);
  db.serialize(function () {
    var stmt = db.prepare('UPDATE Dive SET Mode = (?) WHERE DiveId = (?)');
    stmt.run(dive.Mode, dive.DiveId);
    stmt.finalize();
  });
  db.close();
}

module.exports.getDives = getDives;
module.exports.saveDive = saveDive;
<|endoftext|>


<commit_before>/**
 * Helper to slide a new page in the app.
 * This helper only works well if the container is at 100% height.
 *
 * Based on : https://github.com/ccoenraets/directory-backbone-topcoat-require
 *
 */
 (function (root, factory) {
     if (typeof define === 'function' && define.amd) {
         // AMD. Register as an anonymous module.
         define(['jquery'], factory);
     } else if (typeof exports === 'object') {
         // Node.
         module.exports = factory(require('jquery'));
     } else {
         // Browser globals (root is window)
         root.PageSlider = factory(root.jQuery);
     }
 }(this, function ($) {
    'use strict';

    return function PageSlider($container) {

        this.transitionsEnabled = true;
        this.transitionDurationMs = 300;

        var $currentPage;
        var stateHistory = [];

        // The container need specific style
        $container.css({
            height: '100%',
            width: '100%',
            overflow: 'hidden',
        });

        /**
         * Set a page position via translate3d
         * @param {jquery} $page Page that we want to Position
         * @param {String} newLocation New position ('left', 'right' or null (default))
         */
        var _setPagePosition = function ($page, newLocation) {

            var newPosition = '0px';

            switch (newLocation) {
                case 'left':
                    newPosition = '-100%';
                    break;
                case 'right':
                    newPosition = '100%';
                    break;
            }

            var transform = 'translate3d(' + newPosition + ', 0px , 0px)';

            $page.css({
                'webkitTransform': transform,
                'transform': transform,
            });
        };

        var _jQueryArrayToCollection = function (jqueryArray) {

            if (jqueryArray instanceof $) {
                return jqueryArray;
            }

            var $collection = $();

            jqueryArray.forEach(function ($el) {
                $collection = $collection.add($el);
            });

            return $collection;
        };

        /**
         * Enable css transition on the given page.
         */
        var _enableTransitionOnPages = function ($pages) {

            $pages = _jQueryArrayToCollection($pages);

            $pages.css({
                'webkitTransitionDuration': this.transitionDurationMs + 'ms',
                'transitionDuration': this.transitionDurationMs + 'ms',
            });
        };

        /**
         * Disable css transition on the given page.
         */
        var _disableTransitionOnPages = function ($pages) {

            $pages = _jQueryArrayToCollection($pages);

            $pages.css({
                'webkitTransform': 'none',
                'transform': 'none',
                'webkitTransitionDuration': '0s',
                'transitionDuration': '0s',
            });
        };

        /**
         * Set transition duration in milliseconds
         */
        this.setTransitionDurationMs = function (durationMs) {
            this.transitionDurationMs = durationMs;
        };

        /**
         * Disable css transition on page
         */
        this.disableTransitions = function () {
            this.transitionsEnabled = false;
        };

        /**
         * Enable css transition on page
         */
        this.enableTransitions = function () {
            this.transitionsEnabled = true;
        };

        /**
         * Return the type of slide (null, 'left' or 'right')
         */
        this.getNextSlideOrigin = function () {
            var historyLength = stateHistory.length;

            if (historyLength === 0) {
                return null;
            }
            else if (location.hash === stateHistory[historyLength - 2]) {
                return 'left';
            }
            else {
                return 'right';
            }
        };

        /**
         * Use this function if you want PageSlider to automatically determine
         * the sliding direction based on the state history.
         * afterTransition function is called when the transition ends
         */
        this.slidePage = function ($newPage, options) {

            var state = location.hash;

            var slideBehaviour = this.getNextSlideOrigin();

            switch (slideBehaviour) {
                case 'left':
                    stateHistory.pop();
                    this.slidePageFrom($newPage, 'left', options);
                    break;
                case 'right':
                    stateHistory.push(state);
                    this.slidePageFrom($newPage, 'right', options);
                    break;
                default:
                    stateHistory.push(state);
                    this.slidePageFrom($newPage, null, options);
                    break;
            }
        };

        /**
         * Use this function directly if you want to control the sliding direction outside PageSlider
         * @param  {$} $newPage The new page to slide in
         * @param  {String} origin Origin of the slide ('left', 'right', or null)
         * @param  {function} options
         *  beforeTransition: Called before the transition, after the page is added
         *                    to the DOM.
         *   afterTransition: Called when the slide end
         *                    or immediately if there is no transition.
         *                    A boolean is passed to the callback : true if we just slide
         *                    in the very first page.
         *
         */
        this.slidePageFrom = function ($newPage, origin, options) {

            options = options || {};
            options.beforeTransition = options.beforeTransition || $.noop;
            options.afterTransition = options.afterTransition || $.noop;

            // Current page must be removed after the transition
            var $oldPage = $currentPage;
            var isFirstPageSlide = !$oldPage;

            $newPage.addClass('page');
            $container.append($newPage);

            options.beforeTransition();

            // First loaded page (no old page) or no transition
            if (isFirstPageSlide || !origin || !this.transitionsEnabled) {

                // Disable transition
                _disableTransitionOnPages($newPage);

                // Remove old page if it exists
                if ($oldPage) {
                    $oldPage.remove();
                }

                $currentPage = $newPage;

                // We call the transition end callback anyway
                options.afterTransition(isFirstPageSlide);
                return;
            }

            // Position the page at the starting position of the animation
            _setPagePosition($newPage, origin);

            // Shim transitionend if it's not fired
            var shimTransitionEnd = setTimeout(function() {
                onTransitionEnd();
            }, this.transitionDurationMs + 100);

            $currentPage.one('transitionend webkitTransitionEnd', function () {
                onTransitionEnd();
            });

            // Position the new page and the current page at the ending position of their animation
            // And enable their animation via transition

            _enableTransitionOnPages.call(this, [$newPage, $oldPage]);

            // Force reflow. More information here:
            // http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/
            /*jshint -W030*/
            $container[0].offsetWidth;

            setTimeout(function () {
                _setPagePosition($newPage, 'center');
                _setPagePosition($oldPage,  (origin === 'left' ? 'right' : 'left'));
                $currentPage = $newPage;
            }, 0);

            var onTransitionEnd = function () {
                _disableTransitionOnPages($currentPage);

                $container.find('> .page:not(:last)').remove();

                clearTimeout(shimTransitionEnd);
                options.afterTransition(false);
            };

        };

    };
}));
<commit_msg>Add some documentation<commit_after>/**
 * Helper to slide a new page in the app.
 * This helper only works well if the container is at 100% height/width and overflow hidden.
 *
 * Based on : https://github.com/ccoenraets/directory-backbone-topcoat-require
 *
 */
 (function (root, factory) {
     if (typeof define === 'function' && define.amd) {
         // AMD. Register as an anonymous module.
         define(['jquery'], factory);
     } else if (typeof exports === 'object') {
         // Node.
         module.exports = factory(require('jquery'));
     } else {
         // Browser globals (root is window)
         root.PageSlider = factory(root.jQuery);
     }
 }(this, function ($) {
    'use strict';

    return function PageSlider($container) {

        this.transitionsEnabled = true;
        this.transitionDurationMs = 300;

        var $currentPage;
        var stateHistory = [];

        // The container need specific style
        $container.css({
            height: '100%',
            width: '100%',
            overflow: 'hidden',
        });

        /**
         * Set a page position via translate3d
         * @param {jquery} $page Page that we want to Position
         * @param {String} newLocation New position ('left', 'right' or null (default))
         */
        var _setPagePosition = function ($page, newLocation) {

            var newPosition = '0px';

            switch (newLocation) {
                case 'left':
                    newPosition = '-100%';
                    break;
                case 'right':
                    newPosition = '100%';
                    break;
            }

            var transform = 'translate3d(' + newPosition + ', 0px , 0px)';

            $page.css({
                'webkitTransform': transform,
                'transform': transform,
            });
        };

        var _jQueryArrayToCollection = function (jqueryArray) {

            if (jqueryArray instanceof $) {
                return jqueryArray;
            }

            var $collection = $();

            jqueryArray.forEach(function ($el) {
                $collection = $collection.add($el);
            });

            return $collection;
        };

        /**
         * Enable css transition on the given page.
         */
        var _enableTransitionOnPages = function ($pages) {

            $pages = _jQueryArrayToCollection($pages);

            $pages.css({
                'webkitTransitionDuration': this.transitionDurationMs + 'ms',
                'transitionDuration': this.transitionDurationMs + 'ms',
            });
        };

        /**
         * Disable css transition on the given page.
         */
        var _disableTransitionOnPages = function ($pages) {

            $pages = _jQueryArrayToCollection($pages);

            $pages.css({
                'webkitTransform': 'none',
                'transform': 'none',
                'webkitTransitionDuration': '0s',
                'transitionDuration': '0s',
            });
        };

        /**
         * Set transition duration in milliseconds
         */
        this.setTransitionDurationMs = function (durationMs) {
            this.transitionDurationMs = durationMs;
        };

        /**
         * Disable css transition on page
         */
        this.disableTransitions = function () {
            this.transitionsEnabled = false;
        };

        /**
         * Enable css transition on page
         */
        this.enableTransitions = function () {
            this.transitionsEnabled = true;
        };

        /**
         * Return the type of slide (null, 'left' or 'right')
         */
        this.getNextSlideOrigin = function () {
            var historyLength = stateHistory.length;

            if (historyLength === 0) {
                return null;
            }
            else if (location.hash === stateHistory[historyLength - 2]) {
                return 'left';
            }
            else {
                return 'right';
            }
        };

        /**
         * Use this function if you want PageSlider to automatically determine
         * the sliding direction based on the state history.
         * afterTransition function is called when the transition ends
         */
        this.slidePage = function ($newPage, options) {

            var state = location.hash;

            var slideBehaviour = this.getNextSlideOrigin();

            switch (slideBehaviour) {
                case 'left':
                    stateHistory.pop();
                    this.slidePageFrom($newPage, 'left', options);
                    break;
                case 'right':
                    stateHistory.push(state);
                    this.slidePageFrom($newPage, 'right', options);
                    break;
                default:
                    stateHistory.push(state);
                    this.slidePageFrom($newPage, null, options);
                    break;
            }
        };

        /**
         * Use this function directly if you want to control the sliding direction outside PageSlider
         * @param  {$} $newPage The new page to slide in
         * @param  {String} origin Origin of the slide ('left', 'right', or null)
         * @param  {function} options
         *  beforeTransition: Called before the transition, after the page is added
         *                    to the DOM.
         *   afterTransition: Called when the slide end
         *                    or immediately if there is no transition.
         *                    A boolean is passed to the callback : true if we just slide
         *                    in the very first page.
         *
         */
        this.slidePageFrom = function ($newPage, origin, options) {

            options = options || {};
            options.beforeTransition = options.beforeTransition || $.noop;
            options.afterTransition = options.afterTransition || $.noop;

            // Current page must be removed after the transition
            var $oldPage = $currentPage;
            var isFirstPageSlide = !$oldPage;

            $newPage.addClass('page');
            $container.append($newPage);

            options.beforeTransition();

            // First loaded page (no old page) or no transition
            if (isFirstPageSlide || !origin || !this.transitionsEnabled) {

                // Disable transition
                _disableTransitionOnPages($newPage);

                // Remove old page if it exists
                if ($oldPage) {
                    $oldPage.remove();
                }

                $currentPage = $newPage;

                // We call the transition end callback anyway
                options.afterTransition(isFirstPageSlide);
                return;
            }

            // Position the page at the starting position of the animation
            _setPagePosition($newPage, origin);

            // Shim transitionend if it's not fired
            var shimTransitionEnd = setTimeout(function() {
                onTransitionEnd();
            }, this.transitionDurationMs + 100);

            $currentPage.one('transitionend webkitTransitionEnd', function () {
                onTransitionEnd();
            });

            // Position the new page and the current page at the ending position of their animation
            // And enable their animation via transition

            _enableTransitionOnPages.call(this, [$newPage, $oldPage]);

            // Force reflow. More information here:
            // http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/
            /*jshint -W030*/
            $container[0].offsetWidth;

            setTimeout(function () {
                _setPagePosition($newPage, 'center');
                _setPagePosition($oldPage,  (origin === 'left' ? 'right' : 'left'));
                $currentPage = $newPage;
            }, 0);

            var onTransitionEnd = function () {
                _disableTransitionOnPages($currentPage);

                $container.find('> .page:not(:last)').remove();

                clearTimeout(shimTransitionEnd);
                options.afterTransition(false);
            };

        };

    };
}));
<|endoftext|>


<commit_before>import React from 'react'

import { APP_NAME, SOURCE_URL } from '../config'

const REACT_URL = 'https://github.com/facebook/react'
const FETCH_REDDIT_URL = 'https://github.com/CookPete/fetch-reddit'
const REACT_PLAYER_URL = 'https://github.com/CookPete/react-player'
const CURATION_URL = 'https://www.reddit.com/r/listentothis/comments/1iwc8n/meta_announcing_the_official_rlistentothis_music/'
const LISTENTOTHIS_URL = 'https://www.reddit.com/r/listentothis'

export default function About () {
  return (

FAQ

What is this?

          {APP_NAME} creates playlists from any Reddit comment thread, subreddit or multi-reddit. Just replace reddit.com in any Reddit URL to {window.location.host} and you’re good.

How does it work?

          The app is written using React. It fetches stuff from Reddit using fetch-reddit, then react-player plays any supported URLs. See the source code on GitHub. Playlists are curated by the mighty u/evilnight over at r/listentothis.

What can it play?

          {APP_NAME} currently supports YouTube, SoundCloud and Vimeo links.

What about radd.it, reddit.musicplayer.io, redditplaylister, etc?

          Yes, there are other apps that do the job. I wanted to create something simple with a clean, minimal interface. Also, this app fixes issues that other apps still suffer from.

  )
}
<commit_msg>Open FAQ links in new window<commit_after>import React from 'react'

import { APP_NAME, SOURCE_URL } from '../config'

const REACT_URL = 'https://github.com/facebook/react'
const FETCH_REDDIT_URL = 'https://github.com/CookPete/fetch-reddit'
const REACT_PLAYER_URL = 'https://github.com/CookPete/react-player'
const CURATION_URL = 'https://www.reddit.com/r/listentothis/comments/1iwc8n/meta_announcing_the_official_rlistentothis_music/'
const LISTENTOTHIS_URL = 'https://www.reddit.com/r/listentothis'

export default function About () {
  return (

FAQ

What is this?

          {APP_NAME} creates playlists from any Reddit comment thread, subreddit or multi-reddit. Just replace reddit.com in any Reddit URL to {window.location.host} and you’re good.

How does it work?

          The app is written using React. It fetches stuff from Reddit using fetch-reddit, then react-player plays any supported URLs. See the source code on GitHub. Playlists are curated by the mighty u/evilnight over at r/listentothis.

What can it play?

          {APP_NAME} currently supports YouTube, SoundCloud and Vimeo links.

What about radd.it, reddit.musicplayer.io, redditplaylister, etc?

          Yes, there are other apps that do the job. I wanted to create something simple with a clean, minimal interface. Also, this app fixes issues that other apps still suffer from.

  )
}
<|endoftext|>


<commit_before>import React from 'react'
import {connect} from 'react-redux'
import {pushState } from 'redux-router'
import * as Actions from '../actions/AppActions'

import TestComponent from '../components/TestComponent';

@connect(
  state => ({
    login: state.login
  })
)
class Login extends React.Component {

  componentWillReceiveProps(nextProps){
    const {dispatch} = this.props

    if(nextProps.login.toJS().logged){
      dispatch(pushState(null,'/posts'))
    }

  }

  render() {
    const {login, dispatch} = this.props

    const handleLogin = (event) => {
      const {email, password} = this.refs

      dispatch(Actions.login(email.value, password.value))
    }

    return (

          <form>
            Sign In Please!
            <input type="text" placeholder="email" ref="email" required></input>
            <input type="password" placeholder="password" ref="password" required></input>
            <input type="button" value="Log In" onClick={handleLogin}/>
          </form>

    )
  }
}

export default  Login
<commit_msg>Added signup button to login<commit_after>import React from 'react'
import {connect} from 'react-redux'
import {pushState } from 'redux-router'
import * as Actions from '../actions/AppActions'

import TestComponent from '../components/TestComponent';

@connect(
  state => ({
    login: state.login
  })
)
class Login extends React.Component {

  componentWillReceiveProps(nextProps){
    const {dispatch} = this.props

    if(nextProps.login.toJS().logged){
      dispatch(pushState(null,'/posts'))
    }

  }

  render() {
    const {login, dispatch} = this.props

    const handleLogin = (event) => {
      const {email, password} = this.refs

      dispatch(Actions.login(email.value, password.value))
    }

    return (

          <form>
            Sign In Please!
            <input type="text" placeholder="email" ref="email" required></input>
            <input type="password" placeholder="password" ref="password" required></input>
            <input type="button" value="Log In" onClick={handleLogin}/>

              <input type="button" value="Sign Up"/>

          </form>

    )
  }
}

export default  Login
<|endoftext|>


<commit_before>
/*
 * Copyright (C) NGINX, Inc.
 */

'use strict';

const EventEmitter = require('events');
const http = require('http');
const util = require('util');
const unit_lib = require('unit-http/build/Release/unit-http.node');
const unit_socket = require('unit-http/socket');

const { Socket } = unit_socket;

function ServerResponse(req) {
    EventEmitter.call(this);

    this.headers = {};
}
util.inherits(ServerResponse, EventEmitter);

ServerResponse.prototype.statusCode = 200;
ServerResponse.prototype.statusMessage = undefined;
ServerResponse.prototype.headers_len = 0;
ServerResponse.prototype.headers_count = 0;
ServerResponse.prototype.headersSent = false;
ServerResponse.prototype.finished = false;

ServerResponse.prototype._finish = function _finish() {
    this.headers = {};
    this.headers_len = 0;
    this.headers_count = 0;
    this.finished = true;
};

ServerResponse.prototype.assignSocket = function assignSocket(socket) {
};

ServerResponse.prototype.detachSocket = function detachSocket(socket) {
};

ServerResponse.prototype.writeContinue = function writeContinue(cb) {
};

ServerResponse.prototype.writeProcessing = function writeProcessing(cb) {
};

ServerResponse.prototype.setHeader = function setHeader(name, value) {
    if (typeof name !== 'string') {
        throw new TypeError('Name argument must be a string');
    }

    let value_len = 0
    let count = 0;

    if (Array.isArray(value)) {
        count = value.length;

        value.forEach(function(val) {
            value_len += Buffer.byteLength(val + "", 'latin1');
        });

    } else {
        count = 1;
        value_len = Buffer.byteLength(value + "", 'latin1');
    }

    let lc_name = name.toLowerCase();

    if (lc_name in this.headers) {
        this._removeHeader(lc_name);
    }

    let name_len = Buffer.byteLength(name, 'latin1');

    this.headers[lc_name] = [name, value];
    this.headers_len += value_len + (name_len * count);
    this.headers_count += count;
};

ServerResponse.prototype.getHeader = function getHeader(name) {
    const entry = this.headers[name.toLowerCase()];

    return entry && entry[1];
};

ServerResponse.prototype.getHeaderNames = function getHeaderNames() {
    return Object.keys(this.headers);
};

ServerResponse.prototype.getHeaders = function getHeaders() {
    const ret = Object.create(null);

    if (this.headers) {
        const keys = Object.keys(this.headers);

        for (var i = 0; i < keys.length; i++) {
            const key = keys[i];

            ret[key] = this.headers[key][1];
        }
    }

    return ret;
};

ServerResponse.prototype.hasHeader = function hasHeader(name) {
    return name.toLowerCase() in this.headers;
};

ServerResponse.prototype.removeHeader = function removeHeader(name) {
    if (typeof name !== 'string') {
        throw new TypeError('Name argument must be a string');
    }

    let lc_name = name.toLowerCase();

    if (lc_name in this.headers) {
        this._removeHeader(lc_name);
    }
};

ServerResponse.prototype._removeHeader = function _removeHeader(lc_name) {
    let entry = this.headers[lc_name];
    let name_len = Buffer.byteLength(entry[0] + "", 'latin1');
    let value = entry[1];

    delete this.headers[lc_name];

    if (Array.isArray(value)) {
        this.headers_count -= value.length;
        this.headers_len -= value.length * name_len;

        value.forEach(function(val) {
            this.headers_len -= Buffer.byteLength(val + "", 'latin1');
        });

        return;
    }

    this.headers_count--;
    this.headers_len -= name_len + Buffer.byteLength(value + "", 'latin1');
};

ServerResponse.prototype.sendDate = function sendDate() {
    throw new Error("Not supported");
};

ServerResponse.prototype.setTimeout = function setTimeout(msecs, callback) {
    this.timeout = msecs;

    if (callback) {
        this.on('timeout', callback);
    }

    return this;
};

ServerResponse.prototype.writeHead = writeHead;
ServerResponse.prototype.writeHeader = ServerResponse.prototype.writeHead;

function writeHead(statusCode, reason, obj) {
    var originalStatusCode = statusCode;

    statusCode |= 0;

    if (statusCode < 100 || statusCode > 999) {
        throw new ERR_HTTP_INVALID_STATUS_CODE(originalStatusCode);
    }

    if (typeof reason === 'string') {
        this.statusMessage = reason;

    } else {
        if (!this.statusMessage) {
            this.statusMessage = http.STATUS_CODES[statusCode] || 'unknown';
        }

        obj = reason;
    }

    this.statusCode = statusCode;

    if (obj) {
        var k;
        var keys = Object.keys(obj);

        for (var i = 0; i < keys.length; i++) {
            k = keys[i];

            if (k) {
                this.setHeader(k, obj[k]);
            }
        }
    }
};

ServerResponse.prototype._writeBody = function(chunk, encoding, callback) {
    var contentLength = 0;

    if (!this.headersSent) {
        unit_lib.unit_response_headers(this, this.statusCode, this.headers,
                                       this.headers_count, this.headers_len);

        this.headersSent = true;
    }

    if (typeof chunk === 'function') {
        callback = chunk;
        chunk = null;

    } else if (typeof encoding === 'function') {
        callback = encoding;
        encoding = null;
    }

    if (chunk) {
        if (typeof chunk !== 'string' && !(chunk instanceof Buffer)) {
            throw new TypeError('First argument must be a string or Buffer');
        }

        if (typeof chunk === 'string') {
            contentLength = Buffer.byteLength(chunk, encoding);

        } else {
            contentLength = chunk.length;
        }

        unit_lib.unit_response_write(this, chunk, contentLength);
    }

    if (typeof callback === 'function') {
        /*
         * The callback must be called only when response.write() caller
         * completes.  process.nextTick() postpones the callback execution.
         *
         * process.nextTick() is not technically part of the event loop.
         * Instead, the nextTickQueue will be processed after the current
         * operation completes, regardless of the current phase of
         * the event loop.  All callbacks passed to process.nextTick()
         * will be resolved before the event loop continues.
         */
        process.nextTick(function () {
            callback(this);
        }.bind(this));
    }
};

ServerResponse.prototype.write = function write(chunk, encoding, callback) {
    if (this.finished) {
        throw new Error("Write after end");
    }

    this._writeBody(chunk, encoding, callback);

    return true;
};

ServerResponse.prototype.end = function end(chunk, encoding, callback) {
    if (!this.finished) {
        this._writeBody(chunk, encoding, callback);

        unit_lib.unit_response_end(this);

        this.finished = true;
    }

    return this;
};

function ServerRequest(server) {
    EventEmitter.call(this);

    this.server = server;
}
util.inherits(ServerRequest, EventEmitter);

ServerRequest.prototype.unpipe = undefined;

ServerRequest.prototype.setTimeout = function setTimeout(msecs, callback) {
    this.timeout = msecs;

    if (callback) {
        this.on('timeout', callback);
    }

    return this;
};

ServerRequest.prototype.statusCode = function statusCode() {
    /* Only valid for response obtained from http.ClientRequest. */
};

ServerRequest.prototype.statusMessage = function statusMessage() {
    /* Only valid for response obtained from http.ClientRequest. */
};

ServerRequest.prototype.trailers = function trailers() {
    throw new Error("Not supported");
};

ServerRequest.prototype.METHODS = function METHODS() {
    return http.METHODS;
};

ServerRequest.prototype.STATUS_CODES = function STATUS_CODES() {
    return http.STATUS_CODES;
};

ServerRequest.prototype.listeners = function listeners() {
    return [];
};

ServerRequest.prototype.resume = function resume() {
    return [];
};

/*
 * The "on" method is overridden to defer reading data until user code is
 * ready, that is (ev === "data").  This can occur after req.emit("end") is
 * executed, since the user code can be scheduled asynchronously by Promises
 * and so on.  Passing the data is postponed by process.nextTick() until
 * the "on" method caller completes.
 */
ServerRequest.prototype.on = function on(ev, fn) {
    Server.prototype.on.call(this, ev, fn);

    if (ev === "data") {
        process.nextTick(function () {
            if (this.server.buffer.length !== 0) {
                this.emit("data", this.server.buffer);
            }

        }.bind(this));
    }
};

ServerRequest.prototype.addListener = ServerRequest.prototype.on;

function Server(requestListener) {
    EventEmitter.call(this);

    this.unit = new unit_lib.Unit();
    this.unit.server = this;

    this.unit.createServer();

    this.socket = Socket;
    this.request = ServerRequest;
    this.response = ServerResponse;

    if (requestListener) {
        this.on('request', requestListener);
    }
}
util.inherits(Server, EventEmitter);

Server.prototype.setTimeout = function setTimeout(msecs, callback) {
    this.timeout = msecs;

    if (callback) {
        this.on('timeout', callback);
    }

    return this;
};

Server.prototype.listen = function () {
    this.unit.listen();
};

Server.prototype.emit_events = function (server, req, res) {
    req.server = server;
    res.server = server;
    req.res = res;
    res.req = req;

    server.buffer = server.unit._read(req.socket.req_pointer);

    server.emit("request", req, res);

    process.nextTick(() => {
        req.emit("finish");
        req.emit("end");
    });
};

Server.prototype.emit_close = function () {
    this.emit('close');
};

function connectionListener(socket) {
}

module.exports = {
    STATUS_CODES: http.STATUS_CODES,
    Server,
    ServerResponse,
    ServerRequest,
    _connectionListener: connectionListener
};
<commit_msg>Backed out changeset f74d4dd9c3db.<commit_after>
/*
 * Copyright (C) NGINX, Inc.
 */

'use strict';

const EventEmitter = require('events');
const http = require('http');
const util = require('util');
const unit_lib = require('unit-http/build/Release/unit-http.node');
const unit_socket = require('unit-http/socket');

const { Socket } = unit_socket;

function ServerResponse(req) {
    EventEmitter.call(this);

    this.headers = {};
}
util.inherits(ServerResponse, EventEmitter);

ServerResponse.prototype.statusCode = 200;
ServerResponse.prototype.statusMessage = undefined;
ServerResponse.prototype.headers_len = 0;
ServerResponse.prototype.headers_count = 0;
ServerResponse.prototype.headersSent = false;
ServerResponse.prototype.finished = false;

ServerResponse.prototype._finish = function _finish() {
    this.headers = {};
    this.headers_len = 0;
    this.headers_count = 0;
    this.finished = true;
};

ServerResponse.prototype.assignSocket = function assignSocket(socket) {
};

ServerResponse.prototype.detachSocket = function detachSocket(socket) {
};

ServerResponse.prototype.writeContinue = function writeContinue(cb) {
};

ServerResponse.prototype.writeProcessing = function writeProcessing(cb) {
};

ServerResponse.prototype.setHeader = function setHeader(name, value) {
    if (typeof name !== 'string') {
        throw new TypeError('Name argument must be a string');
    }

    let value_len = 0
    let count = 0;

    if (Array.isArray(value)) {
        count = value.length;

        value.forEach(function(val) {
            value_len += Buffer.byteLength(val + "", 'latin1');
        });

    } else {
        count = 1;
        value_len = Buffer.byteLength(value + "", 'latin1');
    }

    let lc_name = name.toLowerCase();

    if (lc_name in this.headers) {
        this._removeHeader(lc_name);
    }

    let name_len = Buffer.byteLength(name, 'latin1');

    this.headers[lc_name] = [name, value];
    this.headers_len += value_len + (name_len * count);
    this.headers_count += count;
};

ServerResponse.prototype.getHeader = function getHeader(name) {
    const entry = this.headers[name.toLowerCase()];

    return entry && entry[1];
};

ServerResponse.prototype.getHeaderNames = function getHeaderNames() {
    return Object.keys(this.headers);
};

ServerResponse.prototype.getHeaders = function getHeaders() {
    const ret = Object.create(null);

    if (this.headers) {
        const keys = Object.keys(this.headers);

        for (var i = 0; i < keys.length; i++) {
            const key = keys[i];

            ret[key] = this.headers[key][1];
        }
    }

    return ret;
};

ServerResponse.prototype.hasHeader = function hasHeader(name) {
    return name.toLowerCase() in this.headers;
};

ServerResponse.prototype.removeHeader = function removeHeader(name) {
    if (typeof name !== 'string') {
        throw new TypeError('Name argument must be a string');
    }

    let lc_name = name.toLowerCase();

    if (lc_name in this.headers) {
        this._removeHeader(lc_name);
    }
};

ServerResponse.prototype._removeHeader = function _removeHeader(lc_name) {
    let entry = this.headers[lc_name];
    let name_len = Buffer.byteLength(entry[0] + "", 'latin1');
    let value = entry[1];

    delete this.headers[lc_name];

    if (Array.isArray(value)) {
        this.headers_count -= value.length;
        this.headers_len -= value.length * name_len;

        value.forEach(function(val) {
            this.headers_len -= Buffer.byteLength(val + "", 'latin1');
        });

        return;
    }

    this.headers_count--;
    this.headers_len -= name_len + Buffer.byteLength(value + "", 'latin1');
};

ServerResponse.prototype.sendDate = function sendDate() {
    throw new Error("Not supported");
};

ServerResponse.prototype.setTimeout = function setTimeout(msecs, callback) {
    this.timeout = msecs;

    if (callback) {
        this.on('timeout', callback);
    }

    return this;
};

ServerResponse.prototype.writeHead = writeHead;
ServerResponse.prototype.writeHeader = ServerResponse.prototype.writeHead;

function writeHead(statusCode, reason, obj) {
    var originalStatusCode = statusCode;

    statusCode |= 0;

    if (statusCode < 100 || statusCode > 999) {
        throw new ERR_HTTP_INVALID_STATUS_CODE(originalStatusCode);
    }

    if (typeof reason === 'string') {
        this.statusMessage = reason;

    } else {
        if (!this.statusMessage) {
            this.statusMessage = http.STATUS_CODES[statusCode] || 'unknown';
        }

        obj = reason;
    }

    this.statusCode = statusCode;

    if (obj) {
        var k;
        var keys = Object.keys(obj);

        for (var i = 0; i < keys.length; i++) {
            k = keys[i];

            if (k) {
                this.setHeader(k, obj[k]);
            }
        }
    }
};

/*
 * Some Node.js packages are known to be using this undocumented function,
 * notably "compression" middleware.
 */
ServerResponse.prototype._implicitHeader = function _implicitHeader() {
    this.writeHead(this.statusCode);
};

ServerResponse.prototype._writeBody = function(chunk, encoding, callback) {
    var contentLength = 0;

    if (!this.headersSent) {
        unit_lib.unit_response_headers(this, this.statusCode, this.headers,
                                       this.headers_count, this.headers_len);

        this.headersSent = true;
    }

    if (typeof chunk === 'function') {
        callback = chunk;
        chunk = null;

    } else if (typeof encoding === 'function') {
        callback = encoding;
        encoding = null;
    }

    if (chunk) {
        if (typeof chunk !== 'string' && !(chunk instanceof Buffer)) {
            throw new TypeError('First argument must be a string or Buffer');
        }

        if (typeof chunk === 'string') {
            contentLength = Buffer.byteLength(chunk, encoding);

        } else {
            contentLength = chunk.length;
        }

        unit_lib.unit_response_write(this, chunk, contentLength);
    }

    if (typeof callback === 'function') {
        /*
         * The callback must be called only when response.write() caller
         * completes.  process.nextTick() postpones the callback execution.
         *
         * process.nextTick() is not technically part of the event loop.
         * Instead, the nextTickQueue will be processed after the current
         * operation completes, regardless of the current phase of
         * the event loop.  All callbacks passed to process.nextTick()
         * will be resolved before the event loop continues.
         */
        process.nextTick(function () {
            callback(this);
        }.bind(this));
    }
};

ServerResponse.prototype.write = function write(chunk, encoding, callback) {
    if (this.finished) {
        throw new Error("Write after end");
    }

    this._writeBody(chunk, encoding, callback);

    return true;
};

ServerResponse.prototype.end = function end(chunk, encoding, callback) {
    if (!this.finished) {
        this._writeBody(chunk, encoding, callback);

        unit_lib.unit_response_end(this);

        this.finished = true;
    }

    return this;
};

function ServerRequest(server) {
    EventEmitter.call(this);

    this.server = server;
}
util.inherits(ServerRequest, EventEmitter);

ServerRequest.prototype.unpipe = undefined;

ServerRequest.prototype.setTimeout = function setTimeout(msecs, callback) {
    this.timeout = msecs;

    if (callback) {
        this.on('timeout', callback);
    }

    return this;
};

ServerRequest.prototype.statusCode = function statusCode() {
    /* Only valid for response obtained from http.ClientRequest. */
};

ServerRequest.prototype.statusMessage = function statusMessage() {
    /* Only valid for response obtained from http.ClientRequest. */
};

ServerRequest.prototype.trailers = function trailers() {
    throw new Error("Not supported");
};

ServerRequest.prototype.METHODS = function METHODS() {
    return http.METHODS;
};

ServerRequest.prototype.STATUS_CODES = function STATUS_CODES() {
    return http.STATUS_CODES;
};

ServerRequest.prototype.listeners = function listeners() {
    return [];
};

ServerRequest.prototype.resume = function resume() {
    return [];
};

/*
 * The "on" method is overridden to defer reading data until user code is
 * ready, that is (ev === "data").  This can occur after req.emit("end") is
 * executed, since the user code can be scheduled asynchronously by Promises
 * and so on.  Passing the data is postponed by process.nextTick() until
 * the "on" method caller completes.
 */
ServerRequest.prototype.on = function on(ev, fn) {
    Server.prototype.on.call(this, ev, fn);

    if (ev === "data") {
        process.nextTick(function () {
            if (this.server.buffer.length !== 0) {
                this.emit("data", this.server.buffer);
            }

        }.bind(this));
    }
};

ServerRequest.prototype.addListener = ServerRequest.prototype.on;

function Server(requestListener) {
    EventEmitter.call(this);

    this.unit = new unit_lib.Unit();
    this.unit.server = this;

    this.unit.createServer();

    this.socket = Socket;
    this.request = ServerRequest;
    this.response = ServerResponse;

    if (requestListener) {
        this.on('request', requestListener);
    }
}
util.inherits(Server, EventEmitter);

Server.prototype.setTimeout = function setTimeout(msecs, callback) {
    this.timeout = msecs;

    if (callback) {
        this.on('timeout', callback);
    }

    return this;
};

Server.prototype.listen = function () {
    this.unit.listen();
};

Server.prototype.emit_events = function (server, req, res) {
    req.server = server;
    res.server = server;
    req.res = res;
    res.req = req;

    server.buffer = server.unit._read(req.socket.req_pointer);

    server.emit("request", req, res);

    process.nextTick(() => {
        req.emit("finish");
        req.emit("end");
    });
};

Server.prototype.emit_close = function () {
    this.emit('close');
};

function connectionListener(socket) {
}

module.exports = {
    STATUS_CODES: http.STATUS_CODES,
    Server,
    ServerResponse,
    ServerRequest,
    _connectionListener: connectionListener
};
<|endoftext|>


<commit_before>define([
  "plask",
  "pex/core/Context",
  "pex/gui/ScreenImage",
  "pex/util/Time",
  "pex/gui/SkiaRenderer",
  "pex/gui/HTMLCanvasRenderer",
  "pex/core/Rect",
  "pex/sys/IO"
],
function(plask, Context, ScreenImage, Time, SkiaRenderer, HTMLCanvasRenderer, Rect, IO) {
  function GUIControl(o) {
    for(var i in o) {
      this[i] = o[i];
    }
  }

  GUIControl.prototype.setPosition = function(x, y) {
    this.px = x;
    this.py = y;
  }

  GUIControl.prototype.getNormalizedValue = function() {
    if (!this.contextObject) return "";

    var val = this.contextObject[this.attributeName];
    var options = this.options;
    if (options && options.min !== undefined && options.max !== undefined) {
      val = (val - options.min) / (options.max - options.min);
    }
    return val;
  }

  GUIControl.prototype.setNormalizedValue = function(val) {
    if (!this.contextObject) return;

    var options = this.options;
    if (options && options.min !== undefined && options.max !== undefined) {
      val = options.min + val * (options.max - options.min);
    }
    this.contextObject[this.attributeName] = val;
  }

  GUIControl.prototype.getValue = function() {
    if (this.type == "slider") {
      return Math.floor(this.contextObject[this.attributeName]*100)/100;
    }
    else return 0;
  }

  function GUI(window, x, y) {
    this.gl = Context.currentContext.gl;
    this.x = (x == undefined) ? 0 : x;
    this.y = (y == undefined) ? 0 : y;

    if (plask.SkCanvas) {
      this.renderer = new SkiaRenderer(window.width, window.height);
    }
    else {
      this.renderer = new HTMLCanvasRenderer(window.width, window.height);
    }

    this.screenImage = new ScreenImage(window.width, window.height, this.x, this.y, window.width, window.height, this.renderer.getTexture());

    this.items = [];

    this.bindEventListeners(window);
  }

  GUI.prototype.bindEventListeners = function(window) {
    var self = this;
    window.on("leftMouseDown", function(e) {
      self.onMouseDown(e);
    });

    window.on("mouseDragged", function(e) {
      self.onMouseDrag(e);
    });

    window.on("leftMouseUp", function(e) {
      self.onMouseUp(e);
    });
  }

  GUI.prototype.onMouseDown = function(e) {
    this.activeControl = null;
    var mousePos = { x : e.x - this.x, y : e.y - this.y }
    for(var i=0; i<this.items.length; i++) {
      if (this.items[i].activeArea.contains(mousePos)) {
        this.activeControl = this.items[i];
        this.activeControl.active = true;
        if (this.activeControl.type == "button") {
          this.activeControl.contextObject[this.activeControl.methodName]();
        }
        else if (this.activeControl.type == "toggle") {
          this.activeControl.contextObject[this.activeControl.attributeName] = !this.activeControl.contextObject[this.activeControl.attributeName];
          if (this.activeControl.onchange) {
            this.activeControl.onchange(this.activeControl.contextObject[this.activeControl.attributeName]);
          }
        }
        else if (this.activeControl.type == "radiolist") {
          var hitY = mousePos.y - this.activeControl.activeArea.y;
          var hitItemIndex = Math.floor(this.activeControl.items.length * hitY/this.activeControl.activeArea.height);
          if (hitItemIndex < 0) continue;
          if (hitItemIndex >= this.activeControl.items.length) continue;
          this.activeControl.contextObject[this.activeControl.attributeName] = this.activeControl.items[hitItemIndex].value;
          if (this.activeControl.onchange) {
            this.activeControl.onchange(this.activeControl.items[hitItemIndex].value);
          }
        }
        e.handled = true;
        this.onMouseDrag(e);
        break;
      }
    }
  }

  GUI.prototype.onMouseDrag = function(e) {
    if (this.activeControl) {
      var aa = this.activeControl.activeArea;
      if (this.activeControl.type == "slider") {
        var val = (e.x - aa.x) / aa.width;
        val = Math.max(0, Math.min(val, 1));
        this.activeControl.setNormalizedValue(val);
        if (this.activeControl.onchange) {
          this.activeControl.onchange(this.activeControl.contextObject[this.activeControl.attributeName]);
        }
      }
      e.handled = true;
    }
  }

  GUI.prototype.onMouseUp = function(e) {
    if (this.activeControl) {
      this.activeControl.active = false;
      this.activeControl = null;
    }
  }

  GUI.prototype.addLabel = function(title) {
    var ctrl = new GUIControl(
      { type: "label", title: title, activeArea: new Rect(0, 0, 0, 0) }
    );
    this.items.push(ctrl);
    return ctrl;
  }

  GUI.prototype.addParam = function(title, contextObject, attributeName, options, onchange) {
    options = options || {};
    if (attributeName == "[]") {
      var ctrl = new GUIControl(
        {
          type: "multislider",
          title: title,
          contextObject: contextObject,
          attributeName: attributeName,
          activeArea: new Rect(0, 0, 0, 0),
          options: options,
          onchange : onchange
        }
      );
      this.items.push(ctrl);
      return ctrl;
    }
    else if (contextObject[attributeName] === false || contextObject[attributeName] === true) {
      var ctrl = new GUIControl(
        {
          type: "toggle",
          title: title,
          contextObject: contextObject,
          attributeName: attributeName,
          activeArea: new Rect(0, 0, 0, 0),
          options: options,
          onchange : onchange
        }
      );
      this.items.push(ctrl);
      return ctrl;
    }
    else {
      var ctrl = new GUIControl(
        {
          type: "slider",
          title: title,
          contextObject: contextObject,
          attributeName: attributeName,
          activeArea: new Rect(0, 0, 0, 0),
          options: options,
          onchange : onchange
        }
      );
      this.items.push(ctrl);
      return ctrl;
    }
  }

  GUI.prototype.addButton = function(title, contextObject, methodName) {
    var ctrl = new GUIControl(
      {
        type: "button",
        title: title,
        contextObject: contextObject,
        methodName: methodName,
        activeArea: new Rect(0, 0, 0, 0)
      }
    );
    this.items.push(ctrl);
    return ctrl;
  }

  GUI.prototype.addRadioList = function(title, contextObject, attributeName, items, onchange) {
    var ctrl = new GUIControl(
      {
        type: "radiolist",
        title: title,
        contextObject: contextObject,
        attributeName: attributeName,
        activeArea: new Rect(0, 0, 0, 0),
        items: items,
        onchange : onchange
      }
    );
    this.items.push(ctrl);
    return ctrl;

  }

  GUI.prototype.dispose = function() {
    //TODO: delete texture object
  }

  var frame = 0;
  GUI.prototype.draw = function() {
    Time.update();

    this.renderer.draw(this.items);
    this.screenImage.draw();
  }

  GUI.prototype.serialize = function() {
    var data = {};
    this.items.forEach(function(item, i) {
      data[item.title] = item.getNormalizedValue();
    })
    return data;
  }

  GUI.prototype.deserialize = function(data) {
    this.items.forEach(function(item, i) {
      if (!(data[item.title] == undefined)) {
        item.setNormalizedValue(data[item.title]);
      }
    })
  }

  GUI.prototype.save = function(path) {
    var data = this.serialize();
    IO.saveTextFile(path, JSON.stringify(data));
  }

  GUI.prototype.load = function(path) {
    var self = this;
    IO.loadTextFile(path, function(dataStr) {
      var data = JSON.parse(dataStr);
      self.deserialize(data);
    })
  }

  GUI.ScreenImage = ScreenImage;

  return GUI;
});
<commit_msg>Texture2D param support in GUI<commit_after>define([
  "plask",
  "pex/core/Context",
  "pex/gui/ScreenImage",
  "pex/util/Time",
  "pex/gui/SkiaRenderer",
  "pex/gui/HTMLCanvasRenderer",
  "pex/core/Rect",
  "pex/sys/IO"
],
function(plask, Context, ScreenImage, Time, SkiaRenderer, HTMLCanvasRenderer, Rect, IO) {
  function GUIControl(o) {
    for(var i in o) {
      this[i] = o[i];
    }
  }

  GUIControl.prototype.setPosition = function(x, y) {
    this.px = x;
    this.py = y;
  }

  GUIControl.prototype.getNormalizedValue = function() {
    if (!this.contextObject) return "";

    var val = this.contextObject[this.attributeName];
    var options = this.options;
    if (options && options.min !== undefined && options.max !== undefined) {
      val = (val - options.min) / (options.max - options.min);
    }
    return val;
  }

  GUIControl.prototype.setNormalizedValue = function(val) {
    if (!this.contextObject) return;

    var options = this.options;
    if (options && options.min !== undefined && options.max !== undefined) {
      val = options.min + val * (options.max - options.min);
    }
    this.contextObject[this.attributeName] = val;
  }

  GUIControl.prototype.getValue = function() {
    if (this.type == "slider") {
      return Math.floor(this.contextObject[this.attributeName]*100)/100;
    }
    else return 0;
  }

  function GUI(window, x, y) {
    this.gl = Context.currentContext.gl;
    this.window = window;
    x = (x == undefined) ? 0 : x;
    y = (y == undefined) ? 0 : y;

    if (plask.SkCanvas) {
      this.renderer = new SkiaRenderer(window.width, window.height);
    }
    else {
      this.renderer = new HTMLCanvasRenderer(window.width, window.height);
    }

    this.screenBounds = new Rect(x, y, window.width, window.height);
    this.screenImage = new ScreenImage(window.width, window.height, x, y, window.width, window.height, this.renderer.getTexture());

    this.items = [];

    this.bindEventListeners(window);
  }

  GUI.prototype.bindEventListeners = function(window) {
    var self = this;
    window.on("leftMouseDown", function(e) {
      self.onMouseDown(e);
    });

    window.on("mouseDragged", function(e) {
      self.onMouseDrag(e);
    });

    window.on("leftMouseUp", function(e) {
      self.onMouseUp(e);
    });
  }

  GUI.prototype.onMouseDown = function(e) {
    this.activeControl = null;
    var mousePos = { x : e.x - this.x, y : e.y - this.y }
    for(var i=0; i<this.items.length; i++) {
      if (this.items[i].activeArea.contains(mousePos)) {
        this.activeControl = this.items[i];
        this.activeControl.active = true;
        if (this.activeControl.type == "button") {
          this.activeControl.contextObject[this.activeControl.methodName]();
        }
        else if (this.activeControl.type == "toggle") {
          this.activeControl.contextObject[this.activeControl.attributeName] = !this.activeControl.contextObject[this.activeControl.attributeName];
          if (this.activeControl.onchange) {
            this.activeControl.onchange(this.activeControl.contextObject[this.activeControl.attributeName]);
          }
        }
        else if (this.activeControl.type == "radiolist") {
          var hitY = mousePos.y - this.activeControl.activeArea.y;
          var hitItemIndex = Math.floor(this.activeControl.items.length * hitY/this.activeControl.activeArea.height);
          if (hitItemIndex < 0) continue;
          if (hitItemIndex >= this.activeControl.items.length) continue;
          this.activeControl.contextObject[this.activeControl.attributeName] = this.activeControl.items[hitItemIndex].value;
          if (this.activeControl.onchange) {
            this.activeControl.onchange(this.activeControl.items[hitItemIndex].value);
          }
        }
        e.handled = true;
        this.onMouseDrag(e);
        break;
      }
    }
  }

  GUI.prototype.onMouseDrag = function(e) {
    if (this.activeControl) {
      var aa = this.activeControl.activeArea;
      if (this.activeControl.type == "slider") {
        var val = (e.x - aa.x) / aa.width;
        val = Math.max(0, Math.min(val, 1));
        this.activeControl.setNormalizedValue(val);
        if (this.activeControl.onchange) {
          this.activeControl.onchange(this.activeControl.contextObject[this.activeControl.attributeName]);
        }
      }
      e.handled = true;
    }
  }

  GUI.prototype.onMouseUp = function(e) {
    if (this.activeControl) {
      this.activeControl.active = false;
      this.activeControl = null;
    }
  }

  GUI.prototype.addLabel = function(title) {
    var ctrl = new GUIControl(
      { type: "label", title: title, activeArea: new Rect(0, 0, 0, 0) }
    );
    this.items.push(ctrl);
    return ctrl;
  }

  GUI.prototype.addParam = function(title, contextObject, attributeName, options, onchange) {
    options = options || {};
    if (attributeName == "[]") {
      var ctrl = new GUIControl(
        {
          type: "multislider",
          title: title,
          contextObject: contextObject,
          attributeName: attributeName,
          activeArea: new Rect(0, 0, 0, 0),
          options: options,
          onchange : onchange
        }
      );
      this.items.push(ctrl);
      return ctrl;
    }
    else if (contextObject[attributeName] === false || contextObject[attributeName] === true) {
      var ctrl = new GUIControl(
        {
          type: "toggle",
          title: title,
          contextObject: contextObject,
          attributeName: attributeName,
          activeArea: new Rect(0, 0, 0, 0),
          options: options,
          onchange : onchange
        }
      );
      this.items.push(ctrl);
      return ctrl;
    }
    else {
      var ctrl = new GUIControl(
        {
          type: "slider",
          title: title,
          contextObject: contextObject,
          attributeName: attributeName,
          activeArea: new Rect(0, 0, 0, 0),
          options: options,
          onchange : onchange
        }
      );
      this.items.push(ctrl);
      return ctrl;
    }
  }

  GUI.prototype.addButton = function(title, contextObject, methodName) {
    var ctrl = new GUIControl(
      {
        type: "button",
        title: title,
        contextObject: contextObject,
        methodName: methodName,
        activeArea: new Rect(0, 0, 0, 0)
      }
    );
    this.items.push(ctrl);
    return ctrl;
  }

  GUI.prototype.addRadioList = function(title, contextObject, attributeName, items, onchange) {
    var ctrl = new GUIControl(
      {
        type: "radiolist",
        title: title,
        contextObject: contextObject,
        attributeName: attributeName,
        activeArea: new Rect(0, 0, 0, 0),
        items: items,
        onchange : onchange
      }
    );
    this.items.push(ctrl);
    return ctrl;
  }

  GUI.prototype.addTexture2D = function(title, texture) {
    var ctrl = new GUIControl(
      {
        type: "texture2D",
        title: title,
        texture: texture,
        activeArea: new Rect(0, 0, 0, 0)
      }
    );
    this.items.push(ctrl);
    return ctrl;
  }

  GUI.prototype.dispose = function() {
    //TODO: delete texture object
  }

  var frame = 0;
  GUI.prototype.draw = function() {
    Time.update();

    this.renderer.draw(this.items);
    this.screenImage.draw();
    this.drawTextures();
  }

  GUI.prototype.drawTextures = function() {
    for(var i=0; i<this.items.length; i++) {
      var item = this.items[i];
      if (item.type == "texture2D") {
        if (item.texture.bind) item.texture.bind();
        else {
          this.gl.bindTexture(item.texture.target, item.texture.handle);
        }
        this.screenImage.setBounds(item.activeArea);
        this.screenImage.setTexture(null);
        this.screenImage.draw();
      }
    }
    this.screenImage.setBounds(this.screenBounds);
    this.screenImage.setTexture(this.renderer.getTexture());
  }

  GUI.prototype.serialize = function() {
    var data = {};
    this.items.forEach(function(item, i) {
      data[item.title] = item.getNormalizedValue();
    })
    return data;
  }

  GUI.prototype.deserialize = function(data) {
    this.items.forEach(function(item, i) {
      if (!(data[item.title] == undefined)) {
        item.setNormalizedValue(data[item.title]);
      }
    })
  }

  GUI.prototype.save = function(path) {
    var data = this.serialize();
    IO.saveTextFile(path, JSON.stringify(data));
  }

  GUI.prototype.load = function(path) {
    var self = this;
    IO.loadTextFile(path, function(dataStr) {
      var data = JSON.parse(dataStr);
      self.deserialize(data);
    })
  }

  GUI.ScreenImage = ScreenImage;

  return GUI;
});
<|endoftext|>


<commit_before>/* eslint-env browser */
'use strict'

let	d3 = require('d3'),
	tnt = require('tnt.utils'),
	tntTree = require('tnt.tree'),
	parser = require('tnt.newick'),
	treeLayout = require('./treelayout.js'),
	utils = require('./utils.js'),
	treeOperations = require('./treeOperations.js'),
	tntTooltip = require('./tnt_tooltip.js')

let tree = tntTree()
let expandedNode = tntTree.node_display.circle()
let collapsedNode = tntTree.node_display.triangle()
let fontSizeOfTreeLeafs = 12
let nodeSize = 3
let nodeDisplay = tree.node_display()
	.size(nodeSize)
	.fill('black')
	.display(function(node) {
		if (node.is_collapsed())
			collapsedNode.display().call(this, node)
		else
			expandedNode.display().call(this, node)
	})

// creates the tree and renders it to the div 'treeBox'
exports.makeTree = function(newickString) {
	if (document.getElementsByClassName('tnt_groupDiv').length !== 0) {
		let existingTree = document.getElementsByClassName('tnt_groupDiv')[0]
		document.getElementById('treeBox').removeChild(existingTree)
	}

	let treeBox = document.getElementById('treeBox')

	let treeObj = parser.parse_newick(newickString),
		numOfLeaves = utils.countLeaves(treeObj)

	tree
		.data(treeObj)
		.node_display(nodeDisplay)
		.label(tntTree.label
			.text()
			.fontsize(fontSizeOfTreeLeafs)
			.height(window.innerHeight / (numOfLeaves + 4))
		)
		.layout(tntTree.layout.vertical()
			.width(window.innerWidth)
			.scale(false)
		)
	tree(treeBox)

	let svgTree = d3.select('#treeBox').select('svg'),
		g = svgTree.select('g')

	svgTree.call(d3.zoom()
		.on('zoom', () => {
			g.attr('transform', d3.event.transform)
		})
	)
}

// resets the zoom and transform of tree to original
exports.fitScreen = function() {
	let svgTree = d3.select('#treeBox').select('svg'),
		g = svgTree.select('g')

	svgTree.call(d3.zoom().transform, d3.zoomIdentity)
	g.attr('transform', {k: 1, x: 0, y: 0})
}

// calls the function to update the layout of the tree to vertical view
exports.updateVertical = function() {
	treeLayout.updateVertical(tree)
}

// calls the function to update the layout of the tree to radial view
exports.updateRadial = function() {
	treeLayout.updateRadial(tree)
}

// calls the function to toggle support values displayed at individual nodes
exports.toggleSupport = function() {
	treeOperations.toggleSupport()
}

// calls the function to change the branch color of the subtree of the node #[nodeID]
exports.changeBranchColor = function(e, nodeID, numOfChildren) {
	treeOperations.changeBranchColor(e, nodeID, numOfChildren)
}

// calls the function to change the branch width of the subtree of the node #[nodeID]
exports.changeBranchWidth = function(e, nodeID, numOfChildren) {
	treeOperations.changeBranchWidth(e, nodeID, numOfChildren)
}

// exports a PNG image of the SVG display
exports.exportPNG = function(e) {
	let pngExporter = tnt.png()
		.filename('treeSample.png')
	pngExporter(d3.select('#treeBox')
		.select('svg'))
}

let min = 1000

// helper function for sorting
function getShortestPathToLeaf(node) {
	if (node.is_leaf()) {
		return 1
	}
	let x = node.children()
	for (let i = 0; i < x.length; i++) {
		temp = 1 + getShortestPathToLeaf(x[i])
		if (temp < min) {
			min = temp
			temp = 0
		}
	}
}

// sorts the tree ?? (need better description)
exports.ladderizeTree = function() {
	tree.root().sort(function(node1, node2) {
		let highest1 = getShortestPathToLeaf(node1)
		let highest2 = getShortestPathToLeaf(node2)
		return getShortestPathToLeaf(node1) - getShortestPathToLeaf(node2)
	})
	tree.update()
}

// changes the expanded node shape of the tree
exports.changeExpandedNodeShape = function(shape) {
	if (shape === 'circle') {
		expandedNode = tntTree.node_display.circle()
	}
	else if (shape === 'triangle') {
		expandedNode = tntTree.node_display.triangle()
	}
	else if (shape === 'rectangle') {
		expandedNode = tntTree.node_display.rectangle()
	}
	tree.node_display(nodeDisplay)
	tree.update_nodes()
}

// installs a listener at each node that displays a tooltip upon click
tree.on('click', function(node) {
	// resets color of all nodes to black
	d3.selectAll('.tnt_tree_node')
		.selectAll('.tnt_node_display_elem')
		.attr('fill', 'black')

	// generates tooltip for selected node
	tntTooltip.table(tree, node)
		.width(120)
		.call(this, {
			'header' : 'Node #' + node.id(),
			/* "rows" : [
				{"label": "ID", "value": node.id()}
			] */
		})
})

// module.exports = 'phylogician'
<commit_msg>framework for collapsed node modification<commit_after>/* eslint-env browser */
'use strict'

let	d3 = require('d3'),
	tnt = require('tnt.utils'),
	tntTree = require('tnt.tree'),
	parser = require('tnt.newick'),
	treeLayout = require('./treelayout.js'),
	utils = require('./utils.js'),
	treeOperations = require('./treeOperations.js'),
	tntTooltip = require('./tnt_tooltip.js')

let tree = tntTree()
let expandedNode = tntTree.node_display.circle()
let collapsedNode = tntTree.node_display.triangle()
let fontSizeOfTreeLeafs = 12
let nodeSize = 3
let nodeDisplay = tree.node_display()
	.size(nodeSize)
	.fill('black')
	.display(function(node) {
		if (node.is_collapsed())
			collapsedNode.display().call(this, node)
		else
			expandedNode.display().call(this, node)
	})

// creates the tree and renders it to the div 'treeBox'
exports.makeTree = function(newickString) {
	if (document.getElementsByClassName('tnt_groupDiv').length !== 0) {
		let existingTree = document.getElementsByClassName('tnt_groupDiv')[0]
		document.getElementById('treeBox').removeChild(existingTree)
	}

	let treeBox = document.getElementById('treeBox')

	let treeObj = parser.parse_newick(newickString),
		numOfLeaves = utils.countLeaves(treeObj)

	tree
		.data(treeObj)
		.node_display(nodeDisplay)
		.label(tntTree.label
			.text()
			.fontsize(fontSizeOfTreeLeafs)
			.height(window.innerHeight / (numOfLeaves + 4))
		)
		.layout(tntTree.layout.vertical()
			.width(window.innerWidth)
			.scale(false)
		)
	tree(treeBox)

	let svgTree = d3.select('#treeBox').select('svg'),
		g = svgTree.select('g')

	svgTree.call(d3.zoom()
		.on('zoom', () => {
			g.attr('transform', d3.event.transform)
		})
	)
}

// resets the zoom and transform of tree to original
exports.fitScreen = function() {
	let svgTree = d3.select('#treeBox').select('svg'),
		g = svgTree.select('g')

	svgTree.call(d3.zoom().transform, d3.zoomIdentity)
	g.attr('transform', {k: 1, x: 0, y: 0})
}

// calls the function to update the layout of the tree to vertical view
exports.updateVertical = function() {
	treeLayout.updateVertical(tree)
}

// calls the function to update the layout of the tree to radial view
exports.updateRadial = function() {
	treeLayout.updateRadial(tree)
}

// calls the function to toggle support values displayed at individual nodes
exports.toggleSupport = function() {
	treeOperations.toggleSupport()
}

// calls the function to change the branch color of the subtree of the node #[nodeID]
exports.changeBranchColor = function(e, nodeID, numOfChildren) {
	treeOperations.changeBranchColor(e, nodeID, numOfChildren)
}

// calls the function to change the branch width of the subtree of the node #[nodeID]
exports.changeBranchWidth = function(e, nodeID, numOfChildren) {
	treeOperations.changeBranchWidth(e, nodeID, numOfChildren)
}

// exports a PNG image of the SVG display
exports.exportPNG = function(e) {
	let pngExporter = tnt.png()
		.filename('treeSample.png')
	pngExporter(d3.select('#treeBox')
		.select('svg'))
}

let min = 1000

// helper function for sorting
function getShortestPathToLeaf(node) {
	if (node.is_leaf()) {
		return 1
	}
	let x = node.children()
	for (let i = 0; i < x.length; i++) {
		temp = 1 + getShortestPathToLeaf(x[i])
		if (temp < min) {
			min = temp
			temp = 0
		}
	}
}

// sorts the tree ?? (need better description)
exports.ladderizeTree = function() {
	tree.root().sort(function(node1, node2) {
		let highest1 = getShortestPathToLeaf(node1)
		let highest2 = getShortestPathToLeaf(node2)
		return getShortestPathToLeaf(node1) - getShortestPathToLeaf(node2)
	})
	tree.update()
}

// changes the expanded node shape of the tree
exports.changeExpandedNodeShape = function(shape) {
	if (shape === 'circle') {
		expandedNode = tntTree.node_display.circle()
	}
	else if (shape === 'triangle') {
		expandedNode = tntTree.node_display.triangle()
	}
	else if (shape === 'rectangle') {
		expandedNode = tntTree.node_display.rectangle()
	}
	tree.node_display(nodeDisplay)
	tree.update_nodes()
}

// changes the collapsed node shape of the tree -- TO BE COMPLETED
exports.changeCollapsedNodeShape = function(shape) {
	tree.update_nodes()
}

// installs a listener at each node that displays a tooltip upon click
tree.on('click', function(node) {
	// resets color of all nodes to black
	d3.selectAll('.tnt_tree_node')
		.selectAll('.tnt_node_display_elem')
		.attr('fill', 'black')

	// generates tooltip for selected node
	tntTooltip.table(tree, node)
		.width(120)
		.call(this, {
			'header' : 'Node #' + node.id(),
			/* "rows" : [
				{"label": "ID", "value": node.id()}
			] */
		})
})

// module.exports = 'phylogician'
<|endoftext|>