<commit_before>/**
 * filtercollection.js
 *
 * Provides a collection type that utilizes automatic filtering to create what
 * are essentially materialized views.
 * -----------------------------------------------------------------------------
 *
 * Composer.js is an MVC framework for creating and organizing javascript
 * applications. For documentation, please visit:
 *
 *     http://lyonbros.github.com/composer.js/
 *
 * -----------------------------------------------------------------------------
 *
 * Copyright (c) 2011, Lyon Bros Enterprises, LLC. (http://www.lyonbros.com)
 *
 * Licensed under The MIT License.
 * Redistributions of files must retain the above copyright notice.
 */
(function() {
	"use strict";

	/**
	 * Collection that exists solely to be a "materialized view" of another
	 * "master" collection. Whenever items are added/removed from the master
	 * collection, the changes are filtered and applied to this collection as well.
	 * This is useful for keeping many collections in sync with one master list
	 * without having to manually update them all.
	 */
	var FilterCollection = Composer.Collection.extend({
		/**
		 * Track this object's type. Useful for debugging, mainly
		 */
		__composer_type: 'filtercollection',

		// holds the master collection, used to derive the items in this
		// filtercollection
		master: null,

		// the filter function, used to determine if a model should be included
		// in the filtercollection's results
		filter: function() { return true },

		// transformation function, called on a model when it's added or removed
		// to the collection
		transform: null,

		// if set to an integer will limit the amount of models this collection
		// will keep (post sort)
		limit: false,

		options: {
			forward_all_events: false,
			refresh_on_change: false,	// performance hit, but needed for backward compat
			sort_event: false			// if true, fires a 'sort' event instead of 'reset' when sorting
		},

		initialize: function(master, options)
		{
			options || (options = {});

			var optkeys = Object.keys(this.options);
			Object.keys(options).forEach(function(k) {
				var v = options[k];
				if(typeof(v) == 'function') v = v.bind(this);
				if(optkeys.indexOf(k) >= 0)
				{
					this.options[k] = v;
				}
				else
				{
					this[k] = v;
				}
			}.bind(this));

			// call Base.initialize
			this.parent();

			this.master = master;

			if(!this.master) return false;
			if(!this.filter) return false;

			this.attach(options);
			if(!options.skip_initial_sync) this.refresh();
		},

		/**
		 * bind our events to the master collection and start filtering
		 */
		attach: function()
		{
			this.master.bind('all', this.match_action.bind(this), 'filtercollection:'+this.cid()+':all');
			this.bind('reset', function(options) {
				options || (options = {});
				if(options.has_reload) return false;
				this.refresh(options);
			}.bind(this), 'filtercollection:reset');
		},

		/**
		 * detach from the master collection (stop listening and filtering)
		 */
		detach: function()
		{
			this.master.unbind('all', 'filtercollection:'+this.cid()+':all');
			this.unbind('reset', 'filtercollection:reset');
		},

		/**
		 * internal function used to match events from the master collection.
		 */
		match_action: function(event, model)
		{
			var args = Array.prototype.slice.call(arguments, 0);
			switch(event)
			{
			case 'add':
				this.add_event(model, {from_event: true}); break;
			case 'reset':
				this.refresh(); break;
			case 'clear':
				this.clear(); break;
			case 'remove':
				this.remove_event(model, {from_event: true}); break;
			case 'change':
				this.change_event(model, {}, args); break;
			case 'sort':
				this.refresh(); break;
			default:
				this.forward_event(event, model, args); break;
			}
		},

		/**
		 * match our models to the master collection
		 *
		 * works by filtering the master's models then comparing the original
		 * models to the new (filtered) ones and firing the add/remove events
		 * for each model respectively.
		 *
		 * also performs sorting/limiting.
		 */
		refresh: function(options)
		{
			options || (options = {});

			if(options.diff_events)
			{
				var old_models = this._models;
			}
			this._models = this.master._models.filter(function(model) {
				return this.filter(model, this);
			}.bind(this));
			this.sort({silent: true});
			if(this.limit) this._models.splice(this.limit, this._models.length);
			if(options.diff_events)
			{
				var arrdiff = function(arr1, arr2) { return arr1.filter(function(el) { return arr2.indexOf(el) < 0; }); };

				arrdiff(old_models, this._models).forEach(function(model) {
					this.fire_event('remove', options, model);
				}, this);

				arrdiff(this._models, old_models).forEach(function(model) {
					this.fire_event('add', options, model);
				}, this);
			}
			this.fire_event('reset', options, {has_reload: true});
		},

		/**
		 * fired when a model changes. when this happens, we have to make sure
		 * the model still meets the filtercollection's criteria so we call
		 * tihs.filter on it to see if it "fits in."
		 */
		change_event: function(model, options, forward_args)
		{
			options || (options = {});

			// see if this model even belongs to this collection
			if(!model || (this.models().indexOf(model) < 0 && !this.filter(model, this))) return false;

			// track the current number of items and reloda the data
			var num_items = this._models.length;

			if(this.options.refresh_on_change)
			{
				// the brute force option (re-sort everything, re-filter everything)
				// VERY expensive
				this.refresh({silent: true});
			}
			else
			{
				// a more tactful approach
				var cur_index = this._models.indexOf(model);
				var new_index = this.sort_index(model);

				if(cur_index == -1 && this.filter(model, this))
				{
					// welcome to the team!
					this.add(model, options);
				}
				else if(cur_index > -1 && !this.filter(model, this))
				{
					// we feel that your interests no longer align with the team's
					// ...we're going to have to let you go.
					//
					// You BASTARDS I've poured my LIFE into this collection!!
					//
					// Yes and we're thankful for your hard work, but feel it's
					// time to move on. Your replacement is a potted plant (come
					// to think of it, so is your severance). Think of this as a
					// new beginning! Now get out of my office.
					this.remove(model, options);
				}
				else if(cur_index != new_index)
				{
					// sort order changed
					if(this.options.sort_event)
					{
						this.sort(Composer.object.merge({}, options, {silent: true}));
						this.fire_event('sort', options);
					}
					else
					{
						this.sort(options);
					}
				}
			}

			// if the number of elements in the FC is unchanged, just fire a
			// standard "change" event (with the forwarded args), otherwise the
			// change triggered a membership change...in this case, the
			// add/remove events should cover the change.
			if(this._models.length == num_items)
			{
				forward_args.shift();
				var args = ['change', options].concat(forward_args);
				this.fire_event.apply(this, args);
			}
			else if(this.options.refresh_on_change)
			{
				this.fire_event('reset', options);
			}
		},

		/**
		 * extension of Collection.add that makes sure our model passes the
		 * filter test, and also adds the model into the master collection
		 * instead of the filtercollection's models dircetly.
		 */
		add: function(data, options)
		{
			if (Composer.array.is(data))
			{
				return Composer.object.each(data, function(model) { this.add(model, options); }, this);
			}

			options || (options = {});
			if(typeof(options.transform) == 'undefined') options.transform = true;

			// if we are passing raw data, create a new model from data
			var model = data.__composer_type == 'model' ? data : new this.master.model(data, options);

			if(this.transform && options.transform)
			{
				model = this.transform.call(this, model, 'add');
			}

			// model doesn't match filter. NICE TRY
			if(!this.filter(model, this)) return false;

			if(typeof(options.at) == 'number')
			{
				// find the correct insertion point in the master it options.at is set.
				var current = this.at(options.at);
				var master_idx = this.master.index_of(current);
				if(master_idx !== false)
				{
					options.at = master_idx;
				}
			}

			// if this model exists in the master already, we call our special
			// _do_add method, which manually adds, sorts, and limits for us.
			// otherwise, we just call master.add() and the model will be added
			// here via our wonderful events
			if(this.master.index_of(model))
			{
				this._do_add(model, options);
			}
			else
			{
				this.master.add(model, options);
				if(this.limit) this._models.splice(this.limit);
			}
			return model;
		},

		/**
		 * Manually add a model to this collection. Sorts and limits as well.
		 */
		_do_add: function(model, options)
		{
			// master already has item, so we don't need to add it to
			// master (it will just fire "upsert"). what we need is to
			// add the model to this collection's models, sorted, and
			// apply the limit.
			this._models.push(model);
			var old_idx = this._models.indexOf(model);
			this.sort({silent: true});
			var new_idx = this._models.indexOf(model);
			if(this.limit) this._models.splice(this.limit);
			// after sort/limit, model may not actually be in the FC, so
			// check before wildly firing add/sort events
			if(this.index_of(model))
			{
				// model was actually added, fire "add" event
				this.fire_event('add', options, model, this, options);
				if(old_idx != new_idx)
				{
					// sort changed! fire appropriate event
					if(this.options.sort_event)
					{
						this.fire_event('sort', options);
					}
					else
					{
						this.fire_event('reset', options);
					}
				}
			}
		},

		/**
		 * extension of Colleciton.remove that removes the model from the
		 * collection but only if it exists
		 */
		remove: function(model, options)
		{
			if (Composer.array.is(model))
			{
				return Composer.object.each(model, function(m) { this.remove(m); }, this);
			}

			options || (options = {});
			if(typeof(options.transform) == 'undefined') options.transform = true;

			if(this._models.indexOf(model) < 0) return false;

			if(this.transform && options.transform)
			{
				model = this.transform.call(this, model, 'remove');
			}

			// remove the model
			Composer.array.erase(this._models, model);

			this.fire_event('remove', options, model);

			// remove the model from the collection
			this._remove_reference(model);
		},

		add_event: function(model, options)
		{
			if(!this.filter(model, this)) return false;
			this.refresh({silent: true});
			if(this.options.sort_event) this.fire_event('sort', options);
			this.fire_event('add', options, model, this, options);
		},

		remove_event: function(model, options)
		{
			if(this._models.indexOf(model) < 0) return false;
			this.refresh({silent: true});
			this.fire_event('remove', options, model);
		},

		forward_event: function(event, model, args)
		{
			// return if not forwarding events
			if(!this.options.forward_all_events) return false;

			// we're forwarding events, but we're not about to forward them for
			// a model that doesn't "fit in" around here
			if(model && model.__composer_type == 'model' && !this.filter(model, this))
			{
				return false;
			}
			this.trigger.apply(this, args);
		}
	});

	this.Composer.exp0rt({ FilterCollection: FilterCollection });
}).apply((typeof exports != 'undefined') ? exports : this);

<commit_msg>filtercollection bugfix (`add` event wasnt firing when it should have), and also some change_event performance enhancements<commit_after>/**
 * filtercollection.js
 *
 * Provides a collection type that utilizes automatic filtering to create what
 * are essentially materialized views.
 * -----------------------------------------------------------------------------
 *
 * Composer.js is an MVC framework for creating and organizing javascript
 * applications. For documentation, please visit:
 *
 *     http://lyonbros.github.com/composer.js/
 *
 * -----------------------------------------------------------------------------
 *
 * Copyright (c) 2011, Lyon Bros Enterprises, LLC. (http://www.lyonbros.com)
 *
 * Licensed under The MIT License.
 * Redistributions of files must retain the above copyright notice.
 */
(function() {
	"use strict";

	/**
	 * Collection that exists solely to be a "materialized view" of another
	 * "master" collection. Whenever items are added/removed from the master
	 * collection, the changes are filtered and applied to this collection as well.
	 * This is useful for keeping many collections in sync with one master list
	 * without having to manually update them all.
	 */
	var FilterCollection = Composer.Collection.extend({
		/**
		 * Track this object's type. Useful for debugging, mainly
		 */
		__composer_type: 'filtercollection',

		// holds the master collection, used to derive the items in this
		// filtercollection
		master: null,

		// the filter function, used to determine if a model should be included
		// in the filtercollection's results
		filter: function() { return true },

		// transformation function, called on a model when it's added or removed
		// to the collection
		transform: null,

		// if set to an integer will limit the amount of models this collection
		// will keep (post sort)
		limit: false,

		options: {
			forward_all_events: false,
			refresh_on_change: false,	// performance hit, but needed for backward compat
			sort_event: false			// if true, fires a 'sort' event instead of 'reset' when sorting
		},

		initialize: function(master, options)
		{
			options || (options = {});

			var optkeys = Object.keys(this.options);
			Object.keys(options).forEach(function(k) {
				var v = options[k];
				if(typeof(v) == 'function') v = v.bind(this);
				if(optkeys.indexOf(k) >= 0)
				{
					this.options[k] = v;
				}
				else
				{
					this[k] = v;
				}
			}.bind(this));

			// call Base.initialize
			this.parent();

			this.master = master;

			if(!this.master) return false;
			if(!this.filter) return false;

			this.attach(options);
			if(!options.skip_initial_sync) this.refresh();
		},

		/**
		 * bind our events to the master collection and start filtering
		 */
		attach: function()
		{
			this.master.bind('all', this.match_action.bind(this), 'filtercollection:'+this.cid()+':all');
			this.bind('reset', function(options) {
				options || (options = {});
				if(options.has_reload) return false;
				this.refresh(options);
			}.bind(this), 'filtercollection:reset');
		},

		/**
		 * detach from the master collection (stop listening and filtering)
		 */
		detach: function()
		{
			this.master.unbind('all', 'filtercollection:'+this.cid()+':all');
			this.unbind('reset', 'filtercollection:reset');
		},

		/**
		 * internal function used to match events from the master collection.
		 */
		match_action: function(event, model)
		{
			var args = Array.prototype.slice.call(arguments, 0);
			switch(event)
			{
			case 'add':
				this.add_event(model, {from_event: true}); break;
			case 'reset':
				this.refresh(); break;
			case 'clear':
				this.clear(); break;
			case 'remove':
				this.remove_event(model, {from_event: true}); break;
			case 'change':
				this.change_event(model, {}, args); break;
			case 'sort':
				this.refresh(); break;
			default:
				this.forward_event(event, model, args); break;
			}
		},

		/**
		 * match our models to the master collection
		 *
		 * works by filtering the master's models then comparing the original
		 * models to the new (filtered) ones and firing the add/remove events
		 * for each model respectively.
		 *
		 * also performs sorting/limiting.
		 */
		refresh: function(options)
		{
			options || (options = {});

			if(options.diff_events)
			{
				var old_models = this._models;
			}
			this._models = this.master._models.filter(function(model) {
				return this.filter(model, this);
			}.bind(this));
			this.sort({silent: true});
			if(this.limit) this._models.splice(this.limit, this._models.length);
			if(options.diff_events)
			{
				var arrdiff = function(arr1, arr2) { return arr1.filter(function(el) { return arr2.indexOf(el) < 0; }); };

				arrdiff(old_models, this._models).forEach(function(model) {
					this.fire_event('remove', options, model);
				}, this);

				arrdiff(this._models, old_models).forEach(function(model) {
					this.fire_event('add', options, model);
				}, this);
			}
			this.fire_event('reset', options, {has_reload: true});
		},

		/**
		 * fired when a model changes. when this happens, we have to make sure
		 * the model still meets the filtercollection's criteria so we call
		 * tihs.filter on it to see if it "fits in."
		 */
		change_event: function(model, options, forward_args)
		{
			options || (options = {});

			// see if this model even belongs to this collection
			var cur_index = this.models().indexOf(model);
			var filters = this.filter(model, this);
			if(!model || (cur_index < 0 && !filters)) return false;

			// track the current number of items and reloda the data
			var num_items = this._models.length;

			if(this.options.refresh_on_change)
			{
				// the brute force option (re-sort everything, re-filter everything)
				// VERY expensive
				this.refresh({silent: true});
			}
			else
			{
				// a more tactful approach
				var new_index = this.sort_index(model);

				if(cur_index == -1 && filters)
				{
					// welcome to the team!
					this.add(model, options);
				}
				else if(cur_index > -1 && !filters)
				{
					// we feel that your interests no longer align with the team's
					// ...we're going to have to let you go.
					//
					// You BASTARDS I've poured my LIFE into this collection!!
					//
					// Yes and we're thankful for your hard work, but feel it's
					// time to move on. Your replacement is a potted plant (come
					// to think of it, so is your severance). Think of this as a
					// new beginning! Now get out of my office.
					this.remove(model, options);
				}
				else if(cur_index != new_index)
				{
					// sort order changed
					if(this.options.sort_event)
					{
						this.sort(Composer.object.merge({}, options, {silent: true}));
						this.fire_event('sort', options);
					}
					else
					{
						this.sort(options);
					}
				}
			}

			// if the number of elements in the FC is unchanged, just fire a
			// standard "change" event (with the forwarded args), otherwise the
			// change triggered a membership change...in this case, the
			// add/remove events should cover the change.
			if(this._models.length == num_items)
			{
				forward_args.shift();
				var args = ['change', options].concat(forward_args);
				this.fire_event.apply(this, args);
			}
			else if(this.options.refresh_on_change)
			{
				this.fire_event('reset', options);
			}
		},

		/**
		 * extension of Collection.add that makes sure our model passes the
		 * filter test, and also adds the model into the master collection
		 * instead of the filtercollection's models dircetly.
		 */
		add: function(data, options)
		{
			if (Composer.array.is(data))
			{
				return Composer.object.each(data, function(model) { this.add(model, options); }, this);
			}

			options || (options = {});
			if(typeof(options.transform) == 'undefined') options.transform = true;

			// if we are passing raw data, create a new model from data
			var model = data.__composer_type == 'model' ? data : new this.master.model(data, options);

			if(this.transform && options.transform)
			{
				model = this.transform.call(this, model, 'add');
			}

			// model doesn't match filter. NICE TRY
			if(!this.filter(model, this)) return false;

			if(typeof(options.at) == 'number')
			{
				// find the correct insertion point in the master it options.at is set.
				var current = this.at(options.at);
				var master_idx = this.master.index_of(current);
				if(master_idx !== false)
				{
					options.at = master_idx;
				}
			}

			// if this model exists in the master already, we call our special
			// _do_add method, which manually adds, sorts, and limits for us.
			// otherwise, we just call master.add() and the model will be added
			// here via our wonderful events
			if(this.master.index_of(model))
			{
				this._do_add(model, options);
			}
			else
			{
				this.master.add(model, options);
				if(this.limit) this._models.splice(this.limit);
			}
			return model;
		},

		/**
		 * Manually add a model to this collection. Sorts and limits as well.
		 */
		_do_add: function(model, options)
		{
			// master already has item, so we don't need to add it to
			// master (it will just fire "upsert"). what we need is to
			// add the model to this collection's models, sorted, and
			// apply the limit.
			this._models.push(model);
			var old_idx = this._models.indexOf(model);
			this.sort({silent: true});
			var new_idx = this._models.indexOf(model);
			if(this.limit) this._models.splice(this.limit);
			// after sort/limit, model may not actually be in the FC, so
			// check before wildly firing add/sort events
			if(this.index_of(model) >= 0)
			{
				// model was actually added, fire "add" event
				this.fire_event('add', options, model, this, options);
				if(old_idx != new_idx)
				{
					// sort changed! fire appropriate event
					if(this.options.sort_event)
					{
						this.fire_event('sort', options);
					}
					else
					{
						this.fire_event('reset', options);
					}
				}
			}
		},

		/**
		 * extension of Colleciton.remove that removes the model from the
		 * collection but only if it exists
		 */
		remove: function(model, options)
		{
			if (Composer.array.is(model))
			{
				return Composer.object.each(model, function(m) { this.remove(m); }, this);
			}

			options || (options = {});
			if(typeof(options.transform) == 'undefined') options.transform = true;

			if(this._models.indexOf(model) < 0) return false;

			if(this.transform && options.transform)
			{
				model = this.transform.call(this, model, 'remove');
			}

			// remove the model
			Composer.array.erase(this._models, model);

			this.fire_event('remove', options, model);

			// remove the model from the collection
			this._remove_reference(model);
		},

		add_event: function(model, options)
		{
			if(!this.filter(model, this)) return false;
			this.refresh({silent: true});
			if(this.options.sort_event) this.fire_event('sort', options);
			this.fire_event('add', options, model, this, options);
		},

		remove_event: function(model, options)
		{
			if(this._models.indexOf(model) < 0) return false;
			this.refresh({silent: true});
			this.fire_event('remove', options, model);
		},

		forward_event: function(event, model, args)
		{
			// return if not forwarding events
			if(!this.options.forward_all_events) return false;

			// we're forwarding events, but we're not about to forward them for
			// a model that doesn't "fit in" around here
			if(model && model.__composer_type == 'model' && !this.filter(model, this))
			{
				return false;
			}
			this.trigger.apply(this, args);
		}
	});

	this.Composer.exp0rt({ FilterCollection: FilterCollection });
}).apply((typeof exports != 'undefined') ? exports : this);

<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var User = require("../models/user");
var Request = require("../models/request");
var Access = require("../config/access");
var fs = require('fs');
var helpers = require('./helpers');
var warnings = undefined;

router.index = function(req, res, next) {
	res.redirect('/login');
};

router.renderLogin = function(req, res) {
	res.render('login.jade', {
		title: 'Login',
		messages: req.flash('loginFlash'),
		links: [
			{ text: "Login", href: "/login", active: true },
			{ text: "Register", href: "/register" }
		],
		hideLogout: true
	});
}

router.renderRegister = function(req, res) {
    res.render('register.jade', {
    	title: 'Register',
    	messages: req.flash('registerFlash'),
		links: [
			{ text: "Login", href: "/login" },
			{ text: "Register", href: "/register", active: true }
		],
		hideLogout: true
	});
}

router.renderSubform = function(req, res) {
	var links = [
		{ text: "Dashboard", href: "/dashboard" },
		{ text: "Submit a Request", href: "/dashboard/submit", active: true }
	];
	if (req.user.access >= Access.SUPERVISOR)
		links.push({ text: "Users", href: "/users" });
    res.render('submission_form.jade', {
    	title: 'Submission Form',
    	links: links,
    	messages: req.flash('submissionFlash'),
    	shouldSelectRequestee: req.user.access >= Access.SUPERVISOR
    });
}

router.renderApproval = function(req, res) {
	if (!warnings)
		warnings = JSON.parse(fs.readFileSync("public/data/warnings.json", 'utf8'));
	// Merge warnings to requests
	for(var i = 0; i < req.request.legs.length; i++) {
		req.request.legs[i].warnings = warnings[req.request.legs[i].country_code];
	}
	if (req.request.is_pending == false) {
		var deniedFlash = {
			text: 'This request has been denied.',
			class: 'danger'
		};
		var approvedFlash = {
			text: 'This request has been approved.',
			class: 'success'
		};
		req.flash('approvalFlash', (req.request.is_approved ? approvedFlash : deniedFlash));
	}
	res.render('approval.jade', {
		title: 'Request Approval',
		links: [
			{ text: "Dashboard", href: "/dashboard" },
			{ text: "Submit a Request", href: "/dashboard/submit" }
		],
		messages: req.flash('approvalFlash'),
		request: req.request,
		next_request_id: req.next_request_id,
		prev_request_id: req.prev_request_id
	});
}

router.renderDashboard = function(req, res) {
	var links = [
		{ text: "Dashboard", href: "/dashboard", active: true },
		{ text: "Submit a Request", href: "/dashboard/submit" }
	];
	if (req.user.access >= Access.SUPERVISOR)
		links.push({ text: "Users", href: "/users" });
	res.render('dashboard.jade', {
		title: "Dashboard",
		links: links,
		messages: req.flash('dashboardFlash')
	});
}

router.renderUsers = function(req, res) {
	if (req.user.access >= Access.SUPERVISOR) {
		helpers.getUsers({
			maxAccess: req.user.access
		}, function(err, users) {
			if (err) console.error(err);

			// Split users based on their access level
			admins = [];
			supervisors = [];
			volunteers = [];
			for (var i = 0; i < users.length; i++) {
				var user = users[i];
				switch (user.access) {
					case Access.ADMIN:
						admins.push(user);
						break;
					case Access.SUPERVISOR:
						supervisors.push(user);
						break;
					case Access.VOLUNTEER:
						volunteers.push(user);
						break;
				}
			};

		    res.render('users.jade', {
		    	title: 'Users',
		    	links: [
					{ text: "Dashboard", href: "/dashboard" },
					{ text: "Submit a Request", href: "/dashboard/submit" },
					{ text: "Users", href: "/users", active: true }
		    	],
		    	messages: req.flash('usersFlash'),
		    	admins: admins,
		    	supervisors: supervisors,
		    	volunteers: volunteers
		    });
		});
	} else {
		res.redirect('/dashboard');
	}
}

module.exports = router;

<commit_msg>Fixed missing users link<commit_after>var express = require('express');
var router = express.Router();
var User = require("../models/user");
var Request = require("../models/request");
var Access = require("../config/access");
var fs = require('fs');
var helpers = require('./helpers');
var warnings = undefined;

router.index = function(req, res, next) {
	res.redirect('/login');
};

router.renderLogin = function(req, res) {
	res.render('login.jade', {
		title: 'Login',
		messages: req.flash('loginFlash'),
		links: [
			{ text: "Login", href: "/login", active: true },
			{ text: "Register", href: "/register" }
		],
		hideLogout: true
	});
}

router.renderRegister = function(req, res) {
    res.render('register.jade', {
    	title: 'Register',
    	messages: req.flash('registerFlash'),
		links: [
			{ text: "Login", href: "/login" },
			{ text: "Register", href: "/register", active: true }
		],
		hideLogout: true
	});
}

router.renderSubform = function(req, res) {
	var links = [
		{ text: "Dashboard", href: "/dashboard" },
		{ text: "Submit a Request", href: "/dashboard/submit", active: true }
	];
	if (req.user.access >= Access.SUPERVISOR)
		links.push({ text: "Users", href: "/users" });
    res.render('submission_form.jade', {
    	title: 'Submission Form',
    	links: links,
    	messages: req.flash('submissionFlash'),
    	shouldSelectRequestee: req.user.access >= Access.SUPERVISOR
    });
}

router.renderApproval = function(req, res) {
	if (!warnings)
		warnings = JSON.parse(fs.readFileSync("public/data/warnings.json", 'utf8'));
	// Merge warnings to requests
	for(var i = 0; i < req.request.legs.length; i++) {
		req.request.legs[i].warnings = warnings[req.request.legs[i].country_code];
	}
	if (req.request.is_pending == false) {
		var deniedFlash = {
			text: 'This request has been denied.',
			class: 'danger'
		};
		var approvedFlash = {
			text: 'This request has been approved.',
			class: 'success'
		};
		req.flash('approvalFlash', (req.request.is_approved ? approvedFlash : deniedFlash));
	}
	var links = [
		{ text: "Dashboard", href: "/dashboard" },
		{ text: "Submit a Request", href: "/dashboard/submit" }
	];
	if (req.user.access >= Access.SUPERVISOR)
		links.push({ text: "Users", href: "/users" });
	res.render('approval.jade', {
		title: 'Request Approval',
		links: links,
		messages: req.flash('approvalFlash'),
		request: req.request,
		next_request_id: req.next_request_id,
		prev_request_id: req.prev_request_id
	});
}

router.renderDashboard = function(req, res) {
	var links = [
		{ text: "Dashboard", href: "/dashboard", active: true },
		{ text: "Submit a Request", href: "/dashboard/submit" }
	];
	if (req.user.access >= Access.SUPERVISOR)
		links.push({ text: "Users", href: "/users" });
	res.render('dashboard.jade', {
		title: "Dashboard",
		links: links,
		messages: req.flash('dashboardFlash')
	});
}

router.renderUsers = function(req, res) {
	if (req.user.access >= Access.SUPERVISOR) {
		helpers.getUsers({
			maxAccess: req.user.access
		}, function(err, users) {
			if (err) console.error(err);

			// Split users based on their access level
			admins = [];
			supervisors = [];
			volunteers = [];
			for (var i = 0; i < users.length; i++) {
				var user = users[i];
				switch (user.access) {
					case Access.ADMIN:
						admins.push(user);
						break;
					case Access.SUPERVISOR:
						supervisors.push(user);
						break;
					case Access.VOLUNTEER:
						volunteers.push(user);
						break;
				}
			};

		    res.render('users.jade', {
		    	title: 'Users',
		    	links: [
					{ text: "Dashboard", href: "/dashboard" },
					{ text: "Submit a Request", href: "/dashboard/submit" },
					{ text: "Users", href: "/users", active: true }
		    	],
		    	messages: req.flash('usersFlash'),
		    	admins: admins,
		    	supervisors: supervisors,
		    	volunteers: volunteers
		    });
		});
	} else {
		res.redirect('/dashboard');
	}
}

module.exports = router;

<|endoftext|>


<commit_before>var _; // globals

describe("About Applying What We Have Learnt", function() {
  var products;

  beforeEach(function () {
    products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];
  });

  /*********************************************************************************/

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () {
    var i,j,hasMushrooms, productsICanEat = [];

    for (i = 0; i < products.length; i+=1) {
        if (products[i].containsNuts === false) {
            hasMushrooms = false;
            for (j = 0; j < products[i].ingredients.length; j+=1) {
               if (products[i].ingredients[j] === "mushrooms") {
                  hasMushrooms = true;
               }
            }
            if (!hasMushrooms) productsICanEat.push(products[i]);
        }
    }

    expect(productsICanEat.length).toBe(1);
  });

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {
    var productsICanEat = [];

    //using _.filter and _.all

    productsICanEat = _.filter(products, function(pizza){
      return _.all(pizza, function(){
        var noMushrooms = true;
        _.each(pizza.ingredients, function(item){
          if (item === "mushrooms"){
            noMushrooms = false;
          }
        })
        return noMushrooms && !pizza.containsNuts;
      })

    })
        //console.log(productsICanEat);

        /* solve using filter() & all() / any() */

    expect(productsICanEat.length).toBe(1);
  });

  /*********************************************************************************/

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () {
    var sum = 0;

    for(var i=1; i<1000; i+=1) {
      if (i % 3 === 0 || i % 5 === 0) {
        sum += i;
      }
    }

    expect(sum).toBe(233168);
  });

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () {
    var sum = 0;    /* try chaining range() and reduce() */
    function range(a, b){
      var arr = [];
      for(var i = a; i < b; i++){
        arr.push(i);
      }
      return arr;
    }

    expect(233168).toBe(range(1, 1000).reduce(function(a, c){
      if(c % 3 === 0 || c % 5 === 0){
        a = a + c;
      }
      return a;
    }, 0));
  });

  /*********************************************************************************/
   it("should count the ingredient occurrence (imperative)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    for (i = 0; i < products.length; i+=1) {
        for (j = 0; j < products[i].ingredients.length; j+=1) {
            ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
        }
    }

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  it("should count the ingredient occurrence (functional)", function () {
    var ingredientCount = {};

    Array.prototype.flatten = function flatten(){
      return _.reduce(this, function(a, c){
        return a.concat(c);
      }, [])
    }
// chaining map flatten & reduce
    products.map(function(pizza){
      return pizza.ingredients;
    }).flatten().reduce(function(a, c){
      if(a[c] === undefined){
        a[c] = 1;
      }
      else{
        a[c]++;
      }
      return a;
    }, ingredientCount);

    /* chain() together map(), flatten() and reduce() */

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  /*********************************************************************************/
  /* UNCOMMENT FOR EXTRA CREDIT */

  it("should find the largest prime factor of a composite number", function () {

    largestPrimeFactor = function(compositeNum){
      //finding the factors of composite number
      var factors = [];
      for(var i = 2; i < compositeNum; i++){
        if(compositeNum % i === 0){
          factors.push(i);
        }
      }
      //filtering the factors for prime number
      var prime = [];
      _.each(factors, function(val){
        var isPrime = true;
        for(var i = 2; i < val; i++){
          if(val % i === 0) {
            isPrime = false;
          }
        }
        if(isPrime){
          prime.push(val);
        }
      })
    // returning the largest prime factor
      return prime.pop();
    }
    expect(largestPrimeFactor(10001)).toBe(137);

  });

  it("should find the largest palindrome made from the product of two 3 digit numbers", function () {

  expect(palindrome).toBe();
  });

  it("should find the smallest number divisible by each of the numbers 1 to 20", function () {
    function smallestDivisibleByOneToTwenty(){
      var smallest;
      for(var i = 40; ; i+=10){
        for(var j = 20; j >= 2; j--){
          if(i % j !== 0){
            break;
          }
        }
        if (j < 2) {
          smallest = i;
          return smallest;
        }
      }
    };
  expect(smallestDivisibleByOneToTwenty()).toBe(232792560);

  });

  it("should find the difference between the sum of the squares and the square of the sums", function () {

  expect(difference).toBe();
  });

  it("should find the 10001st prime", function () {

  expect(10001).toBe();
  });

});
<commit_msg>diff between sum of sqrs and sqr of sums (extra credit)<commit_after>var _; // globals

describe("About Applying What We Have Learnt", function() {
  var products;

  beforeEach(function () {
    products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];
  });

  /*********************************************************************************/

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () {
    var i,j,hasMushrooms, productsICanEat = [];

    for (i = 0; i < products.length; i+=1) {
        if (products[i].containsNuts === false) {
            hasMushrooms = false;
            for (j = 0; j < products[i].ingredients.length; j+=1) {
               if (products[i].ingredients[j] === "mushrooms") {
                  hasMushrooms = true;
               }
            }
            if (!hasMushrooms) productsICanEat.push(products[i]);
        }
    }

    expect(productsICanEat.length).toBe(1);
  });

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {
    var productsICanEat = [];

    //using _.filter and _.all

    productsICanEat = _.filter(products, function(pizza){
      return _.all(pizza, function(){
        var noMushrooms = true;
        _.each(pizza.ingredients, function(item){
          if (item === "mushrooms"){
            noMushrooms = false;
          }
        })
        return noMushrooms && !pizza.containsNuts;
      })

    })
        //console.log(productsICanEat);

        /* solve using filter() & all() / any() */

    expect(productsICanEat.length).toBe(1);
  });

  /*********************************************************************************/

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () {
    var sum = 0;

    for(var i=1; i<1000; i+=1) {
      if (i % 3 === 0 || i % 5 === 0) {
        sum += i;
      }
    }

    expect(sum).toBe(233168);
  });

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () {
    var sum = 0;    /* try chaining range() and reduce() */
    function range(a, b){
      var arr = [];
      for(var i = a; i < b; i++){
        arr.push(i);
      }
      return arr;
    }

    expect(233168).toBe(range(1, 1000).reduce(function(a, c){
      if(c % 3 === 0 || c % 5 === 0){
        a = a + c;
      }
      return a;
    }, 0));
  });

  /*********************************************************************************/
   it("should count the ingredient occurrence (imperative)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    for (i = 0; i < products.length; i+=1) {
        for (j = 0; j < products[i].ingredients.length; j+=1) {
            ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
        }
    }

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  it("should count the ingredient occurrence (functional)", function () {
    var ingredientCount = {};

    Array.prototype.flatten = function flatten(){
      return _.reduce(this, function(a, c){
        return a.concat(c);
      }, [])
    }
// chaining map flatten & reduce
    products.map(function(pizza){
      return pizza.ingredients;
    }).flatten().reduce(function(a, c){
      if(a[c] === undefined){
        a[c] = 1;
      }
      else{
        a[c]++;
      }
      return a;
    }, ingredientCount);

    /* chain() together map(), flatten() and reduce() */

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  /*********************************************************************************/
  /* UNCOMMENT FOR EXTRA CREDIT */

  it("should find the largest prime factor of a composite number", function () {

    largestPrimeFactor = function(compositeNum){
      //finding the factors of composite number
      var factors = [];
      for(var i = 2; i < compositeNum; i++){
        if(compositeNum % i === 0){
          factors.push(i);
        }
      }
      //filtering the factors for prime number
      var prime = [];
      _.each(factors, function(val){
        var isPrime = true;
        for(var i = 2; i < val; i++){
          if(val % i === 0) {
            isPrime = false;
          }
        }
        if(isPrime){
          prime.push(val);
        }
      })
    // returning the largest prime factor
      return prime.pop();
    }
    expect(largestPrimeFactor(10001)).toBe(137);

  });

  it("should find the largest palindrome made from the product of two 3 digit numbers", function () {

  expect(palindrome).toBe();
  });

  it("should find the smallest number divisible by each of the numbers 1 to 20", function () {
    function smallestDivisibleByOneToTwenty(){
      var smallest;
      for(var i = 40; ; i+=10){
        for(var j = 20; j >= 2; j--){
          if(i % j !== 0){
            break;
          }
        }
        if (j < 2) {
          smallest = i;
          return smallest;
        }
      }
    };
  expect(smallestDivisibleByOneToTwenty()).toBe(232792560);

  });

  it("should find the difference between the sum of the squares and the square of the sums", function () {
    function difference(num1, num2){
    var rangeArr = [], sqrArr = [];
    var sumRange = 0, sumSqr = 0;
    var result;

    // creating an array for the range of numbers
    for(var i = num1; i <= num2; i++){
        rangeArr.push(i);
    }

    //creating another array with the square of each num in range array
    for(var i = 0; i < rangeArr.length; i++){
        sqrArr.push(rangeArr[i] * rangeArr[i]);
    }

    // summing all the numbers in range array
    _.each(rangeArr, function(val){
        sumRange += val;
    })

    //summing the squares of each number
    _.each(sqrArr, function(val){
        sumSqr += val;
    })

    result = (sumRange * sumRange) - sumSqr;
    return result;
}

  expect(difference(1, 10)).toBe(2640);
  });

  it("should find the 10001st prime", function () {

  expect(10001).toBe();
  });

});
<|endoftext|>


<commit_before>import { fix_ints } from '../db/neo4j'

const waves = (app, get_session) => {

  app.route('/waves')
    .get((req, res) => {
      const session = get_session()
      session
        .run('MATCH (wave:Wave) return wave')
        .then(result => {
          const waves = result.records.map(record => {
            const { properties } = record.get('wave')
            return fix_ints({
              ...properties
            })
          })

          session.close()
          res.send({waves})
        })
    })

  app.route('/waves/:id')
    .get((req, res) => {
      res.status(404).end()
    })

}

export default waves<commit_msg>Added waves/:id route. Returns wave & expansions data. Closes #6.<commit_after>import { fix_ints } from '../db/neo4j'

const waves = (app, get_session) => {

  app.route('/waves')
    .get((req, res) => {
      const session = get_session()
      session
        .run('MATCH (wave:Wave) return wave')
        .then(result => {
          const waves = result.records.map(record => {
            const { properties } = record.get('wave')
            return fix_ints({
              ...properties
            })
          })

          session.close()
          res.send({waves})
        })
    })

  app.route('/waves/:id')
    .get((req, res) => {
      const id = req.params.id
      const session = get_session()

      session
        .run(`
          MATCH (wave:Wave{id: $id})<-[released:Released]-(expansion:Expansion)
          RETURN wave, released, expansion`,
          {id}
        )
        .then(result => {
          if (result.records.length > 0) {
            const wave = result.records[0].get('wave').properties
            const expansions = result.records.map(record => {
              return fix_ints({
                ...record.get('expansion').properties,
                ...record.get('released').properties
              })
            })

            session.close()
            res.send(fix_ints({
              ...wave,
              expansions
            }))
          } else {
            session.close()
            res.status(404).end()
          }
        })
    })

}

export default waves<|endoftext|>


<commit_before>import Element from '../../Element';
import runloop from 'global/runloop';
import { toArray } from 'utils/array';

function valueContains ( selectValue, optionValue ) {
	let i = selectValue.length;
	while ( i-- ) {
		if ( selectValue[i] == optionValue ) return true;
	}
}

export default class Select extends Element {
	constructor ( options ) {
		super( options );
		this.options = [];
	}

	bubble () {
		if ( !this.dirty ) {
			this.dirty = true;

			runloop.scheduleTask( () => {
				this.sync();
				this.dirty = false;
			});
		}

		this.parentFragment.bubble(); // default behaviour
	}

	render ( target ) {
		super.render( target );
		this.sync();

		const node = this.node;

		let i = node.options.length;
		while ( i-- ) {
			node.options[i].defaultSelected = node.options[i].selected;
		}
	}

	sync () {
		const selectNode = this.node;

		if ( !selectNode ) return;

		const options = toArray( selectNode.options );

		const selectValue = this.getAttribute( 'value' );
		const isMultiple = this.getAttribute( 'multiple' );

		// If the <select> has a specified value, that should override
		// these options
		if ( selectValue !== undefined ) {
			let optionWasSelected;

			options.forEach( o => {
				const optionValue = o._ractive ? o._ractive.value : o.value;
				const shouldSelect = isMultiple ? valueContains( selectValue, optionValue ) : selectValue == optionValue;

				if ( shouldSelect ) {
					optionWasSelected = true;
				}

				o.selected = shouldSelect;
			});

			if ( !optionWasSelected && !isMultiple ) {
				if ( options[0] ) {
					options[0].selected = true;
				}

				if ( this.binding ) {
					this.binding.forceUpdate();
				}
			}
		}

		// Otherwise the value should be initialised according to which
		// <option> element is selected, if twoway binding is in effect
		else if ( this.binding ) {
			this.binding.forceUpdate();
		}
	}

	update () {
		super.update();
		this.sync();
	}
}
<commit_msg>dont sync select on initial render<commit_after>import Element from '../../Element';
import runloop from 'global/runloop';
import { toArray } from 'utils/array';

function valueContains ( selectValue, optionValue ) {
	let i = selectValue.length;
	while ( i-- ) {
		if ( selectValue[i] == optionValue ) return true;
	}
}

export default class Select extends Element {
	constructor ( options ) {
		super( options );
		this.options = [];
	}

	bubble () {
		if ( !this.dirty ) {
			this.dirty = true;

			if ( this.rendered ) {
				runloop.scheduleTask( () => {
					this.sync();
					this.dirty = false;
				});
			}

			this.parentFragment.bubble(); // default behaviour
		}
	}

	render ( target ) {
		super.render( target );
		this.sync();

		const node = this.node;

		let i = node.options.length;
		while ( i-- ) {
			node.options[i].defaultSelected = node.options[i].selected;
		}

		this.rendered = true;
	}

	sync () {
		const selectNode = this.node;

		if ( !selectNode ) return;

		const options = toArray( selectNode.options );

		const selectValue = this.getAttribute( 'value' );
		const isMultiple = this.getAttribute( 'multiple' );

		// If the <select> has a specified value, that should override
		// these options
		if ( selectValue !== undefined ) {
			let optionWasSelected;

			options.forEach( o => {
				const optionValue = o._ractive ? o._ractive.value : o.value;
				const shouldSelect = isMultiple ? valueContains( selectValue, optionValue ) : selectValue == optionValue;

				if ( shouldSelect ) {
					optionWasSelected = true;
				}

				o.selected = shouldSelect;
			});

			if ( !optionWasSelected && !isMultiple ) {
				if ( options[0] ) {
					options[0].selected = true;
				}

				if ( this.binding ) {
					this.binding.forceUpdate();
				}
			}
		}

		// Otherwise the value should be initialised according to which
		// <option> element is selected, if twoway binding is in effect
		else if ( this.binding ) {
			this.binding.forceUpdate();
		}
	}

	update () {
		super.update();
		this.sync();
	}
}
<|endoftext|>


<commit_before>const cheerio = require('cheerio');
const nunjucksIncludeData = require('nunjucks-includeData');
const marky = require('marky-markdown');
const nunjucksMarkdown = require('nunjucks-markdown');

const replaceEverythingBeforeH2Element = true;

const cleanSlug = slug => slug.replace('setup-instructions', 'setup');

module.exports = function (nunjucksEnv) {
  nunjucksIncludeData.install(nunjucksEnv);

  nunjucksMarkdown.register(nunjucksEnv, str => {
    let dirty = marky(str, {
      headingSvgClass: [],
      prefixHeadingIds: false,
      enableHeadingLinkIcons: false
    });

    // Remove everything before the first `<h2>` element.
    if (replaceEverythingBeforeH2Element) {
      dirty = dirty.substring(dirty.indexOf('
 {
      const $list = $(list);
      $list.addClass('bullets-light');
      $list.html($list.html().replace(/
/gi, '
').replace(/<\/li>/gi, '
'));
    });

    let html = '';
    let sections = [];

    $('h2 > a').each((idx, a) => {
      const $a = $(a);
      const id = cleanSlug($a.attr('id'));
      const href = cleanSlug($a.attr('href'));
      $a.attr('id', id);
      $a.attr('href', href);
      const $h2 = $a.parent();
      const headingText = $h2.text();
      $a.text(headingText);
      $h2.html($a);

      if (!html) {
        const bodyHtml = $('body').html();
        html = bodyHtml.substring(0, bodyHtml.indexOf('<h2'));
      }

      let sectionHtml = `<section data-section="${id}" id="${id}" class="section">\n`;
      sectionHtml += `${$.html($h2)}\n`;
      $h2.nextUntil('h2').each((idx, sibling) => {
        const $sibling = $(sibling);
        sectionHtml += $.html($sibling) + '\n';
        $sibling.remove();
      });
      sectionHtml += '
\n';

      sections.push(sectionHtml);
    });

    if (sections.length) {
      html += sections.join('\n\n');
    } else {
      html = $.html();
    }

    return html;
  });
};
<commit_msg>use inner HTML of `<body>` for Nunjucks+Markdown formatter<commit_after>const cheerio = require('cheerio');
const nunjucksIncludeData = require('nunjucks-includeData');
const marky = require('marky-markdown');
const nunjucksMarkdown = require('nunjucks-markdown');

const replaceEverythingBeforeH2Element = true;

const cleanSlug = slug => slug.replace('setup-instructions', 'setup');

module.exports = function (nunjucksEnv) {
  nunjucksIncludeData.install(nunjucksEnv);

  nunjucksMarkdown.register(nunjucksEnv, str => {
    let dirty = marky(str, {
      headingSvgClass: [],
      prefixHeadingIds: false,
      enableHeadingLinkIcons: false
    });

    // Remove everything before the first `<h2>` element.
    if (replaceEverythingBeforeH2Element) {
      dirty = dirty.substring(dirty.indexOf('
 {
      const $list = $(list);
      $list.addClass('bullets-light');
      $list.html($list.html().replace(/
/gi, '
').replace(/<\/li>/gi, '
'));
    });

    let html = '';
    let sections = [];

    $('h2 > a').each((idx, a) => {
      const $a = $(a);
      const id = cleanSlug($a.attr('id'));
      const href = cleanSlug($a.attr('href'));
      $a.attr('id', id);
      $a.attr('href', href);
      const $h2 = $a.parent();
      const headingText = $h2.text();
      $a.text(headingText);
      $h2.html($a);

      if (!html) {
        const bodyHtml = $('body').html();
        html = bodyHtml.substring(0, bodyHtml.indexOf('<h2'));
      }

      let sectionHtml = `<section data-section="${id}" id="${id}" class="section">\n`;
      sectionHtml += `${$.html($h2)}\n`;
      $h2.nextUntil('h2').each((idx, sibling) => {
        const $sibling = $(sibling);
        sectionHtml += $.html($sibling) + '\n';
        $sibling.remove();
      });
      sectionHtml += '
\n';

      sections.push(sectionHtml);
    });

    if (sections.length) {
      html += sections.join('\n\n');
    } else {
      html = $('body').html();
    }

    return html;
  });
};
<|endoftext|>


<commit_before>/*
Copyright 2014 Sebastian Zimmer

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

APP.forms = (function () {
	'use strict';

	//PRIVATE

	var checkForValueOrTakeDefault = function(data_object, field){
		var value;

		if (typeof data_object != "undefined"){
			value = data_object;
		}

		else if (field.default_value) {
			value = field.default_value;
		}

		else {

			if (field.type == "check"){
				value =  false;
			}

			else if (field.type == "date"){
				value = {
					year: "YYYY",
					month: "MM",
					day: "DD"
				};
			}

			else {
				value = "";
			}

		}

		return value;
	};

	var getValueFromDataObject = function(data_object, field){
		var value;

		if (field.name && field.name !== ""){  //sub object

			if (typeof data_object != "undefined" && data_object[field.name]){
				value = data_object[field.name];
			}

			else {
				value = undefined;
			}

		}

		else {

			if (data_object){
				value = data_object;
			}

			else {
				value = undefined;
			}

		}

		return value;

	};

	var makeFunctions = {
		text: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var input;

			input = dom.makeTextInput(parent, field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				(session_object && session_object[field.name] ? session_object[field.name] : ""),
				field.comment
			);

			return input;

		},

		date: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var input;

			input = dom.makeDateInput(parent, field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				(session_object && session_object[field.name] ? session_object[field.name].year : ""),
				(session_object && session_object[field.name] ? session_object[field.name].month : ""),
				(session_object && session_object[field.name] ? session_object[field.name].day : ""),
				field.comment
			);

			return input;

		},

		textarea: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var input;

			input = dom.makeTextarea(
				APP.CONF.form_textarea_rows,
				APP.CONF.form_textarea_columns,
				parent,
				field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				(session_object && session_object[field.name] ? session_object[field.name] : ""),
				field.comment
			);

			return input;

		},

		subarea: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var h3 = dom.h3(parent, field.heading);

			if (field.comment){
				h3.title = field.comment;
			}

			if (field.fields){

				element_id_prefix += field.name + "_";
				makeForEach(field.fields, parent, element_id_prefix, element_class_prefix, session_object[field.name]);

			}
		},

		column: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var td_name;

			if (field.name && field.name !== ""){

				td_name = field.name+"_td";

			}

			else {

				td_name = "td";

			}

			var td = dom.newElement("td",element_id_prefix+td_name,element_class_prefix+td_name,parent);

			if (field.title && field.title !== ""){
				dom.newElement("h2","","",td,field.title);
			}

			if (field.fields){

				if (field.name && field.name !== ""){

					element_id_prefix += field.name + "_";

				}

				makeForEach(field.fields, td, element_id_prefix, element_class_prefix, (session_object ? session_object[field.name] : undefined));

			}

		},

		form: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			if ((field.fields) && (field.fields[0].type == "column")){
				var table = dom.newElement("table",element_id_prefix+"table","session_table",parent);
				var tr = dom.newElement("tr","","",table);
				var form_parent = tr;
			}

			else {
				form_parent = parent;
			}

			makeForEach(field.fields, form_parent, element_id_prefix, element_class_prefix, session_object);

		},

		special: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			APP.environments.active_environment.specialInput(field, parent, element_id_prefix, element_class_prefix);

		},

		select: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var input;

			input = dom.makeSelect(
				parent, field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				field.size,
				field.vocabulary,
				(session_object && session_object[field.name] ? session_object[field.name] : field.default_value),
				field.comment
			);

			return input;

		},

		open_vocabulary: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var value;
			var input;

			if (session_object && session_object[field.name]){
				value = session_object[field.name];
			}

			else if (field.default_value){
				value = field.default_value;
			}

			input = dom.openVocabulary(
				parent, field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				field.size,
				field.vocabulary,
				value,
				field.comment
			);

			return input;

		},

		check:  function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var input;

			input = dom.makeCheckbox(
				parent, field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				(session_object && session_object[field.name] ? session_object[field.name] : false),
				field.comment
			);

			return input;
		},

	};

	var makeForEach = function (fields, parent, element_id_prefix, element_class_prefix, session_object){

		forEach(fields, function (subfield){

			make(parent, subfield, element_id_prefix, element_class_prefix, session_object);

		});

	};

	var make = function (parent, field, element_id_prefix, element_class_prefix, session_object){

		var input;

		if (makeFunctions[field.type]) {
			input = makeFunctions[field.type](parent, field, element_id_prefix, element_class_prefix, session_object);
		}

		else {
			console.log("ERROR: APP.forms.make: Field type not supported! Field type = " + field.type);
			return;
		}

		if (field.not_allowed_chars){

			input.onkeypress = function(e) {
				var chr = String.fromCharCode(e.which);

				if (field.not_allowed_chars.indexOf(chr) >= 0){
					APP.log("This character is not allowed here.","error");
					return false;
				}
			};

		}

	};

	var my = {};

	my.make = make;

	my.fill = function (field, element_id_prefix, data_object){

		var target;
		var f;

		if (field.type == "column"){

			if (field.name && field.name !== ""){
				element_id_prefix += field.name + "_";
			}

		}

		if (field.type == "form" || field.type == "subarea" || field.type == "column"){

			forEach(field.fields, function(field){

				target = getValueFromDataObject(data_object, field);

				my.fill(field, element_id_prefix, target);

			});

		}

		if (field.type == "text" || field.type == "textarea" || field.type == "select" || field.type == "open_vocabulary" || field.type == "check"){

			target = checkForValueOrTakeDefault(data_object, field);

			dom.setFormValue(element_id_prefix+field.name, target, field.vocabulary);

		}

		if (field.type == "date"){

			target = checkForValueOrTakeDefault(data_object, field);

			g(element_id_prefix+field.name+"_year").value = target.year;
			g(element_id_prefix+field.name+"_month").value = target.month;
			g(element_id_prefix+field.name+"_day").value = target.day;

		}

		if (field.type == "special"){
			//?????
			return;

		}

	};

	my.createEmptyObjectFromTemplate = function (field, resulting_object){

		var f;
		var sub_object;

		if (field.type == "form") {

			var object = {};

			forEach(field.fields, function(field){

				my.createEmptyObjectFromTemplate(field, object);

			});

			return object;

		}

		if (field.type == "column") {

			if (field.name && field.name !== ""){
				//create sub object
				sub_object = {};
				resulting_object[field.name] = sub_object;
			}

			else {  //if field has no name, do not create a sub object
				sub_object = resulting_object;
			}

			if (field.fields){

				forEach(field.fields, function(field){

					my.createEmptyObjectFromTemplate(field, sub_object);

				});

			}

		}

		if (field.type == "subarea") {
			var parent_field_name = field.name;

			//create sub object
			resulting_object[parent_field_name] = {};

			if (field.fields){

				forEach(field.fields, function(field){

					my.createEmptyObjectFromTemplate(field, resulting_object[parent_field_name]);

				});

			}

		}

		if (field.type == "date") {

			var date_object = {
				year: "",
				month: "",
				day: ""
			};

			resulting_object[field.name] = date_object;

			return;
		}

		if (field.type == "special") {
			if (field.object_structure == "array"){
				resulting_object[field.name] = [];
			}

			else if (field.object_structure == "object"){
				resulting_object[field.name] = {};

				if (field.object_arrays){

					forEach(field.object_arrays, function (object_array){
						resulting_object[field.name][object_array] = [];
					});

				}
			}

			else {
				resulting_object[field.name] = null;
			}

			return;
		}

		if (field.type == "select" || field.type == "open_vocabulary" || field.type == "textarea" || field.type == "text") {
			resulting_object[field.name] = "";
			return;
		}

		if (field.type == "check") {
			resulting_object[field.name] = false;
			return;
		}

	};

	my.makeObjectWithFormData = function(field, element_id_prefix){

		var object = my.createEmptyObjectFromTemplate(field);

		my.fillObjectWithFormData(object, element_id_prefix, field);

		return object;

	};

	my.fillObjectWithFormData = function (object, element_id_prefix, form_element){
	//object = the object to be filled with form data
	//form_element = element of the form as specified in session_form

		var f;
		var sub_object;

		if ((form_element.type == "text") || (form_element.type == "textarea") || (form_element.type == "select") || (form_element.type == "open_vocabulary")){

			object[form_element.name] = get(element_id_prefix+form_element.name);

		}

		if (form_element.type == "check"){

			object[form_element.name] = g(element_id_prefix+form_element.name).checked;

		}

		if (form_element.type == "date"){

			object[form_element.name].year = get(element_id_prefix+form_element.name+"_year");
			object[form_element.name].month = get(element_id_prefix+form_element.name+"_month");
			object[form_element.name].day = get(element_id_prefix+form_element.name+"_day");
		}

		if (form_element.type == "column"){

			if (form_element.name && form_element.name !== ""){
				element_id_prefix += form_element.name + "_";
			}

			for (f=0; f<form_element.fields.length; f++){

				my.fillObjectWithFormData(object, element_id_prefix, form_element.fields[f]);

			}
		}

		if (form_element.type == "subarea"){

			if (form_element.name && form_element.name !== ""){
				element_id_prefix += form_element.name + "_";
			}

			for (f=0; f<form_element.fields.length; f++){

				my.fillObjectWithFormData(object[form_element.name], element_id_prefix, form_element.fields[f]);

			}
		}

		if (form_element.type == "form"){

			for (f=0; f<form_element.fields.length; f++){
				var subfield = form_element.fields[f];

				//check if a sub object has to be created
				if (subfield.name && subfield.name !== "" && (subfield.type == "column" || subfield.type == "subarea")){
					sub_object = object[subfield.name];
				}

				else {
					sub_object = object;
				}

				my.fillObjectWithFormData(sub_object, element_id_prefix, subfield);

			}

		}

		if (form_element.type == "special"){
			// TO DO!!!
			//object[form_element.name] = APP.active_environment.getSpecialFormData(field, parent, element_id_prefix, element_class_prefix);
			return;
		}

	};

	return my;

})();<commit_msg>Smoothing APP.forms<commit_after>/*
Copyright 2014 Sebastian Zimmer

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

APP.forms = (function () {
	'use strict';

	//PRIVATE

	var checkForValueOrTakeDefault = function(data_object, field){
		var value;

		if (typeof data_object != "undefined"){
			value = data_object;
		}

		else if (field.default_value) {
			value = field.default_value;
		}

		else {

			if (field.type == "check"){
				value =  false;
			}

			else if (field.type == "date"){
				value = {
					year: "YYYY",
					month: "MM",
					day: "DD"
				};
			}

			else {
				value = "";
			}

		}

		return value;
	};

	var getValueFromDataObject = function(data_object, field){
		var value;

		if (field.name && field.name !== ""){  //sub object

			if (typeof data_object != "undefined" && data_object[field.name]){
				value = data_object[field.name];
			}

			else {
				value = undefined;
			}

		}

		else {

			if (data_object){
				value = data_object;
			}

			else {
				value = undefined;
			}

		}

		return value;

	};

	var makeFunctions = {
		text: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var input;

			input = dom.makeTextInput(parent, field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				(session_object && session_object[field.name] ? session_object[field.name] : ""),
				field.comment
			);

			return input;

		},

		date: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var input;

			input = dom.makeDateInput(parent, field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				(session_object && session_object[field.name] ? session_object[field.name].year : ""),
				(session_object && session_object[field.name] ? session_object[field.name].month : ""),
				(session_object && session_object[field.name] ? session_object[field.name].day : ""),
				field.comment
			);

			return input;

		},

		textarea: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var input;

			input = dom.makeTextarea(
				APP.CONF.form_textarea_rows,
				APP.CONF.form_textarea_columns,
				parent,
				field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				(session_object && session_object[field.name] ? session_object[field.name] : ""),
				field.comment
			);

			return input;

		},

		subarea: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var h3 = dom.h3(parent, field.heading);

			if (field.comment){
				h3.title = field.comment;
			}

			if (field.fields){

				element_id_prefix += field.name + "_";
				makeForEach(field.fields, parent, element_id_prefix, element_class_prefix, session_object[field.name]);

			}
		},

		column: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var td_name;

			if (field.name && field.name !== ""){

				td_name = field.name+"_td";

			}

			else {

				td_name = "td";

			}

			var td = dom.newElement("td",element_id_prefix+td_name,element_class_prefix+td_name,parent);

			if (field.title && field.title !== ""){
				dom.newElement("h2","","",td,field.title);
			}

			if (field.fields){

				if (field.name && field.name !== ""){

					element_id_prefix += field.name + "_";

				}

				makeForEach(field.fields, td, element_id_prefix, element_class_prefix, (session_object ? session_object[field.name] : undefined));

			}

		},

		form: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			if ((field.fields) && (field.fields[0].type == "column")){
				var table = dom.newElement("table",element_id_prefix+"table","session_table",parent);
				var tr = dom.newElement("tr","","",table);
				var form_parent = tr;
			}

			else {
				form_parent = parent;
			}

			makeForEach(field.fields, form_parent, element_id_prefix, element_class_prefix, session_object);

		},

		special: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			APP.environments.active_environment.specialInput(field, parent, element_id_prefix, element_class_prefix);

		},

		select: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var input;

			input = dom.makeSelect(
				parent, field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				field.size,
				field.vocabulary,
				(session_object && session_object[field.name] ? session_object[field.name] : field.default_value),
				field.comment
			);

			return input;

		},

		open_vocabulary: function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var value;
			var input;

			if (session_object && session_object[field.name]){
				value = session_object[field.name];
			}

			else if (field.default_value){
				value = field.default_value;
			}

			input = dom.openVocabulary(
				parent, field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				field.size,
				field.vocabulary,
				value,
				field.comment
			);

			return input;

		},

		check:  function(parent, field, element_id_prefix, element_class_prefix, session_object){

			var input;

			input = dom.makeCheckbox(
				parent, field.heading,
				element_id_prefix+field.name,
				element_id_prefix+field.name,
				(session_object && session_object[field.name] ? session_object[field.name] : false),
				field.comment
			);

			return input;
		},

	};

	var makeForEach = function (fields, parent, element_id_prefix, element_class_prefix, session_object){

		forEach(fields, function (subfield){

			make(parent, subfield, element_id_prefix, element_class_prefix, session_object);

		});

	};

	var make = function (parent, field, element_id_prefix, element_class_prefix, session_object){

		var input;

		if (makeFunctions[field.type]) {
			input = makeFunctions[field.type](parent, field, element_id_prefix, element_class_prefix, session_object);
		}

		else {
			console.log("ERROR: APP.forms.make: Field type not supported! Field type = " + field.type);
			return;
		}

		if (field.not_allowed_chars){

			input.onkeypress = function(e) {
				var chr = String.fromCharCode(e.which);

				if (field.not_allowed_chars.indexOf(chr) >= 0){
					APP.log("This character is not allowed here.","error");
					return false;
				}
			};

		}

	};

	var my = {};

	my.make = make;

	my.fill = function (field, element_id_prefix, data_object){

		var target;
		var f;

		if (field.type == "column"){

			if (field.name && field.name !== ""){
				element_id_prefix += field.name + "_";
			}

		}

		if (field.type == "form" || field.type == "subarea" || field.type == "column"){

			forEach(field.fields, function(field){

				target = getValueFromDataObject(data_object, field);

				my.fill(field, element_id_prefix, target);

			});

		}

		if (field.type == "text" || field.type == "textarea" || field.type == "select" || field.type == "open_vocabulary" || field.type == "check"){

			target = checkForValueOrTakeDefault(data_object, field);

			dom.setFormValue(element_id_prefix+field.name, target, field.vocabulary);

		}

		if (field.type == "date"){

			target = checkForValueOrTakeDefault(data_object, field);

			g(element_id_prefix+field.name+"_year").value = target.year;
			g(element_id_prefix+field.name+"_month").value = target.month;
			g(element_id_prefix+field.name+"_day").value = target.day;

		}

		if (field.type == "special"){
			//?????
			return;

		}

	};

	my.createEmptyObjectFromTemplate = function (field, resulting_object){
	//resulting object does not have to be specified, when calling this method, it is only neccessary because of
	//the recursive nature of this method

		var f;
		var sub_object;

		if (field.type == "form") {

			var object = {};

			forEach(field.fields, function(field){

				my.createEmptyObjectFromTemplate(field, object);

			});

			return object;

		}

		if (field.type == "column") {

			if (field.name && field.name !== ""){
				//create sub object
				sub_object = {};
				resulting_object[field.name] = sub_object;
			}

			else {  //if field has no name, do not create a sub object
				sub_object = resulting_object;
			}

			if (field.fields){

				forEach(field.fields, function(field){

					my.createEmptyObjectFromTemplate(field, sub_object);

				});

			}

		}

		if (field.type == "subarea") {
			var parent_field_name = field.name;

			//create sub object
			resulting_object[parent_field_name] = {};

			if (field.fields){

				forEach(field.fields, function(field){

					my.createEmptyObjectFromTemplate(field, resulting_object[parent_field_name]);

				});

			}

		}

		if (field.type == "date") {

			var date_object = {
				year: "",
				month: "",
				day: ""
			};

			resulting_object[field.name] = date_object;

			return;
		}

		if (field.type == "special") {
			if (field.object_structure == "array"){
				resulting_object[field.name] = [];
			}

			else if (field.object_structure == "object"){
				resulting_object[field.name] = {};

				if (field.object_arrays){

					forEach(field.object_arrays, function (object_array){
						resulting_object[field.name][object_array] = [];
					});

				}
			}

			else {
				resulting_object[field.name] = null;
			}

			return;
		}

		if (field.type == "select" || field.type == "open_vocabulary" || field.type == "textarea" || field.type == "text") {
			resulting_object[field.name] = "";
			return;
		}

		if (field.type == "check") {
			resulting_object[field.name] = false;
			return;
		}

	};

	my.makeObjectWithFormData = function(field, element_id_prefix){

		var object = my.createEmptyObjectFromTemplate(field);

		my.fillObjectWithFormData(object, element_id_prefix, field);

		return object;

	};

	var fillObjectForEach = function(fields, object, element_id_prefix){

		forEach(fields, function(field){

			fillObjectWithFormData(object, element_id_prefix, field);

		});

	};

	var fillObjectWithFormData = function (object, element_id_prefix, field){
	//object = the object to be filled with form data
	//field = form template object

		var f;
		var sub_object;

		if ((field.type == "text") || (field.type == "textarea") || (field.type == "select") || (field.type == "open_vocabulary")){

			object[field.name] = get(element_id_prefix+field.name);

		}

		if (field.type == "check"){

			object[field.name] = g(element_id_prefix+field.name).checked;

		}

		if (field.type == "date"){

			object[field.name].year = get(element_id_prefix+field.name+"_year");
			object[field.name].month = get(element_id_prefix+field.name+"_month");
			object[field.name].day = get(element_id_prefix+field.name+"_day");
		}

		if (field.type == "column"){

			if (field.name && field.name !== ""){
				element_id_prefix += field.name + "_";
			}

			fillObjectForEach(field.fields, object, element_id_prefix);

		}

		if (field.type == "subarea"){

			if (field.name && field.name !== ""){
				element_id_prefix += field.name + "_";
			}

			fillObjectForEach(field.fields, object[field.name], element_id_prefix);

		}

		if (field.type == "form"){

			forEach(field.fields, function(field){

				//check if a sub object has to be created
				if (field.name && field.name !== "" && (field.type == "column" || field.type == "subarea")){
					sub_object = object[field.name];
				}

				else {
					sub_object = object;
				}

				my.fillObjectWithFormData(sub_object, element_id_prefix, field);

			});

		}

		if (field.type == "special"){
			// TO DO!!!
			//object[field.name] = APP.active_environment.getSpecialFormData(field, parent, element_id_prefix, element_class_prefix);
			return;
		}

	};

	my.fillObjectWithFormData = fillObjectWithFormData;

	return my;

})();<|endoftext|>