<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';

import {
	addComponent,
	removeComponent,
	watchComponent,
	updateQuery,
	setQueryOptions,
} from '@appbaseio/reactivecore/lib/actions';
import {
	getQueryOptions,
	pushToAndClause,
	checkValueChange,
	getAggsOrder,
	checkPropChange,
	checkSomePropChange,
	getClassName,
} from '@appbaseio/reactivecore/lib/utils/helper';

import types from '@appbaseio/reactivecore/lib/utils/types';

import Title from '../../styles/Title';
import Input from '../../styles/Input';
import { UL, Radio } from '../../styles/FormControlList';

class SingleList extends Component {
	constructor(props) {
		super(props);

		this.state = {
			currentValue: '',
			options: [],
			searchTerm: '',
		};
		this.type = 'term';
		this.locked = false;
		this.internalComponent = `${props.componentId}__internal`;
	}

	componentWillMount() {
		this.props.addComponent(this.internalComponent);
		this.props.addComponent(this.props.componentId);
		this.updateQueryOptions(this.props);

		this.setReact(this.props);

		if (this.props.selectedValue) {
			this.setValue(this.props.selectedValue);
		} else if (this.props.defaultSelected) {
			this.setValue(this.props.defaultSelected);
		}
	}

	componentWillReceiveProps(nextProps) {
		checkPropChange(
			this.props.react,
			nextProps.react,
			() => this.setReact(nextProps),
		);
		checkPropChange(
			this.props.options,
			nextProps.options,
			() => {
				this.setState({
					options: nextProps.options[nextProps.dataField]
						? nextProps.options[nextProps.dataField].buckets
						: [],
				});
			},
		);
		checkSomePropChange(
			this.props,
			nextProps,
			['size', 'sortBy'],
			() => this.updateQueryOptions(nextProps),
		);

		checkPropChange(
			this.props.dataField,
			nextProps.dataField,
			() => {
				this.updateQueryOptions(nextProps);
				this.updateQuery(this.state.currentValue, nextProps);
			},
		);

		if (this.props.defaultSelected !== nextProps.defaultSelected) {
			this.setValue(nextProps.defaultSelected);
		} else if (this.state.currentValue !== nextProps.selectedValue) {
			this.setValue(nextProps.selectedValue || '');
		}
	}

	componentWillUnmount() {
		this.props.removeComponent(this.props.componentId);
		this.props.removeComponent(this.internalComponent);
	}

	setReact = (props) => {
		const { react } = props;
		if (react) {
			const newReact = pushToAndClause(react, this.internalComponent);
			props.watchComponent(props.componentId, newReact);
		} else {
			props.watchComponent(props.componentId, { and: this.internalComponent });
		}
	};

	defaultQuery = (value, props) => {
		if (this.props.selectAllLabel && this.props.selectAllLabel === value) {
			return {
				exists: {
					field: props.dataField,
				},
			};
		} else if (value) {
			return {
				[this.type]: {
					[props.dataField]: value,
				},
			};
		}
		return null;
	};

	setValue = (nextValue, props = this.props) => {
		// ignore state updates when component is locked
		if (props.beforeValueChange && this.locked) {
			return;
		}

		this.locked = true;
		let value = nextValue;
		if (nextValue === this.state.currentValue) {
			value = '';
		}

		const performUpdate = () => {
			this.setState({
				currentValue: value,
			}, () => {
				this.updateQuery(value, props);
				this.locked = false;
			});
		};

		checkValueChange(
			props.componentId,
			value,
			props.beforeValueChange,
			props.onValueChange,
			performUpdate,
		);
	};

	updateQuery = (value, props) => {
		const query = props.customQuery || this.defaultQuery;
		let onQueryChange = null;
		if (props.onQueryChange) {
			onQueryChange = props.onQueryChange;
		}
		props.updateQuery({
			componentId: props.componentId,
			query: query(value, props),
			value,
			label: props.filterLabel,
			showFilter: props.showFilter,
			onQueryChange,
			URLParams: props.URLParams,
		});
	};

	updateQueryOptions = (props) => {
		const queryOptions = getQueryOptions(props);
		queryOptions.aggs = {
			[props.dataField]: {
				terms: {
					field: props.dataField,
					size: props.size,
					order: getAggsOrder(props.sortBy),
				},
			},
		};
		props.setQueryOptions(this.internalComponent, queryOptions);
	};

	handleInputChange = (e) => {
		const { value } = e.target;
		this.setState({
			searchTerm: value,
		});
	};

	renderSearch = () => {
		if (this.props.showSearch) {
			return (<Input
				className={getClassName(this.props.innerClass, 'input') || null}
				onChange={this.handleInputChange}
				value={this.state.searchTerm}
				placeholder={this.props.placeholder}
				style={{
					margin: '0 0 8px',
				}}
			/>);
		}
		return null;
	};

	handleClick = (e) => {
		this.setValue(e.target.value);
	};

	render() {
		const { selectAllLabel } = this.props;

		if (this.state.options.length === 0) {
			return null;
		}

		return (

				{this.props.title && <Title className={getClassName(this.props.innerClass, 'title') || null}>{this.props.title}</Title>}
				{this.renderSearch()}

					{
						selectAllLabel
							? (
								<li key={selectAllLabel} className={`${this.state.currentValue === selectAllLabel ? 'active' : ''}`}>
									<Radio
										className={getClassName(this.props.innerClass, 'radio')}
										id={selectAllLabel}
										name={this.props.componentId}
										value={selectAllLabel}
										onClick={this.handleClick}
										readOnly
										checked={this.state.currentValue === selectAllLabel}
										show={this.props.showRadio}
									/>

										{selectAllLabel}

							)
							: null
					}
					{
						this.state.options
							.filter((item) => {
								if (String(item.key).length) {
									if (this.props.showSearch && this.state.searchTerm) {
										return String(item.key).toLowerCase()
											.includes(this.state.searchTerm.toLowerCase());
									}
									return true;
								}
								return false;
							})
							.map(item => (
								<li key={item.key} className={`${this.state.currentValue === String(item.key) ? 'active' : ''}`}>
									<Radio
										className={getClassName(this.props.innerClass, 'radio')}
										id={item.key}
										name={this.props.componentId}
										value={item.key}
										readOnly
										onClick={this.handleClick}
										checked={this.state.currentValue === String(item.key)}
										show={this.props.showRadio}
									/>

										{item.key}
										{
											this.props.showCount
											&& ` (${item.doc_count})`
										}

							))
					}

		);
	}
}

SingleList.propTypes = {
	componentId: types.stringRequired,
	addComponent: types.funcRequired,
	dataField: types.stringRequired,
	sortBy: types.sortByWithCount,
	setQueryOptions: types.funcRequired,
	updateQuery: types.funcRequired,
	defaultSelected: types.string,
	react: types.react,
	options: types.options,
	removeComponent: types.funcRequired,
	beforeValueChange: types.func,
	onValueChange: types.func,
	customQuery: types.func,
	onQueryChange: types.func,
	placeholder: types.string,
	title: types.title,
	showRadio: types.boolRequired,
	filterLabel: types.string,
	selectedValue: types.selectedValue,
	URLParams: types.boolRequired,
	showFilter: types.bool,
	size: types.number,
	showCount: types.bool,
	showSearch: types.bool,
	selectAllLabel: types.string,
	style: types.style,
	className: types.string,
	innerClass: types.style,
};

SingleList.defaultProps = {
	size: 100,
	sortBy: 'count',
	showRadio: true,
	URLParams: false,
	showCount: true,
	showFilter: true,
	placeholder: 'Search',
	showSearch: true,
	style: {},
	className: null,
};

const mapStateToProps = (state, props) => ({
	options: state.aggregations[props.componentId],
	selectedValue: (state.selectedValues[props.componentId]
		&& state.selectedValues[props.componentId].value) || '',
});

const mapDispatchtoProps = dispatch => ({
	addComponent: component => dispatch(addComponent(component)),
	removeComponent: component => dispatch(removeComponent(component)),
	watchComponent: (component, react) => dispatch(watchComponent(component, react)),
	updateQuery: updateQueryObject => dispatch(updateQuery(updateQueryObject)),
	setQueryOptions: (component, props) => dispatch(setQueryOptions(component, props)),
});

export default connect(mapStateToProps, mapDispatchtoProps)(SingleList);
<commit_msg>web: SingleList - onQueryChange prop destructing<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';

import {
	addComponent,
	removeComponent,
	watchComponent,
	updateQuery,
	setQueryOptions,
} from '@appbaseio/reactivecore/lib/actions';
import {
	getQueryOptions,
	pushToAndClause,
	checkValueChange,
	getAggsOrder,
	checkPropChange,
	checkSomePropChange,
	getClassName,
} from '@appbaseio/reactivecore/lib/utils/helper';

import types from '@appbaseio/reactivecore/lib/utils/types';

import Title from '../../styles/Title';
import Input from '../../styles/Input';
import { UL, Radio } from '../../styles/FormControlList';

class SingleList extends Component {
	constructor(props) {
		super(props);

		this.state = {
			currentValue: '',
			options: [],
			searchTerm: '',
		};
		this.type = 'term';
		this.locked = false;
		this.internalComponent = `${props.componentId}__internal`;
	}

	componentWillMount() {
		this.props.addComponent(this.internalComponent);
		this.props.addComponent(this.props.componentId);
		this.updateQueryOptions(this.props);

		this.setReact(this.props);

		if (this.props.selectedValue) {
			this.setValue(this.props.selectedValue);
		} else if (this.props.defaultSelected) {
			this.setValue(this.props.defaultSelected);
		}
	}

	componentWillReceiveProps(nextProps) {
		checkPropChange(
			this.props.react,
			nextProps.react,
			() => this.setReact(nextProps),
		);
		checkPropChange(
			this.props.options,
			nextProps.options,
			() => {
				this.setState({
					options: nextProps.options[nextProps.dataField]
						? nextProps.options[nextProps.dataField].buckets
						: [],
				});
			},
		);
		checkSomePropChange(
			this.props,
			nextProps,
			['size', 'sortBy'],
			() => this.updateQueryOptions(nextProps),
		);

		checkPropChange(
			this.props.dataField,
			nextProps.dataField,
			() => {
				this.updateQueryOptions(nextProps);
				this.updateQuery(this.state.currentValue, nextProps);
			},
		);

		if (this.props.defaultSelected !== nextProps.defaultSelected) {
			this.setValue(nextProps.defaultSelected);
		} else if (this.state.currentValue !== nextProps.selectedValue) {
			this.setValue(nextProps.selectedValue || '');
		}
	}

	componentWillUnmount() {
		this.props.removeComponent(this.props.componentId);
		this.props.removeComponent(this.internalComponent);
	}

	setReact = (props) => {
		const { react } = props;
		if (react) {
			const newReact = pushToAndClause(react, this.internalComponent);
			props.watchComponent(props.componentId, newReact);
		} else {
			props.watchComponent(props.componentId, { and: this.internalComponent });
		}
	};

	defaultQuery = (value, props) => {
		if (this.props.selectAllLabel && this.props.selectAllLabel === value) {
			return {
				exists: {
					field: props.dataField,
				},
			};
		} else if (value) {
			return {
				[this.type]: {
					[props.dataField]: value,
				},
			};
		}
		return null;
	};

	setValue = (nextValue, props = this.props) => {
		// ignore state updates when component is locked
		if (props.beforeValueChange && this.locked) {
			return;
		}

		this.locked = true;
		let value = nextValue;
		if (nextValue === this.state.currentValue) {
			value = '';
		}

		const performUpdate = () => {
			this.setState({
				currentValue: value,
			}, () => {
				this.updateQuery(value, props);
				this.locked = false;
			});
		};

		checkValueChange(
			props.componentId,
			value,
			props.beforeValueChange,
			props.onValueChange,
			performUpdate,
		);
	};

	updateQuery = (value, props) => {
		const query = props.customQuery || this.defaultQuery;

		const { onQueryChange = null } = props;

		props.updateQuery({
			componentId: props.componentId,
			query: query(value, props),
			value,
			label: props.filterLabel,
			showFilter: props.showFilter,
			onQueryChange,
			URLParams: props.URLParams,
		});
	};

	updateQueryOptions = (props) => {
		const queryOptions = getQueryOptions(props);
		queryOptions.aggs = {
			[props.dataField]: {
				terms: {
					field: props.dataField,
					size: props.size,
					order: getAggsOrder(props.sortBy),
				},
			},
		};
		props.setQueryOptions(this.internalComponent, queryOptions);
	};

	handleInputChange = (e) => {
		const { value } = e.target;
		this.setState({
			searchTerm: value,
		});
	};

	renderSearch = () => {
		if (this.props.showSearch) {
			return (<Input
				className={getClassName(this.props.innerClass, 'input') || null}
				onChange={this.handleInputChange}
				value={this.state.searchTerm}
				placeholder={this.props.placeholder}
				style={{
					margin: '0 0 8px',
				}}
			/>);
		}
		return null;
	};

	handleClick = (e) => {
		this.setValue(e.target.value);
	};

	render() {
		const { selectAllLabel } = this.props;

		if (this.state.options.length === 0) {
			return null;
		}

		return (

				{this.props.title && <Title className={getClassName(this.props.innerClass, 'title') || null}>{this.props.title}</Title>}
				{this.renderSearch()}

					{
						selectAllLabel
							? (
								<li key={selectAllLabel} className={`${this.state.currentValue === selectAllLabel ? 'active' : ''}`}>
									<Radio
										className={getClassName(this.props.innerClass, 'radio')}
										id={selectAllLabel}
										name={this.props.componentId}
										value={selectAllLabel}
										onClick={this.handleClick}
										readOnly
										checked={this.state.currentValue === selectAllLabel}
										show={this.props.showRadio}
									/>

										{selectAllLabel}

							)
							: null
					}
					{
						this.state.options
							.filter((item) => {
								if (String(item.key).length) {
									if (this.props.showSearch && this.state.searchTerm) {
										return String(item.key).toLowerCase()
											.includes(this.state.searchTerm.toLowerCase());
									}
									return true;
								}
								return false;
							})
							.map(item => (
								<li key={item.key} className={`${this.state.currentValue === String(item.key) ? 'active' : ''}`}>
									<Radio
										className={getClassName(this.props.innerClass, 'radio')}
										id={item.key}
										name={this.props.componentId}
										value={item.key}
										readOnly
										onClick={this.handleClick}
										checked={this.state.currentValue === String(item.key)}
										show={this.props.showRadio}
									/>

										{item.key}
										{
											this.props.showCount
											&& ` (${item.doc_count})`
										}

							))
					}

		);
	}
}

SingleList.propTypes = {
	componentId: types.stringRequired,
	addComponent: types.funcRequired,
	dataField: types.stringRequired,
	sortBy: types.sortByWithCount,
	setQueryOptions: types.funcRequired,
	updateQuery: types.funcRequired,
	defaultSelected: types.string,
	react: types.react,
	options: types.options,
	removeComponent: types.funcRequired,
	beforeValueChange: types.func,
	onValueChange: types.func,
	customQuery: types.func,
	onQueryChange: types.func,
	placeholder: types.string,
	title: types.title,
	showRadio: types.boolRequired,
	filterLabel: types.string,
	selectedValue: types.selectedValue,
	URLParams: types.boolRequired,
	showFilter: types.bool,
	size: types.number,
	showCount: types.bool,
	showSearch: types.bool,
	selectAllLabel: types.string,
	style: types.style,
	className: types.string,
	innerClass: types.style,
};

SingleList.defaultProps = {
	size: 100,
	sortBy: 'count',
	showRadio: true,
	URLParams: false,
	showCount: true,
	showFilter: true,
	placeholder: 'Search',
	showSearch: true,
	style: {},
	className: null,
};

const mapStateToProps = (state, props) => ({
	options: state.aggregations[props.componentId],
	selectedValue: (state.selectedValues[props.componentId]
		&& state.selectedValues[props.componentId].value) || '',
});

const mapDispatchtoProps = dispatch => ({
	addComponent: component => dispatch(addComponent(component)),
	removeComponent: component => dispatch(removeComponent(component)),
	watchComponent: (component, react) => dispatch(watchComponent(component, react)),
	updateQuery: updateQueryObject => dispatch(updateQuery(updateQueryObject)),
	setQueryOptions: (component, props) => dispatch(setQueryOptions(component, props)),
});

export default connect(mapStateToProps, mapDispatchtoProps)(SingleList);
<|endoftext|>


<commit_before>angular.module('experience', []).controller('ExperienceController', function($scope, $http) {
	$scope.companyname='';
	$scope.companies = [];
	$scope.history = [];

	function loadLookupData(resourceName)
	{
		var responsePromise = $http.get('/api/lookup/' + resourceName);

        responsePromise.success(function(data, status, headers, config) {
        	$scope.lookups[resourceName] = data._embedded[resourceName];

        	alert(JSON.stringify($scope.lookups[resourceName][0]));
        });

        responsePromise.error(function(data, status, headers, config) {
            alert("Loading lookup data for " + resourceName + " failed.");
        });
	}

	loadLookupData('jobstatus');
	loadLookupData('committeerole');
	loadLookupData('jobarea');

	$scope.$watch(function() {return element.attr('class'); }, function(newValue){ alert(newValue);});

	$scope.autocomplete = function() {

		var responsePromise = $http.get('/ajax/company/search?format=autocomplete&limit=200&name=' + this.companyname);
		var companies = $scope.companies;

        responsePromise.success(function(data, status, headers, config) {
        	companies.length = 0;
        	for (i=0; i<data.length; i++) {
        		var companyDetails = data[i].source;
        		companyDetails['arrayindex'] = i;
        		companies.push(companyDetails);
        	}
        });

        responsePromise.error(function(data, status, headers, config) {
            alert("Autocomplete AJAX failed!");
        });
	};

	function loadHistory() {
		var historyPromise = $http.get('/ajax/experience/history');

		historyPromise.success(function(data, status, headers, config) {
			$scope.history = [];
			for (var i=0; i<data.length; i++) {
				$scope.history[i] = {
					'companyid': data[i].companydirectoryid,
					'name': data[i].name
				};
			}
		});

		historyPromise.error(function(data, status, headers, config) {
			alert("Load history AJAX failed!");
		});
	}

	function updateHistory() {

		var historyPromise = $http.post('/ajax/experience/history', $scope.history);

		historyPromise.success(function(data, status, headers, config) {
		});

		historyPromise.error(function(data, status, headers, config) {
			alert("History AJAX failed!");
		});
	}

	$scope.select = function(arrayindex) {

		$scope.history.push($scope.companies[arrayindex]);

		var elementId = '#companyid-' + $scope.companies[arrayindex].companyid;

		setTimeout(function () {
			$(elementId).css('display', 'none');
			$(elementId).fadeIn(1200, function () {});
			setupDatepickers();
		}, 0);

		$scope.companies = [];

		updateHistory();
	}

	$scope.remove = function(companyId) {

		if (confirm('Do you wish to remove this company from your history?')) {
			var elementId = '#companyid-' + companyId;

			$(elementId).fadeOut('slow', function () {
				var foundIndex = -1;

				for (var i=0; i<$scope.history.length; i++) {
					if ($scope.history[i].companyid == companyId) {
						foundIndex = i;
						break;
					}
				}

				if (foundIndex != -1) {
					$scope.history.splice(foundIndex, 1);
				}

				setTimeout(function () {
					updateHistory();
				});
			});

		}
	}

	function setupDatefields()
	{
		alert(1);
		$('.date-entry').datepicker( {
			changeYear: true, yearRange: "1920:2020",
			dateFormat: "yy-mm-dd",
			inline: true,
			defaultDate: 0,
	        showOtherMonths: true,
	        dayNamesMin: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']}
		);
	}

	loadHistory();

});<commit_msg>Fix Javascript<commit_after>angular.module('experience', []).controller('ExperienceController', function($scope, $http) {
	$scope.companyname='';
	$scope.companies = [];
	$scope.history = [];

	function loadLookupData(resourceName)
	{
		var responsePromise = $http.get('/api/lookup/' + resourceName);

        responsePromise.success(function(data, status, headers, config) {
        	$scope.lookups[resourceName] = data._embedded[resourceName];
        });

        responsePromise.error(function(data, status, headers, config) {
            alert("Loading lookup data for " + resourceName + " failed.");
        });
	}

	$scope.lookups = [];

	$scope.lookups.jobstatus = [];
	loadLookupData('jobstatus');

	$scope.lookups.committeerole = [];
	loadLookupData('committeerole');

	$scope.lookups.jobarea = [];
	loadLookupData('jobarea');

	$scope.$watch(function() {return element.attr('class'); }, function(newValue){ alert(newValue);});

	$scope.autocomplete = function() {

		var responsePromise = $http.get('/ajax/company/search?format=autocomplete&limit=200&name=' + this.companyname);
		var companies = $scope.companies;

        responsePromise.success(function(data, status, headers, config) {
        	companies.length = 0;
        	for (i=0; i<data.length; i++) {
        		var companyDetails = data[i].source;
        		companyDetails['arrayindex'] = i;
        		companies.push(companyDetails);
        	}
        });

        responsePromise.error(function(data, status, headers, config) {
            alert("Autocomplete AJAX failed!");
        });
	};

	function loadHistory() {
		var historyPromise = $http.get('/ajax/experience/history');

		historyPromise.success(function(data, status, headers, config) {
			$scope.history = [];
			for (var i=0; i<data.length; i++) {
				$scope.history[i] = {
					'companyid': data[i].companydirectoryid,
					'name': data[i].name
				};
			}
		});

		historyPromise.error(function(data, status, headers, config) {
			alert("Load history AJAX failed!");
		});
	}

	function updateHistory() {

		var historyPromise = $http.post('/ajax/experience/history', $scope.history);

		historyPromise.success(function(data, status, headers, config) {
		});

		historyPromise.error(function(data, status, headers, config) {
			alert("History AJAX failed!");
		});
	}

	$scope.select = function(arrayindex) {

		$scope.history.push($scope.companies[arrayindex]);

		var elementId = '#companyid-' + $scope.companies[arrayindex].companyid;

		setTimeout(function () {
			$(elementId).css('display', 'none');
			$(elementId).fadeIn(1200, function () {});
			setupDatepickers();
		}, 0);

		$scope.companies = [];

		updateHistory();
	}

	$scope.remove = function(companyId) {

		if (confirm('Do you wish to remove this company from your history?')) {
			var elementId = '#companyid-' + companyId;

			$(elementId).fadeOut('slow', function () {
				var foundIndex = -1;

				for (var i=0; i<$scope.history.length; i++) {
					if ($scope.history[i].companyid == companyId) {
						foundIndex = i;
						break;
					}
				}

				if (foundIndex != -1) {
					$scope.history.splice(foundIndex, 1);
				}

				setTimeout(function () {
					updateHistory();
				});
			});

		}
	}

	function setupDatefields()
	{
		alert(1);
		$('.date-entry').datepicker( {
			changeYear: true, yearRange: "1920:2020",
			dateFormat: "yy-mm-dd",
			inline: true,
			defaultDate: 0,
	        showOtherMonths: true,
	        dayNamesMin: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']}
		);
	}

	loadHistory();

});<|endoftext|>


<commit_before>sage.directive('observation', function($http, appConstants) {
  return {
    restrict: "A",
    templateUrl: appConstants.rootUrl + "/js/app/partials/observation-template.html",
    scope: {
      layers: "=layers",
      observationId: "=observationid",
      marker: "=marker",
      newLayer: "=newlayer",
      currentLayerId: "=currentlayerid",
      newFeature: "=newfeature"
    },
    controller: derp = function ($scope, $element, $attrs, $http, teams, levels, observationTypes, appConstants) {
      /* Observation parameters. These are what get sent back to the server when a new observation is created. */
      $scope.teams = teams;
      $scope.levels = levels;
      $scope.observationTypes = observationTypes;

      $scope.observation = {}; // need to clean all of this up and figure out how to make it generic
      $scope.team = teams[0];
      $scope.level = levels[0];
      $scope.observationType = observationTypes[0];
      $scope.unit = "";
      $scope.description = "";
      $scope.files = []; // pre upload
      $scope.attachments = []; // images loaded from the server
      $scope.progressVisible = false;
      $scope.progressVisible = 0;

      // this is a hack, need to start using the ui-bootstrap, couldnt get the yo-dawged directive's scopes to play nice
      $scope.selectedTab = 1;

      /*
        If the ID changes and is -1, then it is a new observation, pop open the form and let the user create a new observation.
        If it is not -1, or 0, then lookup the rest of the attributes and populate the form.
      */
      $scope.$watch("observationId", function (newValue, oldValue) {
        console.log("id changed!!!!");
        var observation = $scope.observationId;
        if (!observation) return;

        var observationId = $scope.observationId.feature.properties.OBJECTID;

        if (observationId == 0) {          // hide the observation dialog
          $('#observation-panel').addCl***REMOVED***('hide');
          console.log ('id = 0');
        } else if(observationId == -1) { // creating a new observation
          $scope.team = teams[0];
          $scope.level = levels[0];
          $scope.observationType = observationTypes[0];
          $scope.unit = "";
          $scope.description = "";
          $('#observation-panel').removeCl***REMOVED***('hide');
          console.log('id = -1');
        } else if (observationId > 0) {  // look up the observation and show it in the dialog
          var layerId = $scope.observationId.layer.id;

          $('#observation-panel').removeCl***REMOVED***('hide');
          /* get the observation properties */
          $http.get(appConstants.rootUrl + '/FeatureServer/'+ layerId + '/' + observationId + "?query&outFields=*").
            success(function (data, status, headers, config) {
              $scope.observation = data;
              $scope.team = _.find($scope.teams, function (t) {
                if(t.name == $scope.observation.attributes.TEAM) {
                  return t;
                }
              });
              $scope.level = _.find($scope.levels, function (l) {
                if (l.color == $scope.observation.attributes.EVENTLEVEL){
                  return l;
                }
              });
              $scope.observationType = _.find($scope.observationTypes, function (o) {
                if (o.title == $scope.observation.attributes.TYPE){
                  return o;
                }
              });
              $scope.description = $scope.observation.attributes.DESCRIPTION;
              $scope.unit = $scope.observation.attributes.UNIT;
            }).
            error(function (data, status, headers, config) {
              $log.log("Error adding feature: " + status);
            });

          /* get the observation's attachments */
          $scope.attachmentUrl = appConstants.rootUrl + '/FeatureServer/'+ layerId + '/' + observationId + '/attachments/';
          $http.get($scope.attachmentUrl).
            success(function (data, status, headers, config) {
              $scope.attachments = data.attachmentInfos;
            }).
            error(function (data, status, headers, config) {

            });
          console.log('id > 0');
        } else {
          console.log("id is weird...not so sure what to do" + observationId);
        }
      }, true); // scope.$watch

      /* Hide the observation panel, and reset the fields for next time. */
      $scope.cancelObservation = function () {
        console.log("in new observation");
        $scope.observationId = {feature: {properties: {OBJECTID: 0}}}; // hide the observation panel
        $scope.files = [];
      }

      /* Send the observation to the server */
      $scope.saveObservation = function () {
        console.log("in new observation");
        console.log("Team: " + $scope.team.name + ", Level: " + $scope.level.color + ", Observation Type: " + $scope.observationType.title + ", Unit: " + $scope.unit + ", Description: " + $scope.description);

        var operation = "";
        var ob = [];

        /* check to see if this is this an update or a new observation */
        if ($scope.observationId > 0) {
          operation = "updateFeatures";
          ob = [{
            "geometry": {
              "x": $scope.observation.geometry.coordinates[0],
              "y":$scope.observation.geometry.coordinates[1]
            },
            "attributes": {
              "OBJECTID": $scope.observationId,
              "EVENTDATE":new Date().getTime(),
              "TYPE":$scope.observationType.title,
              "EVENTLEVEL":$scope.level.color,
              "TEAM":$scope.team.name,
              "DESCRIPTION":$scope.description,
              "EVENTCLEAR":0,
              "UNIT":$scope.unit
            }
          }];
        } else {
          operation = "addFeatures";
          ob = [{
            "geometry": {
              "x": $scope.marker.lng,
              "y": $scope.marker.lat
            },
            "attributes": {
              "EVENTDATE":new Date().getTime(),
              "TYPE":$scope.observationType.title,
              "EVENTLEVEL":$scope.level.color,
              "TEAM":$scope.team.name,
              "DESCRIPTION":$scope.description,
              "EVENTCLEAR":0,
              "UNIT":$scope.unit
            }
          }];
        }

        $http.post(appConstants.rootUrl + '/FeatureServer/'+ $scope.currentLayerId + '/' + operation, "features=" + JSON.stringify(ob),
        {
          headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        }).
        success(function (data, status, headers, config) {
          var objectId = data.addResults ? data.addResults[0].objectId : data.updateResults[0].objectId;

          $scope.newFeature = {
            type: "Feature",
            geometry: {
              type: "Point",
              coordinates: [$scope.marker.lng, $scope.marker.lat]
            },
            properties: {
              OBJECTID: objectId
            }
          }

          if ($scope.files.length > 0) {
            $scope.fileUploadUrl = appConstants.rootUrl + '/FeatureServer/' + $scope.currentLayerId + '/' + objectId + '/addAttachment';
            $scope.uploadFile();
          }

          $scope.observationId = 0; // hide the observation panel
        }).
        error(function (data, status, headers, config) {
          $log.log("Error adding feature: " + status);
        });
      } // end of saveObservation

      $scope.setFiles = function (element) {
        $scope.$apply(function(scope) {
          console.log('files:', element.files);
          // Turn the FileList object into an Array
          $scope.files = []
          for (var i = 0; i < element.files.length; i++) {
            $scope.files.push(element.files[i])
          }
          $scope.progressVisible = false
        });
      }

      $scope.uploadFile = function() {
        var fd = new FormData()
        for (var i in $scope.files) {
          fd.append("attachment", $scope.files[i])
        }
        var xhr = new XMLHttpRequest()
        xhr.upload.addEventListener("progress", uploadProgress, false)
        xhr.addEventListener("load", uploadComplete, false)
        xhr.addEventListener("error", uploadFailed, false)
        xhr.addEventListener("abort", uploadCanceled, false)
        xhr.open("POST", $scope.fileUploadUrl)
        $scope.progressVisible = true
        xhr.send(fd)
      }

      function uploadProgress(evt) {
        $scope.$apply(function(){
          if (evt.lengthComputable) {
            $scope.progress = Math.round(evt.loaded * 100 / evt.total)
          } else {
            $scope.progress = 'unable to compute'
          }
        });
      }

      function uploadComplete(evt) {
        $scope.files = [];
      }

      function uploadFailed(evt) {
        alert("There was an error attempting to upload the file.")
      }

      function uploadCanceled(evt) {
        $scope.$apply(function(){
            $scope.progressVisible = false
        })
        alert("The upload has been canceled by the user or the browser dropped the connection.")
      }
    } // directive controller
  }; // return
});<commit_msg>fixed save not hiding panel.<commit_after>sage.directive('observation', function($http, appConstants) {
  return {
    restrict: "A",
    templateUrl: appConstants.rootUrl + "/js/app/partials/observation-template.html",
    scope: {
      layers: "=layers",
      observationId: "=observationid",
      marker: "=marker",
      newLayer: "=newlayer",
      currentLayerId: "=currentlayerid",
      newFeature: "=newfeature"
    },
    controller: derp = function ($scope, $element, $attrs, $http, teams, levels, observationTypes, appConstants) {
      /* Observation parameters. These are what get sent back to the server when a new observation is created. */
      $scope.teams = teams;
      $scope.levels = levels;
      $scope.observationTypes = observationTypes;

      $scope.observation = {}; // need to clean all of this up and figure out how to make it generic
      $scope.team = teams[0];
      $scope.level = levels[0];
      $scope.observationType = observationTypes[0];
      $scope.unit = "";
      $scope.description = "";
      $scope.files = []; // pre upload
      $scope.attachments = []; // images loaded from the server
      $scope.progressVisible = false;
      $scope.progressVisible = 0;

      // this is a hack, need to start using the ui-bootstrap, couldnt get the yo-dawged directive's scopes to play nice
      $scope.selectedTab = 1;

      /*
        If the ID changes and is -1, then it is a new observation, pop open the form and let the user create a new observation.
        If it is not -1, or 0, then lookup the rest of the attributes and populate the form.
      */
      $scope.$watch("observationId", function (newValue, oldValue) {
        console.log("id changed!!!!");
        var observation = $scope.observationId;
        if (!observation) return;

        var observationId = $scope.observationId.feature.properties.OBJECTID;

        if (observationId == 0) {          // hide the observation dialog
          $('#observation-panel').addCl***REMOVED***('hide');
          console.log ('id = 0');
        } else if(observationId == -1) { // creating a new observation
          $scope.team = teams[0];
          $scope.level = levels[0];
          $scope.observationType = observationTypes[0];
          $scope.unit = "";
          $scope.description = "";
          $('#observation-panel').removeCl***REMOVED***('hide');
          console.log('id = -1');
        } else if (observationId > 0) {  // look up the observation and show it in the dialog
          var layerId = $scope.observationId.layer.id;

          $('#observation-panel').removeCl***REMOVED***('hide');
          /* get the observation properties */
          $http.get(appConstants.rootUrl + '/FeatureServer/'+ layerId + '/' + observationId + "?query&outFields=*").
            success(function (data, status, headers, config) {
              $scope.observation = data;
              $scope.team = _.find($scope.teams, function (t) {
                if(t.name == $scope.observation.attributes.TEAM) {
                  return t;
                }
              });
              $scope.level = _.find($scope.levels, function (l) {
                if (l.color == $scope.observation.attributes.EVENTLEVEL){
                  return l;
                }
              });
              $scope.observationType = _.find($scope.observationTypes, function (o) {
                if (o.title == $scope.observation.attributes.TYPE){
                  return o;
                }
              });
              $scope.description = $scope.observation.attributes.DESCRIPTION;
              $scope.unit = $scope.observation.attributes.UNIT;
            }).
            error(function (data, status, headers, config) {
              $log.log("Error adding feature: " + status);
            });

          /* get the observation's attachments */
          $scope.attachmentUrl = appConstants.rootUrl + '/FeatureServer/'+ layerId + '/' + observationId + '/attachments/';
          $http.get($scope.attachmentUrl).
            success(function (data, status, headers, config) {
              $scope.attachments = data.attachmentInfos;
            }).
            error(function (data, status, headers, config) {

            });
          console.log('id > 0');
        } else {
          console.log("id is weird...not so sure what to do" + observationId);
        }
      }, true); // scope.$watch

      /* Hide the observation panel, and reset the fields for next time. */
      $scope.cancelObservation = function () {
        console.log("in new observation");
        $scope.observationId = {feature: {properties: {OBJECTID: 0}}}; // hide the observation panel
        $scope.files = [];
      }

      /* Send the observation to the server */
      $scope.saveObservation = function () {
        console.log("in new observation");
        console.log("Team: " + $scope.team.name + ", Level: " + $scope.level.color + ", Observation Type: " + $scope.observationType.title + ", Unit: " + $scope.unit + ", Description: " + $scope.description);

        var operation = "";
        var ob = [];

        /* check to see if this is this an update or a new observation */
        if ($scope.observationId > 0) {
          operation = "updateFeatures";
          ob = [{
            "geometry": {
              "x": $scope.observation.geometry.coordinates[0],
              "y":$scope.observation.geometry.coordinates[1]
            },
            "attributes": {
              "OBJECTID": $scope.observationId,
              "EVENTDATE":new Date().getTime(),
              "TYPE":$scope.observationType.title,
              "EVENTLEVEL":$scope.level.color,
              "TEAM":$scope.team.name,
              "DESCRIPTION":$scope.description,
              "EVENTCLEAR":0,
              "UNIT":$scope.unit
            }
          }];
        } else {
          operation = "addFeatures";
          ob = [{
            "geometry": {
              "x": $scope.marker.lng,
              "y": $scope.marker.lat
            },
            "attributes": {
              "EVENTDATE":new Date().getTime(),
              "TYPE":$scope.observationType.title,
              "EVENTLEVEL":$scope.level.color,
              "TEAM":$scope.team.name,
              "DESCRIPTION":$scope.description,
              "EVENTCLEAR":0,
              "UNIT":$scope.unit
            }
          }];
        }

        $http.post(appConstants.rootUrl + '/FeatureServer/'+ $scope.currentLayerId + '/' + operation, "features=" + JSON.stringify(ob),
        {
          headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        }).
        success(function (data, status, headers, config) {
          var objectId = data.addResults ? data.addResults[0].objectId : data.updateResults[0].objectId;

          $scope.newFeature = {
            type: "Feature",
            geometry: {
              type: "Point",
              coordinates: [$scope.marker.lng, $scope.marker.lat]
            },
            properties: {
              OBJECTID: objectId
            }
          }

          if ($scope.files.length > 0) {
            $scope.fileUploadUrl = appConstants.rootUrl + '/FeatureServer/' + $scope.currentLayerId + '/' + objectId + '/addAttachment';
            $scope.uploadFile();
          }

          // hide the observation panel
          //TODO need a better way to send hide events for this panel
          $scope.observationId = {feature: { properties: {OBJECTID: 0}}};
        }).
        error(function (data, status, headers, config) {
          $log.log("Error adding feature: " + status);
        });
      } // end of saveObservation

      $scope.setFiles = function (element) {
        $scope.$apply(function(scope) {
          console.log('files:', element.files);
          // Turn the FileList object into an Array
          $scope.files = []
          for (var i = 0; i < element.files.length; i++) {
            $scope.files.push(element.files[i])
          }
          $scope.progressVisible = false
        });
      }

      $scope.uploadFile = function() {
        var fd = new FormData()
        for (var i in $scope.files) {
          fd.append("attachment", $scope.files[i])
        }
        var xhr = new XMLHttpRequest()
        xhr.upload.addEventListener("progress", uploadProgress, false)
        xhr.addEventListener("load", uploadComplete, false)
        xhr.addEventListener("error", uploadFailed, false)
        xhr.addEventListener("abort", uploadCanceled, false)
        xhr.open("POST", $scope.fileUploadUrl)
        $scope.progressVisible = true
        xhr.send(fd)
      }

      function uploadProgress(evt) {
        $scope.$apply(function(){
          if (evt.lengthComputable) {
            $scope.progress = Math.round(evt.loaded * 100 / evt.total)
          } else {
            $scope.progress = 'unable to compute'
          }
        });
      }

      function uploadComplete(evt) {
        $scope.files = [];
      }

      function uploadFailed(evt) {
        alert("There was an error attempting to upload the file.")
      }

      function uploadCanceled(evt) {
        $scope.$apply(function(){
            $scope.progressVisible = false
        })
        alert("The upload has been canceled by the user or the browser dropped the connection.")
      }
    } // directive controller
  }; // return
});<|endoftext|>


<commit_before>//RS tree builder
(function (app, $) {
  ko.components.register('juggler-rstrees', {
    viewModel: function (params) {

      var amountNodes = ko.observable(5);
      var nodeSize = ko.observable(3);
      var intersectionSize = ko.observable(1);

      var built = ko.observable(false);

      var treeNodes = ko.observableArray([]);
      var treeEdges = ko.observableArray([]);

      var shortTreeNodes = ko.observableArray([]);
      var shortTreeEdges = ko.observableArray([]);

      var fullTreeCode = ko.observableArray([]);
      var shortTreeCode = ko.observableArray([]);

      var edgesText = ko.computed(function () {
        return _.map(treeEdges(), function (edge) {
          return '{' + edge[0] + ',' + edge[1] + '}';
        })
      });

      function buildRSTree(r, s, k) {
        s = s || 1;
        r = r || 3;
        k = k || 5;

        var nodes = [];
        var edges = [];

        var fullCode = [];
        var shortCode = [];
        var shortTreeNodes = [];
        var shortTreeEdges = [];

        var counter = 0;
        // var pNode = [];
        for (var part = 0; part < k; part++) {
          var node = [];
          var snode = [];
          var startFrom = 0;

          if (fullCode.length > 0) {
            var prevNodeIndex = app.random(fullCode.length);
            // if(!_.contains(shortTreeNodes, prevNodeIndex))
            // shortTreeNodes.push(prevNodeIndex);
            shortTreeEdges.push([prevNodeIndex, part]);

            var pNode = _.clone(fullCode[prevNodeIndex]);

            for (var sIndex = 0; sIndex < s; sIndex++) {
              var prevIndex = app.random(pNode.length);

              snode.push(pNode[prevIndex]);
              node.push(pNode[prevIndex]);

              if (prevIndex > -1) {
                pNode.splice(prevIndex, 1);
              }
            }
            startFrom = s;
          }

          for (var rIndex = startFrom; rIndex < r; rIndex++) {
            node.push(counter++);
          }

          node.sort();
          snode.sort();

          fullCode.push(node);
          shortCode.push(snode);
          // pNode = _.clone(node);

        }
        shortTreeNodes = _.range(k);
        nodes = _.range(counter);

        for (var nodeIndex = 0; nodeIndex < fullCode.length; nodeIndex++) {
          var codeNode = fullCode[nodeIndex];

          for (var i = 0; i < codeNode.length; i++) {
            for (var j = i + 1; j < codeNode.length; j++) {
              edges.push([codeNode[i], codeNode[j]]);
            }
          }

        }
        edges = _.uniq(edges);
        //edges.push([0, 1]);

        return {
          nodes: nodes,
          edges: edges,

          shortTreeNodes: shortTreeNodes,
          shortTreeEdges: shortTreeEdges,

          fullCode: fullCode,
          shortCode: shortCode
        };
      }

      function buildAction() {
        var res = buildRSTree(nodeSize(), intersectionSize(), amountNodes());

        console.dir(res);

        //var fCode = _.flatten(res.fullCode);
        //var sCode = _.flatten(res.shortCode);

        //console.dir(fCode);
        //console.dir(sCode);

        var fCode = '';
        for (var i = 0; i < res.fullCode.length; i++) {
          fCode += _s.humanize(res.fullCode[i]) + '| ';
        }
        fullTreeCode(fCode);

        var sCode = '';
        for (var i = 1; i < res.shortCode.length; i++) {
          sCode += _s.humanize(res.shortCode[i]) + '| ';
        }
        shortTreeCode(sCode);

        //shortTreeCode(_s.humanize(sCode));

        treeNodes(res.nodes);
        treeEdges(res.edges);

        shortTreeNodes(res.shortTreeNodes);
        shortTreeEdges(res.shortTreeEdges);

        built(true);
      }

      return {
        amountNodes: amountNodes,
        nodeSize: nodeSize,
        intersectionSize: intersectionSize,

        warning: '',

        build: buildAction,
        reset: function (params) {
        },

        nodes: treeNodes,
        edges: treeEdges,

        shortTreeNodes: shortTreeNodes,
        shortTreeEdges: shortTreeEdges,

        fullCode: fullTreeCode,
        shortCode: shortTreeCode,

        built: built,

        edgesText: edgesText
      };
    },
    template: {
      fromUrl: 'rstrees.html',
      maxCacheAge: 60000
    }
  });
})(window.juggler = window.juggler || {}, jQuery);
<commit_msg>Validation<commit_after>//RS tree builder
(function (app, $) {
  ko.components.register('juggler-rstrees', {
    viewModel: function (params) {

      var amountNodes = ko.observable(5);
      var nodeSize = ko.observable(3);
      var intersectionSize = ko.observable(1);

      var warning = ko.observable('');

      var built = ko.observable(false);

      var treeNodes = ko.observableArray([]);
      var treeEdges = ko.observableArray([]);

      var shortTreeNodes = ko.observableArray([]);
      var shortTreeEdges = ko.observableArray([]);

      var fullTreeCode = ko.observableArray([]);
      var shortTreeCode = ko.observableArray([]);

      var edgesText = ko.computed(function () {
        return _.map(treeEdges(), function (edge) {
          return '{' + edge[0] + ',' + edge[1] + '}';
        })
      });

      function buildRSTree(r, s, k) {

        function sortNumber(a, b) {
          return a - b;
        }

        s = s || 1;
        r = r || 3;
        k = k || 5;

        var nodes = [];
        var edges = [];

        var fullCode = [];
        var shortCode = [];
        var shortTreeNodes = [];
        var shortTreeEdges = [];

        var counter = 0;
        // var pNode = [];
        for (var part = 0; part < k; part++) {
          var node = [];
          var snode = [];
          var startFrom = 0;

          if (fullCode.length > 0) {
            var prevNodeIndex = app.random(fullCode.length);
            // if(!_.contains(shortTreeNodes, prevNodeIndex))
            // shortTreeNodes.push(prevNodeIndex);
            shortTreeEdges.push([prevNodeIndex, part]);

            var pNode = _.clone(fullCode[prevNodeIndex]);

            for (var sIndex = 0; sIndex < s; sIndex++) {
              var prevIndex = app.random(pNode.length);

              snode.push(pNode[prevIndex]);
              node.push(pNode[prevIndex]);

              if (prevIndex > -1) {
                pNode.splice(prevIndex, 1);
              }
            }
            startFrom = s;
          }

          for (var rIndex = startFrom; rIndex < r; rIndex++) {
            node.push(counter++);
          }

          node.sort(sortNumber);
          snode.sort(sortNumber);

          fullCode.push(node);
          shortCode.push(snode);
          // pNode = _.clone(node);

        }
        shortTreeNodes = _.range(k);
        nodes = _.range(counter);

        for (var nodeIndex = 0; nodeIndex < fullCode.length; nodeIndex++) {
          var codeNode = fullCode[nodeIndex];

          for (var i = 0; i < codeNode.length; i++) {
            for (var j = i + 1; j < codeNode.length; j++) {
              edges.push([codeNode[i], codeNode[j]]);
            }
          }

        }
        edges = _.uniq(edges);
        //edges.push([0, 1]);

        return {
          nodes: nodes,
          edges: edges,

          shortTreeNodes: shortTreeNodes,
          shortTreeEdges: shortTreeEdges,

          fullCode: fullCode,
          shortCode: shortCode
        };
      }

      function buildAction() {
        if (nodeSize() <= 0 || intersectionSize() >= nodeSize() || intersectionSize() <= 0) {
          warning('Некорректные параметры');
          built(false);
          return;
        } else {
          warning('');
        }

        var res = buildRSTree(nodeSize(), intersectionSize(), amountNodes());

        console.dir(res);

        var fCode = '';
        for (var i = 0; i < res.fullCode.length; i++) {
          fCode += _s.humanize(res.fullCode[i]) + '| ';
        }
        fullTreeCode(fCode);

        var sCode = '';
        for (var i = 1; i < res.shortCode.length; i++) {
          sCode += _s.humanize(res.shortCode[i]) + '| ';
        }
        shortTreeCode(sCode);

        treeNodes(res.nodes);
        treeEdges(res.edges);

        shortTreeNodes(res.shortTreeNodes);
        shortTreeEdges(res.shortTreeEdges);

        built(true);
      }

      return {
        amountNodes: amountNodes,
        nodeSize: nodeSize,
        intersectionSize: intersectionSize,

        warning: warning,

        build: buildAction,
        reset: function (params) {
        },

        nodes: treeNodes,
        edges: treeEdges,

        shortTreeNodes: shortTreeNodes,
        shortTreeEdges: shortTreeEdges,

        fullCode: fullTreeCode,
        shortCode: shortTreeCode,

        built: built,

        edgesText: edgesText
      };
    },
    template: {
      fromUrl: 'rstrees.html',
      maxCacheAge: 60000
    }
  });
})(window.juggler = window.juggler || {}, jQuery);
<|endoftext|>


<commit_before>var prev = document.querySelector(".prevItem");
var next = document.querySelector(".nextItem");
var items = document.querySelector(".carousel-container ol");

var width = items.querySelector("li").getBoundingClientRect().width;

var left = 0;
/*
var clickCountLeft = 0;
var clickCountRight = 0;
var itemsCount = items.childNodes;
*/
/* divide itemsCount by two as it counts both <li> and <p> */

prev.addEventListener("click",rollLeft);
next.addEventListener("click",rollRight);

console.log("width times 3 = " + width*3);

function rollLeft() {

  if (Math.abs(left) == (width*3)) {
    left = 0;
  }

  if ((Math.abs(left) < width*3) && left !=0 ) {
    left = left + width;
    items.style.left = left + "px";
  }
  console.log(Math.abs(left));
}

function rollRight() {

  if (Math.abs(left) == (width*3)) {
    left = 0;
  }

  if (Math.abs(left) < width*3 && left != width*3 ) {
    left = left - width;
    items.style.left = left + "px";
  }
  console.log(Math.abs(left));
}

/* Click count solution for The Hall of Fame

function rollLeft(){
  clickCountRight = 0;
  clickCountLeft += 2.5;
  if (clickCountLeft < (itemsCount.length)) {
    left = left + width;
    items.style.left = left + "px";
  }
  console.log(itemsCount.length);
  console.log(clickCountLeft);
  console.log(left);
}

function rollRight(){
  clickCountLeft = 0;
  clickCountRight += 2.5;
  if (clickCountRight < (itemsCount.length)) {
  left = left - width;
  items.style.left = left + "px";
  }
  console.log(itemsCount.length);
  console.log(clickCountRight);
  console.log(left);
}

*/
<commit_msg>almost 100% fixed left-right navigation, added updateWidth() to carousel<commit_after>var prev = document.querySelector(".prevItem");
var next = document.querySelector(".nextItem");
var items = document.querySelector(".carousel-container ol");

var width = items.querySelector("li").getBoundingClientRect().width;

var left = 0;

/*
var clickCountLeft = 0;
var clickCountRight = 0;
var itemsCount = items.childNodes;
*/
/* divide itemsCount by two as it counts both <li> and <p> */

window.addEventListener("resize",updateWidth);
prev.addEventListener("click",rollLeft);
next.addEventListener("click",rollRight);

function updateWidth() {
  width = items.querySelector("li").getBoundingClientRect().width;
}

console.log("width times 3 = " + width*3);

function rollLeft() {

  if (left == 0) {
    prev.style.display = "none";
    next.style.display = "inline-block";
  }

  if ((Math.abs(left) < width*3) && left !=0 ) {
    left = left + width;
    items.style.left = left + "px";
  }
  console.log(Math.abs(left));
}

function rollRight() {

  if (Math.abs(left) == (width*3)) {
    left = 0;
    next.style.display = "none";
    prev.style.display = "inline-block";
  }

  if (Math.abs(left) < width*3 && left != width*3 ) {
    left = left - width;
    items.style.left = left + "px";
  }
  console.log(Math.abs(left));
}

/* Click count solution for The Hall of Fame

function rollLeft(){
  clickCountRight = 0;
  clickCountLeft += 2.5;
  if (clickCountLeft < (itemsCount.length)) {
    left = left + width;
    items.style.left = left + "px";
  }
  console.log(itemsCount.length);
  console.log(clickCountLeft);
  console.log(left);
}

function rollRight(){
  clickCountLeft = 0;
  clickCountRight += 2.5;
  if (clickCountRight < (itemsCount.length)) {
  left = left - width;
  items.style.left = left + "px";
  }
  console.log(itemsCount.length);
  console.log(clickCountRight);
  console.log(left);
}

*/
<|endoftext|>


<commit_before>/*
var blocks = {
  "regular":[
    {"start":"7:45","end":"9:06","name":"Block 1","bold":false,"startHour":7,"startMinute":45,"endHour":9,"endMinute":6},
    {"start":"9:06","end":"9:16","name":"Break","bold":true,"startHour":9,"startMinute":6,"endHour":9,"endMinute":16},
    {"start":"9:21","end":"10:53","name":"Block 2","bold":false,"startHour":9,"startMinute":21,"endHour":10,"endMinute":53},
    {"start":"10:58","end":"12:19","name":"Block 3","bold":false,"startHour":10,"startMinute":58,"endHour":12,"endMinute":19},
    {"start":"12:19","end":"12:44","name":"Intervention","bold":false,"startHour":12,"startMinute":19,"endHour":12,"endMinute":44},
    {"start":"12:44","end":"1:14","name":"Lunch","bold":true,"startHour":12,"startMinute":44,"endHour":13,"endMinute":14},
    {"start":"1:19","end":"2:40","name":"Block 4","bold":false,"startHour":13,"startMinute":19,"endHour":14,"endMinute":40}
  ],

  "articulation":[
    {"start":"7:45","end":"8:53","name":"Block 1","bold":false,"startHour":7,"startMinute":45,"endHour":8,"endMinute":53},
    {"start":"8:58","end":"10:14","name":"Block 2","bold":false,"startHour":8,"startMinute":58,"endHour":10,"endMinute":14},
    {"start":"10:14","end":"10:34","name":"Break/Lunch","bold":true,"startHour":10,"startMinute":14,"endHour":10,"endMinute":34},
    {"start":"10:39","end":"11:47","name":"Block 3","bold":false,"startHour":10,"startMinute":39,"endHour":11,"endMinute":47},
    {"start":"11:52","end":"1:00","name":"Block 4","bold":false,"startHour":11,"startMinute":52,"endHour":13,"endMinute":0}
  ]
};
*/

// Maintenance Note: Change all `var data = blocks` to `var data = JSON.parse(blocks);` when editing code

function getTimeAdv (date) {
  return [ date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds() ];
}

function getNext () {
  var i;
  var cycle = true;
  var data = blocks;
  var days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
  var date = new Date();
  var render;
  var currentEvent;
  var time = getTimeAdv(date);

  if (date.getDay() !== 0 || date.getDay() !== 6) {
    if (date.getDay() === 1) {
      render = data.articulation;
    } else {
      render = data.regular;
    }

    var currentTime = 0;
    var nextTime = 0;
    var hoursLeft = 0;
    var minutesLeft = 0;
    for (i = 0; i < render.length; i++) {
      currentTime = (time[0] * 60) + time[1];
      nextTime = (render[i].endHour * 60) + render[i].endMinute;
      if (currentTime < nextTime) {
        hoursLeft = Math.floor((nextTime - currentTime) / 60);
        minutesLeft = Math.floor((nextTime - (hoursLeft * 60)) - currentTime);
        if (hoursLeft === 0) {
          return minutesLeft + ' minutes until the end of ' + render[i].name;
        } else if (hoursLeft !== 0) {
          return hoursLeft + ' hours and ' + minutesLeft + ' minutes until the end of ' + render[i].name;
        }
      }
    }
    return 'School is over.';
  }
}

$(document).ready(function () {
  var days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
  var data = blocks;
  var i;
  var date = new Date();
  var render;
  if (date.getDay() === 1) {
    render = data.articulation;
    for (i = 0; i < render.length; i++) {
      if (!render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      } else if (render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      }
    }
    document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
  } else if (date.getDay() === 2 || date.getDay() === 3 || date.getDay() === 4 || date.getDay() === 5) {
    render = data.regular;
    for (i = 0; i < render.length; i++) {
      if (!render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      } else if (render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      }
    }
    document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
  } else if (date.getDay() === 0 || date.getDay() === 6) {
    document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
    $('#text').show();
    $('#text').text("No school today, it's " + days[date.getDay()] + "!");
  }
});

var timeUpdate = setInterval(function () {
  $('#time').html('The time is currently ' + new Date().toLocaleTimeString() + '.');
  $('#next').html(getNext());
}, 500);
<commit_msg>Update schedule.js<commit_after>/*
var blocks = {
  "regular":[
    {"start":"7:45","end":"9:06","name":"Block 1","bold":false,"startHour":7,"startMinute":45,"endHour":9,"endMinute":6},
    {"start":"9:06","end":"9:16","name":"Break","bold":true,"startHour":9,"startMinute":6,"endHour":9,"endMinute":16},
    {"start":"9:21","end":"10:53","name":"Block 2","bold":false,"startHour":9,"startMinute":21,"endHour":10,"endMinute":53},
    {"start":"10:58","end":"12:19","name":"Block 3","bold":false,"startHour":10,"startMinute":58,"endHour":12,"endMinute":19},
    {"start":"12:19","end":"12:44","name":"Intervention","bold":false,"startHour":12,"startMinute":19,"endHour":12,"endMinute":44},
    {"start":"12:44","end":"1:14","name":"Lunch","bold":true,"startHour":12,"startMinute":44,"endHour":13,"endMinute":14},
    {"start":"1:19","end":"2:40","name":"Block 4","bold":false,"startHour":13,"startMinute":19,"endHour":14,"endMinute":40}
  ],

  "articulation":[
    {"start":"7:45","end":"8:53","name":"Block 1","bold":false,"startHour":7,"startMinute":45,"endHour":8,"endMinute":53},
    {"start":"8:58","end":"10:14","name":"Block 2","bold":false,"startHour":8,"startMinute":58,"endHour":10,"endMinute":14},
    {"start":"10:14","end":"10:34","name":"Break/Lunch","bold":true,"startHour":10,"startMinute":14,"endHour":10,"endMinute":34},
    {"start":"10:39","end":"11:47","name":"Block 3","bold":false,"startHour":10,"startMinute":39,"endHour":11,"endMinute":47},
    {"start":"11:52","end":"1:00","name":"Block 4","bold":false,"startHour":11,"startMinute":52,"endHour":13,"endMinute":0}
  ]
};
*/

// Maintenance Note: Change all `var data = blocks` to `var data = JSON.parse(blocks);` when editing code

function getTimeAdv (date) {
  return [ date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds() ];
}

function timeUpdate () {
  $('#time').html('The time is currently ' + new Date().toLocaleTimeString() + '.');
  $('#next').html(getNext());
}

function getNext () {
  var i;
  var cycle = true;
  var data = blocks;
  var days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
  var date = new Date();
  var render;
  var currentEvent;
  var time = getTimeAdv(date);

  if (date.getDay() !== 0 || date.getDay() !== 6) {
    if (date.getDay() === 1) {
      render = data.articulation;
    } else {
      render = data.regular;
    }

    var currentTime = 0;
    var nextTime = 0;
    var hoursLeft = 0;
    var minutesLeft = 0;
    for (i = 0; i < render.length; i++) {
      currentTime = (time[0] * 60) + time[1];
      nextTime = (render[i].endHour * 60) + render[i].endMinute;
      if (currentTime < nextTime) {
        hoursLeft = Math.floor((nextTime - currentTime) / 60);
        minutesLeft = Math.floor((nextTime - (hoursLeft * 60)) - currentTime);
        if (hoursLeft === 0) {
          return minutesLeft + ' minutes until the end of ' + render[i].name;
        } else if (hoursLeft !== 0) {
          return hoursLeft + ' hours and ' + minutesLeft + ' minutes until the end of ' + render[i].name;
        }
      }
    }
    return 'School is over.';
  }
}

$(document).ready(function () {
  var days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
  var data = blocks;
  var i;
  var date = new Date();
  var render;
  if (date.getDay() === 1) {
    render = data.articulation;
    for (i = 0; i < render.length; i++) {
      if (!render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      } else if (render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      }
    }
    document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
  } else if (date.getDay() === 2 || date.getDay() === 3 || date.getDay() === 4 || date.getDay() === 5) {
    render = data.regular;
    for (i = 0; i < render.length; i++) {
      if (!render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      } else if (render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      }
    }
    document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
  } else if (date.getDay() === 0 || date.getDay() === 6) {
    document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
    $('#text').show();
    $('#text').text("No school today, it's " + days[date.getDay()] + "!");
  }

  timeUpdate();

  var clock = setInterval(function () {
    timeUpdate();
  }, 500);
});
<|endoftext|>


<commit_before>/* globals expect, beforeEach, it, describe, jasmine, spyOn */
import mementoBuilder from '../../../../src/patterns/behavioral/memento.js';
import commandBuilder from '../../../../src/patterns/behavioral/command.js';
import chainOfResponsibilityBuilder from '../../../../src/patterns/behavioral/chainOfResponsibility.js';
import json from '../../../../src/helpers/json.js';

describe('memento', function() {
  var Memento;
  var memento;
  var history;
  var parsedHistory;
  var key;
  beforeEach(function() {
    spyOn(json, 'stringify').and.callThrough();
    spyOn(json, 'parse').and.callThrough();
    history = {
      test: 'testing'
    };
    Memento = mementoBuilder().build();
    memento = new Memento();
    key = memento.add(history);
    parsedHistory = memento.get(key);
  });
  it('should add an object', function() {
    expect(key).toBeDefined();
    expect(key).toEqual(0);
    expect(json.stringify).toHaveBeenCalledWith(history);
  });
  it('should return a parsed object', function() {
    expect(json.parse).toHaveBeenCalled();
    expect(parsedHistory === history).not.toBeTruthy();
    expect(parsedHistory).toEqual(history);
  });
  describe('Advanced Level: Undo Redo using Memento, Command, and ChainOfResponsibility', function() {
    var chain;
    var UndoManager;
    var undoManager;
    var PointInTime;
    var runSpy;
    beforeEach(function() {
      PointInTime = function(index) {
        this.index = index;
        this.previous = null;
        this.next = null;
      };

      chain = (...args) => {
        var ChainOfResponsibility = chainOfResponsibilityBuilder().build();
        var overloader = new ChainOfResponsibility();
        args.forEach(overloader.add.bind(overloader));
        return overloader.run;
      };

      UndoManager = mementoBuilder(commandBuilder({
        constructor() {
          this.methods = {};
          this.state = {};
          this.pit = new PointInTime(this.add(this.state));

          var execute = this.execute.bind(this);
          this.execute = chain(
            this._onExecute.bind(this),
            (next, ...args) => {
              execute(...args);
              next();
            }
          );

          var add = this.add.bind(this);
          this.add = chain(
            (_, o) => {
              add(o);
            },
            (next, method, obj) => {
              if(typeof method !== 'string') {
                return next();
              }
              this.methods[method] = obj;
            }
          );
        },
        publics: {
          _onExecute(next, _, ...args) {
            if(_ !== 'run') {
              return this.execute.apply(null, ['run', _].concat(args));
            }
            var o = new PointInTime(this.add(this.state));
            o.previous = this.pit;
            this.pit.next = o;
            this.pit = o;
          },
          run(method, ...args) {
            return this.methods[method] && this.methods[method].apply(null, [this.state].concat(args));
          },
          undo() {
            if(this.pit.previous === null) {
              return;
            }
            this.pit = this.pit.previous;
            this._updateState();
          },
          redo() {
            if(this.pit.next === null) {
              return;
            }
            this.pit = this.pit.next;
            this._updateState();
          },
          _updateState() {
            this.state = this.get(this.pit.index);
          }
        }
      })).build();
      undoManager = new UndoManager();

      runSpy = jasmine.createSpy('run');
      undoManager.add('test', (state, arg) => {
        runSpy(arg);
        state.test = arg;
      });
      undoManager.execute('test', 'testing');
    });
    it('should run a method', function() {
      expect(runSpy).toHaveBeenCalledWith('testing');
      expect(undoManager.state.test).toEqual('testing');
    });
    it('should undo a method', function() {
      undoManager.undo();
      expect(undoManager.state.test).not.toEqual('testing');
    });
    it('should redo a method', function() {
      undoManager.redo();
      expect(undoManager.state.test).toEqual('testing');
    });
  });
});
<commit_msg>add empty-option test check<commit_after>/* globals expect, beforeEach, it, describe, jasmine, spyOn */
import mementoBuilder from '../../../../src/patterns/behavioral/memento.js';
import commandBuilder from '../../../../src/patterns/behavioral/command.js';
import chainOfResponsibilityBuilder from '../../../../src/patterns/behavioral/chainOfResponsibility.js';
import json from '../../../../src/helpers/json.js';

describe('memento', function() {
  var Memento;
  var memento;
  var history;
  var parsedHistory;
  var key;
  beforeEach(function() {
    spyOn(json, 'stringify').and.callThrough();
    spyOn(json, 'parse').and.callThrough();
    history = {
      test: 'testing'
    };
    Memento = mementoBuilder().build();
    memento = new Memento();
    key = memento.add(history);
    parsedHistory = memento.get(key);
  });
  it('should allow empty options', function() {
    var emptyOptions = undefined;
    var Memento = mementoBuilder(emptyOptions).build();
    var memento = new Memento();
    var key = memento.add({test: 'testing'});
    var result = memento.get(key);
    expect(result.test).toEqual('testing');
  });
  it('should add an object', function() {
    expect(key).toBeDefined();
    expect(key).toEqual(0);
    expect(json.stringify).toHaveBeenCalledWith(history);
  });
  it('should return a parsed object', function() {
    expect(json.parse).toHaveBeenCalled();
    expect(parsedHistory === history).not.toBeTruthy();
    expect(parsedHistory).toEqual(history);
  });
  describe('Advanced Level: Undo Redo using Memento, Command, and ChainOfResponsibility', function() {
    var chain;
    var UndoManager;
    var undoManager;
    var PointInTime;
    var runSpy;
    beforeEach(function() {
      PointInTime = function(index) {
        this.index = index;
        this.previous = null;
        this.next = null;
      };

      chain = (...args) => {
        var ChainOfResponsibility = chainOfResponsibilityBuilder().build();
        var overloader = new ChainOfResponsibility();
        args.forEach(overloader.add.bind(overloader));
        return overloader.run;
      };

      UndoManager = mementoBuilder(commandBuilder({
        constructor() {
          this.methods = {};
          this.state = {};
          this.pit = new PointInTime(this.add(this.state));

          var execute = this.execute.bind(this);
          this.execute = chain(
            this._onExecute.bind(this),
            (next, ...args) => {
              execute(...args);
              next();
            }
          );

          var add = this.add.bind(this);
          this.add = chain(
            (_, o) => {
              add(o);
            },
            (next, method, obj) => {
              if(typeof method !== 'string') {
                return next();
              }
              this.methods[method] = obj;
            }
          );
        },
        publics: {
          _onExecute(next, _, ...args) {
            if(_ !== 'run') {
              return this.execute.apply(null, ['run', _].concat(args));
            }
            var o = new PointInTime(this.add(this.state));
            o.previous = this.pit;
            this.pit.next = o;
            this.pit = o;
          },
          run(method, ...args) {
            return this.methods[method] && this.methods[method].apply(null, [this.state].concat(args));
          },
          undo() {
            if(this.pit.previous === null) {
              return;
            }
            this.pit = this.pit.previous;
            this._updateState();
          },
          redo() {
            if(this.pit.next === null) {
              return;
            }
            this.pit = this.pit.next;
            this._updateState();
          },
          _updateState() {
            this.state = this.get(this.pit.index);
          }
        }
      })).build();
      undoManager = new UndoManager();

      runSpy = jasmine.createSpy('run');
      undoManager.add('test', (state, arg) => {
        runSpy(arg);
        state.test = arg;
      });
      undoManager.execute('test', 'testing');
    });
    it('should run a method', function() {
      expect(runSpy).toHaveBeenCalledWith('testing');
      expect(undoManager.state.test).toEqual('testing');
    });
    it('should undo a method', function() {
      undoManager.undo();
      expect(undoManager.state.test).not.toEqual('testing');
    });
    it('should redo a method', function() {
      undoManager.redo();
      expect(undoManager.state.test).toEqual('testing');
    });
  });
});
<|endoftext|>


<commit_before>(function( Factlink ) {
// Function to search the page
Factlink.search = function(searchString){
	var document = window.document,
		alert = window.alert,
		// Array which will hold all the results
		results = [],

        // Store scroll settings to reset to afterwards
        scrollTop = document.body.scrollTop,
        scrollLeft = document.body.scrollLeft,

        rangy = window.rangy,
        selection, range, ierange, scroll;

    if ( window.find ) { // Chrome, Firefox, Safari
        // Reset the selection
        // Maybe we later need to store the current selection before
        // processing the document, so we can reset it afterwards
        window.getSelection().removeAllRanges();

        // Loop through all the results of the search string
        while ( window.find(searchString, false) ) {
            selection = window.getSelection();
            range = selection.getRangeAt(0);

            // Add the range to the results
            results.push(range);
        }

        // Reset the selection
        // Maybe we later need to store the current selection before
        // processing the document, so we can reset it afterwards
        window.getSelection().removeAllRanges();
    } else if (document.body.createTextRange) { // IE
            // Create an empty range object
        range = document.body.createTextRange();

        if ( range.findText ) { // IE
            // IE8 Doesn't support search over multiple elements...
            if (document.documentMode && document.documentMode === 8) { // IE8
                alert( "Your browser is currently running in IE8 Mode, this rendering " +
                       "mode of IE8 has a bug which may cause Factlink from not finding " +
                       "all the available Factlinks on this page.");
            }

            while ( range.findText(searchString) ) {
                // We need to encapsulate the following statements in a try-catch
                // because IE will throw an error (800a025e) when trying to select
                // a non-visible range
                // TODO: Find out if we can surpass this by using the internal rangy
                //       functions which will parse a normal range into a rangy-range
                try {
                    // Select the current range, necessary because of the ierange
                    // we're using
                    range.select();

                        // Because of IE's shitty implementation of the Range and
                        // Selection objects, we have to refresh the range (this
                        // time the rangy module is used)
                    selection = rangy.getSelection();

                        // the rangy object
                    ierange = selection.getRangeAt(0);

                    // Push the range to the results
                    results.push(ierange);

                    // Move on
                    range.collapse(false);
                    selection.removeAllRanges();
                } catch (e) {
                    // We need to collapse the range because otherwise IE will
                    // keep matching this range
                    range.collapse(false);
                }
            }
        } else { // No findText available
            return false;
        }
    } else { // No window.find and createTextRange
        return false;
    }

    // Scroll back to previous location
    window.scroll(scrollLeft,scrollTop);

    return results;
};
})( window.Factlink );<commit_msg>Internet Explorer support has been removed because the rangy dependency was not loaded anyway.<commit_after>(function( Factlink ) {
// Function to search the page
Factlink.search = function(searchString){
	var document = window.document,
		alert = window.alert,
		// Array which will hold all the results
		results = [],

        // Store scroll settings to reset to afterwards
        scrollTop = document.body.scrollTop,
        scrollLeft = document.body.scrollLeft,

        rangy = window.rangy,
        selection, range, ierange, scroll;

    if ( window.find ) { // Chrome, Firefox, Safari
        // Reset the selection
        // Maybe we later need to store the current selection before
        // processing the document, so we can reset it afterwards
        window.getSelection().removeAllRanges();

        // Loop through all the results of the search string
        while ( window.find(searchString, false) ) {
            selection = window.getSelection();
            range = selection.getRangeAt(0);

            // Add the range to the results
            results.push(range);
        }

        // Reset the selection
        // Maybe we later need to store the current selection before
        // processing the document, so we can reset it afterwards
        window.getSelection().removeAllRanges();
    } else { // No window.find and createTextRange
        return false;
    }

    // Scroll back to previous location
    window.scroll(scrollLeft,scrollTop);

    return results;
};
})( window.Factlink );<|endoftext|>


<commit_before>/*
	UpdateLocation POST

	By doing a HTTP Post on the /UpdateLocation method of this server you should
	be able to trigger this method here.

	curl -H "Content-Type: application/json" -X POST http://localhost:3000/UpdateLocation -d '{"JSON": "HERE"}'

	curl -H "Content-Type: application/json" -X POST http://localhost:3000/UpdateLocation -d '{"MiataruConfig":{"EnableLocationHistory":"Fa":"15"},"MiataruLocation":[{"Device":"7b8e6e0ee5296db345162dc2ef652c1350761823","Timestamp":"1376735651302","Longitude":"10.837502","Latitude":"49.828925","HorizontalAccuracy":"50.00"}]}'

	To store information Redis is used. The naming conventions are as follows:

	Last Known Location (expiring key-value): miad:$deviceid:last
	Location History (non expiring list): miad:$deviceid:hist
 */

var seq = require('seq');

var configuration = require('../../../configuration');
var db = require('../../../db');

var inputParser = require('./inputParser');
var kb = require('../../../utils/keyBuilder');

var KEY_HISTORY = 'hist';
var KEY_LAST = 'last';

var models = require('../../../models');

module.exports.updateLocation = updateLocation;
module.exports.getLocation = getLocation;
module.exports.getLocationHistory = getLocationHistory;

/**
 * GetLocationHistory
 * Retrieves the complete History
 * @param req
 * @param res
 * @param next
 */
function getLocationHistory(req, res, next) {
    var locationRequest = req.MIATARU.request;
    var key = kb.build(locationRequest.device(), KEY_HISTORY);

    seq()
        .par('listLength', function() {
            db.llen(key, this);
        })
        .par('list', function() {
            db.lrange(key, locationRequest.amount() * -1, -1, this);
        })
        .seq(function() {
            res.send((new models.ResponseLocationHistory(
                this.vars.listLength,
                configuration.maximumNumberOfHistoryItems,
                this.vars.list
            )).data());
        })
        .catch(function(error) {
            next(new errors.InternalServerError(error));
        });
}

/**
 * UpdateLocation
 * api endpoint that updates the currentLocation and a arbitrary number of history locations
 *
 * @param req
 * @param res
 * @param next
 */
function updateLocation(req, res, next) {
    var MIATARU = req.MIATARU;
    var requestConfig = MIATARU.config;
    var locations = MIATARU.locations;

    var chain = seq();

    if(requestConfig.enableLocationHistory()) {
        locations.forEach(function(loc, idx) {
            var value = JSON.stringify(loc.data());
            var historyKey = kb.build(loc.device(), KEY_HISTORY);
            var lastKey = kb.build(loc.device(), KEY_LAST);

            chain
                // we do want to store location history, so check if we got, so lpush and trim
                .seq(function() {
                    db.lpush(historyKey, value, this);
                })
                // take care that the location history does not grow beyond the set range of maximumNumberOfHistoryItems
                .seq(function() {
                    db.ltrim(historyKey, 0, configuration.maximumNumberOfHistoryItems-1, this);
                });

            if(idx === locations.length - 1) {
                // finally also update the last known location...
                chain.seq(function() {
                    db.set(lastKey, value, this);
                });
            }
        });
    } else {
        //we're only interested in the last item as we're not saving a history
        var loc = locations[locations.length-1];

        var timeToKeep = requestConfig.locationDataRetentionTime() * 60;
        var value = JSON.stringify(loc.data());

        seq()
            // we do not want to save a location history, this means if there's one we delete it...
            .par(function() {
                db.del(kb.build(loc.device(), KEY_HISTORY), this);
            })
            // update the last known location
            .par(function() {
                db.setex(kb.build(loc.device(), KEY_LAST), timeToKeep, value, this);
            });
    }

    chain
        .seq(function() {
            var eyes = ['x', '!', '^', '°'];
            res.send((new models.ResponseUpdateLocation(eyes[parseInt(Math.random() * eyes.length, 10)])).data());
        })
        .catch(next);
}

/**
 * GetLocation
 * This is used to get the current location of a device.
 *
 * @param req
 * @param res
 * @param next
 */
function getLocation(req, res, next) {
    var chain = seq();
    var response = new models.ResponseLocation();

    req.MIATARU.devices.forEach(function(device) {
        chain.par(function() {
            var done = this;

            db.get(kb.build(device.device(), KEY_LAST), function (error, reply) {
                if(error)  return done(error);

                response.pushLocation(JSON.parse(reply));
                done();
            });
        });
    });

    chain.seq(function() {
        res.send(response.data());
    })
    .catch(next);
}<commit_msg>restructure<commit_after>/*
	UpdateLocation POST

	By doing a HTTP Post on the /UpdateLocation method of this server you should
	be able to trigger this method here.

	curl -H "Content-Type: application/json" -X POST http://localhost:3000/UpdateLocation -d '{"JSON": "HERE"}'

	curl -H "Content-Type: application/json" -X POST http://localhost:3000/UpdateLocation -d '{"MiataruConfig":{"EnableLocationHistory":"Fa":"15"},"MiataruLocation":[{"Device":"7b8e6e0ee5296db345162dc2ef652c1350761823","Timestamp":"1376735651302","Longitude":"10.837502","Latitude":"49.828925","HorizontalAccuracy":"50.00"}]}'

	To store information Redis is used. The naming conventions are as follows:

	Last Known Location (expiring key-value): miad:$deviceid:last
	Location History (non expiring list): miad:$deviceid:hist
 */

var seq = require('seq');

var configuration = require('../../../configuration');
var db = require('../../../db');
var kb = require('../../../utils/keyBuilder');
var models = require('../../../models');

var KEY_HISTORY = 'hist';
var KEY_LAST = 'last';

/**
 * GetLocationHistory
 * Retrieves the complete History
 * @param req
 * @param res
 * @param next
 */
function getLocationHistory(req, res, next) {
    var locationRequest = req.MIATARU.request;
    var key = kb.build(locationRequest.device(), KEY_HISTORY);

    seq()
        .par('listLength', function() {
            db.llen(key, this);
        })
        .par('list', function() {
            db.lrange(key, locationRequest.amount() * -1, -1, this);
        })
        .seq(function() {
            res.send((new models.ResponseLocationHistory(
                this.vars.listLength,
                configuration.maximumNumberOfHistoryItems,
                this.vars.list
            )).data());
        })
        .catch(function(error) {
            next(new errors.InternalServerError(error));
        });
}

/**
 * UpdateLocation
 * api endpoint that updates the currentLocation and a arbitrary number of history locations
 *
 * @param req
 * @param res
 * @param next
 */
function updateLocation(req, res, next) {
    var MIATARU = req.MIATARU;
    var requestConfig = MIATARU.config;
    var locations = MIATARU.locations;

    var chain = seq();

    if(requestConfig.enableLocationHistory()) {
        locations.forEach(function(loc, idx) {
            var value = JSON.stringify(loc.data());
            var historyKey = kb.build(loc.device(), KEY_HISTORY);
            var lastKey = kb.build(loc.device(), KEY_LAST);

            chain
                // we do want to store location history, so check if we got, so lpush and trim
                .seq(function() {
                    db.lpush(historyKey, value, this);
                })
                // take care that the location history does not grow beyond the set range of maximumNumberOfHistoryItems
                .seq(function() {
                    db.ltrim(historyKey, 0, configuration.maximumNumberOfHistoryItems-1, this);
                });

            if(idx === locations.length - 1) {
                // finally also update the last known location...
                chain.seq(function() {
                    db.set(lastKey, value, this);
                });
            }
        });
    } else {
        //we're only interested in the last item as we're not saving a history
        var loc = locations[locations.length-1];

        var timeToKeep = requestConfig.locationDataRetentionTime() * 60;
        var value = JSON.stringify(loc.data());

        seq()
            // we do not want to save a location history, this means if there's one we delete it...
            .par(function() {
                db.del(kb.build(loc.device(), KEY_HISTORY), this);
            })
            // update the last known location
            .par(function() {
                db.setex(kb.build(loc.device(), KEY_LAST), timeToKeep, value, this);
            });
    }

    chain
        .seq(function() {
            var eyes = ['x', '!', '^', '°'];
            res.send((new models.ResponseUpdateLocation(eyes[parseInt(Math.random() * eyes.length, 10)])).data());
        })
        .catch(next);
}

/**
 * GetLocation
 * This is used to get the current location of a device.
 *
 * @param req
 * @param res
 * @param next
 */
function getLocation(req, res, next) {
    var chain = seq();
    var response = new models.ResponseLocation();

    req.MIATARU.devices.forEach(function(device) {
        chain.par(function() {
            var done = this;

            db.get(kb.build(device.device(), KEY_LAST), function (error, reply) {
                if(error)  return done(error);

                response.pushLocation(JSON.parse(reply));
                done();
            });
        });
    });

    chain.seq(function() {
        res.send(response.data());
    })
    .catch(next);
}

module.exports = {
    updateLocation: updateLocation,
    getLocation: getLocation,
    getLocationHistory: getLocationHistory
};<|endoftext|>


<commit_before>/* exported Class, Module */

const GObject = imports.gi.GObject;
const Lang = imports.lang;

const Knowledge = imports.app.knowledge;

/**
 * Class: Class
 * Counterpart to Lang.Class for modules
 *
 * To create a new module, use this metaclass as you would use Lang.Class to
 * create a regular class:
 *
 * > const MyModule = new Module.Class({
 * >     Name: 'MyModule',
 * >     Extends: GObject.Object,
 * > });
 *
 * The <Module.Module> interface is implemented automatically even if you don't
 * specify it, since all modules must implement this interface.
 */
const Class = new Lang.Class({
    Name: 'Class',
    Extends: Knowledge.Class,

    _construct: function (props={}) {
        // Make sure Module is implemented before chaining
        props.Implements = props.Implements || [];
        if (props.Implements.indexOf(Module) === -1)
            props.Implements.unshift(Module);

        let slots = {};
        // Looking for a 'Slots' property on the interface's prototype allows us
        // to get away with not defining a separate meta-interface for module
        // interfaces. If we need something more fancy, such as freezing the
        // interface's slots object, we can switch later.
        props.Implements.forEach(iface =>
            Lang.copyProperties(iface.prototype.Slots, slots));
        Lang.copyProperties(props.Extends.__slots__, slots);
        Lang.copyProperties(props.Slots, slots);
        delete props.Slots;

        if (Object.keys(slots).some(name => name.indexOf('.') !== -1))
            throw new Error('Slot names should never contain a "."');

        let module = this.parent(props);

        Object.defineProperties(module, {
            '__slots__': {
                writable: false,
                configurable: false,
                enumerable: false,
                value: _freeze_recurse(slots),
            },
        });

        /**
         * Method: get_slot_names
         * Class method for listing names of slots
         *
         * Returns an array containing the names of slots offered by this module.
         */
        module.get_slot_names = function () {
            return Object.keys(this.__slots__);
        };

        return module;
    },
});

function _freeze_recurse(o) {
    Object.getOwnPropertyNames(o).forEach(prop => _freeze_recurse(o[prop]));
    return Object.freeze(o);
}

/**
 * Interface: Module
 */
const Module = new Lang.Interface({
    Name: 'Module',
    Requires: [ GObject.Object ],

    Properties: {
        /**
         * Property: factory
         *
         * The <ModuleFactory> widget that is used to construct and return
         * the module to its parent application. The type of this property
         * is flexible to allow for factory mocking in tests.
         */
        'factory': GObject.ParamSpec.object('factory', 'Factory', 'Factory',
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
            GObject.Object.$gtype),

        /**
         * Property: factory_name
         *
         * The factory_name is used to identify this module within the app.json. The
         * factory will use the factory_name to  return the appropriate submodules
         * for this module's slots.
         */
        'factory-name': GObject.ParamSpec.string('factory-name', 'Module Name', 'Module Name',
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
            ''),
    },

    /**
     * Method: create_submodule
     * Create a new instance of a submodule
     *
     * Creates an instance of a submodule through the factory, optionally adding
     * some construct properties.
     * This doesn't pack the submodule anywhere, just returns it.
     *
     * Properties:
     *   slot - the slot for which to create the module (string)
     *   extra_props - dictionary of construct properties
     */
    create_submodule: function (slot, extra_props={}) {
        return this.factory.create_module_for_slot(this, slot,
            extra_props);
    },
});
<commit_msg>module: allow non-object values in slots<commit_after>/* exported Class, Module */

const GObject = imports.gi.GObject;
const Lang = imports.lang;

const Knowledge = imports.app.knowledge;

/**
 * Class: Class
 * Counterpart to Lang.Class for modules
 *
 * To create a new module, use this metaclass as you would use Lang.Class to
 * create a regular class:
 *
 * > const MyModule = new Module.Class({
 * >     Name: 'MyModule',
 * >     Extends: GObject.Object,
 * > });
 *
 * The <Module.Module> interface is implemented automatically even if you don't
 * specify it, since all modules must implement this interface.
 */
const Class = new Lang.Class({
    Name: 'Class',
    Extends: Knowledge.Class,

    _construct: function (props={}) {
        // Make sure Module is implemented before chaining
        props.Implements = props.Implements || [];
        if (props.Implements.indexOf(Module) === -1)
            props.Implements.unshift(Module);

        let slots = {};
        // Looking for a 'Slots' property on the interface's prototype allows us
        // to get away with not defining a separate meta-interface for module
        // interfaces. If we need something more fancy, such as freezing the
        // interface's slots object, we can switch later.
        props.Implements.forEach(iface =>
            Lang.copyProperties(iface.prototype.Slots, slots));
        Lang.copyProperties(props.Extends.__slots__, slots);
        Lang.copyProperties(props.Slots, slots);
        delete props.Slots;

        if (Object.keys(slots).some(name => name.indexOf('.') !== -1))
            throw new Error('Slot names should never contain a "."');

        let module = this.parent(props);

        Object.defineProperties(module, {
            '__slots__': {
                writable: false,
                configurable: false,
                enumerable: false,
                value: _freeze_recurse(slots),
            },
        });

        /**
         * Method: get_slot_names
         * Class method for listing names of slots
         *
         * Returns an array containing the names of slots offered by this module.
         */
        module.get_slot_names = function () {
            return Object.keys(this.__slots__);
        };

        return module;
    },
});

function _freeze_recurse(o) {
    if (typeof o !== 'object')
        return o;
    Object.getOwnPropertyNames(o).forEach(prop => _freeze_recurse(o[prop]));
    return Object.freeze(o);
}

/**
 * Interface: Module
 */
const Module = new Lang.Interface({
    Name: 'Module',
    Requires: [ GObject.Object ],

    Properties: {
        /**
         * Property: factory
         *
         * The <ModuleFactory> widget that is used to construct and return
         * the module to its parent application. The type of this property
         * is flexible to allow for factory mocking in tests.
         */
        'factory': GObject.ParamSpec.object('factory', 'Factory', 'Factory',
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
            GObject.Object.$gtype),

        /**
         * Property: factory_name
         *
         * The factory_name is used to identify this module within the app.json. The
         * factory will use the factory_name to  return the appropriate submodules
         * for this module's slots.
         */
        'factory-name': GObject.ParamSpec.string('factory-name', 'Module Name', 'Module Name',
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
            ''),
    },

    /**
     * Method: create_submodule
     * Create a new instance of a submodule
     *
     * Creates an instance of a submodule through the factory, optionally adding
     * some construct properties.
     * This doesn't pack the submodule anywhere, just returns it.
     *
     * Properties:
     *   slot - the slot for which to create the module (string)
     *   extra_props - dictionary of construct properties
     */
    create_submodule: function (slot, extra_props={}) {
        return this.factory.create_module_for_slot(this, slot,
            extra_props);
    },
});
<|endoftext|>