<commit_before>/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2000-2012
//    by aixigo AG, Aachen, Germany.
//
//  All rights reserved. This material is confidential and proprietary to AIXIGO AG and no part of this
//  material should be reproduced, published in any form by any means, electronic or mechanical including
//  photocopy or any information storage or retrieval system nor should the material be disclosed to third
//  parties without the express written authorization of AIXIGO AG.
//
//  aixigo AG
//  http://www.aixigo.de
//  Aachen, Germany
//
/*jshint strict:false*//*global exports,console*/
var fsWatchTree = require( './../misc/multi_watch_tree' );
var fs = require( 'fs' );

exports.start = start;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

var rootDir_;
var entryFile_;
var sockets_ = {};
function start( app, rootDir, entryFile, watchedDirs ) {
   if( !entryFile || !watchedDirs.length ) {
      console.log( 'no watched dirs or entry file given' );
      return;
   }

   rootDir_ = rootDir;
   entryFile_ = entryFile;

   watchedDirs.forEach( function( dir ) {
      fsWatchTree.watchTree( rootDir + '/' + dir.replace( /^\//, '' ), handleFileChanged );
   } );

   app.get( '/' + entryFile.replace( /^\//, '' ), injectReloadingCode );

   app.get( 'io' ).sockets.on( 'connection', function( socket ) {
      sockets_[ socket.id ] = socket;
      socket.on( 'disconnect', function() {
         delete sockets_[ socket.id ];
      } );
   } );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

var timeout_;
function handleFileChanged( event ) {
   if( timeout_ ) {
      return;
   }

   // multiple changes should not result in multiple reloads. Therefore we wait a bit before reloading.
   timeout_ = setTimeout( function() {
      timeout_ = null;
      for( var key in sockets_ ) {
         if( sockets_.hasOwnProperty( key ) ) {
            sockets_[ key ].emit( 'reload' );
         }
      }
   }, 200 );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

function injectReloadingCode( req, res ) {
   fs.readFile( rootDir_ + req.path, function( err, data ) {
      if( err ) {
         res.send( 500, 'internal error: ' + err );
         return;
      }

      var html = String( data ).replace( '', createInjectionCode() + '' );
      res.type( 'text/html' );
      res.send( html );
   } );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

function createInjectionCode() {
   return '\n' +
      '';
}<commit_msg>- improved reloading code injection. - added reloading of spec runners.<commit_after>/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2000-2012
//    by aixigo AG, Aachen, Germany.
//
//  All rights reserved. This material is confidential and proprietary to AIXIGO AG and no part of this
//  material should be reproduced, published in any form by any means, electronic or mechanical including
//  photocopy or any information storage or retrieval system nor should the material be disclosed to third
//  parties without the express written authorization of AIXIGO AG.
//
//  aixigo AG
//  http://www.aixigo.de
//  Aachen, Germany
//
/*jshint strict:false*//*global exports,console*/
var fsWatchTree = require( './../misc/multi_watch_tree' );
var fs = require( 'fs' );

exports.start = start;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

var rootDir_;
var entryFile_;
var sockets_ = {};
function start( app, rootDir, entryFile, watchedDirs ) {
   if( !entryFile || !watchedDirs.length ) {
      console.log( 'no watched dirs or entry file given' );
      return;
   }

   rootDir_ = rootDir;
   entryFile_ = entryFile;

   watchedDirs.forEach( function( dir ) {
      fsWatchTree.watchTree( rootDir + '/' + dir.replace( /^\//, '' ), handleFileChanged );
   } );

   app.get( '/' + entryFile.replace( /^\//, '' ), injectReloadingCode );

   // NEEDS FIX B: This should be configurable as well.
   app.get( /(.+)\/(spec_runner\.html)$/, injectReloadingCode );

   app.get( 'io' ).sockets.on( 'connection', function( socket ) {
      sockets_[ socket.id ] = socket;
      socket.on( 'disconnect', function() {
         delete sockets_[ socket.id ];
      } );
   } );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

var timeout_;
function handleFileChanged( event ) {
   if( timeout_ ) {
      return;
   }

   // multiple changes should not result in multiple reloads. Therefore we wait a bit before reloading.
   timeout_ = setTimeout( function() {
      timeout_ = null;
      for( var key in sockets_ ) {
         if( sockets_.hasOwnProperty( key ) ) {
            sockets_[ key ].emit( 'reload' );
         }
      }
   }, 200 );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

function injectReloadingCode( req, res ) {
   fs.readFile( rootDir_ + req.path, function( err, data ) {
      if( err ) {
         res.send( 500, 'internal error: ' + err );
         return;
      }

      var html = String( data ).replace( /(]*>)([\S\s]*)(<\/head>)/igm,
                                         function( match, headStart, headContent, headEnd ) {
         if( headContent.indexOf( '\n' +
      '';
}<|endoftext|>


<commit_before>var test = require('tap').test;

var tconsole = require('../index');

function Person(first, last, age) {
  this.first = first;
  this.last = last;
  this.age = age;
}

var personFields = {
  'First': function() { return this.first; },
  'Last': function() { return this.last; },
  'Name': function() { return this.first+' '+this.last; },
  'Age': function() { return this.age; }
};

var config = {
  'person': {
    test: function() {
      return (this instanceof Person);
    },
    fields: personFields,
    defaultFields: [
      'Name',
      'Age'
    ]
  },
  'array:person': {
    defaultFields: [
      'First',
      'Last',
      'Age'
    ]
  }
};

test('has same footprint as console', function(t) {
  var konsole = tconsole({});

  for (var key in console) {
    t.ok(konsole.hasOwnProperty(key));
  }

  t.end();
});

test('.toString', function(t) {
  var konsole = tconsole({});

  t.ok(konsole.hasOwnProperty('toString'));
  t.type(konsole.toString, 'function');

  t.end();
});

test('Example: Person', function(t) {
  var harry = new Person('Harry', 'Potter');

  var konsole = tconsole(config);

  t.equal(konsole.toString(harry), '┌──────┬──────────────┐\n│ Name │ Harry Potter │\n├──────┼──────────────┤\n│ Age  │              │\n└──────┴──────────────┘');
  t.end();
});

test('Example: Array of Person', function(t) {
  var harry = new Person('Harry', 'Potter');
  var sirius = new Person('Sirius', 'Black', 37);

  var konsole = tconsole(config);

  t.equal(konsole.toString([ harry, sirius ]), '┌────────┬────────┬─────┐\n│ First  │ Last   │ Age │\n├────────┼────────┼─────┤\n│ Harry  │ Potter │     │\n├────────┼────────┼─────┤\n│ Sirius │ Black  │ 37  │\n└────────┴────────┴─────┘')

  t.end();
});

<commit_msg>Add test for Date object<commit_after>var test = require('tap').test;

var tconsole = require('../index');
var combine = require('../combine');

function Person(first, last, age) {
  this.first = first;
  this.last = last;
  this.age = age;
}

var personFields = {
  'First': function() { return this.first; },
  'Last': function() { return this.last; },
  'Name': function() { return this.first+' '+this.last; },
  'Age': function() { return this.age; },
};

var personConfig = {
  'person': {
    test: function() {
      return (this instanceof Person);
    },
    fields: personFields,
    defaultFields: [
      'Name',
      'Age'
    ],
  },
  'array:person': {
    defaultFields: [
      'First',
      'Last',
      'Age'
    ],
  },
};

var dateConfig = {
  'date': {
    test: function() {
      return (this instanceof Date);
    },
    fields: {
      'Date': function() { return this.getDate(); },
      'Year': function() { return this.getFullYear(); },
      'Month': function() { return this.getMonth()+1; },
    }
  }
};

test('has same footprint as console', function(t) {
  var konsole = tconsole({});

  for (var key in console) {
    t.ok(konsole.hasOwnProperty(key));
  }

  t.end();
});

test('.toString', function(t) {
  var konsole = tconsole({});

  t.ok(konsole.hasOwnProperty('toString'));
  t.type(konsole.toString, 'function');

  t.end();
});

test('Example: Person', function(t) {
  var harry = new Person('Harry', 'Potter');

  var konsole = tconsole(personConfig);

  t.equal(konsole.toString(harry), '┌──────┬──────────────┐\n│ Name │ Harry Potter │\n├──────┼──────────────┤\n│ Age  │              │\n└──────┴──────────────┘');
  t.end();
});

test('Example: Array of Person', function(t) {
  var harry = new Person('Harry', 'Potter');
  var sirius = new Person('Sirius', 'Black', 37);

  var konsole = tconsole(personConfig);

  t.equal(konsole.toString([ harry, sirius ]), '┌────────┬────────┬─────┐\n│ First  │ Last   │ Age │\n├────────┼────────┼─────┤\n│ Harry  │ Potter │     │\n├────────┼────────┼─────┤\n│ Sirius │ Black  │ 37  │\n└────────┴────────┴─────┘');

  t.end();
});

test('Example: Date', function(t) {
  // Sun Jan 18 2015 22:30:30 GMT+0100 (CET)
  var date = new Date(1421616630508);

  var konsole = tconsole(dateConfig);

  t.equal(konsole.toString(date), '┌───────┬──────┐\n\│ Date  │ 18   │\n├───────┼──────┤\n│ Year  │ 2015 │\n├───────┼──────┤\n│ Month │ 1    │\n└───────┴──────┘');

  t.end();
});
<|endoftext|>


<commit_before>(function () {
	'use strict';

	angular
		.module('core')
		.run(routeFilter);

	routeFilter.$inject = ['$transitions', '$state', '$stateParams', 'Authentication', 'OrgsService'];

	function routeFilter($transitions, $state, $stateParams, Authentication, OrgsService) {

		// Store previous state
		function storePreviousState(state, params) {
			// only store this state if it shouldn't be ignored
			if (!state.data || !state.data.ignoreState) {
				$state.previous = {
					state: state,
					params: params,
					href: $state.href(state, params)
				};
			}
		}

		// Route filter for org editing - makes sure current user is admin when routing to org editing views
		$transitions.onStart({ to: 'orgadmin.**'}, function(trans) {

			return new Promise(function(resolve, reject) {
				// If not signed redirect to sign-in
				if (!Authentication.user) {
					storePreviousState(trans.to(), trans.params('to'));
					resolve($state.target('authentication.signin'));
				}

				// Wait for the org to resolve on the route
				trans.injector().getAsync('org')
				.then(function(org) {
					if (org.admins.map(function(admin) { return admin._id; }).indexOf(Authentication.user._id) < 0) {
						resolve($state.target('forbidden'));
					}
					else {
						resolve();
					}
				});
			})
		});

		// Main route filter - checks for allowed/denied roles and redirects apppropriately
		$transitions.onStart({}, function(trans) {
			var userRoles = (Authentication.user && Authentication.user.roles !== undefined) ? Authentication.user.roles : ['guest'];
			var toState = trans.to();

			var allowedRoles = (toState.data && toState.data.roles) ? toState.data.roles : [];
			var deniedRoles = (toState.data && toState.data.notroles) ? toState.data.notrole : [];

			var userHasAccess = true;
			if (allowedRoles.length > 0) {
				userHasAccess = false;
				allowedRoles.forEach(function(allowedRole) {
					if (allowedRole === 'guest' || userRoles.indexOf(allowedRole) >= 0) {
						userHasAccess = true;
					}
				});
			}

			if (deniedRoles && deniedRoles.length > 0) {
				deniedRoles.forEach(function(deniedRole) {
					if (userRoles.indexOf(deniedRole) >= 0) {
						userHasAccess = false;
					}
				});
			}

			// If the user does not have access to this route do one of the following
			// Redirect to sign-in if they haven't authenticated
			// Redirect to 'Forbidden' if they aren't authorized
			if (!userHasAccess) {
				if (!Authentication.user) {
					storePreviousState(toState, trans.params('to'));
					return $state.target('authentication.signin');
				}
				else {
					return $state.target('forbidden');
				}
			}

		});
	}
}());
<commit_msg>BA-980 - Clean-up client route filtering<commit_after>(function () {
	'use strict';

	angular
		.module('core')
		.run(routeFilter);

	routeFilter.$inject = ['$transitions', '$state', 'Authentication'];

	function routeFilter($transitions, $state, Authentication) {

		// Store previous state
		function storePreviousState(state, params) {
			// only store this state if it shouldn't be ignored
			if (!state.data || !state.data.ignoreState) {
				$state.previous = {
					state: state,
					params: params,
					href: $state.href(state, params)
				};
			}
		}

		// Route filter for org editing - makes sure current user is admin when routing to org editing views
		$transitions.onStart({ to: 'orgadmin.**'}, function(trans) {

			return new Promise(function(resolve, reject) {
				// If not signed redirect to sign-in
				if (!Authentication.user) {
					storePreviousState(trans.to(), trans.params('to'));
					resolve($state.target('authentication.signin'));
				}

				// Wait for the org to resolve on the route
				trans.injector().getAsync('org')
				.then(function(org) {
					if (org.admins.map(function(admin) { return admin._id; }).indexOf(Authentication.user._id) < 0) {
						resolve($state.target('forbidden'));
					}
					else {
						resolve();
					}
				});
			})
		});

		// Main route filter - checks for allowed/denied roles and redirects apppropriately
		$transitions.onStart({}, function(trans) {
			var userRoles = (Authentication.user && Authentication.user.roles !== undefined) ? Authentication.user.roles : ['guest'];
			var toState = trans.to();

			var allowedRoles = (toState.data && toState.data.roles) ? toState.data.roles : [];
			var deniedRoles = (toState.data && toState.data.notroles) ? toState.data.notrole : [];

			var userHasAccess = true;
			if (allowedRoles.length > 0) {
				userHasAccess = false;
				allowedRoles.forEach(function(allowedRole) {
					if (allowedRole === 'guest' || userRoles.indexOf(allowedRole) >= 0) {
						userHasAccess = true;
					}
				});
			}

			if (deniedRoles && deniedRoles.length > 0) {
				deniedRoles.forEach(function(deniedRole) {
					if (userRoles.indexOf(deniedRole) >= 0) {
						userHasAccess = false;
					}
				});
			}

			// If the user does not have access to this route do one of the following
			// Redirect to sign-in if they haven't authenticated
			// Redirect to 'Forbidden' if they aren't authorized
			if (!userHasAccess) {
				if (!Authentication.user) {
					storePreviousState(toState, trans.params('to'));
					return $state.target('authentication.signin');
				}
				else {
					return $state.target('forbidden');
				}
			}

		});
	}
}());
<|endoftext|>


<commit_before>import React from 'react'
import Page from 'components/Page'
import History from 'components/History'
import autobind from 'autobind-decorator'

import {ContentForHeader} from 'components/Header'
import Breadcrumbs from 'components/Breadcrumbs'
import ReportForm from 'components/ReportForm'

import API from 'api'
import {Report} from 'models'

export default class ReportNew extends Page {
	static pageProps = {
		useNavigation: false
	}

	static contextTypes = {
		app: React.PropTypes.object,
	}

	constructor(props, context) {
		super(props)

		this.state = {
			report: new Report(),

			recents: {
				persons: [],
				locations: [],
				poams: [],
			},
			currentUser: null
		}
	}

	fetchData() {
		API.query(/* GraphQL */`
			locations(f:recents) {
				id, name
			}
			persons(f:recents) {
				id, name, rank, role
			}
			poams(f:recents) {
				id, shortName, longName
			}
		`).then(data => this.setState({recents: data}))
	}

	//use this to auto add the author to the report attendees
	componentWillReceiveProps(nextProps, nextContext) {
		this.tryToAddAuthor()
	}

	componentDidMount() {
		this.fetchData(this.props)
		this.tryToAddAuthor()
	}

	@autobind
	tryToAddAuthor() {
		let currUser = this.state.currentUser
		let newUser = this.context.app.state && this.context.app.state.currentUser

		let currUserId = currUser && currUser.id
		let newUserId = newUser && newUser.id

		if (newUserId && newUserId !== currUserId) {
			console.log('updating', currUser, newUser);
			let report = this.state.report
			newUser.primary = true
			report.attendees.push(newUser)
			this.setState({report: report})
		} else {
			console.log('notUpdating', currUser, newUser);
		}

	}

	render() {
		let {report, recents} = this.state
		return (

				<ContentForHeader>

Create a new Report

				</ContentForHeader>

				<Breadcrumbs items={[['Submit a report', Report.pathForNew()]]} />

				<ReportForm report={report}
					recents={recents}
					onChange={this.onChange}
					onSubmit={this.onSubmit}
					error={this.state.error}
					actionText="Save report" />

		)
	}

	@autobind
	onChange() {
		let report = this.state.report
		this.setState({report})
	}

	@autobind
	onSubmit(event) {
		event.stopPropagation()
		event.preventDefault()

		let report = this.state.report

		if(report.primaryAdvisor) { report.attendees.find(a => a.id === report.primaryAdvisor.id).isPrimary = true; }
		if(report.primaryPrincipal) { report.attendees.find(a => a.id === report.primaryPrincipal.id).isPrimary = true; }

		delete report.primaryPrincipal
		delete report.primaryAdvisor

		API.send('/api/reports/new', report)
			.then(report => {
				History.push(Report.pathFor(report))
				window.scrollTo(0, 0)
			})
			.catch(response => {
				this.setState({error: response.message})
				window.scrollTo(0, 0)
			})
	}

}
<commit_msg>Clear Report state when a new Report New form is mounted.  Fixes #133<commit_after>import React from 'react'
import Page from 'components/Page'
import History from 'components/History'
import autobind from 'autobind-decorator'

import {ContentForHeader} from 'components/Header'
import Breadcrumbs from 'components/Breadcrumbs'
import ReportForm from 'components/ReportForm'

import API from 'api'
import {Report} from 'models'

export default class ReportNew extends Page {
	static pageProps = {
		useNavigation: false
	}

	static contextTypes = {
		app: React.PropTypes.object,
	}

	constructor(props, context) {
		super(props)

		this.state = {
			report: new Report(),

			recents: {
				persons: [],
				locations: [],
				poams: [],
			},
			currentUser: null
		}
	}

	fetchData() {
		API.query(/* GraphQL */`
			locations(f:recents) {
				id, name
			}
			persons(f:recents) {
				id, name, rank, role
			}
			poams(f:recents) {
				id, shortName, longName
			}
		`).then(data => this.setState({recents: data, report: new Report()}))
	}

	//use this to auto add the author to the report attendees
	componentWillReceiveProps(nextProps, nextContext) {
		this.tryToAddAuthor()
	}

	componentDidMount() {
		this.fetchData(this.props)
		this.tryToAddAuthor()
	}

	@autobind
	tryToAddAuthor() {
		let currUser = this.state.currentUser
		let newUser = this.context.app.state && this.context.app.state.currentUser

		let currUserId = currUser && currUser.id
		let newUserId = newUser && newUser.id

		if (newUserId && newUserId !== currUserId) {
			console.log('updating', currUser, newUser);
			let report = this.state.report
			newUser.primary = true
			report.attendees.push(newUser)
			this.setState({report: report})
		} else {
			console.log('notUpdating', currUser, newUser);
		}

	}

	render() {
		let {report, recents} = this.state
		return (

				<ContentForHeader>

Create a new Report

				</ContentForHeader>

				<Breadcrumbs items={[['Submit a report', Report.pathForNew()]]} />

				<ReportForm report={report}
					recents={recents}
					onChange={this.onChange}
					onSubmit={this.onSubmit}
					error={this.state.error}
					actionText="Save report" />

		)
	}

	@autobind
	onChange() {
		let report = this.state.report
		this.setState({report})
	}

	@autobind
	onSubmit(event) {
		event.stopPropagation()
		event.preventDefault()

		let report = this.state.report

		if(report.primaryAdvisor) { report.attendees.find(a => a.id === report.primaryAdvisor.id).isPrimary = true; }
		if(report.primaryPrincipal) { report.attendees.find(a => a.id === report.primaryPrincipal.id).isPrimary = true; }

		delete report.primaryPrincipal
		delete report.primaryAdvisor

		API.send('/api/reports/new', report)
			.then(report => {
				History.push(Report.pathFor(report))
				window.scrollTo(0, 0)
			})
			.catch(response => {
				this.setState({error: response.message})
				window.scrollTo(0, 0)
			})
	}

}
<|endoftext|>


<commit_before>'use strict';

const util = require('util');

const aws = require('aws-sdk');

const lambda = new aws.Lambda({ apiVersion: '2015-03-31', region: 'ap-northeast-1' });
const dynamodb = new aws.DynamoDB({ apiVersion: '2012-08-10', region: 'ap-northeast-1' });
const dynamodbClient = new aws.DynamoDB.DocumentClient({ service: dynamodb });

function loadPreference(keys) {
  return new Promise((resolve, reject) => {
    const realKeys = [];

    if (util.isString(keys)) {
      realKeys.push({ name: keys });
    } else if (util.isArray(keys)) {
      for (const keyName of keys) {
        realKeys.push({ name: keyName });
      }
    } else {
      throw new Error('Invalid keys');
    }

    const params = {
      RequestItems: {
        CodeTengu_Preference: {
          Keys: realKeys,
        },
      },
    };

    dynamodbClient.batchGet(params, (err, data) => {
      if (err) {
        console.log('FAIL');
        console.log(util.inspect(err));

        reject(err);
      } else {
        const response = {};

        for (const config of data.Responses.CodeTengu_Preference) {
          response[config.name] = config;
        }

        resolve(response);
      }
    });
  });
}

function checkHTTPStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  }

  throw new Error(`HTTP ${response.status}`);
}

module.exports = {
  lambda,
  dynamodbClient,
  loadPreference,
  checkHTTPStatus,
};
<commit_msg>add utils.invokeLambdaFunction()<commit_after>'use strict';

const util = require('util');

const aws = require('aws-sdk');

const lambda = new aws.Lambda({ apiVersion: '2015-03-31', region: 'ap-northeast-1' });
const dynamodb = new aws.DynamoDB({ apiVersion: '2012-08-10', region: 'ap-northeast-1' });
const dynamodbClient = new aws.DynamoDB.DocumentClient({ service: dynamodb });

function invokeLambdaFunction(funcName, payload) {
  return new Promise((resolve, reject) => {
    const params = {
      FunctionName: funcName,
      InvocationType: 'Event', // asynchronous execution
      Payload: JSON.stringify(payload),
    };

    lambda.invoke(params, (err, data) => {
      if (err) {
        console.log('FAIL', params);
        console.log(util.inspect(err));

        reject(err);
      } else {
        resolve(data);
      }
    });
  });
}

function loadPreference(keys) {
  return new Promise((resolve, reject) => {
    const realKeys = [];

    if (util.isString(keys)) {
      realKeys.push({ name: keys });
    } else if (util.isArray(keys)) {
      for (const keyName of keys) {
        realKeys.push({ name: keyName });
      }
    } else {
      throw new Error('Invalid keys');
    }

    const params = {
      RequestItems: {
        CodeTengu_Preference: {
          Keys: realKeys,
        },
      },
    };

    dynamodbClient.batchGet(params, (err, data) => {
      if (err) {
        console.log('FAIL');
        console.log(util.inspect(err));

        reject(err);
      } else {
        const response = {};

        for (const config of data.Responses.CodeTengu_Preference) {
          response[config.name] = config;
        }

        resolve(response);
      }
    });
  });
}

function checkHTTPStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  }

  throw new Error(`HTTP ${response.status}`);
}

module.exports = {
  lambda,
  invokeLambdaFunction,
  dynamodbClient,
  loadPreference,
  checkHTTPStatus,
};
<|endoftext|>


<commit_before>(function() {
  // Global settings
  var el = "#admissions .d3-viz";
  var w = $('#admissions .d3-viz').width(),
      h = 300,
      xPadding = 50,
      yPadding = 30
      ;

  // Initialize SVG
  var svg = d3.select(el)
    .append("svg:svg")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("viewBox", "0 0 " + w + " " + h)
    .attr("preserveAspectRatio", "xMinYMin meet")
    ;

  // Datasets
  var datasets = $("#admissions table.table").tabulate();
  var applicants = datasets[0];
  var admissions = datasets[1];
  var enrollment = datasets[2];

  // Scales
  var minYear = d3.min(applicants, function(d) { return d.x; });
  var maxYear = d3.max(applicants, function(d) { return d.x; });
  var maxApplicants = d3.max(applicants, function(d) { return d.y; });
  var minAdmissions = d3.min(admissions, function(d) { return d.y; });
  var maxAdmissions = d3.max(admissions, function(d) { return d.y; });
  var rScale = d3.scale.linear().domain([0, maxAdmissions]).range([h - yPadding, yPadding]);
  var xScale = d3.scale.linear().domain([minYear, maxYear]).range([xPadding, w]);
  var yScale = d3.scale.linear().domain([0, maxApplicants]).range([h - yPadding, yPadding]);
  var barWidth = w / (maxYear - minYear) - 30;

  // Axes,
  var yearFormat = d3.format("4d");
  var xAxis = d3.svg.axis().scale(xScale).orient("bottom").tickSize(6, 1, 1).tickFormat(yearFormat);
  var yAxis = d3.svg.axis().scale(yScale).orient("left").ticks(5);

  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(" + (barWidth / 2 + 20) + ", " + (h - yPadding) + ")")
    .call(xAxis);

  svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate(" + xPadding + ", 0)")
    .call(yAxis);

  // Attrs
  function xN(d, i, n) {
    return xScale(d.x) + (n * 10);
  }

  function y(d) {
    return yScale(d.y) - yPadding;
  }

  function height(d) {
    return h - yScale(d.y);
  }

  function rY(d) {
    return rScale(d.y) - yPadding;
  }

  function rHeight(d) {
    return h - rScale(d.y);
  }

  var applicantsG = svg.append("g");

  // Render applicants
  applicantsG
    .selectAll("rect")
    .data(applicants)
    .enter()
    .append("rect")
    .attr("fill", "#99CCFF")
    .attr("width", barWidth)
    .attr("height", height)
    .attr("x", function(d, i) { return xN(d, i, 0); })
    .attr("y", y)
    ;

  // Render admissions
  svg.append("g")
    .selectAll("rect")
    .data(admissions)
    .enter()
    .append("rect")
    .attr("fill", "#3399CC")
    .attr("width", barWidth)
    .attr("height", height)
    .attr("x", function(d, i) { return xN(d, i, 1); })
    .attr("y", y)
    ;

  // Render enrollment
  svg.append("g")
    .selectAll("rect")
    .data(enrollment)
    .enter()
    .append("rect")
    .attr("fill", "#003366")
    .attr("width", barWidth)
    .attr("height", height)
    .attr("x", function(d, i) { return xN(d, i, 2); })
    .attr("y", y)
    ;

  // Toggle zoom
  $("#admissions a.zoom").toggle(function(e) {
    e.preventDefault();
    svg.selectAll("rect")
      .transition()
      .attr("y", rY)
      .attr("height", rHeight);
    svg.select("g.y.axis")
      .transition()
      .call(yAxis.scale(rScale));
    $(this).children("i").attr("class", "icon-minus");
  }, function(e) {
    e.preventDefault();
    svg.selectAll("rect")
      .transition()
      .attr("y", y)
      .attr("height", height);
    svg.select("g.y.axis")
      .transition()
      .call(yAxis.scale(yScale));
    $(this).children("i").attr("class", "icon-plus");
  });

  // Tooltip
  $('#admissions rect').tooltip({
    title: function(){
      var d = this.__data__;
      return d.series + " (" + d.x + "):
" + d.y + "";
    }
  });
})();
<commit_msg>fix admissions chart didn't clear loading state<commit_after>(function() {
  // Global settings
  var el = "#admissions .d3-viz";
  var w = $(el).removeClass('loading').width(),  // HAHAHAHAHAHA
      h = 300,
      xPadding = 50,
      yPadding = 30
      ;

  // Initialize SVG
  var svg = d3.select(el)
    .append("svg:svg")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("viewBox", "0 0 " + w + " " + h)
    .attr("preserveAspectRatio", "xMinYMin meet")
    ;

  // Datasets
  var datasets = $("#admissions table.table").tabulate();
  var applicants = datasets[0];
  var admissions = datasets[1];
  var enrollment = datasets[2];

  // Scales
  var minYear = d3.min(applicants, function(d) { return d.x; });
  var maxYear = d3.max(applicants, function(d) { return d.x; });
  var maxApplicants = d3.max(applicants, function(d) { return d.y; });
  var minAdmissions = d3.min(admissions, function(d) { return d.y; });
  var maxAdmissions = d3.max(admissions, function(d) { return d.y; });
  var rScale = d3.scale.linear().domain([0, maxAdmissions]).range([h - yPadding, yPadding]);
  var xScale = d3.scale.linear().domain([minYear, maxYear]).range([xPadding, w]);
  var yScale = d3.scale.linear().domain([0, maxApplicants]).range([h - yPadding, yPadding]);
  var barWidth = w / (maxYear - minYear) - 30;

  // Axes,
  var yearFormat = d3.format("4d");
  var xAxis = d3.svg.axis().scale(xScale).orient("bottom").tickSize(6, 1, 1).tickFormat(yearFormat);
  var yAxis = d3.svg.axis().scale(yScale).orient("left").ticks(5);

  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(" + (barWidth / 2 + 20) + ", " + (h - yPadding) + ")")
    .call(xAxis);

  svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate(" + xPadding + ", 0)")
    .call(yAxis);

  // Attrs
  function xN(d, i, n) {
    return xScale(d.x) + (n * 10);
  }

  function y(d) {
    return yScale(d.y) - yPadding;
  }

  function height(d) {
    return h - yScale(d.y);
  }

  function rY(d) {
    return rScale(d.y) - yPadding;
  }

  function rHeight(d) {
    return h - rScale(d.y);
  }

  var applicantsG = svg.append("g");

  // Render applicants
  applicantsG
    .selectAll("rect")
    .data(applicants)
    .enter()
    .append("rect")
    .attr("fill", "#99CCFF")
    .attr("width", barWidth)
    .attr("height", height)
    .attr("x", function(d, i) { return xN(d, i, 0); })
    .attr("y", y)
    ;

  // Render admissions
  svg.append("g")
    .selectAll("rect")
    .data(admissions)
    .enter()
    .append("rect")
    .attr("fill", "#3399CC")
    .attr("width", barWidth)
    .attr("height", height)
    .attr("x", function(d, i) { return xN(d, i, 1); })
    .attr("y", y)
    ;

  // Render enrollment
  svg.append("g")
    .selectAll("rect")
    .data(enrollment)
    .enter()
    .append("rect")
    .attr("fill", "#003366")
    .attr("width", barWidth)
    .attr("height", height)
    .attr("x", function(d, i) { return xN(d, i, 2); })
    .attr("y", y)
    ;

  // Toggle zoom
  $("#admissions a.zoom").toggle(function(e) {
    e.preventDefault();
    svg.selectAll("rect")
      .transition()
      .attr("y", rY)
      .attr("height", rHeight);
    svg.select("g.y.axis")
      .transition()
      .call(yAxis.scale(rScale));
    $(this).children("i").attr("class", "icon-minus");
  }, function(e) {
    e.preventDefault();
    svg.selectAll("rect")
      .transition()
      .attr("y", y)
      .attr("height", height);
    svg.select("g.y.axis")
      .transition()
      .call(yAxis.scale(yScale));
    $(this).children("i").attr("class", "icon-plus");
  });

  // Tooltip
  $('#admissions rect').tooltip({
    title: function(){
      var d = this.__data__;
      return d.series + " (" + d.x + "):
" + d.y + "";
    }
  });
})();
<|endoftext|>


<commit_before>define(
  'mapObjectsViewModel',
  ['underscore', 'backbone', 'mapObjectsDictionary'],
  function(_, Backbone, MapObjectsDictionary) {

  'use strict'

  /*
  * View-Model object for map objects view.
  */
  var MapObjectsViewModel = Backbone.Model.extend({

    /*
    * Default values for view model.
    */
    defaults: {
      graduality: 10,
      speed: 150
    },

    /*
    * Backbone model initialization.
    */
    initialize: function() {
      // Initialize sub-models
      this.map = new GMaps({ div: '#map', lat: 0, lng: 0, zoom: 2 });
      this.collection = new MapObjectsDictionary({ map: this.map });

      this.collection
        .on('add', function(model) {
          model.on(
            'change:showObject',
            function(model, showObject) {
              if (showObject) {
                model.calculatePos(this.currentTime(), this.realtime())
              }
            }.bind(this));
        }.bind(this))
        .on('remove', function(model) {
          model.clearPos();
        });
    },

    /*
    * Set current time for view model.
    *
    * Method update each object on map and ask them to recalculate their
    * positions.
    */
    currentTime: function(value) {
      if (!_.isUndefined(value)) {
        this.set('currentTime', value);
        this.collection.each(function(obj) {
          if (obj.showObject()) {
            obj.calculatePos(value, this.realtime());
          }
        }.bind(this));
      }

      return this.get('currentTime');
    },

    /*
    * Set begin time of current view model.
    * @param time - timestamp.
    */
    setBeginTime: function(time) {
      this.set('beginTime', time);
    },

    /*
    * Set end time of current view model.
    * @param time - timestamp.
    */
    setEndTime: function(time) {
      this.set('endTime', time);
    },

    /*
    * Add objects on the map.
    * @param data - array of { obj: [obj fields], point: { ts: [float], lat: [float], lon: [float]}}.
    */
    addDataPoints: function(data) {
      var beginTime = this.has('beginTime') ? this.get('beginTime') : null;
      var endTime = this.has('endTime') ? this.get('endTime') : null;
      var currentTime = this.currentTime();
      var realtime = this.realtime();
      _.each(data, function(p) {
        if (!realtime || !currentTime || currentTime < p.point.ts) {
          beginTime = Math.min(p.point.ts, beginTime || p.point.ts);
          endTime = Math.max(p.point.ts, endTime || p.point.ts);
          this.collection.addData(p.obj, p.point);
        }
      }.bind(this));
      if (beginTime) this.set('beginTime', beginTime);
      if (endTime) this.set('endTime', endTime);
    },

    /*
    * Add object on the map.
    * @param obj - object located on this point.
    * @param point - position of the object in time { ts: [float], lat: [float], lon: [float]}
    */
    addData: function(obj, point) {
      this.set('beginTime', !this.has('beginTime') ? point.ts : Math.min(point.ts, this.get('beginTime')));
      this.set('endTime', !this.has('endTime') ? point.ts : Math.max(point.ts, this.get('endTime')));
      return this.collection.addData(obj, point);
    },

    /*
    * Remove all tracking objects.
    */
    removeAllObjects: function() {
      this.pause();
      this.collection.reset();
      this.unset({currentTime: null, beginTime: null, endTime: null});
    },

    /*
    * Start playback of all objects on map.
    *
    * In case of realtime we just move all system to latest known point in time.
    */
    play: function() {
      if (!this.has('beginTime') || !this.has('endTime') || this.has('playInterval')) {
        // No objects or already in play mode
        return;
      }

      if (this.realtime()) {
        this.currentTime(this.get('endTime'));
      } else {
        if (!this.has('currentTime')) {
          this.currentTime(this.get('beginTime'));
        }

        this.set('playInterval', setInterval(function() {
          this.currentTime(this.currentTime() + (this.get('speed') / this.get('graduality')));
          if (this.currentTime() > this.get('endTime')) {
            this.pause();
          }
        }.bind(this), (1000 / this.get('graduality'))));
      }
    },

    /*
    * Pause playback.
    */
    pause: function() {
      if (this.has('playInterval')) {
        clearInterval(this.get('playInterval'));
        this.unset('playInterval');
      }
    },

    /*
    * Auto-zoom map to area of selected objects.
    */
    autoZoom: function() {
      // Calculate bounds of all visible objects
      var bounds = new google.maps.LatLngBounds();
      this.collection.each(function(model) {
        if (model.showObject()) {
          var points = model.getPoints();
          _.each(points, function(point) {
            bounds.extend(new google.maps.LatLng(point.lat, point.lon))
          });
        }
      });

      this.map.fitBounds(bounds);
    },

    /*
    * Gets or sets if current view is in realtime.
    */
    realtime: function(value) {
      if (!_.isUndefined(value)) {
        if (value) {
          this.pause();
        }
        this.set('realtime', value);
      }

      return this.get('realtime');
    }
  });

  return MapObjectsViewModel;
});<commit_msg>Auto zoom to routes and objects<commit_after>define(
  'mapObjectsViewModel',
  ['underscore', 'backbone', 'mapObjectsDictionary'],
  function(_, Backbone, MapObjectsDictionary) {

  'use strict'

  /*
  * View-Model object for map objects view.
  */
  var MapObjectsViewModel = Backbone.Model.extend({

    /*
    * Default values for view model.
    */
    defaults: {
      graduality: 10,
      speed: 150
    },

    /*
    * Backbone model initialization.
    */
    initialize: function() {
      // Initialize sub-models
      this.map = new GMaps({ div: '#map', lat: 0, lng: 0, zoom: 2 });
      this.collection = new MapObjectsDictionary({ map: this.map });

      this.collection
        .on('add', function(model) {
          model.on(
            'change:showObject',
            function(model, showObject) {
              if (showObject) {
                model.calculatePos(this.currentTime(), this.realtime())
              }
            }.bind(this));
        }.bind(this))
        .on('remove', function(model) {
          model.clearPos();
        });
    },

    /*
    * Set current time for view model.
    *
    * Method update each object on map and ask them to recalculate their
    * positions.
    */
    currentTime: function(value) {
      if (!_.isUndefined(value)) {
        this.set('currentTime', value);
        this.collection.each(function(obj) {
          if (obj.showObject()) {
            obj.calculatePos(value, this.realtime());
          }
        }.bind(this));
      }

      return this.get('currentTime');
    },

    /*
    * Set begin time of current view model.
    * @param time - timestamp.
    */
    setBeginTime: function(time) {
      this.set('beginTime', time);
    },

    /*
    * Set end time of current view model.
    * @param time - timestamp.
    */
    setEndTime: function(time) {
      this.set('endTime', time);
    },

    /*
    * Add objects on the map.
    * @param data - array of { obj: [obj fields], point: { ts: [float], lat: [float], lon: [float]}}.
    */
    addDataPoints: function(data) {
      var beginTime = this.has('beginTime') ? this.get('beginTime') : null;
      var endTime = this.has('endTime') ? this.get('endTime') : null;
      var currentTime = this.currentTime();
      var realtime = this.realtime();
      _.each(data, function(p) {
        if (!realtime || !currentTime || currentTime < p.point.ts) {
          beginTime = Math.min(p.point.ts, beginTime || p.point.ts);
          endTime = Math.max(p.point.ts, endTime || p.point.ts);
          this.collection.addData(p.obj, p.point);
        }
      }.bind(this));
      if (beginTime) this.set('beginTime', beginTime);
      if (endTime) this.set('endTime', endTime);
    },

    /*
    * Add object on the map.
    * @param obj - object located on this point.
    * @param point - position of the object in time { ts: [float], lat: [float], lon: [float]}
    */
    addData: function(obj, point) {
      this.set('beginTime', !this.has('beginTime') ? point.ts : Math.min(point.ts, this.get('beginTime')));
      this.set('endTime', !this.has('endTime') ? point.ts : Math.max(point.ts, this.get('endTime')));
      return this.collection.addData(obj, point);
    },

    /*
    * Remove all tracking objects.
    */
    removeAllObjects: function() {
      this.pause();
      this.collection.reset();
      this.unset({currentTime: null, beginTime: null, endTime: null});
    },

    /*
    * Start playback of all objects on map.
    *
    * In case of realtime we just move all system to latest known point in time.
    */
    play: function() {
      if (!this.has('beginTime') || !this.has('endTime') || this.has('playInterval')) {
        // No objects or already in play mode
        return;
      }

      if (this.realtime()) {
        this.currentTime(this.get('endTime'));
      } else {
        if (!this.has('currentTime')) {
          this.currentTime(this.get('beginTime'));
        }

        this.set('playInterval', setInterval(function() {
          this.currentTime(this.currentTime() + (this.get('speed') / this.get('graduality')));
          if (this.currentTime() > this.get('endTime')) {
            this.pause();
          }
        }.bind(this), (1000 / this.get('graduality'))));
      }
    },

    /*
    * Pause playback.
    */
    pause: function() {
      if (this.has('playInterval')) {
        clearInterval(this.get('playInterval'));
        this.unset('playInterval');
      }
    },

    /*
    * Auto-zoom map to area of selected objects.
    */
    autoZoom: function() {
      // Calculate bounds of all visible objects
      var bounds = new google.maps.LatLngBounds();
      this.collection.each(function(model) {
        if (model.showObject() || model.showRoute()) {
          var points = model.getPoints();
          _.each(points, function(point) {
            bounds.extend(new google.maps.LatLng(point.lat, point.lon))
          });
        }
      });

      this.map.fitBounds(bounds);
    },

    /*
    * Gets or sets if current view is in realtime.
    */
    realtime: function(value) {
      if (!_.isUndefined(value)) {
        if (value) {
          this.pause();
        }
        this.set('realtime', value);
      }

      return this.get('realtime');
    }
  });

  return MapObjectsViewModel;
});<|endoftext|>


<commit_before>/**
 * # loggers.js
 * Copyright(c) 2021 Stefano Balietti
 * MIT Licensed
 *
 * Configuration file for Winston.js in nodegame-server
 */

module.exports = configure;

const path = require('path');
const winston = require('winston');

// Variable loggers is winston.loggers.
function configure(loggers, logDir) {
    let logLevel = winston.level;

    // ServerNode.
    loggers.add('servernode', {
        transports: [
            new winston.transports.Console({
                level: logLevel,
                colorize: true
            }),
            new winston.transports.File({
                level: logLevel,
                timestamp: true,
                filename: path.join(logDir, 'servernode.log'),
                maxsize: 1000000,
                maxFiles: 10
            })
        ]

    });

    // Channel.
    loggers.add('channel', {
        transports: [
            new winston.transports.Console({
                level: logLevel,
                colorize: true,
            }),
            new winston.transports.File({
                level: logLevel,
                timestamp: true,
                filename: path.join(logDir, 'channels.log'),
                maxsize: 1000000,
                maxFiles: 10
            })
       ]
    });

    // Messages.
    // Make custom levels and only File transports for messages.
    let msgLogger = loggers.add('messages', {
        transports: [
            new winston.transports.File({
                timestamp: true,
                maxsize: 1000000,
                filename: path.join(logDir, 'messages.log')
            })
        ]
    });

    // Removed in winston v3.
    // Do not change, or logging might be affected.
    // Logger.js hardcodes the values for speed.
    msgLogger.setLevels({
        // Log none.
        none: 0,
        // All DATA msgs.
        data: 1,
        // All SET and DATA msgs.
        set: 3,
        // All SET, GET and DATA msgs.
        get: 5,
        // All SETUP, SET, GET and DATA msgs.
        setup: 7,
        // All messages, but **not** PLAYER_UPDATE, SERVERCOMMAND and ALERT.
        game: 9,
        // All messages.
        all: 11
    });

    // Set default logging level for messages.
    msgLogger.level = 'all';

    // Clients.
    loggers.add('clients', {
        transports: [
            new winston.transports.Console({
                level: logLevel,
                colorize: true,
            }),
            new winston.transports.File({
                level: 'silly',
                timestamp: true,
                filename: path.join(logDir, 'clients.log')
            })
       ]
    });

    return true;
}
<commit_msg>minor<commit_after>/**
 * # loggers.js
 * Copyright(c) 2021 Stefano Balietti
 * MIT Licensed
 *
 * Configuration file for Winston.js in nodegame-server
 */

module.exports = configure;

const path = require('path');
const winston = require('winston');

// Variable loggers is winston.loggers.
function configure(loggers, logDir) {
    let logLevel = winston.level;

    // ServerNode.
    loggers.add('servernode', {
        transports: [
            new winston.transports.Console({
                level: logLevel,
                colorize: true
            }),
            new winston.transports.File({
                level: logLevel,
                timestamp: true,
                filename: path.join(logDir, 'servernode.log'),
                maxsize: 1000000,
                maxFiles: 10
            })
        ]

    });

    // Channel.
    loggers.add('channel', {
        transports: [
            new winston.transports.Console({
                level: logLevel,
                colorize: true,
            }),
            new winston.transports.File({
                level: logLevel,
                timestamp: true,
                filename: path.join(logDir, 'channels.log'),
                maxsize: 1000000,
                maxFiles: 10
            })
       ]
    });

    // Messages.
    // Make custom levels and only File transports for messages.
    let msgLogger = loggers.add('messages', {
        transports: [
            new winston.transports.File({
                timestamp: true,
                maxsize: 1000000,
                filename: path.join(logDir, 'messages.log')
            })
        ]
    });

    // Removed in winston v3.
    // Do not change, or logging might be affected.
    // Logger.js hardcodes the values for speed.
    msgLogger.setLevels({
        // Log none.
        none: 0,
        // All DATA msgs.
        data: 1,
        // All SET and DATA msgs.
        set: 3,
        // All SET, GET and DATA msgs.
        get: 5,
        // All SETUP, SET, GET and DATA msgs.
        setup: 7,
        // All messages, but **not** PLAYER_UPDATE, SERVERCOMMAND and ALERT.
        game: 9,
        // All messages.
        all: 11
    });

    // Set default logging level for messages.
    msgLogger.level = 'all';

    // Clients.
    loggers.add('clients', {
        transports: [
            new winston.transports.Console({
                level: logLevel,
                colorize: true,
            }),
            new winston.transports.File({
                level: 'silly',
                timestamp: true,
                filename: path.join(logDir, 'clients.log')
            })
       ]
    });

    return true;
}
<|endoftext|>


<commit_before>const overlay = document.createElement('div')
overlay.style.backgroundColor = 'rgba(104, 182, 255, 0.35)'
overlay.style.position = 'fixed'
overlay.style.zIndex = '99999'
overlay.style.pointerEvents = 'none'

/**
 * Highlight an instance.
 *
 * @param {Vue} instance
 */

export function highlight (instance) {
  if (!instance) return
  if (!util().inDoc(instance.$el)) {
    return
  }
  if (!instance._isFragment) {
    showOverlay(instance.$el.getBoundingClientRect())
  } else {
    highlightFragment(instance)
  }
}

/**
 * Remove highlight overlay.
 */

export function unHighlight () {
  if (overlay.parentNode) {
    document.body.removeChild(overlay)
  }
}

/**
 * Highlight a fragment instance.
 * Loop over its node range and determine its bounding box.
 *
 * @param {Vue} instance
 */

function highlightFragment ({ _fragmentStart, _fragmentEnd }) {
  let top, bottom, left, right
  util().mapNodeRange(_fragmentStart, _fragmentEnd, function (node) {
    let rect
    if (node.nodeType === 1 || node.getBoundingClientRect) {
      rect = node.getBoundingClientRect()
    } else if (node.nodeType === 3 && node.data.trim()) {
      rect = getTextRect(node)
    }
    if (rect) {
      if (!top || rect.top < top) {
        top = rect.top
      }
      if (!bottom || rect.bottom > bottom) {
        bottom = rect.bottom
      }
      if (!left || rect.left < left) {
        left = rect.left
      }
      if (!right || rect.right > right) {
        right = rect.right
      }
    }
  })
  showOverlay({
    top,
    left,
    width: right - left,
    height: bottom - top
  })
}

/**
 * Get the bounding rect for a text node using a Range.
 *
 * @param {Text} node
 * @return {Rect}
 */

const range = document.createRange()
function getTextRect (node) {
  range.selectNode(node)
  return range.getBoundingClientRect()
}

/**
 * Display the overlay with given rect.
 *
 * @param {Rect}
 */

function showOverlay ({ width = 0, height = 0, top = 0, left = 0 }) {
  overlay.style.width = ~~width + 'px'
  overlay.style.height = ~~height + 'px'
  overlay.style.top = ~~top + 'px'
  overlay.style.left = ~~left + 'px'
  document.body.appendChild(overlay)
}

/**
 * Get Vue's util
 */

function util () {
  return window.__VUE_DEVTOOLS_GLOBAL_HOOK__.Vue.util
}
<commit_msg>refactor highlighter<commit_after>const overlay = document.createElement('div')
overlay.style.backgroundColor = 'rgba(104, 182, 255, 0.35)'
overlay.style.position = 'fixed'
overlay.style.zIndex = '99999'
overlay.style.pointerEvents = 'none'

/**
 * Highlight an instance.
 *
 * @param {Vue} instance
 */

export function highlight (instance) {
  if (!instance) return
  if (!util().inDoc(instance.$el)) {
    return
  }
  showOverlay(getInstanceRect(instance))
}

/**
 * Remove highlight overlay.
 */

export function unHighlight () {
  if (overlay.parentNode) {
    document.body.removeChild(overlay)
  }
}

/**
 * Get the client rect for an instance.
 *
 * @param {Vue} instance
 * @return {Object}
 */

export function getInstanceRect (instance) {
  if (instance._isFragment) {
    return getFragmentRect(instance)
  } else {
    return instance.$el.getBoundingClientRect()
  }
}

/**
 * Highlight a fragment instance.
 * Loop over its node range and determine its bounding box.
 *
 * @param {Vue} instance
 * @return {Object}
 */

function getFragmentRect ({ _fragmentStart, _fragmentEnd }) {
  let top, bottom, left, right
  util().mapNodeRange(_fragmentStart, _fragmentEnd, function (node) {
    let rect
    if (node.nodeType === 1 || node.getBoundingClientRect) {
      rect = node.getBoundingClientRect()
    } else if (node.nodeType === 3 && node.data.trim()) {
      rect = getTextRect(node)
    }
    if (rect) {
      if (!top || rect.top < top) {
        top = rect.top
      }
      if (!bottom || rect.bottom > bottom) {
        bottom = rect.bottom
      }
      if (!left || rect.left < left) {
        left = rect.left
      }
      if (!right || rect.right > right) {
        right = rect.right
      }
    }
  })
  return {
    top,
    left,
    width: right - left,
    height: bottom - top
  }
}

/**
 * Get the bounding rect for a text node using a Range.
 *
 * @param {Text} node
 * @return {Rect}
 */

const range = document.createRange()
function getTextRect (node) {
  range.selectNode(node)
  return range.getBoundingClientRect()
}

/**
 * Display the overlay with given rect.
 *
 * @param {Rect}
 */

function showOverlay ({ width = 0, height = 0, top = 0, left = 0 }) {
  overlay.style.width = ~~width + 'px'
  overlay.style.height = ~~height + 'px'
  overlay.style.top = ~~top + 'px'
  overlay.style.left = ~~left + 'px'
  document.body.appendChild(overlay)
}

/**
 * Get Vue's util
 */

function util () {
  return window.__VUE_DEVTOOLS_GLOBAL_HOOK__.Vue.util
}
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

// Promises
var Q = require('q');

// validator
var validator = require('validator');
var sanitize = validator.sanitize;

exports.loginUser = function(bodyObj){
	// Check emailbox for a user based on the submitted credentials

	var defer = Q.defer();

	process.nextTick(function(){

		var user = {};

		user.access_token = bodyObj.access_token;
		console.log('u');
		console.log(bodyObj.access_token);

		models.Emailbox.user(user)

			.then(function(result){
				// Did we get authenticated with Emailbox?

				if(typeof result.id != 'string'){
					defer.reject(2);
					return;
				}

				// Sweet, we have a valid user

				// Update the user_token for this user
				// - or if they don't exist in the DB, add them

				var created = new Date();
				created = created.getTime();

				// Try and insert the user and key
				models.mysql.acquire(function(err, client) {
					if (err) {
						defer.reject({code:404,msg:'mysql failure'});
						return;
					}
					client.query(
						'INSERT INTO f_users (id, emailbox_id, access_token, created) ' +
						'VALUES (?, ?, ?, ?) ' +
						'ON DUPLICATE KEY UPDATE ' +
						'access_token=?'
						,[null, result.id, bodyObj.access_token, created, bodyObj.access_token]
						, function(error, info, fields) {

							models.mysql.release(client);

							if (error) {
								defer.reject({code:101,msg:'Failed INSERT or UPDATE'});
								return false;
							}

							// Inserted anybody?
							if(info.insertId > 0){
								// Yes
							} else {
								// No
							}

							// Get the full person
							models.Api.getUser(result.id)
								.then(function(user){
									defer.resolve(user);
								})
								.fail(function(){
									defer.reject();
								});

							// Build the newUser
							// var newUser = {
							// 	id : info.insertId,
							// 	username : obj.email,
							// 	developer: developer
							// };

							// defer.resolve(info);

						}
					);

				});

			})

			.fail(function(result){
				console.log('result');
				console.log(result);
				defer.reject({code:404,msg:result});
				// jsonError(res,101,'Failed logging in user');
			});

	});

	return defer.promise;

};

exports.getUser = function(emailbox_id){
	// Return a User
	var defer = Q.defer();

	// Search for the User
	// - only return a single person
	models.mysql.acquire(function(err, client) {
		if (err) {
			defer.reject({code:404,msg:'mysql failure'});
			return;
		}
		client.query(
			'SELECT * FROM f_users ' +
			'WHERE f_users.emailbox_id=?'
			,[emailbox_id]
			, function(error, rows, fields) {

				models.mysql.release(client);

				if (error) {
					defer.reject({code:101,msg:'Failed INSERT or UPDATE'});
					return false;
				}

				if(rows.length < 1){
					// Unable to find User
					defer.reject();
					return;
				}

				// Resolve with single user
				defer.resolve(rows[0]);
			}
		)
	});

	return defer.promise;

};

<commit_msg>this is why programming is a grind sometimes<commit_after>/**
 * Module dependencies.
 */

// Promises
var Q = require('q');

// validator
var validator = require('validator');
var sanitize = validator.sanitize;

exports.loginUser = function(bodyObj){
	// Check emailbox for a user based on the submitted credentials

	var defer = Q.defer();

	process.nextTick(function(){

		var user = {};

		user.access_token = bodyObj.access_token;

		console.log('access_token:');
		console.log(bodyObj.access_token);

		models.Emailbox.user(user)

			.then(function(result){
				// Did we get authenticated with Emailbox?

				if(typeof result.id != 'string'){
					defer.reject(2);
					return;
				}

				// Sweet, we have a valid user

				// Update the user_token for this user
				// - or if they don't exist in the DB, add them

				var created = new Date();
				created = created.getTime();

				// Try and insert the user and key
				models.mysql.acquire(function(err, client) {
					if (err) {
						defer.reject({code:404,msg:'mysql failure'});
						return;
					}
					client.query(
						'INSERT INTO f_users (id, emailbox_id, access_token, created) ' +
						'VALUES (?, ?, ?, ?) ' +
						'ON DUPLICATE KEY UPDATE ' +
						'access_token=?'
						,[null, result.id, bodyObj.access_token, created, bodyObj.access_token]
						, function(error, info, fields) {

							models.mysql.release(client);

							if (error) {
								defer.reject({code:101,msg:'Failed INSERT or UPDATE'});
								return false;
							}

							// Inserted anybody?
							if(info.insertId > 0){
								// Yes
							} else {
								// No
							}

							// Get the full person
							models.Api.getUser(result.id)
								.then(function(user){
									defer.resolve(user);
								})
								.fail(function(){
									defer.reject();
								});

							// Build the newUser
							// var newUser = {
							// 	id : info.insertId,
							// 	username : obj.email,
							// 	developer: developer
							// };

							// defer.resolve(info);

						}
					);

				});

			})

			.fail(function(result){
				console.log('result');
				console.log(result);
				defer.reject({code:404,msg:result});
				// jsonError(res,101,'Failed logging in user');
			});

	});

	return defer.promise;

};

exports.updateUser = function(userObj){
	// Check emailbox for a user based on the submitted credentials

	var defer = Q.defer();

	process.nextTick(function(){

		// Build user object
		var user = {
			access_token: bodyObj.access_token // used for requesting Emailbox user (later)
		};

		// Only updating:
		// - android_reg_id
		// - ios_something (todo...)
		var updating = {};

		user.android_reg_id = bodyObj.android_reg_id || null;

		console.log('android_reg_id:');
		console.log(bodyObj.android_reg_id);

		if(user.android_reg_id){
			// Updating android_reg_id

			// Validate android_reg_id
			if(typeof user.android_reg_id != 'string'){
				defer.reject({code: 404, msg: 'Invalid android_reg_id'});
				return;
			} else {
				updating['android_reg_id'] = user.android_reg_id;
			}
		}

		// Updating anything??
		if(!_.size(updating)){
			defer.reject({code: 404, msg:'No valid update requests provided'});
			return;
		}

		// Get the User from Emailbox
		models.Emailbox.user(user)

			.then(function(result){
				// Did we get authenticated with Emailbox?

				if(typeof result.id != 'string'){
					defer.reject(2);
					return;
				}

				// Sweet, we have a valid user

				// Update the user_token for this user
				// - or if they don't exist in the DB, add them

				var created = new Date();
				created = created.getTime();

				// Get keys to update
				var keys = [];
				for(var k in obj) keys.push(k);

				// Add user's id

				// Try and update the user's things
				models.mysql.acquire(function(err, client) {
					if (err) {
						defer.reject({code:404,msg:'mysql failure'});
						return;
					}
					client.query(
						'UPDATE * FROM f_users ' +
						'SET android_reg_id=? ' +
						'WHERE id=?'
						,[bodyObj.android_reg_id, result.id]
						, function(error, info, fields) {

							models.mysql.release(client);

							if (error) {
								defer.reject({code:101,msg:'Failed INSERT or UPDATE'});
								return false;
							}

							// Inserted anybody?
							console.log('info');
							console.log(info);

							// Check if updated
							// - expect a single entry to be updated
							defer.resolve(true);

						}
					);

				});

			})

			.fail(function(result){
				console.log('result');
				console.log(result);
				defer.reject({code:404,msg:result});
				// jsonError(res,101,'Failed logging in user');
			});

	});

	return defer.promise;

};

exports.getUser = function(emailbox_id){
	// Return a User
	var defer = Q.defer();

	// Search for the User
	// - only return a single person
	models.mysql.acquire(function(err, client) {
		if (err) {
			defer.reject({code:404,msg:'mysql failure'});
			return;
		}
		client.query(
			'SELECT * FROM f_users ' +
			'WHERE f_users.emailbox_id=?'
			,[emailbox_id]
			, function(error, rows, fields) {

				models.mysql.release(client);

				if (error) {
					defer.reject({code:101,msg:'Failed INSERT or UPDATE'});
					return false;
				}

				if(rows.length < 1){
					// Unable to find User
					defer.reject();
					return;
				}

				// Resolve with single user
				defer.resolve(rows[0]);
			}
		)
	});

	return defer.promise;

};

// exports.getEmailboxUserSettings = function(emailbox_id){
// 	// Return a User
// 	var defer = Q.defer();

// 	var searchData = {
// 		model: 'Email',
// 		conditions: {
// 			_id: email._id
// 		},
// 		fields: ['app.AppPkgDevMinimail',
// 				 'attributes.thread_id',
// 				 'original.TextBody',
// 				 'original.labels',
// 				 'original.headers.From',
// 				 'original.headers.Subject',
// 				 'original.ParsedData.[0]',
// 				 'original.ParsedData.0'
// 				 ],
// 		limit: 1
// 	};

// 	console.log('Searching');

// 	var getUser = Q.defer();

// 	// Get the local user_id
// 	models.User.get_local_by_emailbox_id(bodyObj.auth.user_id)
// 		.then(function(local_user){
// 			// console.log('User');
// 			// console.log(local_user);
// 			getUser.resolve(local_user);
// 		});

// 	getUser.promise.then(function(local_user){

// 		models.Emailbox.search(searchData,bodyObj.auth)
// 			.then(function(emails){

// 	return defer.promise;

// };

<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @emails oncall+react_native
 */

'use strict';

const React = require('react');
const ReactTestRenderer = require('react-test-renderer');

const VirtualizedList = require('../VirtualizedList');

describe('VirtualizedList', () => {
  it('renders simple list', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'i1'}, {key: 'i2'}, {key: 'i3'}]}
        renderItem={({item}) => <item value={item.key} />}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('renders simple list using ListItemComponent', () => {
    function ListItemComponent({item}) {
      return <item value={item.key} />;
    }
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'i1'}, {key: 'i2'}, {key: 'i3'}]}
        ListItemComponent={ListItemComponent}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('warns if both renderItem or ListItemComponent are specified. Uses ListItemComponent', () => {
    jest.spyOn(console, 'warn').mockImplementationOnce(() => {});
    function ListItemComponent({item}) {
      return <item value={item.key} testID={`${item.key}-ListItemComponent`} />;
    }
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'i1'}]}
        ListItemComponent={ListItemComponent}
        renderItem={({item}) => (
          <item value={item.key} testID={`${item.key}-renderItem`} />
        )}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );

    expect(console.warn).toBeCalledWith(
      'VirtualizedList: Both ListItemComponent and renderItem props are present. ListItemComponent will take precedence over renderItem.',
    );
    expect(component).toMatchSnapshot();
    console.warn.mockRestore();
  });

  it('throws if no renderItem or ListItemComponent', () => {
    // Silence the React error boundary warning; we expect an uncaught error.
    const consoleError = console.error;
    jest.spyOn(console, 'error').mockImplementation(message => {
      if (message.startsWith('The above error occured in the ')) {
        return;
      }
      consoleError(message);
    });

    const componentFactory = () =>
      ReactTestRenderer.create(
        <VirtualizedList
          data={[{key: 'i1'}, {key: 'i2'}, {key: 'i3'}]}
          getItem={(data, index) => data[index]}
          getItemCount={data => data.length}
        />,
      );
    expect(componentFactory).toThrow(
      'VirtualizedList: Either ListItemComponent or renderItem props are required but none were found.',
    );

    console.error.mockRestore();
  });

  it('renders empty list', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[]}
        renderItem={({item}) => <item value={item.key} />}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('renders null list', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={undefined}
        renderItem={({item}) => <item value={item.key} />}
        getItem={(data, index) => data[index]}
        getItemCount={data => 0}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('renders empty list with empty component', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[]}
        ListEmptyComponent={() => <empty />}
        ListFooterComponent={() => <footer />}
        ListHeaderComponent={() => <header />}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
        renderItem={({item}) => <item value={item.key} />}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('renders list with empty component', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'hello'}]}
        ListEmptyComponent={() => <empty />}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
        renderItem={({item}) => <item value={item.key} />}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('renders all the bells and whistles', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        ItemSeparatorComponent={() => <separator />}
        ListEmptyComponent={() => <empty />}
        ListFooterComponent={() => <footer />}
        ListHeaderComponent={() => <header />}
        data={new Array(5).fill().map((_, ii) => ({id: String(ii)}))}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
        getItemLayout={({index}) => ({length: 50, offset: index * 50})}
        inverted={true}
        keyExtractor={(item, index) => item.id}
        onRefresh={jest.fn()}
        refreshing={false}
        renderItem={({item}) => <item value={item.id} />}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('test getItem functionality where data is not an Array', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={new Map([['id_0', {key: 'item_0'}]])}
        getItem={(data, index) => data.get('id_' + index)}
        getItemCount={(data: Map) => data.size}
        renderItem={({item}) => <item value={item.key} />}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('handles separators correctly', () => {
    const infos = [];
    const component = ReactTestRenderer.create(
      <VirtualizedList
        ItemSeparatorComponent={props => <separator {...props} />}
        data={[{key: 'i0'}, {key: 'i1'}, {key: 'i2'}]}
        renderItem={info => {
          infos.push(info);
          return <item title={info.item.key} />;
        }}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    expect(component).toMatchSnapshot();
    infos[1].separators.highlight();
    expect(component).toMatchSnapshot();
    infos[2].separators.updateProps('leading', {press: true});
    expect(component).toMatchSnapshot();
    infos[1].separators.unhighlight();
  });

  it('handles nested lists', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'outer0'}, {key: 'outer1'}]}
        renderItem={outerInfo => (
          <VirtualizedList
            data={[
              {key: outerInfo.item.key + ':inner0'},
              {key: outerInfo.item.key + ':inner1'},
            ]}
            horizontal={outerInfo.item.key === 'outer1'}
            renderItem={innerInfo => {
              return <item title={innerInfo.item.key} />;
            }}
            getItem={(data, index) => data[index]}
            getItemCount={data => data.length}
          />
        )}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('returns the viewableItems correctly in the onViewableItemsChanged callback after changing the data', () => {
    const ITEM_HEIGHT = 800;
    let data = [{key: 'i1'}, {key: 'i2'}, {key: 'i3'}];
    const nativeEvent = {
      contentOffset: {y: 0, x: 0},
      layoutMeasurement: {width: 300, height: 600},
      contentSize: {width: 300, height: data.length * ITEM_HEIGHT},
      zoomScale: 1,
      contentInset: {right: 0, top: 0, left: 0, bottom: 0},
    };
    const onViewableItemsChanged = jest.fn();
    const props = {
      data,
      renderItem: ({item}) => <item value={item.key} />,
      getItem: (items, index) => items[index],
      getItemCount: items => items.length,
      getItemLayout: (items, index) => ({
        length: ITEM_HEIGHT,
        offset: ITEM_HEIGHT * index,
        index,
      }),
      onViewableItemsChanged,
    };

    const component = ReactTestRenderer.create(<VirtualizedList {...props} />);

    const instance = component.getInstance();

    instance._onScrollBeginDrag({nativeEvent});
    instance._onScroll({
      timeStamp: 1000,
      nativeEvent,
    });

    expect(onViewableItemsChanged).toHaveBeenCalledTimes(1);
    expect(onViewableItemsChanged).toHaveBeenLastCalledWith(
      expect.objectContaining({
        viewableItems: [expect.objectContaining({isViewable: true, key: 'i1'})],
      }),
    );
    data = [{key: 'i4'}, ...data];
    component.update(<VirtualizedList {...props} data={data} />);

    instance._onScroll({
      timeStamp: 2000,
      nativeEvent: {
        ...nativeEvent,
        contentOffset: {y: 100, x: 0},
      },
    });

    expect(onViewableItemsChanged).toHaveBeenCalledTimes(2);
    expect(onViewableItemsChanged).toHaveBeenLastCalledWith(
      expect.objectContaining({
        viewableItems: [expect.objectContaining({isViewable: true, key: 'i4'})],
      }),
    );
  });

  it('getScrollRef for case where it returns a ScrollView', () => {
    const listRef = React.createRef(null);

    ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'i1'}, {key: 'i2'}, {key: 'i3'}]}
        renderItem={({item}) => <item value={item.key} />}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
        ref={listRef}
      />,
    );

    const scrollRef = listRef.current.getScrollRef();

    // This is checking if the ref acts like a ScrollView. If we had an
    // `isScrollView(ref)` method, that would be preferred.
    expect(scrollRef.scrollTo).toBeInstanceOf(Function);
  });

  it('getScrollRef for case where it returns a View', () => {
    const listRef = React.createRef(null);

    ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'outer0'}, {key: 'outer1'}]}
        renderItem={outerInfo => (
          <VirtualizedList
            data={[
              {key: outerInfo.item.key + ':inner0'},
              {key: outerInfo.item.key + ':inner1'},
            ]}
            renderItem={innerInfo => {
              return <item title={innerInfo.item.key} />;
            }}
            getItem={(data, index) => data[index]}
            getItemCount={data => data.length}
            ref={listRef}
          />
        )}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    const scrollRef = listRef.current.getScrollRef();

    // This is checking if the ref acts like a host component. If we had an
    // `isHostComponent(ref)` method, that would be preferred.
    expect(scrollRef.measure).toBeInstanceOf(jest.fn().constructor);
    expect(scrollRef.measureLayout).toBeInstanceOf(jest.fn().constructor);
    expect(scrollRef.measureInWindow).toBeInstanceOf(jest.fn().constructor);
  });
  it('does not call onEndReached when onContentSizeChange happens after onLayout', () => {
    const ITEM_HEIGHT = 40;
    const layout = {width: 300, height: 600};
    let data = Array(20)
      .fill()
      .map((_, key) => ({key: String(key)}));
    const onEndReached = jest.fn();
    const props = {
      data,
      initialNumToRender: 10,
      onEndReachedThreshold: 2,
      windowSize: 21,
      renderItem: ({item}) => <item value={item.key} />,
      getItem: (items, index) => items[index],
      getItemCount: items => items.length,
      getItemLayout: (items, index) => ({
        length: ITEM_HEIGHT,
        offset: ITEM_HEIGHT * index,
        index,
      }),
      onEndReached,
    };

    const component = ReactTestRenderer.create(<VirtualizedList {...props} />);

    const instance = component.getInstance();

    instance._onLayout({nativeEvent: {layout}});

    const initialContentHeight = props.initialNumToRender * ITEM_HEIGHT;

    // We want to test the unusual case of onContentSizeChange firing after
    // onLayout, which can cause https://github.com/facebook/react-native/issues/16067
    instance._onContentSizeChange(300, initialContentHeight);
    instance._onContentSizeChange(300, data.length * ITEM_HEIGHT);
    jest.runAllTimers();

    expect(onEndReached).not.toHaveBeenCalled();

    instance._onScroll({
      timeStamp: 1000,
      nativeEvent: {
        contentOffset: {y: initialContentHeight, x: 0},
        layoutMeasurement: layout,
        contentSize: {...layout, height: data.length * ITEM_HEIGHT},
        zoomScale: 1,
        contentInset: {right: 0, top: 0, left: 0, bottom: 0},
      },
    });
    jest.runAllTimers();

    expect(onEndReached).toHaveBeenCalled();
  });

  it('provides a trace when a listKey collision occurs', () => {
    const errors = [];
    jest.spyOn(console, 'error').mockImplementation((...args) => {
      // Silence the DEV-only React error boundary warning.
      if ((args[0] || '').startsWith('The above error occured in the ')) {
        return;
      }
      errors.push(args);
    });
    const commonProps = {
      data: [{key: 'cell0'}],
      getItem: (data, index) => data[index],
      getItemCount: data => data.length,
      renderItem: ({item}) => <item value={item.key} />,
    };
    try {
      ReactTestRenderer.create(
        <VirtualizedList
          {...commonProps}
          horizontal={false}
          listKey="level0"
          renderItem={() => (
            <VirtualizedList
              {...commonProps}
              horizontal={true}
              listKey="level1"
              renderItem={() => (
                <>
                  {/* Force a collision */}
                  <VirtualizedList
                    {...commonProps}
                    horizontal={true}
                    listKey="level2"
                  />
                  <VirtualizedList
                    {...commonProps}
                    horizontal={true}
                    listKey="level2"
                  />
                </>
              )}
            />
          )}
        />,
      );
      expect(errors).toMatchInlineSnapshot(`
        Array [
          Array [
            "A VirtualizedList contains a cell which itself contains more than one VirtualizedList of the same orientation as the parent list. You must pass a unique listKey prop to each sibling list.

        VirtualizedList trace:
          Child (horizontal):
            listKey: level2
            cellKey: cell0
          Parent (horizontal):
            listKey: level1
            cellKey: cell0
          Parent (vertical):
            listKey: level0
            cellKey: rootList",
          ],
        ]
      `);
    } finally {
      console.error.mockRestore();
    }
  });
});
<commit_msg>Fix indentation of inline snapshots in tests<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @emails oncall+react_native
 */

'use strict';

const React = require('react');
const ReactTestRenderer = require('react-test-renderer');

const VirtualizedList = require('../VirtualizedList');

describe('VirtualizedList', () => {
  it('renders simple list', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'i1'}, {key: 'i2'}, {key: 'i3'}]}
        renderItem={({item}) => <item value={item.key} />}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('renders simple list using ListItemComponent', () => {
    function ListItemComponent({item}) {
      return <item value={item.key} />;
    }
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'i1'}, {key: 'i2'}, {key: 'i3'}]}
        ListItemComponent={ListItemComponent}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('warns if both renderItem or ListItemComponent are specified. Uses ListItemComponent', () => {
    jest.spyOn(console, 'warn').mockImplementationOnce(() => {});
    function ListItemComponent({item}) {
      return <item value={item.key} testID={`${item.key}-ListItemComponent`} />;
    }
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'i1'}]}
        ListItemComponent={ListItemComponent}
        renderItem={({item}) => (
          <item value={item.key} testID={`${item.key}-renderItem`} />
        )}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );

    expect(console.warn).toBeCalledWith(
      'VirtualizedList: Both ListItemComponent and renderItem props are present. ListItemComponent will take precedence over renderItem.',
    );
    expect(component).toMatchSnapshot();
    console.warn.mockRestore();
  });

  it('throws if no renderItem or ListItemComponent', () => {
    // Silence the React error boundary warning; we expect an uncaught error.
    const consoleError = console.error;
    jest.spyOn(console, 'error').mockImplementation(message => {
      if (message.startsWith('The above error occured in the ')) {
        return;
      }
      consoleError(message);
    });

    const componentFactory = () =>
      ReactTestRenderer.create(
        <VirtualizedList
          data={[{key: 'i1'}, {key: 'i2'}, {key: 'i3'}]}
          getItem={(data, index) => data[index]}
          getItemCount={data => data.length}
        />,
      );
    expect(componentFactory).toThrow(
      'VirtualizedList: Either ListItemComponent or renderItem props are required but none were found.',
    );

    console.error.mockRestore();
  });

  it('renders empty list', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[]}
        renderItem={({item}) => <item value={item.key} />}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('renders null list', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={undefined}
        renderItem={({item}) => <item value={item.key} />}
        getItem={(data, index) => data[index]}
        getItemCount={data => 0}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('renders empty list with empty component', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[]}
        ListEmptyComponent={() => <empty />}
        ListFooterComponent={() => <footer />}
        ListHeaderComponent={() => <header />}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
        renderItem={({item}) => <item value={item.key} />}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('renders list with empty component', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'hello'}]}
        ListEmptyComponent={() => <empty />}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
        renderItem={({item}) => <item value={item.key} />}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('renders all the bells and whistles', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        ItemSeparatorComponent={() => <separator />}
        ListEmptyComponent={() => <empty />}
        ListFooterComponent={() => <footer />}
        ListHeaderComponent={() => <header />}
        data={new Array(5).fill().map((_, ii) => ({id: String(ii)}))}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
        getItemLayout={({index}) => ({length: 50, offset: index * 50})}
        inverted={true}
        keyExtractor={(item, index) => item.id}
        onRefresh={jest.fn()}
        refreshing={false}
        renderItem={({item}) => <item value={item.id} />}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('test getItem functionality where data is not an Array', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={new Map([['id_0', {key: 'item_0'}]])}
        getItem={(data, index) => data.get('id_' + index)}
        getItemCount={(data: Map) => data.size}
        renderItem={({item}) => <item value={item.key} />}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('handles separators correctly', () => {
    const infos = [];
    const component = ReactTestRenderer.create(
      <VirtualizedList
        ItemSeparatorComponent={props => <separator {...props} />}
        data={[{key: 'i0'}, {key: 'i1'}, {key: 'i2'}]}
        renderItem={info => {
          infos.push(info);
          return <item title={info.item.key} />;
        }}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    expect(component).toMatchSnapshot();
    infos[1].separators.highlight();
    expect(component).toMatchSnapshot();
    infos[2].separators.updateProps('leading', {press: true});
    expect(component).toMatchSnapshot();
    infos[1].separators.unhighlight();
  });

  it('handles nested lists', () => {
    const component = ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'outer0'}, {key: 'outer1'}]}
        renderItem={outerInfo => (
          <VirtualizedList
            data={[
              {key: outerInfo.item.key + ':inner0'},
              {key: outerInfo.item.key + ':inner1'},
            ]}
            horizontal={outerInfo.item.key === 'outer1'}
            renderItem={innerInfo => {
              return <item title={innerInfo.item.key} />;
            }}
            getItem={(data, index) => data[index]}
            getItemCount={data => data.length}
          />
        )}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    expect(component).toMatchSnapshot();
  });

  it('returns the viewableItems correctly in the onViewableItemsChanged callback after changing the data', () => {
    const ITEM_HEIGHT = 800;
    let data = [{key: 'i1'}, {key: 'i2'}, {key: 'i3'}];
    const nativeEvent = {
      contentOffset: {y: 0, x: 0},
      layoutMeasurement: {width: 300, height: 600},
      contentSize: {width: 300, height: data.length * ITEM_HEIGHT},
      zoomScale: 1,
      contentInset: {right: 0, top: 0, left: 0, bottom: 0},
    };
    const onViewableItemsChanged = jest.fn();
    const props = {
      data,
      renderItem: ({item}) => <item value={item.key} />,
      getItem: (items, index) => items[index],
      getItemCount: items => items.length,
      getItemLayout: (items, index) => ({
        length: ITEM_HEIGHT,
        offset: ITEM_HEIGHT * index,
        index,
      }),
      onViewableItemsChanged,
    };

    const component = ReactTestRenderer.create(<VirtualizedList {...props} />);

    const instance = component.getInstance();

    instance._onScrollBeginDrag({nativeEvent});
    instance._onScroll({
      timeStamp: 1000,
      nativeEvent,
    });

    expect(onViewableItemsChanged).toHaveBeenCalledTimes(1);
    expect(onViewableItemsChanged).toHaveBeenLastCalledWith(
      expect.objectContaining({
        viewableItems: [expect.objectContaining({isViewable: true, key: 'i1'})],
      }),
    );
    data = [{key: 'i4'}, ...data];
    component.update(<VirtualizedList {...props} data={data} />);

    instance._onScroll({
      timeStamp: 2000,
      nativeEvent: {
        ...nativeEvent,
        contentOffset: {y: 100, x: 0},
      },
    });

    expect(onViewableItemsChanged).toHaveBeenCalledTimes(2);
    expect(onViewableItemsChanged).toHaveBeenLastCalledWith(
      expect.objectContaining({
        viewableItems: [expect.objectContaining({isViewable: true, key: 'i4'})],
      }),
    );
  });

  it('getScrollRef for case where it returns a ScrollView', () => {
    const listRef = React.createRef(null);

    ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'i1'}, {key: 'i2'}, {key: 'i3'}]}
        renderItem={({item}) => <item value={item.key} />}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
        ref={listRef}
      />,
    );

    const scrollRef = listRef.current.getScrollRef();

    // This is checking if the ref acts like a ScrollView. If we had an
    // `isScrollView(ref)` method, that would be preferred.
    expect(scrollRef.scrollTo).toBeInstanceOf(Function);
  });

  it('getScrollRef for case where it returns a View', () => {
    const listRef = React.createRef(null);

    ReactTestRenderer.create(
      <VirtualizedList
        data={[{key: 'outer0'}, {key: 'outer1'}]}
        renderItem={outerInfo => (
          <VirtualizedList
            data={[
              {key: outerInfo.item.key + ':inner0'},
              {key: outerInfo.item.key + ':inner1'},
            ]}
            renderItem={innerInfo => {
              return <item title={innerInfo.item.key} />;
            }}
            getItem={(data, index) => data[index]}
            getItemCount={data => data.length}
            ref={listRef}
          />
        )}
        getItem={(data, index) => data[index]}
        getItemCount={data => data.length}
      />,
    );
    const scrollRef = listRef.current.getScrollRef();

    // This is checking if the ref acts like a host component. If we had an
    // `isHostComponent(ref)` method, that would be preferred.
    expect(scrollRef.measure).toBeInstanceOf(jest.fn().constructor);
    expect(scrollRef.measureLayout).toBeInstanceOf(jest.fn().constructor);
    expect(scrollRef.measureInWindow).toBeInstanceOf(jest.fn().constructor);
  });
  it('does not call onEndReached when onContentSizeChange happens after onLayout', () => {
    const ITEM_HEIGHT = 40;
    const layout = {width: 300, height: 600};
    let data = Array(20)
      .fill()
      .map((_, key) => ({key: String(key)}));
    const onEndReached = jest.fn();
    const props = {
      data,
      initialNumToRender: 10,
      onEndReachedThreshold: 2,
      windowSize: 21,
      renderItem: ({item}) => <item value={item.key} />,
      getItem: (items, index) => items[index],
      getItemCount: items => items.length,
      getItemLayout: (items, index) => ({
        length: ITEM_HEIGHT,
        offset: ITEM_HEIGHT * index,
        index,
      }),
      onEndReached,
    };

    const component = ReactTestRenderer.create(<VirtualizedList {...props} />);

    const instance = component.getInstance();

    instance._onLayout({nativeEvent: {layout}});

    const initialContentHeight = props.initialNumToRender * ITEM_HEIGHT;

    // We want to test the unusual case of onContentSizeChange firing after
    // onLayout, which can cause https://github.com/facebook/react-native/issues/16067
    instance._onContentSizeChange(300, initialContentHeight);
    instance._onContentSizeChange(300, data.length * ITEM_HEIGHT);
    jest.runAllTimers();

    expect(onEndReached).not.toHaveBeenCalled();

    instance._onScroll({
      timeStamp: 1000,
      nativeEvent: {
        contentOffset: {y: initialContentHeight, x: 0},
        layoutMeasurement: layout,
        contentSize: {...layout, height: data.length * ITEM_HEIGHT},
        zoomScale: 1,
        contentInset: {right: 0, top: 0, left: 0, bottom: 0},
      },
    });
    jest.runAllTimers();

    expect(onEndReached).toHaveBeenCalled();
  });

  it('provides a trace when a listKey collision occurs', () => {
    const errors = [];
    jest.spyOn(console, 'error').mockImplementation((...args) => {
      // Silence the DEV-only React error boundary warning.
      if ((args[0] || '').startsWith('The above error occured in the ')) {
        return;
      }
      errors.push(args);
    });
    const commonProps = {
      data: [{key: 'cell0'}],
      getItem: (data, index) => data[index],
      getItemCount: data => data.length,
      renderItem: ({item}) => <item value={item.key} />,
    };
    try {
      ReactTestRenderer.create(
        <VirtualizedList
          {...commonProps}
          horizontal={false}
          listKey="level0"
          renderItem={() => (
            <VirtualizedList
              {...commonProps}
              horizontal={true}
              listKey="level1"
              renderItem={() => (
                <>
                  {/* Force a collision */}
                  <VirtualizedList
                    {...commonProps}
                    horizontal={true}
                    listKey="level2"
                  />
                  <VirtualizedList
                    {...commonProps}
                    horizontal={true}
                    listKey="level2"
                  />
                </>
              )}
            />
          )}
        />,
      );
      expect(errors).toMatchInlineSnapshot(`
        Array [
          Array [
            "A VirtualizedList contains a cell which itself contains more than one VirtualizedList of the same orientation as the parent list. You must pass a unique listKey prop to each sibling list.

        VirtualizedList trace:
          Child (horizontal):
            listKey: level2
            cellKey: cell0
          Parent (horizontal):
            listKey: level1
            cellKey: cell0
          Parent (vertical):
            listKey: level0
            cellKey: rootList",
          ],
        ]
      `);
    } finally {
      console.error.mockRestore();
    }
  });
});
<|endoftext|>


<commit_before>'use strict';

/* global describe it */

// core modules
var assert = require('assert');

// local modules
var EventLoop = require('../lib');

var Tasks = function() {
  var tasks = {};

  tasks.completed = [];

  tasks.create = function(id) {
    return tasks.completed.push.bind(tasks.completed, id);
  };

  return tasks;
};

var Fixture = function() {
  var x = {};

  x.eventLoop = EventLoop();
  x.tasks = Tasks();

  return x;
};

describe('EventLoop', function() {
  it('Can run a single task', function() {
    var x = Fixture();

    x.eventLoop.post(x.tasks.create('foo'));
    x.eventLoop.run();

    assert.deepEqual(x.tasks.completed, ['foo']);
  });

  it('runNext runs the next task', function() {
    var x = Fixture();

    x.eventLoop.post(x.tasks.create('a'));
    x.eventLoop.post(x.tasks.create('b'));
    x.eventLoop.post(x.tasks.create('c'));

    assert.deepEqual(x.tasks.completed, []);
    x.eventLoop.runNext();
    assert.deepEqual(x.tasks.completed, ['a']);
    x.eventLoop.runNext();
    assert.deepEqual(x.tasks.completed, ['a', 'b']);
    x.eventLoop.runNext();
    assert.deepEqual(x.tasks.completed, ['a', 'b', 'c']);
  });

  it('runs all tasks and tasks within tasks in the correct order', function() {
    var x = Fixture();

    x.eventLoop.post(x.tasks.create('a'));

    x.eventLoop.post(function() {
      x.eventLoop.post(x.tasks.create('b'));
    });

    x.eventLoop.post(x.tasks.create('c'));

    x.eventLoop.post(function() {
      x.eventLoop.post(x.tasks.create('d'));
    });

    assert.deepEqual(x.tasks.completed, []);
    x.eventLoop.run();
    assert.deepEqual(x.tasks.completed, ['a', 'c', 'b', 'd']);
  });
});
<commit_msg>runs tasks according to time<commit_after>'use strict';

/* global describe it */

// core modules
var assert = require('assert');

// local modules
var EventLoop = require('../lib');

var Tasks = function() {
  var tasks = {};

  tasks.completed = [];

  tasks.create = function(id) {
    return tasks.completed.push.bind(tasks.completed, id);
  };

  return tasks;
};

var Fixture = function() {
  var x = {};

  x.eventLoop = EventLoop();
  x.tasks = Tasks();

  return x;
};

describe('EventLoop', function() {
  it('Can run a single task', function() {
    var x = Fixture();

    x.eventLoop.post(x.tasks.create('foo'));
    x.eventLoop.run();

    assert.deepEqual(x.tasks.completed, ['foo']);
  });

  it('runNext runs the next task', function() {
    var x = Fixture();

    x.eventLoop.post(x.tasks.create('a'));
    x.eventLoop.post(x.tasks.create('b'));
    x.eventLoop.post(x.tasks.create('c'));

    assert.deepEqual(x.tasks.completed, []);
    x.eventLoop.runNext();
    assert.deepEqual(x.tasks.completed, ['a']);
    x.eventLoop.runNext();
    assert.deepEqual(x.tasks.completed, ['a', 'b']);
    x.eventLoop.runNext();
    assert.deepEqual(x.tasks.completed, ['a', 'b', 'c']);
  });

  it('runs all tasks and tasks within tasks in the correct order', function() {
    var x = Fixture();

    x.eventLoop.post(x.tasks.create('a'));

    x.eventLoop.post(function() {
      x.eventLoop.post(x.tasks.create('b'));
    });

    x.eventLoop.post(x.tasks.create('c'));

    x.eventLoop.post(function() {
      x.eventLoop.post(x.tasks.create('d'));
    });

    assert.deepEqual(x.tasks.completed, []);
    x.eventLoop.run();
    assert.deepEqual(x.tasks.completed, ['a', 'c', 'b', 'd']);
  });

  it('runs tasks according to time', function() {
    var x = Fixture();

    x.eventLoop.post(x.tasks.create('a'), 2);
    x.eventLoop.post(x.tasks.create('b'), 1);
    x.eventLoop.post(x.tasks.create('c'), 0);

    x.eventLoop.run();

    assert.deepEqual(x.tasks.completed, ['c', 'b', 'a']);
  });
});
<|endoftext|>