<commit_before>/* eslint-disable no-console, react/forbid-prop-types */

import React, { Component } from 'react';
import { Route, withRouter, Switch } from 'react-router-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import * as CookieHelpers from 'shared/utils/cookieHelper';
import Login from 'shared/components/login/login';
import IdmeVerify from 'shared/components/idme/idmeverify/idmeverify';
import AuthenticatedRoute from 'shared/components/authenticatedRoute/authenticatedRoute';
import familyImage from 'images/Family-2.jpg';
import Profile from './profile/profile';
import SignUp from './signup/signup';
import MentorRequestsTable from './mentor/mentorRequestsTable/mentorRequestsTable';
import SquadsTable from './squads/squadsTable/squadsTable';
import Dashboard from './dashboard/dashboard';
import MentorsTable from './mentor/mentorsTable/mentorsTable';
import Thanks from './thanks/thanks';
import Team from './team/team';
import Gala from './gala/gala';
import FAQ from './faq/faq';
import Contact from './contact/contact';
import History from './history/history';
import FinancialStatements from './about/financialStatements/financialStatements';
import Header from './header/header';
import Landing from './landing/landing';
import Footer from './footer/footer';
import FourOhFour from './404/fourOhFour';
import MentorRequest from './mentorRequest/mentorRequest';
import SquadsNew from './squads/squadsNew/squadsNew';
import CodeSchools from './codeSchools/codeSchools';
import About from './about/about';
import Press from './press/press';
import ResetPassword from './resetPassword/resetPassword';
import Challenge from './challenge/challenge';
import styles from './home.css';

class Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      bgImage: false,
      bgImageUrl: null,
      signedIn: false,
      mentor: false
    };

    this.props.history.listen((location) => {
      this.setBgImage(location);
    });
  }

  componentWillMount() {
    this.setBgImage(this.props.location);
    this.updateRootAuthState();
  }

  setBgImage(location) {
    if (location.pathname === '/') {
      this.setState({ bgChanged: !(this.state.bgImage), bgImage: true, bgImageUrl: familyImage });
    } else {
      this.setState({ bgChanged: this.state.bgImage, bgImage: false, bgImageUrl: null });
    }
  }

  updateRootAuthState = (cb) => {
    const cookies = CookieHelpers.getUserStatus();
    this.setState({
      signedIn: cookies.signedIn,
      mentor: cookies.mentor,
      verified: cookies.verified
    }, () => {
      if (cb) {
        cb(this.props.history);
      }
    });
  }

  logOut = () => {
    CookieHelpers.clearAuthCookies();
    this.setState({
      signedIn: false,
      mentor: false,
      verified: false
    }, () => this.props.history.push('/'));
  }

  render() {
    const { mentor, signedIn, verified } = this.state;
    const authProps = {
      signedIn,
      mentor,
      verified
    };

    const classes = classNames({
      [`${styles.home}`]: true,
      [`${styles.backgroundImage}`]: this.state.bgImage
    });
    return (
      <div
        className={classes}
        style={(this.state.bgImage) ? { backgroundImage: `url(${this.state.bgImageUrl})` } : {}}
      >

          <Switch>
            <Route
              path="/home"
              component={Dashboard}
            />
            <Route
              path="/code-schools"
              component={CodeSchools}
            />
            <Route
              path="/code_schools"
              component={CodeSchools}
            />
            <Route
              path="/signup"
              component={SignUp}
            />
            <Route
              path="/join"
              component={SignUp}
            />
            <Route
              path="/history"
              component={History}
            />
            <Route
              path="/sign-up"
              component={SignUp}
            />
            <Route
              path="/thanks"
              component={Thanks}
            />
            <Route
              path="/team"
              component={Team}
            />
            <Route
              path="/faq"
              component={FAQ}
            />
            <Route
              path="/contact"
              component={Contact}
            />
            <Route
              path="/about"
              component={About}
            />
            <Route
              path="/press"
              component={Press}
            />
            <Route
              path="/media"
              component={Press}
            />
            <Route
              path="/challenge"
              component={Challenge}
            />
            <Route
              exact
              path="/"
              render={props => (
                <Landing {...props} />
              )}
            />
            <Route
              path="/mentor-request"
              render={() => (
                <MentorRequest {...authProps} />
              )}
            />
            <Route
              path="/requests"
              render={() => (
                <MentorRequestsTable {...authProps} />
              )}
            />
            <Route
              path="/squads/new-squad"
              render={() => (
                <SquadsNew {...authProps} />
              )}
            />
            <Route
              exact path="/mentors"
              render={() => (
                <MentorsTable {...authProps} />
              )}
            />
            <Route
              path="/squads"
              render={() => (
                <SquadsTable {...authProps} />
              )}
            />
            <Route
              path="/gala"
              render={() => (
                <Gala {...authProps} />
              )}
            />
            <Route
              path="/newgibill"
              component={() => (window.location = 'http://www.benefits.va.gov/gibill/post911_gibill.asp')}
            />
            <Route
              path="/login"
              render={() => (
                <Login updateRootAuthState={this.updateRootAuthState} {...authProps} />
              )}
            />
            <AuthenticatedRoute
              exact path="/profile"
              isLoggedIn={CookieHelpers.getUserStatus().signedIn}
              component={Profile}
              {...authProps}
            />
            <AuthenticatedRoute
              exact path="/profile/verify"
              isLoggedIn={CookieHelpers.getUserStatus().signedIn}
              component={IdmeVerify}
              updateRootAuthState={this.updateRootAuthState}
              {...authProps}
            />
            <Route exact path="/about/financial-statements" component={FinancialStatements} />
            <Route exact path="/reset_password" component={ResetPassword} />
            <Route
              path="*" component={FourOhFour}
            />
          </Switch>

    );
  }
}

Home.propTypes = {
  history: PropTypes.object.isRequired,
  location: PropTypes.object.isRequired
};

export default withRouter(Home);
<commit_msg>Fix rendering of /about/financial-statements<commit_after>/* eslint-disable no-console, react/forbid-prop-types */

import React, { Component } from 'react';
import { Route, withRouter, Switch } from 'react-router-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import * as CookieHelpers from 'shared/utils/cookieHelper';
import Login from 'shared/components/login/login';
import IdmeVerify from 'shared/components/idme/idmeverify/idmeverify';
import AuthenticatedRoute from 'shared/components/authenticatedRoute/authenticatedRoute';
import familyImage from 'images/Family-2.jpg';
import Profile from './profile/profile';
import SignUp from './signup/signup';
import MentorRequestsTable from './mentor/mentorRequestsTable/mentorRequestsTable';
import SquadsTable from './squads/squadsTable/squadsTable';
import Dashboard from './dashboard/dashboard';
import MentorsTable from './mentor/mentorsTable/mentorsTable';
import Thanks from './thanks/thanks';
import Team from './team/team';
import Gala from './gala/gala';
import FAQ from './faq/faq';
import Contact from './contact/contact';
import History from './history/history';
import FinancialStatements from './about/financialStatements/financialStatements';
import Header from './header/header';
import Landing from './landing/landing';
import Footer from './footer/footer';
import FourOhFour from './404/fourOhFour';
import MentorRequest from './mentorRequest/mentorRequest';
import SquadsNew from './squads/squadsNew/squadsNew';
import CodeSchools from './codeSchools/codeSchools';
import About from './about/about';
import Press from './press/press';
import ResetPassword from './resetPassword/resetPassword';
import Challenge from './challenge/challenge';
import styles from './home.css';

class Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      bgImage: false,
      bgImageUrl: null,
      signedIn: false,
      mentor: false
    };

    this.props.history.listen((location) => {
      this.setBgImage(location);
    });
  }

  componentWillMount() {
    this.setBgImage(this.props.location);
    this.updateRootAuthState();
  }

  setBgImage(location) {
    if (location.pathname === '/') {
      this.setState({ bgChanged: !(this.state.bgImage), bgImage: true, bgImageUrl: familyImage });
    } else {
      this.setState({ bgChanged: this.state.bgImage, bgImage: false, bgImageUrl: null });
    }
  }

  updateRootAuthState = (cb) => {
    const cookies = CookieHelpers.getUserStatus();
    this.setState({
      signedIn: cookies.signedIn,
      mentor: cookies.mentor,
      verified: cookies.verified
    }, () => {
      if (cb) {
        cb(this.props.history);
      }
    });
  }

  logOut = () => {
    CookieHelpers.clearAuthCookies();
    this.setState({
      signedIn: false,
      mentor: false,
      verified: false
    }, () => this.props.history.push('/'));
  }

  render() {
    const { mentor, signedIn, verified } = this.state;
    const authProps = {
      signedIn,
      mentor,
      verified
    };

    const classes = classNames({
      [`${styles.home}`]: true,
      [`${styles.backgroundImage}`]: this.state.bgImage
    });
    return (
      <div
        className={classes}
        style={(this.state.bgImage) ? { backgroundImage: `url(${this.state.bgImageUrl})` } : {}}
      >

          <Switch>
            <Route
              path="/home"
              component={Dashboard}
            />
            <Route
              path="/code-schools"
              component={CodeSchools}
            />
            <Route
              path="/code_schools"
              component={CodeSchools}
            />
            <Route
              path="/signup"
              component={SignUp}
            />
            <Route
              path="/join"
              component={SignUp}
            />
            <Route
              path="/history"
              component={History}
            />
            <Route
              path="/sign-up"
              component={SignUp}
            />
            <Route
              path="/thanks"
              component={Thanks}
            />
            <Route
              path="/team"
              component={Team}
            />
            <Route
              path="/faq"
              component={FAQ}
            />
            <Route
              path="/contact"
              component={Contact}
            />
            <Route
              exact
              path="/about/financial-statements"
              component={FinancialStatements}
            />
            <Route
              path="/about"
              component={About}
            />
            <Route
              path="/press"
              component={Press}
            />
            <Route
              path="/media"
              component={Press}
            />
            <Route
              path="/challenge"
              component={Challenge}
            />
            <Route
              exact
              path="/"
              render={props => (
                <Landing {...props} />
              )}
            />
            <Route
              path="/mentor-request"
              render={() => (
                <MentorRequest {...authProps} />
              )}
            />
            <Route
              path="/requests"
              render={() => (
                <MentorRequestsTable {...authProps} />
              )}
            />
            <Route
              path="/squads/new-squad"
              render={() => (
                <SquadsNew {...authProps} />
              )}
            />
            <Route
              exact path="/mentors"
              render={() => (
                <MentorsTable {...authProps} />
              )}
            />
            <Route
              path="/squads"
              render={() => (
                <SquadsTable {...authProps} />
              )}
            />
            <Route
              path="/gala"
              render={() => (
                <Gala {...authProps} />
              )}
            />
            <Route
              path="/newgibill"
              component={() => (window.location = 'http://www.benefits.va.gov/gibill/post911_gibill.asp')}
            />
            <Route
              path="/login"
              render={() => (
                <Login updateRootAuthState={this.updateRootAuthState} {...authProps} />
              )}
            />
            <AuthenticatedRoute
              exact path="/profile"
              isLoggedIn={CookieHelpers.getUserStatus().signedIn}
              component={Profile}
              {...authProps}
            />
            <AuthenticatedRoute
              exact path="/profile/verify"
              isLoggedIn={CookieHelpers.getUserStatus().signedIn}
              component={IdmeVerify}
              updateRootAuthState={this.updateRootAuthState}
              {...authProps}
            />
            <Route exact path="/reset_password" component={ResetPassword} />
            <Route
              path="*" component={FourOhFour}
            />
          </Switch>

    );
  }
}

Home.propTypes = {
  history: PropTypes.object.isRequired,
  location: PropTypes.object.isRequired
};

export default withRouter(Home);
<|endoftext|>


<commit_before>import { assert } from '../util/debug'
// import { ease } from '../util/ease'

// Number of items to instantiate beyond current view in the scroll direction.
const RUNWAY_ITEMS = 30

// Number of items to instantiate beyond current view in the opposite direction.
const RUNWAY_ITEMS_OPPOSITE = 10

// The animation interval (in ms) for fading in content from tombstones.
const ANIMATION_DURATION_MS = 200

// The number of pixels of default additional length to allow scrolling to.
const DEFAULT_SCROLL_RUNWAY = 2000

export function infiniteMixin(BScroll) {
  BScroll.prototype._initInfinite = function () {
    this.options.probeType = 3
    this.maxScrollY = -DEFAULT_SCROLL_RUNWAY
    this.infiniteScroller = new InfiniteScroller(this, this.options.infinity)
  }
}

function isTombstoneNode(node) {
  if (node && node.classList) {
    return node.classList.contains('tombstone')
  }
}

function InfiniteScroller(scroller, options) {
  this.options = options
  assert(typeof this.options.createTombstone === 'function', 'Infinite scroll need createTombstone Function to create tombstone')

  assert(typeof this.options.fetch === 'function', 'Infinite scroll need fetch Function to fetch new data.')

  assert(typeof this.options.render === 'function', 'Infinite scroll need render Function to render each item.')

  this.firstAttachedItem = 0
  this.lastAttachedItem = 0

  this.anchorScrollTop = 0
  this.anchorItem = {
    index: 0,
    offset: 0
  }
  this.tombstoneHeight = 0
  this.tombstoneWidth = 0
  this.tombstones = []

  this.items = []
  this.loadedItems = 0
  this.requestInProgress = false
  this.hasMore = true

  this.scroller = scroller
  this.wrapperEl = this.scroller.wrapper
  this.scrollerEl = this.scroller.scroller
  this.scroller.on('scroll', () => {
    this.onScroll()
  })
  this.scroller.on('resize', () => {
    this.onResize()
  })

  this.onResize()
}

InfiniteScroller.prototype.onScroll = function () {
  const scrollTop = -this.scroller.y
  let delta = scrollTop - this.anchorScrollTop
  if (scrollTop === 0) {
    this.anchorItem = {
      index: 0,
      offset: 0
    }
  } else {
    this.anchorItem = this._calculateAnchoredItem(this.anchorItem, delta)
  }

  this.anchorScrollTop = scrollTop
  let lastScreenItem = this._calculateAnchoredItem(this.anchorItem, this.wrapperEl.offsetHeight)

  let start = this.anchorItem.index
  let end = lastScreenItem.index
  if (delta < 0) {
    start -= RUNWAY_ITEMS
    end += RUNWAY_ITEMS_OPPOSITE
  } else {
    start -= RUNWAY_ITEMS_OPPOSITE
    end += RUNWAY_ITEMS
  }
  this.fill(start, end)
  this.maybeRequestContent()
}

InfiniteScroller.prototype.onResize = function () {
  let tombstone = this.options.createTombstone()
  tombstone.style.position = 'absolute'
  this.scrollerEl.appendChild(tombstone)
  tombstone.style.display = ''
  this.tombstoneHeight = tombstone.offsetHeight
  this.tombstoneWidth = tombstone.offsetWidth
  this.scrollerEl.removeChild(tombstone)

  for (let i = 0; i < this.items.length; i++) {
    this.items[i].height = this.items[i].width = 0
  }

  this.onScroll()
}

InfiniteScroller.prototype.fill = function (start, end) {
  this.firstAttachedItem = Math.max(0, start)
  if (!this.hasMore) {
    end = Math.min(end, this.items.length)
  }
  this.lastAttachedItem = end
  this.attachContent()
}

InfiniteScroller.prototype.maybeRequestContent = function () {
  if (this.requestInProgress || !this.hasMore) {
    return
  }
  let itemsNeeded = this.lastAttachedItem - this.loadedItems
  if (itemsNeeded <= 0) {
    return
  }
  this.requestInProgress = true
  this.options.fetch(itemsNeeded).then((items) => {
    if (items) {
      this.addContent(items)
    } else {
      this.hasMore = false
      let tombstoneLen = this._removeTombstones()
      let curPos = 0
      if (this.anchorItem.index <= this.items.length) {
        curPos = this._fixScrollPosition()
        this._setupAnimations({}, curPos)
        this.scroller.resetPosition(this.scroller.options.bounceTime)
      } else {
        this.anchorItem.index -= tombstoneLen
        curPos = this._fixScrollPosition()
        this._setupAnimations({}, curPos)
        this.scroller.stop()
        this.scroller.resetPosition()
        this.onScroll()
      }
    }
  })
}

InfiniteScroller.prototype.addContent = function (items) {
  this.requestInProgress = false
  for (let i = 0; i < items.length; i++) {
    if (this.items.length <= this.loadedItems) {
      this._addItem()
    }
    this.items[this.loadedItems++].data = items[i]
  }
  this.attachContent()
  this.maybeRequestContent()
}

InfiniteScroller.prototype.attachContent = function () {
  let unusedNodes = this._collectUnusedNodes()
  let tombstoneAnimations = this._createDOMNodes(unusedNodes)
  this._cleanupUnusedNodes(unusedNodes)
  this._cacheNodeSize()
  let curPos = this._fixScrollPosition()
  this._setupAnimations(tombstoneAnimations, curPos)
}

InfiniteScroller.prototype._removeTombstones = function () {
  let markIndex
  let tombstoneLen = 0
  let itemLen = this.items.length
  for (let i = 0; i < itemLen; i++) {
    const currentNode = this.items[i].node
    const currentData = this.items[i].data
    if ((!currentNode || isTombstoneNode(currentNode)) && !currentData) {
      if (!markIndex) {
        markIndex = i
      }
      if (currentNode) {
        this.scrollerEl.removeChild(currentNode)
      }
    }
  }
  tombstoneLen = itemLen - markIndex
  this.items.splice(markIndex)
  this.lastAttachedItem = Math.min(this.lastAttachedItem, this.items.length)
  return tombstoneLen
}

InfiniteScroller.prototype._collectUnusedNodes = function () {
  let unusedNodes = []
  for (let i = 0; i < this.items.length; i++) {
    // Skip the items which should be visible.
    if (i === this.firstAttachedItem) {
      i = this.lastAttachedItem - 1
      continue
    }
    const currentNode = this.items[i].node
    if (currentNode) {
      if (isTombstoneNode(currentNode)) {
        // Cache tombstones for reuse
        this.tombstones.push(currentNode)
        this.tombstones[this.tombstones.length - 1].style.display = 'none'
      } else {
        unusedNodes.push(currentNode)
      }
    }
    this.items[i].node = null
  }
  return unusedNodes
}

InfiniteScroller.prototype._createDOMNodes = function (unusedNodes) {
  let tombstoneAnimations = {}
  for (let i = this.firstAttachedItem; i < this.lastAttachedItem; i++) {
    while (this.items.length <= i) {
      this._addItem()
    }
    const currentNode = this.items[i].node
    const currentData = this.items[i].data
    if (currentNode) {
      if (isTombstoneNode(currentNode) && currentData) {
        currentNode.style.zIndex = 1
        tombstoneAnimations[i] = [currentNode, this.items[i].top - this.anchorScrollTop]
        this.items[i].node = null
      } else {
        continue
      }
    }
    let node = currentData ? this.options.render(currentData, unusedNodes.pop()) : this._getTombStone()
    node.style.position = 'absolute'
    this.items[i].top = -1
    this.scrollerEl.appendChild(node)
    this.items[i].node = node
  }
  return tombstoneAnimations
}

InfiniteScroller.prototype._cleanupUnusedNodes = function (unusedNodes) {
  while (unusedNodes.length) {
    this.scrollerEl.removeChild(unusedNodes.pop())
  }
}

InfiniteScroller.prototype._cacheNodeSize = function () {
  for (let i = this.firstAttachedItem; i < this.lastAttachedItem; i++) {
    // Only cache the height if we have the real contents, not a placeholder.
    if (this.items[i].data && !this.items[i].height) {
      this.items[i].height = this.items[i].node.offsetHeight
      this.items[i].width = this.items[i].node.offsetWidth
    }
  }
}

InfiniteScroller.prototype._fixScrollPosition = function () {
  this.anchorScrollTop = 0
  for (let i = 0; i < this.anchorItem.index; i++) {
    this.anchorScrollTop += this.items[i].height || this.tombstoneHeight
  }
  this.anchorScrollTop += this.anchorItem.offset

  // Position all nodes.
  let curPos = this.anchorScrollTop - this.anchorItem.offset
  let i = this.anchorItem.index
  while (i > this.firstAttachedItem) {
    curPos -= this.items[i - 1].height || this.tombstoneHeight
    i--
  }

  return curPos
}

InfiniteScroller.prototype._setupAnimations = function (tombstoneAnimations, curPos) {
  for (let i in tombstoneAnimations) {
    const animation = tombstoneAnimations[i]
    this.items[i].node.style.transform = `translateY(${this.anchorScrollTop + animation[1]}px) scale(${this.tombstoneWidth / this.items[i].width}, ${this.tombstoneHeight / this.items[i].height})`
    // Call offsetTop on the nodes to be animated to force them to apply current transforms.
    /* eslint-disable no-unused-expressions */
    this.items[i].node.offsetTop
    animation[0].offsetTop
    this.items[i].node.style.transition = `transform ${ANIMATION_DURATION_MS}ms`
  }

  for (let i = this.firstAttachedItem; i < this.lastAttachedItem; i++) {
    const animation = tombstoneAnimations[i]
    if (animation) {
      const tombstoneNode = animation[0]
      tombstoneNode.style.transition = `transform ${ANIMATION_DURATION_MS}ms, opacity ${ANIMATION_DURATION_MS}ms`
      tombstoneNode.style.transform = `translateY(${curPos}px) scale(${this.items[i].width / this.tombstoneWidth}, ${this.items[i].height / this.tombstoneHeight})`
      tombstoneNode.style.opacity = 0
    }
    if (curPos !== this.items[i].top) {
      if (!animation) {
        this.items[i].node.style.transition = ''
      }
      this.items[i].node.style.transform = `translateY(${curPos}px)`
    }
    this.items[i].top = curPos
    curPos += this.items[i].height || this.tombstoneHeight
  }

  this.scroller.maxScrollY = -(curPos - this.wrapperEl.offsetHeight + (this.hasMore ? DEFAULT_SCROLL_RUNWAY : 0))

  setTimeout(() => {
    for (let i in tombstoneAnimations) {
      const animation = tombstoneAnimations[i]
      animation[0].style.display = 'none'
      // Tombstone can be recycled now.
      this.tombstones.push(animation[0])
    }
  }, ANIMATION_DURATION_MS)
}

InfiniteScroller.prototype._getTombStone = function () {
  let tombstone = this.tombstones.pop()
  if (tombstone) {
    tombstone.style.display = ''
    tombstone.style.opacity = 1
    tombstone.style.transform = ''
    tombstone.style.transition = ''
    return tombstone
  }
  return this.options.createTombstone()
}

InfiniteScroller.prototype._addItem = function () {
  this.items.push({
    data: null,
    node: null,
    height: 0,
    width: 0,
    top: 0
  })
}

InfiniteScroller.prototype._calculateAnchoredItem = function (initialAnchor, delta) {
  if (delta === 0) {
    return initialAnchor
  }
  let i = initialAnchor.index
  let tombstones = 0

  delta += initialAnchor.offset
  if (delta < 0) {
    while (delta < 0 && i > 0 && this.items[i - 1].height) {
      delta += this.items[i - 1].height
      i--
    }
    tombstones = Math.max(-i, Math.ceil(Math.min(delta, 0) / this.tombstoneHeight))
  } else {
    while (delta > 0 && i < this.items.length && this.items[i].height && this.items[i].height < delta) {
      delta -= this.items[i].height
      i++
    }
    if (i >= this.items.length || !this.items[i].height) {
      tombstones = Math.floor(Math.max(delta, 0) / this.tombstoneHeight)
    }
  }
  i += tombstones
  delta -= tombstones * this.tombstoneHeight

  return {
    index: i,
    offset: delta
  }
}
<commit_msg>[feat] add resetMore API for inifinity scroller<commit_after>import { assert } from '../util/debug'
// import { ease } from '../util/ease'

// Number of items to instantiate beyond current view in the scroll direction.
const RUNWAY_ITEMS = 30

// Number of items to instantiate beyond current view in the opposite direction.
const RUNWAY_ITEMS_OPPOSITE = 10

// The animation interval (in ms) for fading in content from tombstones.
const ANIMATION_DURATION_MS = 200

// The number of pixels of default additional length to allow scrolling to.
const DEFAULT_SCROLL_RUNWAY = 2000

export function infiniteMixin(BScroll) {
  BScroll.prototype._initInfinite = function () {
    this.options.probeType = 3
    this.maxScrollY = -DEFAULT_SCROLL_RUNWAY
    this.infiniteScroller = new InfiniteScroller(this, this.options.infinity)
  }
}

function isTombstoneNode(node) {
  if (node && node.classList) {
    return node.classList.contains('tombstone')
  }
}

function InfiniteScroller(scroller, options) {
  this.options = options
  assert(typeof this.options.createTombstone === 'function', 'Infinite scroll need createTombstone Function to create tombstone')

  assert(typeof this.options.fetch === 'function', 'Infinite scroll need fetch Function to fetch new data.')

  assert(typeof this.options.render === 'function', 'Infinite scroll need render Function to render each item.')

  this.firstAttachedItem = 0
  this.lastAttachedItem = 0

  this.anchorScrollTop = 0
  this.anchorItem = {
    index: 0,
    offset: 0
  }
  this.tombstoneHeight = 0
  this.tombstoneWidth = 0
  this.tombstones = []

  this.items = []
  this.loadedItems = 0
  this.requestInProgress = false
  this.hasMore = true

  this.scroller = scroller
  this.wrapperEl = this.scroller.wrapper
  this.scrollerEl = this.scroller.scroller
  this.scroller.on('scroll', () => {
    this.onScroll()
  })
  this.scroller.on('resize', () => {
    this.onResize()
  })

  this.onResize()
}

InfiniteScroller.prototype.onScroll = function () {
  const scrollTop = -this.scroller.y
  let delta = scrollTop - this.anchorScrollTop
  if (scrollTop === 0) {
    this.anchorItem = {
      index: 0,
      offset: 0
    }
  } else {
    this.anchorItem = this._calculateAnchoredItem(this.anchorItem, delta)
  }

  this.anchorScrollTop = scrollTop
  let lastScreenItem = this._calculateAnchoredItem(this.anchorItem, this.wrapperEl.offsetHeight)

  let start = this.anchorItem.index
  let end = lastScreenItem.index
  if (delta < 0) {
    start -= RUNWAY_ITEMS
    end += RUNWAY_ITEMS_OPPOSITE
  } else {
    start -= RUNWAY_ITEMS_OPPOSITE
    end += RUNWAY_ITEMS
  }
  this.fill(start, end)
  this.maybeRequestContent()
}

InfiniteScroller.prototype.onResize = function () {
  let tombstone = this.options.createTombstone()
  tombstone.style.position = 'absolute'
  this.scrollerEl.appendChild(tombstone)
  tombstone.style.display = ''
  this.tombstoneHeight = tombstone.offsetHeight
  this.tombstoneWidth = tombstone.offsetWidth
  this.scrollerEl.removeChild(tombstone)

  for (let i = 0; i < this.items.length; i++) {
    this.items[i].height = this.items[i].width = 0
  }

  this.onScroll()
}

InfiniteScroller.prototype.fill = function (start, end) {
  this.firstAttachedItem = Math.max(0, start)
  if (!this.hasMore) {
    end = Math.min(end, this.items.length)
  }
  this.lastAttachedItem = end
  this.attachContent()
}

InfiniteScroller.prototype.maybeRequestContent = function () {
  if (this.requestInProgress || !this.hasMore) {
    return
  }
  let itemsNeeded = this.lastAttachedItem - this.loadedItems
  if (itemsNeeded <= 0) {
    return
  }
  this.requestInProgress = true
  this.options.fetch(itemsNeeded).then((items) => {
    this.requestInProgress = false
    if (items) {
      this.addContent(items)
    } else {
      this.hasMore = false
      let tombstoneLen = this._removeTombstones()
      let curPos = 0
      if (this.anchorItem.index <= this.items.length) {
        curPos = this._fixScrollPosition()
        this._setupAnimations({}, curPos)
        this.scroller.resetPosition(this.scroller.options.bounceTime)
      } else {
        this.anchorItem.index -= tombstoneLen
        curPos = this._fixScrollPosition()
        this._setupAnimations({}, curPos)
        this.scroller.stop()
        this.scroller.resetPosition()
        this.onScroll()
      }
    }
  })
}

InfiniteScroller.prototype.addContent = function (items) {
  for (let i = 0; i < items.length; i++) {
    if (this.items.length <= this.loadedItems) {
      this._addItem()
    }
    this.items[this.loadedItems++].data = items[i]
  }
  this.attachContent()
  this.maybeRequestContent()
}

InfiniteScroller.prototype.attachContent = function () {
  let unusedNodes = this._collectUnusedNodes()
  let tombstoneAnimations = this._createDOMNodes(unusedNodes)
  this._cleanupUnusedNodes(unusedNodes)
  this._cacheNodeSize()
  let curPos = this._fixScrollPosition()
  this._setupAnimations(tombstoneAnimations, curPos)
}

InfiniteScroller.prototype.resetMore = function () {
  this.hasMore = true
}

InfiniteScroller.prototype._removeTombstones = function () {
  let markIndex
  let tombstoneLen = 0
  let itemLen = this.items.length
  for (let i = 0; i < itemLen; i++) {
    const currentNode = this.items[i].node
    const currentData = this.items[i].data
    if ((!currentNode || isTombstoneNode(currentNode)) && !currentData) {
      if (!markIndex) {
        markIndex = i
      }
      if (currentNode) {
        this.scrollerEl.removeChild(currentNode)
      }
    }
  }
  tombstoneLen = itemLen - markIndex
  this.items.splice(markIndex)
  this.lastAttachedItem = Math.min(this.lastAttachedItem, this.items.length)
  return tombstoneLen
}

InfiniteScroller.prototype._collectUnusedNodes = function () {
  let unusedNodes = []
  for (let i = 0; i < this.items.length; i++) {
    // Skip the items which should be visible.
    if (i === this.firstAttachedItem) {
      i = this.lastAttachedItem - 1
      continue
    }
    const currentNode = this.items[i].node
    if (currentNode) {
      if (isTombstoneNode(currentNode)) {
        // Cache tombstones for reuse
        this.tombstones.push(currentNode)
        this.tombstones[this.tombstones.length - 1].style.display = 'none'
      } else {
        unusedNodes.push(currentNode)
      }
    }
    this.items[i].node = null
  }
  return unusedNodes
}

InfiniteScroller.prototype._createDOMNodes = function (unusedNodes) {
  let tombstoneAnimations = {}
  for (let i = this.firstAttachedItem; i < this.lastAttachedItem; i++) {
    while (this.items.length <= i) {
      this._addItem()
    }
    const currentNode = this.items[i].node
    const currentData = this.items[i].data
    if (currentNode) {
      if (isTombstoneNode(currentNode) && currentData) {
        currentNode.style.zIndex = 1
        tombstoneAnimations[i] = [currentNode, this.items[i].top - this.anchorScrollTop]
        this.items[i].node = null
      } else {
        continue
      }
    }
    let node = currentData ? this.options.render(currentData, unusedNodes.pop()) : this._getTombStone()
    node.style.position = 'absolute'
    this.items[i].top = -1
    this.scrollerEl.appendChild(node)
    this.items[i].node = node
  }
  return tombstoneAnimations
}

InfiniteScroller.prototype._cleanupUnusedNodes = function (unusedNodes) {
  while (unusedNodes.length) {
    this.scrollerEl.removeChild(unusedNodes.pop())
  }
}

InfiniteScroller.prototype._cacheNodeSize = function () {
  for (let i = this.firstAttachedItem; i < this.lastAttachedItem; i++) {
    // Only cache the height if we have the real contents, not a placeholder.
    if (this.items[i].data && !this.items[i].height) {
      this.items[i].height = this.items[i].node.offsetHeight
      this.items[i].width = this.items[i].node.offsetWidth
    }
  }
}

InfiniteScroller.prototype._fixScrollPosition = function () {
  this.anchorScrollTop = 0
  for (let i = 0; i < this.anchorItem.index; i++) {
    this.anchorScrollTop += this.items[i].height || this.tombstoneHeight
  }
  this.anchorScrollTop += this.anchorItem.offset

  // Position all nodes.
  let curPos = this.anchorScrollTop - this.anchorItem.offset
  let i = this.anchorItem.index
  while (i > this.firstAttachedItem) {
    curPos -= this.items[i - 1].height || this.tombstoneHeight
    i--
  }

  return curPos
}

InfiniteScroller.prototype._setupAnimations = function (tombstoneAnimations, curPos) {
  for (let i in tombstoneAnimations) {
    const animation = tombstoneAnimations[i]
    this.items[i].node.style.transform = `translateY(${this.anchorScrollTop + animation[1]}px) scale(${this.tombstoneWidth / this.items[i].width}, ${this.tombstoneHeight / this.items[i].height})`
    // Call offsetTop on the nodes to be animated to force them to apply current transforms.
    /* eslint-disable no-unused-expressions */
    this.items[i].node.offsetTop
    animation[0].offsetTop
    this.items[i].node.style.transition = `transform ${ANIMATION_DURATION_MS}ms`
  }

  for (let i = this.firstAttachedItem; i < this.lastAttachedItem; i++) {
    const animation = tombstoneAnimations[i]
    if (animation) {
      const tombstoneNode = animation[0]
      tombstoneNode.style.transition = `transform ${ANIMATION_DURATION_MS}ms, opacity ${ANIMATION_DURATION_MS}ms`
      tombstoneNode.style.transform = `translateY(${curPos}px) scale(${this.items[i].width / this.tombstoneWidth}, ${this.items[i].height / this.tombstoneHeight})`
      tombstoneNode.style.opacity = 0
    }
    if (curPos !== this.items[i].top) {
      if (!animation) {
        this.items[i].node.style.transition = ''
      }
      this.items[i].node.style.transform = `translateY(${curPos}px)`
    }
    this.items[i].top = curPos
    curPos += this.items[i].height || this.tombstoneHeight
  }

  this.scroller.maxScrollY = -(curPos - this.wrapperEl.offsetHeight + (this.hasMore ? DEFAULT_SCROLL_RUNWAY : 0))

  setTimeout(() => {
    for (let i in tombstoneAnimations) {
      const animation = tombstoneAnimations[i]
      animation[0].style.display = 'none'
      // Tombstone can be recycled now.
      this.tombstones.push(animation[0])
    }
  }, ANIMATION_DURATION_MS)
}

InfiniteScroller.prototype._getTombStone = function () {
  let tombstone = this.tombstones.pop()
  if (tombstone) {
    tombstone.style.display = ''
    tombstone.style.opacity = 1
    tombstone.style.transform = ''
    tombstone.style.transition = ''
    return tombstone
  }
  return this.options.createTombstone()
}

InfiniteScroller.prototype._addItem = function () {
  this.items.push({
    data: null,
    node: null,
    height: 0,
    width: 0,
    top: 0
  })
}

InfiniteScroller.prototype._calculateAnchoredItem = function (initialAnchor, delta) {
  if (delta === 0) {
    return initialAnchor
  }
  let i = initialAnchor.index
  let tombstones = 0

  delta += initialAnchor.offset
  if (delta < 0) {
    while (delta < 0 && i > 0 && this.items[i - 1].height) {
      delta += this.items[i - 1].height
      i--
    }
    tombstones = Math.max(-i, Math.ceil(Math.min(delta, 0) / this.tombstoneHeight))
  } else {
    while (delta > 0 && i < this.items.length && this.items[i].height && this.items[i].height < delta) {
      delta -= this.items[i].height
      i++
    }
    if (i >= this.items.length || !this.items[i].height) {
      tombstones = Math.floor(Math.max(delta, 0) / this.tombstoneHeight)
    }
  }
  i += tombstones
  delta -= tombstones * this.tombstoneHeight

  return {
    index: i,
    offset: delta
  }
}
<|endoftext|>


<commit_before>( function ( root, factory ) {

    var parentName = 'OMHWebVisualizations';
    root[ parentName ] = factory( root, parentName );

}( this, function ( root, parentName ) {

    var parent = root.hasOwnProperty( parentName ) ? root[ parentName ] : {};

    parent.ChartConfiguration = function ( settings ) {

        var mergedSettings;
        var measureNames;

        var defaultSettings = {
            'userInterface': {
                'toolbar': { 'enabled': true },
                'timespanButtons': { 'enabled': true },
                'zoomButtons': { 'enabled': true },
                'navigation': { 'enabled': true },
                'thresholds': { 'show': true },
                'tooltips': {
                    'enabled': true,
                    'timeFormat': 'M/D/YY, h:mma',
                    'decimalPlaces': 0,
                    'contentFormatter': parent.ChartStyles.formatters.defaultTooltip,
                    'grouped': true
                },
                'panZoom': {
                    'enabled': true,
                    'showHint': true
                },
                'axes': {
                    'yAxis': {
                        'visible': true
                    },
                    'xAxis': {
                        'visible': true
                    }
                }
            },
            'measures': {
                'body_weight': {
                    'valueKeyPath': 'body.body_weight.value',
                    'range': { 'min': 0, 'max': 100 },
                    'units': 'kg',
                    'thresholds': { 'max': 57 }
                },
                'heart_rate': {
                    'valueKeyPath': 'body.heart_rate.value',
                    'range': { 'min': 30, 'max': 150 },
                    'units': 'bpm'
                },
                'step_count': {
                    'valueKeyPath': 'body.step_count',
                    'range': { 'min': 0, 'max': 1500 },
                    'units': 'Steps',
                    'seriesName': 'Steps',
                    'timeQuantizationLevel': parent.DataParser.QUANTIZE_DAY,
                    'quantizedDataConsolidationFunction': parent.DataParser.consolidators.summation,
                    'chart': {
                        'type': 'clustered_bar',
                        'barColor': '#eeeeee',
                        'daysShownOnTimeline': { 'min': 7, 'max': 90 }
                    }
                },
                'minutes_moderate_activity': {
                    'valueKeyPath': 'body.minutes_moderate_activity.value',
                    'range': { 'min': 0, 'max': 300 },
                    'units': 'Minutes',
                    'seriesName': 'Minutes of moderate activity',
                    'timeQuantizationLevel': parent.DataParser.QUANTIZE_DAY,
                    'quantizedDataConsolidationFunction': parent.DataParser.consolidators.summation,
                    'chart': {
                        'type': 'clustered_bar',
                        'daysShownOnTimeline': { 'min': 7, 'max': 90 }
                    }
                },
                'systolic_blood_pressure': {
                    'valueKeyPath': 'body.systolic_blood_pressure.value',
                    'range': { 'min': 30, 'max': 200 },
                    'units': 'mmHg',
                    'thresholds': { 'max': 120 }
                },
                'diastolic_blood_pressure': {
                    'valueKeyPath': 'body.diastolic_blood_pressure.value',
                    'range': { 'min': 30, 'max': 200 },
                    'units': 'mmHg',
                    'thresholds': { 'max': 80 }
                }
            }
        };

        var genericMeasureDefaults = {
            'range': { 'min': 0, 'max': 100 },
            'units': 'Units',
            'seriesName': 'Series',
            'timeQuantizationLevel': parent.DataParser.QUANTIZE_NONE,
            'quantizedDataConsolidationFunction': parent.DataParser.consolidators.average,
            'chart': {
                'type': 'line',
                'pointSize': 9,
                'lineColor': '#dedede',
                'pointFillColor': '#4a90e2',
                'pointStrokeColor': '#0066d6',
                'aboveThresholdPointFillColor': '#e8ac4e',
                'aboveThresholdPointStrokeColor': '#745628',
                'barColor': '#4a90e2',
                'daysShownOnTimeline': { 'min': 1, 'max': 1000 }
            }
        };

        /**
         *
         * Initialization
         *
         * */
        var initialize = function () {

            mergedSettings = parent.Utils.mergeObjects( defaultSettings, settings );
            measureNames = Object.keys( mergedSettings.measures );

            measureNames.forEach( function ( measure ) {
                mergedSettings.measures[ measure ] = parent.Utils.mergeObjects( genericMeasureDefaults, mergedSettings.measures[ measure ] );
            } );

        };

        this.getMeasureSettings = function ( measure ) {
            return mergedSettings.measures[ measure ];
        };

        this.getInterfaceSettings = function () {
            return mergedSettings.userInterface;
        };

        /**
         *
         * Initialize the object
         *
         * */

        initialize.call( this );

    };

    return parent;

} ) );

<commit_msg>Bind formatter to config object to access decimal places<commit_after>( function ( root, factory ) {

    var parentName = 'OMHWebVisualizations';
    root[ parentName ] = factory( root, parentName );

}( this, function ( root, parentName ) {

    var parent = root.hasOwnProperty( parentName ) ? root[ parentName ] : {};

    parent.ChartConfiguration = function ( settings ) {

        var mergedSettings;
        var measureNames;

        var defaultSettings = {
            'userInterface': {
                'toolbar': { 'enabled': true },
                'timespanButtons': { 'enabled': true },
                'zoomButtons': { 'enabled': true },
                'navigation': { 'enabled': true },
                'thresholds': { 'show': true },
                'tooltips': {
                    'enabled': true,
                    'timeFormat': 'M/D/YY, h:mma',
                    'decimalPlaces': 0,
                    'contentFormatter': parent.ChartStyles.formatters.defaultTooltip.bind( this ),
                    'grouped': true
                },
                'panZoom': {
                    'enabled': true,
                    'showHint': true
                },
                'axes': {
                    'yAxis': {
                        'visible': true
                    },
                    'xAxis': {
                        'visible': true
                    }
                }
            },
            'measures': {
                'body_weight': {
                    'valueKeyPath': 'body.body_weight.value',
                    'range': { 'min': 0, 'max': 100 },
                    'units': 'kg',
                    'thresholds': { 'max': 57 }
                },
                'heart_rate': {
                    'valueKeyPath': 'body.heart_rate.value',
                    'range': { 'min': 30, 'max': 150 },
                    'units': 'bpm'
                },
                'step_count': {
                    'valueKeyPath': 'body.step_count',
                    'range': { 'min': 0, 'max': 1500 },
                    'units': 'Steps',
                    'seriesName': 'Steps',
                    'timeQuantizationLevel': parent.DataParser.QUANTIZE_DAY,
                    'quantizedDataConsolidationFunction': parent.DataParser.consolidators.summation,
                    'chart': {
                        'type': 'clustered_bar',
                        'barColor': '#eeeeee',
                        'daysShownOnTimeline': { 'min': 7, 'max': 90 }
                    }
                },
                'minutes_moderate_activity': {
                    'valueKeyPath': 'body.minutes_moderate_activity.value',
                    'range': { 'min': 0, 'max': 300 },
                    'units': 'Minutes',
                    'seriesName': 'Minutes of moderate activity',
                    'timeQuantizationLevel': parent.DataParser.QUANTIZE_DAY,
                    'quantizedDataConsolidationFunction': parent.DataParser.consolidators.summation,
                    'chart': {
                        'type': 'clustered_bar',
                        'daysShownOnTimeline': { 'min': 7, 'max': 90 }
                    }
                },
                'systolic_blood_pressure': {
                    'valueKeyPath': 'body.systolic_blood_pressure.value',
                    'range': { 'min': 30, 'max': 200 },
                    'units': 'mmHg',
                    'thresholds': { 'max': 120 }
                },
                'diastolic_blood_pressure': {
                    'valueKeyPath': 'body.diastolic_blood_pressure.value',
                    'range': { 'min': 30, 'max': 200 },
                    'units': 'mmHg',
                    'thresholds': { 'max': 80 }
                }
            }
        };

        var genericMeasureDefaults = {
            'range': { 'min': 0, 'max': 100 },
            'units': 'Units',
            'seriesName': 'Series',
            'timeQuantizationLevel': parent.DataParser.QUANTIZE_NONE,
            'quantizedDataConsolidationFunction': parent.DataParser.consolidators.average,
            'chart': {
                'type': 'line',
                'pointSize': 9,
                'lineColor': '#dedede',
                'pointFillColor': '#4a90e2',
                'pointStrokeColor': '#0066d6',
                'aboveThresholdPointFillColor': '#e8ac4e',
                'aboveThresholdPointStrokeColor': '#745628',
                'barColor': '#4a90e2',
                'daysShownOnTimeline': { 'min': 1, 'max': 1000 }
            }
        };

        /**
         *
         * Initialization
         *
         * */
        var initialize = function () {

            mergedSettings = parent.Utils.mergeObjects( defaultSettings, settings );
            measureNames = Object.keys( mergedSettings.measures );

            measureNames.forEach( function ( measure ) {
                mergedSettings.measures[ measure ] = parent.Utils.mergeObjects( genericMeasureDefaults, mergedSettings.measures[ measure ] );
            } );

        };

        this.getMeasureSettings = function ( measure ) {
            return mergedSettings.measures[ measure ];
        };

        this.getInterfaceSettings = function () {
            return mergedSettings.userInterface;
        };

        /**
         *
         * Initialize the object
         *
         * */

        initialize.call( this );

    };

    return parent;

} ) );

<|endoftext|>


<commit_before>// PLUGIN: Subtitle

(function ( Popcorn ) {

  var scriptLoaded = false,
      i = 0,
      callBack = function( data ) {

        if ( window.google && google.load ) {

          google.load( "language", "1", {
            callback: function() {
              scriptLoaded = true;
            }
          });
        } else {

          setTimeout( function() {

            callBack( data );
          }, 1);
        }
      },
      createDefaultContainer = function( context ) {

        // clear this function from future calls; we are done
        createDefaultContainer = Popcorn.nop;

        var updatePosition = function() {

          // the video element must have height and width defined
          style.fontSize = "18px";
          style.width = media.offsetWidth + "px";
          style.top = position.top  + media.offsetHeight - ctxContainer.offsetHeight - 40 + "px";
          style.left = position.left + "px";

          setTimeout( updatePosition, 10 );
        };

        var ctxContainer = context.container = document.createElement( "div" ),
            style = ctxContainer.style,
            position = context.position(),
            media = context.media;

        ctxContainer.id = "subtitlediv";
        style.position = "absolute";
        style.color = "white";
        style.textShadow = "black 2px 2px 6px";
        style.fontWeight = "bold";
        style.textAlign = "center";

        updatePosition();

        document.body.appendChild( ctxContainer );
      };

  Popcorn.getScript( "http://www.google.com/jsapi", callBack );

  /**
   * Subtitle popcorn plug-in
   * Displays a subtitle over the video, or in the target div
   * Options parameter will need a start, and end.
   * Optional parameters are target and text.
   * Start is the time that you want this plug-in to execute
   * End is the time that you want this plug-in to stop executing
   * Target is the id of the document element that the content is
   *  appended to, this target element must exist on the DOM
   * Text is the text of the subtitle you want to display.
   *
   * Language is the expected language the subtitle text is in
   * Languagesrc is the target id of the element that contains
   *  the language value ("en", "fr", etc.) to translate the text into
   *  example:
   *  <select id="language">
   *    <option value="zh" selected="selected">Chinese</option>
   *    <option value="en">English</option>
   *    <option value="fr">French</option>
   *    <option value="de">German</option>
   *    <option value="it">Italian</option>
   *    <option value="ja">Japanese</option>
   *    <option value="ko">Korean</option>
   *    <option value="fa">Persian</option>
   *    <option value="pl">Polish</option>
   *    <option value="pt">Portuguese</option>
   *    <option value="es">Spanish</option>
   *  </select>
   * Accessibilitysrc is the target id of a checkbox element
   *  checked means show all subtitles regardless of language and languagesrc
   *  not checked means only translate if language and languagesrc are different
   *  if no accessibilitysrc exists, default is to display all subtitles regardless
   *
   * @param {Object} options
   *
   * Example:
     var p = Popcorn('#video')
        .subtitle({
          start:            5,                 // seconds, mandatory
          end:              15,                // seconds, mandatory
          text:             'Hellow world',    // optional
          target:           'subtitlediv',     // optional
          language:         'en',              // optional
          languagesrc:      'language',        // optional
          accessibilitysrc: 'accessibility'    // optional
        } )
   *
   */

  // translates whatever is in options.container into selected language
  var translate = function( options, text ) {

    options.selectedLanguage = options.languageSrc.options[ options.languageSrc.selectedIndex ].value;
    google.language.translate( text, "", options.selectedLanguage, function( result ) {

      for( var k = 0, children = options.container.children, len = children.length; k < len; k++ ) {
        if ( children[ k ].style.display === "inline" ) {
          children[ k ].innerHTML = result.translation;
        }
      }

    });
  };

  Popcorn.plugin( "subtitle" , {

      manifest: {
        about: {
          name: "Popcorn Subtitle Plugin",
          version: "0.1",
          author: "Scott Downe",
          website: "http://scottdowne.wordpress.com/"
        },
        options: {
          start: {
            elem: "input",
            type: "text",
            label: "In"
          },
          end: {
            elem: "input",
            type: "text",
            label: "Out"
          },
          target: "subtitle-container",
          text: {
            elem: "input",
            type: "text",
            label: "Text"
          }
        }
      },

      _setup: function( options ) {
        var newdiv = document.createElement( "div" ),
            accessibility = document.getElementById( options.accessibilitysrc );

        newdiv.id = "subtitle-" + i;
        newdiv.style.display = "none";
        i++;

        // Creates a div for all subtitles to use
        ( !this.container && !options.target || options.target === "subtitle-container" ) &&
          createDefaultContainer( this );

        // if a target is specified, use that
        if ( options.target && options.target !== "subtitle-container" ) {
          options.container = document.getElementById( options.target );
        } else {
          // use shared default container
          options.container = this.container;
        }

        document.getElementById( options.container.id ).appendChild( newdiv );
        options.innerContainer = newdiv;

        options.showSubtitle = function() {
          options.innerContainer.innerHTML = options.text;
        };
        options.toggleSubtitles = function() {};

        var readyCheck = setInterval(function() {
          if ( !scriptLoaded ) {
            return;
          }
          clearInterval( readyCheck );

          if ( options.languagesrc ) {
            options.showSubtitle = translate;
            options.languageSrc = document.getElementById( options.languagesrc );
            options.selectedLanguage = options.languageSrc.options[ options.languageSrc.selectedIndex ].value;

            if ( !this.languageSources ) {
              this.languageSources = {};
            }

            if ( !this.languageSources[ options.languagesrc ] ) {
              this.languageSources[ options.languagesrc ] = {};
            }

            if ( !this.languageSources[ options.languagesrc ][ options.target ] ) {
              this.languageSources[ options.languagesrc ][ options.target ] = true;

              options.languageSrc.addEventListener( "change", function() {

                options.toggleSubtitles();

                for( var k = 0, children = options.container.children, len = children.length; k < len; k++ ) {
                  if ( children[ k ].style.display === "inline" ) {
                    options.showSubtitle( options, children[ k ].innerHTML );
                  }
                }

              }, false );

            }

          }
          if ( accessibility ) {
            options.accessibility = accessibility;

            options.toggleSubtitles = function() {
              options.selectedLanguage = options.languageSrc.options[ options.languageSrc.selectedIndex ].value;
            };

            options.accessibility.addEventListener( "change", options.toggleSubtitles, false );

            // initiate it once to set starting state
            options.toggleSubtitles();
          }
        }, 5);

      },
      /**
       * @member subtitle
       * The start function will be executed when the currentTime
       * of the video  reaches the start time provided by the
       * options variable
       */
      start: function( event, options ){
        options.innerContainer.style.display = "inline";
        options.showSubtitle( options, options.text );
      },
      /**
       * @member subtitle
       * The end function will be executed when the currentTime
       * of the video  reaches the end time provided by the
       * options variable
       */
      end: function( event, options ) {
        options.innerContainer.style.display = "none";
        options.innerContainer.innerHTML = "";
      },

      _teardown: function ( options ) {
        options.container.removeChild( options.innerContainer );
      }

  });

})( Popcorn );
<commit_msg>[#565] Fixed positioning error<commit_after>// PLUGIN: Subtitle

(function ( Popcorn ) {

  var scriptLoaded = false,
      i = 0,
      callBack = function( data ) {

        if ( window.google && google.load ) {

          google.load( "language", "1", {
            callback: function() {
              scriptLoaded = true;
            }
          });
        } else {

          setTimeout( function() {

            callBack( data );
          }, 1);
        }
      },
      createDefaultContainer = function( context ) {

        // clear this function from future calls; we are done
        createDefaultContainer = Popcorn.nop;

        var updatePosition = function() {
          var position = context.position();
          // the video element must have height and width defined
          style.fontSize = "18px";
          style.width = media.offsetWidth + "px";
          style.top = position.top  + media.offsetHeight - ctxContainer.offsetHeight - 40 + "px";
          style.left = position.left + "px";

          setTimeout( updatePosition, 10 );
        };

        var ctxContainer = context.container = document.createElement( "div" ),
            style = ctxContainer.style,
            media = context.media;

        ctxContainer.id = "subtitlediv";
        style.position = "absolute";
        style.color = "white";
        style.textShadow = "black 2px 2px 6px";
        style.fontWeight = "bold";
        style.textAlign = "center";

        updatePosition();

        document.body.appendChild( ctxContainer );
      };

  Popcorn.getScript( "http://www.google.com/jsapi", callBack );

  /**
   * Subtitle popcorn plug-in
   * Displays a subtitle over the video, or in the target div
   * Options parameter will need a start, and end.
   * Optional parameters are target and text.
   * Start is the time that you want this plug-in to execute
   * End is the time that you want this plug-in to stop executing
   * Target is the id of the document element that the content is
   *  appended to, this target element must exist on the DOM
   * Text is the text of the subtitle you want to display.
   *
   * Language is the expected language the subtitle text is in
   * Languagesrc is the target id of the element that contains
   *  the language value ("en", "fr", etc.) to translate the text into
   *  example:
   *  <select id="language">
   *    <option value="zh" selected="selected">Chinese</option>
   *    <option value="en">English</option>
   *    <option value="fr">French</option>
   *    <option value="de">German</option>
   *    <option value="it">Italian</option>
   *    <option value="ja">Japanese</option>
   *    <option value="ko">Korean</option>
   *    <option value="fa">Persian</option>
   *    <option value="pl">Polish</option>
   *    <option value="pt">Portuguese</option>
   *    <option value="es">Spanish</option>
   *  </select>
   * Accessibilitysrc is the target id of a checkbox element
   *  checked means show all subtitles regardless of language and languagesrc
   *  not checked means only translate if language and languagesrc are different
   *  if no accessibilitysrc exists, default is to display all subtitles regardless
   *
   * @param {Object} options
   *
   * Example:
     var p = Popcorn('#video')
        .subtitle({
          start:            5,                 // seconds, mandatory
          end:              15,                // seconds, mandatory
          text:             'Hellow world',    // optional
          target:           'subtitlediv',     // optional
          language:         'en',              // optional
          languagesrc:      'language',        // optional
          accessibilitysrc: 'accessibility'    // optional
        } )
   *
   */

  // translates whatever is in options.container into selected language
  var translate = function( options, text ) {

    options.selectedLanguage = options.languageSrc.options[ options.languageSrc.selectedIndex ].value;
    google.language.translate( text, "", options.selectedLanguage, function( result ) {

      for( var k = 0, children = options.container.children, len = children.length; k < len; k++ ) {
        if ( children[ k ].style.display === "inline" ) {
          children[ k ].innerHTML = result.translation;
        }
      }

    });
  };

  Popcorn.plugin( "subtitle" , {

      manifest: {
        about: {
          name: "Popcorn Subtitle Plugin",
          version: "0.1",
          author: "Scott Downe",
          website: "http://scottdowne.wordpress.com/"
        },
        options: {
          start: {
            elem: "input",
            type: "text",
            label: "In"
          },
          end: {
            elem: "input",
            type: "text",
            label: "Out"
          },
          target: "subtitle-container",
          text: {
            elem: "input",
            type: "text",
            label: "Text"
          }
        }
      },

      _setup: function( options ) {
        var newdiv = document.createElement( "div" ),
            accessibility = document.getElementById( options.accessibilitysrc );

        newdiv.id = "subtitle-" + i;
        newdiv.style.display = "none";
        i++;

        // Creates a div for all subtitles to use
        ( !this.container && !options.target || options.target === "subtitle-container" ) &&
          createDefaultContainer( this );

        // if a target is specified, use that
        if ( options.target && options.target !== "subtitle-container" ) {
          options.container = document.getElementById( options.target );
        } else {
          // use shared default container
          options.container = this.container;
        }

        document.getElementById( options.container.id ).appendChild( newdiv );
        options.innerContainer = newdiv;

        options.showSubtitle = function() {
          options.innerContainer.innerHTML = options.text;
        };
        options.toggleSubtitles = function() {};

        var readyCheck = setInterval(function() {
          if ( !scriptLoaded ) {
            return;
          }
          clearInterval( readyCheck );

          if ( options.languagesrc ) {
            options.showSubtitle = translate;
            options.languageSrc = document.getElementById( options.languagesrc );
            options.selectedLanguage = options.languageSrc.options[ options.languageSrc.selectedIndex ].value;

            if ( !this.languageSources ) {
              this.languageSources = {};
            }

            if ( !this.languageSources[ options.languagesrc ] ) {
              this.languageSources[ options.languagesrc ] = {};
            }

            if ( !this.languageSources[ options.languagesrc ][ options.target ] ) {
              this.languageSources[ options.languagesrc ][ options.target ] = true;

              options.languageSrc.addEventListener( "change", function() {

                options.toggleSubtitles();

                for( var k = 0, children = options.container.children, len = children.length; k < len; k++ ) {
                  if ( children[ k ].style.display === "inline" ) {
                    options.showSubtitle( options, children[ k ].innerHTML );
                  }
                }

              }, false );

            }

          }
          if ( accessibility ) {
            options.accessibility = accessibility;

            options.toggleSubtitles = function() {
              options.selectedLanguage = options.languageSrc.options[ options.languageSrc.selectedIndex ].value;
            };

            options.accessibility.addEventListener( "change", options.toggleSubtitles, false );

            // initiate it once to set starting state
            options.toggleSubtitles();
          }
        }, 5);

      },
      /**
       * @member subtitle
       * The start function will be executed when the currentTime
       * of the video  reaches the start time provided by the
       * options variable
       */
      start: function( event, options ){
        options.innerContainer.style.display = "inline";
        options.showSubtitle( options, options.text );
      },
      /**
       * @member subtitle
       * The end function will be executed when the currentTime
       * of the video  reaches the end time provided by the
       * options variable
       */
      end: function( event, options ) {
        options.innerContainer.style.display = "none";
        options.innerContainer.innerHTML = "";
      },

      _teardown: function ( options ) {
        options.container.removeChild( options.innerContainer );
      }

  });

})( Popcorn );
<|endoftext|>


<commit_before>function processMessageNodes(nodes) {
    var reportKeys = {
        sr: [],     //spy report
        cr: [],     //combat report
        rr: [],     //recycle report
        mr: []      //missile report
    };

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var apiElement = node.querySelector(".icon_apikey");
        if (apiElement !== null) {
            var key = apiElement.parentNode.href.replace(/.*?:\/\//g, "");
            var type = key.substring(0, 2);
            if (reportKeys.hasOwnProperty(type)) {
                reportKeys[type].push(key);
            }
        }
    }

    postData({
        endpoint: "keys",
        data: {
            reportKeys: reportKeys
        }
    });
}

function processPlanetNodes(nodes) {
    var planets = [];

    for (var i = 0; i < nodes.length; i++) {
        var planetDiv = nodes[i];
        var planetId = planetDiv.id.replace("planet-", "");
        var planetName = planetDiv.querySelector(".planet-name").innerHTML;
        var planetCoordsRaw = planetDiv.querySelector(".planet-koords").innerHTML;
        var planetCoordsList = planetCoordsRaw.slice(1, -1).split(":");
        planets.push({
            id: planetId,
            name: planetName,
            galaxy: planetCoordsList[0],
            solarSystem: planetCoordsList[1],
            position: planetCoordsList[2]
        });
    }

    executeIfNotCached("planets", planets, function () {
        postData({
            endpoint: "planets",
            data: {
                planets: planets
            }
        });
    });
}

function processResearchNodes(nodes) {
    var researches = [];

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var detailButtonElement = node.querySelector(".detail_button");
        if (detailButtonElement !== null) {
            var researchId = detailButtonElement.getAttribute("ref");
            var cloneLevelNode = detailButtonElement.querySelector(".level").cloneNode(true);
            var children = [].slice.call(cloneLevelNode.children);

            for (var j = 0; j < children.length; j++) {
                var child = children[j];
                if (child.className === "textlabel" || child.className === "undermark") {
                    cloneLevelNode.removeChild(child);
                }
            }
            var researchLevel = cloneLevelNode.innerHTML.trim();

            researches.push({
                id: researchId,
                level: researchLevel
            });
        }
    }

    executeIfNotCached("researches", researches, function () {
        postData({
            endpoint: "researches",
            data: {
                researches: researches
            }
        });
    });
}

function processResourceBuildingNodes(nodes) {
    var buildings = [];

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var detailButtonElement = node.querySelector("[id='details']");
        if (detailButtonElement !== null) {
            var buildingId = detailButtonElement.getAttribute("ref");
            var cloneLevelNode = detailButtonElement.querySelector(".level").cloneNode(true);
            var children = [].slice.call(cloneLevelNode.children);

            for (var j = 0; j < children.length; j++) {
                var child = children[j];
                if (child.className === "textlabel" || child.className === "undermark") {
                    cloneLevelNode.removeChild(child);
                }
            }
            var buildingLevel = cloneLevelNode.innerHTML.trim();

            buildings.push({
                id: buildingId,
                level: buildingLevel
            });
        }
    }

    executeIfNotCached("resource_buildings", buildings, function () {
        var data = {
            buildings: buildings
        }
        addPlanetData(data);
        postData({
            endpoint: "resourceBuildings",
            data: data
        });
    });
}

function processFacilityBuildingNodes(nodes) {
    var buildings = [];

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var detailButtonElement = node.querySelector(".detail_button");
        if (detailButtonElement !== null) {
            var buildingId = detailButtonElement.getAttribute("ref");
            var cloneLevelNode = detailButtonElement.querySelector(".level").cloneNode(true);
            var children = [].slice.call(cloneLevelNode.children);

            for (var j = 0; j < children.length; j++) {
                var child = children[j];
                if (child.className === "textlabel" || child.className === "undermark") {
                    cloneLevelNode.removeChild(child);
                }
            }
            var buildingLevel = cloneLevelNode.innerHTML.trim();

            buildings.push({
                id: buildingId,
                level: buildingLevel
            });
        }
    }

    executeIfNotCached("facility_buildings", buildings, function () {
        var data = {
            buildings: buildings
        }
        addPlanetData(data);
        postData({
            endpoint: "facilityBuildings",
            data: data
        });
    });
}

function processDefenceNodes(nodes) {
    var defences = [];

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var detailButtonElement = node.querySelector(".detail_button");
        if (detailButtonElement !== null) {
            var buildingId = detailButtonElement.getAttribute("ref");
            var cloneLevelNode = detailButtonElement.querySelector(".level").cloneNode(true);
            var children = [].slice.call(cloneLevelNode.children);

            for (var j = 0; j < children.length; j++) {
                var child = children[j];
                if (child.className === "textlabel" || child.className === "undermark") {
                    cloneLevelNode.removeChild(child);
                }
            }
            var defenceLevel = cloneLevelNode.innerHTML.trim();

            defences.push({
                id: buildingId,
                level: defenceLevel
            });
        }
    }

    executeIfNotCached("defences", defences, function () {
        var data = {
            defences: defences
        }
        addPlanetData(data);
        postData({
            endpoint: "defences",
            data: data
        });
    });
}

function postData(object) {
    addPlayerData(object.data);
    console.log(JSON.stringify(object.data));
    GM_xmlhttpRequest({
        method: "POST",
        url: oLogInstanceUrl + "api/userscript/" + object.endpoint,
        data: JSON.stringify(object.data),
        headers: {
            "Content-Type": "application/json"
        },
        onload: function(response) {
            console.log("load");
        },
        onerror: function(response) {
            console.log("error");
        }
    });
}

function addPlayerData(data) {
    data.serverGroup = getWindowVariable("constants.language");
    data.universe = getWindowVariable("constants.name");
    data.playerId = getWindowVariable("playerId");
    data.playerName = getWindowVariable("playerName");
}

function addPlanetData(data) {
    data.planetId = getMetaValue("ogame-planet-id");
    data.planetName = getMetaValue("ogame-planet-name");
    var coordinate = getMetaValue("ogame-planet-coordinates").split(":");
    data.planetGalaxy = coordinate[0];
    data.planetSolarSystem = coordinate[1];
    data.planetPosition = coordinate[2];
}

/**
 * Returns a global variable.
 *
 * Needed because a @grant other than none puts the script
 * in a separate scope.
 *
 * @param {string} name The name of the global variable.
 */
function getWindowVariable(name) {
    return window.eval(name);
}

function getMetaValue(name) {
    return document.querySelector("meta[name='" + name + "']").content;
}

function showSuccessMessage(message) {
    getWindowVariable("fadeBox")(message, false);
}

function showErrorMessage(message) {
    getWindowVariable("fadeBox")(message, true);
}

function saveSetting(key, value) {
    GM_setValue(getFullSettingsKey(key), value);
}

function getSetting(key, defaultValue) {
    return GM_getValue(getFullSettingsKey(key), defaultValue);
}

function getFullSettingsKey(key) {
    return getWindowVariable("constants.language") + ":" + getWindowVariable("constants.name") + ":" + getWindowVariable("playerId") + ":" + key;
}

function executeIfNotCached(cacheKey, value, callback) {
    var valueString = JSON.stringify(value);
    var fullCacheKey = getFullCacheKey(cacheKey);
    if (getSetting(fullCacheKey, "") !== valueString) {
        callback();
        saveSetting(fullCacheKey, valueString);
    }
}

function getFullCacheKey(cacheKey) {
    return "cache." + cacheKey;
}<commit_msg>Renamed level parameter of defences to amount.<commit_after>function processMessageNodes(nodes) {
    var reportKeys = {
        sr: [],     //spy report
        cr: [],     //combat report
        rr: [],     //recycle report
        mr: []      //missile report
    };

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var apiElement = node.querySelector(".icon_apikey");
        if (apiElement !== null) {
            var key = apiElement.parentNode.href.replace(/.*?:\/\//g, "");
            var type = key.substring(0, 2);
            if (reportKeys.hasOwnProperty(type)) {
                reportKeys[type].push(key);
            }
        }
    }

    postData({
        endpoint: "keys",
        data: {
            reportKeys: reportKeys
        }
    });
}

function processPlanetNodes(nodes) {
    var planets = [];

    for (var i = 0; i < nodes.length; i++) {
        var planetDiv = nodes[i];
        var planetId = planetDiv.id.replace("planet-", "");
        var planetName = planetDiv.querySelector(".planet-name").innerHTML;
        var planetCoordsRaw = planetDiv.querySelector(".planet-koords").innerHTML;
        var planetCoordsList = planetCoordsRaw.slice(1, -1).split(":");
        planets.push({
            id: planetId,
            name: planetName,
            galaxy: planetCoordsList[0],
            solarSystem: planetCoordsList[1],
            position: planetCoordsList[2]
        });
    }

    executeIfNotCached("planets", planets, function () {
        postData({
            endpoint: "planets",
            data: {
                planets: planets
            }
        });
    });
}

function processResearchNodes(nodes) {
    var researches = [];

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var detailButtonElement = node.querySelector(".detail_button");
        if (detailButtonElement !== null) {
            var researchId = detailButtonElement.getAttribute("ref");
            var cloneLevelNode = detailButtonElement.querySelector(".level").cloneNode(true);
            var children = [].slice.call(cloneLevelNode.children);

            for (var j = 0; j < children.length; j++) {
                var child = children[j];
                if (child.className === "textlabel" || child.className === "undermark") {
                    cloneLevelNode.removeChild(child);
                }
            }
            var researchLevel = cloneLevelNode.innerHTML.trim();

            researches.push({
                id: researchId,
                level: researchLevel
            });
        }
    }

    executeIfNotCached("researches", researches, function () {
        postData({
            endpoint: "researches",
            data: {
                researches: researches
            }
        });
    });
}

function processResourceBuildingNodes(nodes) {
    var buildings = [];

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var detailButtonElement = node.querySelector("[id='details']");
        if (detailButtonElement !== null) {
            var buildingId = detailButtonElement.getAttribute("ref");
            var cloneLevelNode = detailButtonElement.querySelector(".level").cloneNode(true);
            var children = [].slice.call(cloneLevelNode.children);

            for (var j = 0; j < children.length; j++) {
                var child = children[j];
                if (child.className === "textlabel" || child.className === "undermark") {
                    cloneLevelNode.removeChild(child);
                }
            }
            var buildingLevel = cloneLevelNode.innerHTML.trim();

            buildings.push({
                id: buildingId,
                level: buildingLevel
            });
        }
    }

    executeIfNotCached("resource_buildings", buildings, function () {
        var data = {
            buildings: buildings
        }
        addPlanetData(data);
        postData({
            endpoint: "resourceBuildings",
            data: data
        });
    });
}

function processFacilityBuildingNodes(nodes) {
    var buildings = [];

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var detailButtonElement = node.querySelector(".detail_button");
        if (detailButtonElement !== null) {
            var buildingId = detailButtonElement.getAttribute("ref");
            var cloneLevelNode = detailButtonElement.querySelector(".level").cloneNode(true);
            var children = [].slice.call(cloneLevelNode.children);

            for (var j = 0; j < children.length; j++) {
                var child = children[j];
                if (child.className === "textlabel" || child.className === "undermark") {
                    cloneLevelNode.removeChild(child);
                }
            }
            var buildingLevel = cloneLevelNode.innerHTML.trim();

            buildings.push({
                id: buildingId,
                level: buildingLevel
            });
        }
    }

    executeIfNotCached("facility_buildings", buildings, function () {
        var data = {
            buildings: buildings
        }
        addPlanetData(data);
        postData({
            endpoint: "facilityBuildings",
            data: data
        });
    });
}

function processDefenceNodes(nodes) {
    var defences = [];

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var detailButtonElement = node.querySelector(".detail_button");
        if (detailButtonElement !== null) {
            var buildingId = detailButtonElement.getAttribute("ref");
            var cloneLevelNode = detailButtonElement.querySelector(".level").cloneNode(true);
            var children = [].slice.call(cloneLevelNode.children);

            for (var j = 0; j < children.length; j++) {
                var child = children[j];
                if (child.className === "textlabel" || child.className === "undermark") {
                    cloneLevelNode.removeChild(child);
                }
            }
            var defenceAmount = cloneLevelNode.innerHTML.trim();

            defences.push({
                id: buildingId,
                amount: defenceAmount
            });
        }
    }

    executeIfNotCached("defences", defences, function () {
        var data = {
            defences: defences
        }
        addPlanetData(data);
        postData({
            endpoint: "defences",
            data: data
        });
    });
}

function postData(object) {
    addPlayerData(object.data);
    console.log(JSON.stringify(object.data));
    GM_xmlhttpRequest({
        method: "POST",
        url: oLogInstanceUrl + "api/userscript/" + object.endpoint,
        data: JSON.stringify(object.data),
        headers: {
            "Content-Type": "application/json"
        },
        onload: function(response) {
            console.log("load");
        },
        onerror: function(response) {
            console.log("error");
        }
    });
}

function addPlayerData(data) {
    data.serverGroup = getWindowVariable("constants.language");
    data.universe = getWindowVariable("constants.name");
    data.playerId = getWindowVariable("playerId");
    data.playerName = getWindowVariable("playerName");
}

function addPlanetData(data) {
    data.planetId = getMetaValue("ogame-planet-id");
    data.planetName = getMetaValue("ogame-planet-name");
    var coordinate = getMetaValue("ogame-planet-coordinates").split(":");
    data.planetGalaxy = coordinate[0];
    data.planetSolarSystem = coordinate[1];
    data.planetPosition = coordinate[2];
}

/**
 * Returns a global variable.
 *
 * Needed because a @grant other than none puts the script
 * in a separate scope.
 *
 * @param {string} name The name of the global variable.
 */
function getWindowVariable(name) {
    return window.eval(name);
}

function getMetaValue(name) {
    return document.querySelector("meta[name='" + name + "']").content;
}

function showSuccessMessage(message) {
    getWindowVariable("fadeBox")(message, false);
}

function showErrorMessage(message) {
    getWindowVariable("fadeBox")(message, true);
}

function saveSetting(key, value) {
    GM_setValue(getFullSettingsKey(key), value);
}

function getSetting(key, defaultValue) {
    return GM_getValue(getFullSettingsKey(key), defaultValue);
}

function getFullSettingsKey(key) {
    return getWindowVariable("constants.language") + ":" + getWindowVariable("constants.name") + ":" + getWindowVariable("playerId") + ":" + key;
}

function executeIfNotCached(cacheKey, value, callback) {
    var valueString = JSON.stringify(value);
    var fullCacheKey = getFullCacheKey(cacheKey);
    if (getSetting(fullCacheKey, "") !== valueString) {
        callback();
        saveSetting(fullCacheKey, valueString);
    }
}

function getFullCacheKey(cacheKey) {
    return "cache." + cacheKey;
}<|endoftext|>


<commit_before>$(document).ready(function() {
	//--- check if presed enter ---
	$.fn.pressEnter = function(fn) {
		return this.each(function() {
			$(this).bind('enterPress', fn);
			$(this).keyup(function(e) {
				if(e.keyCode == 13) {
					$(this).trigger("enterPress");
				}
			})
		});
	};

	//---reload a image
	$.fn.reloadimg = function(fn) {
		return this.each(function(index) {
			var src = $(this).attr('src');
			$(this).attr('src', src);
			console.log("reload image:\nimg="+index+"\nsrc='"+src+"'");
		});
	};
});

//--- function basename (like PHP) ---
function basename(path) {
	var b = path;
	var lastChar = b.charAt(b.length - 1);
	if (lastChar === '/' || lastChar === '\\') {
		b = b.slice(0, -1);
	}
	b = b.replace(/^.*[\/\\]/g, '');
	return b;
}

//--- function empty (like PHP) ---
function empty(str) {
    return (!str || 0 === str.length);
}

//--- emailpattern ---
var emailpattern = new RegExp('^([a-zA-Z0-9\\-\\.\\_]+)(\\@)([a-zA-Z0-9\\-\\.]+)(\\.)([a-zA-Z]{2,4})$');

//--- Scroll to place ---
$(document).ready(function() {
	$("a[href^='#']").click(function(event) {
		event.preventDefault();
		var target = $(this).attr('href');
		$('html,body').animate({
			scrollTop: $(target).offset().top
		}, 1000);
		console.log("Scroll to "+target);
	});
});
function scrollto(place, valuetype) {
	if(typeof valuetype == "undefined") {
		var valuetype = object;
	}
	if(valuetype == "position") {
		$('html,body').animate({
			scrollTop: place^
		}, 1000);
		return false;
	}
	if(valuetype == "object") {
		$('html,body').animate({
			scrollTop: $(place).offset().top
		}, 1000);
		return false;
	}
}

//--- images first show after load --------------------------------------------
var images_show_after_laod = true;
$(document).ready(function() {
	if(images_show_after_laod) {
		$('img').each(function(){
			if(!$(this).hasClass("nojsload")) {
				$(this).hide();
				$(this).load(function() {
					$(this).fadeIn(400);
				});
			}
		})
	}
});<commit_msg>fixes<commit_after>$(document).ready(function() {
	//--- check if presed enter ---
	$.fn.pressEnter = function(fn) {
		return this.each(function() {
			$(this).bind('enterPress', fn);
			$(this).keyup(function(e) {
				if(e.keyCode == 13) {
					$(this).trigger("enterPress");
				}
			})
		});
	};

	//---reload a image
	$.fn.reloadimg = function(fn) {
		return this.each(function(index) {
			var src = $(this).attr('src');
			$(this).attr('src', src);
			console.log("reload image:\nimg="+index+"\nsrc='"+src+"'");
		});
	};
});

//--- function basename (like PHP) ---
function basename(path) {
	var b = path;
	var lastChar = b.charAt(b.length - 1);
	if (lastChar === '/' || lastChar === '\\') {
		b = b.slice(0, -1);
	}
	b = b.replace(/^.*[\/\\]/g, '');
	return b;
}

//--- function empty (like PHP) ---
function empty(str) {
    return (!str || 0 === str.length);
}

//--- emailpattern ---
var emailpattern = new RegExp('^([a-zA-Z0-9\\-\\.\\_]+)(\\@)([a-zA-Z0-9\\-\\.]+)(\\.)([a-zA-Z]{2,4})$');

//--- Scroll to place ---
$(document).ready(function() {
	$("a[href^='#']").click(function(event) {
		event.preventDefault();
		var target = $(this).attr('href');
		$('html,body').animate({
			scrollTop: $(target).offset().top
		}, 1000);
		console.log("Scroll to "+target);
	});
});
function scrollto(place, valuetype) {
	if(typeof valuetype == "undefined") {
		var valuetype = object;
	}
	if(valuetype == "position") {
		$('html,body').animate({
			scrollTop: place
		}, 1000);
		return false;
	}
	if(valuetype == "object") {
		$('html,body').animate({
			scrollTop: $(place).offset().top
		}, 1000);
		return false;
	}
}

//--- images first show after load --------------------------------------------
var images_show_after_laod = true;
$(document).ready(function() {
	if(images_show_after_laod) {
		$('img').each(function(){
			if(!$(this).hasClass("nojsload")) {
				$(this).hide();
				$(this).load(function() {
					$(this).fadeIn(400);
				});
			}
		})
	}
});<|endoftext|>


<commit_before>/* eslint global-require: 0 */

const {
  FuseBox, BabelPlugin, PostCSS, CSSPlugin, RawPlugin,
  SassPlugin, HTMLPlugin, UglifyJSPlugin, EnvPlugin
} = require('fuse-box');

const POST_CSS_PLUGINS = [
  require('postcss-transform-shortcut'),
  require('autoprefixer')('last 2 versions')
];

// Create FuseBox Instance
const fuse = new FuseBox({
  homeDir: 'app/',
  outFile: './dist/bundle.js',
  sourceMaps: false,
  plugins: [
    [
      SassPlugin(),
      PostCSS(POST_CSS_PLUGINS),
      CSSPlugin({ minify: false })
    ],

    RawPlugin(['.html']),
    HTMLPlugin({ useDefault: true }),

    EnvPlugin({ NODE_ENV: process.env.NODE_ENV }),
    BabelPlugin({
      test: /\.js$/, // test is optional
      config: {
        presets: ['es2015', 'stage-2']
      },
    }),
    UglifyJSPlugin({
      compress: {
        warnings: false
      }
    })
  ],
  shim: {
    jquery: {
      exports: 'jQuery',
    },
    angular: {
      exports: 'angular'
    },
    firebase: {
      exports: 'firebase'
    },
    moment: {
      exports: 'moment'
    }
  }
});

fuse.bundle('>index.js');
<commit_msg>minify css for dist bundle<commit_after>/* eslint global-require: 0 */

const {
  FuseBox, BabelPlugin, PostCSS, CSSPlugin, RawPlugin,
  SassPlugin, HTMLPlugin, UglifyJSPlugin, EnvPlugin
} = require('fuse-box');

const POST_CSS_PLUGINS = [
  require('postcss-transform-shortcut'),
  require('autoprefixer')('last 2 versions')
];

// Create FuseBox Instance
const fuse = new FuseBox({
  homeDir: 'app/',
  outFile: './dist/bundle.js',
  sourceMaps: false,
  plugins: [
    [
      SassPlugin(),
      PostCSS(POST_CSS_PLUGINS),
      CSSPlugin({ minify: true })
    ],

    RawPlugin(['.html']),
    HTMLPlugin({ useDefault: true }),

    EnvPlugin({ NODE_ENV: process.env.NODE_ENV }),
    BabelPlugin({
      test: /\.js$/, // test is optional
      config: {
        presets: ['es2015', 'stage-2']
      },
    }),
    UglifyJSPlugin({
      compress: {
        warnings: false
      }
    })
  ],
  shim: {
    jquery: {
      exports: 'jQuery',
    },
    angular: {
      exports: 'angular'
    },
    firebase: {
      exports: 'firebase'
    },
    moment: {
      exports: 'moment'
    }
  }
});

fuse.bundle('>index.js');
<|endoftext|>