<commit_before>/* jQueryMobile-router v0.5
 * Copyright 2011, Andrea Zicchetti
 */
(function($){

$(document).bind("mobileinit",function(){

	/* supports the following configurations:
		$.mobile.jqmRouter.fixFirstPageDataUrl=true
		$.mobile.jqmRouter.firstPageDataUrl="index.html"
			jQM doesn't handle correctly the dataurl of the first page you display
			in a single-page template mode. In fact, the page is fetched again
			from the server the first time you try to access it through a link.
			If this option is set to true, jquery mobile router extensions will
			try to fix this problem. In order to set the data url, you have to
			provide the name of the file containing the first page into the
			"firstPageDataUrl" property (for example: index.html)

	*/

	var config=$.extend({
		fixFirstPageDataUrl: false, firstPageDataUrl: "index.html"
	},$.mobile.jqmRouter || {});

	var DEBUG=true;
	function debug(err){
		if (DEBUG) console.log(err);
	}

	var previousUrl=null, nextUrl=null;

	$(document).bind("pagebeforechange", function( e, data ) {
		// We only want to handle changePage() calls where the caller is
		// asking us to load a page by URL.
		if ( typeof data.toPage === "string" ) {
			// We are being asked to load a page by URL, but we only
			// want to handle URLs that request the data for a specific
			// category.
			var u = $.mobile.path.parseUrl( data.toPage );
			previousUrl=nextUrl;
			nextUrl=u;

			if ( u.hash.indexOf("?") !== -1 ) {
				var page=u.hash.replace( /\?.*$/, "" );
				// We don't want the data-url of the page we just modified
				// to be the url that shows up in the browser's location field,
				// so set the dataUrl option to the URL with hash parameters
				data.options.dataUrl = u.href;
				// Now call changePage() and tell it to switch to
				// the page we just modified, but only in case it's different
				// from the current page
				if (	$.mobile.activePage &&
					page.replace(/^#/,"")==$.mobile.activePage.jqmData("url")
				){
					data.options.allowSamePageTransition=true;
					$.mobile.changePage( $(page), data.options );
				} else {
					$.mobile.changePage( $(page), data.options );
				}
				// Make sure to tell changePage() we've handled this call so it doesn't
				// have to do anything.
				e.preventDefault();
			}
		}
	});

	if (config.fixFirstPageDataUrl){
		$(document).ready(function(){
			var page=$(":jqmData(role='page')").first();
			var	dataUrl=page.jqmData("url"),
				guessedDataUrl=
					window.location.pathname.slice(-1)=="/"?
						window.location.pathname
						+config.firstPageDataUrl
						:window.location.pathname
			;
			if (dataUrl!=guessedDataUrl){
				page.attr("data-url",guessedDataUrl)
					.jqmData("url",guessedDataUrl);
			}
		});
	}

	$.mobile.Router=function(userRoutes,userHandlers,conf){
		/* userRoutes format:
			{
				"regexp": "function name", // defaults to jqm pagebeforeshow event
				"regexp": function(){ ... }, // defaults to jqm pagebeforeshow event
				"regexp": { handler: "function name", events: "bc,c,bs,s,bh,h"	},
				"regexp": { handler: function(){ ... }, events: "bc,c,bs,s,bh,h" }
			}
		*/
		this.routes={
			pagebeforecreate: null, pagecreate: null,
			pagebeforeshow: null, pageshow: null,
			pagebeforehide: null, pagehide: null,
			pageinit: null, pageremove: null
		};
		this.routesRex={};
		this.conf=$.extend({
			ajaxApp: false
		}, config || {});
		this.add(userRoutes,userHandlers);
	}
	$.extend($.mobile.Router.prototype,{
		add: function(userRoutes,userHandlers){
			if (!userRoutes) return;

			var _self=this, evtList=[], evtLookup={
				bc: "pagebeforecreate", c: "pagecreate",
				bs: "pagebeforeshow", s: "pageshow",
				bh: "pagebeforehide", h: "pagehide",
				i: "pageinit", rm: "pageremove"
			};
			if (userRoutes instanceof Array){
				$.each(userRoutes,$.proxy(function(k,v){
					this.add(v,userHandlers);
				},this));
			} else {
				$.each(userRoutes,function(r,el){
					if(typeof(el)=="string" || typeof(el)=="function"){
						if (_self.routes.pagebeforeshow===null){
							_self.routes.pagebeforeshow={};
						}
						_self.routes.pagebeforeshow[r]=el;
						if (! _self.routesRex.hasOwnProperty(r)){
							_self.routesRex[r]=new RegExp(r);
						}
					} else {
						var i,trig=el.events.split(","),evt;
						for(i in trig){
							evt=evtLookup[trig[i]];
							if (_self.routes.hasOwnProperty(evt)){
								if (_self.routes[evt]===null){
									_self.routes[evt]={};
								}
								_self.routes[evt][r]=el.handler;
								if (! _self.routesRex.hasOwnProperty(r)){
									_self.routesRex[r]=new RegExp(r);
								}
							} else {
								debug("can't set unsupported route "+trig[i]);
							}
						}
					}
				});
				$.each(_self.routes,function(evt,el){
					if (el!==null){
						evtList.push(evt);
					}
				});
				if (!this.userHandlers) this.userHandlers={};
				$.extend(this.userHandlers,userHandlers||{});
				this._detachEvents();
				if (evtList.length>0){
					this._liveData={
						events: evtList.join(" "),
						handler: function(e,ui){ _self._processRoutes(e,ui,this); }
					};
					$("div:jqmData(role='page'),div:jqmData(role='dialog')").live(
						this._liveData.events, this._liveData.handler
					);
				}
			}
		},

		_processRoutes: function(e,ui,page){
			var _self=this, refUrl, url;
			if (e.type in {
				"pagebeforehide":true, "pagehide":true, "pageremove": true
			}){
				refUrl=previousUrl;
			} else {
				refUrl=nextUrl;
			}
			if (!refUrl && page){
				$page=$(page);
				refUrl=$page.jqmData("url");
				if (refUrl){
					if ($page.attr("id")==refUrl) refUrl="#"+refUrl;
					refUrl=$.mobile.path.parseUrl(refUrl);
				} else {
					refUrl=window.location;
				}
			}
			if (!refUrl) return;
			url=( !this.conf.ajaxApp ?
				refUrl.hash
				:refUrl.pathname + refUrl.search + refUrl.hash
			);
			$.each(this.routes[e.type],function(route,handler){
				var res, handleFn;
				if ( (res=url.match(_self.routesRex[route])) ){
					if (typeof(handler)=="function"){
						handleFn=handler;
					} else if (typeof(_self.userHandlers[handler])=="function"){
						handleFn=_self.userHandlers[handler];
					}
					if (handleFn){
						try { handleFn(e.type,res,ui,page);
						}catch(err){ debug(err); }
					}
				}
			});
		},

		_detachEvents: function(){
			if (this._liveData){
				$("div:jqmData(role='page'),div:jqmData(role='dialog')").die(
					this._liveData.events, this._liveData.handler
				);
			}
		} ,

		destroy: function(){
			this._detachEvents();
			this.routes=this.routesRex=null;
		} ,

		getParams: function(hashparams){
			if (!hashparams) return null;
			var params={}, tmp;
			var tokens=hashparams.slice( hashparams.indexOf('?')+1 ).split("&");
			$.each(tokens,function(k,v){
				tmp=v.split("=");
				params[tmp[0]]=tmp[1];
			});
			if ($.isEmptyObject(params)) return null;
			return params;
		}
	});

});

})(jQuery);
<commit_msg>Fixed a problem with events triggered during the initial page load. Support for array parameters in the url<commit_after>/* jQueryMobile-router v0.5
 * Copyright 2011, Andrea Zicchetti
 */
(function($){

$(document).bind("mobileinit",function(){

	/* supports the following configurations:
		$.mobile.jqmRouter.fixFirstPageDataUrl=true
		$.mobile.jqmRouter.firstPageDataUrl="index.html"
			jQM doesn't handle correctly the dataurl of the first page you display
			in a single-page template mode. In fact, the page is fetched again
			from the server the first time you try to access it through a link.
			If this option is set to true, jquery mobile router extensions will
			try to fix this problem. In order to set the data url, you have to
			provide the name of the file containing the first page into the
			"firstPageDataUrl" property (for example: index.html)

	*/

	var config=$.extend({
		fixFirstPageDataUrl: false, firstPageDataUrl: "index.html"
	},$.mobile.jqmRouter || {});

	var DEBUG=true;
	function debug(err){
		if (DEBUG) console.log(err);
	}

	var previousUrl=null, nextUrl=null;

	$(document).bind("pagebeforechange", function( e, data ) {
		// We only want to handle changePage() calls where the caller is
		// asking us to load a page by URL.
		if ( typeof data.toPage === "string" ) {
			// We are being asked to load a page by URL, but we only
			// want to handle URLs that request the data for a specific
			// category.
			var u = $.mobile.path.parseUrl( data.toPage );
			previousUrl=nextUrl;
			nextUrl=u;

			if ( u.hash.indexOf("?") !== -1 ) {
				var page=u.hash.replace( /\?.*$/, "" );
				// We don't want the data-url of the page we just modified
				// to be the url that shows up in the browser's location field,
				// so set the dataUrl option to the URL with hash parameters
				data.options.dataUrl = u.href;
				// Now call changePage() and tell it to switch to
				// the page we just modified, but only in case it's different
				// from the current page
				if (	$.mobile.activePage &&
					page.replace(/^#/,"")==$.mobile.activePage.jqmData("url")
				){
					data.options.allowSamePageTransition=true;
					$.mobile.changePage( $(page), data.options );
				} else {
					$.mobile.changePage( $(page), data.options );
				}
				// Make sure to tell changePage() we've handled this call so it doesn't
				// have to do anything.
				e.preventDefault();
			}
		}
	});

	if (config.fixFirstPageDataUrl){
		$(document).ready(function(){
			var page=$(":jqmData(role='page')").first();
			var	dataUrl=page.jqmData("url"),
				guessedDataUrl=window.location.pathname
					+config.firstPageDataUrl
					+window.location.search
					+window.location.hash
			;
			if (!window.location.pathname.match("/$")){
				return;
			}
			if (dataUrl!=guessedDataUrl){
				page.attr("data-url",guessedDataUrl)
					.jqmData("url",guessedDataUrl);
			}
		});
	}

	$.mobile.Router=function(userRoutes,userHandlers,conf){
		/* userRoutes format:
			{
				"regexp": "function name", // defaults to jqm pagebeforeshow event
				"regexp": function(){ ... }, // defaults to jqm pagebeforeshow event
				"regexp": { handler: "function name", events: "bc,c,bs,s,bh,h"	},
				"regexp": { handler: function(){ ... }, events: "bc,c,bs,s,bh,h" }
			}
		*/
		this.routes={
			pagebeforecreate: null, pagecreate: null,
			pagebeforeshow: null, pageshow: null,
			pagebeforehide: null, pagehide: null,
			pageinit: null, pageremove: null
		};
		this.routesRex={};
		this.conf=$.extend({
			ajaxApp: false
		}, config || {});
		this.add(userRoutes,userHandlers);
	}
	$.extend($.mobile.Router.prototype,{
		add: function(userRoutes,userHandlers){
			if (!userRoutes) return;

			var _self=this, evtList=[], evtLookup={
				bc: "pagebeforecreate", c: "pagecreate",
				bs: "pagebeforeshow", s: "pageshow",
				bh: "pagebeforehide", h: "pagehide",
				i: "pageinit", rm: "pageremove"
			};
			if (userRoutes instanceof Array){
				$.each(userRoutes,$.proxy(function(k,v){
					this.add(v,userHandlers);
				},this));
			} else {
				$.each(userRoutes,function(r,el){
					if(typeof(el)=="string" || typeof(el)=="function"){
						if (_self.routes.pagebeforeshow===null){
							_self.routes.pagebeforeshow={};
						}
						_self.routes.pagebeforeshow[r]=el;
						if (! _self.routesRex.hasOwnProperty(r)){
							_self.routesRex[r]=new RegExp(r);
						}
					} else {
						var i,trig=el.events.split(","),evt;
						for(i in trig){
							evt=evtLookup[trig[i]];
							if (_self.routes.hasOwnProperty(evt)){
								if (_self.routes[evt]===null){
									_self.routes[evt]={};
								}
								_self.routes[evt][r]=el.handler;
								if (! _self.routesRex.hasOwnProperty(r)){
									_self.routesRex[r]=new RegExp(r);
								}
							} else {
								debug("can't set unsupported route "+trig[i]);
							}
						}
					}
				});
				$.each(_self.routes,function(evt,el){
					if (el!==null){
						evtList.push(evt);
					}
				});
				if (!this.userHandlers) this.userHandlers={};
				$.extend(this.userHandlers,userHandlers||{});
				this._detachEvents();
				if (evtList.length>0){
					this._liveData={
						events: evtList.join(" "),
						handler: function(e,ui){ _self._processRoutes(e,ui,this); }
					};
					$("div:jqmData(role='page'),div:jqmData(role='dialog')").live(
						this._liveData.events, this._liveData.handler
					);
				}
			}
		},

		_processRoutes: function(e,ui,page){
			var _self=this, refUrl, url, $page;
			if (e.type in {
				"pagebeforehide":true, "pagehide":true, "pageremove": true
			}){
				refUrl=previousUrl;
			} else {
				refUrl=nextUrl;
			}
			if (!refUrl){
				if (page){
					$page=$(page);
					refUrl=$page.jqmData("url");
					if (refUrl){
						if ($page.attr("id")==refUrl) refUrl="#"+refUrl;
						refUrl=$.mobile.path.parseUrl(refUrl);
					}
				} else {
					refUrl=window.location;
				}
			}
			if (!refUrl) return;
			url=( !this.conf.ajaxApp ?
				refUrl.hash
				:refUrl.pathname + refUrl.search + refUrl.hash
			);
			$.each(this.routes[e.type],function(route,handler){
				var res, handleFn;
				if ( (res=url.match(_self.routesRex[route])) ){
					if (typeof(handler)=="function"){
						handleFn=handler;
					} else if (typeof(_self.userHandlers[handler])=="function"){
						handleFn=_self.userHandlers[handler];
					}
					if (handleFn){
						try { handleFn(e.type,res,ui,page);
						}catch(err){ debug(err); }
					}
				}
			});
		},

		_detachEvents: function(){
			if (this._liveData){
				$("div:jqmData(role='page'),div:jqmData(role='dialog')").die(
					this._liveData.events, this._liveData.handler
				);
			}
		} ,

		destroy: function(){
			this._detachEvents();
			this.routes=this.routesRex=null;
		} ,

		getParams: function(hashparams){
			if (!hashparams) return null;
			var params={}, tmp;
			var tokens=hashparams.slice( hashparams.indexOf('?')+1 ).split("&");
			$.each(tokens,function(k,v){
				tmp=v.split("=");
				if (params[tmp[0]]){
					if (!(params[tmp[0]] instanceof Array)){
						params[tmp[0]]=[ params[tmp[0]] ];
					}
					params[tmp[0]].push(tmp[1]);
				} else {
					params[tmp[0]]=tmp[1];
				}
			});
			if ($.isEmptyObject(params)) return null;
			return params;
		}
	});

});

})(jQuery);
<|endoftext|>


<commit_before>'use strict';

const express = require('express');
const mongoose = require('mongoose');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const cors = require('cors');
const path = require('path');
const url = require('url');

const redis = require('redis');
// const redisClient = redis.createClient();
const session = require('express-session');
const RedisStore = require('connect-redis')(session);

const logger = require('morgan');
const errorHandler = require('./lib/error_handler');

const index = require('./routes/index');
const commentsRouter = require('./routes/comments');
const coursesRouter = require('./routes/courses');
const gamesRouter = require('./routes/games');
const gameResultRouter = require('./routes/game_result');
const usersRouter = require('./routes/users');
const userStatsRouter = require('./routes/user_stats');
const friendsRouter = require('./routes/friends');

mongoose.Promise = require('bluebird');

const mongoDbOptions = {
  useMongoClient: true,
}

if (process.env.NODE_ENV === 'test')
  mongoose.connect(process.env.DB_SERVER, mongoDbOptions);

if (process.env.NODE_ENV !== 'test')
  mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost/gff-dev', mongoDbOptions);

if (process.env.REDISTOGO_URL) {
  var rtg = require('url').parse(process.env.REDISTOGO_URL);
  var redisClient = redis.createClient(rtg.port, rtg.hostname);

  redisClient.auth(rtg.auth.split(':')[1]);
} else {
  var redisClient = redis.createClient();
}

const app = express();

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');

const sessionOptions = {
  secret: '1337',
  store: new RedisStore({
    client: redisClient,
  }),
  name: 'GolfForeFriends',
  saveUninitialized: true,
  resave: true,
  cookie: {
    maxAge: 86400 * 365,
  },
};

if (app.get('env') === 'production')
  sessionOptions.cookie.secure = true;

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session(sessionOptions));
app.use(cors());

app.use(require('node-sass-middleware')({
  src: path.join(__dirname, 'public'),
  dest: path.join(__dirname, 'public'),
  indentedSyntax: true,
  sourceMap: true
}));
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/courses', coursesRouter);
app.use('/games', gamesRouter);
app.use('/games/result', gameResultRouter);
app.use('/games/comments', commentsRouter);
app.use('/users', usersRouter);
app.use('/users/stats', userStatsRouter);
app.use('/friends', friendsRouter);

app.use(function(req, res, next) {
  const err = new Error('Not Found');
  err.status = 404;
  next(err);
});

app.use(errorHandler);

module.exports = app;
<commit_msg>Prep for deploy.<commit_after>'use strict';

const express = require('express');
const mongoose = require('mongoose');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const cors = require('cors');
const path = require('path');
const url = require('url');

const redis = require('redis');
// const redisClient = redis.createClient();
const session = require('express-session');
const RedisStore = require('connect-redis')(session);

const logger = require('morgan');
const errorHandler = require('./lib/error_handler');

const index = require('./routes/index');
const commentsRouter = require('./routes/comments');
const coursesRouter = require('./routes/courses');
const gamesRouter = require('./routes/games');
const gameResultRouter = require('./routes/game_result');
const usersRouter = require('./routes/users');
const userStatsRouter = require('./routes/user_stats');
const friendsRouter = require('./routes/friends');

mongoose.Promise = require('bluebird');

const mongoDbOptions = {
  useMongoClient: true,
}

if (process.env.NODE_ENV === 'test')
  mongoose.connect(process.env.DB_SERVER, mongoDbOptions);

if (process.env.NODE_ENV !== 'test')
  mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost/gff-dev', mongoDbOptions);

if (process.env.REDISTOGO_URL) {
  var rtg = require('url').parse(process.env.REDISTOGO_URL);
  var redisClient = redis.createClient(rtg.port, rtg.hostname);

  redisClient.auth(rtg.auth.split(':')[1]);
} else {
  var redisClient = redis.createClient();
}

const app = express();

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');

const sessionOptions = {
  secret: '1337',
  store: new RedisStore({
    client: redisClient,
  }),
  name: 'GolfForeFriends',
  saveUninitialized: true,
  resave: true,
  cookie: {
    maxAge: 86400 * 365,
  },
};

if (process.env.NODE_ENV === 'production')
  sessionOptions.cookie.secure = true;

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session(sessionOptions));
app.use(cors());

app.use(require('node-sass-middleware')({
  src: path.join(__dirname, 'public'),
  dest: path.join(__dirname, 'public'),
  indentedSyntax: true,
  sourceMap: true
}));
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/courses', coursesRouter);
app.use('/games', gamesRouter);
app.use('/games/result', gameResultRouter);
app.use('/games/comments', commentsRouter);
app.use('/users', usersRouter);
app.use('/users/stats', userStatsRouter);
app.use('/friends', friendsRouter);

app.use(function(req, res, next) {
  const err = new Error('Not Found');
  err.status = 404;
  next(err);
});

app.use(errorHandler);

module.exports = app;
<|endoftext|>


<commit_before>/*
* jQuery Mobile Framework : widget factory extentions for mobile
* Copyright (c) jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/

(function( $, undefined ) {

$.widget( "mobile.widget", {
	_getCreateOptions: function() {

		var elem = this.element,
			options = {};

		$.each( this.options, function( option ) {

			var value = elem.jqmData( option.replace( /[A-Z]/g, function( c ) {
							return "-" + c.toLowerCase();
						})
					);

			if ( value !== undefined ) {
				options[ option ] = value;
			}
		});

		return options;
	}
});

})( jQuery );
<commit_msg>add 'widgetinit' event for users to enhance widgets and markup post 'widgetcreate'<commit_after>/*
* jQuery Mobile Framework : widget factory extentions for mobile
* Copyright (c) jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/

(function( $, undefined ) {

$.widget( "mobile.widget", {
	// decorate the parent _createWidget to trigger `widgetinit` for users
	// who wish to do post post `widgetcreate` alterations/additions
	//
	// TODO create a pull request for jquery ui to trigger this event
	// in the original _createWidget
	_createWidget: function() {
		$.Widget.prototype._createWidget.apply( this, arguments );
		this._trigger( 'init' );
	},

	_getCreateOptions: function() {

		var elem = this.element,
			options = {};

		$.each( this.options, function( option ) {

			var value = elem.jqmData( option.replace( /[A-Z]/g, function( c ) {
							return "-" + c.toLowerCase();
						})
					);

			if ( value !== undefined ) {
				options[ option ] = value;
			}
		});

		return options;
	}
});

})( jQuery );
<|endoftext|>


<commit_before>// sensors
import SingleList from './sensors/SingleList';
import MultiList from './sensors/MultiList';
import SingleDropdownList from './sensors/SingleDropdownList';
import MultiDropdownList from './sensors/MultiDropdownList';
import RangeSlider from './sensors/RangeSlider';
import TextField from './sensors/TextField';
import DataSearch from './sensors/DataSearch';
import SingleRange from './sensors/SingleRange';
import MultiRange from './sensors/MultiRange';
import SingleDropdownRange from './sensors/SingleDropdownRange';
import MultiDropdownRange from './sensors/MultiDropdownRange';
import ToggleButton from './sensors/ToggleButton';
import DatePicker from './sensors/DatePicker';
import DateRange from './sensors/DateRange';
import NestedList from './sensors/NestedList';
import NumberBox from './sensors/NumberBox';
import ReactiveList from './actuators/ReactiveList';
import ReactiveElement from './actuators/ReactiveElement';
import ReactivePaginatedList from './actuators/ReactivePaginatedList';
import PoweredBy from './sensors/PoweredBy';
import DataController from './sensors/DataController';
// middleware
import ReactiveBase from './middleware/ReactiveBase';
import {manager} from './middleware/ChannelManager';
var helper = require('./middleware/helper.js');
import * as TYPES from './middleware/constants.js';

module.exports = {
	SingleList: SingleList,
	MultiList: MultiList,
	SingleDropdownList: SingleDropdownList,
	MultiDropdownList: MultiDropdownList,
	RangeSlider: RangeSlider,
	TextField: TextField,
	DataSearch: DataSearch,
	SingleRange: SingleRange,
	MultiRange: MultiRange,
	SingleDropdownRange: SingleDropdownRange,
	MultiDropdownRange: MultiDropdownRange,
	ToggleButton: ToggleButton,
	DatePicker: DatePicker,
	DateRange: DateRange,
	NestedList: NestedList,
	NumberBox: NumberBox,
	ReactiveBase: ReactiveBase,
	ReactiveList: ReactiveList,
	ReactiveElement: ReactiveElement,
	ReactivePaginatedList: ReactivePaginatedList,
	AppbaseChannelManager: manager,
	AppbaseSensorHelper: helper,
	PoweredBy: PoweredBy,
	DataController: DataController,
	TYPES: TYPES
};
<commit_msg>Export InitialLoader, NoResults, ResultStats<commit_after>// sensors
import SingleList from './sensors/SingleList';
import MultiList from './sensors/MultiList';
import SingleDropdownList from './sensors/SingleDropdownList';
import MultiDropdownList from './sensors/MultiDropdownList';
import RangeSlider from './sensors/RangeSlider';
import TextField from './sensors/TextField';
import DataSearch from './sensors/DataSearch';
import SingleRange from './sensors/SingleRange';
import MultiRange from './sensors/MultiRange';
import SingleDropdownRange from './sensors/SingleDropdownRange';
import MultiDropdownRange from './sensors/MultiDropdownRange';
import ToggleButton from './sensors/ToggleButton';
import DatePicker from './sensors/DatePicker';
import DateRange from './sensors/DateRange';
import NestedList from './sensors/NestedList';
import NumberBox from './sensors/NumberBox';
import ReactiveList from './actuators/ReactiveList';
import ReactiveElement from './actuators/ReactiveElement';
import ReactivePaginatedList from './actuators/ReactivePaginatedList';
import PoweredBy from './sensors/PoweredBy';
import DataController from './sensors/DataController';
// addons
import InitialLoader from './addons/InitialLoader';
import NoResults from './addons/NoResults';
import ResultStats from './addons/ResultStats';
// middleware
import ReactiveBase from './middleware/ReactiveBase';
import {manager} from './middleware/ChannelManager';
var helper = require('./middleware/helper.js');
import * as TYPES from './middleware/constants.js';

module.exports = {
	SingleList: SingleList,
	MultiList: MultiList,
	SingleDropdownList: SingleDropdownList,
	MultiDropdownList: MultiDropdownList,
	RangeSlider: RangeSlider,
	TextField: TextField,
	DataSearch: DataSearch,
	SingleRange: SingleRange,
	MultiRange: MultiRange,
	SingleDropdownRange: SingleDropdownRange,
	MultiDropdownRange: MultiDropdownRange,
	ToggleButton: ToggleButton,
	DatePicker: DatePicker,
	DateRange: DateRange,
	NestedList: NestedList,
	NumberBox: NumberBox,
	ReactiveBase: ReactiveBase,
	ReactiveList: ReactiveList,
	ReactiveElement: ReactiveElement,
	ReactivePaginatedList: ReactivePaginatedList,
	AppbaseChannelManager: manager,
	AppbaseSensorHelper: helper,
	PoweredBy: PoweredBy,
	DataController: DataController,
	TYPES: TYPES,
	InitialLoader: InitialLoader,
	NoResults: NoResults,
	ResultStats: ResultStats
};
<|endoftext|>


<commit_before>// GUI --------------------------------------------------------
/* exported iniGui, updateGuiInfo */
/*
function initGui() {

	gui = new dat.GUI();
	gui.width = 270;

	gui_info = gui.addFolder( 'Info' );
	gui_info.add( neuralNet, 'numNeurons' ).name( 'Neurons' );
	gui_info.add( neuralNet, 'numAxons' ).name( 'Axons' );
	gui_info.add( neuralNet, 'numSignals', 0, neuralNet.settings.limitSignals ).name( 'Signals' );
	gui_info.autoListen = false;

	gui_settings = gui.addFolder( 'Settings' );
	gui_settings.add( neuralNet.settings, 'currentMaxSignals', 0, neuralNet.settings.limitSignals ).name( 'Max Signals' );
	gui_settings.add( neuralNet.particlePool, 'pSize', 0.2, 2 ).name( 'Signal Size' );
	gui_settings.add( neuralNet.settings, 'signalMinSpeed', 0.0, 8.0, 0.01 ).name( 'Signal Min Speed' );
	gui_settings.add( neuralNet.settings, 'signalMaxSpeed', 0.0, 8.0, 0.01 ).name( 'Signal Max Speed' );
	gui_settings.add( neuralNet, 'neuronSizeMultiplier', 0, 2 ).name( 'Neuron Size Mult' );
	gui_settings.add( neuralNet, 'neuronOpacity', 0, 1.0 ).name( 'Neuron Opacity' );
	gui_settings.add( neuralNet, 'axonOpacityMultiplier', 0.0, 5.0 ).name( 'Axon Opacity Mult' );
	gui_settings.addColor( neuralNet.particlePool, 'pColor' ).name( 'Signal Color' );
	gui_settings.addColor( neuralNet, 'neuronColor' ).name( 'Neuron Color' );
	gui_settings.addColor( neuralNet, 'axonColor' ).name( 'Axon Color' );
	gui_settings.addColor( sceneSettings, 'bgColor' ).name( 'Background' );

	gui_info.open();
	gui_settings.open();

	for ( var i = 0; i < gui_settings.__controllers.length; i++ ) {
		gui_settings.__controllers[ i ].onChange( updateNeuralNetworkSettings );
	}

}

function updateNeuralNetworkSettings() {
	neuralNet.updateSettings();
	if ( neuralNet.settings.signalMinSpeed > neuralNet.settings.signalMaxSpeed ) {
		neuralNet.settings.signalMaxSpeed = neuralNet.settings.signalMinSpeed;
		gui_settings.__controllers[ 3 ].updateDisplay();
	}
}

function updateGuiInfo() {
	for ( var i = 0; i < gui_info.__controllers.length; i++ ) {
		gui_info.__controllers[ i ].updateDisplay();
	}
}
*/
<commit_msg>Update gui.js<commit_after>// GUI --------------------------------------------------------
/* exported iniGui, updateGuiInfo */

function initGui() {

	gui = new dat.GUI();
	gui.width = 270;

	gui_info = gui.addFolder( 'Info' );
	gui_info.add( neuralNet, 'numNeurons' ).name( 'Neurons' );
	gui_info.add( neuralNet, 'numAxons' ).name( 'Axons' );
	gui_info.add( neuralNet, 'numSignals', 0, neuralNet.settings.limitSignals ).name( 'Signals' );
	gui_info.autoListen = false;

	gui_settings = gui.addFolder( 'Settings' );
	gui_settings.add( neuralNet.settings, 'currentMaxSignals', 0, neuralNet.settings.limitSignals ).name( 'Max Signals' );
	gui_settings.add( neuralNet.particlePool, 'pSize', 0.2, 2 ).name( 'Signal Size' );
	gui_settings.add( neuralNet.settings, 'signalMinSpeed', 0.0, 8.0, 0.01 ).name( 'Signal Min Speed' );
	gui_settings.add( neuralNet.settings, 'signalMaxSpeed', 0.0, 8.0, 0.01 ).name( 'Signal Max Speed' );
	gui_settings.add( neuralNet, 'neuronSizeMultiplier', 0, 2 ).name( 'Neuron Size Mult' );
	gui_settings.add( neuralNet, 'neuronOpacity', 0, 1.0 ).name( 'Neuron Opacity' );
	gui_settings.add( neuralNet, 'axonOpacityMultiplier', 0.0, 5.0 ).name( 'Axon Opacity Mult' );
	gui_settings.addColor( neuralNet.particlePool, 'pColor' ).name( 'Signal Color' );
	gui_settings.addColor( neuralNet, 'neuronColor' ).name( 'Neuron Color' );
	gui_settings.addColor( neuralNet, 'axonColor' ).name( 'Axon Color' );
	gui_settings.addColor( sceneSettings, 'bgColor' ).name( 'Background' );

	gui_info.open();
	gui_settings.open();

	for ( var i = 0; i < gui_settings.__controllers.length; i++ ) {
		gui_settings.__controllers[ i ].onChange( updateNeuralNetworkSettings );
	}

}

function updateNeuralNetworkSettings() {
	neuralNet.updateSettings();
	if ( neuralNet.settings.signalMinSpeed > neuralNet.settings.signalMaxSpeed ) {
		neuralNet.settings.signalMaxSpeed = neuralNet.settings.signalMinSpeed;
		gui_settings.__controllers[ 3 ].updateDisplay();
	}
}

function updateGuiInfo() {
	for ( var i = 0; i < gui_info.__controllers.length; i++ ) {
		gui_info.__controllers[ i ].updateDisplay();
	}
}

<|endoftext|>


<commit_before>Number.prototype.toRad=function(){return this*Math.PI/180};Number.prototype.toDeg=function(){return this*180/Math.PI};Array.prototype.remove=function(e,t){var n=this.slice((t||e)+1||this.length);this.length=e<0?this.length+e:e;return this.push.apply(this,n)};var pointOnLine=function(e,t,n){var r=t.lat().toRad(),i=t.lng().toRad();var s=n.lat().toRad(),o=n.lng().toRad();x=r+e*(s-r);y=i+e*(o-i);return new google.maps.LatLng(x.toDeg(),y.toDeg())};var HyperlapsePoint=function(e,t,n){var r=this;var n=n||{};this.location=e;this.pano_id=t;this.heading=n.heading||0;this.pitch=n.pitch||0;this.elevation=n.elevation||0;this.image=n.image||null;this.copyright=n.copyright||"© 2013 Google";this.image_date=n.image_date||""};var Hyperlapse=function(e,t){"use strict";var n=this,r=[],i=e,s=t||{},o=s.width||800,u=s.height||400,a=20,f=s.use_elevation||false,l=s.distance_between_points||5,c=s.max_points||100,h=s.fov||70,p=s.zoom||1,d=0,v=0,m=0,g=0,y=false,b=false,w=0,E=0,S=0,x=true,T=0,N=0,C,k,L,A,O,M,_,D=false,P=Date.now(),H=0,B=0,j=null,F=[],I=[];var q=function(e){if(n.onError)n.onError(e)};var R=function(e){if(n.onFrame)n.onFrame(e)};var U=function(e){if(n.onPlay)n.onPlay(e)};var z=function(e){if(n.onPause)n.onPause(e)};var W=new google.maps.ElevationService;var X=new google.maps.StreetViewService;C=document.createElement("canvas");k=C.getContext("2d");L=new THREE.PerspectiveCamera(h,o/u,1,1100);L.target=new THREE.Vector3(0,0,0);A=new THREE.Scene;A.add(L);try{var V=!!window.WebGLRenderingContext&&!!document.createElement("canvas").getContext("experimental-webgl")}catch($){console.log($)}O=new THREE.WebGLRenderer;O.autoClearColor=false;O.setSize(o,u);M=new THREE.Mesh(new THREE.SphereGeometry(500,60,40),new THREE.MeshBasicMaterial({map:new THREE.Texture,side:THREE.DoubleSide}));A.add(M);i.appendChild(O.domElement);_=new GSVPANO.PanoLoader({zoom:p});_.onError=function(e){q({message:e})};_.onPanoramaLoad=function(){var e=document.createElement("canvas");var t=e.getContext("2d");e.setAttribute("width",this.canvas.width);e.setAttribute("height",this.canvas.height);t.drawImage(this.canvas,0,0);I[w].image=e;if(++w!=I.length){K({position:w});if(!D){_.composePanorama(I[w].pano_id)}else{J({})}}else{Q({})}};var J=function(e){D=false;b=false;if(n.onLoadCanceled)n.onLoadCanceled(e)};var K=function(e){if(n.onLoadProgress)n.onLoadProgress(e)};var Q=function(e){b=false;w=0;it();if(n.onLoadComplete)n.onLoadComplete(e)};var G=function(e){if(n.onRouteProgress)n.onRouteProgress(e)};var Y=function(e){var t=[];for(var r=0;r<I.length;r++){t[r]=I[r].location}if(f){et(t,function(t){if(t){for(r=0;r<I.length;r++){I[r].elevation=t[r].elevation}}else{for(r=0;r<I.length;r++){I[r].elevation=-1}}n.setLookat(n.lookat,true,function(){if(n.onRouteComplete)n.onRouteComplete(e)})})}else{for(r=0;r<I.length;r++){I[r].elevation=-1}n.setLookat(n.lookat,false,function(){if(n.onRouteComplete)n.onRouteComplete(e)})}};var Z=function(e){_.load(F[w],function(){if(_.id!=j){j=_.id;var t=new HyperlapsePoint(_.location,_.id,{heading:_.rotation,pitch:_.pitch,elevation:_.elevation,copyright:_.copyright,image_date:_.image_date});I.push(t);G({point:t});if(w==F.length-1){Y({response:e,points:I})}else{w++;if(!D)Z(e);else J({})}}else{F.splice(w,1);if(w==F.length){Y({response:e,points:I})}else{if(!D)Z(e);else J({})}}})};var et=function(e,t){var n={locations:e};W.getElevationForLocations(n,function(e,n){if(n==google.maps.ElevationStatus.OK){t(e)}else{if(n==google.maps.ElevationStatus.OVER_QUERY_LIMIT){console.log("Over elevation query limit.")}f=false;t(null)}})};var tt=function(e){if(!y){var t=e.routes[0];var r=t.overview_path;var i=t.legs;var s=0;for(var o=0;o<i.length;++o){s+=i[o].distance.value}var u=s/c;a=u<l?a=l:a=u;var f=0;var h=0;var p,d;for(o=0;o<r.length;o++){if(o+1<r.length){p=r[o];d=r[o+1];f=google.maps.geometry.spherical.computeDistanceBetween(p,d);if(h>0&&h<f){p=pointOnLine(h/f,p,d);f=google.maps.geometry.spherical.computeDistanceBetween(p,d);F.push(p);h=0}else if(h>0&&h>f){h-=f}if(h===0){var v=Math.floor(f/a);if(v>0){for(var m=0;m<v;m++){var g=m/v;if(g>0||g+o===0){var b=pointOnLine(g,p,d);F.push(b)}}h=f-a*v}else{h=a*(1-f/a)}}}else{F.push(r[o])}}Z(e)}else{n.pause();tt(e)}};var nt=function(){M.material.map.image=I[w].image;M.material.map.needsUpdate=true;E=I[w].heading;S=I[w].pitch;if(n.use_lookat)T=google.maps.geometry.spherical.computeHeading(I[w].location,n.lookat);if(I[w].elevation!=-1){var e=I[w].elevation-n.elevation_offset;var t=google.maps.geometry.spherical.computeDistanceBetween(I[w].location,n.lookat);var r=N-e;var i=Math.atan(Math.abs(r)/t).toDeg();g=r<0?-i:i}R({position:w,point:I[w]})};var rt=function(){if(!b&&n.length()>0){var e=w/n.length();var t=n.position.x+n.offset.x*e;var r=n.position.y+n.offset.y*e;var i=n.tilt+n.offset.z.toRad()*e;var s=n.use_lookat?T-E.toDeg()+t:t;var o=g+r;var u=v,a=d;v=v+(s-u);d=d+(o-a);d=Math.max(-85,Math.min(85,d));var f=(90-d).toRad();var l=v.toRad();L.target.x=500*Math.sin(f)*Math.cos(l);L.target.y=500*Math.cos(f);L.target.z=500*Math.sin(f)*Math.sin(l);L.lookAt(L.target);L.rotation.z-=i;if(n.use_rotation_comp){L.rotation.z-=n.rotation_comp.toRad()}M.rotation.z=S.toRad();O.render(A,L)}};var it=function(){var e=P;P=Date.now();B+=P-e;if(B>=n.millis){if(y)st();B=0}requestAnimationFrame(it);rt()};var st=function(){nt();if(x){if(++w==I.length){w=I.length-1;x=!x}}else{if(--w==-1){w=0;x=!x}}};this.lookat=s.lookat||null;this.millis=s.millis||50;this.elevation_offset=s.elevation||0;this.tilt=s.tilt||0;this.position={x:0,y:0};this.offset={x:0,y:0,z:0};this.use_lookat=s.use_lookat||false;this.use_rotation_comp=false;this.rotation_comp=0;this.isPlaying=function(){return y};this.isLoading=function(){return b};this.length=function(){return I.length};this.setPitch=function(e){g=e};this.setDistanceBetweenPoint=function(e){l=e};this.setMaxPoints=function(e){c=e};this.fov=function(){return h};this.webgl=function(){return O};this.getCurrentImage=function(){return I[w].image};this.getCurrentPoint=function(){return I[w]};this.setLookat=function(e,t,r){n.lookat=e;if(f&&t){var i=et([n.lookat],function(e){if(e){N=e[0].elevation}else{}if(r&&r.apply)r()})}else{if(r&&r.apply)r()}};this.setFOV=function(e){h=Math.floor(e);L.projectionMatrix.makePerspective(h,o/u,1,1100)};this.setSize=function(e,t){o=e;u=t;O.setSize(o,u);L.projectionMatrix.makePerspective(h,o/u,1,1100)};this.reset=function(){F.remove(0,-1);I.remove(0,-1);n.tilt=0;d=0;v=0;n.position.x=0;n.offset.x=0;n.offset.y=0;n.offset.z=0;m=0;g=0;w=0;E=0;S=0;x=true};this.generate=function(e){if(!b){b=true;n.reset();var t=e||{};l=t.distance_between_points||l;c=t.max_points||c;if(t.route){tt(t.route)}else{console.log("No route provided.")}}};this.load=function(){w=0;_.composePanorama(I[w].pano_id)};this.cancel=function(){if(b){D=true}};this.getCameraPosition=function(){return new google.maps.LatLng(d,v)};this.play=function(){if(!b){y=true;U({})}};this.pause=function(){y=false;z({})};this.next=function(){n.pause();if(w+1!=I.length){w++;nt()}};this.prev=function(){n.pause();if(w-1!==0){w--;nt()}}}<commit_msg>delete old build<commit_after><|endoftext|>


<commit_before>// Incident object definition.
function Incident(incidentData) {
	this.ID = incidentData.incident_number;
	this.Address = incidentData.address;
	this.Category = incidentData.type;
	this.DateLogged = incidentData.datetime ;
	this.Lat = incidentData.report_location.latitude;
	this.Lng = incidentData.report_location.longitude;
};

// Store all fetched incident objects in this global array.
//window.incidents = [];

var log = {
	SecondsTillRefresh: 300,
	BaseUri: 'https://data.seattle.gov/resource/kzjm-xkqj.json',
	RefreshData: function(newest) {
		var dataSource = log.GetDataSource(newest);
		var spinner = $('#spinner');

		$.ajax({
			type : "GET",
			dataType : "JSON",
			url : dataSource,
			timeout: 10000,
			beforeSend: function () {
				spinner.text('Fetching latest data...');
				spinner.slideDown('slow');
			},
			success: function(result) {
				var incidents = getIncidents();

				// Process the result.
				$.each( result, function( i, incidentData ) {
					var thisIncident = new Incident(incidentData);

					// Only push if there is not an object in the array with a matching IncidentID.
					if (!isIncidentLogged(thisIncident))
					{
						incidents.push(thisIncident);
					}
				});

				// Order array chronologically and put back into localStorage.
				setIncidents(log.SortData(incidents));

				// Reset timer if not returning historical data and new data was found.
				if (newest && result.length > 0 || log.SecondsTillRefresh < 1) {
					log.SecondsTillRefresh = 300;
				}
			},
			error: function(xhr, status, error) {
				spinner.text('Error retrieving data.');
			}
		}).complete(function(){
			spinner.slideUp('slow');
			log.RefreshTable();
	    });
	},
	SortData: function(data) {
		// Reference: http://www.stoimen.com/blog/2010/07/09/friday-algorithms-javascript-bubble-sort/

		if (data.length > 0 || data != undefined) {
			var swapped;
			do {
				swapped = false;

				for (var i = 0; i < data.length - 1; i++) {
					if (data[i].DateLogged < data[i + 1].DateLogged) {
						var temp = data[i];
						data[i] = data[i+1];
						data[i+1] = temp;
						swapped = true;
					}
				}

			} while (swapped);
		}

		return data;
	},
	SortCategories: function(categories, alphabetically) {
		if (alphabetically) {
			return categories.sort();
		}
		else {
			// Reference... bro: http://davidwalsh.name/array-sort
			return categories.sort(function(a, b) {
				return b.count - a.count;
			});
		}
	},
	RefreshTable: function () {
		var tableData = [];
		incidents = getIncidents();

		for (var i = 0; i < incidents.length; i++) {
			var thisIncident = incidents[i];
			tableData.push('
' + thisIncident.ID + '	' + thisIncident.Category + '	' + thisIncident.Address + '	' + getUserFriendlyDateTime(thisIncident.DateLogged) + '
');
		}

		$('#row-count').text('Incidents: ' + tableData.length);

		//First remove existing rows.
		$("#log").find('tr:gt(0)').remove();

		//Next append new data.
		$("#log").append(tableData.join(''));

		log.RefreshSummary();
	},
	RefreshSummary: function() {
		var categories = [], i;
		var data = getIncidents();

		// Display the time range represented by the current dataset.
		var incidentRange = $('#incident-range');
		var newestIncident = data[0];
		var oldestIncident = data[data.length - 1];

		incidentRange.text(getUserFriendlyDateTime(newestIncident.DateLogged) + ' - ' + getUserFriendlyDateTime(oldestIncident.DateLogged));

		// Get a distinct list of categories from the current dataset.
		for (i = 0; i < data.length; i++) {
			var found = false;
			for (var c = 0; c < categories.length; c++) {
				if (categories[c].name == data[i].Category) {
					found = true;
				}
			}

			if (found == false) {
				category = { name: data[i].Category, count: getIncidentCountByCategory(data[i].Category)};
				categories.push(category);
			}
		}

		if (categories.length > 0) {
			// Sort the categories alphabetically.
			categories = log.SortCategories(categories, false)

			var htmlList = '
Categories

';

			for (i = 0; i < categories.length; i++) {
				htmlList = htmlList + '
' + categories[i].name + '' + categories[i].count + '
';
			}

			htmlList = htmlList + '
';

			$('#incident-type-summary').html(htmlList);
		}
	},
	GetIncident: function(incidentId) {
		var incidents = getIncidents();

		if (incidents.length > 0) {
			for (var i = 0; i < incidents.length; i++) {
				if (incidents[i].ID == incidentId) {
					return incidents[i];
				}
			}
		}

		return null;
	},
	GetMap: function(lat, lng, incidentId) {
		var incidentLatLng = new google.maps.LatLng(lat,lng);

		var mapOptions = {
		  center: incidentLatLng,
		  zoom: 16
		};

		window.map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);

		// Add Marker.
		var marker = new google.maps.Marker({
		    position: incidentLatLng,
		    animation: google.maps.Animation.DROP,
		    map: map,
		    title:("#" + incidentId)
		});

		// Add InfoWindow.
		marker.info = new google.maps.InfoWindow({
		  content: 'Incident: ' + incidentId
		});

		google.maps.event.addListener(marker, 'click', function() {
		  marker.info.open(map, marker);
		});

		// Invert colors.
		// Reference: https://developers.google.com/maps/documentation/javascript/styling
		var styles = [
		  {
		    "stylers": [
	      		{ "invert_lightness": true }
	    	]
		  }
		];

		map.setOptions({styles: styles});
	},
	GetDataSource: function(newest) {
		var incidents = getIncidents();

		if (incidents.length === 0) {
			// Get current time in miliseconds since the epoch.
			var currentTime = new Date().getTime();
			// Convert to seconds.
			currentTime = (currentTime / 1000);
			// Subtract the number of seconds in 24 hours.
			currentTime = Math.floor(currentTime - (60 * 60 * 24));

			// Convert to ISO-8601 string.
			var dayAgo = new Date(currentTime * 1000).toISOString();
			return log.BaseUri + "?$where=datetime>'" + dayAgo + '\'';

		}
		else
		{
			var incident, dateLogged;
			if (newest) {
				incident = getNewestIncident();
				dateLogged = new Date(incident.DateLogged * 1000).toISOString();
				return log.BaseUri + "?$where=datetime>'" + dateLogged + '\'';
			}
			else {
				incident = getOldestIncident();
				dateLogged = new Date(incident.DateLogged * 1000).toISOString();
				return log.BaseUri + "?$where=datetime<'" + dateLogged + '\'&$limit=50&$order=datetime desc';
			}
		}
	}
};

// Checks to see if an incident already exists in the array matching on ID.
function isIncidentLogged(incident) {
	var incidents = getIncidents();
	for (var i = 0; i < incidents.length; i++)
	{
		if (incidents[i].ID == incident.ID)
		{
			// TODO: Should I compare to see if any of the properties have changed?
			return true;
		}
	}
	return false;
}

// Returns the most recently logged incident.
function getNewestIncident() {
	var newestIncident, data = getIncidents(), i;

	for (i = 0; i < data.length; i++)
	{
		if (newestIncident === undefined) {
			newestIncident = data[i];
		}

		if (newestIncident.DateLogged < data[i].DateLogged) {
			newestIncident = data[i];
		}
	}

	return newestIncident;
}

// Returns the earliest logged incident.
function getOldestIncident() {
	var oldestIncident, data = getIncidents(), i;

	for (i = 0; i < data.length; i++) {
		if (oldestIncident === undefined) {
			oldestIncident = data[i];
		}

		if (oldestIncident.DateLogged > data[i].DateLogged) {
			oldestIncident = data[i];
		}
	}

	return oldestIncident;
}

// Returns the number of incidents in a single category.
function getIncidentCountByCategory(category) {
	var count = 0, data = getIncidents(), i;

	for (i = 0; i < data.length; i++) {
		if (data[i].Category == category) {
			count++;
		}
	}

	return count;
}

// Returns a user-friendly date/time string {00:00:00 XX MM/DD/YYYY}.
function getUserFriendlyDateTime(date) {
	var friendlyDate = new Date(date * 1000);
	return friendlyDate.toLocaleTimeString() + ' ' + friendlyDate.toLocaleDateString();
}

function setIncidents(incidents) {
	localStorage.setItem('incidents', JSON.stringify(incidents));
}

function getIncidents(incidents) {
	if (localStorage.getItem('incidents') === null) {
		setIncidents([]);
	}

	return JSON.parse(localStorage.getItem('incidents'));
}

<commit_msg>Added highlighting logic for new incidents.<commit_after>// Incident object definition.
function Incident(incidentData) {
	this.ID = incidentData.incident_number;
	this.Address = incidentData.address;
	this.Category = incidentData.type;
	this.DateLogged = incidentData.datetime ;
	this.Lat = incidentData.report_location.latitude;
	this.Lng = incidentData.report_location.longitude;
	this.Highlight = true;
};

// Store all fetched incident objects in this global array.
//window.incidents = [];

var log = {
	SecondsTillRefresh: 300,
	BaseUri: 'https://data.seattle.gov/resource/kzjm-xkqj.json',
	RefreshData: function(newest) {
		var dataSource = log.GetDataSource(newest);
		var spinner = $('#spinner');

		$.ajax({
			type : "GET",
			dataType : "JSON",
			url : dataSource,
			timeout: 10000,
			beforeSend: function () {
				spinner.text('Fetching data...');
				spinner.slideDown('slow');
			},
			success: function(result) {
				var incidents = getIncidents();

				// Process the result.
				$.each( result, function( i, incidentData ) {
					var thisIncident = new Incident(incidentData);

					// Only push if there is not an object in the array with a matching IncidentID.
					if (!isIncidentLogged(thisIncident))
					{
						incidents.push(thisIncident);
					}
					else {
						thisIncident.Highlight = false;
					}
				});

				// Order array chronologically and put back into localStorage.
				setIncidents(log.SortData(incidents));

				// Reset timer if not returning historical data and new data was found.
				if (newest && result.length > 0 || log.SecondsTillRefresh < 1) {
					log.SecondsTillRefresh = 300;
				}
			},
			error: function(xhr, status, error) {
				spinner.text('Error retrieving data.');
				console.log(status + ': ' + error);
			}
		}).complete(function(){
			spinner.slideUp('slow');
			log.RefreshTable();
	    });
	},
	SortData: function(data) {
		// Reference: http://www.stoimen.com/blog/2010/07/09/friday-algorithms-javascript-bubble-sort/

		if (data.length > 0 || data != undefined) {
			var swapped;
			do {
				swapped = false;

				for (var i = 0; i < data.length - 1; i++) {
					if (data[i].DateLogged < data[i + 1].DateLogged) {
						var temp = data[i];
						data[i] = data[i+1];
						data[i+1] = temp;
						swapped = true;
					}
				}

			} while (swapped);
		}

		return data;
	},
	SortCategories: function(categories, alphabetically) {
		if (alphabetically) {
			return categories.sort();
		}
		else {
			// Reference... bro: http://davidwalsh.name/array-sort
			return categories.sort(function(a, b) {
				return b.count - a.count;
			});
		}
	},
	RefreshTable: function () {
		var tableData = [];
		incidents = getIncidents();

		for (var i = 0; i < incidents.length; i++) {
			var thisIncident = incidents[i];
			var cssClass;

			if (thisIncident.Highlight == true || i == 0) {
				cssClass = ' class="incident-row highlight"';
			} else {
				cssClass = ' class="incident-row"';
			}

			tableData.push('
' + thisIncident.ID + '	' + thisIncident.Category + '	' + thisIncident.Address + '	' + getUserFriendlyDateTime(thisIncident.DateLogged) + '
');
		}

		$('#row-count').text('Incidents: ' + tableData.length);

		//First remove existing rows.
		$("#log").find('tr:gt(0)').remove();

		//Next append new data.
		$("#log").append(tableData.join(''));

		log.RefreshSummary();
	},
	RefreshSummary: function() {
		var categories = [], i;
		var data = getIncidents();

		// Display the time range represented by the current dataset.
		var incidentRange = $('#incident-range');
		var newestIncident = data[0];
		var oldestIncident = data[data.length - 1];

		incidentRange.text(getUserFriendlyDateTime(newestIncident.DateLogged) + ' - ' + getUserFriendlyDateTime(oldestIncident.DateLogged));

		// Get a distinct list of categories from the current dataset.
		for (i = 0; i < data.length; i++) {
			var found = false;
			for (var c = 0; c < categories.length; c++) {
				if (categories[c].name == data[i].Category) {
					found = true;
				}
			}

			if (found == false) {
				category = { name: data[i].Category, count: getIncidentCountByCategory(data[i].Category)};
				categories.push(category);
			}
		}

		if (categories.length > 0) {
			// Sort the categories alphabetically.
			categories = log.SortCategories(categories, false)

			var htmlList = '
Categories

';

			for (i = 0; i < categories.length; i++) {
				htmlList = htmlList + '
' + categories[i].name + '' + categories[i].count + '
';
			}

			htmlList = htmlList + '
';

			$('#incident-type-summary').html(htmlList);
		}
	},
	GetIncident: function(incidentId) {
		var incidents = getIncidents();

		if (incidents.length > 0) {
			for (var i = 0; i < incidents.length; i++) {
				if (incidents[i].ID == incidentId) {
					return incidents[i];
				}
			}
		}

		return null;
	},
	GetMap: function(lat, lng, incidentId) {
		var incidentLatLng = new google.maps.LatLng(lat,lng);

		var mapOptions = {
		  center: incidentLatLng,
		  zoom: 16
		};

		window.map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);

		// Add Marker.
		var marker = new google.maps.Marker({
		    position: incidentLatLng,
		    animation: google.maps.Animation.DROP,
		    map: map,
		    title:("#" + incidentId)
		});

		// Add InfoWindow.
		marker.info = new google.maps.InfoWindow({
		  content: 'Incident: ' + incidentId
		});

		google.maps.event.addListener(marker, 'click', function() {
		  marker.info.open(map, marker);
		});

		// Invert colors.
		// Reference: https://developers.google.com/maps/documentation/javascript/styling
		var styles = [
		  {
		    "stylers": [
	      		{ "invert_lightness": true }
	    	]
		  }
		];

		map.setOptions({styles: styles});
	},
	GetDataSource: function(newest) {
		var incidents = getIncidents();

		if (incidents.length === 0) {
			// Get current time in miliseconds since the epoch.
			var currentTime = new Date().getTime();
			// Convert to seconds.
			currentTime = (currentTime / 1000);
			// Subtract the number of seconds in 24 hours.
			currentTime = Math.floor(currentTime - (60 * 60 * 24));

			// Convert to ISO-8601 string.
			var dayAgo = new Date(currentTime * 1000).toISOString();
			return log.BaseUri + "?$where=datetime>'" + dayAgo + '\'';

		}
		else
		{
			var incident, dateLogged;
			if (newest) {
				incident = getNewestIncident();
				dateLogged = new Date(incident.DateLogged * 1000).toISOString();
				return log.BaseUri + "?$where=datetime>'" + dateLogged + '\'';
			}
			else {
				incident = getOldestIncident();
				dateLogged = new Date(incident.DateLogged * 1000).toISOString();
				return log.BaseUri + "?$where=datetime<'" + dateLogged + '\'&$limit=50&$order=datetime desc';
			}
		}
	}
};

// Checks to see if an incident already exists in the array matching on ID.
function isIncidentLogged(incident) {
	var incidents = getIncidents();
	for (var i = 0; i < incidents.length; i++)
	{
		if (incidents[i].ID == incident.ID)
		{
			// TODO: Should I compare to see if any of the properties have changed?
			return true;
		}
	}
	return false;
}

// Returns the most recently logged incident.
function getNewestIncident() {
	var newestIncident, data = getIncidents(), i;

	for (i = 0; i < data.length; i++)
	{
		if (newestIncident === undefined) {
			newestIncident = data[i];
		}

		if (newestIncident.DateLogged < data[i].DateLogged) {
			newestIncident = data[i];
		}
	}

	return newestIncident;
}

// Returns the earliest logged incident.
function getOldestIncident() {
	var oldestIncident, data = getIncidents(), i;

	for (i = 0; i < data.length; i++) {
		if (oldestIncident === undefined) {
			oldestIncident = data[i];
		}

		if (oldestIncident.DateLogged > data[i].DateLogged) {
			oldestIncident = data[i];
		}
	}

	return oldestIncident;
}

// Returns the number of incidents in a single category.
function getIncidentCountByCategory(category) {
	var count = 0, data = getIncidents(), i;

	for (i = 0; i < data.length; i++) {
		if (data[i].Category == category) {
			count++;
		}
	}

	return count;
}

// Returns a user-friendly date/time string {00:00:00 XX MM/DD/YYYY}.
function getUserFriendlyDateTime(date) {
	var friendlyDate = new Date(date * 1000);
	return friendlyDate.toLocaleTimeString() + ' ' + friendlyDate.toLocaleDateString();
}

function setIncidents(incidents) {
	localStorage.setItem('incidents', JSON.stringify(incidents));
}

function getIncidents(incidents) {
	if (localStorage.getItem('incidents') === null) {
		setIncidents([]);
	}

	return JSON.parse(localStorage.getItem('incidents'));
}

<|endoftext|>


<commit_before>/**
 * Created by weiyixia on 16/12/15.
 */
import React, {Component, PropTypes} from 'react';
import {
  StyleSheet,
  Text,
  View,
  TouchableHighlight,
  Switch,
  ListView,
  AsyncStorage,
  AlertIOS
} from 'react-native';
import Calendar from 'react-native-calendar';
import dateFormat from 'dateformat';

const customDayHeadings = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const customMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const calendar_style = {
  controlButtonText: {
    color: 'blue'
  },
  weekendDayText: {
    color: 'black'
  },
  weekendHeading: {
    color: 'black'
  },

  eventIndicator: {
    backgroundColor: 'green',
    width: 10,
    height: 10
  }
}

export default class DatePickerScene extends Component {
  static propTypes = {
    navigator: PropTypes.object.isRequired
  };

  constructor(props, context) {
    super(props, context);
    this.state = {
      DIARY_KEY: '@Bref:diaries',
      availableDate : []
    };
  };

  _getCurrentDate() {
    let currentDate = new Date();
    let DateString = currentDate.getFullYear().toString() + "-" + (currentDate.getMonth() + 1).toString() + "-" + currentDate.getDate();
    return DateString;
  }

  async _getAllAvailableDate() {
    let data = await AsyncStorage.getItem(this.state.DIARY_KEY);
    let all_date = [];
    all_date = JSON.parse(data);
    let date_set = new Set();
    for (let i = 0; i < all_date.length; i++) {
      let date = all_date[i].timeStamp;
      let t_date = dateFormat(date, 'yyyy') + '-' + dateFormat(date, 'mm') + '-' + dateFormat(date, 'dd');
      if (date_set.has(t_date)) continue;
      date_set.add(t_date);
      this.state.availableDate.push(t_date);
    }
  }

  componentWillMount() {
    this._getAllAvailableDate().done();
  }

  async _storeSelectDate(value) {
    await AsyncStorage.setItem('@Bref:FilterByDate', "true")
      .then(success => {
        console.log('set filter by date success');
      })
      .catch(error => {
        console.log('set filter by date fail')
      });

    let DateString = value.substring(0, 10);
    await AsyncStorage.setItem('@Bref:SelectDate', DateString)
      .then(success => {
        console.log('store select date success');
      })
      .catch(error => {
        console.log('store select date fail')
      });
  }

  _onDateSelect(date) {
    this._storeSelectDate(date);
  }

  render() {
    return (
      <View style={[{marginTop: 60}, styles.container]}>
        <Calendar
          customStyle={calendar_style}
          showEventIndicators
          eventDates={this.state.availableDate}
          dayHeadings={customDayHeadings}               // Default: ['S', 'M', 'T', 'W', 'T', 'F', 'S']
          monthNames={customMonthNames}                // Defaults to english names of months
          nextButtonText={'Next'}           // Text for next button. Default: 'Next'
          onDateSelect={(date) => this._onDateSelect(date)} // Callback after date selection
          onSwipeNext={this.onSwipeNext}    // Callback for forward swipe event
          onSwipePrev={this.onSwipePrev}    // Callback for back swipe event
          onTouchNext={this.onTouchNext}    // Callback for next touch event
          onTouchPrev={this.onTouchPrev}    // Callback for prev touch event
          prevButtonText={'Prev'}           // Text for previous button. Default: 'Prev'
          scrollEnabled={true}              // False disables swiping. Default: False
          selectedDate={this._getCurrentDate()}       // Day to be selected
          showControls={true}               // False hides prev/next buttons. Default: False
          startDate={this._getCurrentDate()}          // The first month that will display. Default: current month
          titleFormat={'MMMM YYYY'}         // Format for displaying current month. Default: 'MMMM YYYY'
          today={this._getCurrentDate()}              // Defaults to today
          weekStart={1} // Day on which week starts 0 - Sunday, 1 - Monday, 2 - Tuesday, etc, Default: 1
        />
      </View>

    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 0,
    backgroundColor: '#202020',
    justifyContent: 'flex-start'
  },
  commonText: {
    padding: 5,
    paddingTop: 10,
    paddingBottom: 10,
    color: '#FFFFFF'
  },
});<commit_msg>add notifications on unavailable dates<commit_after>/**
 * Created by weiyixia on 16/12/15.
 */
import React, {Component, PropTypes} from 'react';
import {
  StyleSheet,
  Text,
  View,
  TouchableHighlight,
  Switch,
  ListView,
  AsyncStorage,
  AlertIOS
} from 'react-native';
import Calendar from 'react-native-calendar';
import dateFormat from 'dateformat';

const customDayHeadings = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const customMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const calendar_style = {
  controlButtonText: {
    color: 'blue'
  },
  weekendDayText: {
    color: 'black'
  },
  weekendHeading: {
    color: 'black'
  },

  eventIndicator: {
    backgroundColor: 'green',
    width: 10,
    height: 10
  }
}

export default class DatePickerScene extends Component {
  static propTypes = {
    navigator: PropTypes.object.isRequired
  };

  constructor(props, context) {
    super(props, context);
    this.state = {
      DIARY_KEY: '@Bref:diaries',
      availableDate: [],
      currentSelectedDate: ""
    };
    this.date_set = new Set();
  };

  _getCurrentDate() {
    let currentDate = new Date();
    let DateString = currentDate.getFullYear().toString() + "-" + (currentDate.getMonth() + 1).toString() + "-" + currentDate.getDate();
    return DateString;
  }

  async _getAllAvailableDate() {
    let data = await AsyncStorage.getItem(this.state.DIARY_KEY);
    let all_date = [];
    all_date = JSON.parse(data);
    for (let i = 0; i < all_date.length; i++) {
      let date = all_date[i].timeStamp;
      let t_date = dateFormat(date, 'yyyy') + '-' + dateFormat(date, 'mm') + '-' + dateFormat(date, 'dd');
      if (this.date_set.has(t_date)) continue;
      this.date_set.add(t_date);
      this.state.availableDate.push(t_date);
    }
  }

  componentWillMount() {
    this._getAllAvailableDate().done();
  }

  async _storeSelectDate(value) {
    await AsyncStorage.setItem('@Bref:FilterByDate', "true")
      .then(success => {
        console.log('set filter by date success');
      })
      .catch(error => {
        console.log('set filter by date fail')
      });

    let DateString = value.substring(0, 10);
    await AsyncStorage.setItem('@Bref:SelectDate', DateString)
      .then(success => {
        console.log('store select date success');
      })
      .catch(error => {
        console.log('store select date fail')
      });
  }

  _onDateSelect(date) {
    if (!this.date_set.has(date.substring(0, 10)))    //has no moment records
    {
      this.setState({currentSelectedDate: date.substring(0, 10)});
      return;
    }
    this._storeSelectDate(date);
  }

  render() {
    return (
      <View style={[{marginTop: 60}, styles.container]}>
        <Calendar
          customStyle={calendar_style}
          showEventIndicators
          eventDates={this.state.availableDate}
          dayHeadings={customDayHeadings}               // Default: ['S', 'M', 'T', 'W', 'T', 'F', 'S']
          monthNames={customMonthNames}                // Defaults to english names of months
          nextButtonText={'Next'}           // Text for next button. Default: 'Next'
          onDateSelect={(date) => {
            this._onDateSelect(date);
          }} // Callback after date selection
          onSwipeNext={this.onSwipeNext}    // Callback for forward swipe event
          onSwipePrev={this.onSwipePrev}    // Callback for back swipe event
          onTouchNext={this.onTouchNext}    // Callback for next touch event
          onTouchPrev={this.onTouchPrev}    // Callback for prev touch event
          prevButtonText={'Prev'}           // Text for previous button. Default: 'Prev'
          scrollEnabled={true}              // False disables swiping. Default: False
          selectedDate={this._getCurrentDate()}       // Day to be selected
          showControls={true}               // False hides prev/next buttons. Default: False
          startDate={this._getCurrentDate()}          // The first month that will display. Default: current month
          titleFormat={'MMMM YYYY'}         // Format for displaying current month. Default: 'MMMM YYYY'
          today={this._getCurrentDate()}              // Defaults to today
          weekStart={1} // Day on which week starts 0 - Sunday, 1 - Monday, 2 - Tuesday, etc, Default: 1
        />
        <Text style={[styles.commonText, {marginTop: 8}]}>
          Selected date:   {this.state.currentSelectedDate} has no records!
        </Text>
        <Text style={styles.commonText}>
          Only dates with green squares in the bottom are valid.
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 0,
    backgroundColor: '#202020',
    justifyContent: 'flex-start'
  },
  commonText: {
    padding: 5,
    paddingTop: 5,
    paddingBottom: 5,
    color: '#FFFFFF'
  },
});<|endoftext|>


<commit_before>var Widget = require('./widget');
var Button = require('./button');
var Program = require('../app/program');

function ProgramsBar(e, app) {
    Widget.call(this, e);

    this._document = null;
    this._show_delete = null;

    this.document(app.document);
    app.on('notify::document', function() {
        this.document(app.document);
    }, this);

    this._ul = e.querySelector('ul');

    this._new_program = new Button(e.querySelector('#new-program'));
    this._new_program.on('click', this._on_new_program_click, this);

    this._new_program_name = e.querySelector('#new-program-name');
    this._new_program_name.addEventListener('keypress', this._on_new_program_name_keypress.bind(this));
}

ProgramsBar.prototype = Object.create(Widget.prototype);
ProgramsBar.prototype.constructor = Widget;

ProgramsBar.prototype._on_new_program_name_keypress = function(e) {
    if (e.keyCode === 13) {
        this._on_new_program_click(this._new_program, e);
    }
}

ProgramsBar.prototype.document = function(document) {
    if (typeof document === 'undefined') {
        return this._document;
    }

    if (this._document === document) {
        return;
    }

    if (this._document !== null) {
        this._document.off('notify::active-program', this._on_active_program_changed, this);
        this._document.off('program-added', this._on_program_added, this);
        this._document.off('program-removed', this._on_program_removed, this);

        for (var i = 0; i < this._document.programs.length; i++) {
            var p = this._document.programs[i];

            p.off('notify::name', this._on_program_name_changed);
        }
    }

    this._document = document;

    if (this._document !== null) {
        this._document.on('notify::active-program', this._on_active_program_changed, this);
        this._document.on('program-added', this._on_program_added, this);
        this._document.on('program-removed', this._on_program_removed, this);

        for (var i = 0; i < this._document.programs.length; i++) {
            var p = this._document.programs[i];
            this._on_program_added(this._document, p);
        }

        this._on_active_program_changed();
    }
}

ProgramsBar.prototype._unique_program_name = function(name) {
    var names = {};

    for (var i = 0; i < this._document.programs.length; i++) {
        names[this._document.programs[i].name()] = true;
    }

    var i = 0;
    var uname;

    while (true) {
        uname = name;

        if (i !== 0) {
            uname += ' ' + i;
        }

        if (!(uname in names)) {
            break;
        }

        i++;
    }

    return uname;
}

ProgramsBar.prototype._on_new_program_click = function(button, e) {
    var name = this._new_program_name.value.trim();

    if (name.length === 0) {
        this._new_program_name.focus();
        return;
    }

    var prg = Program.default();
    var uname = this._unique_program_name(name);

    prg.name(uname);
    this._document.add_program(prg);
    this._document.active_program(prg);

    this._new_program_name.value = '';

    e.preventDefault();
    e.stopPropagation();
}

ProgramsBar.prototype._find_by_name = function(name) {
    return this._ul.querySelector('[data-program-name=' + JSON.stringify(name) + ']');
}

ProgramsBar.prototype._insert_program_item = function(program, item) {
    var lis = this._ul.querySelectorAll('li');
    var found = null;

    for (var i = 0; i < lis.length; i++) {
        var attr = lis[i].getAttribute('data-program-name');
        if (!attr || program.name() < attr) {
            found = lis[i];
            break;
        }
    }

    this._ul.insertBefore(item, found);
}

ProgramsBar.prototype._display_name = function(program) {
    var name = program.name();

    if (program.is_default()) {
        return '► ' + name;
    }

    return name;
}

ProgramsBar.prototype._on_program_name_changed = function(program, prevname) {
    var item = this._find_by_name(prevname);

    if (item) {
        item.setAttribute('data-program-name', program.name());
        item.querySelector('span.name').textContent = this._display_name(program);

        this._ul.removeChild(item);
        this._insert_program_item(program, item);
    }
}

ProgramsBar.prototype._on_active_program_changed = function() {
    var sel = this._ul.querySelector('li.selected');

    if (sel) {
        sel.classList.remove('selected');
    }

    var p = this._document.active_program();
    sel = this._find_by_name(p.name());

    if (sel) {
        sel.classList.add('selected');
    }

    if (this._show_delete !== null && this._show_delete.element !== sel) {
        this._on_program_toggle_delete(this._show_delete.element, this._show_delete.program);
    }
}

ProgramsBar.prototype._on_program_click = function(program) {
    this._document.active_program(program);
}

ProgramsBar.prototype._on_program_toggle_delete = function(elem, program) {
    var name = elem.querySelector('span.name');

    if (elem.classList.contains('deleting')) {
        elem.classList.remove('deleting');

        var del = elem.querySelector('div.delete');
        del.classList.remove('animate-in');

        this._show_delete = null;

        setTimeout(function() {
            elem.removeChild(del);
        }, 300);
    } else {
        elem.classList.add('deleting');

        var del = document.createElement('div');
        del.classList.add('delete');
        del.setAttribute('title', 'Delete Program');

        var span = document.createElement('span');
        span.textContent = '✖';
        del.appendChild(span);

        elem.appendChild(del);

        // trigger re-layout
        del.offsetWidth;
        del.classList.add('animate-in');

        del.addEventListener('click', (function(e) {
            this._document.remove_program(program);
            e.preventDefault();
            e.stopPropagation();
        }).bind(this));

        this._show_delete = {
            element: elem,
            program: program
        };
    }
}

ProgramsBar.prototype._on_program_begin_edit_name = function(elem, program) {
    if (elem.classList.contains('editing')) {
        return;
    }

    elem.classList.add('editing');
    var inp = document.createElement('input');
    inp.setAttribute('type', 'text');
    inp.value = program.name();

    elem.appendChild(inp);
    inp.select(0, program.name().length);

    inp.addEventListener('keydown', (function(e) {
        switch (e.keyCode) {
        case 27:
            // Escape, cancel
            if (inp.value === program.name()) {
                inp.blur();
            } else {
                inp.value = program.name();
                inp.select(0, inp.value.length);
            }
            break;
        case 13:
            // Enter, accept
            inp.blur();
            break;
        default:
            return;
        }

        e.stopPropagation();
        e.preventDefault();
    }).bind(this));

    inp.addEventListener('blur', (function() {
        elem.classList.remove('editing');
        elem.removeChild(inp);

        var name = inp.value.trim();

        if (name.length !== 0 && program.name() !== name) {
            // Make unique
            program.name(this._unique_program_name(name));
        }
    }).bind(this));
}

ProgramsBar.prototype._on_program_error_changed = function(program) {
    var elem = this._find_by_name(program.name());

    if (elem) {
        if (program.error()) {
            elem.classList.add('error');
        } else {
            elem.classList.remove('error');
        }
    }
}

ProgramsBar.prototype._on_program_added = function(doc, program) {
    program.on('notify::name', this._on_program_name_changed, this);
    program.on('notify::error', this._on_program_error_changed, this);

    var li = document.createElement('li');
    li.setAttribute('data-program-name', program.name());

    var span = document.createElement('span');
    span.classList.add('name');
    span.textContent = this._display_name(program);

    li.appendChild(span);

    li.addEventListener('click', (function(e) {
        this._on_program_click(program);
        e.preventDefault();
        e.stopPropagation();
    }).bind(this));

    li.addEventListener('contextmenu', (function(e) {
        this._on_program_click(program);

        if (!program.is_default()) {
            this._on_program_toggle_delete(li, program);
        }

        e.preventDefault();
        e.stopPropagation();
    }).bind(this));

    li.addEventListener('dblclick', (function(e) {
        this._on_program_begin_edit_name(li, program);

        e.preventDefault();
        e.stopPropagation();
    }).bind(this));

    if (program === this._document.active_program()) {
        li.classList.add('selected');
    }

    this._insert_program_item(program, li);
    this._on_program_error_changed(program);
}

ProgramsBar.prototype._on_program_removed = function(doc, program) {
    program.off('notify::name', this._on_program_name_changed, this);
    program.off('notify::error', this._on_program_error_changed, this);

    var item = this._find_by_name(program.name());

    if (item) {
        item.classList.add('removed');

        if (this._show_delete !== null && this._show_delete.element === item) {
            this._on_program_toggle_delete(elem, program);
        }

        setTimeout((function() {
            this._ul.removeChild(item);
        }).bind(this), 300);
    }
}

module.exports = ProgramsBar;

// vi:ts=4:et
<commit_msg>Clear programs bar when new document is set<commit_after>var Widget = require('./widget');
var Button = require('./button');
var Program = require('../app/program');

function ProgramsBar(e, app) {
    Widget.call(this, e);

    this._document = null;
    this._show_delete = null;

    this.document(app.document);

    app.on('notify::document', function() {
        this.document(app.document);
    }, this);

    this._ul = e.querySelector('ul');

    this._new_program = new Button(e.querySelector('#new-program'));
    this._new_program.on('click', this._on_new_program_click, this);

    this._new_program_name = e.querySelector('#new-program-name');
    this._new_program_name.addEventListener('keypress', this._on_new_program_name_keypress.bind(this));
}

ProgramsBar.prototype = Object.create(Widget.prototype);
ProgramsBar.prototype.constructor = Widget;

ProgramsBar.prototype._on_new_program_name_keypress = function(e) {
    if (e.keyCode === 13) {
        this._on_new_program_click(this._new_program, e);
    }
}

ProgramsBar.prototype.document = function(document) {
    if (typeof document === 'undefined') {
        return this._document;
    }

    if (this._document === document) {
        return;
    }

    if (this._document !== null) {
        this._document.off('notify::active-program', this._on_active_program_changed, this);
        this._document.off('program-added', this._on_program_added, this);
        this._document.off('program-removed', this._on_program_removed, this);

        for (var i = 0; i < this._document.programs.length; i++) {
            var p = this._document.programs[i];
            this._on_program_removed(this._document, p, true);
        }
    }

    this._document = document;

    if (this._document !== null) {
        this._document.on('notify::active-program', this._on_active_program_changed, this);
        this._document.on('program-added', this._on_program_added, this);
        this._document.on('program-removed', this._on_program_removed, this);

        for (var i = 0; i < this._document.programs.length; i++) {
            var p = this._document.programs[i];
            this._on_program_added(this._document, p);
        }

        this._on_active_program_changed();
    }
}

ProgramsBar.prototype._unique_program_name = function(name) {
    var names = {};

    for (var i = 0; i < this._document.programs.length; i++) {
        names[this._document.programs[i].name()] = true;
    }

    var i = 0;
    var uname;

    while (true) {
        uname = name;

        if (i !== 0) {
            uname += ' ' + i;
        }

        if (!(uname in names)) {
            break;
        }

        i++;
    }

    return uname;
}

ProgramsBar.prototype._on_new_program_click = function(button, e) {
    var name = this._new_program_name.value.trim();

    if (name.length === 0) {
        this._new_program_name.focus();
        return;
    }

    var prg = Program.default();
    var uname = this._unique_program_name(name);

    prg.name(uname);
    this._document.add_program(prg);
    this._document.active_program(prg);

    this._new_program_name.value = '';

    e.preventDefault();
    e.stopPropagation();
}

ProgramsBar.prototype._find_by_name = function(name) {
    return this._ul.querySelector('[data-program-name=' + JSON.stringify(name) + ']');
}

ProgramsBar.prototype._insert_program_item = function(program, item) {
    var lis = this._ul.querySelectorAll('li');
    var found = null;

    for (var i = 0; i < lis.length; i++) {
        var attr = lis[i].getAttribute('data-program-name');
        if (!attr || program.name() < attr) {
            found = lis[i];
            break;
        }
    }

    this._ul.insertBefore(item, found);
}

ProgramsBar.prototype._display_name = function(program) {
    var name = program.name();

    if (program.is_default()) {
        return '► ' + name;
    }

    return name;
}

ProgramsBar.prototype._on_program_name_changed = function(program, prevname) {
    var item = this._find_by_name(prevname);

    if (item) {
        item.setAttribute('data-program-name', program.name());
        item.querySelector('span.name').textContent = this._display_name(program);

        this._ul.removeChild(item);
        this._insert_program_item(program, item);
    }
}

ProgramsBar.prototype._on_active_program_changed = function() {
    var sel = this._ul.querySelector('li.selected');

    if (sel) {
        sel.classList.remove('selected');
    }

    var p = this._document.active_program();
    sel = this._find_by_name(p.name());

    if (sel) {
        sel.classList.add('selected');
    }

    if (this._show_delete !== null && this._show_delete.element !== sel) {
        this._on_program_toggle_delete(this._show_delete.element, this._show_delete.program);
    }
}

ProgramsBar.prototype._on_program_click = function(program) {
    this._document.active_program(program);
}

ProgramsBar.prototype._on_program_toggle_delete = function(elem, program) {
    var name = elem.querySelector('span.name');

    if (elem.classList.contains('deleting')) {
        elem.classList.remove('deleting');

        var del = elem.querySelector('div.delete');
        del.classList.remove('animate-in');

        this._show_delete = null;

        setTimeout(function() {
            elem.removeChild(del);
        }, 300);
    } else {
        elem.classList.add('deleting');

        var del = document.createElement('div');
        del.classList.add('delete');
        del.setAttribute('title', 'Delete Program');

        var span = document.createElement('span');
        span.textContent = '✖';
        del.appendChild(span);

        elem.appendChild(del);

        // trigger re-layout
        del.offsetWidth;
        del.classList.add('animate-in');

        del.addEventListener('click', (function(e) {
            this._document.remove_program(program);
            e.preventDefault();
            e.stopPropagation();
        }).bind(this));

        this._show_delete = {
            element: elem,
            program: program
        };
    }
}

ProgramsBar.prototype._on_program_begin_edit_name = function(elem, program) {
    if (elem.classList.contains('editing')) {
        return;
    }

    elem.classList.add('editing');
    var inp = document.createElement('input');
    inp.setAttribute('type', 'text');
    inp.value = program.name();

    elem.appendChild(inp);
    inp.select(0, program.name().length);

    inp.addEventListener('keydown', (function(e) {
        switch (e.keyCode) {
        case 27:
            // Escape, cancel
            if (inp.value === program.name()) {
                inp.blur();
            } else {
                inp.value = program.name();
                inp.select(0, inp.value.length);
            }
            break;
        case 13:
            // Enter, accept
            inp.blur();
            break;
        default:
            return;
        }

        e.stopPropagation();
        e.preventDefault();
    }).bind(this));

    inp.addEventListener('blur', (function() {
        elem.classList.remove('editing');
        elem.removeChild(inp);

        var name = inp.value.trim();

        if (name.length !== 0 && program.name() !== name) {
            // Make unique
            program.name(this._unique_program_name(name));
        }
    }).bind(this));
}

ProgramsBar.prototype._on_program_error_changed = function(program) {
    var elem = this._find_by_name(program.name());

    if (elem) {
        if (program.error()) {
            elem.classList.add('error');
        } else {
            elem.classList.remove('error');
        }
    }
}

ProgramsBar.prototype._on_program_added = function(doc, program) {
    program.on('notify::name', this._on_program_name_changed, this);
    program.on('notify::error', this._on_program_error_changed, this);

    var li = document.createElement('li');
    li.setAttribute('data-program-name', program.name());

    var span = document.createElement('span');
    span.classList.add('name');
    span.textContent = this._display_name(program);

    li.appendChild(span);

    li.addEventListener('click', (function(e) {
        this._on_program_click(program);
        e.preventDefault();
        e.stopPropagation();
    }).bind(this));

    li.addEventListener('contextmenu', (function(e) {
        this._on_program_click(program);

        if (!program.is_default()) {
            this._on_program_toggle_delete(li, program);
        }

        e.preventDefault();
        e.stopPropagation();
    }).bind(this));

    li.addEventListener('dblclick', (function(e) {
        this._on_program_begin_edit_name(li, program);

        e.preventDefault();
        e.stopPropagation();
    }).bind(this));

    if (program === this._document.active_program()) {
        li.classList.add('selected');
    }

    this._insert_program_item(program, li);
    this._on_program_error_changed(program);
}

ProgramsBar.prototype._on_program_removed = function(doc, program, changing_doc) {
    program.off('notify::name', this._on_program_name_changed, this);
    program.off('notify::error', this._on_program_error_changed, this);

    var item = this._find_by_name(program.name());

    if (item) {
        if (!changing_doc) {
            item.classList.add('removed');

            if (this._show_delete !== null && this._show_delete.element === item) {
                this._on_program_toggle_delete(elem, program);
            }

            setTimeout((function() {
                this._ul.removeChild(item);
            }).bind(this), 300);
        } else {
            if (this._show_delete !== null && this._show_delete.element === item) {
                this._show_delete = null;
            }

            this._ul.removeChild(item);
        }
    }
}

module.exports = ProgramsBar;

// vi:ts=4:et
<|endoftext|>


<commit_before>/*
 * Wegas
 * http://wegas.albasim.ch
 *
 * Copyright (c) 2013, 2014, 2015 School of Business and Engineering Vaud, Comem
 * Licensed under the MIT License
 */

/**
 *
 * @fileoverview
 * @author Cyril Junod <cyril.junod at gmail.com>
 */
/*global YUI*/
YUI.add("wegas-showoverlayonclick", function(Y) {
    "use strict";

    var ShowOverlayOnClick, ShowInboxListOnClick;

    ShowOverlayOnClick = Y.Base.create("wegas-showoverlayonclick", Y.Plugin.Base, [Y.Wegas.Plugin, Y.Wegas.Editable], {
        initializer: function() {
            this.handlers = [];
            this.detailsOverlay = new Y.Overlay({
                zIndex: 100,
                constrain: true,
                visible: false
            }).render();

            this.detailsOverlay.plug(Y.Plugin.Injector);
            var maxWidth = this.get("maxwidth");
            if (maxWidth) {
                this.detailsOverlay.get("boundingBox").setStyle("max-width", maxWidth);
            }

            //this.detailsOverlay.set("headerContent", "
" + this.get("title") + "
");
            this.detailsOverlay.setStdModContent('body', "

");

            this.displayed = false;
            this.detailsOverlay.get("boundingBox").addClass("wegas-onclick-overlay");
            this.get("host").get("boundingBox").addClass("wegas-click");
            this.bind();
        },
        bind: function() {
            this.handlers.push(this.get("host").get("boundingBox").on("click", this.onClick, this));
            this.handlers.push(this.get("host").get("boundingBox").on("clickoutside", this.hide, this));
            //this.handlers.push(Y.one("body").on("click", this.hide, this));
            this.onceAfterHostEvent("render", this._sync);
            this.afterHostMethod("syncUI", this._sync);
            this._customBind();
        },
        _customBind: function() {
        },
        _sync: function() {
        },
        hide: function(e) {
            this.detailsOverlay.hide();
            this.widget && this.widget.destroy();
            this.widget = null;
            this.displayed = false;

            var bb = this.get("host").get("boundingBox");
            bb.toggleClass("wegas-onclick-overlay--displayed", false);
        },
        onClick: function(e) {
            if (this.displayed) {
                this.hide(null);
            } else {
                this.display();
            }
        },
        display: function() {
            var bb, br;
            if (!this.widget) {
                this.genWidget();
            }

            bb = this.get("host").get("boundingBox");
            bb.toggleClass("wegas-onclick-overlay--displayed", true);

            br = bb.getDOMNode().getBoundingClientRect();
            this.detailsOverlay.move(br.left, br.bottom);
            // prevent going off-screen
            this.detailsOverlay.get("boundingBox").setStyle("max-height", window.innerHeight - br.bottom - 50);

            this.detailsOverlay.show();
            this.displayed = true;
        },
        genWidget: function() {
            var theVar = this.get("variable");
            if (theVar) {
                var ctx = this,
                    cfg = this.get("theWidget");
                Y.Wegas.Editable.use(cfg, function(Y) {
                    if (ctx.widget) {
                        ctx.widget.set(ctx.get("widgetAttr"), theVar);
                    } else {
                        cfg[ctx.get("widgetAttr")] = theVar;
                        Y.Wegas.use(cfg, Y.bind(function() {
                            this.widget = Y.Wegas.Widget.create(cfg);
                            if (this.widget) {
                                this.widget.render(this.detailsOverlay.get("contentBox").one(".yui3-widget-bd > div"));
                                this.widget.on(["*:message", "*:showOverlay", "*:hideOverlay"], this.fire, this); // Event on the loaded

                                Y.later(100, this, function() {
                                    if (this.widget) {

                                        var bb = this.widget.get("boundingBox"),
                                            br = bb.getDOMNode().getBoundingClientRect();
                                        Y.log(br);
                                        if (br.right > window.innerWidth) {
                                            this.detailsOverlay.get("boundingBox").setStyle("left", window.innerWidth - br.width);
                                            //this.detailsOverlay.move(window.innerWidth - br.width, this.currentPos[1]);
                                        }
                                    }
                                });
                            }
                        }, ctx));
                    }
                });
            }
        },
        /**
         * Destructor methods.
         * @function
         * @private
         */
        destructor: function() {
            var i;
            this.detailsOverlay.destroy();
            this.widget && this.widget.destroy();
            for (i = 0; i < this.handlers.length; i += 1) {
                this.handlers[i].detach();
            }
        }
    }, {
        ATTRS: {
            maxwidth: {
                type: "string",
                value: "",
                optional: true
            },
            variable: {
                getter: Y.Wegas.Widget.VARIABLEDESCRIPTORGETTER,
                _inputex: {
                    _type: "variableselect",
                    label: "Variable"
                }
            },
            theWidget: {
                value: {
                    "type": "InboxList"
                },
                getter: function(v) {
                    return Y.JSON.parse(Y.JSON.stringify(v));
                },
                _inputex: {
                    _type: "group",
                    fields: [{
                            type: "string",
                            name: "type",
                            label: "Type"
                        }]
                }
            },
            widgetAttr: {
                value: "variable",
                type: "string"
            }
        },
        NS: "showoverlayonclick"
    });
    Y.Plugin.ShowOverlayOnClick = ShowOverlayOnClick;

    ShowInboxListOnClick = Y.Base.create("wegas-showinboxlistonclick", Y.Plugin.ShowOverlayOnClick, [], {
    }, {
        ATTRS: {
            variable: {
                getter: Y.Wegas.Widget.VARIABLEDESCRIPTORGETTER,
                _inputex: {
                    _type: "variableselect",
                    label: "Overlay Inbox"
                }
            },
            theWidget: {
                "transient": "true",
                value: {
                    type: "InboxList",
                    template: "clean",
                    chronological: false
                },
                _inputex: {
                    type: "hidden"
                }
            },
            widgetAttr: {
                "transient": "true",
                value: "variable",
                type: "hidden"
            }

        },
        NS: "showinboxlistonclick"
    });
    Y.Plugin.ShowInboxListOnClick = ShowInboxListOnClick;
});
<commit_msg>fix author<commit_after>/*
 * Wegas
 * http://wegas.albasim.ch
 *
 * Copyright (c) 2013, 2014, 2015 School of Business and Engineering Vaud, Comem
 * Licensed under the MIT License
 */

/**
 *
 * @fileoverview
 * @author Maxence
 */
/*global YUI*/
YUI.add("wegas-showoverlayonclick", function(Y) {
    "use strict";

    var ShowOverlayOnClick, ShowInboxListOnClick;

    ShowOverlayOnClick = Y.Base.create("wegas-showoverlayonclick", Y.Plugin.Base, [Y.Wegas.Plugin, Y.Wegas.Editable], {
        initializer: function() {
            this.handlers = [];
            this.detailsOverlay = new Y.Overlay({
                zIndex: 100,
                constrain: true,
                visible: false
            }).render();

            this.detailsOverlay.plug(Y.Plugin.Injector);
            var maxWidth = this.get("maxwidth");
            if (maxWidth) {
                this.detailsOverlay.get("boundingBox").setStyle("max-width", maxWidth);
            }

            //this.detailsOverlay.set("headerContent", "
" + this.get("title") + "
");
            this.detailsOverlay.setStdModContent('body', "

");

            this.displayed = false;
            this.detailsOverlay.get("boundingBox").addClass("wegas-onclick-overlay");
            this.get("host").get("boundingBox").addClass("wegas-click");
            this.bind();
        },
        bind: function() {
            this.handlers.push(this.get("host").get("boundingBox").on("click", this.onClick, this));
            this.handlers.push(this.get("host").get("boundingBox").on("clickoutside", this.hide, this));
            //this.handlers.push(Y.one("body").on("click", this.hide, this));
            this.onceAfterHostEvent("render", this._sync);
            this.afterHostMethod("syncUI", this._sync);
            this._customBind();
        },
        _customBind: function() {
        },
        _sync: function() {
        },
        hide: function(e) {
            this.detailsOverlay.hide();
            this.widget && this.widget.destroy();
            this.widget = null;
            this.displayed = false;

            var bb = this.get("host").get("boundingBox");
            bb.toggleClass("wegas-onclick-overlay--displayed", false);
        },
        onClick: function(e) {
            if (this.displayed) {
                this.hide(null);
            } else {
                this.display();
            }
        },
        display: function() {
            var bb, br;
            if (!this.widget) {
                this.genWidget();
            }

            bb = this.get("host").get("boundingBox");
            bb.toggleClass("wegas-onclick-overlay--displayed", true);

            br = bb.getDOMNode().getBoundingClientRect();
            this.detailsOverlay.move(br.left, br.bottom);
            // prevent going off-screen
            this.detailsOverlay.get("boundingBox").setStyle("max-height", window.innerHeight - br.bottom - 50);

            this.detailsOverlay.show();
            this.displayed = true;
        },
        genWidget: function() {
            var theVar = this.get("variable");
            if (theVar) {
                var ctx = this,
                    cfg = this.get("theWidget");
                Y.Wegas.Editable.use(cfg, function(Y) {
                    if (ctx.widget) {
                        ctx.widget.set(ctx.get("widgetAttr"), theVar);
                    } else {
                        cfg[ctx.get("widgetAttr")] = theVar;
                        Y.Wegas.use(cfg, Y.bind(function() {
                            this.widget = Y.Wegas.Widget.create(cfg);
                            if (this.widget) {
                                this.widget.render(this.detailsOverlay.get("contentBox").one(".yui3-widget-bd > div"));
                                this.widget.on(["*:message", "*:showOverlay", "*:hideOverlay"], this.fire, this); // Event on the loaded

                                Y.later(100, this, function() {
                                    if (this.widget) {

                                        var bb = this.widget.get("boundingBox"),
                                            br = bb.getDOMNode().getBoundingClientRect();
                                        Y.log(br);
                                        if (br.right > window.innerWidth) {
                                            this.detailsOverlay.get("boundingBox").setStyle("left", window.innerWidth - br.width);
                                            //this.detailsOverlay.move(window.innerWidth - br.width, this.currentPos[1]);
                                        }
                                    }
                                });
                            }
                        }, ctx));
                    }
                });
            }
        },
        /**
         * Destructor methods.
         * @function
         * @private
         */
        destructor: function() {
            var i;
            this.detailsOverlay.destroy();
            this.widget && this.widget.destroy();
            for (i = 0; i < this.handlers.length; i += 1) {
                this.handlers[i].detach();
            }
        }
    }, {
        ATTRS: {
            maxwidth: {
                type: "string",
                value: "",
                optional: true
            },
            variable: {
                getter: Y.Wegas.Widget.VARIABLEDESCRIPTORGETTER,
                _inputex: {
                    _type: "variableselect",
                    label: "Variable"
                }
            },
            theWidget: {
                value: {
                    "type": "InboxList"
                },
                getter: function(v) {
                    return Y.JSON.parse(Y.JSON.stringify(v));
                },
                _inputex: {
                    _type: "group",
                    fields: [{
                            type: "string",
                            name: "type",
                            label: "Type"
                        }]
                }
            },
            widgetAttr: {
                value: "variable",
                type: "string"
            }
        },
        NS: "showoverlayonclick"
    });
    Y.Plugin.ShowOverlayOnClick = ShowOverlayOnClick;

    ShowInboxListOnClick = Y.Base.create("wegas-showinboxlistonclick", Y.Plugin.ShowOverlayOnClick, [], {
    }, {
        ATTRS: {
            variable: {
                getter: Y.Wegas.Widget.VARIABLEDESCRIPTORGETTER,
                _inputex: {
                    _type: "variableselect",
                    label: "Overlay Inbox"
                }
            },
            theWidget: {
                "transient": "true",
                value: {
                    type: "InboxList",
                    template: "clean",
                    chronological: false
                },
                _inputex: {
                    type: "hidden"
                }
            },
            widgetAttr: {
                "transient": "true",
                value: "variable",
                type: "hidden"
            }

        },
        NS: "showinboxlistonclick"
    });
    Y.Plugin.ShowInboxListOnClick = ShowInboxListOnClick;
});
<|endoftext|>