<commit_before>var IS_VNODE = 0
var IS_RECYCLED = 1
var IS_TEXT_NODE = 2

var EMPTY_OBJECT = {}
var EMPTY_ARRAY = []

var map = [].map
var isArray = Array.isArray

var isNull = function(any) {
  return any === null || any === undefined
}

var merge = function(a, b) {
  var target = []

  for (var i in a) target[i] = a[i]
  for (var i in b) target[i] = b[i]

  return target
}

var eventProxy = function(event) {
  return event.currentTarget.events[event.type](event)
}

var updateProperty = function(element, name, lastValue, nextValue, isSvg) {
  if (name === "key") {
  } else if (name === "style") {
    for (var i in merge(lastValue, nextValue)) {
      var style = nextValue == null || nextValue[i] == null ? "" : nextValue[i]
      if (i[0] === "-") {
        element[name].setProperty(i, style)
      } else {
        element[name][i] = style
      }
    }
  } else {
    if (name[0] === "o" && name[1] === "n") {
      if (!element.events) element.events = {}
      element.events[(name = name.slice(2))] = nextValue

      if (isNull(nextValue)) {
        element.removeEventListener(name, eventProxy)
      } else if (isNull(lastValue)) {
        element.addEventListener(name, eventProxy)
      }
    } else if (name in element && name !== "list" && !isSvg) {
      element[name] = isNull(nextValue) ? "" : nextValue
    } else if (!isNull(nextValue) && nextValue !== false) {
      element.setAttribute(name, nextValue)
    }

    if (isNull(nextValue) || nextValue === false) {
      element.removeAttribute(name)
    }
  }
}

var createElement = function(node, lifecycle, isSvg) {
  var element =
    node.flags & IS_TEXT_NODE
      ? document.createTextNode(node.name)
      : (isSvg = isSvg || node.name === "svg")
        ? document.createElementNS("http://www.w3.org/2000/svg", node.name)
        : document.createElement(node.name)

  var props = node.props
  if (props) {
    if (props.oncreate) {
      lifecycle.push(function() {
        props.oncreate(element)
      })
    }

    for (var i = 0; i < node.children.length; i++) {
      element.appendChild(createElement(node.children[i], lifecycle, isSvg))
    }

    for (var name in props) {
      updateProperty(element, name, null, props[name], isSvg)
    }
  }

  return (node.element = element)
}

var updateElement = function(
  element,
  lastProps,
  nextProps,
  lifecycle,
  isSvg,
  isRecycled
) {
  for (var name in merge(lastProps, nextProps)) {
    if (
      (name === "value" || name === "checked"
        ? element[name]
        : lastProps[name]) !== nextProps[name]
    ) {
      updateProperty(element, name, lastProps[name], nextProps[name], isSvg)
    }
  }

  var cb = isRecycled ? nextProps.oncreate : nextProps.onupdate
  if (cb) {
    lifecycle.push(function() {
      cb(element, lastProps)
    })
  }
}

var removeChildren = function(node) {
  var props = node.props
  if (props) {
    for (var i = 0; i < node.children.length; i++) {
      removeChildren(node.children[i])
    }

    if (props.ondestroy) {
      props.ondestroy(node.element)
    }
  }
  return node.element
}

var removeElement = function(parent, node) {
  var remove = function() {
    parent.removeChild(removeChildren(node))
  }
  var cb = node.props && node.props.onremove
  if (cb) {
    cb(node.element, remove)
  } else {
    remove()
  }
}

var getKey = function(node) {
  return node ? node.key : null
}

var patchElement = function(
  parent,
  element,
  lastNode,
  nextNode,
  lifecycle,
  isSvg
) {
  if (nextNode === lastNode) {
  } else if (
    !isNull(lastNode) &&
    lastNode.flags & IS_TEXT_NODE &&
    nextNode.flags & IS_TEXT_NODE
  ) {
    if (lastNode.name !== nextNode.name) {
      element.nodeValue = nextNode.name
    }
  } else if (isNull(lastNode) || lastNode.name !== nextNode.name) {
    var newElement = parent.insertBefore(
      createElement(nextNode, lifecycle, isSvg),
      element
    )

    if (!isNull(lastNode)) removeElement(parent, lastNode)

    element = newElement
  } else {
    updateElement(
      element,
      lastNode.props,
      nextNode.props,
      lifecycle,
      (isSvg = isSvg || nextNode.name === "svg"),
      lastNode.flags & IS_RECYCLED
    )

    var child
    var lastCh = lastNode.children
    var lastChStart = 0
    var nextChStart = 0
    var nextCh = nextNode.children
    var lastChEnd = lastCh.length - 1
    var nextChEnd = nextCh.length - 1

    while (nextChStart <= nextChEnd && lastChStart <= lastChEnd) {
      var lastKey = getKey(lastCh[lastChStart])
      var nextKey = getKey(nextCh[nextChStart])

      if (isNull(lastKey) || lastKey !== nextKey) break

      patchElement(
        element,
        lastCh[lastChStart].element,
        lastCh[lastChStart],
        nextCh[nextChStart],
        lifecycle,
        isSvg
      )

      lastChStart++
      nextChStart++
    }

    while (nextChStart <= nextChEnd && lastChStart <= lastChEnd) {
      var lastKey = getKey(lastCh[lastChEnd])
      var nextKey = getKey(nextCh[nextChEnd])

      if (isNull(lastKey) || lastKey !== nextKey) break

      patchElement(
        element,
        lastCh[lastChEnd].element,
        lastCh[lastChEnd],
        nextCh[nextChEnd],
        lifecycle,
        isSvg
      )

      lastChEnd--
      nextChEnd--
    }

    if (lastChStart > lastChEnd) {
      while (nextChStart <= nextChEnd) {
        element.insertBefore(
          createElement(nextCh[nextChStart], lifecycle, isSvg),
          isNull((child = lastCh[lastChStart])) ? null : child.element
        )
        nextChStart++
      }
    } else if (nextChStart > nextChEnd) {
      while (lastChStart <= lastChEnd) {
        removeElement(element, lastCh[lastChStart++])
      }
    } else {
      var lastKeyed = {}
      var nextKeyed = {}

      for (var i = lastChStart, key; i <= lastChEnd; i++) {
        if (!isNull((key = getKey((child = lastCh[i]))))) {
          lastKeyed[key] = child
        }
      }

      var i = lastChStart
      var k = nextChStart

      while (k <= nextChEnd) {
        var lastKey = getKey((child = lastCh[i]))
        var nextKey = getKey(nextCh[k])

        if (nextKeyed[lastKey]) {
          i++
          continue
        }

        if (!isNull(nextKey) && nextKey === getKey(lastCh[i + 1])) {
          if (isNull(lastKey)) {
            removeElement(element, child)
          }
          i++
          continue
        }

        if (isNull(nextKey) || lastNode.flags & IS_RECYCLED) {
          if (isNull(lastKey)) {
            patchElement(
              element,
              child && child.element,
              child,
              nextCh[k],
              lifecycle,
              isSvg
            )
            k++
          }
          i++
        } else {
          var foundNode = lastKeyed[nextKey]

          if (lastKey === nextKey) {
            patchElement(
              element,
              foundNode.element,
              foundNode,
              nextCh[k],
              lifecycle,
              isSvg
            )
            i++
          } else if (foundNode && foundNode.element) {
            patchElement(
              element,
              element.insertBefore(foundNode.element, child && child.element),
              foundNode,
              nextCh[k],
              lifecycle,
              isSvg
            )
          } else {
            patchElement(
              element,
              child && child.element,
              null,
              nextCh[k],
              lifecycle,
              isSvg
            )
          }

          nextKeyed[nextKey] = nextCh[k]
          k++
        }
      }

      while (i <= lastChEnd) {
        if (isNull(getKey((child = lastCh[i++])))) {
          removeElement(element, child)
        }
      }

      for (var key in lastKeyed) {
        if (isNull(nextKeyed[key])) {
          removeElement(element, lastKeyed[key])
        }
      }
    }
  }

  return (nextNode.element = element)
}

var createVNode = function(name, props, children, element, key, flags) {
  return {
    name: name,
    props: props,
    children: children,
    element: element,
    key: key,
    flags: flags
  }
}

var createTextVNode = function(text, element) {
  return createVNode(
    text,
    EMPTY_OBJECT,
    EMPTY_ARRAY,
    element,
    null,
    IS_TEXT_NODE
  )
}

var recycleChild = function(element) {
  return element.nodeType === 3 // Node.TEXT_NODE
    ? createTextVNode(element.nodeValue, element)
    : recycleElement(element)
}

var recycleElement = function(element) {
  return createVNode(
    element.nodeName.toLowerCase(),
    EMPTY_OBJECT,
    map.call(element.childNodes, recycleChild),
    element,
    null,
    IS_RECYCLED
  )
}

export var recycle = function(container) {
  return recycleElement(container.children[0])
}

export var patch = function(lastNode, nextNode, container) {
  var lifecycle = []

  patchElement(container, container.children[0], lastNode, nextNode, lifecycle)

  while (lifecycle.length) lifecycle.pop()()

  return nextNode
}

export var h = function(name, props) {
  var node
  var rest = []
  var children = []
  var length = arguments.length

  while (length-- > 2) rest.push(arguments[length])

  if (!isNull((props = props || {}).children)) {
    rest.push(props.children)
    delete props.children
  }

  while (rest.length > 0) {
    if ((node = rest.pop()) && isArray(node)) {
      for (length = node.length; length--; ) {
        rest.push(node[length])
      }
    } else if (isNull(node) || node === true || node === false) {
    } else {
      children.push(typeof node === "object" ? node : createTextVNode(node))
    }
  }

  return typeof name === "function"
    ? name(props, (props.children = children))
    : createVNode(name, props, children, null, props.key, IS_VNODE)
}
<commit_msg>Refactor mapping of old keyed nodes into a function.<commit_after>var IS_VNODE = 0
var IS_RECYCLED = 1
var IS_TEXT_NODE = 2

var EMPTY_OBJECT = {}
var EMPTY_ARRAY = []

var map = [].map
var isArray = Array.isArray

var isNull = function(any) {
  return any === null || any === undefined
}

var merge = function(a, b) {
  var target = []

  for (var i in a) target[i] = a[i]
  for (var i in b) target[i] = b[i]

  return target
}

var eventProxy = function(event) {
  return event.currentTarget.events[event.type](event)
}

var updateProperty = function(element, name, lastValue, nextValue, isSvg) {
  if (name === "key") {
  } else if (name === "style") {
    for (var i in merge(lastValue, nextValue)) {
      var style = nextValue == null || nextValue[i] == null ? "" : nextValue[i]
      if (i[0] === "-") {
        element[name].setProperty(i, style)
      } else {
        element[name][i] = style
      }
    }
  } else {
    if (name[0] === "o" && name[1] === "n") {
      if (!element.events) element.events = {}
      element.events[(name = name.slice(2))] = nextValue

      if (isNull(nextValue)) {
        element.removeEventListener(name, eventProxy)
      } else if (isNull(lastValue)) {
        element.addEventListener(name, eventProxy)
      }
    } else if (name in element && name !== "list" && !isSvg) {
      element[name] = isNull(nextValue) ? "" : nextValue
    } else if (!isNull(nextValue) && nextValue !== false) {
      element.setAttribute(name, nextValue)
    }

    if (isNull(nextValue) || nextValue === false) {
      element.removeAttribute(name)
    }
  }
}

var createElement = function(node, lifecycle, isSvg) {
  var element =
    node.flags & IS_TEXT_NODE
      ? document.createTextNode(node.name)
      : (isSvg = isSvg || node.name === "svg")
        ? document.createElementNS("http://www.w3.org/2000/svg", node.name)
        : document.createElement(node.name)

  var props = node.props
  if (props.oncreate) {
    lifecycle.push(function() {
      props.oncreate(element)
    })
  }

  for (var i = 0, length = node.children.length; i < length; i++) {
    element.appendChild(createElement(node.children[i], lifecycle, isSvg))
  }

  for (var name in props) {
    updateProperty(element, name, null, props[name], isSvg)
  }

  return (node.element = element)
}

var updateElement = function(
  element,
  lastProps,
  nextProps,
  lifecycle,
  isSvg,
  isRecycled
) {
  for (var name in merge(lastProps, nextProps)) {
    if (
      (name === "value" || name === "checked"
        ? element[name]
        : lastProps[name]) !== nextProps[name]
    ) {
      updateProperty(element, name, lastProps[name], nextProps[name], isSvg)
    }
  }

  var cb = isRecycled ? nextProps.oncreate : nextProps.onupdate
  if (cb) {
    lifecycle.push(function() {
      cb(element, lastProps)
    })
  }
}

var removeChildren = function(node) {
  for (var i = 0, length = node.children.length; i < length; i++) {
    removeChildren(node.children[i])
  }

  if (node.props.ondestroy) {
    node.props.ondestroy(node.element)
  }

  return node.element
}

var removeElement = function(parent, node) {
  var remove = function() {
    parent.removeChild(removeChildren(node))
  }
  var cb = node.props && node.props.onremove
  if (cb) {
    cb(node.element, remove)
  } else {
    remove()
  }
}

var getKey = function(node) {
  return isNull(node) ? null : node.key
}

var createKeyMap = function(children, start, end) {
  var out = {}
  var node
  var key
  for (; start <= end; start++) {
    node = children[start]
    key = node.key
    if (!isNull(key)) out[key] = node
  }
  return out
}

var patchElement = function(
  parent,
  element,
  lastNode,
  nextNode,
  lifecycle,
  isSvg
) {
  if (nextNode === lastNode) {
  } else if (
    !isNull(lastNode) &&
    lastNode.flags & IS_TEXT_NODE &&
    nextNode.flags & IS_TEXT_NODE
  ) {
    if (lastNode.name !== nextNode.name) {
      element.nodeValue = nextNode.name
    }
  } else if (isNull(lastNode) || lastNode.name !== nextNode.name) {
    var newElement = parent.insertBefore(
      createElement(nextNode, lifecycle, isSvg),
      element
    )

    if (!isNull(lastNode)) removeElement(parent, lastNode)

    element = newElement
  } else {
    updateElement(
      element,
      lastNode.props,
      nextNode.props,
      lifecycle,
      (isSvg = isSvg || nextNode.name === "svg"),
      lastNode.flags & IS_RECYCLED
    )

    var childNode

    var lastKey
    var lastCh = lastNode.children
    var lastChStart = 0
    var lastChEnd = lastCh.length - 1

    var nextKey
    var nextCh = nextNode.children
    var nextChStart = 0
    var nextChEnd = nextCh.length - 1

    while (nextChStart <= nextChEnd && lastChStart <= lastChEnd) {
      lastKey = getKey(lastCh[lastChStart])
      nextKey = getKey(nextCh[nextChStart])

      if (isNull(lastKey) || lastKey !== nextKey) break

      patchElement(
        element,
        lastCh[lastChStart].element,
        lastCh[lastChStart],
        nextCh[nextChStart],
        lifecycle,
        isSvg
      )

      lastChStart++
      nextChStart++
    }

    while (nextChStart <= nextChEnd && lastChStart <= lastChEnd) {
      lastKey = getKey(lastCh[lastChEnd])
      nextKey = getKey(nextCh[nextChEnd])

      if (isNull(lastKey) || lastKey !== nextKey) break

      patchElement(
        element,
        lastCh[lastChEnd].element,
        lastCh[lastChEnd],
        nextCh[nextChEnd],
        lifecycle,
        isSvg
      )

      lastChEnd--
      nextChEnd--
    }

    if (lastChStart > lastChEnd) {
      while (nextChStart <= nextChEnd) {
        element.insertBefore(
          createElement(nextCh[nextChStart++], lifecycle, isSvg),
          (childNode = lastCh[lastChStart]) && childNode.element
        )
      }
    } else if (nextChStart > nextChEnd) {
      while (lastChStart <= lastChEnd) {
        removeElement(element, lastCh[lastChStart++])
      }
    } else {
      var lastKeyed = createKeyMap(lastCh, lastChStart, lastChEnd)
      var nextKeyed = {}

      while (nextChStart <= nextChEnd) {
        lastKey = getKey((childNode = lastCh[lastChStart]))
        nextKey = getKey(nextCh[nextChStart])

        if (nextKeyed[lastKey]) {
          lastChStart++
          continue
        }

        if (!isNull(nextKey) && nextKey === getKey(lastCh[lastChStart + 1])) {
          if (isNull(lastKey)) {
            removeElement(element, childNode)
          }
          lastChStart++
          continue
        }

        if (isNull(nextKey) || lastNode.flags & IS_RECYCLED) {
          if (isNull(lastKey)) {
            patchElement(
              element,
              childNode && childNode.element,
              childNode,
              nextCh[nextChStart],
              lifecycle,
              isSvg
            )
            nextChStart++
          }
          lastChStart++
        } else {
          var foundNode = lastKeyed[nextKey]

          if (lastKey === nextKey) {
            patchElement(
              element,
              foundNode.element,
              foundNode,
              nextCh[nextChStart],
              lifecycle,
              isSvg
            )
            lastChStart++
          } else if (foundNode && foundNode.element) {
            patchElement(
              element,
              element.insertBefore(
                foundNode.element,
                childNode && childNode.element
              ),
              foundNode,
              nextCh[nextChStart],
              lifecycle,
              isSvg
            )
          } else {
            patchElement(
              element,
              childNode && childNode.element,
              null,
              nextCh[nextChStart],
              lifecycle,
              isSvg
            )
          }

          nextKeyed[nextKey] = nextCh[nextChStart]
          nextChStart++
        }
      }

      while (lastChStart <= lastChEnd) {
        if (isNull(getKey((childNode = lastCh[lastChStart++])))) {
          removeElement(element, childNode)
        }
      }

      for (var key in lastKeyed) {
        if (isNull(nextKeyed[key])) {
          removeElement(element, lastKeyed[key])
        }
      }
    }
  }

  return (nextNode.element = element)
}

var createVNode = function(name, props, children, element, key, flags) {
  return {
    name: name,
    props: props,
    children: children,
    element: element,
    key: key,
    flags: flags
  }
}

var createTextVNode = function(text, element) {
  return createVNode(
    text,
    EMPTY_OBJECT,
    EMPTY_ARRAY,
    element,
    null,
    IS_TEXT_NODE
  )
}

var recycleChild = function(element) {
  return element.nodeType === 3 // Node.TEXT_NODE
    ? createTextVNode(element.nodeValue, element)
    : recycleElement(element)
}

var recycleElement = function(element) {
  return createVNode(
    element.nodeName.toLowerCase(),
    EMPTY_OBJECT,
    map.call(element.childNodes, recycleChild),
    element,
    null,
    IS_RECYCLED
  )
}

export var recycle = function(container) {
  return recycleElement(container.children[0])
}

export var patch = function(lastNode, nextNode, container) {
  var lifecycle = []

  patchElement(container, container.children[0], lastNode, nextNode, lifecycle)

  while (lifecycle.length) lifecycle.pop()()

  return nextNode
}

export var h = function(name, props) {
  var node
  var rest = []
  var children = []
  var length = arguments.length

  while (length-- > 2) rest.push(arguments[length])

  if (!isNull((props = props || {}).children)) {
    rest.push(props.children)
    delete props.children
  }

  while (rest.length > 0) {
    if ((node = rest.pop()) && isArray(node)) {
      for (length = node.length; length--; ) {
        rest.push(node[length])
      }
    } else if (isNull(node) || node === true || node === false) {
    } else {
      children.push(typeof node === "object" ? node : createTextVNode(node))
    }
  }

  return typeof name === "function"
    ? name(props, (props.children = children))
    : createVNode(name, props, children, null, props.key, IS_VNODE)
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { Animated, Dimensions, ScrollView, View, ViewPropTypes } from 'react-native'

const styles = require('./styles')

import { bool, func, number, string } from 'prop-types'

const window = Dimensions.get('window')

const SCROLLVIEW_REF = 'ScrollView'

const pivotPoint = (a, b) => a - b

const renderEmpty = () => <View />

// Override `toJSON` of interpolated value because of
// an error when serializing style on view inside inspector.
// See: https://github.com/jaysoo/react-native-parallax-scroll-view/issues/23
const interpolate = (value, opts) => {
	const x = value.interpolate(opts)
	x.toJSON = () => x.__getValue()
	return x
}

// Properties accepted by `ParallaxScrollView`.
const IPropTypes = {
	backgroundColor: string,
	backgroundScrollSpeed: number,
	fadeOutForeground: bool,
	fadeOutBackground: bool,
	contentBackgroundColor: string,
	onChangeHeaderVisibility: func,
	parallaxHeaderHeight: number.isRequired,
	renderBackground: func,
	renderFixedHeader: func,
	renderForeground: func,
	renderScrollComponent: func,
	renderStickyHeader: func,
	stickyHeaderHeight: number,
	contentContainerStyle: ViewPropTypes.style,
	outputScaleValue: number
}

class ParallaxScrollView extends Component {
	constructor(props) {
		super(props)
		if (props.renderStickyHeader && !props.stickyHeaderHeight) {
			console.warn(
				'Property `stickyHeaderHeight` must be set if `renderStickyHeader` is used.'
			)
		}
		if (props.renderParallaxHeader !== renderEmpty && !props.renderForeground) {
			console.warn(
				'Property `renderParallaxHeader` is deprecated. Use `renderForeground` instead.'
			)
		}
		this.state = {
			scrollY: new Animated.Value(0),
			viewHeight: window.height,
			viewWidth: window.width
		}
		this.scrollY = new Animated.Value(0)
		this._footerComponent = { setNativeProps() {} } // Initial stub
		this._footerHeight = 0
	}

	animatedEvent = Animated.event(
		[{ nativeEvent: { contentOffset: { y: this.scrollY } } }],
		{ useNativeDriver: true }
	)

	render() {
		const {
			backgroundColor,
			backgroundScrollSpeed,
			children,
			contentBackgroundColor,
			fadeOutForeground,
			fadeOutBackground,
			parallaxHeaderHeight,
			renderBackground,
			renderFixedHeader,
			renderForeground,
			renderParallaxHeader,
			renderScrollComponent,
			renderStickyHeader,
			stickyHeaderHeight,
			style,
			contentContainerStyle,
			outputScaleValue,
			...scrollViewProps
		} = this.props

		const background = this._renderBackground({
			fadeOutBackground,
			backgroundScrollSpeed,
			backgroundColor,
			parallaxHeaderHeight,
			stickyHeaderHeight,
			renderBackground,
			outputScaleValue
		})
		const foreground = this._renderForeground({
			fadeOutForeground,
			parallaxHeaderHeight,
			stickyHeaderHeight,
			renderForeground: renderForeground || renderParallaxHeader
		})
		const bodyComponent = this._wrapChildren(children, {
			contentBackgroundColor,
			stickyHeaderHeight,
			contentContainerStyle
		})
		const footerSpacer = this._renderFooterSpacer({ contentBackgroundColor })
		const maybeStickyHeader = this._maybeRenderStickyHeader({
			parallaxHeaderHeight,
			stickyHeaderHeight,
			backgroundColor,
			renderFixedHeader,
			renderStickyHeader
		})
		const scrollElement = renderScrollComponent(scrollViewProps)
		return (
			<View
				style={[style, styles.container]}
				onLayout={e => this._maybeUpdateViewDimensions(e)}
			>
				{background}
				{React.cloneElement(
					scrollElement,
					{
						ref: SCROLLVIEW_REF,
						style: [styles.scrollView, scrollElement.props.style],
						scrollEventThrottle: 1,
						// Using Native Driver greatly optimizes performance
						onScroll: Animated.event(
							[{ nativeEvent: { contentOffset: { y: this.scrollY } } }],
							{ useNativeDriver: true, listener: this._onScroll.bind(this) }
						)
						// onScroll: this._onScroll.bind(this)
					},
					foreground,
					bodyComponent,
					footerSpacer
				)}
				{maybeStickyHeader}
			</View>
		)
	}

	/*
   * Expose `ScrollView` API so this component is composable with any component that expects a `ScrollView`.
   */
	getScrollResponder() {
		return this.refs[SCROLLVIEW_REF]._component.getScrollResponder()
	}
	getScrollableNode() {
		return this.getScrollResponder().getScrollableNode()
	}
	getInnerViewNode() {
		return this.getScrollResponder().getInnerViewNode()
	}
	scrollTo(...args) {
		this.getScrollResponder().scrollTo(...args)
	}
	setNativeProps(props) {
		this.refs[SCROLLVIEW_REF].setNativeProps(props)
	}

	/*
   * Private helpers
   */

	_onScroll(e) {
		const {
			parallaxHeaderHeight,
			stickyHeaderHeight,
			onChangeHeaderVisibility,
			onScroll: prevOnScroll = e => {}
		} = this.props
		this.props.scrollEvent && this.props.scrollEvent(e)
		const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight)

		// This optimization wont run, since we update the animation value directly in onScroll event
		// this._maybeUpdateScrollPosition(e)

		if (e.nativeEvent.contentOffset.y >= p) {
			onChangeHeaderVisibility(false)
		} else {
			onChangeHeaderVisibility(true)
		}

		prevOnScroll(e)
	}

	// This optimizes the state update of current scrollY since we don't need to
	// perform any updates when user has scrolled past the pivot point.
	_maybeUpdateScrollPosition(e) {
		const { parallaxHeaderHeight, stickyHeaderHeight } = this.props
		const { scrollY } = this
		const { nativeEvent: { contentOffset: { y: offsetY } } } = e
		const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight)
		if (offsetY <= p || scrollY._value <= p) {
			scrollY.setValue(offsetY)
		}
	}

	_maybeUpdateViewDimensions(e) {
		const { nativeEvent: { layout: { width, height } } } = e

		if (width !== this.state.viewWidth || height !== this.state.viewHeight) {
			this.setState({
				viewWidth: width,
				viewHeight: height
			})
		}
	}

	_renderBackground({
		fadeOutBackground,
		backgroundScrollSpeed,
		backgroundColor,
		parallaxHeaderHeight,
		stickyHeaderHeight,
		renderBackground,
		outputScaleValue
	}) {
		const { viewWidth, viewHeight } = this.state
		const { scrollY } = this
		const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight)
		return (
			<Animated.View
				style={[
					styles.backgroundImage,
					{
						backgroundColor: backgroundColor,
						height: parallaxHeaderHeight,
						width: viewWidth,
						opacity: fadeOutBackground
							? interpolate(scrollY, {
									inputRange: [0, p * (1 / 2), p * (3 / 4), p],
									outputRange: [1, 0.3, 0.1, 0],
									extrapolate: 'clamp'
								})
							: 1,
						transform: [
							{
								translateY: interpolate(scrollY, {
									inputRange: [0, p],
									outputRange: [0, -(p / backgroundScrollSpeed)],
									extrapolateRight: 'extend',
									extrapolateLeft: 'clamp'
								})
							},
							{
								scale: interpolate(scrollY, {
									inputRange: [-viewHeight, 0],
									outputRange: [outputScaleValue, 1],
									extrapolate: 'clamp'
								})
							}
						]
					}
				]}
			>
				<View>
					{renderBackground()}
				</View>
			</Animated.View>
		)
	}

	_renderForeground({
		fadeOutForeground,
		parallaxHeaderHeight,
		stickyHeaderHeight,
		renderForeground
	}) {
		const { scrollY } = this
		const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight)
		return (
			<View style={styles.parallaxHeaderContainer}>
				<Animated.View
					style={[
						styles.parallaxHeader,
						{
							height: parallaxHeaderHeight,
							opacity: fadeOutForeground
								? interpolate(scrollY, {
										inputRange: [0, p * (1 / 2), p * (3 / 4), p],
										outputRange: [1, 0.3, 0.1, 0],
										extrapolate: 'clamp'
									})
								: 1
						}
					]}
				>
					<View style={{ height: parallaxHeaderHeight }}>
						{renderForeground()}
					</View>
				</Animated.View>
			</View>
		)
	}

	_wrapChildren(
		children,
		{ contentBackgroundColor, stickyHeaderHeight, contentContainerStyle }
	) {
		const { viewHeight } = this.state
		const containerStyles = [{ backgroundColor: contentBackgroundColor }]

		if (contentContainerStyle) containerStyles.push(contentContainerStyle)

		return (
			<View
				style={containerStyles}
				onLayout={e => {
					// Adjust the bottom height so we can scroll the parallax header all the way up.
					const { nativeEvent: { layout: { height } } } = e
					const footerHeight = Math.max(
						0,
						viewHeight - height - stickyHeaderHeight
					)
					if (this._footerHeight !== footerHeight) {
						this._footerComponent.setNativeProps({
							style: { height: footerHeight }
						})
						this._footerHeight = footerHeight
					}
				}}
			>
				{children}
			</View>
		)
	}

	_renderFooterSpacer({ contentBackgroundColor }) {
		return (
			<View
				ref={ref => {
					if (ref) {
						this._footerComponent = ref;
					}
				}}
				style={{ backgroundColor: contentBackgroundColor }}
			/>
		)
	}

	_maybeRenderStickyHeader({
		parallaxHeaderHeight,
		stickyHeaderHeight,
		backgroundColor,
		renderFixedHeader,
		renderStickyHeader
	}) {
		const { viewWidth } = this.state
		const { scrollY } = this
		if (renderStickyHeader || renderFixedHeader) {
			const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight)
			return (
				<View
					style={[
						styles.stickyHeader,
						{
							width: viewWidth,
							...(stickyHeaderHeight ? { height: stickyHeaderHeight } : null)
						}
					]}
				>
					{renderStickyHeader
						? <Animated.View
								style={{
									backgroundColor: backgroundColor,
									height: stickyHeaderHeight,
									opacity: interpolate(scrollY, {
										inputRange: [0, p],
										outputRange: [0, 1],
										extrapolate: 'clamp'
									})
								}}
							>
								<Animated.View
									style={{
										transform: [
											{
												translateY: interpolate(scrollY, {
													inputRange: [0, p],
													outputRange: [stickyHeaderHeight, 0],
													extrapolate: 'clamp'
												})
											}
										]
									}}
								>
									{renderStickyHeader()}
								</Animated.View>
							</Animated.View>
						: null}
					{renderFixedHeader && renderFixedHeader()}
				</View>
			)
		} else {
			return null
		}
	}
}

ParallaxScrollView.propTypes = IPropTypes

ParallaxScrollView.defaultProps = {
	backgroundScrollSpeed: 5,
	backgroundColor: '#000',
	contentBackgroundColor: '#fff',
	fadeOutForeground: true,
	onChangeHeaderVisibility: () => {},
	renderScrollComponent: props => <Animated.ScrollView {...props} />,
	renderBackground: renderEmpty,
	renderParallaxHeader: renderEmpty, // Deprecated (will be removed in 0.18.0)
	renderForeground: null,
	stickyHeaderHeight: 0,
	contentContainerStyle: null,
	outputScaleValue: 5
}

module.exports = ParallaxScrollView
<commit_msg>renderContentBackground added<commit_after>import React, { Component } from 'react'
import { Animated, Dimensions, ScrollView, View, ViewPropTypes, Image } from 'react-native'

const styles = require('./styles')

import { bool, func, number, string } from 'prop-types'

const window = Dimensions.get('window')

const SCROLLVIEW_REF = 'ScrollView'

const pivotPoint = (a, b) => a - b

const renderEmpty = () => <View />

const noRender = () => <View style={{display: 'none'}} />

// Override `toJSON` of interpolated value because of
// an error when serializing style on view inside inspector.
// See: https://github.com/jaysoo/react-native-parallax-scroll-view/issues/23
const interpolate = (value, opts) => {
	const x = value.interpolate(opts)
	x.toJSON = () => x.__getValue()
	return x
}

// Properties accepted by `ParallaxScrollView`.
const IPropTypes = {
	backgroundColor: string,
	backgroundScrollSpeed: number,
	fadeOutForeground: bool,
	fadeOutBackground: bool,
	contentBackgroundColor: string,
	onChangeHeaderVisibility: func,
	parallaxHeaderHeight: number.isRequired,
	renderBackground: func,
	renderContentBackground: func,
	renderFixedHeader: func,
	renderForeground: func,
	renderScrollComponent: func,
	renderStickyHeader: func,
	stickyHeaderHeight: number,
	contentContainerStyle: ViewPropTypes.style,
	outputScaleValue: number
}

class ParallaxScrollView extends Component {
	constructor(props) {
		super(props)
		if (props.renderStickyHeader && !props.stickyHeaderHeight) {
			console.warn(
				'Property `stickyHeaderHeight` must be set if `renderStickyHeader` is used.'
			)
		}
		if (props.renderParallaxHeader !== renderEmpty && !props.renderForeground) {
			console.warn(
				'Property `renderParallaxHeader` is deprecated. Use `renderForeground` instead.'
			)
		}
		this.state = {
			scrollY: new Animated.Value(0),
			viewHeight: window.height,
			viewWidth: window.width
		}
		this.scrollY = new Animated.Value(0)
		this._footerComponent = { setNativeProps() {} } // Initial stub
		this._footerHeight = 0
	}

	animatedEvent = Animated.event(
		[{ nativeEvent: { contentOffset: { y: this.scrollY } } }],
		{ useNativeDriver: true }
	)

	render() {
		const {
			backgroundColor,
			backgroundScrollSpeed,
			children,
			contentBackgroundColor,
			fadeOutForeground,
			fadeOutBackground,
			parallaxHeaderHeight,
			renderBackground,
			renderContentBackground,
			renderFixedHeader,
			renderForeground,
			renderParallaxHeader,
			renderScrollComponent,
			renderStickyHeader,
			stickyHeaderHeight,
			style,
			contentContainerStyle,
			outputScaleValue,
			...scrollViewProps
		} = this.props

		const background = this._renderBackground({
			fadeOutBackground,
			backgroundScrollSpeed,
			backgroundColor,
			parallaxHeaderHeight,
			stickyHeaderHeight,
			renderBackground,
			outputScaleValue
		})
		const foreground = this._renderForeground({
			fadeOutForeground,
			parallaxHeaderHeight,
			stickyHeaderHeight,
			renderForeground: renderForeground || renderParallaxHeader
		})
		const bodyComponent = this._wrapChildren(children, {
			contentBackgroundColor,
			stickyHeaderHeight,
			renderContentBackground,
			contentContainerStyle
		})
		const footerSpacer = this._renderFooterSpacer({ contentBackgroundColor })
		const maybeStickyHeader = this._maybeRenderStickyHeader({
			parallaxHeaderHeight,
			stickyHeaderHeight,
			backgroundColor,
			renderFixedHeader,
			renderStickyHeader
		})
		const scrollElement = renderScrollComponent(scrollViewProps)
		return (
			<View
				style={[style, styles.container]}
				onLayout={e => this._maybeUpdateViewDimensions(e)}
			>
				{background}
				{React.cloneElement(
					scrollElement,
					{
						ref: SCROLLVIEW_REF,
						style: [styles.scrollView, scrollElement.props.style],
						scrollEventThrottle: 1,
						// Using Native Driver greatly optimizes performance
						onScroll: Animated.event(
							[{ nativeEvent: { contentOffset: { y: this.scrollY } } }],
							{ useNativeDriver: true, listener: this._onScroll.bind(this) }
						)
						// onScroll: this._onScroll.bind(this)
					},
					foreground,
					bodyComponent,
					footerSpacer
				)}
				{maybeStickyHeader}
			</View>
		)
	}

	/*
   * Expose `ScrollView` API so this component is composable with any component that expects a `ScrollView`.
   */
	getScrollResponder() {
		return this.refs[SCROLLVIEW_REF]._component.getScrollResponder()
	}
	getScrollableNode() {
		return this.getScrollResponder().getScrollableNode()
	}
	getInnerViewNode() {
		return this.getScrollResponder().getInnerViewNode()
	}
	scrollTo(...args) {
		this.getScrollResponder().scrollTo(...args)
	}
	setNativeProps(props) {
		this.refs[SCROLLVIEW_REF].setNativeProps(props)
	}

	/*
   * Private helpers
   */

	_onScroll(e) {
		const {
			parallaxHeaderHeight,
			stickyHeaderHeight,
			onChangeHeaderVisibility,
			onScroll: prevOnScroll = e => {}
		} = this.props
		this.props.scrollEvent && this.props.scrollEvent(e)
		const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight)

		// This optimization wont run, since we update the animation value directly in onScroll event
		// this._maybeUpdateScrollPosition(e)

		if (e.nativeEvent.contentOffset.y >= p) {
			onChangeHeaderVisibility(false)
		} else {
			onChangeHeaderVisibility(true)
		}

		prevOnScroll(e)
	}

	// This optimizes the state update of current scrollY since we don't need to
	// perform any updates when user has scrolled past the pivot point.
	_maybeUpdateScrollPosition(e) {
		const { parallaxHeaderHeight, stickyHeaderHeight } = this.props
		const { scrollY } = this
		const { nativeEvent: { contentOffset: { y: offsetY } } } = e
		const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight)
		if (offsetY <= p || scrollY._value <= p) {
			scrollY.setValue(offsetY)
		}
	}

	_maybeUpdateViewDimensions(e) {
		const { nativeEvent: { layout: { width, height } } } = e

		if (width !== this.state.viewWidth || height !== this.state.viewHeight) {
			this.setState({
				viewWidth: width,
				viewHeight: height
			})
		}
	}

	_renderBackground({
		fadeOutBackground,
		backgroundScrollSpeed,
		backgroundColor,
		parallaxHeaderHeight,
		stickyHeaderHeight,
		renderBackground,
		outputScaleValue
	}) {
		const { viewWidth, viewHeight } = this.state
		const { scrollY } = this
		const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight)
		return (
			<Animated.View
				style={[
					styles.backgroundImage,
					{
						backgroundColor: backgroundColor,
						height: parallaxHeaderHeight,
						width: viewWidth,
						opacity: fadeOutBackground
							? interpolate(scrollY, {
									inputRange: [0, p * (1 / 2), p * (3 / 4), p],
									outputRange: [1, 0.3, 0.1, 0],
									extrapolate: 'clamp'
								})
							: 1,
						transform: [
							{
								translateY: interpolate(scrollY, {
									inputRange: [0, p],
									outputRange: [0, -(p / backgroundScrollSpeed)],
									extrapolateRight: 'extend',
									extrapolateLeft: 'clamp'
								})
							},
							{
								scale: interpolate(scrollY, {
									inputRange: [-viewHeight, 0],
									outputRange: [outputScaleValue, 1],
									extrapolate: 'clamp'
								})
							}
						]
					}
				]}
			>
				<View>
					{renderBackground()}
				</View>
			</Animated.View>
		)
	}

	_renderForeground({
		fadeOutForeground,
		parallaxHeaderHeight,
		stickyHeaderHeight,
		renderForeground
	}) {
		const { scrollY } = this
		const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight)
		return (
			<View style={styles.parallaxHeaderContainer}>
				<Animated.View
					style={[
						styles.parallaxHeader,
						{
							height: parallaxHeaderHeight,
							opacity: fadeOutForeground
								? interpolate(scrollY, {
										inputRange: [0, p * (1 / 2), p * (3 / 4), p],
										outputRange: [1, 0.3, 0.1, 0],
										extrapolate: 'clamp'
									})
								: 1
						}
					]}
				>
					<View style={{ height: parallaxHeaderHeight }}>
						{renderForeground()}
					</View>
				</Animated.View>
			</View>
		)
	}

	_wrapChildren(
		children,
		{ contentBackgroundColor, stickyHeaderHeight, contentContainerStyle, renderContentBackground }
	) {
		const { viewHeight } = this.state
		const containerStyles = [{ backgroundColor: contentBackgroundColor }]

		if (contentContainerStyle) containerStyles.push(contentContainerStyle)

		this.containerHeight = this.state.viewHeight;

		children.forEach((item) => {
			console.log(item);
			if (item && Object.keys(item).length != 0) {
				this.containerHeight = 0;
			}
		});

		return (
			<View
				style={[containerStyles, { minHeight: this.containerHeight }]}
				onLayout={e => {
					// Adjust the bottom height so we can scroll the parallax header all the way up.
					const { nativeEvent: { layout: { height } } } = e
					const footerHeight = Math.max(
						0,
						viewHeight - height - stickyHeaderHeight
					)
					if (this._footerHeight !== footerHeight) {
						this._footerComponent.setNativeProps({
							style: { height: footerHeight }
						})
						this._footerHeight = footerHeight
					}
				}}
			>
				{renderContentBackground()}
				{children}
			</View>
		)
	}

	_renderFooterSpacer({ contentBackgroundColor }) {
		return (
			<View
				ref={ref => {
					if (ref) {
						this._footerComponent = ref;
					}
				}}
				style={{ backgroundColor: contentBackgroundColor }}
			/>
		)
	}

	_maybeRenderStickyHeader({
		parallaxHeaderHeight,
		stickyHeaderHeight,
		backgroundColor,
		renderFixedHeader,
		renderStickyHeader
	}) {
		const { viewWidth } = this.state
		const { scrollY } = this
		if (renderStickyHeader || renderFixedHeader) {
			const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight)
			return (
				<View
					style={[
						styles.stickyHeader,
						{
							width: viewWidth,
							...(stickyHeaderHeight ? { height: stickyHeaderHeight } : null)
						}
					]}
				>
					{renderStickyHeader
						? <Animated.View
								style={{
									backgroundColor: backgroundColor,
									height: stickyHeaderHeight,
									opacity: interpolate(scrollY, {
										inputRange: [0, p],
										outputRange: [0, 1],
										extrapolate: 'clamp'
									})
								}}
							>
								<Animated.View
									style={{
										transform: [
											{
												translateY: interpolate(scrollY, {
													inputRange: [0, p],
													outputRange: [stickyHeaderHeight, 0],
													extrapolate: 'clamp'
												})
											}
										]
									}}
								>
									{renderStickyHeader()}
								</Animated.View>
							</Animated.View>
						: null}
					{renderFixedHeader && renderFixedHeader()}
				</View>
			)
		} else {
			return null
		}
	}
}

ParallaxScrollView.propTypes = IPropTypes

ParallaxScrollView.defaultProps = {
	backgroundScrollSpeed: 5,
	backgroundColor: '#000',
	contentBackgroundColor: '#fff',
	fadeOutForeground: true,
	onChangeHeaderVisibility: () => {},
	renderScrollComponent: props => <Animated.ScrollView {...props} />,
	renderBackground: renderEmpty,
	renderContentBackground: noRender,
	renderParallaxHeader: renderEmpty, // Deprecated (will be removed in 0.18.0)
	renderForeground: null,
	stickyHeaderHeight: 0,
	contentContainerStyle: null,
	outputScaleValue: 5
}

module.exports = ParallaxScrollView
<|endoftext|>


<commit_before>recl = React.createClass
div = React.DOM.div
a = React.DOM.a
b = React.DOM.button
hr = React.DOM.hr
table = React.DOM.table
th = React.DOM.th
tr = React.DOM.tr
td = React.DOM.td
input = React.DOM.input

function HashToJSON() {
    var pairs = window.location.hash.slice(1).split('&');
    var result = {};
    pairs.forEach(function(pair) {
        pair = pair.split('=');
        result[pair[0]] = decodeURIComponent(pair[1] || '');
    });

    return JSON.parse(JSON.stringify(result));
}

DOControls = React.createClass({
  createDroplet: function(){
    urb.send({appl: "cloud",
              data: {
                    action:'create-do',
                    name:$('#name').val(),
                    region:$('#region').val(),
                    size:$('#size').val(),
                    image:$('#image').val(),
                    ssh:[], // $('#ssh').val()]
                    backups:null,//$('#backups').val(),
                    ipv6:null,//$('#ipv6').val(),
                    priv_networking:null,//$('#priv-networking').val(),
                    user_data:null//$('#user-data').val()
                    },
              mark: "json"})
  },

  render: function(){
      href = "https://cloud.digitalocean.com/v1/oauth/authorize?client_id=d8f46b95af38c1ab3d78ad34c2157a6959c23eb0eb5d8e393f650f08e6a75c6f&redirect_uri=http%3A%2F%2Flocalhost%3A8443%2Fhome%2Fpub%2Fcloud%2Ffab&response_type=code&scope=read+write"
    return (
      div({}, [
        div({},
          a({href:href},"get authcode"),
          b({onClick:this.props.handleClick('do')}, "Send Authcode")
        ),
        div({}, [
          input({id:"appsecret"},
          b({onClick:this.props.sendSecret('do','#appsecret')}, "Send Secret"))
        ]),

        div({}, [
          b({onClick:this.createDroplet}, "Create Droplet"),
          input({id:"name",placeholder:"Name of droplet"}),
          input({id:"region",placeholder:"Region"}),
          input({id:"size",placeholder:"Size (str ending in mb"}),
          input({id:"image",placeholder:"Image"}),
          input({id:"ssh",placeholder:"ssh keys (optional)"}),
          input({id:"backups",placeholder:"backups (optional)"}),
          input({id:"ipv6",placeholder:"ipv6 (boolean, optional)"}),
          input({id:"user-data",placeholder:" user-data string (optional)"}),
          input({id:"priv-networking",placeholder:"Private Networking (boolean, optional)"})
        ])
      ])
    )
  }
})

GCEControls = React.createClass({
  createDroplet: function(){
  urb.send({
    appl: 'cloud',
    data: {action:'create-gce',
          project:$('#project').val(),
          zone:$('#zone').val(),
          name:$('#gname').val(),
          machine_type:$('#machine_type').val()
          },
    mark: 'json'})
  },

  createDisk: function(){
      urb.send({
        appl: 'cloud',
        data: {action:'create-gce-disk',
               snap:$('#gsnap').val(),
               number:$('#number').val(),
               name:$('#gcpName').val()},
        mark: 'json'})
  },

  render: function(){
    ghref = "https://accounts.google.com/o/oauth2/auth?response_type=token&scope=https://www.googleapis.com/auth/compute&redirect_uri=http://localhost:8443/home/pub/cloud/fab&client_id=719712694742-6htfj2t9s1j2jid92rc4dfq9psrr9qpo.apps.googleusercontent.com"
    return(
      div({}, [
        div({}, [
          b({onClick:this.createDisk}, 'Create Disk From Image'),
          input({id:'gcpName',placeholder:'Name for GCE Disk and Instance'}),
          input({id:'number',placeholder:'Number of instances'}),
          input({id:'gsnap',placeholder:'Snapshot'})
        ]),
        div({}, [
          a({href:ghref},"Get Google Authcode"),
          b({onClick:this.props.handleClick('gce')}, "Send Google Authcode")
        ]),
        div({}, [
          input({id:"gappsecret"},
          b({onClick:this.props.sendSecret('gce','#gappsecret')}, "Send Google Secret"))
        ]),
        div({}, [
          b({onClick:this.createDroplet}, "Create Droplet"),
          input({id:"project",placeholder:"project"}),
          input({id:"zone",placeholder:"zone"}),
          input({id:"gname",placeholder:"Name of droplet"}),
          input({id:"machine_type",placeholder:"Machine Type"}),
          //input({id:"image",placeholder:"Image"}),
      ])
    ]))
  }
})

Droplet = React.createClass({
  dropletAction:function(id, action){
    urb.send({
      appl:"cloud",
      data: {action:action,
            id:id}})
  },

  render: function() {
    var $this = this    //local var, else it always points at second
    var acts = ["start","stop","reboot","delete"]
    var buttons = [];
    var buttons = acts.map(function(act){
      console.log($this.props.id)
      return b({onClick:function(){
        $this.dropletAction($this.props.id, act)
      }}, act)
    })
    kay = Object.keys(this.props)
    kay = kay.filter(function(b){return b!="children"}) //  XX individually adress props
  return div({},
    buttons,
    table({},
      tr({},kay.map(function(k){return th({},k)})),
      tr({},kay.map(function(k){return td({},JSON.stringify($this.props[k]))}))),
    hr())
  }
})

Page = recl({
  handleClick: function(platform){
  return  function(){
      console.log(platform);
      console.log(window.authcode.platform)
      if(window.authcode.length !== ''){
        urb.send({
          appl: "cloud",
          data: {authcode:authcode[platform],
                platform:platform},
          mark: "cloud-auth"})
      } else { console.log("nocode") }
    }
  },

  sendSecret: function(platform,codeid){
    return function(){
    console.log(platform,codeid)
        secret= $(codeid).val()
        if(secret !== '') {
          urb.send({appl: "cloud",
                    data: {secret:secret,
                          platform:platform},
                    mark: "cloud-secret"})
        }
    }
  },

  getList: function(){
    urb.send({appl: "cloud",
              data: {action:"list"},
              mark: "json"})
  },

  render: function(){
      return (div({},
        DOControls({handleClick:this.handleClick,sendSecret:this.sendSecret}),
        GCEControls({handleClick:this.handleClick,sendSecret:this.sendSecret}),
        this.props.droplets.map(Droplet)
      ))
  }
})

var hash = HashToJSON()     //pull out hash of query string for gce authcode
authcode.gce = hash.access_token

mounted = React.render(Page({droplets:[]}), $("#container")[0])
urb.bind("/", function(err,d) {

  mounted.setProps({droplets:d.data})
return})
<commit_msg>Delete main.js<commit_after><|endoftext|>


<commit_before>import Column from './components/Column';
import Row from './components/Row';
import { divvy, media } from './utils';

const utils = {
  [divvy]: divvy,
  [media]: media
};

export { Column, Row, utils };

<commit_msg>Fixed object-shorthand syntax for utils export<commit_after>import Column from './components/Column';
import Row from './components/Row';
import { divvy, media } from './utils';

const utils = {
  divvy,
  media
};

export { Column, Row, utils };

<|endoftext|>


<commit_before>import React, {Component} from 'react';
import {graphql} from 'react-apollo';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {Container, Header, Item, Button} from 'semantic-ui-react';
import Loader from '../components/Loader';
import ModelHeader from '../components/ModelHeader';
import Markdown from '../components/Markdown';
import ErrorPage from '../components/ErrorPage';
import {MODELS_QUERY} from '../graphql/models';
import {updateLocationParams} from '../actions/location';

class Models extends Component {
  componentWillMount() {
    this.props.updateLocationParams({
      entity: this.props.match.params.entity,
      model: null,
    });
  }

  componentDidUpdate() {
    window.Prism.highlightAll();
  }

  models() {
    return (this.props.models && this.props.models.edges) || [];
  }

  render() {
    return this.props.error ? (
      <ErrorPage error={this.props.error} history={this.props.history} />
    ) : (
      <Container>
        <Loader />
        {this.props.user && (
          <Button
            as="a"
            href={`/${this.props.entity}/new`}
            style={{zIndex: 5}}
            floated="right">
            Create Project
          </Button>
        )}
        Projects
        <Item.Group divided relaxed>
          {this.models().map(edge => (
            <Item style={{display: 'block'}} key={edge.node.id}>
              <ModelHeader condensed={true} project={edge.node} />

              <Markdown content={edge.node.description} />
            </Item>
          ))}
          {!this.props.loading &&
            this.models().length === 0 && (

No runs for this project yet.

New to wandb?

                    Visit the getting started{' '}

                      documentation.

                    Take a look at our{' '}

                      example projects.

            )}
        </Item.Group>
      </Container>
    );
  }
}

Models.defaultProps = {
  models: {edges: []},
};

const withData = graphql(MODELS_QUERY, {
  options: ({match: {params}}) => ({
    variables: {entityName: params.entity || 'models'},
  }),
  props: ({
    data: {loading, models, fetchMore, error, variables: {entityName}},
  }) => ({
    loading,
    models,
    error,
    entity: entityName,
    loadMoreEntries: () => {
      return fetchMore({
        query: MODELS_QUERY,
        variables: {
          cursor: models.pageInfo.endCursor,
        },
        updateQuery: (previousResult, {fetchMoreResult}) => {
          const newEdges = fetchMoreResult.data.models.edges;
          const pageInfo = fetchMoreResult.data.models.pageInfo;
          return {
            comments: {
              edges: [...previousResult.models.edges, ...newEdges],
              pageInfo,
            },
          };
        },
      });
    },
  }),
});

const modelsMapDispatchToProps = (dispatch, ownProps) => {
  return bindActionCreators({updateLocationParams}, dispatch);
};

// export dumb component for testing purposes
export {Models};

export default withData(connect(null, modelsMapDispatchToProps)(Models));
<commit_msg>Fix always showing loading indicator on projects page.<commit_after>import React, {Component} from 'react';
import {graphql} from 'react-apollo';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {Container, Header, Item, Button} from 'semantic-ui-react';
import Loader from '../components/Loader';
import ModelHeader from '../components/ModelHeader';
import Markdown from '../components/Markdown';
import ErrorPage from '../components/ErrorPage';
import {MODELS_QUERY} from '../graphql/models';
import {updateLocationParams} from '../actions/location';

class Models extends Component {
  componentWillMount() {
    this.props.updateLocationParams({
      entity: this.props.match.params.entity,
      model: null,
    });
  }

  componentDidUpdate() {
    window.Prism.highlightAll();
  }

  models() {
    return (this.props.models && this.props.models.edges) || [];
  }

  render() {
    return this.props.error ? (
      <ErrorPage error={this.props.error} history={this.props.history} />
    ) : (
      <Container>
        {this.props.loading && <Loader />}
        {this.props.user && (
          <Button
            as="a"
            href={`/${this.props.entity}/new`}
            style={{zIndex: 5}}
            floated="right">
            Create Project
          </Button>
        )}
        Projects
        <Item.Group divided relaxed>
          {this.models().map(edge => (
            <Item style={{display: 'block'}} key={edge.node.id}>
              <ModelHeader condensed={true} project={edge.node} />

              <Markdown content={edge.node.description} />
            </Item>
          ))}
          {!this.props.loading &&
            this.models().length === 0 && (

No runs for this project yet.

New to wandb?

                    Visit the getting started{' '}

                      documentation.

                    Take a look at our{' '}

                      example projects.

            )}
        </Item.Group>
      </Container>
    );
  }
}

Models.defaultProps = {
  models: {edges: []},
};

const withData = graphql(MODELS_QUERY, {
  options: ({match: {params}}) => ({
    variables: {entityName: params.entity || 'models'},
  }),
  props: ({
    data: {loading, models, fetchMore, error, variables: {entityName}},
  }) => ({
    loading,
    models,
    error,
    entity: entityName,
    loadMoreEntries: () => {
      return fetchMore({
        query: MODELS_QUERY,
        variables: {
          cursor: models.pageInfo.endCursor,
        },
        updateQuery: (previousResult, {fetchMoreResult}) => {
          const newEdges = fetchMoreResult.data.models.edges;
          const pageInfo = fetchMoreResult.data.models.pageInfo;
          return {
            comments: {
              edges: [...previousResult.models.edges, ...newEdges],
              pageInfo,
            },
          };
        },
      });
    },
  }),
});

const modelsMapDispatchToProps = (dispatch, ownProps) => {
  return bindActionCreators({updateLocationParams}, dispatch);
};

// export dumb component for testing purposes
export {Models};

export default withData(connect(null, modelsMapDispatchToProps)(Models));
<|endoftext|>


<commit_before>//
// Select all links with the 'rel' attribute set to "less"
//
var sheets = document.querySelectorAll("link[rel=less]");

less.env = location.hostname == '127.0.0.1' ||
           location.hostname == '0.0.0.0'   ||
           location.hostname == 'localhost' ||
           location.protocol == 'file:'     ? 'development'
                                            : 'production';

for (var i = 0; i < sheets.length; i++) {
    (function (sheet) { // Because the functions here are async, we need to create a closure
        var css = localStorage.getItem(sheet.href);
        var styles = css && JSON.parse(css);

        xhr(sheet.href, function (data, lastModified) {
            if (styles && (new(Date)(lastModified).value ===
                           new(Date)(styles.timestamp).value)) {
                // Use local copy
                createCSS(styles.css, sheet);
                log("less: loading " + sheet.href + " from local storage.");
            } else {
                // Use remote copy (re-parse)
                new(less.Parser)({ optimization: 3 }).parse(data, function (e, root) {
                    if (e) { return error(e, sheet.href) }
                    createCSS(root.toCSS(), sheet, lastModified);
                    log("less: parsed " + sheet.href + " successfully.");
                });
            }
        });
    })(sheets[i]);
}

function createCSS(styles, sheet, lastModified) {
    var css = document.createElement('style');
    css.type = 'text/css';
    css.media = 'screen';
    css.title = 'lessheet';

    if (sheet) {
        css.title = sheet.title || sheet.href.match(/\/([-\w]+)\.[a-z]+$/i)[1];

        // Don't update the local store if the file wasn't modified
        if (lastModified) {
            localStorage.setItem(sheet.href, JSON.stringify({ timestamp: lastModified, css: styles }));
        }
    }

    if (css.styleSheet) {
        css.styleSheet.cssText = styles;
    } else {
        css.appendChild(document.createTextNode(styles));
    }
    document.getElementsByTagName('head')[0].appendChild(css);
}

function xhr(url, callback, errback) {
    var xhr = new(XMLHttpRequest);

    if (window.location.protocol === "file:") {
        xhr.open('GET', url, false);
        xhr.send(null);
        if (xhr.status === 0) {
            callback(xhr.responseText);
        } else {
            errback(xhr.responseText);
        }
    } else {
        xhr.open('GET', url, true);
        xhr.onreadystatechange = function () {
            if (this.readyState == 4) {
                if (this.status >= 200 && this.status < 300) {
                    callback(this.responseText,
                             this.getResponseHeader("Last-Modified"));
                } else if (typeof(errback) === 'function') {
                    errback(this.responseText);
                }
            }
        };
        xhr.send(null);
    }
}

function log(str) {
    if (less.env == 'development') { console.log(str) }
}

function error(e, href) {
    var template = ['
',
                        '
[-1]{0}
',
                        '
[0]{current}
',
                        '
[1]{2}
',
                    '
'].join('\n');

    var elem = document.createElement('div'), timer;
    elem.id = "less-error-message";
    elem.innerHTML = '
There is an error in your .less file
 '           +
                     '
' + href + " "            +
                     'on line '     + e.line + ', column ' + e.column + ':
' +
                     template.replace(/\[(-?\d)\]/g, function (_, i) {
                         console.log(i)
                         return e.line + parseInt(i);
                     }).replace(/\{(\d)\}/g, function (_, i) {
                         return e.extract[parseInt(i)];
                     }).replace(/\{current\}/, e.extract[1].slice(0, e.column)  +
                                               ''           +
                                               e.extract[1].slice(e.column) +
                                               '');

    createCSS([
        '#less-error-message span {',
            'margin-right: 15px;',
        '}',
        '#less-error-message pre {',
            'color: #ee4444;',
            'padding: 4px 0;',
            'margin: 0;',
        '}',
        '#less-error-message pre.ctx {',
            'color: #ee7777;',
        '}',
        '#less-error-message h3 {',
            'padding: 15px 0 5px 0;',
            'margin: 0;',
        '}',
        '#less-error-message a {',
            'color: #10a',
        '}',
        '#less-error-message .error {',
            'color: red;',
            'font-weight: bold;',
            'padding-bottom: 2px;',
            'border-bottom: 1px dashed red;',
        '}'
    ].join(''));

    elem.style.cssText = [
        "font-family: Arial, sans-serif",
        "border: 1px solid #e00",
        "background-color: #eee",
        "border-radius: 5px",
        "color: #e00",
        "padding: 15px",
        "margin-bottom: 15px"
    ].join(';');

    if (less.env == 'development') {
        timer = setInterval(function () {
            if (document.body) {
                document.body.insertBefore(elem, document.body.childNodes[0]);
                clearInterval(timer);
            }
        }, 10);
    }
}
<commit_msg>fix timestamps not being compared properly, when loading a .less<commit_after>//
// Select all links with the 'rel' attribute set to "less"
//
var sheets = document.querySelectorAll("link[rel=less]");

less.env = location.hostname == '127.0.0.1' ||
           location.hostname == '0.0.0.0'   ||
           location.hostname == 'localhost' ||
           location.protocol == 'file:'     ? 'development'
                                            : 'production';

for (var i = 0; i < sheets.length; i++) {
    (function (sheet) { // Because the functions here are async, we need to create a closure
        var css = localStorage.getItem(sheet.href);
        var styles = css && JSON.parse(css);

        xhr(sheet.href, function (data, lastModified) {
            if (styles && (new(Date)(lastModified).valueOf() ===
                           new(Date)(styles.timestamp).valueOf())) {
                // Use local copy
                createCSS(styles.css, sheet);
                log("less: loading " + sheet.href + " from local storage.");
            } else {
                // Use remote copy (re-parse)
                new(less.Parser)({ optimization: 3 }).parse(data, function (e, root) {
                    if (e) { return error(e, sheet.href) }
                    createCSS(root.toCSS(), sheet, lastModified);
                    log("less: parsed " + sheet.href + " successfully.");
                });
            }
        });
    })(sheets[i]);
}

function createCSS(styles, sheet, lastModified) {
    var css = document.createElement('style');
    css.type = 'text/css';
    css.media = 'screen';
    css.title = 'lessheet';

    if (sheet) {
        css.title = sheet.title || sheet.href.match(/\/([-\w]+)\.[a-z]+$/i)[1];

        // Don't update the local store if the file wasn't modified
        if (lastModified) {
            localStorage.setItem(sheet.href, JSON.stringify({ timestamp: lastModified, css: styles }));
        }
    }

    if (css.styleSheet) {
        css.styleSheet.cssText = styles;
    } else {
        css.appendChild(document.createTextNode(styles));
    }
    document.getElementsByTagName('head')[0].appendChild(css);
}

function xhr(url, callback, errback) {
    var xhr = new(XMLHttpRequest);

    if (window.location.protocol === "file:") {
        xhr.open('GET', url, false);
        xhr.send(null);
        if (xhr.status === 0) {
            callback(xhr.responseText);
        } else {
            errback(xhr.responseText);
        }
    } else {
        xhr.open('GET', url, true);
        xhr.onreadystatechange = function () {
            if (this.readyState == 4) {
                if (this.status >= 200 && this.status < 300) {
                    callback(this.responseText,
                             this.getResponseHeader("Last-Modified"));
                } else if (typeof(errback) === 'function') {
                    errback(this.responseText);
                }
            }
        };
        xhr.send(null);
    }
}

function log(str) {
    if (less.env == 'development') { console.log(str) }
}

function error(e, href) {
    var template = ['
',
                        '
[-1]{0}
',
                        '
[0]{current}
',
                        '
[1]{2}
',
                    '
'].join('\n');

    var elem = document.createElement('div'), timer;
    elem.id = "less-error-message";
    elem.innerHTML = '
There is an error in your .less file
 '           +
                     '
' + href + " "            +
                     'on line '     + e.line + ', column ' + e.column + ':
' +
                     template.replace(/\[(-?\d)\]/g, function (_, i) {
                         console.log(i)
                         return e.line + parseInt(i);
                     }).replace(/\{(\d)\}/g, function (_, i) {
                         return e.extract[parseInt(i)];
                     }).replace(/\{current\}/, e.extract[1].slice(0, e.column)  +
                                               ''           +
                                               e.extract[1].slice(e.column) +
                                               '');

    createCSS([
        '#less-error-message span {',
            'margin-right: 15px;',
        '}',
        '#less-error-message pre {',
            'color: #ee4444;',
            'padding: 4px 0;',
            'margin: 0;',
        '}',
        '#less-error-message pre.ctx {',
            'color: #ee7777;',
        '}',
        '#less-error-message h3 {',
            'padding: 15px 0 5px 0;',
            'margin: 0;',
        '}',
        '#less-error-message a {',
            'color: #10a',
        '}',
        '#less-error-message .error {',
            'color: red;',
            'font-weight: bold;',
            'padding-bottom: 2px;',
            'border-bottom: 1px dashed red;',
        '}'
    ].join(''));

    elem.style.cssText = [
        "font-family: Arial, sans-serif",
        "border: 1px solid #e00",
        "background-color: #eee",
        "border-radius: 5px",
        "color: #e00",
        "padding: 15px",
        "margin-bottom: 15px"
    ].join(';');

    if (less.env == 'development') {
        timer = setInterval(function () {
            if (document.body) {
                document.body.insertBefore(elem, document.body.childNodes[0]);
                clearInterval(timer);
            }
        }, 10);
    }
}
<|endoftext|>


<commit_before>(function (exports) {

  'use strict';

  var transformProp;
  var loaded;

  (function () {
    var style = document.createElement('a').style;
    var prop;
    if (style[prop = 'webkitTransform'] !== undefined) {
      transformProp = prop;
    }
    if (style[prop = 'msTransform'] !== undefined) {
      transformProp = prop;
    }
    if (style[prop = 'transform'] !== undefined) {
      transformProp = prop;
    }
  }());

  function forEach(arr, cb) {
    if (arr) {
      for (var i = 0, len = arr.length; i < len; i++) {
        if (arr[i]) {
          cb(arr[i], i, arr);
        }
      }
    }
  }

  function minigrid(props) {
    var containerEle = props.container instanceof Node ?
      props.container : document.querySelector(props.container);

    if (!containerEle) {
      return false;
    }

    var itemsNodeList = props.item instanceof NodeList ?
      props.item : containerEle.querySelectorAll(props.item);
    if (!itemsNodeList || itemsNodeList.length === 0) {
      return false;
    }

    if (loaded || props.skipWindowOnLoad) {
      init(containerEle, itemsNodeList, props);
      return;
    }

    if (/webkit/.test(navigator.userAgent.toLowerCase())) {
      setTimeout(function() {
        webkitWaitForReadyState({
          container: containerEle,
          item: itemsNodeList,
          props: props
        });
      }, 10);
    } else {
      window.onload = function() {
        init(containerEle, itemsNodeList, props);
      };
    }

  }

  function webkitWaitForReadyState(minigrid) {
    if (document.readyState === 'loaded' || document.readyState === 'complete') {
      init(minigrid.container, minigrid.item, minigrid.props);
    } else {
      setTimeout(function() {
        webkitWaitForReadyState(minigrid);
      }, 10);
    }
  }

  function init(containerEle, itemsNodeList, props) {

    if (!/loaded/.test(containerEle.className)) {
      containerEle.classList.add(containerEle.className.split(' ')[0] + '--loaded');
    }
    loaded = true;

    var gutter = (
      typeof props.gutter === 'number' &&
      isFinite(props.gutter) &&
      Math.floor(props.gutter) === props.gutter
    ) ? props.gutter : 0;
    var done = props.done;

    containerEle.style.width = '';

    var containerWidth = containerEle.getBoundingClientRect().width;
    var firstChildWidth = itemsNodeList[0].getBoundingClientRect().width + gutter;
    var cols = Math.max(Math.floor((containerWidth - gutter) / firstChildWidth), 1);
    var count = 0;

    containerWidth = (firstChildWidth * cols + gutter) + 'px';
    containerEle.style.width = containerWidth;
    containerEle.style.position = 'relative';

    var itemsGutter = [];
    var itemsPosX = [];

    for ( var g = 0 ; g < cols ; ++g ) {
      itemsPosX.push(g * firstChildWidth + gutter);
      itemsGutter.push(gutter);
    }

    forEach(itemsNodeList, function (item) {
      var itemIndex = itemsGutter
        .slice(0)
        .sort(function (a, b) {
          return a - b;
        })
        .shift();
      itemIndex = itemsGutter.indexOf(itemIndex);

      var posX = itemsPosX[itemIndex];
      var posY = itemsGutter[itemIndex];

      item.style.position = 'absolute';
      if (!/loaded/.test(item.className)) {
        item.classList.add(item.className.split(' ')[0] + '--loaded');
      }

      if (!props.animate && transformProp) {
        item.style[transformProp] = 'translate3D(' + posX + 'px,' + posY + 'px, 0)';
      }

      itemsGutter[itemIndex] += item.getBoundingClientRect().height + gutter;
      count = count + 1;

      if (props.animate) {
        return props.animate(item, posX, posY, count);
      }

    });

    var containerHeight = itemsGutter
      .slice(0)
      .sort(function (a, b) {
        return a - b;
      })
      .pop();

    containerEle.style.height = containerHeight + 'px';
    //containerEle.style.minHeight = containerHeight + 'px';

    if (typeof done === 'function') {
      done(itemsNodeList);
    }
  }

  if (typeof define === 'function' && define.amd) {
    define(function() { return minigrid; });
  } else if (typeof module !== 'undefined' && module.exports) {
    module.exports = minigrid;
  } else {
    exports.minigrid = minigrid;
  }

})(this);
<commit_msg>Added containerLoaded and itemLoaded options<commit_after>(function (exports) {

  'use strict';

  var transformProp;
  var loaded;

  (function () {
    var style = document.createElement('a').style;
    var prop;
    if (style[prop = 'webkitTransform'] !== undefined) {
      transformProp = prop;
    }
    if (style[prop = 'msTransform'] !== undefined) {
      transformProp = prop;
    }
    if (style[prop = 'transform'] !== undefined) {
      transformProp = prop;
    }
  }());

  function forEach(arr, cb) {
    if (arr) {
      for (var i = 0, len = arr.length; i < len; i++) {
        if (arr[i]) {
          cb(arr[i], i, arr);
        }
      }
    }
  }

  function minigrid(props) {
    var containerEle = props.container instanceof Node ?
      props.container : document.querySelector(props.container);

    if (!containerEle) {
      return false;
    }

    var itemsNodeList = props.item instanceof NodeList ?
      props.item : containerEle.querySelectorAll(props.item);
    if (!itemsNodeList || itemsNodeList.length === 0) {
      return false;
    }

    if (!props.containerLoaded || typeof props.containerLoaded !== 'string') {
      props.containerLoaded = false;
    }

    if (!props.containerLoaded || typeof props.itemLoaded !== 'string') {
      props.itemLoaded = false;
    }

    if (loaded || props.skipWindowOnLoad) {
      init(containerEle, itemsNodeList, props);
      return;
    }

    if (/webkit/.test(navigator.userAgent.toLowerCase())) {
      setTimeout(function() {
        webkitWaitForReadyState({
          container: containerEle,
          item: itemsNodeList,
          props: props
        });
      }, 10);
    } else {
      window.onload = function() {
        init(containerEle, itemsNodeList, props);
      };
    }

  }

  function webkitWaitForReadyState(minigrid) {
    if (document.readyState === 'loaded' || document.readyState === 'complete') {
      init(minigrid.container, minigrid.item, minigrid.props);
    } else {
      setTimeout(function() {
        webkitWaitForReadyState(minigrid);
      }, 10);
    }
  }

  function init(containerEle, itemsNodeList, props) {
    if (props.containerLoaded) {
      containerEle.classList.add(props.containerLoaded);
    } else if (!/loaded/.test(containerEle.className)) {
      containerEle.classList.add(containerEle.className.split(' ')[0] + '--loaded');
    }

    loaded = true;

    var gutter = (
      typeof props.gutter === 'number' &&
      isFinite(props.gutter) &&
      Math.floor(props.gutter) === props.gutter
    ) ? props.gutter : 0;
    var done = props.done;

    containerEle.style.width = '';

    var containerWidth = containerEle.getBoundingClientRect().width;
    var firstChildWidth = itemsNodeList[0].getBoundingClientRect().width + gutter;
    var cols = Math.max(Math.floor((containerWidth - gutter) / firstChildWidth), 1);
    var count = 0;

    containerWidth = (firstChildWidth * cols + gutter) + 'px';
    containerEle.style.width = containerWidth;
    containerEle.style.position = 'relative';

    var itemsGutter = [];
    var itemsPosX = [];

    for ( var g = 0 ; g < cols ; ++g ) {
      itemsPosX.push(g * firstChildWidth + gutter);
      itemsGutter.push(gutter);
    }

    forEach(itemsNodeList, function (item) {
      var itemIndex = itemsGutter
        .slice(0)
        .sort(function (a, b) {
          return a - b;
        })
        .shift();
      itemIndex = itemsGutter.indexOf(itemIndex);

      var posX = itemsPosX[itemIndex];
      var posY = itemsGutter[itemIndex];

      item.style.position = 'absolute';
      if (props.itemLoaded) {
        item.classList.add(props.itemLoaded);
      } else if (!/loaded/.test(item.className)) {
        item.classList.add(item.className.split(' ')[0] + '--loaded');
      }

      if (!props.animate && transformProp) {
        item.style[transformProp] = 'translate3D(' + posX + 'px,' + posY + 'px, 0)';
      }

      itemsGutter[itemIndex] += item.getBoundingClientRect().height + gutter;
      count = count + 1;

      if (props.animate) {
        return props.animate(item, posX, posY, count);
      }

    });

    var containerHeight = itemsGutter
      .slice(0)
      .sort(function (a, b) {
        return a - b;
      })
      .pop();

    containerEle.style.height = containerHeight + 'px';
    //containerEle.style.minHeight = containerHeight + 'px';

    if (typeof done === 'function') {
      done(itemsNodeList);
    }
  }

  if (typeof define === 'function' && define.amd) {
    define(function() { return minigrid; });
  } else if (typeof module !== 'undefined' && module.exports) {
    module.exports = minigrid;
  } else {
    exports.minigrid = minigrid;
  }

})(this);
<|endoftext|>


<commit_before>var dift = require('dift')

// Js types
var STRING          = 'string'
var NUMBER          = 'number'
var FUNCTION        = 'function'

// Props
var KEY             = 'key'
var VALUE           = 'value'
var CHECKED         = 'checked'
var SELECTED        = 'selected'
var DISABLED        = 'disabled'
var FOCUS           = 'focus'
var ON              = 'on'
var EMPTYSTRING     = ''

// Html
var VOID_ELEMENTS = { area:1, base:1, br:1, col:1, command:1, embed:1, hr:1, img:1, input:1, keygen:1, link:1, meta:1, param:1, source:1, track:1, wbr:1 }

// vDomType
var VATOM   = 0
var VNODE   = 1
var VCHILD  = 2
var VNULL   = 3

/*
vAtom ::
    String
    Number

vNode ::
    [String]
    [String, { attrs }]
    [String, { attrs }, [vDom ...]]

vChild ::
    [Function, { params }, vNode?]

vDom ::
    vAtom
    vNode
    vChild
    vNull
*/

// vDom -> vDomType
function getType (vDom) {

    if (vDom instanceof Array) {
        return typeof vDom[0] === FUNCTION ? VCHILD : VNODE

    } else if (typeof vDom === STRING || typeof vDom === NUMBER) {
        return VATOM

    } else {
        return VNULL
    }
}

// vDom -> int -> key
function keyOf (v, i) {
    return (v instanceof Array && v[1] && v[1].key) || i
}

// [vDom] -> [{ key: *, vDom: vDom, pos: i }]
function groupChildren (vDoms, DChildren) {
    var res = []
    var v
    var i
    for (i = 0; i < vDoms.length; i++) {
        v = vDoms[i]
        if (!(v === false || v === undefined || v === null)) {
            res.push({ key: keyOf(v, i), vDom: v, element: DChildren && DChildren[i] })
        }
    }
    return res
}

// vDom -> key
function getKey (v) {
    return v.key
}

// [vDom] -> [vDom] -> domNode -> domNode
function updateChildren (currentChildren, nextChildren, D) {

    dift.default(

        groupChildren(currentChildren, D.childNodes),
        groupChildren(nextChildren),

        function effect (type, current, next, pos) {

            switch (type){
                case dift.CREATE: // null, new, posToCreate
                    D.insertBefore(vDomToDom(next.vDom), D.childNodes[pos] || null)
                    break

                case dift.UPDATE: // old, new, null
                    updateDom(current.vDom, next.vDom, current.element, D)
                    break

                case dift.MOVE: // old, new, newPos
                    D.insertBefore(
                        updateDom(current.vDom, next.vDom, current.element, D),
                        current.element
                    )
                    break

                case dift.REMOVE: // null, old, null
                    D.removeChild(current.element)
                    break
            }
        },

        getKey
    )

    return D
}

// vDom -> vDom -> domNode -> domNode -> domNode
function updateDom (current, next, D, DParent) {

    if (D === undefined) { throw new Error('No dom node to update') }

    if (current === next) { return }

    var currentExists = current !== undefined
    var nextExists    = next !== undefined

    if (!currentExists && nextExists) {
        DParent.appendChild(vDomToDom(next))

    } else if (currentExists && !nextExists) {
        DParent.removeChild(D)

    } else if (currentExists && nextExists) {

        var currentType   = getType(current)
        var nextType      = getType(next)

        if (shouldExploreFurther(current, next, currentType, nextType)) {

            switch (nextType) {

                case VNODE:
                    updateAttributes(current[1] || {}, next[1] || {}, D)
                    updateChildren(current[2] || [], next[2] || [], D)
                    break

                case VCHILD:
                    if (!next[0].shouldUpdate || next[0].shouldUpdate(current[1], next[1])) {
                        next[2] = next[0](next[1])
                        updateAttributes(current[2][1] || {}, next[2][1] || {}, D)
                        updateChildren(current[2][2] || [], next[2][2] || [], D)

                    } else {
                        next[2] = current[2]
                    }
                    break
            }

        } else if (current !== next) {
            DParent.replaceChild(vDomToDom(next), D)
        }
    }

    return D
}

// vDom -> vDom -> domNode -> domNode
function updateAttributes (currentAttrs, nextAttrs, D) {

    var a
    var currentVal
    var nextVal
    var evt
    var currentEvts = currentAttrs[ON]
    var nextEvts    = nextAttrs[ON]

    for (a in currentAttrs) { // remove all those not in B from A

        currentVal = currentAttrs[a]
        nextVal = nextAttrs[a]

        if (nextVal === undefined || nextVal === null || nextVal === false) {

            switch (a) {
                case ON:
                case KEY:
                    break
                case CHECKED:
                case DISABLED:
                case SELECTED:
                    D[a] = false
                    break
                case VALUE:
                    D.value = EMPTYSTRING
                    break
                case FOCUS:
                    D.blur()
                    break
                default:
                    D.removeAttribute(a)
                    break
            }
        }
    }

    for (a in nextAttrs) { // set all those in B to A

        currentVal = currentAttrs[a]
        nextVal = nextAttrs[a]

        if (!(nextVal === undefined || nextVal === null || nextVal === false) &&
            nextVal !== currentVal &&
            typeof nextVal !== FUNCTION) {

            switch (a) {
                case ON:
                case KEY:
                    break
                case CHECKED:
                case DISABLED:
                case SELECTED:
                case VALUE:
                    D[a] = nextVal
                    break
                case FOCUS:
                    D.focus()
                    break
                default:
                    D.setAttribute(a, nextVal)
                    break
            }
        }
    }

    // update event listeners
    if (currentEvts && !nextEvts) {
        for (evt in currentEvts) {
             D.removeEventListener(evt, currentEvts[evt])
        }

    } else if (!currentEvts && nextEvts) {
        for (evt in nextEvts) {
             D.addEventListener(evt, nextEvts[evt])
        }

    } else if (currentEvts && nextEvts) {
        for (evt in currentEvts) {
            if (!nextEvts[evt]) {
                D.removeEventListener(evt, currentEvts[evt])
            }
        }
        for (evt in nextEvts) {
            if (currentEvts[evt] !== nextEvts[evt]) {
                if (currentEvts[evt]) {
                    D.removeEventListener(evt, currentEvts[evt])
                }
                D.addEventListener(evt, nextEvts[evt])
            }
        }
    }

    return D
}

// vDom -> vDom -> vType -> vType -> bool
function shouldExploreFurther (current, next, currentType, nextType) {
    return currentType === nextType &&
            (currentType === VNODE || currentType === VCHILD) &&
            current[0] === next[0]
}

// vDom -> HtmlString
function vDomToHtmlString (vDom) {

    switch (getType(vDom)) {

        case VCHILD:
            vDom[2] = vDom[0](vDom[1])
            return vNodeToHtmlString(vDom[2])

        case VNODE:
            return vNodeToHtmlString(vDom)

        case VATOM:
            return vDom

        default:
            return ''
    }
}

// vDom -> HtmlString
function vNodeToHtmlString (vDom) {

    var tag = vDom[0]
    var attrs = vDom[1]
    var val
    var children = vDom[2]
    var a
    var attrPairs = []
    var c
    var res

    for (a in attrs) {
        val = attrs[a]
        if (!(val === undefined || val === null || val === false) && a !== KEY && a !== ON) {
            attrPairs.push(a + '="' + val + '"')
        }
    }

    res = '<' + [tag].concat(attrPairs).join(' ') + '>'

    if (!VOID_ELEMENTS[tag]) {
        for (c = 0; c < children.length; c++) {
            if (!(c === undefined || c === null || c === false)) {
                res += vDomToHtmlString(children[c])
            }
        }
        res += '</' + tag + '>'
    }

    return res
}

// vDom -> domNode
function vDomToDom (vDom) {

    switch (getType(vDom)) {

        case VATOM:
            return document.createTextNode(vDom)

        case VNODE:
        case VCHILD: // child rendering is handled by vDomToHtmlString
            var el = document.createElement('div')
            el.innerHTML = vDomToHtmlString(vDom)
            var dom = el.firstChild
            bindEvents(vDom, dom)
            return dom

        case VNULL:
            throw new Error('Null vdom')
    }
}

// vDom -> domNode -> _
function bindEvents (vDom, D) {

    var vType = getType(vDom)
    var vNode
    var evts
    var evt
    var child
    var children

    if (vType === VATOM || vType === VNULL) { return }

    vNode = vType === VCHILD ? vDom[2] : vDom
    evts = vNode[1][ON]
    children = vNode[2]

    if (evts) {
        for (evt in evts) {
             D.addEventListener(evt, evts[evt])
        }
    }

    if (children) {
        for (child = 0; child < children.length; child++) {
            bindEvents(children[child], D.childNodes[child])
        }
    }
}

module.exports = {
    vDomToHtmlString: vDomToHtmlString,
    vDomToDom: vDomToDom,
    updateDom: updateDom
}
<commit_msg>child empty nodes fix<commit_after>var dift = require('dift')

// Js types
var STRING          = 'string'
var NUMBER          = 'number'
var FUNCTION        = 'function'

// Props
var KEY             = 'key'
var VALUE           = 'value'
var CHECKED         = 'checked'
var SELECTED        = 'selected'
var DISABLED        = 'disabled'
var FOCUS           = 'focus'
var ON              = 'on'
var EMPTYSTRING     = ''

// Html
var VOID_ELEMENTS = { area:1, base:1, br:1, col:1, command:1, embed:1, hr:1, img:1, input:1, keygen:1, link:1, meta:1, param:1, source:1, track:1, wbr:1 }

// vDomType
var VATOM   = 0
var VNODE   = 1
var VCHILD  = 2
var VNULL   = 3

/*
vAtom ::
    String
    Number

vNode ::
    [String]
    [String, { attrs }]
    [String, { attrs }, [vDom ...]]

vChild ::
    [Function, { params }, vNode?]

vDom ::
    vAtom
    vNode
    vChild
    vNull
*/

// * -> bool
function truthy (c) {
    return !(c === undefined || c === null || c === false)
}

// vDom -> vDomType
function getType (vDom) {

    if (vDom instanceof Array) {
        return typeof vDom[0] === FUNCTION ? VCHILD : VNODE

    } else if (typeof vDom === STRING || typeof vDom === NUMBER) {
        return VATOM

    } else {
        return VNULL
    }
}

// vDom -> int -> key
function keyOf (v, i) {
    return (v instanceof Array && v[1] && v[1].key) || i
}

// [vDom] -> [{ key: *, vDom: vDom, pos: i }]
function groupChildren (vDoms, DChildren) {
    var res = []
    var v
    var i

    for (i = 0; i < vDoms.length; i++) {
        v = vDoms[i]
        res.push({ key: keyOf(v, i), vDom: v, element: DChildren && DChildren[i] })
    }

    return res
}

// vDom -> key
function getKey (v) {
    return v.key
}

// [vDom] -> [vDom] -> domNode -> domNode
function updateChildren (current, next, D) {

    var currentChildren = current[2] || []
    var nextChildren = []

    if (next[2]) {
        next[2] = next[2].filter(truthy)
        nextChildren = next[2]
    }

    dift.default(

        groupChildren(currentChildren, D.childNodes),
        groupChildren(nextChildren),

        function effect (type, current, next, pos) {

            switch (type){
                case dift.CREATE: // null, new, posToCreate
                    D.insertBefore(vDomToDom(next.vDom), D.childNodes[pos] || null)
                    break

                case dift.UPDATE: // old, new, null
                    updateDom(current.vDom, next.vDom, current.element, D)
                    break

                case dift.MOVE: // old, new, newPos
                    D.insertBefore(
                        updateDom(current.vDom, next.vDom, current.element, D),
                        current.element
                    )
                    break

                case dift.REMOVE: // null, old, null
                    D.removeChild(current.element)
                    break
            }
        },

        getKey
    )

    return D
}

// vDom -> vDom -> domNode -> domNode -> domNode
function updateDom (current, next, D, DParent) {

    if (D === undefined) { throw new Error('No dom node to update') }

    if (current === next) { return }

    var currentExists = current !== undefined
    var nextExists    = next !== undefined

    if (!currentExists && nextExists) {
        DParent.appendChild(vDomToDom(next))

    } else if (currentExists && !nextExists) {
        DParent.removeChild(D)

    } else if (currentExists && nextExists) {

        var currentType   = getType(current)
        var nextType      = getType(next)

        if (shouldExploreFurther(current, next, currentType, nextType)) {

            switch (nextType) {

                case VNODE:
                    updateAttributes(current[1] || {}, next[1] || {}, D)
                    updateChildren(current, next, D)
                    break

                case VCHILD:
                    if (!next[0].shouldUpdate || next[0].shouldUpdate(current[1], next[1])) {
                        next[2] = next[0](next[1])
                        updateAttributes(current[2][1] || {}, next[2][1] || {}, D)
                        updateChildren(current[2], next[2], D)

                    } else {
                        next[2] = current[2]
                    }
                    break
            }

        } else if (current !== next) {
            DParent.replaceChild(vDomToDom(next), D)
        }
    }

    return D
}

// vDom -> vDom -> domNode -> domNode
function updateAttributes (currentAttrs, nextAttrs, D) {

    var a
    var currentVal
    var nextVal
    var evt
    var currentEvts = currentAttrs[ON]
    var nextEvts    = nextAttrs[ON]

    for (a in currentAttrs) { // remove all those not in B from A

        currentVal = currentAttrs[a]
        nextVal = nextAttrs[a]

        if (!truthy(nextVal)) {

            switch (a) {
                case ON:
                case KEY:
                    break
                case CHECKED:
                case DISABLED:
                case SELECTED:
                    D[a] = false
                    break
                case VALUE:
                    D.value = EMPTYSTRING
                    break
                case FOCUS:
                    D.blur()
                    break
                default:
                    D.removeAttribute(a)
                    break
            }
        }
    }

    for (a in nextAttrs) { // set all those in B to A

        currentVal = currentAttrs[a]
        nextVal = nextAttrs[a]

        if (truthy(nextVal) &&
            nextVal !== currentVal &&
            typeof nextVal !== FUNCTION) {

            switch (a) {
                case ON:
                case KEY:
                    break
                case CHECKED:
                case DISABLED:
                case SELECTED:
                case VALUE:
                    D[a] = nextVal
                    break
                case FOCUS:
                    D.focus()
                    break
                default:
                    D.setAttribute(a, nextVal)
                    break
            }
        }
    }

    // update event listeners
    if (currentEvts && !nextEvts) {
        for (evt in currentEvts) {
             D.removeEventListener(evt, currentEvts[evt])
        }

    } else if (!currentEvts && nextEvts) {
        for (evt in nextEvts) {
             D.addEventListener(evt, nextEvts[evt])
        }

    } else if (currentEvts && nextEvts) {
        for (evt in currentEvts) {
            if (!nextEvts[evt]) {
                D.removeEventListener(evt, currentEvts[evt])
            }
        }
        for (evt in nextEvts) {
            if (currentEvts[evt] !== nextEvts[evt]) {
                if (currentEvts[evt]) {
                    D.removeEventListener(evt, currentEvts[evt])
                }
                D.addEventListener(evt, nextEvts[evt])
            }
        }
    }

    return D
}

// vDom -> vDom -> vType -> vType -> bool
function shouldExploreFurther (current, next, currentType, nextType) {
    return currentType === nextType &&
            (currentType === VNODE || currentType === VCHILD) &&
            current[0] === next[0]
}

// vDom -> HtmlString
function vDomToHtmlString (vDom) {

    switch (getType(vDom)) {

        case VCHILD:
            vDom[2] = vDom[0](vDom[1])
            return vNodeToHtmlString(vDom[2])

        case VNODE:
            return vNodeToHtmlString(vDom)

        case VATOM:
            return vDom

        default:
            return ''
    }
}

// vDom -> HtmlString
function vNodeToHtmlString (vDom) {

    var tag = vDom[0]
    var attrs = vDom[1]
    var val
    var children = []
    var a
    var attrPairs = []
    var c
    var res

    if (vDom[2]) {
        vDom[2] = vDom[2].filter(truthy)
        children = vDom[2]
    }

    for (a in attrs) {
        val = attrs[a]
        if (truthy(val) && a !== KEY && a !== ON) {
            attrPairs.push(a + '="' + val + '"')
        }
    }

    res = '<' + [tag].concat(attrPairs).join(' ') + '>'

    if (!VOID_ELEMENTS[tag]) {
        for (c = 0; c < children.length; c++) {
            res += vDomToHtmlString(children[c])
        }
        res += '</' + tag + '>'
    }

    return res
}

// vDom -> domNode
function vDomToDom (vDom) {

    switch (getType(vDom)) {

        case VATOM:
            return document.createTextNode(vDom)

        case VNODE:
        case VCHILD: // child rendering is handled by vDomToHtmlString
            var el = document.createElement('div')
            el.innerHTML = vDomToHtmlString(vDom)
            var dom = el.firstChild
            bindEvents(vDom, dom)
            return dom

        case VNULL:
            throw new Error('Null vdom')
    }
}

// vDom -> domNode -> _
function bindEvents (vDom, D) {

    var vType = getType(vDom)
    var vNode
    var evts
    var evt
    var child
    var children

    if (vType === VATOM || vType === VNULL) { return }

    vNode = vType === VCHILD ? vDom[2] : vDom
    evts = vNode[1][ON]
    children = vNode[2]

    if (evts) {
        for (evt in evts) {
             D.addEventListener(evt, evts[evt])
        }
    }

    if (children) {
        for (child = 0; child < children.length; child++) {
            bindEvents(children[child], D.childNodes[child])
        }
    }
}

module.exports = {
    vDomToHtmlString: vDomToHtmlString,
    vDomToDom: vDomToDom,
    updateDom: updateDom
}
<|endoftext|>


<commit_before>import React from 'react';
import { render } from 'react-dom';

import bala from 'balajs';
import configureStore from './store/configureStore';
import Root from './components/Root';
import { initialize } from './actions';

let Wrap;

if (process.env.NODE_ENV === 'development') {
    Wrap = require('react-hot-loader').AppContainer;
} else {
    Wrap = ({ children }) => children;
}

module.exports = function githubEmbed(node, pathToSettings) {
    const store = configureStore();

    store.dispatch(initialize(pathToSettings));

    render(
        <Wrap>
            <Root store={store} />
        </Wrap>,
        bala.one(node)
    );

    if (module.hot) {
        module.hot.accept('./components/Root', () => {
            // eslint-disable-next-line global-require
            const RootContainer = require('./components/Root').default;

            render(
                <Wrap>
                    <RootContainer store={store} />
                </Wrap>,
                bala.one(node)
            );
        });
    }
};
<commit_msg>chore: Fix lint errors<commit_after>import React from 'react';
import { render } from 'react-dom';

import bala from 'balajs';
import configureStore from './store/configureStore';
import Root from './components/Root';
import { initialize } from './actions';

let Wrap;

if (process.env.NODE_ENV === 'development') {
    // eslint-disable-next-line global-require
    Wrap = require('react-hot-loader').AppContainer;
} else {
    Wrap = ({ children }) => children;
}

module.exports = function githubEmbed(node, pathToSettings) {
    const store = configureStore();

    store.dispatch(initialize(pathToSettings));

    render(
        <Wrap>
            <Root store={store} />
        </Wrap>,
        bala.one(node)
    );

    if (module.hot) {
        module.hot.accept('./components/Root', () => {
            // eslint-disable-next-line global-require
            const RootContainer = require('./components/Root').default;

            render(
                <Wrap>
                    <RootContainer store={store} />
                </Wrap>,
                bala.one(node)
            );
        });
    }
};
<|endoftext|>