<commit_before>/** @jsx createElement */
import { Component, createElement, render, nextTick } from '../src'
import { rerender } from '../src/render-queue'
import sinon from 'sinon'

// @TODO: figure out why run component.spec before event.spec will occurs error
describe('Events', () => {
  let scratch
  beforeAll(() => {
    scratch = document.createElement('div')
    document.body.appendChild(scratch)
  })

  beforeEach(() => {
    scratch.innerHTML = ''
    const { addEventListener, removeEventListener } = document.constructor.prototype
    if (addEventListener.restore) {
      addEventListener.restore()
    }
    if (removeEventListener.restore) {
      removeEventListener.restore()
    }
  })

  afterAll(() => {
    scratch.parentNode.removeChild(scratch)
    scratch = null
  })

  it('should only register on* functions as handlers', () => {
    const click = () => { }
    const onclick = () => { }

    let doRender = null
    const proto = document.constructor.prototype
    const addEventListenerSpy = sinon.spy(proto, 'addEventListener')

    class Outer extends Component {
      constructor () {
        super(...arguments)
        this.state = {
          show: true
        }
      }

      componentDidMount () {
        doRender = () => {
          this.setState({
            show: false
          })
        }
      }

      render () {
        return (
          this.state.show ?
 : null
        )
      }
    }

    render(<Outer />, scratch)

    expect(scratch.childNodes[0].attributes.length.toString()).toMatch(/0|1/) // 1 for ie8
    expect(addEventListenerSpy.calledOnce).toBeTruthy()
    expect(addEventListenerSpy.calledWithExactly('click', sinon.match.func, false)).toBeTruthy()

    addEventListenerSpy.restore()
    doRender()
    rerender()
  })

  it('should add and remove event handlers', () => {
    const click = sinon.spy()
    const mousedown = sinon.spy()

    let doRender = null
    const proto = document.constructor.prototype
    const addEventListenerSpy = sinon.spy(proto, 'addEventListener')
    const removeEventListenerSpy = sinon.spy(proto, 'removeEventListener')

    function fireEvent (on, type) {
      const e = document.createEvent('Event')
      e.initEvent(type, true, true)
      on.dispatchEvent(e)
    }

    class Outer extends Component {
      constructor () {
        super(...arguments)
        this.state = {
          count: 0
        }
        this.clickHandler = () => {
          click(this.state.count)
        }
      }

      componentDidMount () {
        doRender = () => {
          this.setState({
            count: ++this.state.count
          })
        }
      }

      render () {
        return ([

,

,

        ][this.state.count])
      }
    }

    render(<Outer />, scratch)

    expect(addEventListenerSpy.callCount).toBe(2)
    expect(addEventListenerSpy.calledWith('click')).toBeTruthy()
    expect(addEventListenerSpy.calledWith('mousedown')).toBeTruthy()

    fireEvent(scratch.childNodes[0], 'click')
    expect(click.calledOnce).toBeTruthy()
    expect(click.calledWith(0)).toBeTruthy()

    addEventListenerSpy.reset()
    click.reset()
    doRender()
    rerender()

    expect(addEventListenerSpy.called).toBeFalsy()

    expect(removeEventListenerSpy.calledOnce).toBeTruthy()
    expect(removeEventListenerSpy.calledWith('mousedown')).toBeTruthy()

    fireEvent(scratch.childNodes[0], 'click')
    expect(click.calledOnce).toBeTruthy()
    expect(click.calledWith(1)).toBeTruthy()

    fireEvent(scratch.childNodes[0], 'mousedown')
    expect(mousedown.called).toBeFalsy()

    removeEventListenerSpy.reset()
    click.reset()
    mousedown.reset()

    doRender()
    rerender()

    expect(removeEventListenerSpy.calledOnce).toBeTruthy()
    expect(removeEventListenerSpy.calledWith('click')).toBeTruthy()

    fireEvent(scratch.childNodes[0], 'click')
    expect(click.called).toBeFalsy()

    addEventListenerSpy.restore()
    removeEventListenerSpy.restore()
  })

  it('unbubbleEvents should attach to node instaed of document', async () => {
    const focus = sinon.spy()

    let doRender = null

    class Outer extends Component {
      constructor () {
        super(...arguments)
        this.state = {
          count: 0
        }
        this.focusHandler = () => {
          focus(this.state.count)
        }
      }

      componentDidMount () {
        doRender = () => {
          this.setState({
            count: ++this.state.count
          })
        }
      }

      render () {
        return ([
          <input onFocus={this.focusHandler} id='input' />,
          <input onFocus={() => ({})} />
        ][this.state.count])
      }
    }

    render(<Outer />, scratch)
    const input = scratch.childNodes[0]
    const proto = input.constructor.prototype
    const addEventListenerSpy = sinon.spy(proto, 'addEventListener')
    const removeEventListenerSpy = sinon.spy(proto, 'removeEventListener')
    // https://stackoverflow.com/questions/1096436/document-getelementbyidid-focus-is-not-working-for-firefox-or-chrome
    input.focus()
    await nextTick()
    // expect(addEventListenerSpy.called).toBeTruthy(`expect(focus.calledOnce)`)
    addEventListenerSpy.reset()
    focus.reset()
    doRender()
    await nextTick()
    rerender()
    scratch.childNodes[0].focus()
    await nextTick()
    expect(removeEventListenerSpy.called).toBeTruthy()
  })
})
<commit_msg>test: remove event<commit_after>/** @jsx createElement */
import { Component, createElement, render, nextTick } from '../src'
import { rerender } from '../src/render-queue'
import sinon from 'sinon'

// @TODO: figure out why run component.spec before event.spec will occurs error
describe('Events', () => {
  let scratch
  beforeAll(() => {
    scratch = document.createElement('div')
    document.body.appendChild(scratch)
  })

  beforeEach(() => {
    scratch.innerHTML = ''
    const { addEventListener, removeEventListener } = document.constructor.prototype
    if (addEventListener.restore) {
      addEventListener.restore()
    }
    if (removeEventListener.restore) {
      removeEventListener.restore()
    }
  })

  afterAll(() => {
    scratch.parentNode.removeChild(scratch)
    scratch = null
  })

  it('should only register on* functions as handlers', () => {
    const click = () => { }
    const onclick = () => { }

    let doRender = null
    const proto = document.constructor.prototype
    const addEventListenerSpy = sinon.spy(proto, 'addEventListener')

    class Outer extends Component {
      constructor () {
        super(...arguments)
        this.state = {
          show: true
        }
      }

      componentDidMount () {
        doRender = () => {
          this.setState({
            show: false
          })
        }
      }

      render () {
        return (
          this.state.show ?
 : null
        )
      }
    }

    render(<Outer />, scratch)

    expect(scratch.childNodes[0].attributes.length.toString()).toMatch(/0|1/) // 1 for ie8
    expect(addEventListenerSpy.calledOnce).toBeTruthy()
    expect(addEventListenerSpy.calledWithExactly('click', sinon.match.func, false)).toBeTruthy()

    addEventListenerSpy.restore()
    doRender()
    rerender()
  })

  it('should add and remove event handlers', () => {
    const click = sinon.spy()
    const mousedown = sinon.spy()

    let doRender = null
    const proto = document.constructor.prototype
    const addEventListenerSpy = sinon.spy(proto, 'addEventListener')
    const removeEventListenerSpy = sinon.spy(proto, 'removeEventListener')

    function fireEvent (on, type) {
      const e = document.createEvent('Event')
      e.initEvent(type, true, true)
      on.dispatchEvent(e)
    }

    class Outer extends Component {
      constructor () {
        super(...arguments)
        this.state = {
          count: 0
        }
        this.clickHandler = () => {
          click(this.state.count)
        }
      }

      componentDidMount () {
        doRender = () => {
          this.setState({
            count: ++this.state.count
          })
        }
      }

      render () {
        return ([

,

,

        ][this.state.count])
      }
    }

    render(<Outer />, scratch)

    expect(addEventListenerSpy.callCount).toBe(2)
    expect(addEventListenerSpy.calledWith('click')).toBeTruthy()
    expect(addEventListenerSpy.calledWith('mousedown')).toBeTruthy()

    fireEvent(scratch.childNodes[0], 'click')
    expect(click.calledOnce).toBeTruthy()
    expect(click.calledWith(0)).toBeTruthy()

    addEventListenerSpy.reset()
    click.reset()
    doRender()
    rerender()

    expect(addEventListenerSpy.called).toBeFalsy()

    expect(removeEventListenerSpy.calledOnce).toBeTruthy()
    expect(removeEventListenerSpy.calledWith('mousedown')).toBeTruthy()

    fireEvent(scratch.childNodes[0], 'click')
    expect(click.calledOnce).toBeTruthy()
    expect(click.calledWith(1)).toBeTruthy()

    fireEvent(scratch.childNodes[0], 'mousedown')
    expect(mousedown.called).toBeFalsy()

    removeEventListenerSpy.reset()
    click.reset()
    mousedown.reset()

    doRender()
    rerender()

    expect(removeEventListenerSpy.calledOnce).toBeTruthy()
    expect(removeEventListenerSpy.calledWith('click')).toBeTruthy()

    fireEvent(scratch.childNodes[0], 'click')
    expect(click.called).toBeFalsy()

    addEventListenerSpy.restore()
    removeEventListenerSpy.restore()
  })

  it('unbubbleEvents should attach to node instaed of document', async () => {
    const focus = sinon.spy()

    let doRender = null

    class Outer extends Component {
      constructor () {
        super(...arguments)
        this.state = {
          count: 0
        }
        this.focusHandler = () => {
          focus(this.state.count)
        }
      }

      componentDidMount () {
        doRender = () => {
          this.setState({
            count: ++this.state.count
          })
        }
      }

      render () {
        return ([
          <input onFocus={this.focusHandler} id='input' />,
          <input onFocus={() => ({})} />
        ][this.state.count])
      }
    }

    render(<Outer />, scratch)
    const input = scratch.childNodes[0]
    const proto = input.constructor.prototype
    const addEventListenerSpy = sinon.spy(proto, 'addEventListener')
    // const removeEventListenerSpy = sinon.spy(proto, 'removeEventListener')
    // https://stackoverflow.com/questions/1096436/document-getelementbyidid-focus-is-not-working-for-firefox-or-chrome
    input.focus()
    await nextTick()
    // expect(addEventListenerSpy.called).toBeTruthy(`expect(focus.calledOnce)`)
    addEventListenerSpy.reset()
    focus.reset()
    doRender()
    await nextTick()
    rerender()
    scratch.childNodes[0].focus()
    await nextTick()
    // expect(removeEventListenerSpy.called).toBeTruthy()
  })
})
<|endoftext|>


<commit_before>import PNG from 'png-js';
import JPEG from './jpeg';
const request = require('request');

function getImage(body, extension) {
  switch (extension.toLowerCase()) {
    case 'jpg':
    case 'jpeg':
      return new JPEG(body);
    case 'png':
      return new PNG(body);
    default:
      throw new Error(`Image type not supported: ${extension}`);
  }
}

export const fetchImage = src => {
  if (typeof src === 'object') {
    if (src.data && src.format) {
      // Local file given
      return new Promise((resolve, reject) =>
        resolve(getImage(src.data, src.format)),
      );
    }
    throw new Error(
      `Invalid data given for local file: ${JSON.stringify(src)}`,
    );
  }

  const extension = src.split('.').pop();
  return new Promise((resolve, reject) => {
    request(
      {
        url: src,
        method: 'GET',
        encoding: null,
      },
      (error, response, body) => {
        if (error) {
          return reject(error);
        }

        const image = getImage(body, extension);
        return resolve(image);
      },
    );
  });
};
<commit_msg>Check image extension with buffer (#207)<commit_after>import PNG from 'png-js';
import JPEG from './jpeg';
const request = require('request');

function getImage(body, extension) {
  switch (extension.toLowerCase()) {
    case 'jpg':
    case 'jpeg':
      return new JPEG(body);
    case 'png':
      return new PNG(body);
    default:
      throw new Error(`Image type not supported: ${extension}`);
  }
}

export const fetchImage = src => {
  if (typeof src === 'object') {
    if (src.data && src.format) {
      // Local file given
      return new Promise((resolve, reject) =>
        resolve(getImage(src.data, src.format)),
      );
    }
    throw new Error(
      `Invalid data given for local file: ${JSON.stringify(src)}`,
    );
  }

  return new Promise((resolve, reject) => {
    request(
      {
        url: src,
        method: 'GET',
        encoding: null,
      },
      (error, response, body) => {
        if (error) {
          return reject(error);
        }

        const isPng =
          body[0] === 137 &&
          body[1] === 80 &&
          body[2] === 78 &&
          body[3] === 71 &&
          body[4] === 13 &&
          body[5] === 10 &&
          body[6] === 26 &&
          body[7] === 10;

        const isJpg = body[0] === 255 && body[1] === 216 && body[2] === 255;

        let extension = '';
        if (isPng) {
          extension = 'png';
        } else if (isJpg) {
          extension = 'jpg';
        } else reject(new Error('Not valid image extension'));

        const image = getImage(body, extension);
        return resolve(image);
      },
    );
  });
};
<|endoftext|>


<commit_before>import ReactDOMServer from 'react-dom/server'
import React from 'react'
import raf from 'raf'
import Radium from 'radium'

import phash from './lib/phash'
import log from './lib/log'
import hotCache from './mixins/hotCache'
import reportError from './lib/reportError'
import runEvents from './lib/runEvents'
import createElement from './tag/createElement'
import viewOn from './lib/viewOn'

const capitalize = str =>
  str[0].toUpperCase() + str.substring(1)

const pathWithoutProps = path =>
  path.replace(/\.[a-z0-9\-]+$/, '')

let views = {}

export default function createComponent(Flint, Internal, name, view, options = {}) {
  const el = createElement(name)
  let isChanged = options.changed

  if (process.env.production)
    return createViewComponent()

  if (options.changed) {
    views[name] = createViewComponent()
  }

  // once rendered, isChanged is used to prevent
  // unnecessary props hashing, for faster hot reloads
  Flint.on('render:done', () => {
    isChanged = false
  })

  return createProxyComponent()

  // proxy components handle hot reloads
  function createProxyComponent() {
    return React.createClass({

      childContextTypes: {
        path: React.PropTypes.string,
        displayName: React.PropTypes.string
      },

      contextTypes: {
        path: React.PropTypes.string
      },

      getChildContext() {
        return {
          path: this.getPath()
        }
      },

      getPath() {
        if (!this.path) this.setPath()
        return `${this.path}-${this.props.__flint && this.props.__flint.key || ''}`
      },

      pathKey() {
        return this.context.path + this.props.__flint && this.props.__flint.key
      },

      setPath() {
        if (!isChanged) {
          const prevPath = Internal.paths[this.pathKey()]
          if (prevPath) {
            this.path = prevPath
            return
          }
        }

        // get the props hash, but lets cache it so its not a ton of work
        let propsHash = phash(this.props)

        const sep = name == 'Main' ? '' : ','
        this.path = (this.context.path || '') + sep + name + '.' + propsHash

        // for faster retrieval hot reloading
        Internal.paths[this.pathKey()] = this.path
      },

      onMount(component) {
        const path = this.getPath()
        const lastRendered = component.lastRendered

        Internal.mountedViews[name] = Internal.mountedViews[name] || []
        Internal.mountedViews[name].push(this)
        Internal.viewsAtPath[path] = component

        if (lastRendered)
          Internal.lastWorkingRenders[pathWithoutProps(path)] = lastRendered

        Internal.lastWorkingViews[name] = { component }
      },

      render() {
        const View = views[name]

        let viewProps = Object.assign({}, this.props)

        viewProps.__flint = viewProps.__flint || {}
        viewProps.__flint.onMount = this.onMount
        viewProps.__flint.path = this.getPath()

        return React.createElement(View, viewProps)
      }
    })
  }

  // create view
  function createViewComponent() {
    const component = React.createClass({
      displayName: name,
      name,
      Flint,
      el,

      mixins: [hotCache({ Internal, options, name })],

      // TODO: shouldComponentUpdate based on hot load for perf
      shouldComponentUpdate() {
        return !this.isPaused
      },

      shouldReRender() {
        return (
          this._isMounted && !this.isUpdating &&
          !this.isPaused && !this.firstRender &&
          !this.isRendering
        )
      },

      // LIFECYCLES

      getInitialState() {
        const fprops = this.props.__flint

        Internal.getInitialStates[fprops ? fprops.path : 'Main'] = () => this.getInitialState()

        let u = null

        this.successfulRender = null
        this.firstRender = true
        this.styles = { _static: {} }
        this.events = { mount: u, unmount: u, change: u, props: u }
        this.path = null

        // scope on() to view
        this.viewOn = viewOn(this)

        // cache Flint view render() (defined below)
        const flintRender = this.render

        this.renders = []

        // setter to capture view render
        this.render = renderFn => {
          this.renders.push(renderFn)
        }

        // call view
        if (process.env.production)
          view.call(this, this, this.viewOn, this.styles)
        else {
          try {
            view.call(this, this, this.viewOn, this.styles)
            this.recoveryRender = false
          }
          catch(e) {
            Internal.caughtRuntimeErrors++
            reportError(e)
            console.error(e.stack)
            this.recoveryRender = true
          }
        }

        // reset original render
        this.render = flintRender

        return null
      },

      runEvents(name) {
        runEvents(this.events, name)
      },

      componentWillReceiveProps(nextProps) {
        this.props = nextProps
        this.runEvents('props')
      },

      componentDidMount() {
        this.isRendering = false
        this._isMounted = true
        this.runEvents('mount')

        if (!process.env.production) {
          this.props.__flint.onMount(this)
          this.setID()
        }
      },

      componentWillUnmount() {
        // fixes unmount errors #60
        if (!process.env.production) {
          this.render()
        }

        this._isMounted = false
        this.runEvents('unmount')
      },

      componentWillMount() {
        // componentWillUpdate only run after first render
        this.runEvents('change')
        this.runEvents('props')
      },

      componentWillUpdate() {
        this.isUpdating = true
        this.runEvents('change')
      },

      setID() {
        // set flintID for state inspect
        const node = ReactDOM.findDOMNode(this)
        if (node) node.__flintID = this.props.__flint.path
      },

      componentDidUpdate() {
        this.isRendering = false
        this.isUpdating = false

        if (!process.env.production) {
          this.setID()

          if (this.queuedUpdate) {
            this.isRendering = false
            this.update()
          }
        }
      },

      // FLINT HELPERS

      // helpers for controlling re-renders
      pause() { this.isPaused = true },
      resume() { this.isPaused = false },

      update() {
        if (!Internal.firstRender && !this.isRendering) {
          this.queuedUpdate = false
          raf(() => this.isMounted() && this.forceUpdate())
        }
        else {
          log(name, 'called update, isRendering still, queued?', this.queuedUpdate)
          if (!this.queuedUpdate)
            raf(() => this.update())

          this.queuedUpdate = true
        }
      },

      // helpers for context
      childContext(obj) {
        if (!obj) return

        Object.keys(obj).forEach(key => {
          this.constructor.childContextTypes[key] =
            React.PropTypes[typeof obj[key]]
        })

        this.getChildContext = () => obj
      },

      getWrapper(tags, props, numRenders) {
        const wrapperName = name.toLowerCase()

        let tagProps = Object.assign({
          isWrapper: true
        }, props)

        return this.el(`view.${name}`, tagProps, ...tags)
      },

      getRender() {
        if (this.recoveryRender)
          return this.getLastGoodRender()

        let tags, props
        let addWrapper = true
        const numRenders = this.renders && this.renders.length

        if (!numRenders) {
          tags = []
          props = { yield: true }
        }

        else if (numRenders == 1) {
          tags = this.renders[0].call(this)

          addWrapper = (
            Array.isArray(tags) ||
            !tags.props
          )

          if (!Array.isArray(tags) && tags.props && tags.props.__flint && tags.props.__flint.tagName != name.toLowerCase()) {
            addWrapper = true
            tags = [tags]
          }
        }

        else if (numRenders > 1) {
          tags = this.renders.map(r => r.call(this))
        }

        // if $ = false, unwrap if possible
        // if (this.styles._static && this.styles._static.$ == false && tags.length == 1) {
        //   addWrapper = false
        //   tags = tags[0]
        // }

        // top level tag returned false
        if (!tags)
          addWrapper = true

        const wrappedTags = addWrapper ?
          this.getWrapper(tags, props, numRenders) :
          tags

        const cleanName = name.replace('.', '-')
        const viewClassName = `View${cleanName}`
        const parentClassName = wrappedTags.props.className
        const className = parentClassName
          ? `${viewClassName} ${parentClassName}`
          : viewClassName

        const withClass = React.cloneElement(wrappedTags, { className })

        return withClass
      },

      getLastGoodRender() {
        return Internal.lastWorkingRenders[pathWithoutProps(this.props.__flint.path)]
      },

      render() {
        this.isRendering = true
        this.firstRender = false

        if (process.env.production)
          return this.getRender()

        // try render
        try {
          const els = this.getRender()
          this.lastRendered = els
          return els
        }
        catch(e) {
          Internal.caughtRuntimeErrors++

          console.warn(`Render error in view ${name}:`)
          console.error(e)
          reportError(e)

          const lastRender = this.getLastGoodRender()

          try {
            let inner = Error in view {name}

            if (lastRender) {
              let __html = ReactDOMServer.renderToString(lastRender)
              __html = __html.replace(/\s*data\-react[a-z-]*\=\"[^"]*\"/g, '')

              inner =
            }

            // highlight in red and return last working render
            return (

                {inner}

            )
          }
          catch(e) {
            log("Error rendering last version of view after error")
          }
        }
      }
    })

    return Radium(component)
  }
}
<commit_msg>debounce error messages in console a bit, for sanity<commit_after>import ReactDOMServer from 'react-dom/server'
import React from 'react'
import raf from 'raf'
import Radium from 'radium'

import phash from './lib/phash'
import log from './lib/log'
import hotCache from './mixins/hotCache'
import reportError from './lib/reportError'
import runEvents from './lib/runEvents'
import createElement from './tag/createElement'
import viewOn from './lib/viewOn'

const capitalize = str =>
  str[0].toUpperCase() + str.substring(1)

const pathWithoutProps = path =>
  path.replace(/\.[a-z0-9\-]+$/, '')

let views = {}
let viewErrorDebouncers = {}

export default function createComponent(Flint, Internal, name, view, options = {}) {
  const el = createElement(name)
  let isChanged = options.changed

  if (process.env.production)
    return createViewComponent()

  if (options.changed) {
    views[name] = createViewComponent()
  }

  // once rendered, isChanged is used to prevent
  // unnecessary props hashing, for faster hot reloads
  Flint.on('render:done', () => {
    isChanged = false
  })

  return createProxyComponent()

  // proxy components handle hot reloads
  function createProxyComponent() {
    return React.createClass({

      childContextTypes: {
        path: React.PropTypes.string,
        displayName: React.PropTypes.string
      },

      contextTypes: {
        path: React.PropTypes.string
      },

      getChildContext() {
        return {
          path: this.getPath()
        }
      },

      getPath() {
        if (!this.path) this.setPath()
        return `${this.path}-${this.props.__flint && this.props.__flint.key || ''}`
      },

      pathKey() {
        return this.context.path + this.props.__flint && this.props.__flint.key
      },

      setPath() {
        if (!isChanged) {
          const prevPath = Internal.paths[this.pathKey()]
          if (prevPath) {
            this.path = prevPath
            return
          }
        }

        // get the props hash, but lets cache it so its not a ton of work
        let propsHash = phash(this.props)

        const sep = name == 'Main' ? '' : ','
        this.path = (this.context.path || '') + sep + name + '.' + propsHash

        // for faster retrieval hot reloading
        Internal.paths[this.pathKey()] = this.path
      },

      onMount(component) {
        const path = this.getPath()
        const lastRendered = component.lastRendered

        Internal.mountedViews[name] = Internal.mountedViews[name] || []
        Internal.mountedViews[name].push(this)
        Internal.viewsAtPath[path] = component

        if (lastRendered)
          Internal.lastWorkingRenders[pathWithoutProps(path)] = lastRendered

        Internal.lastWorkingViews[name] = { component }
      },

      render() {
        const View = views[name]

        let viewProps = Object.assign({}, this.props)

        viewProps.__flint = viewProps.__flint || {}
        viewProps.__flint.onMount = this.onMount
        viewProps.__flint.path = this.getPath()

        return React.createElement(View, viewProps)
      }
    })
  }

  // create view
  function createViewComponent() {
    const component = React.createClass({
      displayName: name,
      name,
      Flint,
      el,

      mixins: [hotCache({ Internal, options, name })],

      // TODO: shouldComponentUpdate based on hot load for perf
      shouldComponentUpdate() {
        return !this.isPaused
      },

      shouldReRender() {
        return (
          this._isMounted && !this.isUpdating &&
          !this.isPaused && !this.firstRender &&
          !this.isRendering
        )
      },

      // LIFECYCLES

      getInitialState() {
        const fprops = this.props.__flint

        Internal.getInitialStates[fprops ? fprops.path : 'Main'] = () => this.getInitialState()

        let u = null

        this.successfulRender = null
        this.firstRender = true
        this.styles = { _static: {} }
        this.events = { mount: u, unmount: u, change: u, props: u }
        this.path = null

        // scope on() to view
        this.viewOn = viewOn(this)

        // cache Flint view render() (defined below)
        const flintRender = this.render

        this.renders = []

        // setter to capture view render
        this.render = renderFn => {
          this.renders.push(renderFn)
        }

        // call view
        if (process.env.production)
          view.call(this, this, this.viewOn, this.styles)
        else {
          try {
            view.call(this, this, this.viewOn, this.styles)
            this.recoveryRender = false
          }
          catch(e) {
            Internal.caughtRuntimeErrors++
            reportError(e)
            console.error(e.stack)
            this.recoveryRender = true
          }
        }

        // reset original render
        this.render = flintRender

        return null
      },

      runEvents(name) {
        runEvents(this.events, name)
      },

      componentWillReceiveProps(nextProps) {
        this.props = nextProps
        this.runEvents('props')
      },

      componentDidMount() {
        this.isRendering = false
        this._isMounted = true
        this.runEvents('mount')

        if (!process.env.production) {
          this.props.__flint.onMount(this)
          this.setID()
        }
      },

      componentWillUnmount() {
        // fixes unmount errors #60
        if (!process.env.production) {
          this.render()
        }

        this._isMounted = false
        this.runEvents('unmount')
      },

      componentWillMount() {
        // componentWillUpdate only run after first render
        this.runEvents('change')
        this.runEvents('props')
      },

      componentWillUpdate() {
        this.isUpdating = true
        this.runEvents('change')
      },

      setID() {
        // set flintID for state inspect
        const node = ReactDOM.findDOMNode(this)
        if (node) node.__flintID = this.props.__flint.path
      },

      componentDidUpdate() {
        this.isRendering = false
        this.isUpdating = false

        if (!process.env.production) {
          this.setID()

          if (this.queuedUpdate) {
            this.isRendering = false
            this.update()
          }
        }
      },

      // FLINT HELPERS

      // helpers for controlling re-renders
      pause() { this.isPaused = true },
      resume() { this.isPaused = false },

      update() {
        if (!Internal.firstRender && !this.isRendering) {
          this.queuedUpdate = false
          raf(() => this.isMounted() && this.forceUpdate())
        }
        else {
          log(name, 'called update, isRendering still, queued?', this.queuedUpdate)
          if (!this.queuedUpdate)
            raf(() => this.update())

          this.queuedUpdate = true
        }
      },

      // helpers for context
      childContext(obj) {
        if (!obj) return

        Object.keys(obj).forEach(key => {
          this.constructor.childContextTypes[key] =
            React.PropTypes[typeof obj[key]]
        })

        this.getChildContext = () => obj
      },

      getWrapper(tags, props, numRenders) {
        const wrapperName = name.toLowerCase()

        let tagProps = Object.assign({
          isWrapper: true
        }, props)

        return this.el(`view.${name}`, tagProps, ...tags)
      },

      getRender() {
        if (this.recoveryRender)
          return this.getLastGoodRender()

        let tags, props
        let addWrapper = true
        const numRenders = this.renders && this.renders.length

        if (!numRenders) {
          tags = []
          props = { yield: true }
        }

        else if (numRenders == 1) {
          tags = this.renders[0].call(this)

          addWrapper = (
            Array.isArray(tags) ||
            !tags.props
          )

          if (!Array.isArray(tags) && tags.props && tags.props.__flint && tags.props.__flint.tagName != name.toLowerCase()) {
            addWrapper = true
            tags = [tags]
          }
        }

        else if (numRenders > 1) {
          tags = this.renders.map(r => r.call(this))
        }

        // if $ = false, unwrap if possible
        // if (this.styles._static && this.styles._static.$ == false && tags.length == 1) {
        //   addWrapper = false
        //   tags = tags[0]
        // }

        // top level tag returned false
        if (!tags)
          addWrapper = true

        const wrappedTags = addWrapper ?
          this.getWrapper(tags, props, numRenders) :
          tags

        const cleanName = name.replace('.', '-')
        const viewClassName = `View${cleanName}`
        const parentClassName = wrappedTags.props.className
        const className = parentClassName
          ? `${viewClassName} ${parentClassName}`
          : viewClassName

        const withClass = React.cloneElement(wrappedTags, { className })

        return withClass
      },

      getLastGoodRender() {
        return Internal.lastWorkingRenders[pathWithoutProps(this.props.__flint.path)]
      },

      render() {
        const self = this

        self.isRendering = true
        self.firstRender = false

        if (process.env.production)
          return self.getRender()
        else {
          clearTimeout(viewErrorDebouncers[self.props.__flint.path])
        }

        // try render
        try {
          const els = self.getRender()
          self.lastRendered = els
          return els
        }
        catch(e) {
          Internal.caughtRuntimeErrors++

          // console warn, with debounce
          viewErrorDebouncers[self.props.__flint.path] = setTimeout(() => {
            console.warn(`Render error in view ${name}:`)
            console.error(e)
          }, 500)

          reportError(e)

          const lastRender = self.getLastGoodRender()

          try {
            let inner = Error in view {name}

            if (lastRender) {
              let __html = ReactDOMServer.renderToString(lastRender)
              __html = __html.replace(/\s*data\-react[a-z-]*\=\"[^"]*\"/g, '')
              inner =
            }

            // highlight in red and return last working render
            return (

                {inner}

            )
          }
          catch(e) {
            log("Error rendering last version of view after error")
          }
        }
      }
    })

    return Radium(component)
  }
}
<|endoftext|>


<commit_before>const Searcher = require('@cardstack/elasticsearch/searcher');
const SchemaCache = require('@cardstack/server/schema-cache');
const temp = require('@cardstack/plugin-utils/node-tests/temp-helper');
const { makeRepo } = require('@cardstack/git/node-tests/support');
const GitIndexer = require('@cardstack/git/indexer');
const Indexers = require('@cardstack/server/indexers');
const Writers = require('@cardstack/server/writers');
const Schema = require('@cardstack/server/schema');
const ElasticAssert = require('@cardstack/elasticsearch/node-tests/assertions');
const JSONAPIFactory = require('@cardstack/test-support/jsonapi-factory');

exports.createDefaultEnvironment = async function(initialModels = []) {
  let repoPath = await temp.mkdir('cardstack-server-test');

  // TODO: The git writer should make its own local repo when it
  // starts up the first time.
  let { head, repo } = await makeRepo(repoPath);

  let user = {
    id: 'the-default-test-user',
    fullName: 'Default Test Environment',
    email: 'test@example.com'
  };

  let factory = new JSONAPIFactory();

  factory.addResource('plugin-configs')
    .withAttributes({
      module: '@cardstack/server',
    }).withRelated(
      'default-data-source',
      factory.addResource('data-sources')
        .withAttributes({
          'source-type': '@cardstack/git',
          params: { repo: repoPath }
        })
    );

  factory.addResource('plugin-configs')
    .withAttributes({ module: '@cardstack/git' });

  factory.addResource('grants')
    .withAttributes({
      groupId: 'the-default-test-user',
      mayCreateResource: true,
      mayUpdateResource: true,
      mayDeleteResource: true,
      mayWriteField: true
    });

  let schemaCache = new SchemaCache(factory.getModels());

  // TODO: we need Searchers as to Searcher as Writers is to Writer,
  // so we have a place to route special searches, and so we're not
  // hard-coding the @cardsatck/elasticsearch/searcher module
  // here. Should be data-driven instead.
  let searcher = new Searcher(schemaCache);
  let writers = new Writers(schemaCache);

  // TODO: Indexers should just take schemaCache and figure out its
  // own indexers list. Need to figure out how this plays with the
  // branches. In some cases, a "branch" exists because of
  // configuration on a data-source (like using different postgres
  // databases to represent "master" vs "production"). But in the git
  // case, the branches are discovered by the indexer and we have a
  // circular dependency to break.
  //
  // Solution: add some server-level config (probably in the
  // plugin-config for @cardstack/server) for the branch name that
  // always controls which indexers to run. This would also work for
  // branch-level grants: to create a branch, you must have a grant on
  // this specially-privileged branch.
  let indexer = new Indexers(schemaCache, [new GitIndexer({
    repoPath
  })]);

  // This creates the indices
  await indexer.update();

  for (let model of inDependencyOrder(initialModels)) {
    // TODO: this one-by-one creation is still slower than is nice for tests.
    let response = await writers.create('master', user, model.type, model);
    head = response.meta.version;
  }

  await indexer.update({ realTime: true });

  return {
    searcher,
    indexer,
    writers,
    user,
    schemaCache,
    head,
    repo,
    repoPath
  };
};

exports.destroyDefaultEnvironment = async function(/* env */) {
  await destroyIndices();
  await temp.cleanup();
};

exports.destroyIndices = destroyIndices;
async function destroyIndices() {
  let ea = new ElasticAssert();
  await ea.deleteAllIndices();
}

exports.indexRecords = async function(records) {
  let stub = new StubIndexer();
  let schemaCache = new SchemaCache();
  let indexers = new Indexers(schemaCache, [stub]);
  let schemaTypes = Schema.ownTypes();
  for (let record of records) {
    if (schemaTypes.indexOf(record.type) >= 0) {
      stub.schemaRecords.push(record);
    }
    stub.records.push(record);
  }
  await indexers.update({ realTime: true });
};

class StubIndexer {
  constructor() {
    this.records = [];
    this.schemaRecords = [];
  }
  async branches() {
    return ['master'];
  }
  async beginUpdate() {
    return new StubUpdater(this);
  }
}

class StubUpdater {
  constructor(source) {
    this.source = source;
    this.name = 'stub';
  }
  async schema() {
    return this.source.schemaRecords.slice();
  }
  async updateContent(meta, hints, ops) {
    for (let record of this.source.records) {
      await ops.save(record.type, record.id, record);
    }
  }
}

function inDependencyOrder(models) {
  let priority = ['default-values', 'plugin-configs', 'constraints', 'fields', 'content-types'];
  return priority.map(type => models.filter(m => m.type === type)).reduce((a,b) => a.concat(b), []).concat(models.filter(m => !priority.includes(m.type)));
}
<commit_msg>adding note<commit_after>const Searcher = require('@cardstack/elasticsearch/searcher');
const SchemaCache = require('@cardstack/server/schema-cache');
const temp = require('@cardstack/plugin-utils/node-tests/temp-helper');
const { makeRepo } = require('@cardstack/git/node-tests/support');
const GitIndexer = require('@cardstack/git/indexer');
const Indexers = require('@cardstack/server/indexers');
const Writers = require('@cardstack/server/writers');
const Schema = require('@cardstack/server/schema');
const ElasticAssert = require('@cardstack/elasticsearch/node-tests/assertions');
const JSONAPIFactory = require('@cardstack/test-support/jsonapi-factory');

exports.createDefaultEnvironment = async function(initialModels = []) {
  let repoPath = await temp.mkdir('cardstack-server-test');

  // TODO: The git writer should make its own local repo when it
  // starts up the first time.
  let { head, repo } = await makeRepo(repoPath);

  let user = {
    id: 'the-default-test-user',
    fullName: 'Default Test Environment',
    email: 'test@example.com'
  };

  let factory = new JSONAPIFactory();

  factory.addResource('plugin-configs')
    .withAttributes({
      module: '@cardstack/server',
    }).withRelated(
      'default-data-source',
      factory.addResource('data-sources')
        .withAttributes({
          'source-type': '@cardstack/git',
          params: { repo: repoPath }
        })
    );

  factory.addResource('plugin-configs')
    .withAttributes({ module: '@cardstack/git' });

  factory.addResource('grants')
    .withAttributes({
      groupId: 'the-default-test-user',
      mayCreateResource: true,
      mayUpdateResource: true,
      mayDeleteResource: true,
      mayWriteField: true
    });

  let schemaCache = new SchemaCache(factory.getModels());

  // TODO: we need Searchers as to Searcher as Writers is to Writer,
  // so we have a place to route special searches, and so we're not
  // hard-coding the @cardsatck/elasticsearch/searcher module
  // here. Should be data-driven instead.
  let searcher = new Searcher(schemaCache);
  let writers = new Writers(schemaCache);

  // TODO: Indexers should just take schemaCache and figure out its
  // own indexers list. Need to figure out how this plays with the
  // branches. In some cases, a "branch" exists because of
  // configuration on a data-source (like using different postgres
  // databases to represent "master" vs "production"). But in the git
  // case, the branches are discovered by the indexer and we have a
  // circular dependency to break.
  //
  // Solution: add some server-level config (probably in the
  // plugin-config for @cardstack/server) for the branch name that
  // always controls which indexers to run. This would also work for
  // branch-level grants: to create a branch, you must have a grant on
  // this specially-privileged branch.
  let indexer = new Indexers(schemaCache, [new GitIndexer({
    repoPath
  })]);

  // This creates the indices
  await indexer.update();

  for (let model of inDependencyOrder(initialModels)) {
    // TODO: this one-by-one creation is still slower than is nice for
    // tests -- each time we write a schema model it invalidates the
    // schema cache, which needs to get rebuilt before we can write
    // the next one. Which also requires us to use inDependencyOrder,
    // which is kinda lame.
    //
    // On the other hand, this is a high-quality test of our ability
    // to build up the entire state in the same way an end user would
    // via JSONAPI requests. If we optimize this away, we should also
    // add some tests like that that are similarly comprehensive.
    let response = await writers.create('master', user, model.type, model);
    head = response.meta.version;
  }

  await indexer.update({ realTime: true });

  return {
    searcher,
    indexer,
    writers,
    user,
    schemaCache,
    head,
    repo,
    repoPath
  };
};

exports.destroyDefaultEnvironment = async function(/* env */) {
  await destroyIndices();
  await temp.cleanup();
};

exports.destroyIndices = destroyIndices;
async function destroyIndices() {
  let ea = new ElasticAssert();
  await ea.deleteAllIndices();
}

exports.indexRecords = async function(records) {
  let stub = new StubIndexer();
  let schemaCache = new SchemaCache();
  let indexers = new Indexers(schemaCache, [stub]);
  let schemaTypes = Schema.ownTypes();
  for (let record of records) {
    if (schemaTypes.indexOf(record.type) >= 0) {
      stub.schemaRecords.push(record);
    }
    stub.records.push(record);
  }
  await indexers.update({ realTime: true });
};

class StubIndexer {
  constructor() {
    this.records = [];
    this.schemaRecords = [];
  }
  async branches() {
    return ['master'];
  }
  async beginUpdate() {
    return new StubUpdater(this);
  }
}

class StubUpdater {
  constructor(source) {
    this.source = source;
    this.name = 'stub';
  }
  async schema() {
    return this.source.schemaRecords.slice();
  }
  async updateContent(meta, hints, ops) {
    for (let record of this.source.records) {
      await ops.save(record.type, record.id, record);
    }
  }
}

function inDependencyOrder(models) {
  let priority = ['default-values', 'plugin-configs', 'constraints', 'fields', 'content-types'];
  return priority.map(type => models.filter(m => m.type === type)).reduce((a,b) => a.concat(b), []).concat(models.filter(m => !priority.includes(m.type)));
}
<|endoftext|>


<commit_before>// Copyright (c) IPython Development Team.
// Distributed under the terms of the Modified BSD License.

define([
    'base/js/namespace',
    'jquery',
    'codemirror/lib/codemirror',
], function(IPython, $, CodeMirror) {
    "use strict";

    var modal = function (options) {

        var modal = $("
")
            .addClass("modal")
            .addClass("fade")
            .attr("role", "dialog");
        var dialog = $("
")
            .addClass("modal-dialog")
            .appendTo(modal);
        var dialog_content = $("
")
            .addClass("modal-content")
            .appendTo(dialog);
        dialog_content.append(
            $("
")
                .addClass("modal-header")
                .append($("<button>")
                    .attr("type", "button")
                    .addClass("close")
                    .attr("data-dismiss", "modal")
                    .attr("aria-hidden", "true")
                    .html("×")
                ).append(
                    $("
")
                        .addClass('modal-title')
                        .text(options.title || "")
                )
        ).append(
            $("
").addClass("modal-body").append(
                options.body || $("
")
            )
        );

        var footer = $("
").addClass("modal-footer");

        for (var label in options.buttons) {
            var btn_opts = options.buttons[label];
            var button = $("<button/>")
                .addClass("btn btn-default btn-sm")
                .attr("data-dismiss", "modal")
                .text(label);
            if (btn_opts.click) {
                button.click($.proxy(btn_opts.click, dialog_content));
            }
            if (btn_opts.class) {
                button.addClass(btn_opts.class);
            }
            footer.append(button);
        }
        dialog_content.append(footer);
        // hook up on-open event
        modal.on("shown.bs.modal", function() {
            setTimeout(function() {
                footer.find("button").last().focus();
                if (options.open) {
                    $.proxy(options.open, modal)();
                }
            }, 0);
        });

        // destroy modal on hide, unless explicitly asked not to
        if (options.destroy === undefined || options.destroy) {
            modal.on("hidden.bs.modal", function () {
                modal.remove();
            });
        }
        modal.on("hidden.bs.modal", function () {
            if (options.notebook) {
                var cell = options.notebook.get_selected_cell();
                if (cell) cell.select();
            }
            if (options.keyboard_manager) {
                options.keyboard_manager.enable();
                options.keyboard_manager.command_mode();
            }
        });

        if (options.keyboard_manager) {
            options.keyboard_manager.disable();
        }

        options.backdrop = options.backdrop || 'static';

        return modal.modal(options);
    };

    var kernel_modal = function (options) {
        /**
         * only one kernel dialog should be open at a time -- but
         * other modal dialogs can still be open
         */
        $('.kernel-modal').modal('hide');
        var dialog = modal(options);
        dialog.addClass('kernel-modal');
        return dialog;
    };

    var edit_metadata = function (options) {
        options.name = options.name || "Cell";
        var error_div = $('
').css('color', 'red');
        var message =
            "Manually edit the JSON below to manipulate the metadata for this " + options.name + "." +
            " We recommend putting custom metadata attributes in an appropriately named sub-structure," +
            " so they don't conflict with those of others.";

        var textarea = $('<textarea/>')
            .attr('rows', '13')
            .attr('cols', '80')
            .attr('name', 'metadata')
            .text(JSON.stringify(options.md || {}, null, 2));

        var dialogform = $('
').attr('title', 'Edit the metadata')
            .append(
                $('<form/>').append(
                    $('<fieldset/>').append(
                        $('')
                        .attr('for','metadata')
                        .text(message)
                        )
                        .append(error_div)
                        .append($('
'))
                        .append(textarea)
                    )
            );
        var editor = CodeMirror.fromTextArea(textarea[0], {
            lineNumbers: true,
            matchBrackets: true,
            indentUnit: 2,
            autoIndent: true,
            mode: 'application/json',
        });
        var modal_obj = modal({
            title: "Edit " + options.name + " Metadata",
            body: dialogform,
            buttons: {
                OK: { class : "btn-primary",
                    click: function() {
                        /**
                         * validate json and set it
                         */
                        var new_md;
                        try {
                            new_md = JSON.parse(editor.getValue());
                        } catch(e) {
                            console.log(e);
                            error_div.text('WARNING: Could not save invalid JSON.');
                            return false;
                        }
                        options.callback(new_md);
                    }
                },
                Cancel: {}
            },
            notebook: options.notebook,
            keyboard_manager: options.keyboard_manager,
        });

        modal_obj.on('shown.bs.modal', function(){ editor.refresh(); });
    };

    var dialog = {
        modal : modal,
        kernel_modal : kernel_modal,
        edit_metadata : edit_metadata,
    };

    // Backwards compatability.
    IPython.dialog = dialog;

    return dialog;
});
<commit_msg>Sanitize dialog text-body.<commit_after>// Copyright (c) IPython Development Team.
// Distributed under the terms of the Modified BSD License.

define(function(require) {
    "use strict";

    var CodeMirror = require('codemirror/lib/codemirror');
    var IPython = require('base/js/namespace');
    var $ = require('jquery');

    var modal = function (options) {

        var modal = $("
")
            .addClass("modal")
            .addClass("fade")
            .attr("role", "dialog");
        var dialog = $("
")
            .addClass("modal-dialog")
            .appendTo(modal);
        var dialog_content = $("
")
            .addClass("modal-content")
            .appendTo(dialog);
        if(typeof(options.body) === 'string'){
            options.body = $("
").text(options.body)
        }
        dialog_content.append(
            $("
")
                .addClass("modal-header")
                .append($("<button>")
                    .attr("type", "button")
                    .addClass("close")
                    .attr("data-dismiss", "modal")
                    .attr("aria-hidden", "true")
                    .html("×")
                ).append(
                    $("
")
                        .addClass('modal-title')
                        .text(options.title || "No Title")
                )
        ).append(
            $("
").addClass("modal-body").append(
                options.body || $("
")
            )
        );

        var footer = $("
").addClass("modal-footer");

        for (var label in options.buttons) {
            var btn_opts = options.buttons[label];
            var button = $("<button/>")
                .addClass("btn btn-default btn-sm")
                .attr("data-dismiss", "modal")
                .text(label);
            if (btn_opts.click) {
                button.click($.proxy(btn_opts.click, dialog_content));
            }
            if (btn_opts.class) {
                button.addClass(btn_opts.class);
            }
            footer.append(button);
        }
        dialog_content.append(footer);
        // hook up on-open event
        modal.on("shown.bs.modal", function() {
            setTimeout(function() {
                footer.find("button").last().focus();
                if (options.open) {
                    $.proxy(options.open, modal)();
                }
            }, 0);
        });

        // destroy modal on hide, unless explicitly asked not to
        if (options.destroy === undefined || options.destroy) {
            modal.on("hidden.bs.modal", function () {
                modal.remove();
            });
        }
        modal.on("hidden.bs.modal", function () {
            if (options.notebook) {
                var cell = options.notebook.get_selected_cell();
                if (cell) cell.select();
            }
            if (options.keyboard_manager) {
                options.keyboard_manager.enable();
                options.keyboard_manager.command_mode();
            }
        });

        if (options.keyboard_manager) {
            options.keyboard_manager.disable();
        }

        options.backdrop = options.backdrop || 'static';

        return modal.modal(options);
    };

    var kernel_modal = function (options) {
        /**
         * only one kernel dialog should be open at a time -- but
         * other modal dialogs can still be open
         */
        $('.kernel-modal').modal('hide');
        var dialog = modal(options);
        dialog.addClass('kernel-modal');
        return dialog;
    };

    var edit_metadata = function (options) {
        options.name = options.name || "Cell";
        var error_div = $('
').css('color', 'red');
        var message =
            "Manually edit the JSON below to manipulate the metadata for this " + options.name + "." +
            " We recommend putting custom metadata attributes in an appropriately named sub-structure," +
            " so they don't conflict with those of others.";

        var textarea = $('<textarea/>')
            .attr('rows', '13')
            .attr('cols', '80')
            .attr('name', 'metadata')
            .text(JSON.stringify(options.md || {}, null, 2));

        var dialogform = $('
').attr('title', 'Edit the metadata')
            .append(
                $('<form/>').append(
                    $('<fieldset/>').append(
                        $('')
                        .attr('for','metadata')
                        .text(message)
                        )
                        .append(error_div)
                        .append($('
'))
                        .append(textarea)
                    )
            );
        var editor = CodeMirror.fromTextArea(textarea[0], {
            lineNumbers: true,
            matchBrackets: true,
            indentUnit: 2,
            autoIndent: true,
            mode: 'application/json',
        });
        var modal_obj = modal({
            title: "Edit " + options.name + " Metadata",
            body: dialogform,
            buttons: {
                OK: { class : "btn-primary",
                    click: function() {
                        /**
                         * validate json and set it
                         */
                        var new_md;
                        try {
                            new_md = JSON.parse(editor.getValue());
                        } catch(e) {
                            console.log(e);
                            error_div.text('WARNING: Could not save invalid JSON.');
                            return false;
                        }
                        options.callback(new_md);
                    }
                },
                Cancel: {}
            },
            notebook: options.notebook,
            keyboard_manager: options.keyboard_manager,
        });

        modal_obj.on('shown.bs.modal', function(){ editor.refresh(); });
    };

    var dialog = {
        modal : modal,
        kernel_modal : kernel_modal,
        edit_metadata : edit_metadata,
    };

    // Backwards compatability.
    IPython.dialog = dialog;

    return dialog;
});
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 * @format
 * @providesModule BundleSegments
 */

'use strict';

let segmentLoaders = new Map();

/**
 * Ensure that a bundle segment is ready for use, for example requiring some of
 * its module. We cache load promises so as to avoid calling `fetchBundle` twice
 * for the same bundle. We assume that once a segment is fetched/loaded, it is
 * never gettting removed during this instance of the JavaScript VM.
 */
async function loadForModule(moduleID: number): Promise<void> {
  const {segmentId} = (require: $FlowFixMe).unpackModuleId(moduleID);
  if (segmentId === 0) {
    return;
  }
  let segmentLoader = segmentLoaders.get(segmentId);
  if (segmentLoader != null) {
    return await segmentLoader;
  }
  // FIXME: `fetchBundle` should be renamed `fetchSegment`.
  const {fetchBundle} = global;
  if (fetchBundle == null) {
    throw new Error(
      'When bundle splitting is enabled, the `global.fetchBundle` function ' +
        'must be provided to be able to load particular bundle segments.',
    );
  }
  segmentLoader = new Promise((resolve, reject) => {
    fetchBundle(segmentId, error => {
      if (error != null) {
        reject(error);
        return;
      }
      resolve();
    });
  });
  segmentLoaders.set(segmentId, segmentLoader);
  return await segmentLoader;
}

module.exports = {loadForModule};
<commit_msg>Revert D6210177: react-native: BundleSegments<commit_after><|endoftext|>


<commit_before>define([
	"dojo/_base/declare",
	"dojo/_base/lang",
	"dojo/_base/array",
	"dojo/string",
	"dojo/has",
	"dojo/on",
	"dojo/touch",
	"dojo/keys",
	"dojo/dom-construct",
	"dojo/dom-class",
	"dojo/dom-geometry",
	"dui/_WidgetBase",
	"dojo/has!dojo-bidi?dui/mobile/bidi/StarRating",
	"dojo/i18n!./nls/StarRating"
], function(declare, lang, array, string, has, on, touch, keys, domConstruct, domClass, domGeometry, WidgetBase, BidiStarRating, messages){

	// module:
	//		dui/mobile/StarRating

	var StarRating = declare(WidgetBase, {
		// summary:
		//		A widget that displays a rating, usually with stars, and that allows setting a different rating value
		//		by touching the stars.
		// description:
		//		This widget shows the rating using an image sprite that contains full stars, half stars and empty stars.
		//		The star displayed can be fully customized by redefining the following css classes in your application:
		//		- duiStarRatingStarIcon: defines the size of each star icon, and the css sprite to use as the background image stars;
		//		- duiStarRatingFullStar: defines the background-position of the css sprite to display a full star icon;
		//		- duiStarRatingHalfStar: defines the background-position of the css sprite to display a half star icon (ltr);
		//		- duiStarRatingHalfStarRtl: defines the background-position of the css sprite to display a half star icon (rtl);
		//		- duiStarRatingEmptyStar: defines the background-position of the css sprite to display an empty star icon.
		//		Note that if your using a different baseClass than the default one 'duiStarRating', you should replace 'duiStarRating'
		//		in the previous css class names with your baseClass value (for example, with a baseClass of 'myClass', the css classes to use
		//		will be myClassStarIcon, myClassFullStar, myClassHalfStar, myClassHalfStarRtl, myClassEmptyStar).
		//
		//		The widget can be used in read-only or in editable mode. In editable mode, the widget allows to set the
		//		rating to 0 stars or not using the zeroAreaWidth property. In this mode, it also allows to set
		//		half values or not using the editHalfValues property.
		//
		//		This widget supports right to left direction.

		// baseClass: String
		//		The name of the CSS class of this widget.
		baseClass: "duiStarRating",

		// maximum: Number
		//		The maximum rating, that is also the number of stars to show.
		maximum: 5,

		// value: Number
		//		The current value of the Rating.
		value: 0,

		// editable: Boolean
		//		Is the user allowed to edit the value of the Rating by touching / clicking the stars ?
		editable: false,

		// editHalfValues: Boolean
		//		If the Rating is editable, is the user allowed to edit half values (0.5, 1.5, ...) or not ?
		editHalfValues: false,

		// zeroAreaWidth: Number
		//		The number of pixel to add to the left of the widget (or right if the direction is rtl) to allow setting the value to 0
		//		when editable is set to true. Default value is 0 if the widget is not editable, 20 if the widget is editable.
		//		Set this value to 0 to forbid the user from setting the value to zero during edition. Setting this attribute to a negative
		//		value is not supported.
		zeroAreaWidth: null,

		// tabIndex: Number
		//		The tabindex of the widget node (set when the widget is in editable mode), for keyboard navigation order in the page.
		tabIndex: 0,

		/* internal properties */

		_enterValue: null,
		_hovering: false,
		_hoveredValue: null,
		_startHandlers: null,
		_otherEventsHandlers: [],
		_keyDownHandler: null,
		_incrementKeyCodes: [keys.RIGHT_ARROW, keys.UP_ARROW, keys.NUMPAD_PLUS], // keys to press to increment value
		_decrementKeyCodes: [keys.LEFT_ARROW, keys.DOWN_ARROW, keys.NUMPAD_MINUS], // keys to press to decrement value

		postMixInProperties: function(){
			if(this.zeroAreaWidth == null){
				this.zeroAreaWidth = this.editable ? 20 : 0;
			}
		},

		buildRendering: function(){
			this.inherited(arguments);
			this.domNode.style.display = "inline-block";
			// init WAI-ARIA attributes
			this.domNode.setAttribute('role', 'slider');
			this.domNode.setAttribute('aria-label', messages['aria-label']);
			this.domNode.setAttribute('aria-valuemin', 0);
			this.domNode.setAttribute('aria-valuemax', this.maximum);
			this.domNode.setAttribute('aria-valuenow', this.value);
			this.domNode.setAttribute('aria-valuetext', string.substitute(messages['aria-valuetext'], this));
			this.domNode.setAttribute('aria-disabled', !this.editable);
			// keyboard navigation
			this.domNode.setAttribute('tabindex', this.editable ? this.tabIndex : -1);
			this._keyDownHandler = this.on('keydown', lang.hitch(this, '_onKeyDown'));
		},

		_removeEventsHandlers: function(){
			while(this._otherEventsHandlers.length){
				this._otherEventsHandlers.pop().remove();
			}
		},

		_onTouchStart: function(/*Event*/ event){
			event.preventDefault();
			if(!this._otherEventsHandlers.length){
				// handle move on the stars strip
				this._otherEventsHandlers.push(this.on(touch.move, lang.hitch(this, '_onTouchMove')));
				// handle the end of the value editing
				this._otherEventsHandlers.push(this.on(touch.release, lang.hitch(this, '_onTouchRelease')));
				this._otherEventsHandlers.push(this.on(touch.leave, lang.hitch(this, '_onTouchLeave')));
				this._otherEventsHandlers.push(this.on(touch.cancel, lang.hitch(this, '_onTouchLeave')));
			}
		},

		_onTouchEnter: function(/*Event*/ event){
			this._onTouchStart(event);
			if(event.type !== 'dojotouchover'){
				this._hovering = true;
				domClass.add(this.domNode, this.baseClass + 'Hovered');
			}
			this._enterValue = this.value;
		},

		_onTouchMove: function(/*Event*/ event){
			var newValue = this._coordToValue(event);
			if(this._hovering){
				if(newValue != this._hoveredValue){
					domClass.add(this.domNode, this.baseClass + 'Hovered');
					this._updateStars(newValue, false);
					this._hoveredValue = newValue;
				}
			}else{
				this._setValueAttr(newValue);
			}
		},

		_onTouchRelease: function(/*Event*/ event){
			this._setValueAttr(this._coordToValue(event));
			this._enterValue = this.value;
			if(!this._hovering){
				this._removeEventsHandlers();
			}else{
				domClass.remove(this.domNode, this.baseClass + 'Hovered');
			}
		},

		_onTouchLeave: function(/*Event*/ event){
			if(this._hovering){
				this._hovering = false;
				this._hoveredValue = null;
				domClass.remove(this.domNode, this.baseClass + 'Hovered');
				this._setValueAttr(this._enterValue);
			}
			this._removeEventsHandlers();
		},

		_onKeyDown: function(/*Event*/ event){
			if(array.indexOf(this._incrementKeyCodes, event.keyCode) != -1){
				event.preventDefault();
				this._incrementValue();
			}else if(array.indexOf(this._decrementKeyCodes, event.keyCode) != -1){
				event.preventDefault();
				this._decrementValue();
			}
		},

		_incrementValue: function(){
			if(this.value < this.maximum){
				this.set('value', this.value + (this.editHalfValues ? 0.5 : 1));
			}
		},

		_decrementValue: function(){
			if(this.value > (this.zeroAreaWidth ? 0 : (this.editHalfValues ? 0.5 : 1))){
				this.set('value', this.value - (this.editHalfValues ? 0.5 : 1));
			}
		},

		_coordToValue: function(/*Event*/event){
			var box = domGeometry.position(this.domNode, false);
			var xValue = event.clientX - box.x;
			var rawValue = null, discreteValue;
			// fix off values observed on leave event
			if(xValue < 0){
				xValue = 0;
			}else if(xValue > box.w){
				xValue = box.w;
			}
			if(this._inZeroSettingArea(xValue, box.w)){
				return 0;
			}else{
				rawValue = this._xToRawValue(xValue, box.w);
			}
			if(rawValue != null){
				if(rawValue == 0){
					rawValue = 0.1; // do not allow setting the value to 0 when clicking on a star
				}
				discreteValue = Math.ceil(rawValue);
				if(this.editHalfValues && (discreteValue - rawValue) > 0.5){
					discreteValue -= 0.5;
				}
				return discreteValue;
			}
		},

		_inZeroSettingArea: function(/*Number*/x, /*Number*/domNodeWidth){
			return x < this.zeroAreaWidth;
		},

		_xToRawValue: function(/*Number*/x, /*Number*/domNodeWidth){
			var starStripLength = domNodeWidth - this.zeroAreaWidth;
			return (x - this.zeroAreaWidth) / (starStripLength / this.maximum);
		},

		_setMaximumAttr: function(/*Number*/value){
			this._set("maximum", value);
			this.domNode.setAttribute('aria-valuemax', this.maximum);
			// set value to trigger redrawing of the widget
			this.set("value", this.value);
		},

		_setValueAttr: function(/*Number*/value){
			// summary:
			//		Sets the value of the Rating.
			// tags:
			//		private
			var createChildren = this.domNode.children.length != this.maximum;
			this._set("value", value);
			if(createChildren){
				domConstruct.empty(this.domNode);
			}
			this._updateStars(value, createChildren);
			this.domNode.setAttribute('aria-valuenow', this.value);
			this.domNode.setAttribute('aria-valuetext', string.substitute(messages['aria-valuetext'], this));
		},

		_setEditableAttr: function(/*Boolean*/value){
			this._set("editable", value);
			this.domNode.setAttribute('tabindex', this.editable ? this.tabIndex : -1);
			if(this.editable && !this._keyDownHandler){
				this._keyDownHandler = this.on('keydown', lang.hitch(this, '_onKeyDown'));
			}else if(!this.editable && this._keyDownHandler){
				this._keyDownHandler.remove();
				this._keyDownHandler = null;
			}
			this.domNode.setAttribute('aria-disabled', !this.editable);
			if(this.editable && !this._startHandlers){
				this._startHandlers = [this.on(touch.enter, lang.hitch(this, '_onTouchEnter')),
				                       this.on(touch.press, lang.hitch(this, '_onTouchStart'))];
			}else if(!this.editable && this._startHandlers){
				while(this._startHandlers.length){
					this._startHandlers.pop().remove();
				}
				this._startHandlers = null;
			}
		},

		_setZeroAreaWidthAttr: function(/*Number*/value){
			this._set("zeroAreaWidth", value);
			this.domNode.style.paddingLeft = this.zeroAreaWidth + "px";
		},

		_updateStars: function(/*Number*/value, /*Boolean*/create){
			var i, parent, starClass;
			for(i = 0; i < this.maximum; i++){
				if(i <= value - 1){
					starClass = this.baseClass + "FullStar";
				}else if(i >= value){
					starClass = this.baseClass + "EmptyStar";
				}else{
					starClass = this.baseClass + "HalfStar";
				}
				if(create){
					parent = domConstruct.create("div", {
						style: {"float": "left"}
					}, this.domNode);
				}else{
					parent = this.domNode.children[i];
				}
				parent.className = this.baseClass +  "StarIcon " + starClass;
			}
		}
	});

	return has('dojo-bidi') ? declare([StarRating, BidiStarRating]) : StarRating;
});
<commit_msg>_onTouchStart has been renamed _wireEvents. Comment added.<commit_after>define([
	"dojo/_base/declare",
	"dojo/_base/lang",
	"dojo/_base/array",
	"dojo/string",
	"dojo/has",
	"dojo/on",
	"dojo/touch",
	"dojo/keys",
	"dojo/dom-construct",
	"dojo/dom-class",
	"dojo/dom-geometry",
	"dui/_WidgetBase",
	"dojo/has!dojo-bidi?dui/mobile/bidi/StarRating",
	"dojo/i18n!./nls/StarRating"
], function(declare, lang, array, string, has, on, touch, keys, domConstruct, domClass, domGeometry, WidgetBase, BidiStarRating, messages){

	// module:
	//		dui/mobile/StarRating

	var StarRating = declare(WidgetBase, {
		// summary:
		//		A widget that displays a rating, usually with stars, and that allows setting a different rating value
		//		by touching the stars.
		// description:
		//		This widget shows the rating using an image sprite that contains full stars, half stars and empty stars.
		//		The star displayed can be fully customized by redefining the following css classes in your application:
		//		- duiStarRatingStarIcon: defines the size of each star icon, and the css sprite to use as the background image stars;
		//		- duiStarRatingFullStar: defines the background-position of the css sprite to display a full star icon;
		//		- duiStarRatingHalfStar: defines the background-position of the css sprite to display a half star icon (ltr);
		//		- duiStarRatingHalfStarRtl: defines the background-position of the css sprite to display a half star icon (rtl);
		//		- duiStarRatingEmptyStar: defines the background-position of the css sprite to display an empty star icon.
		//		Note that if your using a different baseClass than the default one 'duiStarRating', you should replace 'duiStarRating'
		//		in the previous css class names with your baseClass value (for example, with a baseClass of 'myClass', the css classes to use
		//		will be myClassStarIcon, myClassFullStar, myClassHalfStar, myClassHalfStarRtl, myClassEmptyStar).
		//
		//		The widget can be used in read-only or in editable mode. In editable mode, the widget allows to set the
		//		rating to 0 stars or not using the zeroAreaWidth property. In this mode, it also allows to set
		//		half values or not using the editHalfValues property.
		//
		//		This widget supports right to left direction.

		// baseClass: String
		//		The name of the CSS class of this widget.
		baseClass: "duiStarRating",

		// maximum: Number
		//		The maximum rating, that is also the number of stars to show.
		maximum: 5,

		// value: Number
		//		The current value of the Rating.
		value: 0,

		// editable: Boolean
		//		Is the user allowed to edit the value of the Rating by touching / clicking the stars ?
		editable: false,

		// editHalfValues: Boolean
		//		If the Rating is editable, is the user allowed to edit half values (0.5, 1.5, ...) or not ?
		editHalfValues: false,

		// zeroAreaWidth: Number
		//		The number of pixel to add to the left of the widget (or right if the direction is rtl) to allow setting the value to 0
		//		when editable is set to true. Default value is 0 if the widget is not editable, 20 if the widget is editable.
		//		Set this value to 0 to forbid the user from setting the value to zero during edition. Setting this attribute to a negative
		//		value is not supported.
		zeroAreaWidth: null,

		// tabIndex: Number
		//		The tabindex of the widget node (set when the widget is in editable mode), for keyboard navigation order in the page.
		tabIndex: 0,

		/* internal properties */

		_enterValue: null,
		_hovering: false,
		_hoveredValue: null,
		_startHandlers: null,
		_otherEventsHandlers: [],
		_keyDownHandler: null,
		_incrementKeyCodes: [keys.RIGHT_ARROW, keys.UP_ARROW, keys.NUMPAD_PLUS], // keys to press to increment value
		_decrementKeyCodes: [keys.LEFT_ARROW, keys.DOWN_ARROW, keys.NUMPAD_MINUS], // keys to press to decrement value

		postMixInProperties: function(){
			if(this.zeroAreaWidth == null){
				this.zeroAreaWidth = this.editable ? 20 : 0;
			}
		},

		buildRendering: function(){
			this.inherited(arguments);
			this.domNode.style.display = "inline-block";
			// init WAI-ARIA attributes
			this.domNode.setAttribute('role', 'slider');
			this.domNode.setAttribute('aria-label', messages['aria-label']);
			this.domNode.setAttribute('aria-valuemin', 0);
			this.domNode.setAttribute('aria-valuemax', this.maximum);
			this.domNode.setAttribute('aria-valuenow', this.value);
			this.domNode.setAttribute('aria-valuetext', string.substitute(messages['aria-valuetext'], this));
			this.domNode.setAttribute('aria-disabled', !this.editable);
			// keyboard navigation
			this.domNode.setAttribute('tabindex', this.editable ? this.tabIndex : -1);
			this._keyDownHandler = this.on('keydown', lang.hitch(this, '_onKeyDown'));
		},

		_removeEventsHandlers: function(){
			while(this._otherEventsHandlers.length){
				this._otherEventsHandlers.pop().remove();
			}
		},

		_wireHandlers: function(/*Event*/ event){
			event.preventDefault();
			if(!this._otherEventsHandlers.length){
				// handle move on the stars strip
				this._otherEventsHandlers.push(this.on(touch.move, lang.hitch(this, '_onTouchMove')));
				// handle the end of the value editing
				this._otherEventsHandlers.push(this.on(touch.release, lang.hitch(this, '_onTouchRelease')));
				this._otherEventsHandlers.push(this.on(touch.leave, lang.hitch(this, '_onTouchLeave')));
				this._otherEventsHandlers.push(this.on(touch.cancel, lang.hitch(this, '_onTouchLeave')));
			}
		},

		_onTouchEnter: function(/*Event*/ event){
			this._wireHandlers(event);
			if(event.type !== 'dojotouchover'){ // Note: this will be replaced by a test on event.pointerType when we'll implement the pointer event spec in dojo.
				this._hovering = true;
				domClass.add(this.domNode, this.baseClass + 'Hovered');
			}
			this._enterValue = this.value;
		},

		_onTouchMove: function(/*Event*/ event){
			var newValue = this._coordToValue(event);
			if(this._hovering){
				if(newValue != this._hoveredValue){
					domClass.add(this.domNode, this.baseClass + 'Hovered');
					this._updateStars(newValue, false);
					this._hoveredValue = newValue;
				}
			}else{
				this._setValueAttr(newValue);
			}
		},

		_onTouchRelease: function(/*Event*/ event){
			this._setValueAttr(this._coordToValue(event));
			this._enterValue = this.value;
			if(!this._hovering){
				this._removeEventsHandlers();
			}else{
				domClass.remove(this.domNode, this.baseClass + 'Hovered');
			}
		},

		_onTouchLeave: function(/*Event*/ event){
			if(this._hovering){
				this._hovering = false;
				this._hoveredValue = null;
				domClass.remove(this.domNode, this.baseClass + 'Hovered');
				this._setValueAttr(this._enterValue);
			}
			this._removeEventsHandlers();
		},

		_onKeyDown: function(/*Event*/ event){
			if(array.indexOf(this._incrementKeyCodes, event.keyCode) != -1){
				event.preventDefault();
				this._incrementValue();
			}else if(array.indexOf(this._decrementKeyCodes, event.keyCode) != -1){
				event.preventDefault();
				this._decrementValue();
			}
		},

		_incrementValue: function(){
			if(this.value < this.maximum){
				this.set('value', this.value + (this.editHalfValues ? 0.5 : 1));
			}
		},

		_decrementValue: function(){
			if(this.value > (this.zeroAreaWidth ? 0 : (this.editHalfValues ? 0.5 : 1))){
				this.set('value', this.value - (this.editHalfValues ? 0.5 : 1));
			}
		},

		_coordToValue: function(/*Event*/event){
			var box = domGeometry.position(this.domNode, false);
			var xValue = event.clientX - box.x;
			var rawValue = null, discreteValue;
			// fix off values observed on leave event
			if(xValue < 0){
				xValue = 0;
			}else if(xValue > box.w){
				xValue = box.w;
			}
			if(this._inZeroSettingArea(xValue, box.w)){
				return 0;
			}else{
				rawValue = this._xToRawValue(xValue, box.w);
			}
			if(rawValue != null){
				if(rawValue == 0){
					rawValue = 0.1; // do not allow setting the value to 0 when clicking on a star
				}
				discreteValue = Math.ceil(rawValue);
				if(this.editHalfValues && (discreteValue - rawValue) > 0.5){
					discreteValue -= 0.5;
				}
				return discreteValue;
			}
		},

		_inZeroSettingArea: function(/*Number*/x, /*Number*/domNodeWidth){
			return x < this.zeroAreaWidth;
		},

		_xToRawValue: function(/*Number*/x, /*Number*/domNodeWidth){
			var starStripLength = domNodeWidth - this.zeroAreaWidth;
			return (x - this.zeroAreaWidth) / (starStripLength / this.maximum);
		},

		_setMaximumAttr: function(/*Number*/value){
			this._set("maximum", value);
			this.domNode.setAttribute('aria-valuemax', this.maximum);
			// set value to trigger redrawing of the widget
			this.set("value", this.value);
		},

		_setValueAttr: function(/*Number*/value){
			// summary:
			//		Sets the value of the Rating.
			// tags:
			//		private
			var createChildren = this.domNode.children.length != this.maximum;
			this._set("value", value);
			if(createChildren){
				domConstruct.empty(this.domNode);
			}
			this._updateStars(value, createChildren);
			this.domNode.setAttribute('aria-valuenow', this.value);
			this.domNode.setAttribute('aria-valuetext', string.substitute(messages['aria-valuetext'], this));
		},

		_setEditableAttr: function(/*Boolean*/value){
			this._set("editable", value);
			this.domNode.setAttribute('tabindex', this.editable ? this.tabIndex : -1);
			if(this.editable && !this._keyDownHandler){
				this._keyDownHandler = this.on('keydown', lang.hitch(this, '_onKeyDown'));
			}else if(!this.editable && this._keyDownHandler){
				this._keyDownHandler.remove();
				this._keyDownHandler = null;
			}
			this.domNode.setAttribute('aria-disabled', !this.editable);
			if(this.editable && !this._startHandlers){
				this._startHandlers = [this.on(touch.enter, lang.hitch(this, '_onTouchEnter')),
				                       this.on(touch.press, lang.hitch(this, '_wireHandlers'))];
			}else if(!this.editable && this._startHandlers){
				while(this._startHandlers.length){
					this._startHandlers.pop().remove();
				}
				this._startHandlers = null;
			}
		},

		_setZeroAreaWidthAttr: function(/*Number*/value){
			this._set("zeroAreaWidth", value);
			this.domNode.style.paddingLeft = this.zeroAreaWidth + "px";
		},

		_updateStars: function(/*Number*/value, /*Boolean*/create){
			var i, parent, starClass;
			for(i = 0; i < this.maximum; i++){
				if(i <= value - 1){
					starClass = this.baseClass + "FullStar";
				}else if(i >= value){
					starClass = this.baseClass + "EmptyStar";
				}else{
					starClass = this.baseClass + "HalfStar";
				}
				if(create){
					parent = domConstruct.create("div", {
						style: {"float": "left"}
					}, this.domNode);
				}else{
					parent = this.domNode.children[i];
				}
				parent.className = this.baseClass +  "StarIcon " + starClass;
			}
		}
	});

	return has('dojo-bidi') ? declare([StarRating, BidiStarRating]) : StarRating;
});
<|endoftext|>


<commit_before>

function mahrioRun ($rootScope, $ionicPlatform, $location, Users, Socket, Notification) {

  $ionicPlatform.ready(function(){

    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    console.log("ionicPlatform is ready");
    if(window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);

    }

    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }

    if (window.analytics != undefined) {
      console.log("windows.analytics loading...");
      window.analytics.startTrackerWithId('UA-YOURCODEHERE');
      window.analytics.trackView('Testing')
    } else {
      console.log("window.analytics is undefined");
    }

    Users.getCurrent().then( function(){
      console.log('current user loaded');
      $rootScope.$broadcast('event:user:loaded');
      Socket.watchNotificationEvents( Users.getCurrentId(), function(){
        $location.path('/tab/dash');
      });
    }, function(){
      $location.path('/offline');
    });
  });
}

mahrioRun.$inject=['$rootScope', '$ionicPlatform', '$location', 'Users', 'Socket', 'Notification'];

angular.module('starter', [
  'ionic',
  'starter.controllers',
  'starter.services',
  'starter.directives',
  'angular-underscore'])
  .constant('APP_IP', 'http://123.456.789.0:8042')
  .constant('_', window._)
  .run(mahrioRun)
  .config(function($stateProvider, $urlRouterProvider) {

  // Ionic uses AngularUI Router which uses the concept of states
  // Learn more here: https://github.com/angular-ui/ui-router
  // Set up the various states which the app can be in.
  // Each state's controller can be found in controllers.js
  $stateProvider

  // setup an abstract state for the tabs directive
    .state('tab', {
      url: '/tab',
      abstract: true,
      templateUrl: 'templates/tabs.html'
    })

  // Each tab has its own nav history stack:

    .state('tab.dash', {
      url: '/dash',
      views: {
        'tab-dash': {
          templateUrl: 'templates/tab-dash.html',
          controller: 'DashCtrl'
        }
      }
    })
    .state('tab.articles', {
      url: '/articles?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-articles.html'
        }
      }
    })
    .state('tab.article', {
      url: '/article/:articleId?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/article-detail.html',
          controller: 'ArticleDetailCtrl'
        }
      }
    })
    .state('tab.boards', {
      url: '/boards?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-boards.html'
        }
      }
    })
    .state('tab.board', {
      url: '/board/:boardId?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/board-detail.html',
          controller: 'BoardDetailCtrl'
        }
      }
    })
    .state('tab.events', {
      url: '/events?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-events.html'
        }
      }
    })
    .state('tab.event', {
      url: '/event/:eventId?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/event-detail.html',
          controller: 'EventDetailCtrl'
        }
      }
    })
    .state('tab.appliances', {
      url: '/appliances?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-hardware.html'
        }
      }
    })
    .state('tab.appliance', {
      url: '/appliance/:applianceId?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/hardware-detail.html',
          controller: 'HardwareDetailCtrl'
        }
      }
    })
    .state('tab.members', {
      url: '/members?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-members.html'
        }
      }
    })
    .state('tab.member', {
      url: '/member/:memberId?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/member-detail.html',
          controller: 'MemberDetailCtrl'
        }
      }
    })
    .state('tab.networks', {
      url: '/networks',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-network.html',
          controller: 'NetworksCtrl'
        }
      }
    })
    .state('tab.network', {
      url: '/network/:networkId',
      views: {
        'tab-networks': {
          templateUrl: 'templates/network-detail.html',
          controller: 'NetworkDetailCtrl'
        }
      }
    })
    .state('tab.chats', {
      url: '/chats',
      views: {
        'tab-chats': {
          templateUrl: 'templates/tab-chats.html',
          controller: 'ChatsCtrl'
        }
      }
    })
    .state('chat-detail', {
      url: '/chats/:chatId',
      templateUrl: 'templates/chat-detail.html',
      controller: 'ChatsDetailCtrl'
    })
    .state('tab.search', {
      url: '/search',
      views: {
        'tab-search': {
          templateUrl: 'templates/tab-search.html',
          controller: 'SearchCtrl'
        }
      }
    })
    .state('tab.account', {
      url: '/account',
      views: {
        'tab-account': {
          templateUrl: 'templates/tab-account.html',
          controller: 'AccountCtrl'
        }
      }
    })
    .state('tab.profile', {
      url: '/profile',
      views: {
        'tab-account': {
          templateUrl: 'templates/member-detail.html',
          controller: 'MemberDetailCtrl'
        }
      }
    })
    .state('offline', {
      url: '/offline',
      templateUrl: 'templates/offline.html',
      controller: 'OfflineCtrl'
    });

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/tab/dash');

});
<commit_msg>mobile - white listed protocols & cleanup<commit_after>

function mahrioRun ($rootScope, $ionicPlatform, $location, Users, Socket) {

  $ionicPlatform.ready(function(){

    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    console.log("ionicPlatform is ready");
    if(window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);

    }

    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }

    if (window.analytics != undefined) {
      console.log("windows.analytics loading...");
      window.analytics.startTrackerWithId('UA-YOURCODEHERE');
      window.analytics.trackView('Testing')
    } else {
      console.log("window.analytics is undefined");
    }

    Users.getCurrent().then( function(){
      console.log('current user loaded');
      $rootScope.$broadcast('event:user:loaded');
      Socket.watchNotificationEvents( Users.getCurrentId(), function(){
        $location.path('/tab/dash');
      });
    }, function(){
      $location.path('/offline');
    });
  });
}

mahrioRun.$inject=['$rootScope', '$ionicPlatform', '$location', 'Users', 'Socket', 'Notification'];

angular.module('starter', [
  'ionic',
  'starter.controllers',
  'starter.services',
  'starter.directives',
  'starter.filters',
  'angular-underscore'])
  .constant('APP_IP', 'http://123.456.789.0:8042')
  .constant('_', window._)
  .run(mahrioRun)
  .config(function($stateProvider, $urlRouterProvider, $compileProvider) {

    $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel):/);
  // Ionic uses AngularUI Router which uses the concept of states
  // Learn more here: https://github.com/angular-ui/ui-router
  // Set up the various states which the app can be in.
  // Each state's controller can be found in controllers.js
  $stateProvider

  // setup an abstract state for the tabs directive
    .state('tab', {
      url: '/tab',
      abstract: true,
      templateUrl: 'templates/tabs.html'
    })

  // Each tab has its own nav history stack:

    .state('tab.dash', {
      url: '/dash',
      views: {
        'tab-dash': {
          templateUrl: 'templates/tab-dash.html',
          controller: 'DashCtrl'
        }
      }
    })
    .state('tab.articles', {
      url: '/articles?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-articles.html'
        }
      }
    })
    .state('tab.article', {
      url: '/article/:articleId?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/article-detail.html',
          controller: 'ArticleDetailCtrl'
        }
      }
    })
    .state('tab.boards', {
      url: '/boards?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-boards.html'
        }
      }
    })
    .state('tab.board', {
      url: '/board/:boardId?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/board-detail.html',
          controller: 'BoardDetailCtrl'
        }
      }
    })
    .state('tab.events', {
      url: '/events?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-events.html'
        }
      }
    })
    .state('tab.event', {
      url: '/event/:eventId?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/event-detail.html',
          controller: 'EventDetailCtrl'
        }
      }
    })
    .state('tab.appliances', {
      url: '/appliances?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-hardware.html'
        }
      }
    })
    .state('tab.appliance', {
      url: '/appliance/:applianceId?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/hardware-detail.html',
          controller: 'HardwareDetailCtrl'
        }
      }
    })
    .state('tab.members', {
      url: '/members?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-members.html'
        }
      }
    })
    .state('tab.member', {
      url: '/member/:memberId?network',
      views: {
        'tab-networks': {
          templateUrl: 'templates/member-detail.html',
          controller: 'MemberDetailCtrl'
        }
      }
    })
    .state('tab.networks', {
      url: '/networks',
      views: {
        'tab-networks': {
          templateUrl: 'templates/tab-network.html',
          controller: 'NetworksCtrl'
        }
      }
    })
    .state('tab.network', {
      url: '/network/:networkId',
      views: {
        'tab-networks': {
          templateUrl: 'templates/network-detail.html',
          controller: 'NetworkDetailCtrl'
        }
      }
    })
    .state('tab.chats', {
      url: '/chats',
      views: {
        'tab-chats': {
          templateUrl: 'templates/tab-chats.html',
          controller: 'ChatsCtrl'
        }
      }
    })
    .state('chat-detail', {
      url: '/chats/:chatId',
      templateUrl: 'templates/chat-detail.html',
      controller: 'ChatsDetailCtrl'
    })
    .state('tab.search', {
      url: '/search',
      views: {
        'tab-search': {
          templateUrl: 'templates/tab-search.html',
          controller: 'SearchCtrl'
        }
      }
    })
    .state('tab.account', {
      url: '/account',
      views: {
        'tab-account': {
          templateUrl: 'templates/tab-account.html',
          controller: 'AccountCtrl'
        }
      }
    })
    .state('tab.profile', {
      url: '/profile',
      views: {
        'tab-account': {
          templateUrl: 'templates/member-detail.html',
          controller: 'MemberDetailCtrl'
        }
      }
    })
    .state('offline', {
      url: '/offline',
      templateUrl: 'templates/offline.html',
      controller: 'OfflineCtrl'
    });

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/tab/dash');

});
<|endoftext|>