<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author mikael emtinger / http://gomo.se/
 * @author jonobr1 / http://jonobr1.com/
 */

THREE.Mesh = function ( geometry, material ) {

	THREE.Object3D.call( this );

	this.type = 'Mesh';

	this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
	this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } );

	this.updateMorphTargets();

};

THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype );
THREE.Mesh.prototype.constructor = THREE.Mesh;

THREE.Mesh.prototype.updateMorphTargets = function () {

	if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) {

		this.morphTargetBase = - 1;
		this.morphTargetForcedOrder = [];
		this.morphTargetInfluences = [];
		this.morphTargetDictionary = {};

		for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) {

			this.morphTargetInfluences.push( 0 );
			this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m;

		}

	}

};

THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) {

	if ( this.morphTargetDictionary[ name ] !== undefined ) {

		return this.morphTargetDictionary[ name ];

	}

	console.warn( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' );

	return 0;

};

THREE.Mesh.prototype.raycast = ( function () {

	var inverseMatrix = new THREE.Matrix4();
	var ray = new THREE.Ray();
	var sphere = new THREE.Sphere();

	var vA = new THREE.Vector3();
	var vB = new THREE.Vector3();
	var vC = new THREE.Vector3();

	return function ( raycaster, intersects ) {

		var geometry = this.geometry;

		// Checking boundingSphere distance to ray

		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();

		sphere.copy( geometry.boundingSphere );
		sphere.applyMatrix4( this.matrixWorld );

		if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) {

			return;

		}

		// Check boundingBox before continuing

		inverseMatrix.getInverse( this.matrixWorld );
		ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );

		if ( geometry.boundingBox !== null ) {

			if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) {

				return;

			}

		}

		if ( geometry instanceof THREE.BufferGeometry ) {

			var material = this.material;

			if ( material === undefined ) return;

			var attributes = geometry.attributes;

			var a, b, c;

			if ( attributes.index !== undefined ) {

				var indices = attributes.index.array;
				var positions = attributes.position.array;
				var offsets = geometry.offsets;

				if ( offsets.length === 0 ) {

					offsets = [ { start: 0, count: indices.length, index: 0 } ];

				}

				for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) {

					var start = offsets[ oi ].start;
					var count = offsets[ oi ].count;
					var index = offsets[ oi ].index;

					for ( var i = start, il = start + count; i < il; i += 3 ) {

						a = index + indices[ i ];
						b = index + indices[ i + 1 ];
						c = index + indices[ i + 2 ];

						vA.fromArray( positions, a * 3 );
						vB.fromArray( positions, b * 3 );
						vC.fromArray( positions, c * 3 );

						if ( material.side === THREE.BackSide ) {

							var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );

						} else {

							var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );

						}

						if ( intersectionPoint === null ) continue;

						intersectionPoint.applyMatrix4( this.matrixWorld );

						var distance = raycaster.ray.origin.distanceTo( intersectionPoint );

						if ( distance < raycaster.near || distance > raycaster.far ) continue;

						intersects.push( {

							distance: distance,
							point: intersectionPoint,
							face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),
							faceIndex: Math.floor(i/3), // triangle number in indices buffer semantics
							object: this

						} );

					}

				}

			} else {

				var positions = attributes.position.array;

				for ( var i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9 ) {

					a = i;
					b = i + 1;
					c = i + 2;

					vA.fromArray( positions, j );
					vB.fromArray( positions, j + 3 );
					vC.fromArray( positions, j + 6 );

					if ( material.side === THREE.BackSide ) {

						var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );

					} else {

						var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );

					}

					if ( intersectionPoint === null ) continue;

					intersectionPoint.applyMatrix4( this.matrixWorld );

					var distance = raycaster.ray.origin.distanceTo( intersectionPoint );

					if ( distance < raycaster.near || distance > raycaster.far ) continue;

					intersects.push( {

						distance: distance,
						point: intersectionPoint,
						face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),
						index: Math.floor(i/3), // triangle number in positions buffer semantics
						object: this

					} );

				}

			}

		} else if ( geometry instanceof THREE.Geometry ) {

			var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial;
			var objectMaterials = isFaceMaterial === true ? this.material.materials : null;

			var a, b, c;

			var vertices = geometry.vertices;

			for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {

				var face = geometry.faces[ f ];

				var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : this.material;

				if ( material === undefined ) continue;

				a = vertices[ face.a ];
				b = vertices[ face.b ];
				c = vertices[ face.c ];

				if ( material.morphTargets === true ) {

					var morphTargets = geometry.morphTargets;
					var morphInfluences = this.morphTargetInfluences;

					vA.set( 0, 0, 0 );
					vB.set( 0, 0, 0 );
					vC.set( 0, 0, 0 );

					for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {

						var influence = morphInfluences[ t ];

						if ( influence === 0 ) continue;

						var targets = morphTargets[ t ].vertices;

						vA.x += ( targets[ face.a ].x - a.x ) * influence;
						vA.y += ( targets[ face.a ].y - a.y ) * influence;
						vA.z += ( targets[ face.a ].z - a.z ) * influence;

						vB.x += ( targets[ face.b ].x - b.x ) * influence;
						vB.y += ( targets[ face.b ].y - b.y ) * influence;
						vB.z += ( targets[ face.b ].z - b.z ) * influence;

						vC.x += ( targets[ face.c ].x - c.x ) * influence;
						vC.y += ( targets[ face.c ].y - c.y ) * influence;
						vC.z += ( targets[ face.c ].z - c.z ) * influence;

					}

					vA.add( a );
					vB.add( b );
					vC.add( c );

					a = vA;
					b = vB;
					c = vC;

				}

				if ( material.side === THREE.BackSide ) {

					var intersectionPoint = ray.intersectTriangle( c, b, a, true );

				} else {

					var intersectionPoint = ray.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide );

				}

				if ( intersectionPoint === null ) continue;

				intersectionPoint.applyMatrix4( this.matrixWorld );

				var distance = raycaster.ray.origin.distanceTo( intersectionPoint );

				if ( distance < raycaster.near || distance > raycaster.far ) continue;

				intersects.push( {

					distance: distance,
					point: intersectionPoint,
					face: face,
					faceIndex: f,
					object: this

				} );

			}

		}

	};

}() );

THREE.Mesh.prototype.clone = function ( object, recursive ) {

	if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material );

	THREE.Object3D.prototype.clone.call( this, object, recursive );

	return object;

};

THREE.Mesh.prototype.toJSON = function ( meta ) {

	var data = THREE.Object3D.prototype.toJSON.call( this, meta );

	// only serialize if not in meta geometries cache
	if ( meta.geometries[ this.geometry.uuid ] === undefined ) {
		meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta );
	}

	// only serialize if not in meta materials cache
	if ( meta.materials[ this.material.uuid ] === undefined ) {
		meta.materials[ this.material.uuid ] = this.material.toJSON( meta );
	}

	data.object.geometry = this.geometry.uuid;
	data.object.material = this.material.uuid;

	return data;

};
<commit_msg>Mesh.raycast clean up.<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author mikael emtinger / http://gomo.se/
 * @author jonobr1 / http://jonobr1.com/
 */

THREE.Mesh = function ( geometry, material ) {

	THREE.Object3D.call( this );

	this.type = 'Mesh';

	this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
	this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } );

	this.updateMorphTargets();

};

THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype );
THREE.Mesh.prototype.constructor = THREE.Mesh;

THREE.Mesh.prototype.updateMorphTargets = function () {

	if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) {

		this.morphTargetBase = - 1;
		this.morphTargetForcedOrder = [];
		this.morphTargetInfluences = [];
		this.morphTargetDictionary = {};

		for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) {

			this.morphTargetInfluences.push( 0 );
			this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m;

		}

	}

};

THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) {

	if ( this.morphTargetDictionary[ name ] !== undefined ) {

		return this.morphTargetDictionary[ name ];

	}

	console.warn( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' );

	return 0;

};

THREE.Mesh.prototype.raycast = ( function () {

	var inverseMatrix = new THREE.Matrix4();
	var ray = new THREE.Ray();
	var sphere = new THREE.Sphere();

	var vA = new THREE.Vector3();
	var vB = new THREE.Vector3();
	var vC = new THREE.Vector3();

	return function ( raycaster, intersects ) {

		var geometry = this.geometry;
		var material = this.material;

		if ( material === undefined ) return;

		// Checking boundingSphere distance to ray

		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();

		sphere.copy( geometry.boundingSphere );
		sphere.applyMatrix4( this.matrixWorld );

		if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) {

			return;

		}

		// Check boundingBox before continuing

		inverseMatrix.getInverse( this.matrixWorld );
		ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );

		if ( geometry.boundingBox !== null ) {

			if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) {

				return;

			}

		}

		var a, b, c;

		if ( geometry instanceof THREE.BufferGeometry ) {

			var attributes = geometry.attributes;

			if ( attributes.index !== undefined ) {

				var indices = attributes.index.array;
				var positions = attributes.position.array;
				var offsets = geometry.offsets;

				if ( offsets.length === 0 ) {

					offsets = [ { start: 0, count: indices.length, index: 0 } ];

				}

				for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) {

					var start = offsets[ oi ].start;
					var count = offsets[ oi ].count;
					var index = offsets[ oi ].index;

					for ( var i = start, il = start + count; i < il; i += 3 ) {

						a = index + indices[ i ];
						b = index + indices[ i + 1 ];
						c = index + indices[ i + 2 ];

						vA.fromArray( positions, a * 3 );
						vB.fromArray( positions, b * 3 );
						vC.fromArray( positions, c * 3 );

						if ( material.side === THREE.BackSide ) {

							var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );

						} else {

							var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );

						}

						if ( intersectionPoint === null ) continue;

						intersectionPoint.applyMatrix4( this.matrixWorld );

						var distance = raycaster.ray.origin.distanceTo( intersectionPoint );

						if ( distance < raycaster.near || distance > raycaster.far ) continue;

						intersects.push( {

							distance: distance,
							point: intersectionPoint,
							face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),
							faceIndex: Math.floor( i / 3 ), // triangle number in indices buffer semantics
							object: this

						} );

					}

				}

			} else {

				var positions = attributes.position.array;

				for ( var i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9 ) {

					a = i;
					b = i + 1;
					c = i + 2;

					vA.fromArray( positions, j );
					vB.fromArray( positions, j + 3 );
					vC.fromArray( positions, j + 6 );

					if ( material.side === THREE.BackSide ) {

						var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );

					} else {

						var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );

					}

					if ( intersectionPoint === null ) continue;

					intersectionPoint.applyMatrix4( this.matrixWorld );

					var distance = raycaster.ray.origin.distanceTo( intersectionPoint );

					if ( distance < raycaster.near || distance > raycaster.far ) continue;

					intersects.push( {

						distance: distance,
						point: intersectionPoint,
						face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),
						index: Math.floor(i/3), // triangle number in positions buffer semantics
						object: this

					} );

				}

			}

		} else if ( geometry instanceof THREE.Geometry ) {

			var isFaceMaterial = material instanceof THREE.MeshFaceMaterial;
			var materials = isFaceMaterial === true ? material.materials : null;

			var vertices = geometry.vertices;
			var faces = geometry.faces;

			for ( var f = 0, fl = faces.length; f < fl; f ++ ) {

				var face = faces[ f ];
				var faceMaterial = isFaceMaterial === true ? materials[ face.materialIndex ] : material;

				if ( faceMaterial === undefined ) continue;

				a = vertices[ face.a ];
				b = vertices[ face.b ];
				c = vertices[ face.c ];

				if ( faceMaterial.morphTargets === true ) {

					var morphTargets = geometry.morphTargets;
					var morphInfluences = this.morphTargetInfluences;

					vA.set( 0, 0, 0 );
					vB.set( 0, 0, 0 );
					vC.set( 0, 0, 0 );

					for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {

						var influence = morphInfluences[ t ];

						if ( influence === 0 ) continue;

						var targets = morphTargets[ t ].vertices;

						vA.x += ( targets[ face.a ].x - a.x ) * influence;
						vA.y += ( targets[ face.a ].y - a.y ) * influence;
						vA.z += ( targets[ face.a ].z - a.z ) * influence;

						vB.x += ( targets[ face.b ].x - b.x ) * influence;
						vB.y += ( targets[ face.b ].y - b.y ) * influence;
						vB.z += ( targets[ face.b ].z - b.z ) * influence;

						vC.x += ( targets[ face.c ].x - c.x ) * influence;
						vC.y += ( targets[ face.c ].y - c.y ) * influence;
						vC.z += ( targets[ face.c ].z - c.z ) * influence;

					}

					vA.add( a );
					vB.add( b );
					vC.add( c );

					a = vA;
					b = vB;
					c = vC;

				}

				if ( faceMaterial.side === THREE.BackSide ) {

					var intersectionPoint = ray.intersectTriangle( c, b, a, true );

				} else {

					var intersectionPoint = ray.intersectTriangle( a, b, c, faceMaterial.side !== THREE.DoubleSide );

				}

				if ( intersectionPoint === null ) continue;

				intersectionPoint.applyMatrix4( this.matrixWorld );

				var distance = raycaster.ray.origin.distanceTo( intersectionPoint );

				if ( distance < raycaster.near || distance > raycaster.far ) continue;

				intersects.push( {

					distance: distance,
					point: intersectionPoint,
					face: face,
					faceIndex: f,
					object: this

				} );

			}

		}

	};

}() );

THREE.Mesh.prototype.clone = function ( object, recursive ) {

	if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material );

	THREE.Object3D.prototype.clone.call( this, object, recursive );

	return object;

};

THREE.Mesh.prototype.toJSON = function ( meta ) {

	var data = THREE.Object3D.prototype.toJSON.call( this, meta );

	// only serialize if not in meta geometries cache
	if ( meta.geometries[ this.geometry.uuid ] === undefined ) {
		meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta );
	}

	// only serialize if not in meta materials cache
	if ( meta.materials[ this.material.uuid ] === undefined ) {
		meta.materials[ this.material.uuid ] = this.material.toJSON( meta );
	}

	data.object.geometry = this.geometry.uuid;
	data.object.material = this.material.uuid;

	return data;

};
<|endoftext|>


<commit_before>/**
 * React Starter Kit (https://www.reactstarterkit.com/)
 *
 * Copyright © 2014-present Kriasoft, LLC. All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE.txt file in the root directory of this source tree.
 */

/* eslint-disable global-require */

// The top-level (parent) route
const routes = {
  path: '',

  // Keep in mind, routes are evaluated in order
  children: [
    {
      path: '/courses',
      load: () => import(/* webpackChunkName: 'courses' */ './courses'),
    },
    {
      path: '/courses/:id',
      load: () => import(/* webpackChunkName: 'course' */ './course'),
    },
    {
      path: '/courses/:idCourse/:idStudyEntity',
      load: () => import(/* webpackChunkName: 'studyEntity' */ './studyEntity'),
    },
    {
      path: '/users',
      load: () => import(/* webpackChunkName: 'users' */ './users'),
    },
    {
      path: '/users/:id',
      load: () => import(/* webpackChunkName: 'course' */ './user'),
    },
    {
      path: '',
      load: () => import(/* webpackChunkName: 'home' */ './home'),
    },
    {
      path: '/contact',
      load: () => import(/* webpackChunkName: 'contact' */ './contact'),
    },
    {
      path: '/login',
      load: () => import(/* webpackChunkName: 'login' */ './login'),
    },
    {
      path: '/register',
      load: () => import(/* webpackChunkName: 'register' */ './register'),
    },
    {
      path: '/about',
      load: () => import(/* webpackChunkName: 'about' */ './about'),
    },
    {
      path: '/privacy',
      load: () => import(/* webpackChunkName: 'privacy' */ './privacy'),
    },
    {
      path: '/admin',
      load: () => import(/* webpackChunkName: 'admin' */ './admin'),
    },

    // Wildcard routes, e.g. { path: '(.*)', ... } (must go last)
    {
      path: '(.*)',
      load: () => import(/* webpackChunkName: 'not-found' */ './not-found'),
    },
  ],

  async action({ next }) {
    // Execute each child route until one of them return the result
    const route = await next();

    // Provide default values for title, description etc.
    route.title = `${route.title || 'Untitled Page'} - www.reactstarterkit.com`;
    route.description = route.description || '';

    return route;
  },
};

// The error page is available by permanent url for development mode
if (__DEV__) {
  routes.children.unshift({
    path: '/error',
    action: require('./error').default,
  });
}

export default routes;
<commit_msg>fix title<commit_after>/**
 * React Starter Kit (https://www.reactstarterkit.com/)
 *
 * Copyright © 2014-present Kriasoft, LLC. All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE.txt file in the root directory of this source tree.
 */

/* eslint-disable global-require */

// The top-level (parent) route
const routes = {
  path: '',

  // Keep in mind, routes are evaluated in order
  children: [
    {
      path: '/courses',
      load: () => import(/* webpackChunkName: 'courses' */ './courses'),
    },
    {
      path: '/courses/:id',
      load: () => import(/* webpackChunkName: 'course' */ './course'),
    },
    {
      path: '/courses/:idCourse/:idStudyEntity',
      load: () => import(/* webpackChunkName: 'studyEntity' */ './studyEntity'),
    },
    {
      path: '/users',
      load: () => import(/* webpackChunkName: 'users' */ './users'),
    },
    {
      path: '/users/:id',
      load: () => import(/* webpackChunkName: 'course' */ './user'),
    },
    {
      path: '',
      load: () => import(/* webpackChunkName: 'home' */ './home'),
    },
    {
      path: '/contact',
      load: () => import(/* webpackChunkName: 'contact' */ './contact'),
    },
    {
      path: '/login',
      load: () => import(/* webpackChunkName: 'login' */ './login'),
    },
    {
      path: '/register',
      load: () => import(/* webpackChunkName: 'register' */ './register'),
    },
    {
      path: '/about',
      load: () => import(/* webpackChunkName: 'about' */ './about'),
    },
    {
      path: '/privacy',
      load: () => import(/* webpackChunkName: 'privacy' */ './privacy'),
    },
    {
      path: '/admin',
      load: () => import(/* webpackChunkName: 'admin' */ './admin'),
    },

    // Wildcard routes, e.g. { path: '(.*)', ... } (must go last)
    {
      path: '(.*)',
      load: () => import(/* webpackChunkName: 'not-found' */ './not-found'),
    },
  ],

  async action({ next }) {
    // Execute each child route until one of them return the result
    const route = await next();

    // Provide default values for title, description etc.
    route.title = `${route.title || 'Untitled Page'} - NDO`;
    route.description = route.description || '';

    return route;
  },
};

// The error page is available by permanent url for development mode
if (__DEV__) {
  routes.children.unshift({
    path: '/error',
    action: require('./error').default,
  });
}

export default routes;
<|endoftext|>


<commit_before>import React from "react";
import Calendar from "../components/Calendar";

import SourceViewButton from "../components/SourceViewButton";
import AddDay from "../components/AddDay";
import AddPeriod from "../components/AddPeriod";
import config from "../config";
import firebase from "firebase";

export default class CalendarContainer extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            calendarData: {}
        }
    }

    componentDidMount() {
        // Firebase initialization. Does not do auth
        const firebaseConfig = config.firebase;

        firebase.initializeApp(firebaseConfig);

        //const db = firebase.firestore();
        var provider = new firebase.auth.GoogleAuthProvider();
        var credential;
        if(false){ //if cookie
            credential = chrome.storage.sync.get("cred", function(res){
                credential = res.cred;
            });
        }else{
            //else get cred from chrome
            chrome.identity.getAuthToken({ 'interactive': true }, function(token) {
                credential = firebase.auth.GoogleAuthProvider.credential(null, token);
            });
            chrome.storage.sync.set({'cred': credential}, function() {
                console.log("My Schedule firebase cred saved in chrome.storage");
            });
        }
        console.log(credential);
        firebase.auth().signInWithCredential(credential);

    }

    render() {
        return (

                <Calendar calendarData={this.state.calendarData} key="calendar"/>
                <AddDay/>
                <AddPeriod/>
                <SourceViewButton/>

        );
    }
}
<commit_msg>Try to do auth again... getting closer<commit_after>import React from "react";
import Calendar from "../components/Calendar";

import SourceViewButton from "../components/SourceViewButton";
import AddDay from "../components/AddDay";
import AddPeriod from "../components/AddPeriod";
import config from "../config";
import firebase from "firebase";

export default class CalendarContainer extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            calendarData: {}
        }
    }

    componentDidMount() {
        // Firebase initialization. Does not do auth
        const firebaseConfig = config.firebase;

        firebase.initializeApp(firebaseConfig);

        //const db = firebase.firestore();
        var provider = new firebase.auth.GoogleAuthProvider();
        var credential;
        var data;
        chrome.storage.sync.get("cred", function(res){
            console.log("TRYING to get cred from chrome storage...")
            if(chrome.runtime.error){
                console.error("Whoa there! We found a chrome runtime error in storage.get!");
                data = null;
            }else{
                console.log("Res:");
                console.log(res);
                console.log("Data:");
                data = res.cred;
                console.log(data);
                console.log("Data get success. It still may be null at this point.");
            }

            if(data == null || data == undefined){ //if there is no storage
                //else get cred from chrome
                console.log("Data is null. Now getting auth token from chrome identity...");
                chrome.identity.getAuthToken({ 'interactive': false }, function(token) {
                    console.log("Successfully retrieved chrome auth token. Token:");
                    console.log(token);
                    credential = firebase.auth.GoogleAuthProvider.credential(null, token);
                    chrome.storage.sync.set({"cred": credential}, function() {
                        console.log("Extracted firebase cred, now saving the cred in chrome storage");
                        if(chrome.runtime.error){
                            console.error("Whoa there! We found a chrome runtime error in storage.set!");
                        }
                        console.log("Credential:");
                        console.log(credential);
                        firebase.auth().signInWithCredential(credential);
                    });
                });
            }else{
                //use data
                credential = data;
                console.log("If the following is true, then something went REALLY wrong...");
                console.log(data == undefined);
                console.log("Data is not null. Using the data to sign in.");
                console.log("Credential:");
                console.log(credential);
                firebase.auth().signInWithCredential(credential);
            }

        });

    }

    render() {
        return (

                <Calendar calendarData={this.state.calendarData} key="calendar"/>
                <AddDay/>
                <AddPeriod/>
                <SourceViewButton/>

        );
    }
}
<|endoftext|>


<commit_before>/**
 * @module ol/ImageTile
 */
import Tile from './Tile.js';
import TileState from './TileState.js';
import {createCanvasContext2D} from './dom.js';
import {listenImage} from './Image.js';

class ImageTile extends Tile {
  /**
   * @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {import("./TileState.js").default} state State.
   * @param {string} src Image source URI.
   * @param {?string} crossOrigin Cross origin.
   * @param {import("./Tile.js").LoadFunction} tileLoadFunction Tile load function.
   * @param {import("./Tile.js").Options} [opt_options] Tile options.
   */
  constructor(
    tileCoord,
    state,
    src,
    crossOrigin,
    tileLoadFunction,
    opt_options
  ) {
    super(tileCoord, state, opt_options);

    /**
     * @private
     * @type {?string}
     */
    this.crossOrigin_ = crossOrigin;

    /**
     * Image URI
     *
     * @private
     * @type {string}
     */
    this.src_ = src;

    this.key = src;

    /**
     * @private
     * @type {HTMLImageElement|HTMLCanvasElement}
     */
    this.image_ = new Image();
    if (crossOrigin !== null) {
      this.image_.crossOrigin = crossOrigin;
    }

    /**
     * @private
     * @type {?function():void}
     */
    this.unlisten_ = null;

    /**
     * @private
     * @type {import("./Tile.js").LoadFunction}
     */
    this.tileLoadFunction_ = tileLoadFunction;
  }

  /**
   * Get the HTML image element for this tile (may be a Canvas, Image, or Video).
   * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
   * @api
   */
  getImage() {
    return this.image_;
  }

  /**
   * Sets an HTML image element for this tile (may be a Canvas or preloaded Image).
   * @param {HTMLCanvasElement|HTMLImageElement} element Element.
   * @api
   */
  setImage(element) {
    this.image_ = element;
    this.state = TileState.LOADED;
    this.unlistenImage_();
    this.changed();
  }

  /**
   * Tracks loading or read errors.
   *
   * @private
   */
  handleImageError_() {
    this.state = TileState.ERROR;
    this.unlistenImage_();
    this.image_ = getBlankImage();
    this.changed();
  }

  /**
   * Tracks successful image load.
   *
   * @private
   */
  handleImageLoad_() {
    const image = /** @type {HTMLImageElement} */ (this.image_);
    if (image.naturalWidth && image.naturalHeight) {
      this.state = TileState.LOADED;
    } else {
      this.state = TileState.EMPTY;
    }
    this.unlistenImage_();
    this.changed();
  }

  /**
   * Load not yet loaded URI.
   * @api
   */
  load() {
    if (this.state == TileState.ERROR) {
      this.state = TileState.IDLE;
      this.image_ = new Image();
      if (this.crossOrigin_ !== null) {
        this.image_.crossOrigin = this.crossOrigin_;
      }
    }
    if (this.state == TileState.IDLE) {
      this.state = TileState.LOADING;
      this.changed();
      this.tileLoadFunction_(this, this.src_);
      this.unlisten_ = listenImage(
        this.image_,
        this.handleImageLoad_.bind(this),
        this.handleImageError_.bind(this)
      );
    }
  }

  /**
   * Discards event handlers which listen for load completion or errors.
   *
   * @private
   */
  unlistenImage_() {
    if (this.unlisten_) {
      this.unlisten_();
      this.unlisten_ = null;
    }
  }
}

/**
 * Get a 1-pixel blank image.
 * @return {HTMLCanvasElement} Blank image.
 */
function getBlankImage() {
  const ctx = createCanvasContext2D(1, 1);
  ctx.fillStyle = 'rgba(0,0,0,0)';
  ctx.fillRect(0, 0, 1, 1);
  return ctx.canvas;
}

export default ImageTile;
<commit_msg>Don't add setImage to the API<commit_after>/**
 * @module ol/ImageTile
 */
import Tile from './Tile.js';
import TileState from './TileState.js';
import {createCanvasContext2D} from './dom.js';
import {listenImage} from './Image.js';

class ImageTile extends Tile {
  /**
   * @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {import("./TileState.js").default} state State.
   * @param {string} src Image source URI.
   * @param {?string} crossOrigin Cross origin.
   * @param {import("./Tile.js").LoadFunction} tileLoadFunction Tile load function.
   * @param {import("./Tile.js").Options} [opt_options] Tile options.
   */
  constructor(
    tileCoord,
    state,
    src,
    crossOrigin,
    tileLoadFunction,
    opt_options
  ) {
    super(tileCoord, state, opt_options);

    /**
     * @private
     * @type {?string}
     */
    this.crossOrigin_ = crossOrigin;

    /**
     * Image URI
     *
     * @private
     * @type {string}
     */
    this.src_ = src;

    this.key = src;

    /**
     * @private
     * @type {HTMLImageElement|HTMLCanvasElement}
     */
    this.image_ = new Image();
    if (crossOrigin !== null) {
      this.image_.crossOrigin = crossOrigin;
    }

    /**
     * @private
     * @type {?function():void}
     */
    this.unlisten_ = null;

    /**
     * @private
     * @type {import("./Tile.js").LoadFunction}
     */
    this.tileLoadFunction_ = tileLoadFunction;
  }

  /**
   * Get the HTML image element for this tile (may be a Canvas, Image, or Video).
   * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
   * @api
   */
  getImage() {
    return this.image_;
  }

  /**
   * Sets an HTML image element for this tile (may be a Canvas or preloaded Image).
   * @param {HTMLCanvasElement|HTMLImageElement} element Element.
   */
  setImage(element) {
    this.image_ = element;
    this.state = TileState.LOADED;
    this.unlistenImage_();
    this.changed();
  }

  /**
   * Tracks loading or read errors.
   *
   * @private
   */
  handleImageError_() {
    this.state = TileState.ERROR;
    this.unlistenImage_();
    this.image_ = getBlankImage();
    this.changed();
  }

  /**
   * Tracks successful image load.
   *
   * @private
   */
  handleImageLoad_() {
    const image = /** @type {HTMLImageElement} */ (this.image_);
    if (image.naturalWidth && image.naturalHeight) {
      this.state = TileState.LOADED;
    } else {
      this.state = TileState.EMPTY;
    }
    this.unlistenImage_();
    this.changed();
  }

  /**
   * Load not yet loaded URI.
   * @api
   */
  load() {
    if (this.state == TileState.ERROR) {
      this.state = TileState.IDLE;
      this.image_ = new Image();
      if (this.crossOrigin_ !== null) {
        this.image_.crossOrigin = this.crossOrigin_;
      }
    }
    if (this.state == TileState.IDLE) {
      this.state = TileState.LOADING;
      this.changed();
      this.tileLoadFunction_(this, this.src_);
      this.unlisten_ = listenImage(
        this.image_,
        this.handleImageLoad_.bind(this),
        this.handleImageError_.bind(this)
      );
    }
  }

  /**
   * Discards event handlers which listen for load completion or errors.
   *
   * @private
   */
  unlistenImage_() {
    if (this.unlisten_) {
      this.unlisten_();
      this.unlisten_ = null;
    }
  }
}

/**
 * Get a 1-pixel blank image.
 * @return {HTMLCanvasElement} Blank image.
 */
function getBlankImage() {
  const ctx = createCanvasContext2D(1, 1);
  ctx.fillStyle = 'rgba(0,0,0,0)';
  ctx.fillRect(0, 0, 1, 1);
  return ctx.canvas;
}

export default ImageTile;
<|endoftext|>


<commit_before>/**
 * @file 数据类
 * @author errorrik(errorrik@gmail.com)
 */

var ExprType = require('../parser/expr-type');
var evalExpr = require('./eval-expr');
var DataChangeType = require('./data-change-type');
var parseExpr = require('../parser/parse-expr');
var each = require('../util/each');

/**
 * 数据类
 *
 * @class
 * @param {Object?} data 初始数据
 * @param {Model?} parent 父级数据容器
 */
function Data(data, parent) {
    this.parent = parent;
    this.raw = data || {};
    this.listeners = [];
}

// #[begin] error
// 以下两个函数只在开发模式下可用，在生产模式下不存在
/**
 * DataTypes 检测
 */
Data.prototype.checkDataTypes = function () {
    if (this.typeChecker) {
        this.typeChecker(this.raw);
    }
};

/**
 * 设置 type checker
 *
 * @param  {Function} typeChecker 类型校验器
 */
Data.prototype.setTypeChecker = function (typeChecker) {
    this.typeChecker = typeChecker;
};

// #[end]

/**
 * 添加数据变更的事件监听器
 *
 * @param {Function} listener 监听函数
 */
Data.prototype.listen = function (listener) {
    if (typeof listener === 'function') {
        this.listeners.push(listener);
    }
};

/**
 * 移除数据变更的事件监听器
 *
 * @param {Function} listener 监听函数
 */
Data.prototype.unlisten = function (listener) {
    var len = this.listeners.length;
    while (len--) {
        if (!listener || this.listeners[len] === listener) {
            this.listeners.splice(len, 1);
        }
    }
};

/**
 * 触发数据变更
 *
 * @param {Object} change 变更信息对象
 */
Data.prototype.fire = function (change) {
    if (change.option.silent || change.option.silence || change.option.quiet) {
        return;
    }

    each(this.listeners, function (listener) {
        listener.call(this, change);
    }, this);
};

/**
 * 获取数据项
 *
 * @param {string|Object?} expr 数据项路径
 * @return {*}
 */
Data.prototype.get = function (expr) {
    var value = this.raw;
    if (!expr) {
        return value;
    }

    expr = parseExpr(expr);

    var paths = expr.paths;
    var start = 0;
    var l = paths.length;

    for (; start < l; start++) {
        if (paths[start].value == null) {
            break;
        }
    }

    var i = 0;
    for (; value != null && i < start; i++) {
        value = value[paths[i].value];
    }

    if (value == null && this.parent) {
        value = this.parent.get({
            type: ExprType.ACCESSOR,
            paths: paths.slice(0, start)
        });
    }

    for (i = start; value != null && i < l; i++) {
        value = value[evalExpr(paths[i], this)];
    }

    return value;
};

/**
 * 数据对象变更操作
 *
 * @inner
 * @param {Object|Array} source 要变更的源数据
 * @param {Array} exprPaths 属性路径
 * @param {*} value 变更属性值
 * @param {Data} data 对应的Data对象
 * @return {*} 变更后的新数据
 */
function immutableSet(source, exprPaths, value, data) {
    if (exprPaths.length === 0) {
        return value;
    }

    var prop = evalExpr(exprPaths[0], data);
    var result;

    if (source instanceof Array) {
        var index = +prop;

        result = source.slice(0);
        result[isNaN(index) ? prop : index] = immutableSet(source[index], exprPaths.slice(1), value, data);

        return result;
    }
    else if (typeof source === 'object') {
        result = {};

        for (var key in source) {
            if (key !== prop) {
                result[key] = source[key];
            }
        }

        result[prop] = immutableSet(source[prop] || {}, exprPaths.slice(1), value, data);

        return result;
    }

    return source;
}

/**
 * 设置数据项
 *
 * @param {string|Object} expr 数据项路径
 * @param {*} value 数据值
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 */
Data.prototype.set = function (expr, value, option) {
    option = option || {};

    // #[begin] error
    var exprRaw = expr;
    // #[end]

    expr = parseExpr(expr);

    // #[begin] error
    if (expr.type !== ExprType.ACCESSOR) {
        throw new Error('[SAN ERROR] Invalid Expression in Data set: ' + exprRaw);
    }
    // #[end]

    if (this.get(expr) === value) {
        return;
    }

    this.raw = immutableSet(this.raw, expr.paths, value, this);
    this.fire({
        type: DataChangeType.SET,
        expr: expr,
        value: value,
        option: option
    });

    // #[begin] error
    this.checkDataTypes();
    // #[end]

};

Data.prototype.splice = function (expr, args, option) {
    option = option || {};
    // #[begin] error
    var exprRaw = expr;
    // #[end]

    expr = parseExpr(expr);

    // #[begin] error
    if (expr.type !== ExprType.ACCESSOR) {
        throw new Error('[SAN ERROR] Invalid Expression in Data splice: ' + exprRaw);
    }
    // #[end]

    var target = this.get(expr);
    var returnValue = [];

    if (target instanceof Array) {
        var index = args[0];
        if (index < 0 || index > target.length) {
            return;
        }

        var newArray = target.slice(0);
        returnValue = newArray.splice.apply(newArray, args);
        this.raw = immutableSet(this.raw, expr.paths, newArray, this);

        this.fire({
            expr: expr,
            type: DataChangeType.SPLICE,
            index: index,
            deleteCount: returnValue.length,
            value: returnValue,
            insertions: args.slice(2),
            option: option
        });
    }

    // #[begin] error
    this.checkDataTypes();
    // #[end]

    return returnValue;
};

/**
 * 数组数据项push操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {*} item 要push的值
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 * @return {number} 新数组的length属性
 */
Data.prototype.push = function (expr, item, option) {
    var target = this.get(expr);

    if (target instanceof Array) {
        this.splice(expr, [target.length, 0, item], option);
        return target.length + 1;
    }
};

/**
 * 数组数据项pop操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 * @return {*}
 */
Data.prototype.pop = function (expr, option) {
    var target = this.get(expr);

    if (target instanceof Array) {
        var len = target.length;
        if (len) {
            return this.splice(expr, [len - 1, 1], option)[0];
        }
    }
};

/**
 * 数组数据项shift操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 * @return {*}
 */
Data.prototype.shift = function (expr, option) {
    return this.splice(expr, [0, 1], option)[0];
};

/**
 * 数组数据项unshift操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {*} item 要unshift的值
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 * @return {number} 新数组的length属性
 */
Data.prototype.unshift = function (expr, item, option) {
    var target = this.get(expr);

    if (target instanceof Array) {
        this.splice(expr, [0, 0, item], option);
        return target.length + 1;
    }
};

/**
 * 数组数据项移除操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {number} index 要移除项的索引
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 */
Data.prototype.removeAt = function (expr, index, option) {
    this.splice(expr, [index, 1], option);
};

/**
 * 数组数据项移除操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {*} value 要移除的项
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 */
Data.prototype.remove = function (expr, value, option) {
    var target = this.get(expr);

    if (target instanceof Array) {
        var len = target.length;
        while (len--) {
            if (target[len] === value) {
                this.splice(expr, [len, 1], option);
                break;
            }
        }
    }
};

exports = module.exports = Data;
<commit_msg>feat:Data数据对象添加merge、apply方法<commit_after>/**
 * @file 数据类
 * @author errorrik(errorrik@gmail.com)
 */

var ExprType = require('../parser/expr-type');
var evalExpr = require('./eval-expr');
var DataChangeType = require('./data-change-type');
var parseExpr = require('../parser/parse-expr');
var each = require('../util/each');

/**
 * 数据类
 *
 * @class
 * @param {Object?} data 初始数据
 * @param {Model?} parent 父级数据容器
 */
function Data(data, parent) {
    this.parent = parent;
    this.raw = data || {};
    this.listeners = [];
}

// #[begin] error
// 以下两个函数只在开发模式下可用，在生产模式下不存在
/**
 * DataTypes 检测
 */
Data.prototype.checkDataTypes = function () {
    if (this.typeChecker) {
        this.typeChecker(this.raw);
    }
};

/**
 * 设置 type checker
 *
 * @param  {Function} typeChecker 类型校验器
 */
Data.prototype.setTypeChecker = function (typeChecker) {
    this.typeChecker = typeChecker;
};

// #[end]

/**
 * 添加数据变更的事件监听器
 *
 * @param {Function} listener 监听函数
 */
Data.prototype.listen = function (listener) {
    if (typeof listener === 'function') {
        this.listeners.push(listener);
    }
};

/**
 * 移除数据变更的事件监听器
 *
 * @param {Function} listener 监听函数
 */
Data.prototype.unlisten = function (listener) {
    var len = this.listeners.length;
    while (len--) {
        if (!listener || this.listeners[len] === listener) {
            this.listeners.splice(len, 1);
        }
    }
};

/**
 * 触发数据变更
 *
 * @param {Object} change 变更信息对象
 */
Data.prototype.fire = function (change) {
    if (change.option.silent || change.option.silence || change.option.quiet) {
        return;
    }

    each(this.listeners, function (listener) {
        listener.call(this, change);
    }, this);
};

/**
 * 获取数据项
 *
 * @param {string|Object?} expr 数据项路径
 * @return {*}
 */
Data.prototype.get = function (expr) {
    var value = this.raw;
    if (!expr) {
        return value;
    }

    expr = parseExpr(expr);

    var paths = expr.paths;
    var start = 0;
    var l = paths.length;

    for (; start < l; start++) {
        if (paths[start].value == null) {
            break;
        }
    }

    var i = 0;
    for (; value != null && i < start; i++) {
        value = value[paths[i].value];
    }

    if (value == null && this.parent) {
        value = this.parent.get({
            type: ExprType.ACCESSOR,
            paths: paths.slice(0, start)
        });
    }

    for (i = start; value != null && i < l; i++) {
        value = value[evalExpr(paths[i], this)];
    }

    return value;
};

/**
 * 数据对象变更操作
 *
 * @inner
 * @param {Object|Array} source 要变更的源数据
 * @param {Array} exprPaths 属性路径
 * @param {*} value 变更属性值
 * @param {Data} data 对应的Data对象
 * @return {*} 变更后的新数据
 */
function immutableSet(source, exprPaths, value, data) {
    if (exprPaths.length === 0) {
        return value;
    }

    var prop = evalExpr(exprPaths[0], data);
    var result;

    if (source instanceof Array) {
        var index = +prop;

        result = source.slice(0);
        result[isNaN(index) ? prop : index] = immutableSet(source[index], exprPaths.slice(1), value, data);

        return result;
    }
    else if (typeof source === 'object') {
        result = {};

        for (var key in source) {
            if (key !== prop) {
                result[key] = source[key];
            }
        }

        result[prop] = immutableSet(source[prop] || {}, exprPaths.slice(1), value, data);

        return result;
    }

    return source;
}

/**
 * 设置数据项
 *
 * @param {string|Object} expr 数据项路径
 * @param {*} value 数据值
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 */
Data.prototype.set = function (expr, value, option) {
    option = option || {};

    // #[begin] error
    var exprRaw = expr;
    // #[end]

    expr = parseExpr(expr);

    // #[begin] error
    if (expr.type !== ExprType.ACCESSOR) {
        throw new Error('[SAN ERROR] Invalid Expression in Data set: ' + exprRaw);
    }
    // #[end]

    if (this.get(expr) === value) {
        return;
    }

    this.raw = immutableSet(this.raw, expr.paths, value, this);
    this.fire({
        type: DataChangeType.SET,
        expr: expr,
        value: value,
        option: option
    });

    // #[begin] error
    this.checkDataTypes();
    // #[end]

};

/**
 * 合并更新数据项
 *
 * @param {string|Object} expr 数据项路径
 * @param {Object} source 待合并的数据值
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 */
Data.prototype.merge = function (expr, source, option) {
    option = option || {};

    // #[begin] error
    var exprRaw = expr;
    // #[end]

    expr = parseExpr(expr);

    // #[begin] error
    if (expr.type !== ExprType.ACCESSOR) {
        throw new Error('[SAN ERROR] Invalid Expression in Data merge: ' + exprRaw);
    }
    // #[end]

    var oldValue = this.get(expr);

    // #[begin] error
    if (typeof oldValue !== 'object') {
        throw new Error('[SAN ERROR] Merge Expects a Target of Type \'object\'; got ' + typeof oldValue);
    }

    if (typeof source !== 'object') {
        throw new Error('[SAN ERROR] Merge Expects a Source of Type \'object\'; got ' + typeof source);
    }
    // #[end]

    for (var key in oldValue) {
        if (!source.hasOwnProperty(key)) {
            source[key] = oldValue[key];
        }
    }

    this.raw = immutableSet(this.raw, expr.paths, source, this);
    this.fire({
        type: DataChangeType.SET,
        expr: expr,
        value: source,
        option: option
    });

    // #[begin] error
    this.checkDataTypes();
    // #[end]
};

/**
 * 基于更新函数更新数据项
 *
 * @param {string|Object} expr 数据项路径
 * @param {Function} fn 数据处理函数
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 */
Data.prototype.apply = function (expr, fn, option) {
    option = option || {};

    // #[begin] error
    var exprRaw = expr;
    // #[end]

    expr = parseExpr(expr);

    // #[begin] error
    if (expr.type !== ExprType.ACCESSOR) {
        throw new Error('[SAN ERROR] Invalid Expression in Data apply: ' + exprRaw);
    }
    // #[end]

    var oldValue = this.get(expr);

    // #[begin] error
    if (typeof fn !== 'function') {
        throw new Error(
            '[SAN ERROR] Invalid Argument\'s Type in Data apply: '
            + 'Expected Function but got ' + typeof fn
        );
    }
    // #[end]

    var value = fn(oldValue);

    if (oldValue === value) {
        return;
    }

    this.raw = immutableSet(this.raw, expr.paths, value, this);
    this.fire({
        type: DataChangeType.SET,
        expr: expr,
        value: value,
        option: option
    });

    // #[begin] error
    this.checkDataTypes();
    // #[end]
};

Data.prototype.splice = function (expr, args, option) {
    option = option || {};
    // #[begin] error
    var exprRaw = expr;
    // #[end]

    expr = parseExpr(expr);

    // #[begin] error
    if (expr.type !== ExprType.ACCESSOR) {
        throw new Error('[SAN ERROR] Invalid Expression in Data splice: ' + exprRaw);
    }
    // #[end]

    var target = this.get(expr);
    var returnValue = [];

    if (target instanceof Array) {
        var index = args[0];
        if (index < 0 || index > target.length) {
            return;
        }

        var newArray = target.slice(0);
        returnValue = newArray.splice.apply(newArray, args);
        this.raw = immutableSet(this.raw, expr.paths, newArray, this);

        this.fire({
            expr: expr,
            type: DataChangeType.SPLICE,
            index: index,
            deleteCount: returnValue.length,
            value: returnValue,
            insertions: args.slice(2),
            option: option
        });
    }

    // #[begin] error
    this.checkDataTypes();
    // #[end]

    return returnValue;
};

/**
 * 数组数据项push操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {*} item 要push的值
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 * @return {number} 新数组的length属性
 */
Data.prototype.push = function (expr, item, option) {
    var target = this.get(expr);

    if (target instanceof Array) {
        this.splice(expr, [target.length, 0, item], option);
        return target.length + 1;
    }
};

/**
 * 数组数据项pop操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 * @return {*}
 */
Data.prototype.pop = function (expr, option) {
    var target = this.get(expr);

    if (target instanceof Array) {
        var len = target.length;
        if (len) {
            return this.splice(expr, [len - 1, 1], option)[0];
        }
    }
};

/**
 * 数组数据项shift操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 * @return {*}
 */
Data.prototype.shift = function (expr, option) {
    return this.splice(expr, [0, 1], option)[0];
};

/**
 * 数组数据项unshift操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {*} item 要unshift的值
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 * @return {number} 新数组的length属性
 */
Data.prototype.unshift = function (expr, item, option) {
    var target = this.get(expr);

    if (target instanceof Array) {
        this.splice(expr, [0, 0, item], option);
        return target.length + 1;
    }
};

/**
 * 数组数据项移除操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {number} index 要移除项的索引
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 */
Data.prototype.removeAt = function (expr, index, option) {
    this.splice(expr, [index, 1], option);
};

/**
 * 数组数据项移除操作
 *
 * @param {string|Object} expr 数据项路径
 * @param {*} value 要移除的项
 * @param {Object=} option 设置参数
 * @param {boolean} option.silent 静默设置，不触发变更事件
 */
Data.prototype.remove = function (expr, value, option) {
    var target = this.get(expr);

    if (target instanceof Array) {
        var len = target.length;
        while (len--) {
            if (target[len] === value) {
                this.splice(expr, [len, 1], option);
                break;
            }
        }
    }
};

exports = module.exports = Data;
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import Mousetrap from 'mousetrap'
import {
  selectInnerHeight,
  selectInnerWidth,
} from '../selectors/gui'
import {
  selectPostsAssetIds,
} from '../selectors/light_box'
import { scrollToPosition } from '../lib/jello'
import { DismissButtonLGReverse } from '../components/buttons/Buttons'
import PostContainer from './PostContainer'
import CommentContainer from './CommentContainer'
// import { RegionItems } from '../regions/RegionRenderables'
import { css, select, media } from '../styles/jss'
import * as s from '../styles/jso'
import { SHORTCUT_KEYS } from '../constants/application_types'

const baseLightBoxStyle = css(
  s.block,
  s.relative,
  s.bgcF2,
  { margin: '0 auto' },
  select(
    '> .LightBoxMask',
    s.fullscreen,
    s.fullWidth,
    s.fullHeight,
    s.bgcModal,
    s.zModal,
    { transition: `background-color 0.4s ${s.ease}` },
    select(
      '> .LightBox',
      s.fixed,
      s.flood,
      s.fullWidth,
      s.fullHeight,
      s.overflowHidden,
      s.flex,
      s.itemsCenter,
      select(
        '> .LightBoxQueue',
        s.transitionOpacity,
        s.relative,
        {
          width: 'auto',
          whiteSpace: 'nowrap',
          opacity: 1,
        },
      ),
    ),
    select(
      '> .LightBox.loaded',
      select(
        '> .LightBoxQueue',
        s.transitionTransform,
      ),
    ),
    select(
      '> .LightBox.loading',
      select(
        '> .LightBoxQueue',
        { opacity: 0 },
      ),
    ),
  ),
)

const imageRegionStyle = select(
  '> .ImageRegion',
  s.inlineBlock,
  s.relative,
  {
    margin: 0,
    marginLeft: 40,
    marginRight: 40,
    width: 'auto',
  },
  media(
    s.maxBreak4,
    { marginLeft: 30,
      marginRight: 30,
    },
  ),
  media(
    s.maxBreak3,
    { marginLeft: 20,
      marginRight: 20,
    },
  ),
  media(
    s.maxBreak2,
    { marginLeft: 10,
      marginRight: 10,
    },
  ),
  select(
    '> .ImgHolderLightBox',
    s.inline,
  ),
)

const commentsLightBoxStyle = css(
  { ...baseLightBoxStyle },
  select(
    '> .LightBoxMask',
    select(
      '> .LightBox',
      select(
        '> .LightBoxQueue',
        select(
          '> .Comment',
          s.inline,
          { padding: 0 },
          select(
            '> .CommentBody',
            s.inline,
            { padding: 0,
              margin: 0,
              border: 'none',
              width: 'auto',
            },
            select(
              '> div',
              s.inline,
              { ...imageRegionStyle },
            ),
          ),
        ),
      ),
    ),
  ),
)

const postsListLightBoxStyle = css(
  { ...baseLightBoxStyle },
  select(
    '> .LightBoxMask',
    select(
      '> .LightBox',
      select(
        '> .LightBoxQueue',
        select(
          '> .Post',
          s.inline,
          { margin: 0,
            padding: 0,
          },
          select(
            '> .PostBody',
            s.inline,
            { padding: 0,
              margin: 0,
              border: 'none',
              width: 'auto',
            },
            select(
              '> div',
              s.inline,
              { ...imageRegionStyle },
            ),
          ),
        ),
      ),
    ),
  ),
)

// Wraps LightBox controls/state around a component
// This function takes a component
function LightBoxWrapper(WrappedComponent) {
  class BaseLightBox extends Component {
    static propTypes = {
      innerHeight: PropTypes.number,
      innerWidth: PropTypes.number,
      commentIds: PropTypes.object, // for comment stream
      postAssetIdPairs: PropTypes.array, // post/asset id pairs
    }

    static defaultProps = {
      innerHeight: null,
      innerWidth: null,
      commentIds: null,
      postAssetIdPairs: null,
    }

    constructor(props) {
      super(props)
      this.state = {
        open: false,
        loading: true,
        loaded: false,
        assetIdToSet: null,
        assetIdToSetPrev: null,
        assetIdToSetNext: null,
        postIdToSet: null,
        postIdToSetPrev: null,
        postIdToSetNext: null,
        innerWidth: this.props.innerWidth,
        innerHeight: this.props.innerHeight,
        resize: false,
        queueOffsetX: 0,
      }

      this.handleImageClick = this.handleImageClick.bind(this)
      this.handleViewPortResize = this.handleViewPortResize.bind(this)
      this.close = this.close.bind(this)
    }

    componentDidUpdate(prevProps, prevState) {
      // set keybindings
      if (!prevState.open && this.state.open) {
        this.bindKeys()
      }

      const slideDelay = !prevState.open ? 200 : 0
      const transitionDelay = 200

      // advance lightbox queue to specific asset
      if (this.state.open && (prevState.assetIdToSet !== this.state.assetIdToSet)) {
        setTimeout(() => {
          this.slideQueue()
        }, slideDelay)
      }

      // remove loading close if lightbox was recently opened
      if (this.state.open && !prevState.open) {
        setTimeout(() => {
          this.removeLoadingClass()
        }, transitionDelay)
      }

      // check for viewport resizes
      if ((this.state.open && !this.state.resize) &&
        ((this.props.innerWidth !== this.state.innerWidth) ||
        (this.props.innerHeight !== this.state.innerHeight))) {
        this.handleViewPortResize(true)
      }

      // reset resize bool
      if (!prevState.resize && this.state.resize) {
        this.handleViewPortResize(false)
      }
    }

    componentWillUnmount() {
      const releaseKeys = true
      this.bindKeys(releaseKeys)
    }

    setPagination(assetId, postId) {
      const { postAssetIdPairs } = this.props

      if (postAssetIdPairs) {
        const numberItems = postAssetIdPairs.length
        let existingItemIndex = null

        // match `assetId` and `postId` with `postAssetIdPairs` pair
        postAssetIdPairs.map((postAssetIdPair, index) => {
          if ((postAssetIdPair[1] === assetId) &&
            (postAssetIdPair[0] === postId)) {
            existingItemIndex = index
            return existingItemIndex
          }
          return null
        })

        // if there was a match, set prev/next indices + grab ids
        if (existingItemIndex !== null) {
          let prevIndex = existingItemIndex - 1
          let nextIndex = existingItemIndex + 1

          if (existingItemIndex === 0) {
            prevIndex = 0
          }

          if (existingItemIndex === (numberItems - 1)) {
            nextIndex = existingItemIndex
          }

          const prevItemAssetId = postAssetIdPairs[prevIndex][1]
          const nextItemAssetId = postAssetIdPairs[nextIndex][1]
          const prevItemPostId = postAssetIdPairs[prevIndex][0]
          const nextItemPostId = postAssetIdPairs[nextIndex][0]

          return this.setState({
            assetIdToSetPrev: prevItemAssetId,
            assetIdToSetNext: nextItemAssetId,
            postIdToSetPrev: prevItemPostId,
            postIdToSetNext: nextItemPostId,
          })
        }
        return null
      }
      return null
    }

    setLightBoxStyle() {
      const { commentIds } = this.props

      if (commentIds) {
        return commentsLightBoxStyle
      }

      return postsListLightBoxStyle
    }

    advance(direction) {
      let newAssetIdToSet = null
      let newPostIdToSet = null

      switch (direction) {
        case 'prev' :
          newAssetIdToSet = this.state.assetIdToSetPrev
          newPostIdToSet = this.state.postIdToSetPrev
          break
        case 'next' :
          newAssetIdToSet = this.state.assetIdToSetNext
          newPostIdToSet = this.state.postIdToSetNext
          break
        default :
          newAssetIdToSet = this.state.assetIdToSet
          newPostIdToSet = this.state.postIdToSet
      }

      // advance to new image
      this.setState({
        assetIdToSet: newAssetIdToSet,
        postIdToSet: newPostIdToSet,
      })

      // scroll the page to image
      this.scrollToSelectedAsset(newAssetIdToSet, newPostIdToSet)

      // update pagination
      return this.setPagination(newAssetIdToSet, newPostIdToSet)
    }

    slideQueue() {
      const assetId = this.state.assetIdToSet
      const postId = this.state.postIdToSet
      const assetDomId = `lightBoxAsset_${assetId}_${postId}`

      // select the DOM elements
      const lightBoxDomQueue = document.getElementsByClassName('LightBoxQueue')[0]
      const assetInDom = document.getElementById(assetDomId)

      // measurements
      const viewportWidth = window.innerWidth
      const lightBoxDimensions = lightBoxDomQueue.getBoundingClientRect()
      const assetDimensions = assetInDom.getBoundingClientRect()

      // positioning calculations
      const desiredGap = ((viewportWidth - (assetDimensions.width)) / 2)
      const imageOffsetToBox = assetDimensions.x - lightBoxDimensions.x
      const newOffset = desiredGap - imageOffsetToBox

      // update the box position
      return this.setState({
        queueOffsetX: newOffset,
      })
    }

    scrollToSelectedAsset(newAssetIdToSet, newPostIdToSet) {
      const commentsStream = this.props.commentIds
      const assetDomId = `asset_${newAssetIdToSet}_${newPostIdToSet}`

      // grab elements from the dom
      const postList = document.getElementsByClassName('PostList')
      const postSideBar = document.getElementsByClassName('PostSideBar')
      const assetInDom = document.getElementById(assetDomId)

      // determine scroll offset of asset in dom
      let assetInDomTopOffset = null
      if (postSideBar.length) { // post detail view (scrolling inner-div needs different treatement)
        if (commentsStream) {
          assetInDomTopOffset = assetInDom.getBoundingClientRect().top + postSideBar[0].scrollTop
        } else {
          assetInDomTopOffset = assetInDom.getBoundingClientRect().top + postList[0].scrollTop
        }
      } else {
        assetInDomTopOffset = assetInDom.getBoundingClientRect().top + window.scrollY
      }

      // adjust scroll offset for window height / nav bar
      const windowHeight = window.innerHeight
      const offsetPadding = (windowHeight / 10)
      const scrollToOffset = (assetInDomTopOffset - offsetPadding)

      // scroll to new position
      if (postList.length && postSideBar.length) { // post detail view
        let scrollElement = postList[0]
        if (commentsStream) {
          scrollElement = postSideBar[0]
        }
        return scrollToPosition(0, scrollToOffset, { el: scrollElement })
      }
      return scrollToPosition(0, scrollToOffset) // stream container view
    }

    close() {
      const releaseKeys = true
      this.bindKeys(releaseKeys)

      return this.setState({
        open: false,
        loading: true,
        loaded: false,
        assetIdToSet: null,
        queueOffsetX: 0,
      })
    }

    handleMaskClick(e) {
      if (e.target.nodeName !== 'IMG' &&
        e.target.nodeName !== 'VIDEO' &&
        e.target.nodeName !== 'BUTTON') {
        return this.close()
      }
      return null
    }

    handleImageClick(assetId, postId) {
      const { open, assetIdToSet, postIdToSet } = this.state

      if (open && (assetId === assetIdToSet) && (postId === postIdToSet)) {
        return this.close()
      }

      // advance to new image
      this.setState({
        open: true,
        assetIdToSet: assetId,
        postIdToSet: postId,
      })

      // scroll the page to image
      this.scrollToSelectedAsset(assetId, postId)

      // update pagination
      return this.setPagination(assetId, postId)
    }

    handleViewPortResize(isResize) {
      // resize on
      if (isResize) {
        return this.setState({
          innerWidth,
          innerHeight,
          resize: true,
        })
      }

      // resize off
      setTimeout(() => {
        this.slideQueue()
      }, 250)

      return this.setState({
        resize: false,
      })
    }

    removeLoadingClass() {
      const transitionDelay = 200

      this.setState({
        loading: false,
      })

      return setTimeout(() => {
        this.setState({
          loaded: true,
        })
      }, transitionDelay)
    }

    bindKeys(unbind) {
      Mousetrap.unbind(SHORTCUT_KEYS.ESC)
      Mousetrap.unbind(SHORTCUT_KEYS.PREV)
      Mousetrap.unbind(SHORTCUT_KEYS.NEXT)

      if (!unbind) {
        Mousetrap.bind(SHORTCUT_KEYS.ESC, () => { this.close() })
        Mousetrap.bind(SHORTCUT_KEYS.PREV, () => { this.advance('prev') })
        Mousetrap.bind(SHORTCUT_KEYS.NEXT, () => { this.advance('next') })
      }
    }

    constructPostIdsArray() {
      const { postAssetIdPairs } = this.props
      const { assetIdToSet, postIdToSet } = this.state
      const allPostIds = []

      // set the offset indices
      const assetsOffset = 6
      const indexOfSelected = postAssetIdPairs.findIndex(
        postAssetIdPair =>
        (postAssetIdPair[0] === postIdToSet && postAssetIdPair[1] === assetIdToSet))
      const indexLower = indexOfSelected > (assetsOffset - 1) ? (indexOfSelected - assetsOffset) : 0
      const indexHigher = indexOfSelected + assetsOffset

      // truncate the postAssetIdPairs array
      const truncatedPostAssetIdPairs = postAssetIdPairs.slice(indexLower, indexHigher)
      truncatedPostAssetIdPairs.map(postAssedIdPair => allPostIds.push(postAssedIdPair[0]))

      // grab the unique postIds from the pairs array
      const postIds = Array.from(new Set(allPostIds))
      return postIds
    }

    render() {
      const { postAssetIdPairs } = this.props

      return (

          {this.state.open &&

 this.handleMaskClick(e)}>
                <DismissButtonLGReverse
                  onClick={this.close}
                />
                <div className={`LightBox ${this.state.loading ? 'loading' : ''}${this.state.loaded ? 'loaded' : ''}`}>
                  <div
                    className="LightBoxQueue"
                    style={{ transform: `translateX(${this.state.queueOffsetX}px)` }}
                  >
                    {!this.props.commentIds &&
                      postAssetIdPairs &&
                      this.constructPostIdsArray().map(postId =>
                      (<PostContainer
                        key={`lightBoxPost_${postId}`}
                        postId={postId}
                        isPostHeaderHidden
                        isLightBox
                        lightBoxSelectedId={this.state.assetIdToSet}
                        resizeLightBox={this.state.resize}
                        toggleLightBox={(assetId, postIdToSet) =>
                          this.handleImageClick(assetId, postIdToSet)}
                      />),
                    )}
                    {this.props.commentIds &&
                      postAssetIdPairs &&
                      this.constructPostIdsArray().map(postId =>
                      (<CommentContainer
                        key={`lightBoxPost_${postId}`}
                        commentId={postId}
                        isLightBox
                        lightBoxSelectedId={this.state.assetIdToSet}
                        toggleLightBox={(assetId, postIdToSet) =>
                          this.handleImageClick(assetId, postIdToSet)}
                      />),
                    )}

          }
          <WrappedComponent
            toggleLightBox={(assetId, postIdToSet) => this.handleImageClick(assetId, postIdToSet)}
            {...this.props}
          />

      )
    }
  }

  function makeMapStateToProps() {
    return (state, props) =>
      ({
        innerHeight: selectInnerHeight(state),
        innerWidth: selectInnerWidth(state),
        postAssetIdPairs: selectPostsAssetIds(state, props),
      })
  }

  return connect(makeMapStateToProps)(BaseLightBox)
}

export default LightBoxWrapper
<commit_msg>lightbox - manage placement/transitions with truncated queue<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import Mousetrap from 'mousetrap'
import {
  selectInnerHeight,
  selectInnerWidth,
} from '../selectors/gui'
import {
  selectPostsAssetIds,
} from '../selectors/light_box'
import { scrollToPosition } from '../lib/jello'
import { DismissButtonLGReverse } from '../components/buttons/Buttons'
import PostContainer from './PostContainer'
import CommentContainer from './CommentContainer'
// import { RegionItems } from '../regions/RegionRenderables'
import { css, select, media } from '../styles/jss'
import * as s from '../styles/jso'
import { SHORTCUT_KEYS } from '../constants/application_types'

const baseLightBoxStyle = css(
  s.block,
  s.relative,
  s.bgcF2,
  { margin: '0 auto' },
  select(
    '> .LightBoxMask',
    s.fullscreen,
    s.fullWidth,
    s.fullHeight,
    s.bgcModal,
    s.zModal,
    { transition: `background-color 0.4s ${s.ease}` },
    select(
      '> .LightBox',
      s.fixed,
      s.flood,
      s.fullWidth,
      s.fullHeight,
      s.overflowHidden,
      s.flex,
      s.itemsCenter,
      select(
        '> .LightBoxQueue',
        s.transitionOpacity,
        s.relative,
        {
          width: 'auto',
          whiteSpace: 'nowrap',
          opacity: 1,
        },
      ),
    ),
    select(
      '> .LightBox.loaded',
      select(
        '> .LightBoxQueue.transition',
        s.transitionTransform,
      ),
    ),
    select(
      '> .LightBox.loading',
      select(
        '> .LightBoxQueue',
        { opacity: 0 },
      ),
    ),
  ),
)

const imageRegionStyle = select(
  '> .ImageRegion',
  s.inlineBlock,
  s.relative,
  {
    margin: 0,
    marginLeft: 40,
    marginRight: 40,
    width: 'auto',
  },
  media(
    s.maxBreak4,
    { marginLeft: 30,
      marginRight: 30,
    },
  ),
  media(
    s.maxBreak3,
    { marginLeft: 20,
      marginRight: 20,
    },
  ),
  media(
    s.maxBreak2,
    { marginLeft: 10,
      marginRight: 10,
    },
  ),
  select(
    '> .ImgHolderLightBox',
    s.inline,
  ),
)

const commentsLightBoxStyle = css(
  { ...baseLightBoxStyle },
  select(
    '> .LightBoxMask',
    select(
      '> .LightBox',
      select(
        '> .LightBoxQueue',
        select(
          '> .Comment',
          s.inline,
          { padding: 0 },
          select(
            '> .CommentBody',
            s.inline,
            { padding: 0,
              margin: 0,
              border: 'none',
              width: 'auto',
            },
            select(
              '> div',
              s.inline,
              { ...imageRegionStyle },
            ),
          ),
        ),
      ),
    ),
  ),
)

const postsListLightBoxStyle = css(
  { ...baseLightBoxStyle },
  select(
    '> .LightBoxMask',
    select(
      '> .LightBox',
      select(
        '> .LightBoxQueue',
        select(
          '> .Post',
          s.inline,
          { margin: 0,
            padding: 0,
          },
          select(
            '> .PostBody',
            s.inline,
            { padding: 0,
              margin: 0,
              border: 'none',
              width: 'auto',
            },
            select(
              '> div',
              s.inline,
              { ...imageRegionStyle },
            ),
          ),
        ),
      ),
    ),
  ),
)

// Wraps LightBox controls/state around a component
// This function takes a component
function LightBoxWrapper(WrappedComponent) {
  class BaseLightBox extends Component {
    static propTypes = {
      innerHeight: PropTypes.number,
      innerWidth: PropTypes.number,
      commentIds: PropTypes.object, // for comment stream
      postAssetIdPairs: PropTypes.array, // post/asset id pairs
    }

    static defaultProps = {
      innerHeight: null,
      innerWidth: null,
      commentIds: null,
      postAssetIdPairs: null,
    }

    constructor(props) {
      super(props)
      this.state = {
        open: false,
        loading: true,
        loaded: false,
        direction: null,
        assetIdToSet: null,
        assetIdToSetPrev: null,
        assetIdToSetNext: null,
        postIdToSet: null,
        postIdToSetPrev: null,
        postIdToSetNext: null,
        queuePostIdsArray: null,
        oldestQueuePostId: null,
        newestQueuePostId: null,
        innerWidth: this.props.innerWidth,
        innerHeight: this.props.innerHeight,
        resize: false,
        queueOffsetX: 0,
        showOffsetTransition: false,
      }

      this.handleImageClick = this.handleImageClick.bind(this)
      this.handleViewPortResize = this.handleViewPortResize.bind(this)
      this.close = this.close.bind(this)
    }

    componentDidUpdate(prevProps, prevState) {
      // set keybindings
      if (!prevState.open && this.state.open) {
        this.bindKeys()
      }

      // might need to shift the queue left/right if we've added/removed new posts
      if (this.state.open && (prevState.oldestQueuePostId !== this.state.oldestQueuePostId)) {
        const nextPrev = this.getSetPagination(this.state.assetIdToSet,
          this.state.postIdToSet,
          false)

        // need to reset; new posts may have shifted queue
        if (this.state.direction === 'next') {
          this.slideQueue(nextPrev.assetIdToSetPrev, nextPrev.postIdToSetPrev)
        } else {
          setTimeout(() => {
            this.slideQueue(nextPrev.assetIdToSetNext, nextPrev.postIdToSetNext)
          }, 1) // small timeout allows DOM time to instantiate new post
        }
      }

      const slideDelay = !prevState.open ? 200 : 100
      const transitionDelay = 200

      // update the DOM post Ids array and move the queue to the select item
      if (this.state.open && (prevState.assetIdToSet !== this.state.assetIdToSet)) {
        this.constructPostIdsArray()

        setTimeout(() => {
          this.slideQueue()
        }, slideDelay)
      }

      // remove loading class if lightbox was recently opened
      if (this.state.open && !prevState.open) {
        setTimeout(() => {
          this.removeLoadingClass()
        }, transitionDelay)
      }

      // check for viewport resizes
      if ((this.state.open && !this.state.resize) &&
        ((this.props.innerWidth !== this.state.innerWidth) ||
        (this.props.innerHeight !== this.state.innerHeight))) {
        this.handleViewPortResize(true)
      }

      // reset resize bool
      if (!prevState.resize && this.state.resize) {
        this.handleViewPortResize(false)
      }
    }

    componentWillUnmount() {
      const releaseKeys = true
      this.bindKeys(releaseKeys)
    }

    getSetPagination(assetId, postId, updateState = true) {
      const { postAssetIdPairs } = this.props

      if (postAssetIdPairs) {
        const numberItems = postAssetIdPairs.length
        let existingItemIndex = null

        // match `assetId` and `postId` with `postAssetIdPairs` pair
        postAssetIdPairs.map((postAssetIdPair, index) => {
          if ((postAssetIdPair[1] === assetId) &&
            (postAssetIdPair[0] === postId)) {
            existingItemIndex = index
            return existingItemIndex
          }
          return null
        })

        // if there was a match, set prev/next indices + grab ids
        if (existingItemIndex !== null) {
          let prevIndex = existingItemIndex - 1
          let nextIndex = existingItemIndex + 1

          if (existingItemIndex === 0) {
            prevIndex = 0
          }

          if (existingItemIndex === (numberItems - 1)) {
            nextIndex = existingItemIndex
          }

          const prevItemAssetId = postAssetIdPairs[prevIndex][1]
          const nextItemAssetId = postAssetIdPairs[nextIndex][1]
          const prevItemPostId = postAssetIdPairs[prevIndex][0]
          const nextItemPostId = postAssetIdPairs[nextIndex][0]

          if (updateState) {
            return this.setState({
              assetIdToSetPrev: prevItemAssetId,
              assetIdToSetNext: nextItemAssetId,
              postIdToSetPrev: prevItemPostId,
              postIdToSetNext: nextItemPostId,
            })
          }
          const nextPrevSet = {
            assetIdToSetPrev: prevItemAssetId,
            assetIdToSetNext: nextItemAssetId,
            postIdToSetPrev: prevItemPostId,
            postIdToSetNext: nextItemPostId,
          }
          return nextPrevSet
        }
        return null
      }
      return null
    }

    setLightBoxStyle() {
      const { commentIds } = this.props

      if (commentIds) {
        return commentsLightBoxStyle
      }

      return postsListLightBoxStyle
    }

    advance(direction) {
      let newAssetIdToSet = null
      let newPostIdToSet = null

      switch (direction) {
        case 'prev' :
          newAssetIdToSet = this.state.assetIdToSetPrev
          newPostIdToSet = this.state.postIdToSetPrev
          break
        case 'next' :
          newAssetIdToSet = this.state.assetIdToSetNext
          newPostIdToSet = this.state.postIdToSetNext
          break
        default :
          newAssetIdToSet = this.state.assetIdToSet
          newPostIdToSet = this.state.postIdToSet
      }

      // advance to new image
      this.setState({
        direction,
        assetIdToSet: newAssetIdToSet,
        postIdToSet: newPostIdToSet,
      })

      // scroll the page to image
      this.scrollToSelectedAsset(newAssetIdToSet, newPostIdToSet)

      // update pagination
      return this.getSetPagination(newAssetIdToSet, newPostIdToSet)
    }

    slideQueue(assetIdToReset = null, postIdToReset = null) {
      const reset = (assetIdToReset !== null && postIdToReset !== null)

      // either reset the queue position, or advance to new asset
      const assetId = reset ? assetIdToReset : this.state.assetIdToSet
      const postId = reset ? postIdToReset : this.state.postIdToSet
      const assetDomId = `lightBoxAsset_${assetId}_${postId}`

      // select the DOM elements
      const lightBoxDomQueue = document.getElementsByClassName('LightBoxQueue')[0]
      const assetInDom = document.getElementById(assetDomId)

      // measurements
      const viewportWidth = window.innerWidth
      const lightBoxDimensions = lightBoxDomQueue.getBoundingClientRect()
      const assetDimensions = assetInDom.getBoundingClientRect()

      // positioning calculations
      const desiredGap = ((viewportWidth - (assetDimensions.width)) / 2)
      const imageOffsetToBox = assetDimensions.x - lightBoxDimensions.x
      const newOffset = desiredGap - imageOffsetToBox

      // update the box position
      return this.setState({
        queueOffsetX: newOffset,
        showOffsetTransition: !reset,
      })
    }

    scrollToSelectedAsset(newAssetIdToSet, newPostIdToSet) {
      const commentsStream = this.props.commentIds
      const assetDomId = `asset_${newAssetIdToSet}_${newPostIdToSet}`

      // grab elements from the dom
      const postList = document.getElementsByClassName('PostList')
      const postSideBar = document.getElementsByClassName('PostSideBar')
      const assetInDom = document.getElementById(assetDomId)

      // determine scroll offset of asset in dom
      let assetInDomTopOffset = null
      if (postSideBar.length) { // post detail view (scrolling inner-div needs different treatement)
        if (commentsStream) {
          assetInDomTopOffset = assetInDom.getBoundingClientRect().top + postSideBar[0].scrollTop
        } else {
          assetInDomTopOffset = assetInDom.getBoundingClientRect().top + postList[0].scrollTop
        }
      } else {
        assetInDomTopOffset = assetInDom.getBoundingClientRect().top + window.scrollY
      }

      // adjust scroll offset for window height / nav bar
      const windowHeight = window.innerHeight
      const offsetPadding = (windowHeight / 10)
      const scrollToOffset = (assetInDomTopOffset - offsetPadding)

      // scroll to new position
      if (postList.length && postSideBar.length) { // post detail view
        let scrollElement = postList[0]
        if (commentsStream) {
          scrollElement = postSideBar[0]
        }
        return scrollToPosition(0, scrollToOffset, { el: scrollElement })
      }
      return scrollToPosition(0, scrollToOffset) // stream container view
    }

    close() {
      const releaseKeys = true
      this.bindKeys(releaseKeys)

      return this.setState({
        open: false,
        loading: true,
        loaded: false,
        assetIdToSet: null,
        queueOffsetX: 0,
      })
    }

    handleMaskClick(e) {
      if (e.target.nodeName !== 'IMG' &&
        e.target.nodeName !== 'VIDEO' &&
        e.target.nodeName !== 'BUTTON') {
        return this.close()
      }
      return null
    }

    handleImageClick(assetId, postId) {
      const {
        open,
        assetIdToSet,
        assetIdToSetPrev,
        postIdToSet,
        postIdToSetPrev,
      } = this.state

      if (open && (assetId === assetIdToSet) && (postId === postIdToSet)) {
        return this.close()
      }

      // determine direction
      let direction = 'next'
      if (open && (assetId === assetIdToSetPrev) && (postId === postIdToSetPrev)) {
        direction = 'prev'
      }

      // advance to new image
      this.setState({
        open: true,
        direction,
        assetIdToSet: assetId,
        postIdToSet: postId,
      })

      // scroll the page to image
      this.scrollToSelectedAsset(assetId, postId)

      // update pagination
      return this.getSetPagination(assetId, postId)
    }

    handleViewPortResize(isResize) {
      // resize on
      if (isResize) {
        return this.setState({
          innerWidth,
          innerHeight,
          resize: true,
        })
      }

      // resize off
      setTimeout(() => {
        this.slideQueue(this.state.assetIdToSet, this.state.postIdToSet)
      }, 250)

      return this.setState({
        resize: false,
      })
    }

    removeLoadingClass() {
      const transitionDelay = 200

      this.setState({
        loading: false,
      })

      return setTimeout(() => {
        this.setState({
          loaded: true,
        })
      }, transitionDelay)
    }

    bindKeys(unbind) {
      Mousetrap.unbind(SHORTCUT_KEYS.ESC)
      Mousetrap.unbind(SHORTCUT_KEYS.PREV)
      Mousetrap.unbind(SHORTCUT_KEYS.NEXT)

      if (!unbind) {
        Mousetrap.bind(SHORTCUT_KEYS.ESC, () => { this.close() })
        Mousetrap.bind(SHORTCUT_KEYS.PREV, () => { this.advance('prev') })
        Mousetrap.bind(SHORTCUT_KEYS.NEXT, () => { this.advance('next') })
      }
    }

    constructPostIdsArray() {
      const { postAssetIdPairs } = this.props
      const { assetIdToSet, postIdToSet } = this.state
      const allPostIds = []

      // set the offset indices
      const assetsOffset = 6
      const indexOfSelected = postAssetIdPairs.findIndex(
        postAssetIdPair =>
        (postAssetIdPair[0] === postIdToSet && postAssetIdPair[1] === assetIdToSet))
      const indexLower = indexOfSelected > (assetsOffset - 1) ? (indexOfSelected - assetsOffset) : 0
      const indexHigher = indexOfSelected + assetsOffset

      // truncate the postAssetIdPairs array
      const truncatedPostAssetIdPairs = postAssetIdPairs.slice(indexLower, indexHigher)
      truncatedPostAssetIdPairs.map(postAssedIdPair => allPostIds.push(postAssedIdPair[0]))

      // grab the unique postIds from the pairs array
      const postIds = Array.from(new Set(allPostIds))

      this.setState({
        queuePostIdsArray: postIds,
        oldestQueuePostId: postIds[0],
        newestQueuePostId: postIds.slice(-1)[0],
      })

      return postIds
    }

    render() {
      const { postAssetIdPairs } = this.props

      return (

          {this.state.open &&

 this.handleMaskClick(e)}>
                <DismissButtonLGReverse
                  onClick={this.close}
                />
                <div className={`LightBox ${this.state.loading ? 'loading' : ''}${this.state.loaded ? 'loaded' : ''}`}>
                  <div
                    className={`LightBoxQueue${this.state.showOffsetTransition ? ' transition' : ''}`}
                    style={{ transform: `translateX(${this.state.queueOffsetX}px)` }}
                  >
                    {!this.props.commentIds &&
                      postAssetIdPairs &&
                      this.state.queuePostIdsArray.map(postId =>
                      (<PostContainer
                        key={`lightBoxPost_${postId}`}
                        postId={postId}
                        isPostHeaderHidden
                        isLightBox
                        lightBoxSelectedId={this.state.assetIdToSet}
                        resizeLightBox={this.state.resize}
                        toggleLightBox={(assetId, postIdToSet) =>
                          this.handleImageClick(assetId, postIdToSet)}
                      />),
                    )}
                    {this.props.commentIds &&
                      postAssetIdPairs &&
                      this.state.queuePostIdsArray.map(postId =>
                      (<CommentContainer
                        key={`lightBoxPost_${postId}`}
                        commentId={postId}
                        isLightBox
                        lightBoxSelectedId={this.state.assetIdToSet}
                        toggleLightBox={(assetId, postIdToSet) =>
                          this.handleImageClick(assetId, postIdToSet)}
                      />),
                    )}

          }
          <WrappedComponent
            toggleLightBox={(assetId, postIdToSet) => this.handleImageClick(assetId, postIdToSet)}
            {...this.props}
          />

      )
    }
  }

  function makeMapStateToProps() {
    return (state, props) =>
      ({
        innerHeight: selectInnerHeight(state),
        innerWidth: selectInnerWidth(state),
        postAssetIdPairs: selectPostsAssetIds(state, props),
      })
  }

  return connect(makeMapStateToProps)(BaseLightBox)
}

export default LightBoxWrapper
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { connect } from 'react-redux'
import { arrayOf, func } from 'prop-types'
import { personType, roleType, programmeType, availableRoleType } from '../../util/types'

import RoleRequests from './components/RoleRequests'
import PersonSelector from './components/PersonSelector'
import PersonRoleChoose from './components/PersonRoleChoose'
import AddPerson from './components/AddPerson'
import UnitRoleList from '../UnitRoleList'

import { getAvailableRoles, saveRole, deleteRole, getRoleRequestsAction, grantRoleAction } from '../Role/services/roleActions'
import { invitePerson, addPersonAction } from './services/personActions'

import { makePersonRoles } from '../../selectors/personRoles'

export class PersonRoleManagePage extends Component {
    constructor(props) {
        super(props)
        this.props.getAvailableRoles()
        this.state = {
            person: undefined,
            roles: undefined
        }
    }

    componentDidMount() {
        this.props.getRoleRequests()
    }

    componentWillReceiveProps(newProps) {
        const { person } = this.state

        if (person) {
            const roles = newProps.roles.filter(role => role.personId === person.personId)
                .map(role =>
                    Object.assign(
                        role,
                        { programme: newProps.programmes.find(field => field.programmeId === role.programmeId).name }
                    )
                )
            this.setState({ roles })
        }
    }

    checkUserRights = () => {
        const { user } = this.props
        if (user.roles.find(role => role.role === 'admin')) {
            return this.props.programmes
        }
        const managerRoles = user.roles.filter(role => role.role === 'manager')
        const programmes = managerRoles.map(role => ({ programmeId: role.programmeId, name: role.programme }))
        return programmes
    }

    selectPerson = (persons) => {
        const person = persons.find(item => !this.state.person || item.personId !== this.state.person.personId)
        const roles = person ?
            this.props.roles.filter(role => role.personId === person.personId)
                .map(role =>
                    Object.assign(
                        role,
                        { programme: this.props.programmes.find(field => field.programmeId === role.programmeId).name }
                    )
                )
            : undefined
        this.setState({ person, roles })
    };

    handleAddRole = (role) => {
        if (this.state.person.personId && role.roleId && role.programmeId) {
            this.props.saveRole(Object.assign(role, { personId: this.state.person.personId }))
        }
    };

    handleRemoveRole = (role) => {
        this.props.deleteRole(role)
    };

    handleSendInvite = (data) => {
        this.props.invitePerson(data)
    };

    handleGrantRole = (e, data) => {
        this.props.grantRole(data.data)
    }

    renderManagement = () => {
        if (this.state.person) {
            return (
                <PersonRoleChoose
                    person={this.state.person}
                    roles={this.state.roles}
                    programmes={this.props.programmes}
                    availableRoles={this.props.availableRoles}
                    addRole={this.handleAddRole}
                    removeRole={this.handleRemoveRole}
                />
            )
        }
        return undefined
    }

    render() {
        if (this.props.user.roles) {
            const programmes = this.checkUserRights()
            const selected = this.state.person ? [this.state.person] : []
            return (

                        On this page you can invite new users
                        by choosing the correct unit, role and inputting email address.
                        Grappa will then send an email to that address
                        with a link that will make them the role of your choosing.

                        In addition, you can choose a person using the selector.
                        When a person is chosen you can edit their roles.

                    <RoleRequests roleRequests={this.props.roleRequests.filter(request => programmes.find(programme => programme.programmeId === request.programmeId))} handleGrantRole={this.handleGrantRole} />

Add a person to Grappa (NOTE: person without @helsinki email cannot sign in)

                    {this.props.programmes.length > 0 && this.props.availableRoles ?
                        <AddPerson programmes={programmes} roles={this.props.availableRoles.map(role => role.name)} addNewPerson={this.handleSendInvite} /> :

loading
}

Select a person to manage their roles

                    <PersonSelector
                        persons={this.props.persons}
                        selected={selected}
                        changeList={this.selectPerson}
                    />

                    {this.renderManagement()}

                    <UnitRoleList />

            )
        }
        return (
Coming right back
)
    }
}

const mapDispatchToProps = dispatch => ({
    getAvailableRoles() {
        dispatch(getAvailableRoles())
    },
    saveRole(role) {
        dispatch(saveRole(role))
    },
    deleteRole(role) {
        dispatch(deleteRole(role))
    },
    invitePerson(invite) {
        dispatch(invitePerson(invite))
    },
    getRoleRequests: () => (
        dispatch(getRoleRequestsAction())
    ),
    grantRole: data => (
        dispatch(grantRoleAction(data))
    )
})

const personRoles = makePersonRoles()

const mapStateToProps = state => ({
    programmes: state.programmes,
    persons: state.persons,
    roles: personRoles(state),
    availableRoles: state.availableRoles,
    roleRequests: state.roleRequests,
    user: state.user
})

PersonRoleManagePage.propTypes = {
    programmes: arrayOf(programmeType).isRequired,
    persons: arrayOf(personType).isRequired,
    roles: arrayOf(roleType).isRequired,
    availableRoles: arrayOf(availableRoleType).isRequired,
    getAvailableRoles: func.isRequired,
    saveRole: func.isRequired,
    deleteRole: func.isRequired,
    invitePerson: func.isRequired,
    getRoleRequests: func.isRequired,
    grantRole: func.isRequired
}

export default connect(mapStateToProps, mapDispatchToProps)(PersonRoleManagePage)
<commit_msg>remove unused import<commit_after>import React, { Component } from 'react'
import { connect } from 'react-redux'
import { arrayOf, func } from 'prop-types'
import { personType, roleType, programmeType, availableRoleType } from '../../util/types'

import RoleRequests from './components/RoleRequests'
import PersonSelector from './components/PersonSelector'
import PersonRoleChoose from './components/PersonRoleChoose'
import AddPerson from './components/AddPerson'
import UnitRoleList from '../UnitRoleList'

import { getAvailableRoles, saveRole, deleteRole, getRoleRequestsAction, grantRoleAction } from '../Role/services/roleActions'
import { invitePerson } from './services/personActions'

import { makePersonRoles } from '../../selectors/personRoles'

export class PersonRoleManagePage extends Component {
    constructor(props) {
        super(props)
        this.props.getAvailableRoles()
        this.state = {
            person: undefined,
            roles: undefined
        }
    }

    componentDidMount() {
        this.props.getRoleRequests()
    }

    componentWillReceiveProps(newProps) {
        const { person } = this.state

        if (person) {
            const roles = newProps.roles.filter(role => role.personId === person.personId)
                .map(role =>
                    Object.assign(
                        role,
                        { programme: newProps.programmes.find(field => field.programmeId === role.programmeId).name }
                    )
                )
            this.setState({ roles })
        }
    }

    checkUserRights = () => {
        const { user } = this.props
        if (user.roles.find(role => role.role === 'admin')) {
            return this.props.programmes
        }
        const managerRoles = user.roles.filter(role => role.role === 'manager')
        const programmes = managerRoles.map(role => ({ programmeId: role.programmeId, name: role.programme }))
        return programmes
    }

    selectPerson = (persons) => {
        const person = persons.find(item => !this.state.person || item.personId !== this.state.person.personId)
        const roles = person ?
            this.props.roles.filter(role => role.personId === person.personId)
                .map(role =>
                    Object.assign(
                        role,
                        { programme: this.props.programmes.find(field => field.programmeId === role.programmeId).name }
                    )
                )
            : undefined
        this.setState({ person, roles })
    };

    handleAddRole = (role) => {
        if (this.state.person.personId && role.roleId && role.programmeId) {
            this.props.saveRole(Object.assign(role, { personId: this.state.person.personId }))
        }
    };

    handleRemoveRole = (role) => {
        this.props.deleteRole(role)
    };

    handleSendInvite = (data) => {
        this.props.invitePerson(data)
    };

    handleGrantRole = (e, data) => {
        this.props.grantRole(data.data)
    }

    renderManagement = () => {
        if (this.state.person) {
            return (
                <PersonRoleChoose
                    person={this.state.person}
                    roles={this.state.roles}
                    programmes={this.props.programmes}
                    availableRoles={this.props.availableRoles}
                    addRole={this.handleAddRole}
                    removeRole={this.handleRemoveRole}
                />
            )
        }
        return undefined
    }

    render() {
        if (this.props.user.roles) {
            const programmes = this.checkUserRights()
            const selected = this.state.person ? [this.state.person] : []
            return (

                        On this page you can invite new users
                        by choosing the correct unit, role and inputting email address.
                        Grappa will then send an email to that address
                        with a link that will make them the role of your choosing.

                        In addition, you can choose a person using the selector.
                        When a person is chosen you can edit their roles.

                    <RoleRequests roleRequests={this.props.roleRequests.filter(request => programmes.find(programme => programme.programmeId === request.programmeId))} handleGrantRole={this.handleGrantRole} />

Add a person to Grappa (NOTE: person without @helsinki email cannot sign in)

                    {this.props.programmes.length > 0 && this.props.availableRoles ?
                        <AddPerson programmes={programmes} roles={this.props.availableRoles.map(role => role.name)} addNewPerson={this.handleSendInvite} /> :

loading
}

Select a person to manage their roles

                    <PersonSelector
                        persons={this.props.persons}
                        selected={selected}
                        changeList={this.selectPerson}
                    />

                    {this.renderManagement()}

                    <UnitRoleList />

            )
        }
        return (
Coming right back
)
    }
}

const mapDispatchToProps = dispatch => ({
    getAvailableRoles() {
        dispatch(getAvailableRoles())
    },
    saveRole(role) {
        dispatch(saveRole(role))
    },
    deleteRole(role) {
        dispatch(deleteRole(role))
    },
    invitePerson(invite) {
        dispatch(invitePerson(invite))
    },
    getRoleRequests: () => (
        dispatch(getRoleRequestsAction())
    ),
    grantRole: data => (
        dispatch(grantRoleAction(data))
    )
})

const personRoles = makePersonRoles()

const mapStateToProps = state => ({
    programmes: state.programmes,
    persons: state.persons,
    roles: personRoles(state),
    availableRoles: state.availableRoles,
    roleRequests: state.roleRequests,
    user: state.user
})

PersonRoleManagePage.propTypes = {
    programmes: arrayOf(programmeType).isRequired,
    persons: arrayOf(personType).isRequired,
    roles: arrayOf(roleType).isRequired,
    availableRoles: arrayOf(availableRoleType).isRequired,
    getAvailableRoles: func.isRequired,
    saveRole: func.isRequired,
    deleteRole: func.isRequired,
    invitePerson: func.isRequired,
    getRoleRequests: func.isRequired,
    grantRole: func.isRequired
}

export default connect(mapStateToProps, mapDispatchToProps)(PersonRoleManagePage)
<|endoftext|>