<commit_before>/** @jsx element */

import {initializeApp, refresh, setToast, setModalMessage} from './actions'
import HeaderElement from './components/HeaderElement'
import PrintContainer from './pages/PrintContainer'
import PlaylistLoader from './pages/PlaylistLoader'
import CreateModal from './components/CreateModal'
import ProfileLoader from './pages/ProfileLoader'
import PlaylistView from './pages/PlaylistView'
import LinkDecipher from './pages/LinkDecipher'
import CodeLink from './components/CodeLink'
import {setUrl} from 'redux-effects-location'
import ProjectPage from './pages/ProjectPage'
import GameLoader from './pages/GameLoader'
import SearchPage from './pages/SearchPage'
import Loading from './components/Loading'
import {Block, Text, Toast} from 'vdux-ui'
import {signOut} from './middleware/auth'
import Transition from 'vdux-transition'
import Header from './components/Header'
import HomePage from './pages/Explore'
import Auth from './components/Auth'
import Create from './pages/Create'
import element from 'vdux/element'
import enroute from 'enroute'

import createAction from '@f/create-action'

const startLogin = createAction('START_LOGIN')
const endLogin = createAction('END_LOGIN')

function onUpdate (prev, {state}) {
  if (prev.state.title !== state.title) {
    document.title = state.title
  }
}

const initialState = () => ({loggingIn: false})

const router = enroute({
  '/featured': () => <HomePage tab='featured' />,
  '/featured/:project': ({project}) => (
    <HomePage tab='featured' project={project} />
  ),
  '/shared': () => <HomePage tab='shared' />,
  '/create/:draftID': ({draftID, step}, props) => (
    <Create mine new left='60px' draftID={draftID} {...props} />
  ),
  '/create/:draftID/:step': ({draftID, step}, props) => (
    <Create mine new left='60px' draftID={draftID} step={step} {...props} />
  ),
  '/edit/:draftID/:step': ({draftID, step}, props) => (
    <Create mine left='60px' draftID={draftID} step={step} {...props} />
  ),
  '/edit/:draftID': ({draftID, step}, props) => (
    <Create mine left='60px' draftID={draftID} {...props} />
  ),
  '/search': (params, props) => (
    <SearchPage user={props.user} />
  ),
  '/search/:searchType': ({searchType}, props) => (
    <SearchPage searchType={searchType} user={props.user} />
  ),
  '/search/:searchType/:searchQ': ({searchType, searchQ}, props) => (
    <SearchPage searchType={searchType} searchQ={searchQ} user={props.user} />
  ),
  '/playlist/:playlistID': ({playlistID, username}, props) => (
    <PlaylistView w='80%' minWidth='680px' margin='0 auto' activeKey={playlistID} uid={props.user.uid} />
  ),
  '/games/:gameID': ({gameID}, props) => (
    <ProjectPage gameRef={gameID} />
  ),
  '/playSequence/:listID': ({listID}, props) => (
    <PlaylistLoader {...props} playlistRef={listID} uid={props.user} ref='nothing' />
  ),
  '/play/:gameID': ({gameID}, props) => (
    <GameLoader
      {...props}
      completed={
        props.profile.completed &&
        props.profile.completed[gameID] &&
        props.profile.completed[gameID].saveRef
      }
      key={`gameLoader${gameID}`}
      gameCode={gameID} />
  ),
  '/:username/:activity': ({username, activity}, props) => (
    <ProfileLoader mine={props.user.username === username} params={activity} uid={props.user} username={username} />
  ),
  '/:username/:activity/:category': ({username, activity, category}, props) => (
    <ProfileLoader
      params={activity}
      category={category}
      uid={props.user}
      username={username} />
  ),
  '/:link': ({link}, props) => <LinkDecipher link={link} {...props} />,
  '*': homePage
})

function homePage (params, props) {
  if (!props.user || props.username === undefined || (!props.user && !props.profile)) {
    return <Loading />
  }
  return <HomePage {...props} />
}

function onCreate () {
  return initializeApp()
}

function render ({props, state, local}) {
  const {loggingIn} = state
  const {message, url, toast, user, username} = props
  const activeRoute = url.split('/')[1]

  if (!props.user || props.username === undefined || (!props.user && !props.profile)) {
    return <Loading />
  }

  return (
    <Block tall wide>
      <PrintContainer code={!!props.game && props.game.animals[0].sequence} />
      <Header w='80px' top='0' left='0'>
        <Block flex>
          <HeaderElement
            text='Home'
            icon='home'
            active={activeRoute === 'featured'}
            handleClick={[() => setUrl('/'), refresh]} />
          <HeaderElement active={activeRoute === 'search'} onClick={() => setUrl('/search/games')} text='Search' icon='search' />
          {(user && !user.isAnonymous) &&
            <Block>
              <HeaderElement
                active={activeRoute === username}
                onClick={() => activeRoute !== username && setUrl(`/${username}/studio`)}
                text='Profile'
                icon='dashboard' />
              <HeaderElement active={activeRoute === 'create'} onClick={() => setModalMessage(<CreateModal />)} text='Create' icon='add' />
            </Block>
          }
        </Block>
        <HeaderElement onClick={() => setModalMessage(<CodeLink />)} mb='0' text='Code' icon='link' />
        {!user || user.isAnonymous
          ? <HeaderElement handleClick={local(startLogin)} text='Sign In' icon='person_outline' />
          : <HeaderElement handleClick={signOutClick} text='Sign Out' icon='exit_to_app' />
        }
      </Header>
      <Block id='action-bar-holder' class='action-bar-holder' tall overflowY='auto' relative left='80px' column align='start' minHeight='100%' w='calc(100% - 80px)'>
        {
        (url && user) && router(url, props)
      }
      </Block>
      {
        message && message
      }
      {
        loggingIn && <Auth handleDismiss={local(endLogin)} />
      }
      <Transition>
        {toast !== '' && <Toast
          fixed
          minHeight='none'
          w='200px'
          textAlign='center'
          bgColor='#333'
          color='white'
          top='8px'
          bottom='none'
          key='0'
          onDismiss={() => setToast('')}>
          <Text>{toast}</Text>
        </Toast>}
      </Transition>
    </Block>
  )
}

function * signOutClick () {
  yield setUrl('/')
  yield signOut()
}

function reducer (state, action) {
  if (action.type === startLogin.type) {
    return {
      ...state,
      loggingIn: true
    }
  } else if (action.type === endLogin.type) {
    return {
      ...state,
      loggingIn: false
    }
  }
}

// <HeaderElement active={activeRoute === 'sandbox'} onClick={[() => setUrl('/sandbox'), refresh]} text='Sandbox' icon='play_circle_outline'/>

export default {
  initialState,
  onUpdate,
  reducer,
  onCreate,
  render
}
<commit_msg>fix not logged in<commit_after>/** @jsx element */

import {initializeApp, refresh, setToast, setModalMessage} from './actions'
import HeaderElement from './components/HeaderElement'
import PrintContainer from './pages/PrintContainer'
import PlaylistLoader from './pages/PlaylistLoader'
import CreateModal from './components/CreateModal'
import ProfileLoader from './pages/ProfileLoader'
import PlaylistView from './pages/PlaylistView'
import LinkDecipher from './pages/LinkDecipher'
import CodeLink from './components/CodeLink'
import {setUrl} from 'redux-effects-location'
import ProjectPage from './pages/ProjectPage'
import GameLoader from './pages/GameLoader'
import SearchPage from './pages/SearchPage'
import Loading from './components/Loading'
import {Block, Text, Toast} from 'vdux-ui'
import {signOut} from './middleware/auth'
import Transition from 'vdux-transition'
import Header from './components/Header'
import HomePage from './pages/Explore'
import Auth from './components/Auth'
import Create from './pages/Create'
import element from 'vdux/element'
import enroute from 'enroute'

import createAction from '@f/create-action'

const startLogin = createAction('START_LOGIN')
const endLogin = createAction('END_LOGIN')

function onUpdate (prev, {state}) {
  if (prev.state.title !== state.title) {
    document.title = state.title
  }
}

const initialState = () => ({loggingIn: false})

const router = enroute({
  '/featured': () => <HomePage tab='featured' />,
  '/featured/:project': ({project}) => (
    <HomePage tab='featured' project={project} />
  ),
  '/shared': () => <HomePage tab='shared' />,
  '/create/:draftID': ({draftID, step}, props) => (
    <Create mine new left='60px' draftID={draftID} {...props} />
  ),
  '/create/:draftID/:step': ({draftID, step}, props) => (
    <Create mine new left='60px' draftID={draftID} step={step} {...props} />
  ),
  '/edit/:draftID/:step': ({draftID, step}, props) => (
    <Create mine left='60px' draftID={draftID} step={step} {...props} />
  ),
  '/edit/:draftID': ({draftID, step}, props) => (
    <Create mine left='60px' draftID={draftID} {...props} />
  ),
  '/search': (params, props) => (
    <SearchPage user={props.user} />
  ),
  '/search/:searchType': ({searchType}, props) => (
    <SearchPage searchType={searchType} user={props.user} />
  ),
  '/search/:searchType/:searchQ': ({searchType, searchQ}, props) => (
    <SearchPage searchType={searchType} searchQ={searchQ} user={props.user} />
  ),
  '/playlist/:playlistID': ({playlistID, username}, props) => (
    <PlaylistView w='80%' minWidth='680px' margin='0 auto' activeKey={playlistID} uid={props.user.uid} />
  ),
  '/games/:gameID': ({gameID}, props) => (
    <ProjectPage gameRef={gameID} />
  ),
  '/playSequence/:listID': ({listID}, props) => (
    <PlaylistLoader {...props} playlistRef={listID} uid={props.user} ref='nothing' />
  ),
  '/play/:gameID': ({gameID}, props) => (
    <GameLoader
      {...props}
      completed={
        props.profile.completed &&
        props.profile.completed[gameID] &&
        props.profile.completed[gameID].saveRef
      }
      key={`gameLoader${gameID}`}
      gameCode={gameID} />
  ),
  '/:username/:activity': ({username, activity}, props) => (
    <ProfileLoader mine={props.user.username === username} params={activity} uid={props.user} username={username} />
  ),
  '/:username/:activity/:category': ({username, activity, category}, props) => (
    <ProfileLoader
      params={activity}
      category={category}
      uid={props.user}
      username={username} />
  ),
  '/:link': ({link}, props) => <LinkDecipher link={link} {...props} />,
  '*': homePage
})

function homePage (params, props) {
  if (!props.user || props.username === undefined || (!props.user && !props.profile)) {
    return <Loading />
  }
  return <HomePage {...props} />
}

function onCreate () {
  return initializeApp()
}

function render ({props, state, local}) {
  const {loggingIn} = state
  const {message, url, toast, user, username} = props
  const activeRoute = url.split('/')[1]

  if (!props.user || props.username === undefined || (!props.user && !props.profile)) {
    return <Loading />
  }

  return (
    <Block tall wide>
      <PrintContainer code={!!props.game && props.game.animals[0].sequence} />
      <Header w='80px' top='0' left='0'>
        <Block flex>
          <HeaderElement
            text='Home'
            icon='home'
            active={activeRoute === 'featured'}
            handleClick={[() => setUrl('/'), refresh]} />
          <HeaderElement active={activeRoute === 'search'} onClick={() => setUrl('/search/games')} text='Search' icon='search' />
          {(user && username) &&
            <Block>
              <HeaderElement
                active={activeRoute === username}
                onClick={() => activeRoute !== username && setUrl(`/${username}/studio`)}
                text='Profile'
                icon='dashboard' />
              <HeaderElement active={activeRoute === 'create'} onClick={() => setModalMessage(<CreateModal />)} text='Create' icon='add' />
            </Block>
          }
        </Block>
        <HeaderElement onClick={() => setModalMessage(<CodeLink />)} mb='0' text='Code' icon='link' />
        {!user || !username
          ? <HeaderElement handleClick={local(startLogin)} text='Sign In' icon='person_outline' />
          : <HeaderElement handleClick={signOutClick} text='Sign Out' icon='exit_to_app' />
        }
      </Header>
      <Block id='action-bar-holder' class='action-bar-holder' tall overflowY='auto' relative left='80px' column align='start' minHeight='100%' w='calc(100% - 80px)'>
        {
        (url && user) && router(url, props)
      }
      </Block>
      {
        message && message
      }
      {
        loggingIn && <Auth handleDismiss={local(endLogin)} />
      }
      <Transition>
        {toast !== '' && <Toast
          fixed
          minHeight='none'
          w='200px'
          textAlign='center'
          bgColor='#333'
          color='white'
          top='8px'
          bottom='none'
          key='0'
          onDismiss={() => setToast('')}>
          <Text>{toast}</Text>
        </Toast>}
      </Transition>
    </Block>
  )
}

function * signOutClick () {
  yield setUrl('/')
  yield signOut()
}

function reducer (state, action) {
  if (action.type === startLogin.type) {
    return {
      ...state,
      loggingIn: true
    }
  } else if (action.type === endLogin.type) {
    return {
      ...state,
      loggingIn: false
    }
  }
}

// <HeaderElement active={activeRoute === 'sandbox'} onClick={[() => setUrl('/sandbox'), refresh]} text='Sandbox' icon='play_circle_outline'/>

export default {
  initialState,
  onUpdate,
  reducer,
  onCreate,
  render
}
<|endoftext|>


<commit_before>/*global define*/
'use strict';

define([
	'jquery',
	'backbone',
	'underscore'
], function ($, Backbone, _) {

	var R = Backbone.Router.extend({

		/**
		 * Routes to listen to
		 * @type {Object}
		 */
		routes: {
			'': 'home'
		},

		/**
		 * History of known routes
		 * @type {Array}
		 */
		knownHistory: [],

		/**
		 * Is this enabled?
		 * @type {Boolean}
		 */
		enabled: true,

		/**
		 * Initialize the router
		 */
		initialize: function () {

		},

		/**
		 * Navigate to the default route
		 */
		defaultRoute: function () {

			var def = this.routes[''];

			if (def) {
				this.redirect(def);
			}
		},

		/**
		 * Navigate override to maintain a history
		 * @param {String} route
		 * @param {Object} options
		 */
		navigate: function (route, options) {

			var noTrack = options.noTrack || undefined;

			if (noTrack !== false) {
				this.knownHistory.push(route);
			}

			Backbone.Router.prototype.navigate.apply(this, arguments);
		},

		/**
		 * Get the current route
		 */
		currentRoute: function() {
			var Router = this,
				fragment = Backbone.history.fragment,
				routes = _.pairs(Router.routes),
				route = null, params = null, matched;

			matched = _.find(routes, function(handler) {
				route = _.isRegExp(handler[0]) ? handler[0] : Router._routeToRegExp(handler[0]);
				return route.test(fragment);
			});

			if(matched) {
				// NEW: Extracts the params using the internal
				// function _extractParameters
				params = Router._extractParameters(route, fragment);
				route = matched[1];
			}

			return {
				route : route,
				fragment : fragment,
				params : params
			};
		},

		/**
		 * Get the current route fragment
		 */
		current: function () {
			return this.currentRoute().fragment;
		},

		/**
		 * Get the previous route fragment
		 */
		previous: function () {
			return _.last(this.knownHistory);
		},

		/**
		 * Redirect the user to a route. Same as navigate but with a guaranteed trigger.
		 * @param {String} path
		 * @param {Boolean} noTrack
		 */
		link: function (path, noTrack) {

			if (!this.enabled) {
				return;
			}

			if (this.knownHistory.length === 0) {
				this.knownHistory.push(this.current());
			}

			path = path || this.routes[''];

			if (path) {
				this.navigate(path, {trigger: true, noTrack: noTrack});
			}
		},

		/**
		 * Redirect the user to a route. Same as navigate but with a guaranteed trigger.
		 * @param {String} path
		 * @param {Boolean} noTrack
		 */
		redirect: function (path, noTrack) {

			if (!this.enabled) {
				return;
			}

			if (this.knownHistory.length === 0) {
				this.knownHistory.push(this.current());
			}

			path = path || this.routes[''];

			if (path) {
				this.navigate(path, {trigger: true, replace: true, noTrack: noTrack});
			}
		}
	});

	return R;
});<commit_msg>expand history<commit_after>/*global define*/
'use strict';

define([
	'jquery',
	'backbone',
	'underscore'
], function ($, Backbone, _) {

	var R = Backbone.Router.extend({

		/**
		 * Routes to listen to
		 * @type {Object}
		 */
		routes: {
			'': 'home'
		},

		/**
		 * History of known routes
		 * @type {Array}
		 */
		knownHistory: [],

		/**
		 * If the last route was supposed to not be tracked, store it here so
		 * that we don't accidentally track it in the loadUrl override
		 * @type {String}
		 */
		lastUntracked: null,

		/**
		 * Is this enabled?
		 * @type {Boolean}
		 */
		enabled: true,

		/**
		 * Initialize the router
		 */
		initialize: function () {

		},

		/**
		 * Navigate to the default route
		 */
		defaultRoute: function () {

			var def = this.routes[''];

			if (def) {
				this.redirect(def);
			}
		},

		/**
		 * Load URL override to store history of all fragments, not just those called internally
		 * @param {String} fragment [description]
		 */
		loadUrl: function (fragment) {

			// Don't add a duplicate and don't add something that is supposed to be untracked
			if (this.previous() !== fragment && this.lastUntracked !== fragment) {
				this.knownHistory.push(fragment);
			}

			Backbone.Router.prototype.loadUrl.apply(this, arguments);
		},

		/**
		 * Navigate override to maintain a history
		 * @param {String} fragment
		 * @param {Object} options
		 */
		navigate: function (fragment, options) {

			var noTrack = options.noTrack || undefined;

			if (noTrack !== false) {
				this.knownHistory.push(fragment);
				this.lastUntracked = null;
			}
			else {
				this.lastUntracked = fragment;
			}

			Backbone.Router.prototype.navigate.apply(this, arguments);
		},

		/**
		 * Get the current route
		 */
		currentRoute: function() {
			var Router = this,
				fragment = Backbone.history.fragment,
				routes = _.pairs(Router.routes),
				route = null, params = null, matched;

			matched = _.find(routes, function(handler) {
				route = _.isRegExp(handler[0]) ? handler[0] : Router._routeToRegExp(handler[0]);
				return route.test(fragment);
			});

			if(matched) {
				// NEW: Extracts the params using the internal
				// function _extractParameters
				params = Router._extractParameters(route, fragment);
				route = matched[1];
			}

			return {
				route : route,
				fragment : fragment,
				params : params
			};
		},

		/**
		 * Get the current route fragment
		 */
		current: function () {
			return this.currentRoute().fragment;
		},

		/**
		 * Get the previous route fragment
		 */
		previous: function () {
			return _.last(this.knownHistory);
		},

		/**
		 * Redirect the user to a route. Same as navigate but with a guaranteed trigger.
		 * @param {String} path
		 * @param {Boolean} noTrack
		 */
		link: function (path, noTrack) {

			if (!this.enabled) {
				return;
			}

			if (this.knownHistory.length === 0) {
				this.knownHistory.push(this.current());
			}

			path = path || this.routes[''];

			if (path) {
				this.navigate(path, {trigger: true, noTrack: noTrack});
			}
		},

		/**
		 * Redirect the user to a route. Same as navigate but with a guaranteed trigger.
		 * @param {String} path
		 * @param {Boolean} noTrack
		 */
		redirect: function (path, noTrack) {

			if (!this.enabled) {
				return;
			}

			if (this.knownHistory.length === 0) {
				this.knownHistory.push(this.current());
			}

			path = path || this.routes[''];

			if (path) {
				this.navigate(path, {trigger: true, replace: true, noTrack: noTrack});
			}
		}
	});

	return R;
});<|endoftext|>


<commit_before>//straight compile from coffeescript, temporary
var  __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

function SelectionHelper(options) {
    this.highlightObjectAt = __bind(this.highlightObjectAt, this);

    this.selectObjectAt = __bind(this.selectObjectAt, this);

    this.getObjectAt = __bind(this.getObjectAt, this);

    this.isThereObjectAt = __bind(this.isThereObjectAt, this);

    this.get2DBB = __bind(this.get2DBB, this);

    this.getScreenCoords = __bind(this.getScreenCoords, this);

    this._get3DBB = __bind(this._get3DBB, this);

    this._unSelect = __bind(this._unSelect, this);

    this._onSelect = __bind(this._onSelect, this);

    this._unHover = __bind(this._unHover, this);

    this._onHover = __bind(this._onHover, this);

    var defaults;
    //SelectionHelper.__super__.constructor.call(this, options);
    defaults = {
      hiearchyRoot: null,
      camera: null,
      viewWidth: 640,
      viewHeight: 480
    };
    //options = merge(defaults, options);

    this.hiearchyRoot = options.hiearchyRoot, this.camera = options.camera, this.viewWidth = options.viewWidth, this.viewHeight = options.viewHeight;
    this.options = options;
    this.currentHover = null;
    this.currentSelect = null;
    this.projector = new THREE.Projector();
    this.addEventListener = THREE.EventDispatcher.prototype.addEventListener;
    this.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener;
    this.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener;
    this.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent;

		//for camera
		this.isOrtho = false;
		this.selectionColor = 0xfffccc;
		this.outlineColor = 0xffc200;
  }

  SelectionHelper.prototype._onHover = function(selection) {
    var outline, outlineMaterial;
    if (selection != null) {
      this.currentHover = selection;
      /*
      if (!(selection.hoverOutline != null) && !(selection.outline != null) && !(selection.name === "hoverOutline") && !(selection.name === "boundingCage") && !(selection.name === "selectOutline")) {
        selection.currentHoverHex = selection.material.color.getHex();
        selection.material.color.setHex(this.selectionColor);
        outlineMaterial = new THREE.MeshBasicMaterial({
          color: 0xffc200,
          side: THREE.BackSide
        });
        outline = new THREE.Mesh(selection.geometry.clone(), outlineMaterial);
        outline.scale.multiplyScalar(1.03);
        outline.name = "hoverOutline";
        selection.hoverOutline = outline;
        selection.add(outline);
      }*/
      return this.dispatchEvent({
        type: 'hoverIn',
        selection: selection
      });
    }
  };

  SelectionHelper.prototype._unHover = function() {
    if (this.currentHover) {
      /*if (this.currentHover.hoverOutline != null) {
        this.currentHover.material.color.setHex(this.currentHover.currentHoverHex);
        this.currentHover.remove(this.currentHover.hoverOutline);
        this.currentHover.hoverOutline = null;
      }*/
      this.currentHover = null;
      return this.dispatchEvent({
        type: 'hoverOut',
        selection: this.currentHover
      });
    }
  };

  SelectionHelper.prototype._onSelect = function(selection) {
    var outline, outlineMaterial;
    this._unHover();
    this.currentSelect = selection;
    /*new BoundingCage({
      mesh: selection,
      color: this.options.color,
      textColor: this.options.textColor
    });*/

    /*
    var cage = new THREE.BoundingBoxHelper( selection,0xFF0000 );
		cage.name = "boundingCage";
		cage.update();
    selection.cage = cage;
    selection.add(cage);*/

    /*outlineMaterial = new THREE.MeshBasicMaterial({
      color: 0xff0000,//0xffc200,
      side: THREE.BackSide
    });
    outline = new THREE.Mesh(selection.geometry.clone(), outlineMaterial);
    outline.name = "selectOutline";
    outline.scale.multiplyScalar(1.03);
    selection.outline = outline;
    selection.add(outline);*/
    return this.dispatchEvent({
      type: 'selected',
      selection: selection
    });
  };

  SelectionHelper.prototype._unSelect = function() {
    var selection;
    if (this.currentSelect) {
      selection = this.currentSelect;
      /*selection.remove(selection.cage);
      selection.remove(selection.outline);
      selection.cage = null;
      selection.outline = null;
      this.currentSelect = null;*/
      return this.dispatchEvent({
        type: 'unselected',
        selection: selection
      });
    }
  };

  SelectionHelper.prototype._get3DBB = function(object) {
    if (object != null) {
      if (object.geometry != null) {
        if (object.geometry.boundingBox != null) {
          return object.geometry.boundingBox;
        } else {
          object.geometry.computeBoundingBox();
          return object.geometry.boundingBox;
        }
      }
    }
    return null;
  };

  SelectionHelper.prototype.getScreenCoords = function(object, width, height) {
    var result, vector;
    if (object != null) {
      vector = this.projector.projectVector(object.position.clone(), this.camera);
      result = new THREE.Vector2();
      result.x = Math.round(vector.x * (width / 2)) + width / 2;
      result.y = Math.round((0 - vector.y) * (height / 2)) + height / 2;
      return result;
    }
  };

  SelectionHelper.prototype.get2DBB = function(object, width, height) {
    var bbox3d, centerLeft, centerPercX, centerPercY, centerTop, max3d, maxLeft, maxPercX, maxPercY, maxTop, min3d, minLeft, minPercX, minPercY, minTop, objHeight, objLength, objWidth, pMax, pMin, pos, result;
    if (object != null) {
      bbox3d = this._get3DBB(object);
      min3d = bbox3d.min.clone();
      max3d = bbox3d.max.clone();
      objLength = bbox3d.max.x - bbox3d.min.x;
      objWidth = bbox3d.max.y - bbox3d.min.y;
      objHeight = bbox3d.max.z - bbox3d.min.z;
      pMin = this.projector.projectVector(min3d, this.camera);
      pMax = this.projector.projectVector(max3d, this.camera);
      minPercX = (pMin.x + 1) / 2;
      minPercY = (-pMin.y + 1) / 2;
      minLeft = minPercX * width;
      minTop = minPercY * height;
      maxPercX = (pMax.x + 1) / 2;
      maxPercY = (-pMax.y + 1) / 2;
      maxLeft = maxPercX * width;
      maxTop = maxPercY * height;
      pos = object.position.clone();
      pos = this.projector.projectVector(pos, this.camera);
      centerPercX = (pos.x + 1) / 2;
      centerPercY = (-pos.y + 1) / 2;
      centerLeft = centerPercX * width;
      centerTop = centerPercY * height;
      result = [centerLeft, centerTop, objLength, objWidth, objHeight];
      return result;
    }
  };

	SelectionHelper.prototype.pick = function(x,y,isOrtho){
		var isOrtho = isOrtho || this.isOrtho;
		var intersected, intersects, raycaster, v, _ref;
		v = new THREE.Vector3((x / this.viewWidth) * 2 - 1, -(y / this.viewHeight) * 2 + 1, 1);
		if( !isOrtho)
		{
		  var s = Date.now();
		  v.unproject( this.camera );
		  raycaster = new THREE.Raycaster(this.camera.position, v.sub(this.camera.position).normalize());
		  //raycaster.precision = 10;
		  intersects = raycaster.intersectObjects(this.hiearchyRoot, true);
		  				//var e = Date.now();
		  //onsole.log( "Time to pick (internal)" + (e-s) + " ms" );
		}
		else
		{
				// use picking ray since it's an orthographic camera
				var s = Date.now();
				var ray = this.projector.pickingRay( v, this.camera );
				intersects = ray.intersectObjects( this.hiearchyRoot, true );

				var e = Date.now();
      //console.log( "Time to pick (internal)" + (e-s) + " ms" );
		}

    //TODO: really, find a better way to exclude helper objects
    /*for(var i = intersects.length-1; i>=0; i--)
    {
      var intersected = intersects[i].object;
      if (intersected.name === "hoverOutline" || intersected.name === "selectOutline" || intersected.name === "boundingCage")
      {
        intersects.splice(i, 1);
      }
    }*/
		return intersects;
	};

  SelectionHelper.prototype.getSceneCoords = function(x,y,isOrtho){
		var isOrtho = isOrtho || this.isOrtho;
		var raycaster, v, pos;
		v = new THREE.Vector3((x / this.viewWidth) * 2 - 1, -(y / this.viewHeight) * 2 + 1, 1);
		if( !isOrtho)
		{
		  v.unproject( this.camera);

      var dir = v.sub( this.camera.position ).normalize();
      var distance = - this.camera.position.z / dir.z;
      var pos = this.camera.position.clone().add( dir.multiplyScalar( distance ) );
		}
		else
		{
				// use picking ray since it's an orthographic camera
				var ray = this.projector.pickingRay( v, this.camera );
				//intersects = ray.intersectObjects( this.hiearchyRoot, true );
		}
		return pos;
	};

  SelectionHelper.prototype.filterIntersects = function( intersects ){
    	function goUpHierarchy(node, stopCondition)
		{
		  if(stopCondition( node ) ){
        return node;
      }
      else{
        if(node.parent){
        return goUpHierarchy( node.parent, stopCondition );}
        else{
          return null;
        }
      }
		}

		var hierarchyRoot = this.hiearchyRoot;
		var finalInteresects = [];
		//now go up the hierarchy until we find one "root" object ie in hierarchy root
		for(var i=0;i<intersects.length;i++)
		{
		  var node = intersects[i].object;
		  function isOk(node)
		  {
		    if(hierarchyRoot.indexOf( node ) !=-1 ) return true;
		    return false
		  }
		  var validNode = goUpHierarchy(node, isOk);
		  if( validNode && finalInteresects.indexOf( validNode ) ==-1 && !validNode.userData.unselectable ) finalInteresects.push( validNode);
		}
    return finalInteresects;
  }

  /*SelectionHelper.prototype.isThereObjectAt = function(x, y) {
		var intersects = this.pick(x,y,false);
    if (intersects.length > 0) {
      return true;
    }
    return false;
  };*/

  SelectionHelper.prototype.getObjectAt = function(x, y, isOrtho) {
    var isOrtho = isOrtho || false;
    var s = Date.now();
		var intersects = this.pick(x,y,isOrtho);
		intersects = this.filterIntersects( intersects );
    if (intersects.length > 0) {
      var intersected = intersects[0];
      //intersected = intersects[0].object;
      //var e = Date.now();

      //console.log( "Time to pick " + (e-s) + " ms" );

      //console.log("intersected",intersects[0]);
      if ((_ref = intersected.name) === "hoverOutline" || _ref === "selectOutline" || _ref === "boundingCage") {
        intersected = intersected.parent;
      }
      return intersected;
    } else {
      return null;
    }
  };

  SelectionHelper.prototype.selectObjectAt = function(x, y) {
    var intersects = this.pick(x,y,false);
    if (intersects.length > 0) {
      intersected = intersects[0].object;
      intersected._data = {};
      intersected._data.face = intersects[0].face;
      intersected._data.point = intersects[0].point;
      //console.log("intersected",intersected);

      if ((_ref = intersected.name) === "hoverOutline" || _ref === "selectOutline" || _ref === "boundingCage") {
        intersected = intersected.parent;
      }
      if (intersected !== this.currentSelect) {
        this._unSelect();
        this._onSelect(intersected);
        return this.currentSelect;
      } else {
        return this.currentSelect;
      }
    } else {
      return this._unSelect();
    }
  };

  SelectionHelper.prototype.highlightObjectAt = function(x, y) {
    var intersects = this.pick(x,y,false);
    if (intersects.length > 0) {
      if (intersects[0].object !== this.currentHover) {
        if (intersects[0].object.name !== "workplane" && intersects[0].object.name !== "hoverOutline" && intersects[0].object.name !== "boundingCage") {
          this._unHover();
          return this._onHover(intersects[0].object);
        }
      }
    } else {
      return this._unHover();
    }
  };

<commit_msg>- added temporary fix/workaround for picking issue in ortho mode  based on https://github.com/mrdoob/three.js/issues/5263 closes #5<commit_after>//straight compile from coffeescript, temporary
var  __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

function SelectionHelper(options) {
    this.highlightObjectAt = __bind(this.highlightObjectAt, this);

    this.selectObjectAt = __bind(this.selectObjectAt, this);

    this.getObjectAt = __bind(this.getObjectAt, this);

    this.isThereObjectAt = __bind(this.isThereObjectAt, this);

    this.get2DBB = __bind(this.get2DBB, this);

    this.getScreenCoords = __bind(this.getScreenCoords, this);

    this._get3DBB = __bind(this._get3DBB, this);

    this._unSelect = __bind(this._unSelect, this);

    this._onSelect = __bind(this._onSelect, this);

    this._unHover = __bind(this._unHover, this);

    this._onHover = __bind(this._onHover, this);

    var defaults;
    //SelectionHelper.__super__.constructor.call(this, options);
    defaults = {
      hiearchyRoot: null,
      camera: null,
      viewWidth: 640,
      viewHeight: 480
    };
    //options = merge(defaults, options);

    this.hiearchyRoot = options.hiearchyRoot, this.camera = options.camera, this.viewWidth = options.viewWidth, this.viewHeight = options.viewHeight;
    this.options = options;
    this.currentHover = null;
    this.currentSelect = null;
    this.projector = new THREE.Projector();
    this.addEventListener = THREE.EventDispatcher.prototype.addEventListener;
    this.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener;
    this.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener;
    this.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent;

		//for camera
		this.isOrtho = false;
		this.selectionColor = 0xfffccc;
		this.outlineColor = 0xffc200;
  }

  SelectionHelper.prototype._onHover = function(selection) {
    var outline, outlineMaterial;
    if (selection != null) {
      this.currentHover = selection;
      /*
      if (!(selection.hoverOutline != null) && !(selection.outline != null) && !(selection.name === "hoverOutline") && !(selection.name === "boundingCage") && !(selection.name === "selectOutline")) {
        selection.currentHoverHex = selection.material.color.getHex();
        selection.material.color.setHex(this.selectionColor);
        outlineMaterial = new THREE.MeshBasicMaterial({
          color: 0xffc200,
          side: THREE.BackSide
        });
        outline = new THREE.Mesh(selection.geometry.clone(), outlineMaterial);
        outline.scale.multiplyScalar(1.03);
        outline.name = "hoverOutline";
        selection.hoverOutline = outline;
        selection.add(outline);
      }*/
      return this.dispatchEvent({
        type: 'hoverIn',
        selection: selection
      });
    }
  };

  SelectionHelper.prototype._unHover = function() {
    if (this.currentHover) {
      /*if (this.currentHover.hoverOutline != null) {
        this.currentHover.material.color.setHex(this.currentHover.currentHoverHex);
        this.currentHover.remove(this.currentHover.hoverOutline);
        this.currentHover.hoverOutline = null;
      }*/
      this.currentHover = null;
      return this.dispatchEvent({
        type: 'hoverOut',
        selection: this.currentHover
      });
    }
  };

  SelectionHelper.prototype._onSelect = function(selection) {
    var outline, outlineMaterial;
    this._unHover();
    this.currentSelect = selection;
    /*new BoundingCage({
      mesh: selection,
      color: this.options.color,
      textColor: this.options.textColor
    });*/

    /*
    var cage = new THREE.BoundingBoxHelper( selection,0xFF0000 );
		cage.name = "boundingCage";
		cage.update();
    selection.cage = cage;
    selection.add(cage);*/

    /*outlineMaterial = new THREE.MeshBasicMaterial({
      color: 0xff0000,//0xffc200,
      side: THREE.BackSide
    });
    outline = new THREE.Mesh(selection.geometry.clone(), outlineMaterial);
    outline.name = "selectOutline";
    outline.scale.multiplyScalar(1.03);
    selection.outline = outline;
    selection.add(outline);*/
    return this.dispatchEvent({
      type: 'selected',
      selection: selection
    });
  };

  SelectionHelper.prototype._unSelect = function() {
    var selection;
    if (this.currentSelect) {
      selection = this.currentSelect;
      /*selection.remove(selection.cage);
      selection.remove(selection.outline);
      selection.cage = null;
      selection.outline = null;
      this.currentSelect = null;*/
      return this.dispatchEvent({
        type: 'unselected',
        selection: selection
      });
    }
  };

  SelectionHelper.prototype._get3DBB = function(object) {
    if (object != null) {
      if (object.geometry != null) {
        if (object.geometry.boundingBox != null) {
          return object.geometry.boundingBox;
        } else {
          object.geometry.computeBoundingBox();
          return object.geometry.boundingBox;
        }
      }
    }
    return null;
  };

  SelectionHelper.prototype.getScreenCoords = function(object, width, height) {
    var result, vector;
    if (object != null) {
      vector = this.projector.projectVector(object.position.clone(), this.camera);
      result = new THREE.Vector2();
      result.x = Math.round(vector.x * (width / 2)) + width / 2;
      result.y = Math.round((0 - vector.y) * (height / 2)) + height / 2;
      return result;
    }
  };

  SelectionHelper.prototype.get2DBB = function(object, width, height) {
    var bbox3d, centerLeft, centerPercX, centerPercY, centerTop, max3d, maxLeft, maxPercX, maxPercY, maxTop, min3d, minLeft, minPercX, minPercY, minTop, objHeight, objLength, objWidth, pMax, pMin, pos, result;
    if (object != null) {
      bbox3d = this._get3DBB(object);
      min3d = bbox3d.min.clone();
      max3d = bbox3d.max.clone();
      objLength = bbox3d.max.x - bbox3d.min.x;
      objWidth = bbox3d.max.y - bbox3d.min.y;
      objHeight = bbox3d.max.z - bbox3d.min.z;
      pMin = this.projector.projectVector(min3d, this.camera);
      pMax = this.projector.projectVector(max3d, this.camera);
      minPercX = (pMin.x + 1) / 2;
      minPercY = (-pMin.y + 1) / 2;
      minLeft = minPercX * width;
      minTop = minPercY * height;
      maxPercX = (pMax.x + 1) / 2;
      maxPercY = (-pMax.y + 1) / 2;
      maxLeft = maxPercX * width;
      maxTop = maxPercY * height;
      pos = object.position.clone();
      pos = this.projector.projectVector(pos, this.camera);
      centerPercX = (pos.x + 1) / 2;
      centerPercY = (-pos.y + 1) / 2;
      centerLeft = centerPercX * width;
      centerTop = centerPercY * height;
      result = [centerLeft, centerTop, objLength, objWidth, objHeight];
      return result;
    }
  };

	SelectionHelper.prototype.pick = function(x,y,isOrtho){
		var isOrtho = isOrtho || this.isOrtho;
		var intersected, intersects, raycaster, v, _ref;
		v = new THREE.Vector3((x / this.viewWidth) * 2 - 1, -(y / this.viewHeight) * 2 + 1, 1);
		if( !isOrtho)
		{
		  var s = Date.now();
		  v.unproject( this.camera );
		  raycaster = new THREE.Raycaster(this.camera.position, v.sub(this.camera.position).normalize());
		  //raycaster.precision = 10;
		  intersects = raycaster.intersectObjects(this.hiearchyRoot, true);
		}
		else
		{
				// use picking ray since it's an orthographic camera
				//var ray = this.projector.pickingRay( v, this.camera );
				//intersects = ray.intersectObjects( this.hiearchyRoot, true );

				//see here:
				THREE.Vector3.prototype.pickingRay = function ( camera ) {
            var tan = Math.tan( 0.5 * THREE.Math.degToRad( camera.fov ) ) / camera.zoom;

            this.x *= tan * camera.aspect;
            this.y *= tan;
            this.z = - 1;

            return this.transformDirection( camera.matrixWorld );

        };

				//v.unproject( this.camera );
		    //raycaster = new THREE.Raycaster(this.camera.position, v.sub(this.camera.position).normalize());
		     raycaster = new THREE.Raycaster();
         v.pickingRay( this.camera );
         raycaster.set( this.camera.position, v );
		     intersects = raycaster.intersectObjects(this.hiearchyRoot, true);
		}

    //TODO: really, find a better way to exclude helper objects
    /*for(var i = intersects.length-1; i>=0; i--)
    {
      var intersected = intersects[i].object;
      if (intersected.name === "hoverOutline" || intersected.name === "selectOutline" || intersected.name === "boundingCage")
      {
        intersects.splice(i, 1);
      }
    }*/
		return intersects;
	};

  SelectionHelper.prototype.getSceneCoords = function(x,y,isOrtho){
		var isOrtho = isOrtho || this.isOrtho;
		var raycaster, v, pos;
		v = new THREE.Vector3((x / this.viewWidth) * 2 - 1, -(y / this.viewHeight) * 2 + 1, 1);
		if( !isOrtho)
		{
		  v.unproject( this.camera);

      var dir = v.sub( this.camera.position ).normalize();
      var distance = - this.camera.position.z / dir.z;
      var pos = this.camera.position.clone().add( dir.multiplyScalar( distance ) );
		}
		else
		{
				// use picking ray since it's an orthographic camera
				var ray = this.projector.pickingRay( v, this.camera );
				//intersects = ray.intersectObjects( this.hiearchyRoot, true );
		}
		return pos;
	};

  SelectionHelper.prototype.filterIntersects = function( intersects ){
    	function goUpHierarchy(node, stopCondition)
		{
		  if(stopCondition( node ) ){
        return node;
      }
      else{
        if(node.parent){
        return goUpHierarchy( node.parent, stopCondition );}
        else{
          return null;
        }
      }
		}

		var hierarchyRoot = this.hiearchyRoot;
		var finalInteresects = [];
		//now go up the hierarchy until we find one "root" object ie in hierarchy root
		for(var i=0;i<intersects.length;i++)
		{
		  var node = intersects[i].object;
		  function isOk(node)
		  {
		    if(hierarchyRoot.indexOf( node ) !=-1 ) return true;
		    return false
		  }
		  var validNode = goUpHierarchy(node, isOk);
		  if( validNode && finalInteresects.indexOf( validNode ) ==-1 && !validNode.userData.unselectable ) finalInteresects.push( validNode);
		}
    return finalInteresects;
  }

  /*SelectionHelper.prototype.isThereObjectAt = function(x, y) {
		var intersects = this.pick(x,y,false);
    if (intersects.length > 0) {
      return true;
    }
    return false;
  };*/

  SelectionHelper.prototype.getObjectAt = function(x, y, isOrtho) {
    var isOrtho = isOrtho || false;
    var s = Date.now();
		var intersects = this.pick(x,y,isOrtho);
		intersects = this.filterIntersects( intersects );
		var e = Date.now();
    //console.log( "Time to pick " + (e-s) + " ms" );

    if (intersects.length > 0) {
      var intersected = intersects[0];

      //console.log("intersected",intersects[0]);
      if ((_ref = intersected.name) === "hoverOutline" || _ref === "selectOutline" || _ref === "boundingCage") {
        intersected = intersected.parent;
      }
      return intersected;
    } else {
      return null;
    }
  };

  SelectionHelper.prototype.selectObjectAt = function(x, y) {
    var intersects = this.pick(x,y,false);
    if (intersects.length > 0) {
      intersected = intersects[0].object;
      intersected._data = {};
      intersected._data.face = intersects[0].face;
      intersected._data.point = intersects[0].point;
      //console.log("intersected",intersected);

      if ((_ref = intersected.name) === "hoverOutline" || _ref === "selectOutline" || _ref === "boundingCage") {
        intersected = intersected.parent;
      }
      if (intersected !== this.currentSelect) {
        this._unSelect();
        this._onSelect(intersected);
        return this.currentSelect;
      } else {
        return this.currentSelect;
      }
    } else {
      return this._unSelect();
    }
  };

  SelectionHelper.prototype.highlightObjectAt = function(x, y) {
    var intersects = this.pick(x,y,false);
    if (intersects.length > 0) {
      if (intersects[0].object !== this.currentHover) {
        if (intersects[0].object.name !== "workplane" && intersects[0].object.name !== "hoverOutline" && intersects[0].object.name !== "boundingCage") {
          this._unHover();
          return this._onHover(intersects[0].object);
        }
      }
    } else {
      return this._unHover();
    }
  };

<|endoftext|>


<commit_before>import Buttons from 'componentsdir/button/examples/Buttons';
import Cards from 'componentsdir/card/examples/Cards';
import CheckBoxes from 'componentsdir/checkbox/examples/checkboxes';
import Grids from 'componentsdir/grid/examples/Grid';
import Icons from 'componentsdir/icon/examples/Icons';
import Images from 'componentsdir/image/examples/Images';
import Links from 'componentsdir/link/examples/Links';
import Lists from 'componentsdir/list/examples/Lists';
import MediaObjects from 'componentsdir/mediaObject/examples/mediaObject';
import Quotes from 'componentsdir/quote/examples/Quote';
import Radios from 'componentsdir/radio/examples/Radios';
import Ratings from 'componentsdir/rating/examples/Ratings';
import Selects from 'componentsdir/select/examples/Selects';
import Texts from 'componentsdir/text/examples/Text';

import ActivityCards from 'compositionsdir/activityCard/examples/activity';
import Captions from 'compositionsdir/caption/examples/Caption';
import Searches from 'compositionsdir/search/examples/searchbox';
import App from './App';

const routes = [
  { path: '/', component: App },
  { path: '/buttons', name: 'Buttons', component: Buttons },
  { path: '/cards', name: 'Cards', component: Cards },
  { path: '/checkboxes', name: 'CheckBoxes', component: CheckBoxes },
  { path: '/grids', name: 'Grids', component: Grids },
  { path: '/icons', name: 'Icons', component: Icons },
  { path: '/images', name: 'Images', component: Images },
  { path: '/links', name: 'Links', component: Links },
  { path: '/lists', name: 'Lists', component: Lists },
  { path: '/mediaobjects', name: 'Media Objects', component: MediaObjects },
  { path: '/quotes', name: 'Quotes', component: Quotes },
  { path: '/radios', name: 'Radios', component: Radios },
  { path: '/ratings', name: 'Ratings', component: Ratings },
  { path: '/selects', name: 'Selects', component: Selects },
  { path: '/texts', name: 'Texts', component: Texts },
  { path: '/activitycards', name: 'ActivityCards', component: ActivityCards },
  { path: '/captions', name: 'Captions', component: Captions },
  { path: '/searches', name: 'Searches', component: Searches },
];

export default routes;
<commit_msg>refactor(accordion cta): add accordion, cta routes to proving grounds<commit_after>import Accordions from 'componentsdir/accordion/examples/Accordion';
import Buttons from 'componentsdir/button/examples/Buttons';
import Cards from 'componentsdir/card/examples/Cards';
import CheckBoxes from 'componentsdir/checkbox/examples/checkboxes';
import Cta from 'componentsdir/cta/examples/Cta';
import Grids from 'componentsdir/grid/examples/Grid';
import Icons from 'componentsdir/icon/examples/Icons';
import Images from 'componentsdir/image/examples/Images';
import Links from 'componentsdir/link/examples/Links';
import Lists from 'componentsdir/list/examples/Lists';
import MediaObjects from 'componentsdir/mediaObject/examples/mediaObject';
import Quotes from 'componentsdir/quote/examples/Quote';
import Radios from 'componentsdir/radio/examples/Radios';
import Ratings from 'componentsdir/rating/examples/Ratings';
import Selects from 'componentsdir/select/examples/Selects';
import Texts from 'componentsdir/text/examples/Text';

import ActivityCards from 'compositionsdir/activityCard/examples/activity';
import Captions from 'compositionsdir/caption/examples/Caption';
import Searches from 'compositionsdir/search/examples/searchbox';
import App from './App';

const routes = [
  { path: '/', component: App },
  { path: '/accordion', name: 'Accordion', component: Accordions },
  { path: '/buttons', name: 'Buttons', component: Buttons },
  { path: '/cards', name: 'Cards', component: Cards },
  { path: '/checkboxes', name: 'CheckBoxes', component: CheckBoxes },
  { path: '/cta', name: 'CTA', component: Cta },
  { path: '/grids', name: 'Grids', component: Grids },
  { path: '/icons', name: 'Icons', component: Icons },
  { path: '/images', name: 'Images', component: Images },
  { path: '/links', name: 'Links', component: Links },
  { path: '/lists', name: 'Lists', component: Lists },
  { path: '/mediaobjects', name: 'Media Objects', component: MediaObjects },
  { path: '/quotes', name: 'Quotes', component: Quotes },
  { path: '/radios', name: 'Radios', component: Radios },
  { path: '/ratings', name: 'Ratings', component: Ratings },
  { path: '/selects', name: 'Selects', component: Selects },
  { path: '/texts', name: 'Texts', component: Texts },
  { path: '/activitycards', name: 'ActivityCards', component: ActivityCards },
  { path: '/captions', name: 'Captions', component: Captions },
  { path: '/searches', name: 'Searches', component: Searches },
];

export default routes;
<|endoftext|>


<commit_before>import Path from './path.js';
import Loader from './loader.js';
import Utility from './utility.js';
import Component from './component.js';
import Events from './class/events.js';

class Router extends Events {

	constructor () {
		super();

		this.data = [];
		this.location = {};
		this.ran = false;
		this.mode = 'push';
		this.element = null;
		this.contain = false;

		// this.pattern = new RegExp([
		//     '^(https?:)//', // protocol
		//     '(([^:/?#]*)(?::([0-9]+))?)', // host, hostname, port
		//     '(/{0,1}[^?#]*)', // pathname
		//     '(\\?[^#]*|)', // search
		//     '(#.*|)$' // hash
		// ].join(''));
	}

	async setup (options) {
		options = options || {};

		this.mode = options.mode === undefined ? this.mode : options.mode;
		this.after = options.after === undefined ? this.after : options.after;
		this.before = options.before === undefined ? this.before : options.before;
		this.element = options.element === undefined ? this.element : options.element;
		this.contain = options.contain === undefined ? this.contain : options.contain;
		this.external = options.external === undefined ? this.external : options.external;

		if (options.routes) {
			// this.add(options.routes);
			await this.add(options.routes);
		}

		await this.route(window.location.href, { mode: 'replace' });
	}

	scroll (x, y) {
		window.scroll(x, y);
	}

	back () {
		window.history.back();
	}

	forward () {
		window.history.forward();
	}

	redirect (path) {
		window.location.href = path;
	}

	async add (data) {
		let self = this;

		if (!data) {
			throw new Error('Oxe.router.add - requires data parameter');
		} else if (data.constructor === String) {
			let route = await Loader.load(data);
			this.data.push(route);
			// this.data.push({ path: data, load: data });
		} else if (data.constructor === Object) {
			if (!data.path) throw new Error('Oxe.router.add - route path required');
			// if (!data.component) throw new Error('Oxe.router.add - route component required');
			this.data.push(data);
		} else if (data.constructor === Array) {
			// return Promise.all(data.map(function (route) {
			// 	if (data.constructor === String) {
			// 		return Loader.load(data);
			// 	} else {
			// 		return route;
			// 	}
			// })).then(function (routes) {
			// 	routes.forEach(function (route) {
			// 		self.data.push(route);
			// 	});
			// });
			for (let i = 0, l = data.length; i < l; i++) {
				await this.add(data[i]);
			}
		}
	}

	remove (path) {
		for (let i = 0, l = this.data.length; i < l; i++) {
			let route = this.data[i];
			if (route.path === path) {
				this.data.splice(i, 1);
			}
		}
	}

	get (path) {
		for (let i = 0, l = this.data.length; i < l; i++) {
			let route = this.data[i];
			if (route.path === path) {
				return route;
			}
		}
	}

	async find (path) {
		for (let i = 0, l = this.data.length; i < l; i++) {
			let route = this.data[i];
			if (this.isPath(route.path, path)) {
				// if (route.load) {
				// 	let routePath = this.data[i];
				// 	this.data[i] = await Loader.load(route.load);
				// 	this.data[i].path = routePath;
				// 	return this.data[i];
				// } else {
					return route;
				// }
			}
		}
	}

	filter (path) {
		let result = [];

		for (let i = 0, l = this.data.length; i < l; i++) {
			let route = this.data[i];
			if (this.isPath(route.path, path)) {
				result.push(route);
			}
		}

		return result;
	}

	isPath (routePath, userPath) {

		if (routePath.slice(0, 1) !== '/') {
			routePath = Path.resolve(routePath);
		}

		if (!userPath) {
			return false;
		} else if (userPath.constructor.name === 'String') {
			return new RegExp(
				'^' + routePath
				.replace(/{\*}/g, '(?:.*)')
				.replace(/{(\w+)}/g, '([^\/]+)')
				+ '(\/)?$'
			).test(userPath || '/');
		} else if (userPath.constructor.name === 'RegExp') {
			return userPath.test(routePath);
		}
	}

	toParameterObject (routePath, userPath) {
		let result = {};

		if (
			!routePath
			|| !userPath
			|| routePath === '/'
			|| userPath === '/'
		) return result;

		let brackets = /{|}/g;
		let pattern = /{(\w+)}/;
		let userPaths = userPath.split('/');
		let routePaths = routePath.split('/');

		for (let i = 0, l = routePaths.length; i < l; i++) {

			if (pattern.test(routePaths[i])) {
				let name = routePaths[i].replace(brackets, '');
				result[name] = userPaths[i];
			}

		}

		return result;
	}

	toQueryString (data) {
		let result = '?';

		for (let key in data) {
			let value = data[key];
			result += key + '=' + value + '&';
		}

		if (result.slice(-1) === '&') {
			result = result.slice(0, -1);
		}

		return result;
	}

	toQueryObject (path) {
		let result = {};

		if (path.indexOf('?') === 0) path = path.slice(1);
		let queries = path.split('&');

		for (let i = 0, l = queries.length; i < l; i++) {
			let query = queries[i].split('=');

			if (query[0] && query[1]) {
				result[query[0]] = query[1];
			}

		}

		return result;
	}

	toLocationObject (href) {
		var parser = document.createElement('a');
		parser.href = href;
		return {
			href: parser.href,
			host: parser.host,
			port: parser.port,
			hash: parser.hash,
			search: parser.search,
			protocol: parser.protocol,
			hostname: parser.hostname,
			pathname: parser.pathname
		};
	}

	render (route) {
		var self = this;

		if (!route) throw new Error('Oxe.render - route argument required');

		Utility.ready(function () {

			if (route.title) {
				document.title = route.title;
			}

			if (route.description) {
				Utility.ensureElement({
					name: 'meta',
					scope: document.head,
					position: 'afterbegin',
					query: '[name="description"]',
					attributes: [
						{ name: 'name', value: 'description' },
						{ name: 'content', value: route.description }
					]
				});
			}

			if (route.keywords) {
				Utility.ensureElement({
					name: 'meta',
					scope: document.head,
					position: 'afterbegin',
					query: '[name="keywords"]',
					attributes: [
						{ name: 'name', value: 'keywords' },
						{ name: 'content', value: route.keywords }
					]
				});
			}

			if (!self.element) {
				self.element = self.element || 'o-router';

				if (typeof self.element === 'string') {
					self.element = document.body.querySelector(self.element);
				}

				if (!self.element) {
					throw new Error('Oxe.router.render - missing o-router element');
				}

			}

			if (!route.element) {

				// if (route.load) {
				// 	Loader.load(route.load);
				// }

				if (route.component.constructor === String) {
					route.element = document.createElement(route.component);
				}

				if (route.component.constructor === Object) {

					Component.define(route.component);

					if (self.mode === 'compiled') {
					// if (route.component.name.toLowerCase() === self.element.firstElementChild.nodeName.toLowerCase()) {
						route.element = self.element.firstElementChild;
					} else {
						route.element = document.createElement(route.component.name);
					}

				}

			}

			if (!route.component && !route.element) {
				throw new Error('Oxe.router.render - missing route component and');
			}

			if (route.element !== self.element.firstElementChild) {

				while (self.element.firstChild) {
					self.element.removeChild(self.element.firstChild);
				}

				self.element.appendChild(route.element);

			}

			self.scroll(0, 0);
			self.emit('routed');

			if (typeof self.after === 'function') {
				Promise.resolve(self.after).catch(console.error);
			}

		});
	}

	async route (path, options) {
		options = options || {};

		var mode = options.mode || this.mode;
		var location = this.toLocationObject(path);
		var route = await this.find(location.pathname);

		if (!route) {
			throw new Error('Oxe.router.route - route not found');
		}

		location.route = route;
		location.title = location.route.title;
		location.query = this.toQueryObject(location.search);
		location.parameters = this.toParameterObject(location.route.path, location.pathname);

		if (options.query) {
			path += this.toQueryString(options.query);
		}

		if (typeof this.before === 'function') {
			var result = await this.before(location);
			if (result === false) return;
		}

		if (location.route && location.route.handler) {
			return await location.route.handler(location);
		}

		if (location.route && location.route.redirect) {
			return this.redirect(location.route.redirect);
		}

		if (mode === 'href' || mode === 'compiled') {
			return window.location.assign(path);
		} else {
			window.history[mode + 'State']({ path: path }, '', path);
		}

		this.location = location;
		this.emit('routing');
		this.render(location.route);
	}

}

export default new Router();
<commit_msg>fixed ie routing issues<commit_after>import Path from './path.js';
import Loader from './loader.js';
import Utility from './utility.js';
import Component from './component.js';
import Events from './class/events.js';

class Router extends Events {

	constructor () {
		super();

		this.data = [];
		this.location = {};
		this.ran = false;
		this.mode = 'push';
		this.element = null;
		this.contain = false;

		// this.pattern = new RegExp([
		//     '^(https?:)//', // protocol
		//     '(([^:/?#]*)(?::([0-9]+))?)', // host, hostname, port
		//     '(/{0,1}[^?#]*)', // pathname
		//     '(\\?[^#]*|)', // search
		//     '(#.*|)$' // hash
		// ].join(''));
	}

	async setup (options) {
		options = options || {};

		this.mode = options.mode === undefined ? this.mode : options.mode;
		this.after = options.after === undefined ? this.after : options.after;
		this.before = options.before === undefined ? this.before : options.before;
		this.element = options.element === undefined ? this.element : options.element;
		this.contain = options.contain === undefined ? this.contain : options.contain;
		this.external = options.external === undefined ? this.external : options.external;

		if (options.routes) {
			await this.add(options.routes);
		}

		await this.route(window.location.href, { mode: 'replace' });
	}

	scroll (x, y) {
		window.scroll(x, y);
	}

	back () {
		window.history.back();
	}

	forward () {
		window.history.forward();
	}

	redirect (path) {
		window.location.href = path;
	}

	async add (data) {
		let self = this;

		if (!data) {
			throw new Error('Oxe.router.add - requires data parameter');
		} else if (data.constructor === String) {
			let route = await Loader.load(data);
			this.data.push(route);
			// this.data.push({ path: data, load: data });
		} else if (data.constructor === Object) {
			if (!data.path) throw new Error('Oxe.router.add - route path required');
			// if (!data.component) throw new Error('Oxe.router.add - route component required');
			this.data.push(data);
		} else if (data.constructor === Array) {
			// return Promise.all(data.map(function (route) {
			// 	if (data.constructor === String) {
			// 		return Loader.load(data);
			// 	} else {
			// 		return route;
			// 	}
			// })).then(function (routes) {
			// 	routes.forEach(function (route) {
			// 		self.data.push(route);
			// 	});
			// });
			for (let i = 0, l = data.length; i < l; i++) {
				await this.add(data[i]);
			}
		}
	}

	remove (path) {
		for (let i = 0, l = this.data.length; i < l; i++) {
			let route = this.data[i];
			if (route.path === path) {
				this.data.splice(i, 1);
			}
		}
	}

	get (path) {
		for (let i = 0, l = this.data.length; i < l; i++) {
			let route = this.data[i];
			if (route.path === path) {
				return route;
			}
		}
	}

	async find (path) {
		for (let i = 0, l = this.data.length; i < l; i++) {
			let route = this.data[i];
			if (this.isPath(route.path, path)) {
				// if (route.load) {
				// 	let routePath = this.data[i];
				// 	this.data[i] = await Loader.load(route.load);
				// 	this.data[i].path = routePath;
				// 	return this.data[i];
				// } else {
					return route;
				// }
			}
		}
	}

	filter (path) {
		let result = [];

		for (let i = 0, l = this.data.length; i < l; i++) {
			let route = this.data[i];
			if (this.isPath(route.path, path)) {
				result.push(route);
			}
		}

		return result;
	}

	isPath (routePath, userPath) {
		userPath = userPath || '/';

		if (routePath.slice(0, 1) !== '/') {
			routePath = Path.resolve(routePath);
		}

		if (userPath.constructor === String) {
			var userParts = userPath.split('/');
			var routeParts = routePath.split('/');

			for (let i = 0, l = routeParts.length; i < l; i++) {
				if (routeParts[i].indexOf('{') === 0 && routeParts[i].indexOf('}') === routeParts[i].length-1) {
					continue
				} else if (routeParts[i] !== userParts[i]) {
					return false;
				}
			}

			return true;
			// return new RegExp(
			// 	'^' + routePath
			// 	.replace(/{\*}/g, '(?:.*)')
			// 	.replace(/{(\w+)}/g, '([^\/]+)')
			// 	+ '(\/)?$'
			// ).test(userPath || '/');
		} else if (userPath.constructor === RegExp) {
			return userPath.test(routePath);
		}
	}

	toParameterObject (routePath, userPath) {
		let result = {};

		if (
			!routePath
			|| !userPath
			|| routePath === '/'
			|| userPath === '/'
		) return result;

		let brackets = /{|}/g;
		let pattern = /{(\w+)}/;
		let userPaths = userPath.split('/');
		let routePaths = routePath.split('/');

		for (let i = 0, l = routePaths.length; i < l; i++) {

			if (pattern.test(routePaths[i])) {
				let name = routePaths[i].replace(brackets, '');
				result[name] = userPaths[i];
			}

		}

		return result;
	}

	toQueryString (data) {
		let result = '?';

		for (let key in data) {
			let value = data[key];
			result += key + '=' + value + '&';
		}

		if (result.slice(-1) === '&') {
			result = result.slice(0, -1);
		}

		return result;
	}

	toQueryObject (path) {
		let result = {};

		if (path.indexOf('?') === 0) path = path.slice(1);
		let queries = path.split('&');

		for (let i = 0, l = queries.length; i < l; i++) {
			let query = queries[i].split('=');

			if (query[0] && query[1]) {
				result[query[0]] = query[1];
			}

		}

		return result;
	}

	toLocationObject (href) {
		var parser = document.createElement('a');
		parser.href = href;
		return {
			href: parser.href,
			host: parser.host,
			port: parser.port,
			hash: parser.hash,
			search: parser.search,
			protocol: parser.protocol,
			hostname: parser.hostname,
			pathname: parser.pathname[0] === '/' ? parser.pathname : '/' + parser.pathname
		};
	}

	render (route) {
		var self = this;

		if (!route) throw new Error('Oxe.render - route argument required');

		Utility.ready(function () {

			if (route.title) {
				document.title = route.title;
			}

			if (route.description) {
				Utility.ensureElement({
					name: 'meta',
					scope: document.head,
					position: 'afterbegin',
					query: '[name="description"]',
					attributes: [
						{ name: 'name', value: 'description' },
						{ name: 'content', value: route.description }
					]
				});
			}

			if (route.keywords) {
				Utility.ensureElement({
					name: 'meta',
					scope: document.head,
					position: 'afterbegin',
					query: '[name="keywords"]',
					attributes: [
						{ name: 'name', value: 'keywords' },
						{ name: 'content', value: route.keywords }
					]
				});
			}

			if (!self.element) {
				self.element = self.element || 'o-router';

				if (typeof self.element === 'string') {
					self.element = document.body.querySelector(self.element);
				}

				if (!self.element) {
					throw new Error('Oxe.router.render - missing o-router element');
				}

			}

			if (!route.element) {

				// if (route.load) {
				// 	Loader.load(route.load);
				// }

				if (route.component.constructor === String) {
					route.element = document.createElement(route.component);
				}

				if (route.component.constructor === Object) {

					Component.define(route.component);

					if (self.mode === 'compiled') {
					// if (route.component.name.toLowerCase() === self.element.firstElementChild.nodeName.toLowerCase()) {
						route.element = self.element.firstElementChild;
					} else {
						route.element = document.createElement(route.component.name);
					}

				}

			}

			if (!route.component && !route.element) {
				throw new Error('Oxe.router.render - missing route component and');
			}

			if (route.element !== self.element.firstElementChild) {

				while (self.element.firstChild) {
					self.element.removeChild(self.element.firstChild);
				}

				self.element.appendChild(route.element);

			}

			self.scroll(0, 0);
			self.emit('routed');

			if (typeof self.after === 'function') {
				Promise.resolve(self.after).catch(console.error);
			}

		});
	}

	async route (path, options) {
		options = options || {};

		var mode = options.mode || this.mode;
		var location = this.toLocationObject(path);
		var route = await this.find(location.pathname);

		if (!route) {
			throw new Error('Oxe.router.route - route not found');
		}

		location.route = route;
		location.title = location.route.title;
		location.query = this.toQueryObject(location.search);
		location.parameters = this.toParameterObject(location.route.path, location.pathname);

		if (options.query) {
			path += this.toQueryString(options.query);
		}

		if (typeof this.before === 'function') {
			var result = await this.before(location);
			if (result === false) return;
		}

		if (location.route && location.route.handler) {
			return await location.route.handler(location);
		}

		if (location.route && location.route.redirect) {
			return this.redirect(location.route.redirect);
		}

		if (mode === 'href' || mode === 'compiled') {
			return window.location.assign(path);
		} else {
			window.history[mode + 'State']({ path: path }, '', path);
		}

		this.location = location;
		this.emit('routing');
		this.render(location.route);
	}

}

export default new Router();
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */
var _ = require('@sailshq/lodash');
var defaultsDeep = require('merge-defaults');

/**
 * _mixinReqParamsAll
 *
 * Mixes in `req.params.all()`, a convenience method to grab all parameters,
 * whether they're in the path (req.params), query string (req.query),
 * or request body (req.body).
 *
 * Note: this has to be determined per-route, not per request,
 * in order to refer to the proper route/path parameters.
 * e.g. if a request comes in and matches `GET /about` AND `GET /:username`
 * then the set of all params varies depending on which handler is being run.
 * Now that said, since changing the implementation to avoid precalculating
 * unless allParams is actually called, this may not necessarily need to be
 * the case anymore. More exhaustive testing would be required to make that change.
 *
 *
 * @param {Request} req
 * @param {Response} res
 * @api private
 */

module.exports = function _mixinReqParamsAll(req, res) {

  // Add `req.allParams()` method.
  req.allParams = function () {
    // Combines parameters from the query string, and encoded request body
    // to compose a monolithic object of named parameters, irrespective of source
    var queryParams = _.cloneDeep(req.query) || {};
    var bodyParams = _.cloneDeep(req.body) || {};
    var allParams = {};
    defaultsDeep(allParams, bodyParams);
    defaultsDeep(allParams, queryParams);

    // Mixin route params, as long as they have defined values
    _.each(Object.keys(req.params), function(paramName) {
      if (allParams[paramName] || !_.isUndefined(req.params[paramName])) {
        allParams[paramName] = !_.isUndefined(req.params[paramName]) ? req.params[paramName] : allParams[paramName];
      }
    });
    return allParams;
  };

  /////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Note:
  // req.params.all() will be deprecated in Sails v1.0 in favor of `req.allParams()`.
  /////////////////////////////////////////////////////////////////////////////////////////////////////////

  // Define a new non-enumerable property: req.params.all()
  // and make it a synonym to `req.allParams()`
  // (but only if `req.params.all` doesn't already exist!)
  if (!req.params.all) {
    Object.defineProperty(req.params, 'all', {
      value: req.allParams
    });
  }

};
<commit_msg>remove support for `req.params.all()` usage for Sails v1<commit_after>/**
 * Module dependencies
 */
var _ = require('@sailshq/lodash');
var defaultsDeep = require('merge-defaults');

/**
 * _mixinReqParamsAll
 *
 * Mixes in `req.params.all()`, a convenience method to grab all parameters,
 * whether they're in the path (req.params), query string (req.query),
 * or request body (req.body).
 *
 * Note: this has to be determined per-route, not per request,
 * in order to refer to the proper route/path parameters.
 * e.g. if a request comes in and matches `GET /about` AND `GET /:username`
 * then the set of all params varies depending on which handler is being run.
 * Now that said, since changing the implementation to avoid precalculating
 * unless allParams is actually called, this may not necessarily need to be
 * the case anymore. More exhaustive testing would be required to make that change.
 *
 *
 * @param {Request} req
 * @param {Response} res
 * @api private
 */

module.exports = function _mixinReqParamsAll(req, res) {

  // Add `req.allParams()` method.
  req.allParams = function () {
    // Combines parameters from the query string, and encoded request body
    // to compose a monolithic object of named parameters, irrespective of source
    var queryParams = _.cloneDeep(req.query) || {};
    var bodyParams = _.cloneDeep(req.body) || {};
    var allParams = {};
    defaultsDeep(allParams, bodyParams);
    defaultsDeep(allParams, queryParams);

    // Mixin route params, as long as they have defined values
    _.each(Object.keys(req.params), function(paramName) {
      if (allParams[paramName] || !_.isUndefined(req.params[paramName])) {
        allParams[paramName] = !_.isUndefined(req.params[paramName]) ? req.params[paramName] : allParams[paramName];
      }
    });
    return allParams;
  };

  /////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Note:
  // req.params.all() was removed in Sails v1.0 in favor of `req.allParams()`.
  /////////////////////////////////////////////////////////////////////////////////////////////////////////

  // Define a new non-enumerable property: req.params.all()
  // and make it a synonym to `req.allParams()`
  // (but only if `req.params.all` doesn't already exist!)
  if (!req.params.all) {
    Object.defineProperty(req.params, 'all', {
      value: function (){
        throw new Error('req.params.all() is no longer supported as of Sails v1.0.  Please use req.allParams() instead.');
      }
    });
  }

};
<|endoftext|>


<commit_before>'use strict';

var Route = {

  paths: [],
  realPath: null,
  currentPath: null,
  currentRoute: null,
  data: {},

  init: function(){
    window.onpopstate = function(e){
      this.find();
    }.bind(this);

    this.events.register();
    this.find();
  },

  events: {
    register: function(){
      var elems = document.getElementsByTagName('a');
      for(var i = 0; i < elems.length; i++){
        elems[i].addEventListener('click', this.linkClick);
      }
    },

    linkClick: function(event){
      if(event.target.getAttribute('target') !== '_blank')
        event.preventDefault();
      Route.change(event.target.getAttribute('href'));
    }
  },

  set: function(path, middleware, callback, options){
    if(callback === undefined){
      callback = middleware;
      middleware = function(){ return true; };
    }

    this.build(path, middleware, callback, options);
  },

  build: function(path, middleware, callback, options){

    if(path[0] != '/')
      path = '/'+path;

    if(path[path.length-1] == '/')
      path = path.slice(0, -1);

    this.paths.push({
      path: path,
      middleware: middleware,
      callback: callback
    });
  },

  change: function(path, data){
    if(path[0] != '/')
      path = '/'+path;

    if(window.location.hash)
      path += window.location.hash;

    window.history.pushState("","", path);
    this.find();

    for(var prop in data){
      this.data[prop] = data[prop];
    }
  },

  current: function(options){
    return this;
  },

  getParams: function(){
    if(window.location.search != ''){
      var params = window.location.search.replace('?', '').split('&');
      for(var i = 0; i < params.length; i++){
        var key = decodeURI(params[i].split('=')[0]);
        var value = decodeURI(params[i].split('=')[1]);
        this.data[key] = value;
      }
    }
  },

  find: function(){
    this.data = {}; // reset old route data
    this.getParams(); // check for params

    if(!this.paths)
      return;

    for(var i = 0; i < this.paths.length; i++){
      this.realPath = window.location.pathname;

      if(this.realPath[this.realPath.length-1] == '/')
        this.realPath = this.realPath.slice(0, -1);

      if(!(this.paths[i].path.indexOf(':') > false) && this.paths[i].path === this.realPath){
        // normal route
        if(this.paths[i].middleware()){
          this.currentRoute = i;
          this.currentPath = this.paths[i].path;
          this.paths[i].callback();
          this.events.register();
          return this;
        }
      }
    }

    // if no path matched check for paths with vars
    this.checkForVars();
  },

  checkForVars: function(){
    for(var i = 0; i < this.paths.length; i++){
      var route = this.paths[i];

      if((route.path.indexOf(':') > false)){
        var r = this.pathConstructor(route.path);
        if(r.path == this.realPath){
          if(route.middleware()){
            this.currentRoute = i;
            this.currentPath = this.paths[i].path;
            route.callback.apply(this, r.data);
            this.events.register();
            return this;
          }
        }
      }
    }

    this.notFound();
  },

  pathConstructor: function(path){
    path = path.split('/');
    var realPath = this.realPath.split('/');
    var route = {
      data: [],
      path: '',
    };

    for(var i = 0; i < path.length; i++){
      if(path[i][0] === ':'){
        if(realPath[i]){
          this.data[path[i].replace(':', '').replace('?', '')] = decodeURI(realPath[i]);
          route.data.push(decodeURIComponent(realPath[i]));
          path[i] = realPath[i];
        }

        if(path[i].indexOf('?') > false)
          path[i] = realPath[i] || '';
      }
    }

    path = path.join('/');

    if(path[path.length-1] === '/')
      path = path.slice(0, -1);

    route.path = path;
    return route;
  },

  notFound: function(){
    console.warn('Router.js:   Route is not defined...');
  },

};

module.exports = Route;
<commit_msg>Restructured the file so some of the functions isn't exposed in the object<commit_after>'use strict';

var Route = (function(){

  /**
   * Variables
   */
  var realPath = null,
      currentPath = null,
      currentRoute=  null;

  /**
   * events
   * This object handles the registration and handling of events related to the Route object
   *
   * @type {Object}
   */
  var events = {
    register: function(){
      var elems = document.getElementsByTagName('a');
      for(var i = 0; i < elems.length; i++){
        elems[i].addEventListener('click', events.linkClick);
      }
    },

    linkClick: function(event){
      if(event.target.getAttribute('target') !== '_blank')
        event.preventDefault();
      Route.change(event.target.getAttribute('href'));
    }
  };

  /**
   * build
   * Append routes to the available paths array
   *
   * @param  {String}   path       The path to append to the path list
   * @param  {Function} middleware The middle where function, if middleware isn't defined then its null
   * @param  {Function} callback   The callback function
   * @param  {[Object]} options    Options, not used right now, maybe for named routes in the future
   * @return {undefined}
   */
  function build(path, middleware, callback, options){
    if(path[0] != '/')
      path = '/'+path;

    if(path[path.length-1] == '/')
      path = path.slice(0, -1);

    Route.paths.push({
      path: path,
      middleware: middleware,
      callback: callback
    });
  }

  /**
   * getParams
   * This function retrieves url params and appends it to the Route.data object
   *
   * @return {undefined}
   */
  function getParams(){
    if(window.location.search != ''){
      var params = window.location.search.replace('?', '').split('&');
      for(var i = 0; i < params.length; i++){
        var key = decodeURI(params[i].split('=')[0]);
        var value = decodeURI(params[i].split('=')[1]);
        Route.data[key] = value;
      }
    }
  }

  /**
   * pathConstructor
   * Creates a defined route with variables and turns it into a usable route
   *
   * @param  {Sring} path is a string of the route which needs to be formated
   * @return {Object} contains the formatted route and a mapping of the variables in the route
   */
  function pathConstructor(path){
    path = path.split('/');
    var rp = realPath.split('/');
    var route = {
      data: [],
      path: '',
    };

    for(var i = 0; i < path.length; i++){
      if(path[i][0] === ':'){
        if(rp[i]){
          Route.data[path[i].replace(':', '').replace('?', '')] = decodeURI(rp[i]);
          route.data.push(decodeURIComponent(rp[i]));
          path[i] = rp[i];
        }

        if(path[i].indexOf('?') > false)
          path[i] = rp[i] || '';
      }
    }

    path = path.join('/');

    if(path[path.length-1] === '/')
      path = path.slice(0, -1);

    route.path = path;
    return route;
  }

  /**
   * find
   * Find iterates over the registered routes and looks for matches
   * if no route matches, the start look for routes with variables
   *
   * @return {undefined}
   */
  function find(){
    Route.data = {}; // reset old route data
    getParams(); // check for params

    if(!Route.paths)
      return;

    realPath = window.location.pathname;

    if(realPath[realPath.length-1] == '/')
      realPath = realPath.slice(0, -1);

    for(var i = 0; i < Route.paths.length; i++){
      if(!(Route.paths[i].path.indexOf(':') > false) && Route.paths[i].path === realPath){
        // normal route
        if(Route.paths[i].middleware()){
          Route.paths[i].callback();
          setCurrentRoute(i);
          return Route;
        }
      }
    }

    // if no path matched check for paths with vars
    checkForVars();
  }

  /**
   * checkForVars
   * Looks for routes with variables. If nothing matches then trigger Route.notFound()
   *
   * @return {undefined}
   */
  function checkForVars(){
    for(var i = 0; i < Route.paths.length; i++){
      var route = Route.paths[i];

      if((route.path.indexOf(':') > false)){
        var r = pathConstructor(route.path);
        if(r.path == realPath){
          if(route.middleware()){
            route.callback.apply(Route, r.data);
            setCurrentRoute(i);
            return Route;
          }
        }
      }
    }

    Route.notFound();
  }

  /**
   * setCurrentRoute
   *
   * @param {int} i the iteration of paths
   */
  function setCurrentRoute(i){
    currentRoute = i;
    currentPath = realPath;
    events.register();
  }

  /**
   * Route
   * This is the visible object, to handle the routing
   *
   * @type {Object}
   */
  var Route = {

    paths: [],
    data: {},

    init: function(){
      window.onpopstate = function(e){
        find();
      }.bind(this);

      events.register();
      find();
    },

    set: function(path, middleware, callback, options){
      if(callback === undefined){
        callback = middleware;
        middleware = function(){ return true; };
      }

      build(path, middleware, callback, options);
    },

    change: function(path, data){
      if(path[0] != '/')
        path = '/'+path;

      if(window.location.hash)
        path += window.location.hash;

      window.history.pushState("","", path);
      find();

      for(var prop in data){
        this.data[prop] = data[prop];
      }
    },

    current: function(options){
      return currentPath;
    },

    notFound: function(){
      console.warn('Router.js:   Route is not defined...');
    },

  };

  return Route;
}());

if(typeof module === "object" && typeof module.exports === "object"){
  module.exports = Route;
}
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var querystring = require('querystring');

var async = require('async');

var deployment = require('deployment');
var http = require('util/http');
var requiredParams = require('http/middleware/required-params').attachMiddleware;

var INSTANCE_NAME_RE = /^[a-zA-Z0-9_\-]+$/;

/**
 * Given an Instance object, generate an object in a format appropriate for
 * returning via the JSON api.
 *
 * @param {Instance} instance The instance to format.
 * @param {Function} callback A callback taking (err, data).
 */
function formatInstance(instance, callback) {
  var bundleVersion, bundleName;

  // Look up the name and version of each instance
  async.parallel([
    function(callback) {
      instance.getBundleName(function(err, name) {
        bundleName = name;
        callback(err);
        return;
      });
    },

    function(callback) {
      instance.getBundleVersion(function(err, version) {
        if (err) {
          callback(err);
          return;
        }

        bundleVersion = version;
        callback();
        return;
      });
    }
  ],

  function(err) {
    if (err) {
      callback(err);
      return;
    }

    callback(null, {
      'name': instance.name,
      'bundle_name': bundleName,
      'bundle_version': bundleVersion
    });
    return;
  });
}

function listInstances(req, res) {
  deployment.getInstanceList(function(err, instances) {
    if (err) {
      return http.returnError(res, 500, err.message);
    }

    // Format each instance
    async.map(instances, formatInstance, function(err, instanceList) {
      if (err) {
        return http.returnError(res, 500, err.message);
      }

      // Sort by name
      instanceList.sort(function(a, b) {
        return (b.name < a.name);
      });

      http.returnJson(res, 200, instanceList);
    });
  });
}

function getInstance(req, res) {
  var instanceName = req.params.instanceName;

  deployment.getInstance(instanceName, function(err, instance) {
    if (err) {
      return http.returnError(res, 404, 'No such instance');
    }
    formatInstance(instance, function(err, instanceData) {
      if (err) {
        return http.returnError(res, 500, err.message);
      }
      http.returnJson(res, 200, instanceData);
    });
  });
}

function createInstance(req, res) {
  var instanceName = req.params.instanceName;
  var params = req.body;
  var bundleName = params.bundle_name;
  var bundleVersion = params.bundle_version;
  var enableService = params.enable_service;

  deployment.createInstance(instanceName, bundleName, bundleVersion,
                            enableService, function(err) {
    if (err) {
      http.returnError(res, 500, err.message);
    }
    else {
      http.returnJson(res, 200, {
        'result': 'success'
      });
    }
  });
}

function upgradeInstance(req, res) {
  var instanceName = req.params.instanceName;
  var params = req.body;
  var bundleVersion = params.bundle_version;

  deployment.upgradeInstance(instanceName, bundleVersion, function(err) {
    if (err) {
      http.returnError(res, 500, err.message);
    }
    else {
      http.returnJson(res, 200, {
        'result': 'success'
      });
    }
  });
}

function destroyInstance(req, res) {
  var instanceName = req.params.instanceName;

  deployment.getInstance(instanceName, function(err, instance) {
    if (err) {
      return http.returnError(res, 404, 'No such instance');
    }
    instance.destroy(function() {
      http.returnJson(res, 200, {
        'result': 'success'
      });
    });
  });
}

function register(app, apiVersion) {
  app.post('/', listInstances);
  app.get('/:instanceName/', getInstance);
  app.put('/:instanceName/', requiredParams(['bundle_name', 'bundle_version']), createInstance);
  app.post('/:instanceName/upgrade/', requiredParams(['bundle_version']), upgradeInstance);
  app.del('/:instanceName/', destroyInstance);
}

exports.register = register;
<commit_msg>Fix a bug, should be app.get not app.post.<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var querystring = require('querystring');

var async = require('async');

var deployment = require('deployment');
var http = require('util/http');
var requiredParams = require('http/middleware/required-params').attachMiddleware;

var INSTANCE_NAME_RE = /^[a-zA-Z0-9_\-]+$/;

/**
 * Given an Instance object, generate an object in a format appropriate for
 * returning via the JSON api.
 *
 * @param {Instance} instance The instance to format.
 * @param {Function} callback A callback taking (err, data).
 */
function formatInstance(instance, callback) {
  var bundleVersion, bundleName;

  // Look up the name and version of each instance
  async.parallel([
    function(callback) {
      instance.getBundleName(function(err, name) {
        bundleName = name;
        callback(err);
        return;
      });
    },

    function(callback) {
      instance.getBundleVersion(function(err, version) {
        if (err) {
          callback(err);
          return;
        }

        bundleVersion = version;
        callback();
        return;
      });
    }
  ],

  function(err) {
    if (err) {
      callback(err);
      return;
    }

    callback(null, {
      'name': instance.name,
      'bundle_name': bundleName,
      'bundle_version': bundleVersion
    });
    return;
  });
}

function listInstances(req, res) {
  deployment.getInstanceList(function(err, instances) {
    if (err) {
      return http.returnError(res, 500, err.message);
    }

    // Format each instance
    async.map(instances, formatInstance, function(err, instanceList) {
      if (err) {
        return http.returnError(res, 500, err.message);
      }

      // Sort by name
      instanceList.sort(function(a, b) {
        return (b.name < a.name);
      });

      http.returnJson(res, 200, instanceList);
    });
  });
}

function getInstance(req, res) {
  var instanceName = req.params.instanceName;

  deployment.getInstance(instanceName, function(err, instance) {
    if (err) {
      return http.returnError(res, 404, 'No such instance');
    }
    formatInstance(instance, function(err, instanceData) {
      if (err) {
        return http.returnError(res, 500, err.message);
      }
      http.returnJson(res, 200, instanceData);
    });
  });
}

function createInstance(req, res) {
  var instanceName = req.params.instanceName;
  var params = req.body;
  var bundleName = params.bundle_name;
  var bundleVersion = params.bundle_version;
  var enableService = params.enable_service;

  deployment.createInstance(instanceName, bundleName, bundleVersion,
                            enableService, function(err) {
    if (err) {
      http.returnError(res, 500, err.message);
    }
    else {
      http.returnJson(res, 200, {
        'result': 'success'
      });
    }
  });
}

function upgradeInstance(req, res) {
  var instanceName = req.params.instanceName;
  var params = req.body;
  var bundleVersion = params.bundle_version;

  deployment.upgradeInstance(instanceName, bundleVersion, function(err) {
    if (err) {
      http.returnError(res, 500, err.message);
    }
    else {
      http.returnJson(res, 200, {
        'result': 'success'
      });
    }
  });
}

function destroyInstance(req, res) {
  var instanceName = req.params.instanceName;

  deployment.getInstance(instanceName, function(err, instance) {
    if (err) {
      return http.returnError(res, 404, 'No such instance');
    }
    instance.destroy(function() {
      http.returnJson(res, 200, {
        'result': 'success'
      });
    });
  });
}

function register(app, apiVersion) {
  app.get('/', listInstances);
  app.get('/:instanceName/', getInstance);
  app.put('/:instanceName/', requiredParams(['bundle_name', 'bundle_version']), createInstance);
  app.post('/:instanceName/upgrade/', requiredParams(['bundle_version']), upgradeInstance);
  app.del('/:instanceName/', destroyInstance);
}

exports.register = register;
<|endoftext|>