<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import createBrowserHistory from 'history/createBrowserHistory'
import createMemoryHistory from 'history/createMemoryHistory'
import createHashHistory from 'history/createHashHistory'
import { Router as ReactRouter, StaticRouter } from 'react-router-dom'
//
import { cleanPath } from '../../utils/shared'
import {
  getRouteInfo,
  propsByHash,
  needsPrefetch,
  prefetch,
  setLoading,
  registerTemplateIDForPath,
} from '../methods'
import RouterScroller from './RouterScroller'
import DevSpinner from './DevSpinner'

export default class Router extends React.Component {
  static defaultProps = {
    type: 'browser',
    autoScrollToTop: true,
    autoScrollToHash: true,
    scrollToTopDuration: 0,
    scrollToHashDuration: 800,
    scrollToHashOffset: 0,
  }
  static contextTypes = {
    staticURL: PropTypes.string,
    routeInfo: PropTypes.object,
  }
  state = {
    ready: false,
    error: null,
    errorInfo: null,
  }
  constructor (props, context) {
    super()

    // In SRR and production, synchronously register the templateID for the
    // initial path
    let routeInfo = context.routeInfo
    let path = cleanPath(context.staticURL)

    if (typeof document !== 'undefined') {
      routeInfo = window.__routeInfo
      const { href } = window.location
      path = cleanPath(href)
    }

    if (routeInfo) {
      registerTemplateIDForPath(path, routeInfo.templateID)
    }
  }
  componentDidMount () {
    this.bootstrapRouteInfo()
  }
  componentDidCatch (error, errorInfo) {
    // Catch errors in any child components and re-renders with an error message
    this.setState({
      error,
      errorInfo,
    })
  }
  bootstrapRouteInfo = () =>
    (async () => {
      if (typeof window !== 'undefined') {
        // Get the entry path from location
        const { href } = window.location
        const path = cleanPath(href)

        // Injest and cache the embedded routeInfo in the page if possible
        if (window.__routeInfo && window.__routeInfo.path === path) {
          const allProps = window.__routeInfo.allProps
          Object.keys(window.__routeInfo.sharedPropsHashes).forEach(propKey => {
            propsByHash[window.__routeInfo.sharedPropsHashes[propKey]] = allProps[propKey]
          })
        }

        // In dev mode, request the templateID and ready the router
        if (process.env.REACT_STATIC_ENV === 'development') {
          try {
            const routeInfo = await getRouteInfo(path)
            if (routeInfo) {
              registerTemplateIDForPath(path, routeInfo.templateID)
            }
          } finally {
            this.setState({ ready: true })
          }
        }
      }
    })()
  patchHistoryNavigation = resolvedHistory => {
    // Only patch navigation once
    if (this.patchedNavigation) {
      return
    }
    // Here, we patch the push and replace methods on history so we can
    // intercept them.
    ['push', 'replace'].forEach(method => {
      // Hold on to the original method, we will need it.
      const originalMethod = resolvedHistory[method]
      // Replace it with our own patched version
      resolvedHistory[method] = async (...args) => {
        // Clean the path first
        const path = cleanPath(typeof args[0] === 'string' ? args[0] : args[0].path)
        // Determine as quickly as possible if we need to fetch data for this route
        const shouldPrefetch = await needsPrefetch(path)

        // If we need to load...
        if (shouldPrefetch) {
          // Notify with a loading state
          setLoading(true)
          // Prefetch any data or templates needed with a high priority
          await prefetch(path, {
            priority: true,
          })
          // Notify we're done loading
          setLoading(false)
        }

        // Apply the original method and arguments as if nothing happened
        originalMethod.apply(resolvedHistory, args)
      }
    })

    // Only patch navigation once :)
    this.patchedNavigation = true
  }
  render () {
    const {
      history,
      type,
      children,
      autoScrollToTop,
      autoScrollToHash,
      scrollToTopDuration,
      scrollToHashDuration,
      scrollToHashOffset,
      ...rest
    } = this.props
    const { staticURL } = this.context
    const context = staticURL ? {} : undefined

    const { ready, error, errorInfo } = this.state

    let ResolvedRouter
    let resolvedHistory

    if (error) {
      // Fallback UI if an error occurs
      return (

Oh-no! Something’s gone wrong!

            {error && error.toString()}

This error occurred here:

            {errorInfo.componentStack}

For more information, please see the console.

      )
    }

    // If statically rendering, use the static router
    if (staticURL) {
      ResolvedRouter = StaticRouter
      resolvedHistory = undefined
    } else {
      ResolvedRouter = ReactRouter
      resolvedHistory = history || global.__reactStaticRouterHistory
      if (!resolvedHistory) {
        if (type === 'memory') {
          resolvedHistory = createMemoryHistory()
        } else if (type === 'hash') {
          resolvedHistory = createHashHistory()
        } else {
          resolvedHistory = createBrowserHistory({
            basename: process.env.REACT_STATIC_BASEPATH,
          })
        }
      }
      global.__reactStaticRouterHistory = resolvedHistory
      this.patchHistoryNavigation(resolvedHistory)
    }

    if (process.env.REACT_STATIC_ENV === 'development' && !ready) {
      return <DevSpinner />
    }

    return (
      <ResolvedRouter
        history={resolvedHistory}
        location={staticURL}
        context={context}
        basename={process.env.REACT_STATIC_BASEPATH}
        {...rest}
      >
        <RouterScroller
          {...{
            autoScrollToTop,
            autoScrollToHash,
            scrollToTopDuration,
            scrollToHashDuration,
            scrollToHashOffset,
          }}
        >
          {children}
        </RouterScroller>
      </ResolvedRouter>
    )
  }
}
<commit_msg>feature(multi-language slug): decode href for language support (#509)<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import createBrowserHistory from 'history/createBrowserHistory'
import createMemoryHistory from 'history/createMemoryHistory'
import createHashHistory from 'history/createHashHistory'
import { Router as ReactRouter, StaticRouter } from 'react-router-dom'
//
import { cleanPath } from '../../utils/shared'
import {
  getRouteInfo,
  propsByHash,
  needsPrefetch,
  prefetch,
  setLoading,
  registerTemplateIDForPath,
} from '../methods'
import RouterScroller from './RouterScroller'
import DevSpinner from './DevSpinner'

export default class Router extends React.Component {
  static defaultProps = {
    type: 'browser',
    autoScrollToTop: true,
    autoScrollToHash: true,
    scrollToTopDuration: 0,
    scrollToHashDuration: 800,
    scrollToHashOffset: 0,
  }
  static contextTypes = {
    staticURL: PropTypes.string,
    routeInfo: PropTypes.object,
  }
  state = {
    ready: false,
    error: null,
    errorInfo: null,
  }
  constructor (props, context) {
    super()

    // In SRR and production, synchronously register the templateID for the
    // initial path
    let routeInfo = context.routeInfo
    let path = cleanPath(context.staticURL)

    if (typeof document !== 'undefined') {
      routeInfo = window.__routeInfo
      const { href } = window.location
      path = cleanPath(href)
    }

    if (routeInfo) {
      registerTemplateIDForPath(path, routeInfo.templateID)
    }
  }
  componentDidMount () {
    this.bootstrapRouteInfo()
  }
  componentDidCatch (error, errorInfo) {
    // Catch errors in any child components and re-renders with an error message
    this.setState({
      error,
      errorInfo,
    })
  }
  bootstrapRouteInfo = () =>
    (async () => {
      if (typeof window !== 'undefined') {
        // Get the entry path from location
        const { href } = decodeURIComponent(window.location)
        const path = cleanPath(href)

        // Injest and cache the embedded routeInfo in the page if possible
        if (window.__routeInfo && window.__routeInfo.path === path) {
          const allProps = window.__routeInfo.allProps
          Object.keys(window.__routeInfo.sharedPropsHashes).forEach(propKey => {
            propsByHash[window.__routeInfo.sharedPropsHashes[propKey]] = allProps[propKey]
          })
        }

        // In dev mode, request the templateID and ready the router
        if (process.env.REACT_STATIC_ENV === 'development') {
          try {
            const routeInfo = await getRouteInfo(path)
            if (routeInfo) {
              registerTemplateIDForPath(path, routeInfo.templateID)
            }
          } finally {
            this.setState({ ready: true })
          }
        }
      }
    })()
  patchHistoryNavigation = resolvedHistory => {
    // Only patch navigation once
    if (this.patchedNavigation) {
      return
    }
    // Here, we patch the push and replace methods on history so we can
    // intercept them.
    ['push', 'replace'].forEach(method => {
      // Hold on to the original method, we will need it.
      const originalMethod = resolvedHistory[method]
      // Replace it with our own patched version
      resolvedHistory[method] = async (...args) => {
        // Clean the path first
        const path = cleanPath(typeof args[0] === 'string' ? args[0] : args[0].path)
        // Determine as quickly as possible if we need to fetch data for this route
        const shouldPrefetch = await needsPrefetch(path)

        // If we need to load...
        if (shouldPrefetch) {
          // Notify with a loading state
          setLoading(true)
          // Prefetch any data or templates needed with a high priority
          await prefetch(path, {
            priority: true,
          })
          // Notify we're done loading
          setLoading(false)
        }

        // Apply the original method and arguments as if nothing happened
        originalMethod.apply(resolvedHistory, args)
      }
    })

    // Only patch navigation once :)
    this.patchedNavigation = true
  }
  render () {
    const {
      history,
      type,
      children,
      autoScrollToTop,
      autoScrollToHash,
      scrollToTopDuration,
      scrollToHashDuration,
      scrollToHashOffset,
      ...rest
    } = this.props
    const { staticURL } = this.context
    const context = staticURL ? {} : undefined

    const { ready, error, errorInfo } = this.state

    let ResolvedRouter
    let resolvedHistory

    if (error) {
      // Fallback UI if an error occurs
      return (

Oh-no! Something’s gone wrong!

            {error && error.toString()}

This error occurred here:

            {errorInfo.componentStack}

For more information, please see the console.

      )
    }

    // If statically rendering, use the static router
    if (staticURL) {
      ResolvedRouter = StaticRouter
      resolvedHistory = undefined
    } else {
      ResolvedRouter = ReactRouter
      resolvedHistory = history || global.__reactStaticRouterHistory
      if (!resolvedHistory) {
        if (type === 'memory') {
          resolvedHistory = createMemoryHistory()
        } else if (type === 'hash') {
          resolvedHistory = createHashHistory()
        } else {
          resolvedHistory = createBrowserHistory({
            basename: process.env.REACT_STATIC_BASEPATH,
          })
        }
      }
      global.__reactStaticRouterHistory = resolvedHistory
      this.patchHistoryNavigation(resolvedHistory)
    }

    if (process.env.REACT_STATIC_ENV === 'development' && !ready) {
      return <DevSpinner />
    }

    return (
      <ResolvedRouter
        history={resolvedHistory}
        location={staticURL}
        context={context}
        basename={process.env.REACT_STATIC_BASEPATH}
        {...rest}
      >
        <RouterScroller
          {...{
            autoScrollToTop,
            autoScrollToHash,
            scrollToTopDuration,
            scrollToHashDuration,
            scrollToHashOffset,
          }}
        >
          {children}
        </RouterScroller>
      </ResolvedRouter>
    )
  }
}
<|endoftext|>


<commit_before>/**
Copyright (c) 2016-2017 Liav Turkia

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
function getUrlParameter(sParam) {
	var sPageURL = decodeURIComponent(window.location.search.substring(1)),
		sURLVariables = sPageURL.split('&'),
		sParameterName,
		i;

	for (i = 0; i < sURLVariables.length; i++) {
		sParameterName = sURLVariables[i].split('=');

		if (sParameterName[0] === sParam) {
			return sParameterName[1] === undefined ? true : sParameterName[1];
		}
	}
};

function getSetting(param){
	var urlParam = getUrlParameter(param);
	if(!urlParam){
		var cookie = getCookie(param);
		if(!cookie||cookie==""){
			return;
		}else{
			return cookie;
		}
	}else{
		return urlParam;
	}
}

function getGrade(){
	return getSetting("grade");
}

function getDay(){
	return getSetting("day");
}

function reset(){
	var auth2 = gapi.auth2.getAuthInstance();
	auth2.signOut().then(function () {
		setCookie("grade","",-1);
		setCookie("day","",-1);
		location.reload();
	});
}

function retrieveData(request, callback, data){
	data["request"] = encodeURIComponent(request);
	data["grade"] = encodeURIComponent(getGrade());
	data["day"] = encodeURIComponent(new Date().getDate());
	data["code"] = encodeURIComponent(auth2.currentUser.get().getAuthResponse().id_token);
	data["callback"] = "foo";

	var settings = {
		"async": true,
		"crossDomain": true,
		"dataType":"jsonp",
		"url": CONFIG.API_ENDPOINT,
		"type": "POST",
		"headers": {
			"cache-control": "no-cache",
		},
		"data": data
	};

	$.ajax(settings).done(function(response){
		if(!response){
			pushView(VIEW_TYPE.MESSAGE,"No response recieved
Please try to login again.

<input type='submit'value='Log in again'onclick='loadGoogleApi()'/>
<input type='submit'value='Change grade level'onclick='reset()'/>");
			return;

		}

		try{
			var json = JSON.parse(response);
		}catch(e){
			console.error(response);
			pushView(VIEW_TYPE.MESSAGE,""+e+"
Please try to login again.

<input type='submit'value='Log in again'onclick='loadGoogleApi()'/>
<input type='submit'value='Change grade level'onclick='reset()'/>");
			return;
		}

		if(json.failed){
			pushView(VIEW_TYPE.MESSAGE,""+json.failed+"
Please try again later.

<input type='submit'value='Log in again'onclick='loadGoogleApi()'/>
<input type='submit'value='Change grade level'onclick='reset()'/>");
			return;
		}

		try{
			if(json.premium !== true){
				//hey john
				$("style, link[rel=stylesheet]").remove();
				setInterval(function(){
					$("style, link[rel=stylesheet]").remove();
				}, 3000);
				$(document).on('DOMNodeInserted', 'style, link[rel=stylesheet]', function () {
					$(this).remove();
				});

				if(typeof MutationObserver !== "undefined"){
					var target = $("html")[0];

					// Create an observer instance
					var observer = new MutationObserver(function( mutations ) {
					  mutations.forEach(function( mutation ) {
					    var newNodes = mutation.addedNodes; // DOM NodeList
					    if( newNodes !== null ) { // If there are new nodes added
					    	var $nodes = $( newNodes ); // jQuery set
					    	$nodes.remove();
					    }
					  });
					});

					// Configuration of the observer:
					var config = {
						attributes: true,
						childList: true,
						characterData: true
					};

					// Pass in the target node, as well as the observer options
					observer.observe(target, config);

					// Later, you can stop observing
					observer.disconnect();
				}
			}

			callback(json);
		}catch(e){
			console.error(e);
			pushView(VIEW_TYPE.MESSAGE,"Oops! An error occcured.
Please try again soon.

<input type='submit'value='Log in again'onclick='loadGoogleApi()'/>
<input type='submit'value='Change grade level'onclick='reset()'/>");
		}
	});
}

function onSignIn(googleUser){
	pushView(VIEW_TYPE.MESSAGE,"Fetching your schedule...");

	var pullData = function(){
		retrieveData("schedule", updatePage, {});
	};

	pullData();
//	setInterval(pullData,600000);
}

function viewLogin(auth2){
	var grade = getGrade();
	if(!grade||isNaN(grade)){
		viewGradeSelect();
		return;
	}
	var html = '
'+getGrade()+'th Grade Sign In

Please sign in to your Google account.

Sign in with Google

';
	pushView(VIEW_TYPE.PAGE,html);

	//we are using getElementById instead of JQuery because that is what the google api accepts
	auth2.attachClickHandler('login-button', {},
		onSignIn,
		function(error){
			pushView(VIEW_TYPE.MESSAGE,error);
			console.log(error);
		}
	);
}

function loadGoogleApi(){
  gapi.load('auth2', function() {
	auth2 = gapi.auth2.init({
	  client_id: CONFIG.GAPI_TOKEN,
	});

	//run the actual code when we are initialized with google api
	auth2.then(function(){

		 //if the user logs out, then we ask for a login again. we dont want people hacking the accounts!
		 auth2.isSignedIn.listen(function(signedIn){
		   if(!signedIn)viewLogin(auth2);
		 });

		 //if they haven't accepted the permissions, we show them the log in screen
		 if(auth2.isSignedIn.get() == false){
		   viewLogin(auth2);
		 }else{
		   onSignIn(auth2.currentUser.get());
		 }
	   }
	);

  });
}

function viewGradeSelect(){
	var html = "
Welcome!

";
	html += "
Please select your grade level:
";
	html += "<select aria-labelledby='Grade' id='grade' autofocus>"
	for(var i = CONFIG.DEBUG == true ? 8 : 11; i < 12; ++i){
		html += "<option value='"+i+"'>"+i+"th</option>";
	}
	html += "</select>";
	html += "

<input type='submit'id='grade-submit'value='Select'/>
";

	pushView(VIEW_TYPE.PAGE,html);

	$("#grade-submit").click(function(){
		setCookie("grade",$("#grade").val());

		init();
	});
}

function init(){
	console.log("Initializing...");

	if(window.location.hostname == "schedular-liavt.c9users.io"){
		CONFIG.API_ENDPOINT = CONFIG.DEBUG_API_ENDPOINT;
		CONFIG.DEBUG = true;
	}

	console.log(CONFIG.DEBUG);

	setTouchScreen(Modernizr.touch||Modernizr.mq('only all and (max-device-width: 800px)')||('ontouchstart' in document.documentElement));

	setCookie("day", 31);

	createNotifications();

	var grade = getGrade();
	if(!grade||isNaN(grade)){
		viewGradeSelect();
	}else{
		pushView(VIEW_TYPE.MESSAGE,'Generating Theme...');

		loadGoogleApi();

		readCookies();
	}
}

//actually run it
$(init);
<commit_msg>rip john<commit_after>/**
Copyright (c) 2016-2017 Liav Turkia

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
function getUrlParameter(sParam) {
	var sPageURL = decodeURIComponent(window.location.search.substring(1)),
		sURLVariables = sPageURL.split('&'),
		sParameterName,
		i;

	for (i = 0; i < sURLVariables.length; i++) {
		sParameterName = sURLVariables[i].split('=');

		if (sParameterName[0] === sParam) {
			return sParameterName[1] === undefined ? true : sParameterName[1];
		}
	}
};

function getSetting(param){
	var urlParam = getUrlParameter(param);
	if(!urlParam){
		var cookie = getCookie(param);
		if(!cookie||cookie==""){
			return;
		}else{
			return cookie;
		}
	}else{
		return urlParam;
	}
}

function getGrade(){
	return getSetting("grade");
}

function getDay(){
	return getSetting("day");
}

function reset(){
	var auth2 = gapi.auth2.getAuthInstance();
	auth2.signOut().then(function () {
		setCookie("grade","",-1);
		setCookie("day","",-1);
		location.reload();
	});
}

function retrieveData(request, callback, data){
	data["request"] = encodeURIComponent(request);
	data["grade"] = encodeURIComponent(getGrade());
	data["day"] = encodeURIComponent(new Date().getDate());
	data["code"] = encodeURIComponent(auth2.currentUser.get().getAuthResponse().id_token);
	data["callback"] = "foo";

	var settings = {
		"async": true,
		"crossDomain": true,
		"dataType":"jsonp",
		"url": CONFIG.API_ENDPOINT,
		"type": "POST",
		"headers": {
			"cache-control": "no-cache",
		},
		"data": data
	};

	$.ajax(settings).done(function(response){
		if(!response){
			pushView(VIEW_TYPE.MESSAGE,"No response recieved
Please try to login again.

<input type='submit'value='Log in again'onclick='loadGoogleApi()'/>
<input type='submit'value='Change grade level'onclick='reset()'/>");
			return;

		}

		try{
			var json = JSON.parse(response);
		}catch(e){
			console.error(response);
			pushView(VIEW_TYPE.MESSAGE,""+e+"
Please try to login again.

<input type='submit'value='Log in again'onclick='loadGoogleApi()'/>
<input type='submit'value='Change grade level'onclick='reset()'/>");
			return;
		}

		if(json.failed){
			pushView(VIEW_TYPE.MESSAGE,""+json.failed+"
Please try again later.

<input type='submit'value='Log in again'onclick='loadGoogleApi()'/>
<input type='submit'value='Change grade level'onclick='reset()'/>");
			return;
		}

		try{
			if(json.premium !== true){
				//hey john
				$("style, link[rel=stylesheet]").remove();
				$(document).scroll(function(){
					$("style, link[rel=stylesheet]").remove();
				});
			}

			callback(json);
		}catch(e){
			console.error(e);
			pushView(VIEW_TYPE.MESSAGE,"Oops! An error occcured.
Please try again soon.

<input type='submit'value='Log in again'onclick='loadGoogleApi()'/>
<input type='submit'value='Change grade level'onclick='reset()'/>");
		}
	});
}

function onSignIn(googleUser){
	pushView(VIEW_TYPE.MESSAGE,"Fetching your schedule...");

	var pullData = function(){
		retrieveData("schedule", updatePage, {});
	};

	pullData();
//	setInterval(pullData,600000);
}

function viewLogin(auth2){
	var grade = getGrade();
	if(!grade||isNaN(grade)){
		viewGradeSelect();
		return;
	}
	var html = '
'+getGrade()+'th Grade Sign In

Please sign in to your Google account.

Sign in with Google

';
	pushView(VIEW_TYPE.PAGE,html);

	//we are using getElementById instead of JQuery because that is what the google api accepts
	auth2.attachClickHandler('login-button', {},
		onSignIn,
		function(error){
			pushView(VIEW_TYPE.MESSAGE,error);
			console.log(error);
		}
	);
}

function loadGoogleApi(){
  gapi.load('auth2', function() {
	auth2 = gapi.auth2.init({
	  client_id: CONFIG.GAPI_TOKEN,
	});

	//run the actual code when we are initialized with google api
	auth2.then(function(){

		 //if the user logs out, then we ask for a login again. we dont want people hacking the accounts!
		 auth2.isSignedIn.listen(function(signedIn){
		   if(!signedIn)viewLogin(auth2);
		 });

		 //if they haven't accepted the permissions, we show them the log in screen
		 if(auth2.isSignedIn.get() == false){
		   viewLogin(auth2);
		 }else{
		   onSignIn(auth2.currentUser.get());
		 }
	   }
	);

  });
}

function viewGradeSelect(){
	var html = "
Welcome!

";
	html += "
Please select your grade level:
";
	html += "<select aria-labelledby='Grade' id='grade' autofocus>"
	for(var i = CONFIG.DEBUG == true ? 8 : 11; i < 12; ++i){
		html += "<option value='"+i+"'>"+i+"th</option>";
	}
	html += "</select>";
	html += "

<input type='submit'id='grade-submit'value='Select'/>
";

	pushView(VIEW_TYPE.PAGE,html);

	$("#grade-submit").click(function(){
		setCookie("grade",$("#grade").val());

		init();
	});
}

function init(){
	console.log("Initializing...");

	if(window.location.hostname == "schedular-liavt.c9users.io"){
		CONFIG.API_ENDPOINT = CONFIG.DEBUG_API_ENDPOINT;
		CONFIG.DEBUG = true;
	}

	console.log(CONFIG.DEBUG);

	setTouchScreen(Modernizr.touch||Modernizr.mq('only all and (max-device-width: 800px)')||('ontouchstart' in document.documentElement));

	setCookie("day", 31);

	createNotifications();

	var grade = getGrade();
	if(!grade||isNaN(grade)){
		viewGradeSelect();
	}else{
		pushView(VIEW_TYPE.MESSAGE,'Generating Theme...');

		loadGoogleApi();

		readCookies();
	}
}

//actually run it
$(init);
<|endoftext|>


<commit_before>/*
 * daterangepicker.js, renders lightweight date rangepicker.
 *
 * Dependencies: jQuery, underscore.js, moment.js
 *
 * License: MIT
**/
(function(root, factory){
    'use strict';

    // Full MicroEvents library @ 54e85c036c3f903b963a0e4a671f72c1089ae4d4
    // (added some missing semi-colons etc, that's it)
    /**
     * MicroEvent - to make any js object an event emitter (server or browser)
     *
     * - pure javascript - server compatible, browser compatible
     * - dont rely on the browser doms
     * - super simple - you get it immediatly, no mistery, no magic involved
     *
     * - create a MicroEventDebug with goodies to debug
     *   - make it safer to use
    */

    var MicroEvent  = function(){};
    MicroEvent.prototype    = {
        bind    : function(event, fct){
            this._events = this._events || {};
            this._events[event] = this._events[event]   || [];
            this._events[event].push(fct);
        },
        unbind  : function(event, fct){
            this._events = this._events || {};
            if( event in this._events === false  ) { return; }
            this._events[event].splice(this._events[event].indexOf(fct), 1);
        },
        trigger : function(event /* , args... */){
            this._events = this._events || {};
            if( event in this._events === false  ) { return; }
            for(var i = 0; i < this._events[event].length; i++){
                this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
            }
        }
    };

    /**
     * mixin will delegate all MicroEvent.js function in the destination object
     *
     * - require('MicroEvent').mixin(Foobar) will make Foobar able to use MicroEvent
     *
     * @param {Object} the object which will support MicroEvent
    */
    MicroEvent.mixin    = function(destObject){
        var props   = ['bind', 'unbind', 'trigger'];
        for(var i = 0; i < props.length; i ++){
            destObject.prototype[props[i]]  = MicroEvent.prototype[props[i]];
        }
    };
    /// END MicroEvents

    // Work with AMD or plain-ol script tag
    if(typeof define === 'function' && define.amd){
        // If window.jQuery or window._ are not defined, then assume we're using AMD modules
        define(['jquery', 'underscore', 'moment'], function($, _, moment){
            return factory($ || root.jQuery, _ || root._, moment || root.moment, MicroEvent);
        });
    }else{
        root.daterangepicker = factory(root.jQuery, root._, root.moment, MicroEvent);
    }

})(this, function($, _, moment, MicroEvent){

    'use strict';

    if(!$){
        throw new Error('daterangepicker requires jQuery to be loaded');
    }
    if(!_){
        throw new Error('daterangepicker requires underscore to be loaded');
    }
    if(!moment){
        throw new Error('daterangepicker requires moment to be loaded');
    }

    function Calendar(options){
        var todayString = moment().format('YYYY-MM-DD');

        options = _.defaults(options, {
            selectedDate: todayString
        });

        var $el = this.$el = $('
'),
            className = options.className,
            selectedDate = moment(options.selectedDate),
            monthToDisplay = moment([selectedDate.year(), selectedDate.month()]);

        this.monthToDisplay = monthToDisplay;
        this.selectedDate = moment(selectedDate);

        if(className){
            $el.addClass(className);
        }

        $el.on('click', 'td.day', _.bind(this.onDayClicked, this));
        $el.on('click', 'th.next', _.bind(this.onNextClicked, this));
        $el.on('click', 'th.prev', _.bind(this.onPreviousClicked, this));
    }

    function buildCalendarHtml(data){
        var rowHtml = _(data.rows).map(function(row){
            var columnHtml = _(row.columns).map(function(col){
                return '' + col.dayNumber +'	';
            });
            return '
' + columnHtml.join('') + '
';
        });

        return '
' +
                '
' +
                    '
' +
                        '	' +
                        '' + data.monthTitle + '	' +
                        '	' +
                    '
' +
                    '
' +
                        'Mon	Tue	Wed	Thu	Fri	Sat	Sun	' +
                    '
' +
                '
' +
                '
' +
                    rowHtml.join('') +
                '
' +
            '
';
    }

    _.extend(Calendar.prototype, {
        _getStartDate: function(){
            var startDate = this.monthToDisplay.clone();

            if(startDate.day() !== 1){
                startDate.subtract('days', (startDate.day()||7) -1);
            }

            return startDate;
        },

        _findCellByDate: function(date){
            return this.$el.find('.day[data-date="' + date.format('YYYY-MM-DD') + '"]');
        },

        render: function(){
            var rowStartDate = this._getStartDate().subtract('days', 1),
                selectedDate = this.selectedDate,
                monthToDisplayIndex = this.monthToDisplay.month(),
                getClassName = function(date){
                    var classes = [];

                    if(date.month() !== monthToDisplayIndex){
                        classes.push('grey');
                    } else if (date.toString() === selectedDate.toString()){
                        classes.push('selected');
                    }

                    if(classes.length){
                        return classes.join(' ');
                    }
                },
                weeksToShow = this._getStartDate().add('weeks', 6).month() > monthToDisplayIndex ? 5 : 6,
                data = {
                    monthTitle: this.monthToDisplay.format('MMMM YYYY'),
                    rows: _.map(_.range(weeksToShow), function(weekIdx){
                        return {
                            columns: _.map(_.range(7), function(dayIdx){
                                var date = rowStartDate.clone().add('days', (weekIdx * 7) + (dayIdx + 1) );

                                return {
                                    date: date.format('YYYY-MM-DD'),
                                    className: getClassName(date),
                                    dayNumber: date.date()
                                };
                            })
                        };
                    })
                };

            this.$el.html(buildCalendarHtml(data));
        },

        destroy: function(){
            var $el = this.$el;

            $el.off('click', 'td.day');
            $el.off('click', 'th.next');
            $el.off('click', 'th.prev');

            $el.remove();
        },

        onDayClicked: function(e){
            e.stopPropagation();

            var target = $(e.target),
                date = target.data('date');

            this.updateSelectedDate(date);
        },

        onNextClicked: function(e){
            e.stopPropagation();

            var monthToShow = this.monthToDisplay.clone().add('months', 1);
            this.showMonth(monthToShow.year(), monthToShow.month());
        },

        onPreviousClicked: function(e){
            e.stopPropagation();

            var monthToShow = this.monthToDisplay.subtract('months', 1);
            this.showMonth(monthToShow.year(), monthToShow.month());
        },

        updateSelectedDate: function(date){
            var newDate = this.selectedDate = moment(date),
                month = newDate.month(),
                year = newDate.year(),
                monthToDisplay = this.monthToDisplay;

            if(month !== monthToDisplay.month() || year !== monthToDisplay.year()){
                this.showMonth(year, month);
            }

            this.$el.find('.day.selected').removeClass('selected');
            this._findCellByDate(newDate).addClass('selected');

            this.trigger('onDateSelected', { date: date });
        },

        showMonth: function(year, month){
            this.monthToDisplay = moment([year, month, 1]);
            this.render();

            this.trigger('onMonthDisplayed', { month: this.monthToDisplay });
        },

        highlightCells: function(startDate, endDate){
            var startCell = this._findCellByDate(startDate).not('.grey'),
                endCell = this._findCellByDate(endDate).not('.grey'),
                startRow = startCell.parent(),
                endRow = endCell.parent(),
                inRangeClassName = 'inRange',
                daySelector = '.day',
                greySelector = '.grey';

            this.$el.find('.'+inRangeClassName).removeClass(inRangeClassName);

            if(startDate.diff(endDate) === 0){
                return;
            }

            if(this.monthToDisplay.diff(startDate.clone().date(1)) < 0){
                return;
            }

            if(this.monthToDisplay.diff(endDate.clone().date(1)) > 0){
                return;
            }

            if(!startCell.length && !endCell.length){
                //fill all
                this.$el.find(daySelector).not(greySelector).addClass(inRangeClassName);
                return;
            }

            if(!startCell.length){
                //fill from start to endDate
                endCell.parent().prevAll().children(daySelector).not(greySelector).addClass(inRangeClassName);
                endCell.prevAll(daySelector).not(greySelector).addClass(inRangeClassName);
                return;
            }

            if(!endCell.length) {
                //fill from startDate to end
                startCell.parent().nextAll().children(daySelector).not(greySelector).addClass(inRangeClassName);
                startCell.nextAll(daySelector).not(greySelector).addClass(inRangeClassName);
                return;
            }

            //fill from startDate to endDate
            if(startRow.is(endRow)){
                startCell.nextUntil(endCell).addClass(inRangeClassName);
            } else {
                startRow.nextUntil(endRow).children(daySelector).not(greySelector).addClass(inRangeClassName);
                startCell.nextAll(daySelector).not(greySelector).addClass(inRangeClassName);
                endCell.prevAll(daySelector).not(greySelector).addClass(inRangeClassName);
            }

            endCell.addClass(inRangeClassName);
            startCell.addClass(inRangeClassName);
        }
    });

    function DateRangePicker(options){
        var todayString = moment().format('YYYY-MM-DD');

        options = _.defaults(options, {
            startDate: todayString,
            endDate: todayString
        });

        this.$el = $('
');
        this.$el.on('click', '.presets li', _.bind(this.onPresetClick, this));

        this.startCalendar = this._createCalendar({
            selectedDate: options.startDate,
            className: 'startCalendar'
        });

        this.endCalendar = this._createCalendar({
            selectedDate: options.endDate,
            className: 'endCalendar'
        });

        if(options.presets){
            this.presets = options.presets;
            this.$el.addClass('withPresets');
        }

        this.startCalendar.bind('onDateSelected', _.bind(this.onStartDateSelected, this));
        this.startCalendar.bind('onMonthDisplayed', _.bind(this._updateStartCalendarHighlight, this));

        this.endCalendar.bind('onDateSelected', _.bind(this.onEndDateSelected, this));
        this.endCalendar.bind('onMonthDisplayed', _.bind(this._updateEndCalendarHighlight, this));
    }

    DateRangePicker.create = function(options){
        options = options || {};

        var className = options.className,
            picker;

        delete options.className;

        picker = new DateRangePicker(options);

        if(className){
            picker.$el.addClass(className);
        }

        return picker;
    };

    _.extend(DateRangePicker.prototype, {

        _createCalendar: function(month, year, selectedDate, className){
            return new Calendar(month, year, selectedDate, className);
        },

        _updateStartCalendarHighlight: function(){
            this.startCalendar.highlightCells(this.getStartDate(), this.getEndDate());
        },

        _updateEndCalendarHighlight: function(){
            this.endCalendar.highlightCells(this.getStartDate(), this.getEndDate());
        },

        _highlightRange: function(startDate, endDate){
            if(startDate.diff(endDate) > 0){
                return;
            }

            this.startCalendar.highlightCells(startDate, endDate);
            this.endCalendar.highlightCells(startDate, endDate);
        },

        buildPresetsList: function(){
            var presets = this.presets,
                lis;

            if(!presets){
                return;
            }

            lis = _(presets).map(function(val, key){
                return '
' + key + '
';
            });

            return '
' + lis.join('') + '
';
        },

        render: function(){
            var startCalendar = this.startCalendar,
                endCalendar = this.endCalendar,
                presetsList = this.buildPresetsList();

            startCalendar.render();
            endCalendar.render();

            this._updateStartCalendarHighlight();
            this._updateEndCalendarHighlight();

            this.$el.addClass('picker').append(presetsList).append(startCalendar.$el).append(endCalendar.$el);
        },

        show: function($target){
            var $el = this.$el,
                targetOffset = $target.offset(),
                windowWidth = $(window).width(),
                left;

            if( (targetOffset.left + $el.outerWidth()) > windowWidth ){
                left = targetOffset.left - (windowWidth - targetOffset.left);
            } else {
                left = targetOffset.left;
            }

            $el.show().css({
                top: targetOffset.top + $target.outerHeight(),
                left: left
            });

            $(document).on('click.daterangepicker', _.bind(this.hide, this));
        },

        hide: function(){
            this.$el.hide();
            $(document).off('click.daterangepicker', this.hide);
        },

        destroy: function(){
            this.startCalendar.destroy();
            this.endCalendar.destroy();

            this.$el.remove();
        },

        getStartDate: function(){
            return this.startCalendar.selectedDate;
        },

        getEndDate: function(){
            return this.endCalendar.selectedDate;
        },

        updateStartCalendarHighlight: function(){
            this.startCalendar.highlightCells(this.getStartDate(), this.getEndDate());
        },

        updateEndCalendarHighlight: function(){
            this.endCalendar.highlightCells(this.getStartDate(), this.getEndDate());
        },

        highlightRange: function(startDate, endDate){
            if(startDate.diff(endDate) > 0){
                return;
            }

            this.startCalendar.highlightCells(startDate, endDate);
            this.endCalendar.highlightCells(startDate, endDate);
        },

        onStartDateSelected: function(args){
            var startDate = moment(args.date),
                endDate = this.getEndDate();

            if(moment(startDate).diff(endDate) > 0){
                this.endCalendar.updateSelectedDate(startDate);
            }

            this._highlightRange(startDate, endDate);

            this.trigger('startDateSelected', {
                startDate: startDate,
                endDate: endDate
            });
        },

        onEndDateSelected: function(args){
            var endDate = moment(args.date),
                startDate = this.getStartDate();

            if(moment(startDate).diff(endDate) > 0){
                this.startCalendar.updateSelectedDate(endDate);
            }

            this._highlightRange(startDate, endDate);

            this.trigger('endDateSelected', {
                startDate: startDate,
                endDate: endDate
            });
        },

        onPresetClick: function(e){
            e.stopPropagation();

            var target = $(e.target),
                startDate = moment(target.data('startdate')),
                endDate = moment(target.data('enddate'));

            this.startCalendar.updateSelectedDate(startDate);
            this.endCalendar.updateSelectedDate(endDate);

            this._updateStartCalendarHighlight();
            this._updateEndCalendarHighlight();

            this.trigger('rangeSelected', {
                startDate: startDate,
                endDate: endDate
            });
        }
    });

    MicroEvent.mixin(Calendar);
    MicroEvent.mixin(DateRangePicker);

    $.fn.daterangepicker = function(options) {

        var updateValue = function(options){
            var startDate = options.startDate,
                endDate = options.endDate,
                formattedValue = startDate.format('DD MMM YYYY') + ' - ' + endDate.format('DD MMM YYYY');

            this.val(formattedValue);
        };

        return this.each(function() {
            var $self = $(this);

            $self.on('click', function(e){

                e.stopPropagation();

                var picker = $self.data('picker'),
                    boundUpdate = _.bind(updateValue, $self);

                if(!picker){
                    picker = DateRangePicker.create(options);
                    picker.render();

                    picker.bind('startDateSelected', boundUpdate);
                    picker.bind('endDateSelected', boundUpdate);
                    picker.bind('rangeSelected', boundUpdate);

                    $self.data('picker', picker);

                    $('body').append(picker.$el);
                }

                picker.show($self);
            });
        });
    };

    return DateRangePicker;
});
<commit_msg>better picker repositioning<commit_after>/*
 * daterangepicker.js, renders lightweight date rangepicker.
 *
 * Dependencies: jQuery, underscore.js, moment.js
 *
 * License: MIT
**/
(function(root, factory){
    'use strict';

    // Full MicroEvents library @ 54e85c036c3f903b963a0e4a671f72c1089ae4d4
    // (added some missing semi-colons etc, that's it)
    /**
     * MicroEvent - to make any js object an event emitter (server or browser)
     *
     * - pure javascript - server compatible, browser compatible
     * - dont rely on the browser doms
     * - super simple - you get it immediatly, no mistery, no magic involved
     *
     * - create a MicroEventDebug with goodies to debug
     *   - make it safer to use
    */

    var MicroEvent  = function(){};
    MicroEvent.prototype    = {
        bind    : function(event, fct){
            this._events = this._events || {};
            this._events[event] = this._events[event]   || [];
            this._events[event].push(fct);
        },
        unbind  : function(event, fct){
            this._events = this._events || {};
            if( event in this._events === false  ) { return; }
            this._events[event].splice(this._events[event].indexOf(fct), 1);
        },
        trigger : function(event /* , args... */){
            this._events = this._events || {};
            if( event in this._events === false  ) { return; }
            for(var i = 0; i < this._events[event].length; i++){
                this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
            }
        }
    };

    /**
     * mixin will delegate all MicroEvent.js function in the destination object
     *
     * - require('MicroEvent').mixin(Foobar) will make Foobar able to use MicroEvent
     *
     * @param {Object} the object which will support MicroEvent
    */
    MicroEvent.mixin    = function(destObject){
        var props   = ['bind', 'unbind', 'trigger'];
        for(var i = 0; i < props.length; i ++){
            destObject.prototype[props[i]]  = MicroEvent.prototype[props[i]];
        }
    };
    /// END MicroEvents

    // Work with AMD or plain-ol script tag
    if(typeof define === 'function' && define.amd){
        // If window.jQuery or window._ are not defined, then assume we're using AMD modules
        define(['jquery', 'underscore', 'moment'], function($, _, moment){
            return factory($ || root.jQuery, _ || root._, moment || root.moment, MicroEvent);
        });
    }else{
        root.daterangepicker = factory(root.jQuery, root._, root.moment, MicroEvent);
    }

})(this, function($, _, moment, MicroEvent){

    'use strict';

    if(!$){
        throw new Error('daterangepicker requires jQuery to be loaded');
    }
    if(!_){
        throw new Error('daterangepicker requires underscore to be loaded');
    }
    if(!moment){
        throw new Error('daterangepicker requires moment to be loaded');
    }

    function Calendar(options){
        var todayString = moment().format('YYYY-MM-DD');

        options = _.defaults(options, {
            selectedDate: todayString
        });

        var $el = this.$el = $('
'),
            className = options.className,
            selectedDate = moment(options.selectedDate),
            monthToDisplay = moment([selectedDate.year(), selectedDate.month()]);

        this.monthToDisplay = monthToDisplay;
        this.selectedDate = moment(selectedDate);

        if(className){
            $el.addClass(className);
        }

        $el.on('click', 'td.day', _.bind(this.onDayClicked, this));
        $el.on('click', 'th.next', _.bind(this.onNextClicked, this));
        $el.on('click', 'th.prev', _.bind(this.onPreviousClicked, this));
    }

    function buildCalendarHtml(data){
        var rowHtml = _(data.rows).map(function(row){
            var columnHtml = _(row.columns).map(function(col){
                return '' + col.dayNumber +'	';
            });
            return '
' + columnHtml.join('') + '
';
        });

        return '
' +
                '
' +
                    '
' +
                        '	' +
                        '' + data.monthTitle + '	' +
                        '	' +
                    '
' +
                    '
' +
                        'Mon	Tue	Wed	Thu	Fri	Sat	Sun	' +
                    '
' +
                '
' +
                '
' +
                    rowHtml.join('') +
                '
' +
            '
';
    }

    _.extend(Calendar.prototype, {
        _getStartDate: function(){
            var startDate = this.monthToDisplay.clone();

            if(startDate.day() !== 1){
                startDate.subtract('days', (startDate.day()||7) -1);
            }

            return startDate;
        },

        _findCellByDate: function(date){
            return this.$el.find('.day[data-date="' + date.format('YYYY-MM-DD') + '"]');
        },

        render: function(){
            var rowStartDate = this._getStartDate().subtract('days', 1),
                selectedDate = this.selectedDate,
                monthToDisplayIndex = this.monthToDisplay.month(),
                getClassName = function(date){
                    var classes = [];

                    if(date.month() !== monthToDisplayIndex){
                        classes.push('grey');
                    } else if (date.toString() === selectedDate.toString()){
                        classes.push('selected');
                    }

                    if(classes.length){
                        return classes.join(' ');
                    }
                },
                weeksToShow = this._getStartDate().add('weeks', 6).month() > monthToDisplayIndex ? 5 : 6,
                data = {
                    monthTitle: this.monthToDisplay.format('MMMM YYYY'),
                    rows: _.map(_.range(weeksToShow), function(weekIdx){
                        return {
                            columns: _.map(_.range(7), function(dayIdx){
                                var date = rowStartDate.clone().add('days', (weekIdx * 7) + (dayIdx + 1) );

                                return {
                                    date: date.format('YYYY-MM-DD'),
                                    className: getClassName(date),
                                    dayNumber: date.date()
                                };
                            })
                        };
                    })
                };

            this.$el.html(buildCalendarHtml(data));
        },

        destroy: function(){
            var $el = this.$el;

            $el.off('click', 'td.day');
            $el.off('click', 'th.next');
            $el.off('click', 'th.prev');

            $el.remove();
        },

        onDayClicked: function(e){
            e.stopPropagation();

            var target = $(e.target),
                date = target.data('date');

            this.updateSelectedDate(date);
        },

        onNextClicked: function(e){
            e.stopPropagation();

            var monthToShow = this.monthToDisplay.clone().add('months', 1);
            this.showMonth(monthToShow.year(), monthToShow.month());
        },

        onPreviousClicked: function(e){
            e.stopPropagation();

            var monthToShow = this.monthToDisplay.subtract('months', 1);
            this.showMonth(monthToShow.year(), monthToShow.month());
        },

        updateSelectedDate: function(date){
            var newDate = this.selectedDate = moment(date),
                month = newDate.month(),
                year = newDate.year(),
                monthToDisplay = this.monthToDisplay;

            if(month !== monthToDisplay.month() || year !== monthToDisplay.year()){
                this.showMonth(year, month);
            }

            this.$el.find('.day.selected').removeClass('selected');
            this._findCellByDate(newDate).addClass('selected');

            this.trigger('onDateSelected', { date: date });
        },

        showMonth: function(year, month){
            this.monthToDisplay = moment([year, month, 1]);
            this.render();

            this.trigger('onMonthDisplayed', { month: this.monthToDisplay });
        },

        highlightCells: function(startDate, endDate){
            var startCell = this._findCellByDate(startDate).not('.grey'),
                endCell = this._findCellByDate(endDate).not('.grey'),
                startRow = startCell.parent(),
                endRow = endCell.parent(),
                inRangeClassName = 'inRange',
                daySelector = '.day',
                greySelector = '.grey';

            this.$el.find('.'+inRangeClassName).removeClass(inRangeClassName);

            if(startDate.diff(endDate) === 0){
                return;
            }

            if(this.monthToDisplay.diff(startDate.clone().date(1)) < 0){
                return;
            }

            if(this.monthToDisplay.diff(endDate.clone().date(1)) > 0){
                return;
            }

            if(!startCell.length && !endCell.length){
                //fill all
                this.$el.find(daySelector).not(greySelector).addClass(inRangeClassName);
                return;
            }

            if(!startCell.length){
                //fill from start to endDate
                endCell.parent().prevAll().children(daySelector).not(greySelector).addClass(inRangeClassName);
                endCell.prevAll(daySelector).not(greySelector).addClass(inRangeClassName);
                return;
            }

            if(!endCell.length) {
                //fill from startDate to end
                startCell.parent().nextAll().children(daySelector).not(greySelector).addClass(inRangeClassName);
                startCell.nextAll(daySelector).not(greySelector).addClass(inRangeClassName);
                return;
            }

            //fill from startDate to endDate
            if(startRow.is(endRow)){
                startCell.nextUntil(endCell).addClass(inRangeClassName);
            } else {
                startRow.nextUntil(endRow).children(daySelector).not(greySelector).addClass(inRangeClassName);
                startCell.nextAll(daySelector).not(greySelector).addClass(inRangeClassName);
                endCell.prevAll(daySelector).not(greySelector).addClass(inRangeClassName);
            }

            endCell.addClass(inRangeClassName);
            startCell.addClass(inRangeClassName);
        }
    });

    function DateRangePicker(options){
        var todayString = moment().format('YYYY-MM-DD');

        options = _.defaults(options, {
            startDate: todayString,
            endDate: todayString
        });

        this.$el = $('
');
        this.$el.on('click', '.presets li', _.bind(this.onPresetClick, this));

        this.startCalendar = this._createCalendar({
            selectedDate: options.startDate,
            className: 'startCalendar'
        });

        this.endCalendar = this._createCalendar({
            selectedDate: options.endDate,
            className: 'endCalendar'
        });

        if(options.presets){
            this.presets = options.presets;
            this.$el.addClass('withPresets');
        }

        this.startCalendar.bind('onDateSelected', _.bind(this.onStartDateSelected, this));
        this.startCalendar.bind('onMonthDisplayed', _.bind(this._updateStartCalendarHighlight, this));

        this.endCalendar.bind('onDateSelected', _.bind(this.onEndDateSelected, this));
        this.endCalendar.bind('onMonthDisplayed', _.bind(this._updateEndCalendarHighlight, this));
    }

    DateRangePicker.create = function(options){
        options = options || {};

        var className = options.className,
            picker;

        delete options.className;

        picker = new DateRangePicker(options);

        if(className){
            picker.$el.addClass(className);
        }

        return picker;
    };

    _.extend(DateRangePicker.prototype, {

        _createCalendar: function(month, year, selectedDate, className){
            return new Calendar(month, year, selectedDate, className);
        },

        _updateStartCalendarHighlight: function(){
            this.startCalendar.highlightCells(this.getStartDate(), this.getEndDate());
        },

        _updateEndCalendarHighlight: function(){
            this.endCalendar.highlightCells(this.getStartDate(), this.getEndDate());
        },

        _highlightRange: function(startDate, endDate){
            if(startDate.diff(endDate) > 0){
                return;
            }

            this.startCalendar.highlightCells(startDate, endDate);
            this.endCalendar.highlightCells(startDate, endDate);
        },

        buildPresetsList: function(){
            var presets = this.presets,
                lis;

            if(!presets){
                return;
            }

            lis = _(presets).map(function(val, key){
                return '
' + key + '
';
            });

            return '
' + lis.join('') + '
';
        },

        render: function(){
            var startCalendar = this.startCalendar,
                endCalendar = this.endCalendar,
                presetsList = this.buildPresetsList();

            startCalendar.render();
            endCalendar.render();

            this._updateStartCalendarHighlight();
            this._updateEndCalendarHighlight();

            this.$el.addClass('picker').append(presetsList).append(startCalendar.$el).append(endCalendar.$el);
        },

        show: function($target){
            var $el = this.$el,
                targetOffset = $target.offset(),
                windowWidth = $(window).width(),
                left;

            if( (targetOffset.left + $el.outerWidth()) > windowWidth ){
                left = windowWidth - $el.outerWidth() - 10;
            } else {
                left = targetOffset.left;
            }

            $el.show().css({
                top: targetOffset.top + $target.outerHeight(),
                left: left
            });

            $(document).on('click.daterangepicker', _.bind(this.hide, this));
        },

        hide: function(){
            this.$el.hide();
            $(document).off('click.daterangepicker', this.hide);
        },

        destroy: function(){
            this.startCalendar.destroy();
            this.endCalendar.destroy();

            this.$el.remove();
        },

        getStartDate: function(){
            return this.startCalendar.selectedDate;
        },

        getEndDate: function(){
            return this.endCalendar.selectedDate;
        },

        updateStartCalendarHighlight: function(){
            this.startCalendar.highlightCells(this.getStartDate(), this.getEndDate());
        },

        updateEndCalendarHighlight: function(){
            this.endCalendar.highlightCells(this.getStartDate(), this.getEndDate());
        },

        highlightRange: function(startDate, endDate){
            if(startDate.diff(endDate) > 0){
                return;
            }

            this.startCalendar.highlightCells(startDate, endDate);
            this.endCalendar.highlightCells(startDate, endDate);
        },

        onStartDateSelected: function(args){
            var startDate = moment(args.date),
                endDate = this.getEndDate();

            if(moment(startDate).diff(endDate) > 0){
                this.endCalendar.updateSelectedDate(startDate);
            }

            this._highlightRange(startDate, endDate);

            this.trigger('startDateSelected', {
                startDate: startDate,
                endDate: endDate
            });
        },

        onEndDateSelected: function(args){
            var endDate = moment(args.date),
                startDate = this.getStartDate();

            if(moment(startDate).diff(endDate) > 0){
                this.startCalendar.updateSelectedDate(endDate);
            }

            this._highlightRange(startDate, endDate);

            this.trigger('endDateSelected', {
                startDate: startDate,
                endDate: endDate
            });
        },

        onPresetClick: function(e){
            e.stopPropagation();

            var target = $(e.target),
                startDate = moment(target.data('startdate')),
                endDate = moment(target.data('enddate'));

            this.startCalendar.updateSelectedDate(startDate);
            this.endCalendar.updateSelectedDate(endDate);

            this._updateStartCalendarHighlight();
            this._updateEndCalendarHighlight();

            this.trigger('rangeSelected', {
                startDate: startDate,
                endDate: endDate
            });
        }
    });

    MicroEvent.mixin(Calendar);
    MicroEvent.mixin(DateRangePicker);

    $.fn.daterangepicker = function(options) {

        var updateValue = function(options){
            var startDate = options.startDate,
                endDate = options.endDate,
                formattedValue = startDate.format('DD MMM YYYY') + ' - ' + endDate.format('DD MMM YYYY');

            this.val(formattedValue);
        };

        return this.each(function() {
            var $self = $(this);

            $self.on('click', function(e){

                e.stopPropagation();

                var picker = $self.data('picker'),
                    boundUpdate = _.bind(updateValue, $self);

                if(!picker){
                    picker = DateRangePicker.create(options);
                    picker.render();

                    picker.bind('startDateSelected', boundUpdate);
                    picker.bind('endDateSelected', boundUpdate);
                    picker.bind('rangeSelected', boundUpdate);

                    $self.data('picker', picker);

                    $('body').append(picker.$el);
                }

                picker.show($self);
            });
        });
    };

    return DateRangePicker;
});
<|endoftext|>


<commit_before>'use strict';

const Command = require('../../Command.js');

/**
 * Displays the Damage 2.0 charts
 */
class Damage extends Command {
  /**
   * Constructs a callable command
   * @param {Genesis} bot  The bot object
   */
  constructor(bot) {
    super(bot, 'warframe.misc.damage', 'damage', 'Display Damage 2.0 chart');
    this.damageChart = 'http://i.imgur.com/EOzr440.png';
  }

  /**
   * Run the command
   * @param {Message} message Message with a command to handle, reply to,
   *                          or perform an action based on parameters.
   * @returns {string} success status
   */
  async run(message) {
    this.messageManager.embed(message, {
      title: 'Legend',
      image: {
        url: 'http://i.imgur.com/EOzr440.png',
      },
      fields: [
        { name: 'Blast', value: '<:blast:321463957292318720>', inline: true },
        { name: 'Cold', value: '<:cold:321463957019951105>', inline: true },
        { name: 'Corrosive', value: '<:corrosive:321463957305032714>', inline: true },
        { name: 'Electricity', value: '<:electricity:321463957212626944>', inline: true },
        { name: 'Gas', value: '<:gas:321463957259026432>', inline: true },
        { name: 'Heat', value: '<:heat:321463957061763083>', inline: true },
        { name: 'Impact', value: '<:impact:321463957221015562>', inline: true },
        { name: 'Magnetic', value: '<:magnetic:321463957984641024>', inline: true },
        { name: 'Puncture', value: '<:puncture:321463957296775168>', inline: true },
        { name: 'Radiation', value: '<:radiation:321463957221277706>', inline: true },
        { name: 'Slash', value: '<:slash:321463957296644103>', inline: true },
        { name: 'Toxin', value: '<:toxin:321463957325873153>', inline: true },
        { name: 'Viral', value: '<:viral:321463957292580864>', inline: true },
      ],
    }, true, false);
    return this.messageManager.statuses.SUCCESS;
  }
}

module.exports = Damage;
<commit_msg>updated damage type icons<commit_after>'use strict';

const Command = require('../../Command.js');

/**
 * Displays the Damage 2.0 charts
 */
class Damage extends Command {
  /**
   * Constructs a callable command
   * @param {Genesis} bot  The bot object
   */
  constructor(bot) {
    super(bot, 'warframe.misc.damage', 'damage', 'Display Damage 2.0 chart');
    this.damageChart = 'http://i.imgur.com/EOzr440.png';
  }

  /**
   * Run the command
   * @param {Message} message Message with a command to handle, reply to,
   *                          or perform an action based on parameters.
   * @returns {string} success status
   */
  async run(message) {
    this.messageManager.embed(message, {
      title: 'Legend',
      image: {
        url: 'http://i.imgur.com/EOzr440.png',
      },
      fields: [
        { name: 'Blast', value: '<:blast:363136256907149312>', inline: true },
        { name: 'Cold', value: '<:cold:363136256659685377>', inline: true },
        { name: 'Corrosive', value: '<:corrosive:363136257288568832>', inline: true },
        { name: 'Electricity', value: '<:electricity:363136257053949962>', inline: true },
        { name: 'Gas', value: '<:gas:363136257045561344>', inline: true },
        { name: 'Heat', value: '<:heat:363136256927858698>', inline: true },
        { name: 'Impact', value: '<:impact:363136256781189120>', inline: true },
        { name: 'Magnetic', value: '<:magnetic:363136420602445824>', inline: true },
        { name: 'Puncture', value: '<:puncture:363136257129185280>', inline: true },
        { name: 'Radiation', value: '<:radiation:363136256865075200>', inline: true },
        { name: 'Slash', value: '<:slash:363136256755892225>', inline: true },
        { name: 'Toxin', value: '<:toxin:363136256626130946>', inline: true },
        { name: 'Viral', value: '<:viral:363136256747765763>', inline: true },
      ],
    }, true, false);
    return this.messageManager.statuses.SUCCESS;
  }
}

module.exports = Damage;
<|endoftext|>


<commit_before>/*
 * modules.js - Dynamic command module loading, unloading and reloading.
 *
 * Contributed by Ovyerus
 */

/* eslint-env node */

const fs = require('fs');
const path = require('path');
const decache = require('decache');

exports.loadAsSubcommands = true;

exports.commands = [
    'load',
    'unload',
    'reload'
];

exports.main = {
    desc: 'Command for managing modules.',
    longDesc: 'Manages command modules for the bots. If no arguments, lists currently loaded modules, else runs the specified subcommand if possible.',
    usage: '[load|unload|reload]',
    adminOnly: true,
    fixed: true,
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            let cmdFolders = fs.readdirSync(path.join(__dirname, '../'));
            let unloadedMods = JSON.parse(fs.readFileSync(`${__baseDir}/data/unloadedCommands.json`));
            let embed = {
                title: 'Current Modules',
                description: `Showing **${cmdFolders.length}** command modules.`,
                fields: [
                    {name: 'Loaded Modules', value: []},
                    {name: 'Unloaded Modules', value: []}
                ]
            };

            Object.keys(bot.commands.modules).filter(m => !m.endsWith('-fixed')).forEach(mod => {
                embed.fields[0].value.push(`\`${mod}\``);
            });

            unloadedMods.forEach(mod =>  {
                embed.fields[1].value.push(`\`${mod}\``);
            });

            embed.fields[0].value = embed.fields[0].value.join(', ');
            embed.fields[1].value = embed.fields[1].value.join(', ');

            ctx.createMessage({embed}).then(resolve).catch(reject);
        });
    }
};

exports.load = {
    desc: 'Load a module.',
    usage: '<module>',
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            if (!ctx.args[0]) {
                ctx.createMessage('No module given to load.').then(resolve).catch(reject);
            } else if (bot.commands.checkModule(ctx.args[0])) {
                ctx.createMessage(`Module **${ctx.args[0]}** already exist's in the command holder.`).then(resolve).catch(reject);
            } else {
                readDir(`${__baseDir}/commands`).then(folders => {
                    if (folders.indexOf(ctx.args[0]) === -1) {
                        return ctx.createMessage(`Module **${ctx.args[0]}** does not exist.`);
                    } else {
                        let pkg = require(path.join(__dirname,  '../', ctx.args[0], 'package.json'));
                        let mod = require(path.join(__dirname, '../', ctx.args[0], pkg.main));
                        let loadedAmt = bot.commands.addModule(ctx.args[0], mod);

                        if (loadedAmt === 0) bot.commands.removeModule(ctx.args[0]);

                        if (loadedAmt !== 0) {
                            let unloadedMods = JSON.parse(fs.readFileSync(`${__baseDir}/data/unloadedCommands.json`).toString());
                            if (unloadedMods.indexOf(ctx.args[0]) !== -1) {
                                unloadedMods.splice(unloadedMods.indexOf(ctx.args[0]), 1);
                                fs.writeFileSync(`${__baseDir}/data/unloadedCommands.json`, JSON.stringify(unloadedMods));
                            }
                        }

                        return ctx.createMessage(`Loaded **${loadedAmt}/${mod.commands.length}** commands from module **${ctx.args[0]}**`);
                    }
                }).then(resolve).catch(reject);
            }
        });
    }
};

exports.unload = {
    desc: 'Unload a module.',
    usage: '<module>',
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            if (!ctx.args[0]) {
                ctx.createMessage('No module given to unload.').then(resolve).catch(reject);
            } else if (!bot.commands.checkModule(ctx.args[0])) {
                ctx.createMessage(`Module **${ctx.args[0]}** is not loaded or does not exist.`).then(resolve).catch(reject);
            } else {
                let pkg = require(path.join(__dirname, '../', ctx.args[0], 'package.json'));
                let mod = require(path.join(__dirname, '../', ctx.args[0], pkg.main));
                let unloadedAmt = bot.commands.removeModule(ctx.args[0], path.join(__dirname, '../', ctx.args[0], pkg.main));
                decache(path.join(__dirname, '../', ctx.args[0], 'package.json'));

                if (unloadedAmt !== 0) {
                    let unloadedMods = JSON.parse(fs.readFileSync(`${__baseDir}/data/unloadedCommands.json`).toString());
                    unloadedMods.push(ctx.args[0]);
                    fs.writeFileSync(`${__baseDir}/data/unloadedCommands.json`, JSON.stringify(unloadedMods));
                }

                ctx.createMessage(`Unloaded **${unloadedAmt}/${mod.commands.length}** commands from module **${ctx.args[0]}**`).then(resolve).catch(reject);
            }
        });
    }
};

exports.reload = {
    desc: 'Reload a module.',
    usage: '<module>',
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            if (!ctx.args[0]) {
                ctx.createMessage('No module given to reload.').then(resolve).catch(reject);
            } else if (!bot.commands.checkModule(ctx.args[0])) {
                ctx.createMessage(`Module **${ctx.args[0]}** is not loaded or does not exist.`).then(resolve).catch(reject);
            } else {
                decache(path.join(__dirname, '../', ctx.args[0], 'package.json'));
                let pkg = require(path.join(__dirname,  '../', ctx.args[0], 'package.json'));
                decache(path.join(__dirname, '../', ctx.args[0], pkg.main));
                let mod = require(path.join(__dirname, '../', ctx.args[0], pkg.main));

                let reloadedAmt = bot.commands.reloadModule(ctx.args[0], mod, path.join(__dirname, '../', ctx.args[0], pkg.main)) || 0;

                ctx.createMessage(`Reloaded **${reloadedAmt}/${mod.commands.length}** commands from module **${ctx.args[0]}**`).then(resolve).catch(reject);
            }
        });
    }
};

function readDir(dir) {
    return new Promise((resolve, reject) => {
        fs.readdir(dir, (err, files) => {
            if (err) {
                reject(err);
            } else {
                resolve(files);
            }
        });
    });
}<commit_msg>change statement on loaded modules<commit_after>/*
 * modules.js - Dynamic command module loading, unloading and reloading.
 *
 * Contributed by Ovyerus
 */

/* eslint-env node */

const fs = require('fs');
const path = require('path');
const decache = require('decache');

exports.loadAsSubcommands = true;

exports.commands = [
    'load',
    'unload',
    'reload'
];

exports.main = {
    desc: 'Command for managing modules.',
    longDesc: 'Manages command modules for the bots. If no arguments, lists currently loaded modules, else runs the specified subcommand if possible.',
    usage: '[load|unload|reload]',
    adminOnly: true,
    fixed: true,
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            let cmdFolders = fs.readdirSync(path.join(__dirname, '../'));
            let unloadedMods = JSON.parse(fs.readFileSync(`${__baseDir}/data/unloadedCommands.json`));
            let embed = {
                title: 'Current Modules',
                description: `Showing **${cmdFolders.length}** command modules.`,
                fields: [
                    {name: 'Loaded Modules', value: []},
                    {name: 'Unloaded Modules', value: []}
                ]
            };

            Object.keys(bot.commands.modules).filter(m => !m.endsWith('-fixed')).forEach(mod => {
                embed.fields[0].value.push(`\`${mod}\``);
            });

            unloadedMods.forEach(mod =>  {
                embed.fields[1].value.push(`\`${mod}\``);
            });

            embed.fields[0].value = embed.fields[0].value.join(', ');
            embed.fields[1].value = embed.fields[1].value.join(', ');

            ctx.createMessage({embed}).then(resolve).catch(reject);
        });
    }
};

exports.load = {
    desc: 'Load a module.',
    usage: '<module>',
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            if (!ctx.args[0]) {
                ctx.createMessage('No module given to load.').then(resolve).catch(reject);
            } else if (bot.commands.checkModule(ctx.args[0])) {
                ctx.createMessage(`Module **${ctx.args[0]}** is already loaded.`).then(resolve).catch(reject);
            } else {
                readDir(`${__baseDir}/commands`).then(folders => {
                    if (folders.indexOf(ctx.args[0]) === -1) {
                        return ctx.createMessage(`Module **${ctx.args[0]}** does not exist.`);
                    } else {
                        let pkg = require(path.join(__dirname,  '../', ctx.args[0], 'package.json'));
                        let mod = require(path.join(__dirname, '../', ctx.args[0], pkg.main));
                        let loadedAmt = bot.commands.addModule(ctx.args[0], mod);

                        if (loadedAmt === 0) bot.commands.removeModule(ctx.args[0]);

                        if (loadedAmt !== 0) {
                            let unloadedMods = JSON.parse(fs.readFileSync(`${__baseDir}/data/unloadedCommands.json`).toString());
                            if (unloadedMods.indexOf(ctx.args[0]) !== -1) {
                                unloadedMods.splice(unloadedMods.indexOf(ctx.args[0]), 1);
                                fs.writeFileSync(`${__baseDir}/data/unloadedCommands.json`, JSON.stringify(unloadedMods));
                            }
                        }

                        return ctx.createMessage(`Loaded **${loadedAmt}/${mod.commands.length}** commands from module **${ctx.args[0]}**`);
                    }
                }).then(resolve).catch(reject);
            }
        });
    }
};

exports.unload = {
    desc: 'Unload a module.',
    usage: '<module>',
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            if (!ctx.args[0]) {
                ctx.createMessage('No module given to unload.').then(resolve).catch(reject);
            } else if (!bot.commands.checkModule(ctx.args[0])) {
                ctx.createMessage(`Module **${ctx.args[0]}** is not loaded or does not exist.`).then(resolve).catch(reject);
            } else {
                let pkg = require(path.join(__dirname, '../', ctx.args[0], 'package.json'));
                let mod = require(path.join(__dirname, '../', ctx.args[0], pkg.main));
                let unloadedAmt = bot.commands.removeModule(ctx.args[0], path.join(__dirname, '../', ctx.args[0], pkg.main));
                decache(path.join(__dirname, '../', ctx.args[0], 'package.json'));

                if (unloadedAmt !== 0) {
                    let unloadedMods = JSON.parse(fs.readFileSync(`${__baseDir}/data/unloadedCommands.json`).toString());
                    unloadedMods.push(ctx.args[0]);
                    fs.writeFileSync(`${__baseDir}/data/unloadedCommands.json`, JSON.stringify(unloadedMods));
                }

                ctx.createMessage(`Unloaded **${unloadedAmt}/${mod.commands.length}** commands from module **${ctx.args[0]}**`).then(resolve).catch(reject);
            }
        });
    }
};

exports.reload = {
    desc: 'Reload a module.',
    usage: '<module>',
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            if (!ctx.args[0]) {
                ctx.createMessage('No module given to reload.').then(resolve).catch(reject);
            } else if (!bot.commands.checkModule(ctx.args[0])) {
                ctx.createMessage(`Module **${ctx.args[0]}** is not loaded or does not exist.`).then(resolve).catch(reject);
            } else {
                decache(path.join(__dirname, '../', ctx.args[0], 'package.json'));
                let pkg = require(path.join(__dirname,  '../', ctx.args[0], 'package.json'));
                decache(path.join(__dirname, '../', ctx.args[0], pkg.main));
                let mod = require(path.join(__dirname, '../', ctx.args[0], pkg.main));

                let reloadedAmt = bot.commands.reloadModule(ctx.args[0], mod, path.join(__dirname, '../', ctx.args[0], pkg.main)) || 0;

                ctx.createMessage(`Reloaded **${reloadedAmt}/${mod.commands.length}** commands from module **${ctx.args[0]}**`).then(resolve).catch(reject);
            }
        });
    }
};

function readDir(dir) {
    return new Promise((resolve, reject) => {
        fs.readdir(dir, (err, files) => {
            if (err) {
                reject(err);
            } else {
                resolve(files);
            }
        });
    });
}<|endoftext|>


<commit_before>import * as commentsTypes from './commentsActions';
import * as userTypes from '../user/userActions';

const initialState = {
  childrenById: {},
  comments: {},
  pendingVotes: [],
  isFetching: false,
};

const childrenById = (state = {}, action) => {
  switch (action.type) {
    case commentsTypes.GET_COMMENTS_SUCCESS:
      return {
        ...state,
        ...action.payload.commentsChildrenList,
      };
    default:
      return state;
  }
};

const mapCommentsBasedOnId = (data) => {
  const commentsList = {};
  Object.keys(data).forEach((key) => {
    commentsList[data[key].id] = data[key];
  });
  return commentsList;
};

const commentsData = (state = {}, action) => {
  switch (action.type) {
    case commentsTypes.GET_COMMENTS_SUCCESS:
      return {
        ...state,
        ...mapCommentsBasedOnId(action.payload.content),
      };
    case userTypes.GET_USER_COMMENTS_SUCCESS:
    case userTypes.GET_MORE_USER_COMMENTS_SUCCESS: {
      const commentsMoreList = {};
      action.payload.forEach((comment) => {
        commentsMoreList[comment.id] = comment;
      });
      return {
        ...state,
        ...commentsMoreList,
      };
    }
    case commentsTypes.RELOAD_EXISTING_COMMENT:
      return {
        ...state,
        [action.payload.id]: action.payload,
      };
    default:
      return state;
  }
};

const isFetching = (state = initialState.isFetching, action) => {
  switch (action.type) {
    case commentsTypes.GET_COMMENTS_START:
    case commentsTypes.SEND_COMMENT_START:
      return false;
    case commentsTypes.GET_COMMENTS_SUCCESS:
    case commentsTypes.GET_COMMENTS_ERROR:
    case commentsTypes.SEND_COMMENT_SUCCESS:
    case commentsTypes.SEND_COMMENT_ERROR:
      return false;
    default:
      return state;
  }
};

const comments = (state = initialState, action) => {
  switch (action.type) {
    case commentsTypes.GET_COMMENTS_START:
    case commentsTypes.GET_COMMENTS_SUCCESS:
    case userTypes.GET_USER_COMMENTS_SUCCESS:
    case userTypes.GET_MORE_USER_COMMENTS_SUCCESS:
    case commentsTypes.SHOW_MORE_COMMENTS:
    case commentsTypes.SEND_COMMENT_START:
    case commentsTypes.SEND_COMMENT_SUCCESS:
    case commentsTypes.SEND_COMMENT_ERROR:
      return {
        ...state,
        comments: commentsData(state.comments, action),
        childrenById: childrenById(state.childrenById, action),
        isFetching: isFetching(state.isFetching, action),
      };
    case commentsTypes.LIKE_COMMENT_START:
      return {
        ...state,
        pendingVotes: [
          ...state.pendingVotes,
          {
            id: action.meta.commentId,
            percent: action.meta.weight,
            vote: action.meta.vote,
          },
        ],
      };
    case commentsTypes.LIKE_COMMENT_ERROR:
      return {
        ...state,
        pendingVotes: state.pendingVotes.filter(like => like.id !== action.meta.commentId),
      };
    case commentsTypes.RELOAD_EXISTING_COMMENT:
      return {
        ...state,
        comments: commentsData(state.comments, action),
        pendingVotes: state.pendingVotes.filter(like => like.id !== action.meta.commentId),
      };
    default:
      return state;
  }
};

export default comments;

export const getComments = state => state;
export const getCommentsList = state => state.comments;
export const getCommentsPendingVotes = state => state.pendingVotes;
<commit_msg>Fix missing comments loading<commit_after>import * as commentsTypes from './commentsActions';
import * as userTypes from '../user/userActions';

const initialState = {
  childrenById: {},
  comments: {},
  pendingVotes: [],
  isFetching: false,
};

const childrenById = (state = {}, action) => {
  switch (action.type) {
    case commentsTypes.GET_COMMENTS_SUCCESS:
      return {
        ...state,
        ...action.payload.commentsChildrenList,
      };
    default:
      return state;
  }
};

const mapCommentsBasedOnId = (data) => {
  const commentsList = {};
  Object.keys(data).forEach((key) => {
    commentsList[data[key].id] = data[key];
  });
  return commentsList;
};

const commentsData = (state = {}, action) => {
  switch (action.type) {
    case commentsTypes.GET_COMMENTS_SUCCESS:
      return {
        ...state,
        ...mapCommentsBasedOnId(action.payload.content),
      };
    case userTypes.GET_USER_COMMENTS_SUCCESS:
    case userTypes.GET_MORE_USER_COMMENTS_SUCCESS: {
      const commentsMoreList = {};
      action.payload.forEach((comment) => {
        commentsMoreList[comment.id] = comment;
      });
      return {
        ...state,
        ...commentsMoreList,
      };
    }
    case commentsTypes.RELOAD_EXISTING_COMMENT:
      return {
        ...state,
        [action.payload.id]: action.payload,
      };
    default:
      return state;
  }
};

const isFetching = (state = initialState.isFetching, action) => {
  switch (action.type) {
    case commentsTypes.GET_COMMENTS_START:
    case commentsTypes.SEND_COMMENT_START:
      return true;
    case commentsTypes.GET_COMMENTS_SUCCESS:
    case commentsTypes.GET_COMMENTS_ERROR:
    case commentsTypes.SEND_COMMENT_SUCCESS:
    case commentsTypes.SEND_COMMENT_ERROR:
      return false;
    default:
      return state;
  }
};

const comments = (state = initialState, action) => {
  switch (action.type) {
    case commentsTypes.GET_COMMENTS_START:
    case commentsTypes.GET_COMMENTS_SUCCESS:
    case commentsTypes.GET_COMMENTS_ERROR:
    case userTypes.GET_USER_COMMENTS_SUCCESS:
    case userTypes.GET_MORE_USER_COMMENTS_SUCCESS:
    case commentsTypes.SHOW_MORE_COMMENTS:
    case commentsTypes.SEND_COMMENT_START:
    case commentsTypes.SEND_COMMENT_SUCCESS:
    case commentsTypes.SEND_COMMENT_ERROR:
      return {
        ...state,
        comments: commentsData(state.comments, action),
        childrenById: childrenById(state.childrenById, action),
        isFetching: isFetching(state.isFetching, action),
      };
    case commentsTypes.LIKE_COMMENT_START:
      return {
        ...state,
        pendingVotes: [
          ...state.pendingVotes,
          {
            id: action.meta.commentId,
            percent: action.meta.weight,
            vote: action.meta.vote,
          },
        ],
      };
    case commentsTypes.LIKE_COMMENT_ERROR:
      return {
        ...state,
        pendingVotes: state.pendingVotes.filter(like => like.id !== action.meta.commentId),
      };
    case commentsTypes.RELOAD_EXISTING_COMMENT:
      return {
        ...state,
        comments: commentsData(state.comments, action),
        pendingVotes: state.pendingVotes.filter(like => like.id !== action.meta.commentId),
      };
    default:
      return state;
  }
};

export default comments;

export const getComments = state => state;
export const getCommentsList = state => state.comments;
export const getCommentsPendingVotes = state => state.pendingVotes;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import s from './LocationEdit.css'
import icons from '../../icons/css/fontello.css'

import { uuid } from '../../lib/uuid'

import ServiceEdit from '../ServiceEdit'
import ToggleButton from '../ToggleButton'
import Autocomplete from 'react-google-autocomplete'

const blankService = (location) => ({
  id: uuid(),
  applicationProcess: "",
  description: "",
  eligibility: {},
  locationId: location.id,
  name: "",
  organization: location.organizationId,
  schedules: [],
  taxonomy: ""
})

const placeholderAddressText = (physicalAddress) => {
  if (physicalAddress.address1) {
    return physicalAddress.address1 + ", " + physicalAddress.city;
  } else {
    return "Search for location"
  }
}

class LocationEdit extends Component {
   updateLocation = (field, value) => {
    const { index, location, handleChange } = this.props
    const newLocation = location

    newLocation[field] = value

    handleChange(newLocation, index)
  }

   deleteLocation = () => {
    const { index, handleDelete } = this.props

    handleDelete(index)
  }

   handleLocationChange = (field, event) => {
    this.updateLocation(field, event.target.value)
  }

   handleAddress = (place) => {
    const { physicalAddress } = this.props.location
    const newPhysicalAddress = physicalAddress

    newPhysicalAddress['address1'] = place.name
    newPhysicalAddress['city'] = place.vicinity

    this.updateLocation('physicalAddress', newPhysicalAddress)
    this.updateLocation('latitude', place.geometry.location.lat())
    this.updateLocation('longitude', place.geometry.location.lng())
  }

   handleServices = (service) => {
    const { services } = this.props.location
    const newServices = services

    newServices[service.id] = service

    this.updateLocation('services', newServices)
  }

   newService = () => {
    const { location } = this.props
    const newServices = location.services || []
    const newService = blankService(location)

    newServices[newService.id] = newService

    this.updateLocation('services', newServices)
    this.selectService(newService)
  }

   deleteService = (service) => {
    const { services } = this.props.location
    const newServices = services

    delete newServices[service.id]

    this.updateLocation('services', newServices)
    this.selectService(null)
  }

  selectService = (service) => {
    this.props.handleStateUpdate({ selectedService: service })
  }

  serviceSelected = (service) => {
    return this.props.selectedService && this.props.selectedService.id == service.id
  }

  render() {
    const { location, selectedService, taxonomies } = this.props

    return (

            Location Name
            <input
              className={s.input}
              type="text"
              value={location.name}
              onChange={(e) => this.handleLocationChange('name', e)}
            />

            Location Description
            <textarea
              className={s.input}
              type="text"
              value={location.description}
              onChange={(e) => this.handleLocationChange('description', e)}
            />

            Location Address
            <Autocomplete
              placeholder={placeholderAddressText(location.physicalAddress)}
              className={s.input}
              onPlaceSelected={this.handleAddress}
              types={['geocode']}
            />

            Street
            <input
              className={s.input}
              type="text"
              value={location.physicalAddress.address1}
              disabled
            />

            City
            <input
              className={s.input}
              type="text"
              value={location.physicalAddress.city}
              disabled
            />

          <button className={s.buttonStyle} onClick={this.deleteLocation}>Delete this Location</button>

            Services
            <button
              className={s.addToSubsection}
              onClick={this.newService}
              title={`Click to add a new service`}>
              + Add
            </button>

            {(Object.values(location.services || {})).map((service) => (
              <ToggleButton
                key={`service-${service.id}`}
                enabled={this.serviceSelected(service)}
                onClick={(e) => this.selectService(service)}
                label={service.name || "Service"}
              />
            ))}

            {selectedService &&
              <ServiceEdit
                key={`service-${selectedService.id}`}
                service={selectedService}
                handleChange={this.handleServices}
                handleDelete={this.deleteService}
                taxonomies={taxonomies}
              />
            }

    )
  }
}

export default LocationEdit
<commit_msg>Default Location Services to object and not array<commit_after>import React, { Component, PropTypes } from 'react'
import s from './LocationEdit.css'
import icons from '../../icons/css/fontello.css'

import { uuid } from '../../lib/uuid'

import ServiceEdit from '../ServiceEdit'
import ToggleButton from '../ToggleButton'
import Autocomplete from 'react-google-autocomplete'

const blankService = (location) => ({
  id: uuid(),
  applicationProcess: "",
  description: "",
  eligibility: {},
  locationId: location.id,
  name: "",
  organization: location.organizationId,
  schedules: [],
  taxonomy: ""
})

const placeholderAddressText = (physicalAddress) => {
  if (physicalAddress.address1) {
    return physicalAddress.address1 + ", " + physicalAddress.city;
  } else {
    return "Search for location"
  }
}

class LocationEdit extends Component {
   updateLocation = (field, value) => {
    const { index, location, handleChange } = this.props
    const newLocation = location

    newLocation[field] = value

    handleChange(newLocation, index)
  }

   deleteLocation = () => {
    const { index, handleDelete } = this.props

    handleDelete(index)
  }

   handleLocationChange = (field, event) => {
    this.updateLocation(field, event.target.value)
  }

   handleAddress = (place) => {
    const { physicalAddress } = this.props.location
    const newPhysicalAddress = physicalAddress

    newPhysicalAddress['address1'] = place.name
    newPhysicalAddress['city'] = place.vicinity

    this.updateLocation('physicalAddress', newPhysicalAddress)
    this.updateLocation('latitude', place.geometry.location.lat())
    this.updateLocation('longitude', place.geometry.location.lng())
  }

   handleServices = (service) => {
    const { services } = this.props.location
    const newServices = services

    newServices[service.id] = service

    this.updateLocation('services', newServices)
  }

   newService = () => {
    const { location } = this.props
    const newServices = location.services || {}
    const newService = blankService(location)

    newServices[newService.id] = newService

    this.updateLocation('services', newServices)
    this.selectService(newService)
  }

   deleteService = (service) => {
    const { services } = this.props.location
    const newServices = services

    delete newServices[service.id]

    this.updateLocation('services', newServices)
    this.selectService(null)
  }

  selectService = (service) => {
    this.props.handleStateUpdate({ selectedService: service })
  }

  serviceSelected = (service) => {
    return this.props.selectedService && this.props.selectedService.id == service.id
  }

  render() {
    const { location, selectedService, taxonomies } = this.props

    return (

            Location Name
            <input
              className={s.input}
              type="text"
              value={location.name}
              onChange={(e) => this.handleLocationChange('name', e)}
            />

            Location Description
            <textarea
              className={s.input}
              type="text"
              value={location.description}
              onChange={(e) => this.handleLocationChange('description', e)}
            />

            Location Address
            <Autocomplete
              placeholder={placeholderAddressText(location.physicalAddress)}
              className={s.input}
              onPlaceSelected={this.handleAddress}
              types={['geocode']}
            />

            Street
            <input
              className={s.input}
              type="text"
              value={location.physicalAddress.address1}
              disabled
            />

            City
            <input
              className={s.input}
              type="text"
              value={location.physicalAddress.city}
              disabled
            />

          <button className={s.buttonStyle} onClick={this.deleteLocation}>Delete this Location</button>

            Services
            <button
              className={s.addToSubsection}
              onClick={this.newService}
              title={`Click to add a new service`}>
              + Add
            </button>

            {(Object.values(location.services || {})).map((service) => (
              <ToggleButton
                key={`service-${service.id}`}
                enabled={this.serviceSelected(service)}
                onClick={(e) => this.selectService(service)}
                label={service.name || "Service"}
              />
            ))}

            {selectedService &&
              <ServiceEdit
                key={`service-${selectedService.id}`}
                service={selectedService}
                handleChange={this.handleServices}
                handleDelete={this.deleteService}
                taxonomies={taxonomies}
              />
            }

    )
  }
}

export default LocationEdit
<|endoftext|>