<commit_before>import './3d-force-graph.css';

import './threeGlobal';
import 'three/examples/js/controls/TrackBallControls';

import * as d3 from 'd3-force-3d';
import graph from 'ngraph.graph';
import forcelayout from 'ngraph.forcelayout';
import forcelayout3d from 'ngraph.forcelayout3d';
const ngraph = { graph, forcelayout, forcelayout3d };

import * as SWC from 'swc';

//

const CAMERA_DISTANCE2NODES_FACTOR = 150;

export default SWC.createComponent({

	props: [
		new SWC.Prop('width', window.innerWidth),
		new SWC.Prop('height', window.innerHeight),
		new SWC.Prop('jsonUrl'),
		new SWC.Prop('graphData', {
			nodes: [],
			links: []
		}),
		new SWC.Prop('numDimensions', 3),
		new SWC.Prop('nodeRelSize', 4), // volume per val unit
		new SWC.Prop('lineOpacity', 0.2),
		new SWC.Prop('autoColorBy'),
		new SWC.Prop('idField', 'id'),
		new SWC.Prop('valField', 'val'),
		new SWC.Prop('nameField', 'name'),
		new SWC.Prop('colorField', 'color'),
		new SWC.Prop('linkSourceField', 'source'),
		new SWC.Prop('linkTargetField', 'target'),
		new SWC.Prop('forceEngine', 'd3'), // d3 or ngraph
		new SWC.Prop('warmupTicks', 0), // how many times to tick the force engine at init before starting to render
		new SWC.Prop('cooldownTicks', Infinity),
		new SWC.Prop('cooldownTime', 15000) // ms
	],

	init: (domNode, state) => {
		// Wipe DOM
		domNode.innerHTML = '';

		// Add nav info section
		let navInfo;
		domNode.appendChild(navInfo = document.createElement('div'));
		navInfo.className = 'graph-nav-info';
		navInfo.textContent = "MOVE mouse & press LEFT/A: rotate, MIDDLE/S: zoom, RIGHT/D: pan";

		// Add info space
		domNode.appendChild(state.infoElem = document.createElement('div'));
		state.infoElem.className = 'graph-info-msg';
		state.infoElem.textContent = '';

		// Setup tooltip
		const toolTipElem = document.createElement('div');
		toolTipElem.classList.add('graph-tooltip');
		domNode.appendChild(toolTipElem);

		// Capture mouse coords on move
		const raycaster = new THREE.Raycaster();
		const mousePos = new THREE.Vector2();
		mousePos.x = -2; // Initialize off canvas
		mousePos.y = -2;
		domNode.addEventListener("mousemove", ev => {
			// update the mouse pos
			const offset = getOffset(domNode),
				relPos = {
					x: ev.pageX - offset.left,
					y: ev.pageY - offset.top
				};
			mousePos.x = (relPos.x / state.width) * 2 - 1;
			mousePos.y = -(relPos.y / state.height) * 2 + 1;

			// Move tooltip
			toolTipElem.style.top = (relPos.y - 40) + 'px';
			toolTipElem.style.left = (relPos.x - 20) + 'px';

			function getOffset(el) {
				const rect = el.getBoundingClientRect(),
					scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
					scrollTop = window.pageYOffset || document.documentElement.scrollTop;
				return { top: rect.top + scrollTop, left: rect.left + scrollLeft };
			}
		}, false);

		// Setup renderer
		state.renderer = new THREE.WebGLRenderer();
		domNode.appendChild(state.renderer.domElement);

		// Setup scene
		const scene = new THREE.Scene();
		scene.background = new THREE.Color(0x0000A);
		scene.add(state.graphScene = new THREE.Group());

		// Add lights
		scene.add(new THREE.AmbientLight(0xbbbbbb));
		scene.add(new THREE.DirectionalLight(0xffffff, 0.6));

		// Setup camera
		state.camera = new THREE.PerspectiveCamera();
		state.camera.far = 20000;

		// Add camera interaction
		const tbControls = new THREE.TrackballControls(state.camera, state.renderer.domElement);

		// Add D3 force-directed layout
		state.d3ForceLayout = d3.forceSimulation()
			.force('link', d3.forceLink())
			.force('charge', d3.forceManyBody())
			.force('center', d3.forceCenter())
			.stop();

		//

		// Kick-off renderer
		(function animate() { // IIFE
			if(state.onFrame) state.onFrame();

			// Update tooltip
			raycaster.setFromCamera(mousePos, state.camera);
			const intersects = raycaster.intersectObjects(state.graphScene.children)
				.filter(o => o.object.name); // Check only objects with labels
			toolTipElem.textContent = intersects.length ? intersects[0].object.name : '';

			// Frame cycle
			tbControls.update();
			state.renderer.render(scene, state.camera);
			requestAnimationFrame(animate);
		})();
	},

	update: function updateFn(state) {
		resizeCanvas();

		state.onFrame = null; // Pause simulation
		state.infoElem.textContent = 'Loading...';

		if (state.graphData.nodes.length || state.graphData.links.length) {
			console.log('3d-force-graph loading', state.graphData.nodes.length + ' nodes', state.graphData.links.length + ' links');
		}

		if (!state.fetchingJson && state.jsonUrl && !state.graphData.nodes.length && !state.graphData.links.length) {
			// (Re-)load data
			state.fetchingJson = true;
			qwest.get(state.jsonUrl).then((_, json) => {
				state.fetchingJson = false;
				state.graphData = json;
				updateFn(state);  // Force re-update
			});
		}

		// Auto add color to uncolored nodes
		autoColorNodes(state.graphData.nodes, state.autoColorBy, state.colorField);

		// parse links
		state.graphData.links.forEach(link => {
			link.source = link[state.linkSourceField];
			link.target = link[state.linkTargetField];
		});

		// Add WebGL objects
		while (state.graphScene.children.length) { state.graphScene.remove(state.graphScene.children[0]) } // Clear the place

		state.graphData.nodes.forEach(node => {
			const nodeMaterial = new THREE.MeshLambertMaterial({ color: node[state.colorField] || 0xffffaa, transparent: true });
			nodeMaterial.opacity = 0.75;

			const sphere = new THREE.Mesh(
				new THREE.SphereGeometry(Math.cbrt(node[state.valField] || 1) * state.nodeRelSize, 8, 8),
				nodeMaterial
			);

			sphere.name = node[state.nameField]; // Add label

			state.graphScene.add(node.__sphere = sphere);
		});

		const lineMaterial = new THREE.LineBasicMaterial({ color: 0xf0f0f0, transparent: true });
		lineMaterial.opacity = state.lineOpacity;
		state.graphData.links.forEach(link => {
			const line = new THREE.Line(new THREE.Geometry(), lineMaterial);
			line.geometry.vertices=[new THREE.Vector3(0,0,0), new THREE.Vector3(0,0,0)];

			state.graphScene.add(link.__line = line);
		});

		state.camera.lookAt(state.graphScene.position);
		state.camera.position.z = Math.cbrt(state.graphData.nodes.length) * CAMERA_DISTANCE2NODES_FACTOR;

		// Feed data to force-directed layout
		const isD3Sim = state.forceEngine !== 'ngraph';
		let layout;
		if (isD3Sim) {
			// D3-force
			(layout = state.d3ForceLayout)
				.stop()
				.alpha(1)// re-heat the simulation
				.numDimensions(state.numDimensions)
				.nodes(state.graphData.nodes)
				.force('link')
					.id(d => d[state.idField])
					.links(state.graphData.links);
		} else {
			// ngraph
			const graph = ngraph.graph();
			state.graphData.nodes.forEach(node => { graph.addNode(node[state.idField]); });
			state.graphData.links.forEach(link => { graph.addLink(link.source, link.target); });
			layout = ngraph['forcelayout' + (state.numDimensions === 2 ? '' : '3d')](graph);
			layout.graph = graph; // Attach graph reference to layout
		}

		for (let i=0; i<state.warmupTicks; i++) { layout[isD3Sim?'tick':'step'](); } // Initial ticks before starting to render

		let cntTicks = 0;
		const startTickTime = new Date();
		state.onFrame = layoutTick;
		state.infoElem.textContent = '';

		//

		function resizeCanvas() {
			if (state.width && state.height) {
				state.renderer.setSize(state.width, state.height);
				state.camera.aspect = state.width/state.height;
				state.camera.updateProjectionMatrix();
			}
		}

		function layoutTick() {
			if (cntTicks++ > state.cooldownTicks || (new Date()) - startTickTime > state.cooldownTime) {
				state.onFrame = null; // Stop ticking graph
			}

			layout[isD3Sim?'tick':'step'](); // Tick it

			// Update nodes position
			state.graphData.nodes.forEach(node => {
				const sphere = node.__sphere,
					pos = isD3Sim ? node : layout.getNodePosition(node[state.idField]);

				sphere.position.x = pos.x;
				sphere.position.y = pos.y || 0;
				sphere.position.z = pos.z || 0;
			});

			// Update links position
			state.graphData.links.forEach(link => {
				const line = link.__line;

				if (isD3Sim) {
					line.geometry.vertices = [
						new THREE.Vector3(link.source.x, link.source.y || 0, link.source.z || 0),
						new THREE.Vector3(link.target.x, link.target.y || 0, link.target.z || 0)
					];
				} else { // ngraph
					var pos = layout.getLinkPosition(layout.graph.getLink(link.source, link.target).id);

					line.geometry.vertices = [
						new THREE.Vector3(pos.from.x, pos.from.y || 0, pos.from.z || 0),
						new THREE.Vector3(pos.to.x, pos.to.y || 0, pos.to.z || 0)
					];
				}

				line.geometry.verticesNeedUpdate = true;
				line.geometry.computeBoundingSphere();
			});
		}

		function autoColorNodes(nodes, colorBy, colorField) {
			if (!colorBy) return;

			// Color brewer paired set
			const colors = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f','#ff7f00','#cab2d6','#6a3d9a','#ffff99','#b15928'];

			const uncoloredNodes = nodes.filter(node => !node[colorField]),
				nodeGroups = {};

			uncoloredNodes.forEach(node => { nodeGroups[node[colorBy]] = null });
			Object.keys(nodeGroups).forEach((group, idx) => { nodeGroups[group] = idx });

			uncoloredNodes.forEach(node => {
				node[colorField] = parseInt(colors[nodeGroups[node[colorBy]] % colors.length].slice(1), 16);
			});
		}
	}
});

<commit_msg>Refactor Three obj gen<commit_after>import './3d-force-graph.css';

import './threeGlobal';
import 'three/examples/js/controls/TrackBallControls';

import * as d3 from 'd3-force-3d';
import graph from 'ngraph.graph';
import forcelayout from 'ngraph.forcelayout';
import forcelayout3d from 'ngraph.forcelayout3d';
const ngraph = { graph, forcelayout, forcelayout3d };

import * as SWC from 'swc';

//

const CAMERA_DISTANCE2NODES_FACTOR = 150;

export default SWC.createComponent({

	props: [
		new SWC.Prop('width', window.innerWidth),
		new SWC.Prop('height', window.innerHeight),
		new SWC.Prop('jsonUrl'),
		new SWC.Prop('graphData', {
			nodes: [],
			links: []
		}),
		new SWC.Prop('numDimensions', 3),
		new SWC.Prop('nodeRelSize', 4), // volume per val unit
		new SWC.Prop('lineOpacity', 0.2),
		new SWC.Prop('autoColorBy'),
		new SWC.Prop('idField', 'id'),
		new SWC.Prop('valField', 'val'),
		new SWC.Prop('nameField', 'name'),
		new SWC.Prop('colorField', 'color'),
		new SWC.Prop('linkSourceField', 'source'),
		new SWC.Prop('linkTargetField', 'target'),
		new SWC.Prop('forceEngine', 'd3'), // d3 or ngraph
		new SWC.Prop('warmupTicks', 0), // how many times to tick the force engine at init before starting to render
		new SWC.Prop('cooldownTicks', Infinity),
		new SWC.Prop('cooldownTime', 15000) // ms
	],

	init: (domNode, state) => {
		// Wipe DOM
		domNode.innerHTML = '';

		// Add nav info section
		let navInfo;
		domNode.appendChild(navInfo = document.createElement('div'));
		navInfo.className = 'graph-nav-info';
		navInfo.textContent = "MOVE mouse & press LEFT/A: rotate, MIDDLE/S: zoom, RIGHT/D: pan";

		// Add info space
		domNode.appendChild(state.infoElem = document.createElement('div'));
		state.infoElem.className = 'graph-info-msg';
		state.infoElem.textContent = '';

		// Setup tooltip
		const toolTipElem = document.createElement('div');
		toolTipElem.classList.add('graph-tooltip');
		domNode.appendChild(toolTipElem);

		// Capture mouse coords on move
		const raycaster = new THREE.Raycaster();
		const mousePos = new THREE.Vector2();
		mousePos.x = -2; // Initialize off canvas
		mousePos.y = -2;
		domNode.addEventListener("mousemove", ev => {
			// update the mouse pos
			const offset = getOffset(domNode),
				relPos = {
					x: ev.pageX - offset.left,
					y: ev.pageY - offset.top
				};
			mousePos.x = (relPos.x / state.width) * 2 - 1;
			mousePos.y = -(relPos.y / state.height) * 2 + 1;

			// Move tooltip
			toolTipElem.style.top = (relPos.y - 40) + 'px';
			toolTipElem.style.left = (relPos.x - 20) + 'px';

			function getOffset(el) {
				const rect = el.getBoundingClientRect(),
					scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
					scrollTop = window.pageYOffset || document.documentElement.scrollTop;
				return { top: rect.top + scrollTop, left: rect.left + scrollLeft };
			}
		}, false);

		// Setup renderer
		state.renderer = new THREE.WebGLRenderer();
		domNode.appendChild(state.renderer.domElement);

		// Setup scene
		const scene = new THREE.Scene();
		scene.background = new THREE.Color(0x0000A);
		scene.add(state.graphScene = new THREE.Group());

		// Add lights
		scene.add(new THREE.AmbientLight(0xbbbbbb));
		scene.add(new THREE.DirectionalLight(0xffffff, 0.6));

		// Setup camera
		state.camera = new THREE.PerspectiveCamera();
		state.camera.far = 20000;

		// Add camera interaction
		const tbControls = new THREE.TrackballControls(state.camera, state.renderer.domElement);

		// Add D3 force-directed layout
		state.d3ForceLayout = d3.forceSimulation()
			.force('link', d3.forceLink())
			.force('charge', d3.forceManyBody())
			.force('center', d3.forceCenter())
			.stop();

		//

		// Kick-off renderer
		(function animate() { // IIFE
			if(state.onFrame) state.onFrame();

			// Update tooltip
			raycaster.setFromCamera(mousePos, state.camera);
			const intersects = raycaster.intersectObjects(state.graphScene.children)
				.filter(o => o.object.name); // Check only objects with labels
			toolTipElem.textContent = intersects.length ? intersects[0].object.name : '';

			// Frame cycle
			tbControls.update();
			state.renderer.render(scene, state.camera);
			requestAnimationFrame(animate);
		})();
	},

	update: function updateFn(state) {
		resizeCanvas();

		state.onFrame = null; // Pause simulation
		state.infoElem.textContent = 'Loading...';

		if (state.graphData.nodes.length || state.graphData.links.length) {
			console.log('3d-force-graph loading', state.graphData.nodes.length + ' nodes', state.graphData.links.length + ' links');
		}

		if (!state.fetchingJson && state.jsonUrl && !state.graphData.nodes.length && !state.graphData.links.length) {
			// (Re-)load data
			state.fetchingJson = true;
			qwest.get(state.jsonUrl).then((_, json) => {
				state.fetchingJson = false;
				state.graphData = json;
				updateFn(state);  // Force re-update
			});
		}

		// Auto add color to uncolored nodes
		autoColorNodes(state.graphData.nodes, state.autoColorBy, state.colorField);

		// parse links
		state.graphData.links.forEach(link => {
			link.source = link[state.linkSourceField];
			link.target = link[state.linkTargetField];
		});

		// Add WebGL objects
		while (state.graphScene.children.length) { state.graphScene.remove(state.graphScene.children[0]) } // Clear the place

		state.graphData.nodes.forEach(node => {
			const sphere = new THREE.Mesh(
				new THREE.SphereGeometry(Math.cbrt(node[state.valField] || 1) * state.nodeRelSize, 8, 8),
				new THREE.MeshLambertMaterial({ color: node[state.colorField] || 0xffffaa, transparent: true, opacity: 0.75 })
			);

			sphere.name = node[state.nameField]; // Add label

			state.graphScene.add(node.__sphere = sphere);
		});

		const lineMaterial = new THREE.LineBasicMaterial({ color: 0xf0f0f0, transparent: true });
		lineMaterial.opacity = state.lineOpacity;
		state.graphData.links.forEach(link => {
			const line = new THREE.Line(new THREE.Geometry(), lineMaterial);

			state.graphScene.add(link.__line = line);
		});

		state.camera.lookAt(state.graphScene.position);
		state.camera.position.z = Math.cbrt(state.graphData.nodes.length) * CAMERA_DISTANCE2NODES_FACTOR;

		// Feed data to force-directed layout
		const isD3Sim = state.forceEngine !== 'ngraph';
		let layout;
		if (isD3Sim) {
			// D3-force
			(layout = state.d3ForceLayout)
				.stop()
				.alpha(1)// re-heat the simulation
				.numDimensions(state.numDimensions)
				.nodes(state.graphData.nodes)
				.force('link')
					.id(d => d[state.idField])
					.links(state.graphData.links);
		} else {
			// ngraph
			const graph = ngraph.graph();
			state.graphData.nodes.forEach(node => { graph.addNode(node[state.idField]); });
			state.graphData.links.forEach(link => { graph.addLink(link.source, link.target); });
			layout = ngraph['forcelayout' + (state.numDimensions === 2 ? '' : '3d')](graph);
			layout.graph = graph; // Attach graph reference to layout
		}

		for (let i=0; i<state.warmupTicks; i++) { layout[isD3Sim?'tick':'step'](); } // Initial ticks before starting to render

		let cntTicks = 0;
		const startTickTime = new Date();
		state.onFrame = layoutTick;
		state.infoElem.textContent = '';

		//

		function resizeCanvas() {
			if (state.width && state.height) {
				state.renderer.setSize(state.width, state.height);
				state.camera.aspect = state.width/state.height;
				state.camera.updateProjectionMatrix();
			}
		}

		function layoutTick() {
			if (cntTicks++ > state.cooldownTicks || (new Date()) - startTickTime > state.cooldownTime) {
				state.onFrame = null; // Stop ticking graph
			}

			layout[isD3Sim?'tick':'step'](); // Tick it

			// Update nodes position
			state.graphData.nodes.forEach(node => {
				const sphere = node.__sphere,
					pos = isD3Sim ? node : layout.getNodePosition(node[state.idField]);

				sphere.position.x = pos.x;
				sphere.position.y = pos.y || 0;
				sphere.position.z = pos.z || 0;
			});

			// Update links position
			state.graphData.links.forEach(link => {
				const line = link.__line;

				if (isD3Sim) {
					line.geometry.vertices = [
						new THREE.Vector3(link.source.x, link.source.y || 0, link.source.z || 0),
						new THREE.Vector3(link.target.x, link.target.y || 0, link.target.z || 0)
					];
				} else { // ngraph
					var pos = layout.getLinkPosition(layout.graph.getLink(link.source, link.target).id);

					line.geometry.vertices = [
						new THREE.Vector3(pos.from.x, pos.from.y || 0, pos.from.z || 0),
						new THREE.Vector3(pos.to.x, pos.to.y || 0, pos.to.z || 0)
					];
				}

				line.geometry.verticesNeedUpdate = true;
				line.geometry.computeBoundingSphere();
			});
		}

		function autoColorNodes(nodes, colorBy, colorField) {
			if (!colorBy) return;

			// Color brewer paired set
			const colors = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f','#ff7f00','#cab2d6','#6a3d9a','#ffff99','#b15928'];

			const uncoloredNodes = nodes.filter(node => !node[colorField]),
				nodeGroups = {};

			uncoloredNodes.forEach(node => { nodeGroups[node[colorBy]] = null });
			Object.keys(nodeGroups).forEach((group, idx) => { nodeGroups[group] = idx });

			uncoloredNodes.forEach(node => {
				node[colorField] = parseInt(colors[nodeGroups[node[colorBy]] % colors.length].slice(1), 16);
			});
		}
	}
});

<|endoftext|>


<commit_before>/*
*UNDER CONSTRUCTION -- TEMP
*/
// FirebaseUI config.
var uiConfig = {
  'signInSuccessUrl': '/index.html',
  'signInOptions': [
    // Leave the lines as is for the providers you want to offer your users.
    firebase.auth.GoogleAuthProvider.PROVIDER_ID,
    firebase.auth.GithubAuthProvider.PROVIDER_ID,
    firebase.auth.EmailAuthProvider.PROVIDER_ID
  ],
  // Terms of service url.
  'tosUrl': '<your-tos-url>',
};

// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());
// The start method will wait until the DOM is loaded.
ui.start('#firebaseui-auth-container', uiConfig);

initApp = function() {

  //this should become more dynamic, with more intuitive control/interfacing.
  firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
        // User is signed in. Below are properties of the user.
        displayName = user.displayName;
        email = user.email;
        emailVerified = user.emailVerified;
        photoURL = user.photoURL;
        uid = user.uid;
        providerData = user.providerData;

        // this is for more user/site control
          user.getToken().then(function(accessToken) {
          document.getElementById("email_test").innerHTML= "email: " + email + "";
        });

        // update navbar
        var navBar = document.getElementById("navContainer");
        navBar.innerHTML =
        '
' +
            '<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">' +
                'Toggle navigation' +
                'Menu ' +
            '</button>' +
            'Dashboard' +
        '
' +
        '
' +
        '
' +
            '
' +
                'Home' +
            '
' +
            '
' +
                'Committees' +
            '
' +
            '
' +
                'Sign out' +
            '
' +
        '
'+
        '
';

        // if !user
    } else {
      var navBar = document.getElementById("navContainer");
      navBar.innerHTML =
      '
' +
          '<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">' +
              'Toggle navigation' +
              'Menu ' +
          '</button>' +
          'Attendance' +
      '
' +
      '
' +
          '
' +
              '
' +
                  'Home' +
              '
' +
              '
' +
                'Committees' +
              '
' +
              '
' +
                  'Login' +
              '
' +
              '
' +
                  'Register' +
              '
' +
          '
' +
      '
';
    }
    // catch error
  }, function(error) {
    console.log(error);
  });
};

// login function
var login = function(){
  var email = $("#email_login").val();
  var password = $("#password_login").val();

  firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
    // catch error
    var errorCode = error.code;
    var errorMessage = error.message;
    showError(errorMessage);
  });
  $("#prob-alert").html("You're now logged in (testing)");
  $("#prob-alert").show();

};

var register = function() {
  var firstname = $("#firstname").val();
  var lastname = $("#lastname").val();
  var email = $("#email").val();
  var username = $("#username").val();
  var pass1 = $("#pass1").val();
  var pass2 = $("#pass2").val();

  if (firstname == "") {
    showError("First name is empty.");
  } else if (lastname == "") {
    showError("Last name is empty.");
  } else if (email == "") {
    showError("Email is empty.");
  } else if (username == "") {
    showError("Username is empty.");
  } else if (pass1 == "" || pass2 == "") {
    showError("Password is empty.");
  } else if (pass1 != pass2) {
    showError("Passwords do no match.");
  } else {
    firebase.auth().createUserWithEmailAndPassword(email, pass1).catch(function(error) {
      // Handle Errors here.
      var errorCode = error.code;
      var errorMessage = error.message;
      showError(errorMessage);
    });
    $("#prob-alert").html("You're now registered (testing)");
    $("#prob-alert").show();
  }
};

var showError = function(message) {
  $("#prob-alert").html(message);
  $("#prob-alert").show();
};

window.addEventListener('load', function() {
  initApp()
});

var signOut = function() {
  firebase.auth().signOut();

};

var getUser = function() {

};
<commit_msg>Changed 'Become a Member' to 'Attendance' (fixed)<commit_after>/*
*UNDER CONSTRUCTION -- TEMP
*/
// FirebaseUI config.
var uiConfig = {
  'signInSuccessUrl': '/index.html',
  'signInOptions': [
    // Leave the lines as is for the providers you want to offer your users.
    firebase.auth.GoogleAuthProvider.PROVIDER_ID,
    firebase.auth.GithubAuthProvider.PROVIDER_ID,
    firebase.auth.EmailAuthProvider.PROVIDER_ID
  ],
  // Terms of service url.
  'tosUrl': '<your-tos-url>',
};

// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());
// The start method will wait until the DOM is loaded.
ui.start('#firebaseui-auth-container', uiConfig);

initApp = function() {

  //this should become more dynamic, with more intuitive control/interfacing.
  firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
        // User is signed in. Below are properties of the user.
        displayName = user.displayName;
        email = user.email;
        emailVerified = user.emailVerified;
        photoURL = user.photoURL;
        uid = user.uid;
        providerData = user.providerData;

        // this is for more user/site control
          user.getToken().then(function(accessToken) {
          document.getElementById("email_test").innerHTML= "email: " + email + "";
        });

        // update navbar
        var navBar = document.getElementById("navContainer");
        navBar.innerHTML =
        '
' +
            '<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">' +
                'Toggle navigation' +
                'Menu ' +
            '</button>' +
            'Dashboard' +
        '
' +
        '
' +
        '
' +
            '
' +
                'Home' +
            '
' +
            '
' +
                'Committees' +
            '
' +
            '
' +
                'Sign out' +
            '
' +
        '
'+
        '
';

        // if !user
    } else {
      var navBar = document.getElementById("navContainer");
      navBar.innerHTML =
      '
' +
          '<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">' +
              'Toggle navigation' +
              'Menu ' +
          '</button>' +
          'Attendance' +
      '
' +
      '
' +
          '
' +
              '
' +
                  'Home' +
              '
' +
              '
' +
                'Committees' +
              '
' +
              '
' +
                  'Login' +
              '
' +
              '
' +
                  'Register' +
              '
' +
          '
' +
      '
';
    }
    // catch error
  }, function(error) {
    console.log(error);
  });
};

// login function
var login = function(){
  var email = $("#email_login").val();
  var password = $("#password_login").val();

  firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
    // catch error
    var errorCode = error.code;
    var errorMessage = error.message;
    showError(errorMessage);
  });
  $("#prob-alert").html("You're now logged in (testing)");
  $("#prob-alert").show();

};

var register = function() {
  var firstname = $("#firstname").val();
  var lastname = $("#lastname").val();
  var email = $("#email").val();
  var username = $("#username").val();
  var pass1 = $("#pass1").val();
  var pass2 = $("#pass2").val();

  if (firstname == "") {
    showError("First name is empty.");
  } else if (lastname == "") {
    showError("Last name is empty.");
  } else if (email == "") {
    showError("Email is empty.");
  } else if (username == "") {
    showError("Username is empty.");
  } else if (pass1 == "" || pass2 == "") {
    showError("Password is empty.");
  } else if (pass1 != pass2) {
    showError("Passwords do no match.");
  } else {
    firebase.auth().createUserWithEmailAndPassword(email, pass1).catch(function(error) {
      // Handle Errors here.
      var errorCode = error.code;
      var errorMessage = error.message;
      showError(errorMessage);
    });
    $("#prob-alert").html("You're now registered (testing)");
    $("#prob-alert").show();
  }
};

var showError = function(message) {
  $("#prob-alert").html(message);
  $("#prob-alert").show();
};

window.addEventListener('load', function() {
  initApp()
});

var signOut = function() {
  firebase.auth().signOut();

};

var getUser = function() {

};
<|endoftext|>


<commit_before>/* @flow */
'use strict';

import React from 'react';
import { Platform} from 'react-native';
import NativeBaseComponent from '../Base/NativeBaseComponent';
import computeProps from '../../Utils/computeProps';
import Button from './Button';
import View from './View';
import Title from './Title';
import InputGroup from './InputGroup';
import Subtitle from './Subtitle';
import _ from 'lodash';

export default class Header extends NativeBaseComponent {

    propTypes: {
        searchBar : React.PropTypes.bool,
        rounded : React.PropTypes.bool,
        style : React.PropTypes.object,
        iconRight: React.PropTypes.bool
    }

    getInitialStyle() {
        return {
            navbar: {
                backgroundColor: this.getTheme().toolbarDefaultBg,
                justifyContent: (!Array.isArray(this.props.children) && Platform.OS == 'ios') ? 'center' : 'space-between',
                flexDirection: 'row',
                alignItems: 'center',
                paddingLeft: (!Array.isArray(this.props.children) && Platform.OS == 'android') ? 30 : undefined,
                paddingHorizontal: 15,
                paddingTop: (Platform.OS === 'ios' ) ? 15 : 0,
                shadowColor: '#000',
                shadowOffset: {width: 0, height: 2},
                shadowOpacity: 0.1,
                shadowRadius: 1.5,
                height: this.getTheme().toolbarHeight,
                elevation: 3,
                position: 'relative'
            },
            iosToolbarSearch: {
                backgroundColor: this.getTheme().toolbarInputColor,
                borderRadius: this.props.rounded ? 25 : 2,
                height: 30,
                borderColor: 'transparent',
                flex:1
            },
            androidToolbarSearch: {
                backgroundColor: '#fff',
                borderRadius: 2,
                borderColor: 'transparent',
                elevation: 2,
                flex:1
            },
            toolbarButton: {
                paddingHorizontal: 15
            }
        }
    }

    prepareRootProps() {

        var defaultProps = {
            style: this.getInitialStyle().navbar
        };

        return computeProps(this.props, defaultProps);

    }
    renderChildren() {
        if(!Array.isArray(this.props.children)) {
            return this.props.children;
        }

        else if (Array.isArray(this.props.children)) {
            var newChildren = [];
            var childrenArray = React.Children.toArray(this.props.children);

            var buttons = [];
            buttons = _.remove(childrenArray, function(item) {
                if(item.type == Button) {
                    return true;
                }
            });

            var title = [];
            title = _.remove(childrenArray, function(item) {
                if(item.type == Title) {
                    return true;
                }
            });

            var subtitle = [];
            subtitle = _.remove(childrenArray, function(item) {
                if(item.type == Subtitle) {
                    return true;
                }
            });

            var input = [];
            input = _.remove(childrenArray, function(item) {
                if(item.type == InputGroup) {
                    return true;
                }
            });

            if (buttons.length == 1 && this.props.iconRight) {
                if (Platform.OS === 'ios') {
                    newChildren.push(<View key='title' style={{position: 'absolute', left: 0, right: 0, top: 13, bottom: 0, alignSelf: 'center', justifyContent: 'center'}}>
                    {[title[0],subtitle[0]]}
                    </View>)
                    newChildren.push(<View key='title2' style={{flex: 3, alignSelf: 'stretch'}} />)
                    newChildren.push(<View key='btn1' style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -14}}>
                    {React.cloneElement(buttons[0], {color: this.getTheme().iosToolbarBtnColor, style: this.getInitialStyle().toolbarButton})}
                    </View>)
                }
                else {
                    newChildren.push(<View key='title' style={{flex: 3, alignSelf: 'stretch', justifyContent: 'center'}}>
                    {[title[0]]}
                    </View>)
                    newChildren.push(<View key='btn1' style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -10, marginRight: 12}}>
                    {React.cloneElement(buttons[0], {style: this.getInitialStyle().toolbarButton, header : true, textStyle: {color: this.getTheme().toolbarTextColor}})}
                    </View>)
                }
            }

            else if (this.props.searchBar) {
                if (Platform.OS === 'ios') {
                    newChildren.push(<View key='search' style={{flex: 1, alignSelf: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -7}}>
                        {React.cloneElement(input[0],{style: this.getInitialStyle().iosToolbarSearch, toolbar : true, key : 'inp'})}
                        </View>)
                        newChildren.push(<View key='searchBtn' style={{alignItems: 'center', justifyContent: 'center', flexDirection: 'row', marginRight: -14}}>
                        {React.cloneElement(buttons[0], {color: this.getTheme().iosToolbarBtnColor, style: this.getInitialStyle().toolbarButton})}
                        </View>)
                    } else {
                        newChildren.push(<View key='search' style={{flex: 1,alignSelf: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -8, marginRight: -8}}>
                        {React.cloneElement(input[0],{style: this.getInitialStyle().androidToolbarSearch, atoolbar : true})}
                        </View>)
                    }
                }
                else if (buttons.length > 1) {
                    if (Platform.OS === 'ios') {
                        newChildren.push(<View key='title' style={{position: 'absolute', left: 0, right: 0, top: 13, bottom: 0, alignSelf: 'center', justifyContent: 'center'}}>
                        {[title[0],subtitle[0]]}
                        </View>)
                        newChildren.push(<View key='btn1' style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -14}}>
                        {React.cloneElement(buttons[0], {color: this.getTheme().iosToolbarBtnColor, style: this.getInitialStyle().toolbarButton})}
                        </View>)
                        newChildren.push(<View key='title2' style={{flex: 3, alignSelf: 'stretch'}} />)
                        if (buttons.length>1) {
                            for (let i = 1; i < buttons.length; i++) {
                                newChildren.push(<View key={'btn' + (i+1)} style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginRight: -14}}>
                                {React.cloneElement(buttons[i], {color: this.getTheme().iosToolbarBtnColor, style: this.getInitialStyle().toolbarButton})}
                                </View>)
                            }
                        }
                    }
                    else {
                        newChildren.push(<View key='btn1' style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -10, marginRight: 12}}>
                        {React.cloneElement(buttons[0], {style: this.getInitialStyle().toolbarButton, header : true, textStyle: {color: this.getTheme().toolbarTextColor}})}
                        </View>)
                        newChildren.push(<View key='title' style={{flex: 3, alignSelf: 'stretch', justifyContent: 'center'}}>
                        {[title[0]]}
                        </View>)
                        for (let i = 1; i < buttons.length; i++) {
                            newChildren.push(<View key={'btn' + (i+1)} style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginRight: -7}}>
                            {React.cloneElement(buttons[i], {style: this.getInitialStyle().toolbarButton, header : true, textStyle: {color: this.getTheme().toolbarTextColor}})}
                            </View>)
                        }
                    }

                }
                else {
                  if (Platform.OS === 'ios') {
                      newChildren.push(<View key='title' style={{position: 'absolute', left: 0, right: 0, top: 13, bottom: 0, alignSelf: 'center', justifyContent: 'center'}}>
                      {[title[0],subtitle[0]]}
                      </View>)

                      if (childrenArray.length>1) {
                          for (let i = 1; i < childrenArray.length; i++) {
                              newChildren.push(<View key={'btn' + (i+1)} style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginRight: -14}}>
                              {React.cloneElement(childrenArray[i], {})}
                              </View>)
                          }
                      }
                  }
                  else {
                      newChildren.push(<View key='title' style={{flex: 3, alignSelf: 'stretch', justifyContent: 'center'}}>
                      {[title[0]]}
                      </View>)
                      for (let i = 1; i < childrenArray.length; i++) {
                          newChildren.push(<View key={'btn' + (i+1)} style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginRight: -7}}>
                          {React.cloneElement(childrenArray[i], {})}
                          </View>)
                      }
                  }
                }
                return newChildren;
            }
        }

        render() {
            return(
            <View ref={c => this._root = c} {...this.prepareRootProps()} >
            {this.renderChildren()}
            </View>
        );
    }
}
<commit_msg>header fix<commit_after>/* @flow */
'use strict';

import React from 'react';
import { Platform} from 'react-native';
import NativeBaseComponent from '../Base/NativeBaseComponent';
import computeProps from '../../Utils/computeProps';
import Button from './Button';
import View from './View';
import Title from './Title';
import InputGroup from './InputGroup';
import Subtitle from './Subtitle';
import _ from 'lodash';

export default class Header extends NativeBaseComponent {

    propTypes: {
        searchBar : React.PropTypes.bool,
        rounded : React.PropTypes.bool,
        style : React.PropTypes.object,
        iconRight: React.PropTypes.bool
    }

    getInitialStyle() {
        return {
            navbar: {
                backgroundColor: this.getTheme().toolbarDefaultBg,
                justifyContent: (!Array.isArray(this.props.children) && Platform.OS == 'ios') ? 'center' : 'space-between',
                flexDirection: 'row',
                alignItems: 'center',
                paddingLeft: (!Array.isArray(this.props.children) && Platform.OS == 'android') ? 30 : undefined,
                paddingHorizontal: 15,
                paddingTop: (Platform.OS === 'ios' ) ? 15 : 0,
                shadowColor: '#000',
                shadowOffset: {width: 0, height: 2},
                shadowOpacity: 0.1,
                shadowRadius: 1.5,
                height: this.getTheme().toolbarHeight,
                elevation: 3,
                position: 'relative'
            },
            iosToolbarSearch: {
                backgroundColor: this.getTheme().toolbarInputColor,
                borderRadius: this.props.rounded ? 25 : 2,
                height: 30,
                borderColor: 'transparent',
                flex:1
            },
            androidToolbarSearch: {
                backgroundColor: '#fff',
                borderRadius: 2,
                borderColor: 'transparent',
                elevation: 2,
                flex:1
            },
            toolbarButton: {
                paddingHorizontal: 15
            }
        }
    }

    prepareRootProps() {

        var defaultProps = {
            style: this.getInitialStyle().navbar
        };

        return computeProps(this.props, defaultProps);

    }
    renderChildren() {
        if(!Array.isArray(this.props.children)) {
            return this.props.children;
        }

        else if (Array.isArray(this.props.children)) {
            var newChildren = [];
            var childrenArray = React.Children.toArray(this.props.children);

            var buttons = [];
            buttons = _.remove(childrenArray, function(item) {
                if(item.type == Button) {
                    return true;
                }
            });

            var title = [];
            title = _.remove(childrenArray, function(item) {
                if(item.type == Title) {
                    return true;
                }
            });

            var subtitle = [];
            subtitle = _.remove(childrenArray, function(item) {
                if(item.type == Subtitle) {
                    return true;
                }
            });

            var input = [];
            input = _.remove(childrenArray, function(item) {
                if(item.type == InputGroup) {
                    return true;
                }
            });

            if (buttons.length == 1 && this.props.iconRight) {
                if (Platform.OS === 'ios') {
                    newChildren.push(<View key='title' style={{position: 'absolute', left: 0, right: 0, top: 13, bottom: 0, alignSelf: 'center', justifyContent: 'center'}}>
                    {[title[0],subtitle[0]]}
                    </View>)
                    newChildren.push(<View key='title2' style={{flex: 3, alignSelf: 'stretch'}} />)
                    newChildren.push(<View key='btn1' style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -14}}>
                    {React.cloneElement(buttons[0], {color: this.getTheme().iosToolbarBtnColor, style: this.getInitialStyle().toolbarButton})}
                    </View>)
                }
                else {
                    newChildren.push(<View key='title' style={{flex: 3, alignSelf: 'stretch', justifyContent: 'center'}}>
                    {[title[0]]}
                    </View>)
                    newChildren.push(<View key='btn1' style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -10, marginRight: 12}}>
                    {React.cloneElement(buttons[0], {style: this.getInitialStyle().toolbarButton, header : true, textStyle: {color: this.getTheme().toolbarTextColor}})}
                    </View>)
                }
            }

            else if (this.props.searchBar) {
                if (Platform.OS === 'ios') {
                    newChildren.push(<View key='search' style={{flex: 1, alignSelf: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -7}}>
                        {React.cloneElement(input[0],{style: this.getInitialStyle().iosToolbarSearch, toolbar : true, key : 'inp'})}
                        </View>)
                        newChildren.push(<View key='searchBtn' style={{alignItems: 'center', justifyContent: 'center', flexDirection: 'row', marginRight: -14}}>
                        {React.cloneElement(buttons[0], {color: this.getTheme().iosToolbarBtnColor, style: this.getInitialStyle().toolbarButton})}
                        </View>)
                    } else {
                        newChildren.push(<View key='search' style={{flex: 1,alignSelf: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -8, marginRight: -8}}>
                        {React.cloneElement(input[0],{style: this.getInitialStyle().androidToolbarSearch, atoolbar : true})}
                        </View>)
                    }
                }
                else if (buttons.length >= 1) {
                    if (Platform.OS === 'ios') {
                        newChildren.push(<View key='title' style={{position: 'absolute', left: 0, right: 0, top: 13, bottom: 0, alignSelf: 'center', justifyContent: 'center'}}>
                        {[title[0],subtitle[0]]}
                        </View>)
                        newChildren.push(<View key='btn1' style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -14}}>
                        {React.cloneElement(buttons[0], {color: this.getTheme().iosToolbarBtnColor, style: this.getInitialStyle().toolbarButton})}
                        </View>)
                        newChildren.push(<View key='title2' style={{flex: 3, alignSelf: 'stretch'}} />)
                        if (buttons.length>1) {
                            for (let i = 1; i < buttons.length; i++) {
                                newChildren.push(<View key={'btn' + (i+1)} style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginRight: -14}}>
                                {React.cloneElement(buttons[i], {color: this.getTheme().iosToolbarBtnColor, style: this.getInitialStyle().toolbarButton})}
                                </View>)
                            }
                        }
                    }
                    else {
                        newChildren.push(<View key='btn1' style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginLeft: -10, marginRight: 12}}>
                        {React.cloneElement(buttons[0], {style: this.getInitialStyle().toolbarButton, header : true, textStyle: {color: this.getTheme().toolbarTextColor}})}
                        </View>)
                        newChildren.push(<View key='title' style={{flex: 3, alignSelf: 'stretch', justifyContent: 'center'}}>
                        {[title[0]]}
                        </View>)
                        for (let i = 1; i < buttons.length; i++) {
                            newChildren.push(<View key={'btn' + (i+1)} style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginRight: -7}}>
                            {React.cloneElement(buttons[i], {style: this.getInitialStyle().toolbarButton, header : true, textStyle: {color: this.getTheme().toolbarTextColor}})}
                            </View>)
                        }
                    }

                }
                else {
                  if (Platform.OS === 'ios') {
                      newChildren.push(<View key='title' style={{position: 'absolute', left: 0, right: 0, top: 13, bottom: 0, alignSelf: 'center', justifyContent: 'center'}}>
                      {[title[0],subtitle[0]]}
                      </View>)

                      if (childrenArray.length>1) {
                          for (let i = 1; i < childrenArray.length; i++) {
                              newChildren.push(<View key={'btn' + (i+1)} style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginRight: -14}}>
                              {React.cloneElement(childrenArray[i], {})}
                              </View>)
                          }
                      }
                  }
                  else {
                      newChildren.push(<View key='title' style={{flex: 3, alignSelf: 'stretch', justifyContent: 'center'}}>
                      {[title[0]]}
                      </View>)
                      for (let i = 1; i < childrenArray.length; i++) {
                          newChildren.push(<View key={'btn' + (i+1)} style={{alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row', marginRight: -7}}>
                          {React.cloneElement(childrenArray[i], {})}
                          </View>)
                      }
                  }
                }
                return newChildren;
            }
        }

        render() {
            return(
            <View ref={c => this._root = c} {...this.prepareRootProps()} >
            {this.renderChildren()}
            </View>
        );
    }
}
<|endoftext|>


<commit_before>// MIDAS Server. Copyright Kitware SAS. Licensed under the Apache License 2.0.

var midas = midas || {};
midas.tracker = midas.tracker || {};

midas.tracker.OFFICIAL_COLOR_KEY = null;
midas.tracker.UNOFFICIAL_COLOR_KEY = 'red';
midas.tracker.unofficialVisible = true;

/**
 * In modern browsers that support window.history.replaceState,
 * this updates the currently displayed URL in the browser to make
 * permalinking easy.
 */
midas.tracker.updateUrlBar = function () {
    if (typeof window.history.replaceState == 'function') {
        var params = '?trendId=' + json.tracker.trendIds;
        params += '&startDate=' + $('#startdate').val();
        params += '&endDate=' + $('#enddate').val();

        if (json.tracker.rightTrend) {
            params += '&rightTrendId=' + json.tracker.rightTrend.trend_id;
            if (typeof json.tracker.y2Min != 'undefined' && typeof json.tracker.y2Max != 'undefined') {
                params += '&y2Min=' + json.tracker.y2Min + '&y2Max=' + json.tracker.y2Max;
            }
        }
        if (typeof json.tracker.yMin != 'undefined' && typeof json.tracker.yMax != 'undefined') {
            params += '&yMin=' + json.tracker.yMin + '&yMax=' + json.tracker.yMax;
        }
        window.history.replaceState({}, '', params);
    }
};

/**
 * Extract the jqplot curve data from the scalar daos passed to us
 */
midas.tracker.extractCurveData = function (curves) {
    // TODO remove duplicates from branchFilters
    if (!midas.tracker.branchFilters) {
        midas.tracker.branchFilters = [''];
    }
    var allPoints = [],
        allColors = [],
        minVal, maxVal;
    $.each(curves, function (idx, scalars) {
        if (!scalars) {
            return;
        }
        $.each(midas.tracker.branchFilters, function (idx, branchFilter) {
            var points = [];
            var colors = [];
            $.each(scalars, function (idx, scalar) {
                if (!midas.tracker.unofficialVisible && scalar.official == 0) {
                    return;
                }
                var value = parseFloat(scalar.value);
                if (!branchFilter || branchFilter === scalar.branch) {
                    points.push([scalar.submit_time, value]);
                }

                if (typeof minVal == 'undefined' || value < minVal) {
                    minVal = value;
                }
                if (typeof maxVal == 'undefined' || value > maxVal) {
                    maxVal = value;
                }
                if (scalar.official == 1) {
                    colors.push(midas.tracker.OFFICIAL_COLOR_KEY);
                }
                else {
                    colors.push(midas.tracker.UNOFFICIAL_COLOR_KEY);
                }
            });
            allPoints.push(points);
            allColors.push(colors);
        });
    });
    return {
        points: allPoints,
        colors: allColors,
        minVal: minVal,
        maxVal: maxVal
    };
};

/**
 * Fill in the "info" sidebar section based on the curve data
 */
midas.tracker.populateInfo = function (curveData) {
    var count = curveData.points[0].length;
    if (json.tracker.rightTrend) {
        count += curveData.points[1].length;
    }
    $('#pointCount').html(count);
    $('#minVal').html(curveData.minVal);
    $('#maxVal').html(curveData.maxVal);
};

midas.tracker.bindPlotEvents = function () {
    $('#chartDiv').unbind('jqplotDataClick').bind('jqplotClick', function (ev, gridpos, datapos, dataPoint, plot) {
        if (dataPoint == null || typeof dataPoint.seriesIndex == 'undefined') {
            return;
        }
        var scalarId;
        if (!json.tracker.rightTrend || dataPoint.seriesIndex == 0) {
            scalarId = json.tracker.scalars[dataPoint.seriesIndex][dataPoint.pointIndex].scalar_id;
        }
        else {
            scalarId = json.tracker.rightScalars[dataPoint.pointIndex].scalar_id;
        }
        $('.webroot').val(json.global.webroot);
        midas.loadDialog('scalarPoint' + scalarId, '/tracker/scalar/details?scalarId=' + scalarId);
        midas.showDialog('Scalar details', false, {
            width: 500
        });
    });
};

midas.tracker.renderChartArea = function (curveData, first) {
    if (midas.tracker.plot) {
        midas.tracker.plot.destroy();
    }
    if (curveData.points[0].length > 0) {
        $('#chartDiv').html('');
        var opts = {
            axes: {
                xaxis: {
                    pad: 1.05,
                    renderer: $.jqplot.DateAxisRenderer,
                    tickRenderer: $.jqplot.CanvasAxisTickRenderer,
                    tickOptions: {
                        formatString: "%Y-%m-%d",
                        angle: 270,
                        fontSize: '11px',
                        labelPosition: 'middle'
                    }

                },
                yaxis: {
                    pad: 1.05,
                    label: midas.tracker.yaxisLabel,
                    labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
                    labelOptions: {
                        angle: 270,
                        fontSize: '12px'
                    }
                }
            },
            highlighter: {
                show: true,
                showTooltip: true
            },
            cursor: {
                show: true,
                zoom: true,
                showTooltip: false
            },
            grid: {
                backgroundColor: 'white',
                shadow: false
            },
            series: []
        };
        // Now assign official/unofficial color to each marker
        $.each(curveData.colors, function (idx, trendColors) {
            opts.series[idx] = {
                renderer: $.jqplot.DifferentColorMarkerLineRenderer,
                shadow: false,
                rendererOptions: {
                    markerColors: curveData.colors[idx],
                    shapeRenderer: $.jqplot.ShapeRenderer
                }
            };
        });
        if (json.tracker.rightTrend) {
            opts.legend = {
                show: true,
                labels: [json.tracker.trends[0].display_name, json.tracker.rightTrend.display_name],
                location: 'se'
            };
            opts.axes.y2axis = {
                show: true,
                pad: 1.05,
                label: midas.tracker.yaxis2Label,
                labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
                labelOptions: {
                    angle: 270,
                    fontSize: '12px'
                },
                showLabel: true
            };
            opts.series[0].yaxis = 'yaxis';
            opts.series[1].yaxis = 'y2axis';

            if (typeof json.tracker.y2Min != 'undefined' && typeof json.tracker.y2Max != 'undefined') {
                opts.axes.y2axis.min = parseFloat(json.tracker.y2Min);
                opts.axes.y2axis.max = parseFloat(json.tracker.y2Max);
                opts.axes.y2axis.pad = 1.0;
            }
        }
        else if (json.tracker.trends.length > 1 || midas.tracker.branchFilters.length > 1) {
            var labels = [];
            $.each(json.tracker.trends, function (key, trend) {
                var label = trend.display_name;
                if (trend.unit != '') {
                    label += ' (' + trend.unit + ')';
                }
                $.each(midas.tracker.branchFilters, function (idx, branchFilter) {
                    if (!branchFilter) {
                        branchFilter = '[all branches]'
                    }
                    var branchLabel = label + ': ' + branchFilter;
                    labels.push(branchLabel);
                });
            });
            opts.legend = {
                show: true,
                location: 'se',
                labels: labels
            };
        }

        if (typeof json.tracker.yMin != 'undefined' && typeof json.tracker.yMax != 'undefined') {
            opts.axes.yaxis.min = parseFloat(json.tracker.yMin);
            opts.axes.yaxis.max = parseFloat(json.tracker.yMax);
            opts.axes.yaxis.pad = 1.0;
        }

        midas.tracker.plot = $.jqplot('chartDiv', curveData.points, opts);
        midas.tracker.bindPlotEvents();

        $('a.resetZoomAction').unbind('click').click(function () {
            midas.tracker.plot.resetZoom();
        });
    }
    else {
        $('#chartDiv').html('There are no values for this trend in the specified date range.');
    }
    if (first) {
        $.jqplot.postDrawHooks.push(midas.tracker.bindPlotEvents); // must re-bind data click each time we redraw
    }
    midas.tracker.populateInfo(curveData);
};

$(window).load(function () {
    var inputCurves = json.tracker.scalars;
    if (json.tracker.rightTrend) {
        inputCurves.push(json.tracker.rightScalars);
    }
    var curveData = midas.tracker.extractCurveData(inputCurves);

    if (json.tracker.trends.length == 1) {
        midas.tracker.yaxisLabel = json.tracker.trends[0].display_name;
        if (json.tracker.trends[0].unit) {
            midas.tracker.yaxisLabel += ' (' + json.tracker.trends[0].unit + ')';
        }
    }
    else {
        midas.tracker.yaxisLabel = '';
    }
    if (json.tracker.rightTrend) {
        midas.tracker.yaxis2Label = json.tracker.rightTrend.display_name;
        if (json.tracker.rightTrend.unit) {
            midas.tracker.yaxis2Label += ' (' + json.tracker.rightTrend.unit + ')';
        }
    }

    var dates = $("#startdate, #enddate").datepicker({
        defaultDate: "today",
        changeMonth: true,
        numberOfMonths: 1,
        onSelect: function (selectedDate) {
            var option = this.id == "startdate" ? "minDate" : "maxDate";
            var instance = $(this).data("datepicker");
            var date = $.datepicker.parseDate(
                instance.settings.dateFormat || $.datepicker._defaults.dateFormat,
                selectedDate, instance.settings);
            dates.not(this).datepicker("option", option, date);
        },
        dayNamesMin: ["S", "M", "T", "W", "T", "F", "S"]
    });
    $('#startdate').val(json.tracker.initialStartDate);
    $('#enddate').val(json.tracker.initialEndDate);
    $('#filterButton').click(function () {
        $(this).attr('disabled', 'disabled');
        $('#dateRangeUpdating').show();
        var params = {
            trendId: json.tracker.trendIds,
            startDate: $('#startdate').val(),
            endDate: $('#enddate').val()
        };
        if (json.tracker.rightTrend) {
            params.rightTrendId = json.tracker.rightTrend.trend_id;
        }
        $.post(json.global.webroot + '/tracker/trend/scalars', params, function (retVal) {
            var resp = $.parseJSON(retVal);
            json.tracker.scalars = resp.scalars;
            json.tracker.rightScalars = resp.rightScalars;
            var inputCurves = json.tracker.scalars;
            if (json.tracker.rightTrend) {
                inputCurves.push(json.tracker.rightScalars);
            }
            midas.tracker.updateUrlBar();
            midas.tracker.renderChartArea(midas.tracker.extractCurveData(inputCurves), false);
            $('#filterButton').removeAttr('disabled');
            $('#dateRangeUpdating').hide();
        });
    });

    $('.branchFilterContainer').on('change', '.branchfilter', null, function () {
        midas.tracker.updateBranchFilters();
    });

    $('.add-branchfilter').click(function () {
        var div = $('
Other Trend:
');
        var removeLink = $('Remove').click(function () {
            div.remove();
        });
        div.append($($('.branchfilter')[0]).clone()).append(removeLink);

        $('.branchFilterContainer').append(div);
    });

    midas.tracker.renderChartArea(curveData, true);

    $('a.thresholdAction').click(function () {
        midas.loadDialog('thresholdNotification', '/tracker/trend/notify?trendId=' + json.tracker.trends[0].trend_id);
        midas.showDialog('Email notification settings', false);
    });
    $('a.axesControl').click(function () {
        midas.showDialogWithContent('Axes Controls', $('#axesControlTemplate').html(), false, {
            width: 380
        });
        var container = $('div.MainDialog');
        container.find('input.yMin').val(json.tracker.yMin);
        container.find('input.yMax').val(json.tracker.yMax);
        container.find('input.y2Min').val(json.tracker.y2Min);
        container.find('input.y2Max').val(json.tracker.y2Max);
        container.find('input.updateAxes').unbind('click').click(function () {
            json.tracker.yMin = container.find('input.yMin').val();
            json.tracker.yMax = container.find('input.yMax').val();
            if (json.tracker.rightTrend) {
                json.tracker.y2Min = container.find('input.y2Min').val();
                json.tracker.y2Max = container.find('input.y2Max').val();
            }
            midas.tracker.renderChartArea(curveData, false);
            midas.tracker.updateUrlBar();
            container.dialog('close');
        });
    });
    $('a.deleteTrend').click(function () {
        midas.showDialogWithContent('Confirm Delete Trend', $('#deleteTrendTemplate').html(), false, {
            width: 420
        });
        var container = $('div.MainDialog');
        container.find('input.deleteYes').unbind('click').click(function () {
            $(this).attr('disabled', 'disabled');
            container.find('input.deleteNo').attr('disabled', 'disabled');

            midas.ajaxWithProgress(container.find('div.deleteProgressBar'),
                container.find('div.deleteProgressMessage'),
                json.global.webroot + '/tracker/trend/delete', {
                    trendId: json.tracker.trendIds
                },
                midas.tracker.trendDeleted
            );
        });
        container.find('input.deleteNo').unbind('click').click(function () {
            $('div.MainDialog').dialog('close');
        });
    });

    $('a.toggleUnofficialVisibility').click(function () {
        if (midas.tracker.unofficialVisible) {
            $(this).find('.linkText').text('Show unofficial submissions');
            $(this).find('.toggleUnofficialIcon').removeClass('toHide').addClass('toShow');
        }
        else {
            $(this).find('.linkText').text('Hide unofficial submissions');
            $(this).find('.toggleUnofficialIcon').removeClass('toShow').addClass('toHide');
        }
        midas.tracker.unofficialVisible = !midas.tracker.unofficialVisible;
        var curveData = midas.tracker.extractCurveData(inputCurves);
        midas.tracker.renderChartArea(curveData, false);
    });
});

midas.tracker.trendDeleted = function (resp) {
    window.location = json.global.webroot + '/tracker/producer/view?producerId=' + json.tracker.producerId;
};

midas.tracker.updateBranchFilters = function () {
    midas.tracker.branchFilters = [];
    $.each($('.branchfilter'), function () {
        midas.tracker.branchFilters.push($(this).val());
    });
    //midas.tracker.branchFilter = $('.branchfilter:first').val();
    midas.tracker.renderChartArea(midas.tracker.extractCurveData(json.tracker.scalars), false);
};
<commit_msg>Some more style tweaks to trend plot<commit_after>// MIDAS Server. Copyright Kitware SAS. Licensed under the Apache License 2.0.

var midas = midas || {};
midas.tracker = midas.tracker || {};

midas.tracker.OFFICIAL_COLOR_KEY = null;
midas.tracker.UNOFFICIAL_COLOR_KEY = 'red';
midas.tracker.unofficialVisible = true;

/**
 * In modern browsers that support window.history.replaceState,
 * this updates the currently displayed URL in the browser to make
 * permalinking easy.
 */
midas.tracker.updateUrlBar = function () {
    if (typeof window.history.replaceState == 'function') {
        var params = '?trendId=' + json.tracker.trendIds;
        params += '&startDate=' + $('#startdate').val();
        params += '&endDate=' + $('#enddate').val();

        if (json.tracker.rightTrend) {
            params += '&rightTrendId=' + json.tracker.rightTrend.trend_id;
            if (typeof json.tracker.y2Min != 'undefined' && typeof json.tracker.y2Max != 'undefined') {
                params += '&y2Min=' + json.tracker.y2Min + '&y2Max=' + json.tracker.y2Max;
            }
        }
        if (typeof json.tracker.yMin != 'undefined' && typeof json.tracker.yMax != 'undefined') {
            params += '&yMin=' + json.tracker.yMin + '&yMax=' + json.tracker.yMax;
        }
        window.history.replaceState({}, '', params);
    }
};

/**
 * Extract the jqplot curve data from the scalar daos passed to us
 */
midas.tracker.extractCurveData = function (curves) {
    // TODO remove duplicates from branchFilters
    if (!midas.tracker.branchFilters) {
        midas.tracker.branchFilters = [''];
    }
    var allPoints = [],
        allColors = [],
        minVal, maxVal;
    $.each(curves, function (idx, scalars) {
        if (!scalars) {
            return;
        }
        $.each(midas.tracker.branchFilters, function (idx, branchFilter) {
            var points = [];
            var colors = [];
            $.each(scalars, function (idx, scalar) {
                if (!midas.tracker.unofficialVisible && scalar.official == 0) {
                    return;
                }
                var value = parseFloat(scalar.value);
                if (!branchFilter || branchFilter === scalar.branch) {
                    points.push([scalar.submit_time, value]);
                }

                if (typeof minVal == 'undefined' || value < minVal) {
                    minVal = value;
                }
                if (typeof maxVal == 'undefined' || value > maxVal) {
                    maxVal = value;
                }
                if (scalar.official == 1) {
                    colors.push(midas.tracker.OFFICIAL_COLOR_KEY);
                }
                else {
                    colors.push(midas.tracker.UNOFFICIAL_COLOR_KEY);
                }
            });
            allPoints.push(points);
            allColors.push(colors);
        });
    });
    return {
        points: allPoints,
        colors: allColors,
        minVal: minVal,
        maxVal: maxVal
    };
};

/**
 * Fill in the "info" sidebar section based on the curve data
 */
midas.tracker.populateInfo = function (curveData) {
    var count = curveData.points[0].length;
    if (json.tracker.rightTrend) {
        count += curveData.points[1].length;
    }
    $('#pointCount').html(count);
    $('#minVal').html(curveData.minVal);
    $('#maxVal').html(curveData.maxVal);
};

midas.tracker.bindPlotEvents = function () {
    $('#chartDiv').unbind('jqplotDataClick').bind('jqplotClick', function (ev, gridpos, datapos, dataPoint, plot) {
        if (dataPoint == null || typeof dataPoint.seriesIndex == 'undefined') {
            return;
        }
        var scalarId;
        if (!json.tracker.rightTrend || dataPoint.seriesIndex == 0) {
            scalarId = json.tracker.scalars[dataPoint.seriesIndex][dataPoint.pointIndex].scalar_id;
        }
        else {
            scalarId = json.tracker.rightScalars[dataPoint.pointIndex].scalar_id;
        }
        $('.webroot').val(json.global.webroot);
        midas.loadDialog('scalarPoint' + scalarId, '/tracker/scalar/details?scalarId=' + scalarId);
        midas.showDialog('Scalar details', false, {
            width: 500
        });
    });
};

midas.tracker.renderChartArea = function (curveData, first) {
    if (midas.tracker.plot) {
        midas.tracker.plot.destroy();
    }
    if (curveData.points[0].length > 0) {
        $('#chartDiv').html('');
        var opts = {
            axes: {
                xaxis: {
                    pad: 1.05,
                    renderer: $.jqplot.DateAxisRenderer,
                    tickRenderer: $.jqplot.CanvasAxisTickRenderer,
                    tickOptions: {
                        formatString: "%Y-%m-%d",
                        angle: 270,
                        fontSize: '11px',
                        labelPosition: 'middle',
                        showGridline: false
                    }

                },
                yaxis: {
                    pad: 1.05,
                    label: midas.tracker.yaxisLabel,
                    labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
                    labelOptions: {
                        fontSize: '12px',
                        angle: 270
                    }
                }
            },
            highlighter: {
                show: true,
                showTooltip: true
            },
            cursor: {
                show: true,
                zoom: true,
                showTooltip: false
            },
            grid: {
                backgroundColor: 'white',
                borderWidth: 0,
                shadow: false
            },
            series: []
        };
        // Now assign official/unofficial color to each marker
        $.each(curveData.colors, function (idx, trendColors) {
            opts.series[idx] = {
                renderer: $.jqplot.DifferentColorMarkerLineRenderer,
                shadow: false,
                rendererOptions: {
                    markerColors: curveData.colors[idx],
                    shapeRenderer: $.jqplot.ShapeRenderer
                }
            };
        });
        if (json.tracker.rightTrend) {
            opts.legend = {
                show: true,
                labels: [json.tracker.trends[0].display_name, json.tracker.rightTrend.display_name],
                location: 'se'
            };
            opts.axes.y2axis = {
                show: true,
                pad: 1.05,
                label: midas.tracker.yaxis2Label,
                labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
                labelOptions: {
                    angle: 270,
                    fontSize: '12px'
                },
                showLabel: true
            };
            opts.series[0].yaxis = 'yaxis';
            opts.series[1].yaxis = 'y2axis';

            if (typeof json.tracker.y2Min != 'undefined' && typeof json.tracker.y2Max != 'undefined') {
                opts.axes.y2axis.min = parseFloat(json.tracker.y2Min);
                opts.axes.y2axis.max = parseFloat(json.tracker.y2Max);
                opts.axes.y2axis.pad = 1.0;
            }
        }
        else if (json.tracker.trends.length > 1 || midas.tracker.branchFilters.length > 1) {
            var labels = [];
            $.each(json.tracker.trends, function (key, trend) {
                var label = trend.display_name;
                if (trend.unit != '') {
                    label += ' (' + trend.unit + ')';
                }
                $.each(midas.tracker.branchFilters, function (idx, branchFilter) {
                    if (!branchFilter) {
                        branchFilter = '[all branches]'
                    }
                    var branchLabel = label + ': ' + branchFilter;
                    labels.push(branchLabel);
                });
            });
            opts.legend = {
                show: true,
                location: 'se',
                labels: labels
            };
        }

        if (typeof json.tracker.yMin != 'undefined' && typeof json.tracker.yMax != 'undefined') {
            opts.axes.yaxis.min = parseFloat(json.tracker.yMin);
            opts.axes.yaxis.max = parseFloat(json.tracker.yMax);
            opts.axes.yaxis.pad = 1.0;
        }

        midas.tracker.plot = $.jqplot('chartDiv', curveData.points, opts);
        midas.tracker.bindPlotEvents();

        $('a.resetZoomAction').unbind('click').click(function () {
            midas.tracker.plot.resetZoom();
        });
    }
    else {
        $('#chartDiv').html('There are no values for this trend in the specified date range.');
    }
    if (first) {
        $.jqplot.postDrawHooks.push(midas.tracker.bindPlotEvents); // must re-bind data click each time we redraw
    }
    midas.tracker.populateInfo(curveData);
};

$(window).load(function () {
    var inputCurves = json.tracker.scalars;
    if (json.tracker.rightTrend) {
        inputCurves.push(json.tracker.rightScalars);
    }
    var curveData = midas.tracker.extractCurveData(inputCurves);

    if (json.tracker.trends.length == 1) {
        midas.tracker.yaxisLabel = json.tracker.trends[0].display_name;
        if (json.tracker.trends[0].unit) {
            midas.tracker.yaxisLabel += ' (' + json.tracker.trends[0].unit + ')';
        }
    }
    else {
        midas.tracker.yaxisLabel = '';
    }
    if (json.tracker.rightTrend) {
        midas.tracker.yaxis2Label = json.tracker.rightTrend.display_name;
        if (json.tracker.rightTrend.unit) {
            midas.tracker.yaxis2Label += ' (' + json.tracker.rightTrend.unit + ')';
        }
    }

    var dates = $("#startdate, #enddate").datepicker({
        defaultDate: "today",
        changeMonth: true,
        numberOfMonths: 1,
        onSelect: function (selectedDate) {
            var option = this.id == "startdate" ? "minDate" : "maxDate";
            var instance = $(this).data("datepicker");
            var date = $.datepicker.parseDate(
                instance.settings.dateFormat || $.datepicker._defaults.dateFormat,
                selectedDate, instance.settings);
            dates.not(this).datepicker("option", option, date);
        },
        dayNamesMin: ["S", "M", "T", "W", "T", "F", "S"]
    });
    $('#startdate').val(json.tracker.initialStartDate);
    $('#enddate').val(json.tracker.initialEndDate);
    $('#filterButton').click(function () {
        $(this).attr('disabled', 'disabled');
        $('#dateRangeUpdating').show();
        var params = {
            trendId: json.tracker.trendIds,
            startDate: $('#startdate').val(),
            endDate: $('#enddate').val()
        };
        if (json.tracker.rightTrend) {
            params.rightTrendId = json.tracker.rightTrend.trend_id;
        }
        $.post(json.global.webroot + '/tracker/trend/scalars', params, function (retVal) {
            var resp = $.parseJSON(retVal);
            json.tracker.scalars = resp.scalars;
            json.tracker.rightScalars = resp.rightScalars;
            var inputCurves = json.tracker.scalars;
            if (json.tracker.rightTrend) {
                inputCurves.push(json.tracker.rightScalars);
            }
            midas.tracker.updateUrlBar();
            midas.tracker.renderChartArea(midas.tracker.extractCurveData(inputCurves), false);
            $('#filterButton').removeAttr('disabled');
            $('#dateRangeUpdating').hide();
        });
    });

    $('.branchFilterContainer').on('change', '.branchfilter', null, function () {
        midas.tracker.updateBranchFilters();
    });

    $('.add-branchfilter').click(function () {
        var div = $('
Other Trend:
');
        var removeLink = $('Remove').click(function () {
            div.remove();
        });
        div.append($($('.branchfilter')[0]).clone()).append(removeLink);

        $('.branchFilterContainer').append(div);
    });

    midas.tracker.renderChartArea(curveData, true);

    $('a.thresholdAction').click(function () {
        midas.loadDialog('thresholdNotification', '/tracker/trend/notify?trendId=' + json.tracker.trends[0].trend_id);
        midas.showDialog('Email notification settings', false);
    });
    $('a.axesControl').click(function () {
        midas.showDialogWithContent('Axes Controls', $('#axesControlTemplate').html(), false, {
            width: 380
        });
        var container = $('div.MainDialog');
        container.find('input.yMin').val(json.tracker.yMin);
        container.find('input.yMax').val(json.tracker.yMax);
        container.find('input.y2Min').val(json.tracker.y2Min);
        container.find('input.y2Max').val(json.tracker.y2Max);
        container.find('input.updateAxes').unbind('click').click(function () {
            json.tracker.yMin = container.find('input.yMin').val();
            json.tracker.yMax = container.find('input.yMax').val();
            if (json.tracker.rightTrend) {
                json.tracker.y2Min = container.find('input.y2Min').val();
                json.tracker.y2Max = container.find('input.y2Max').val();
            }
            midas.tracker.renderChartArea(curveData, false);
            midas.tracker.updateUrlBar();
            container.dialog('close');
        });
    });
    $('a.deleteTrend').click(function () {
        midas.showDialogWithContent('Confirm Delete Trend', $('#deleteTrendTemplate').html(), false, {
            width: 420
        });
        var container = $('div.MainDialog');
        container.find('input.deleteYes').unbind('click').click(function () {
            $(this).attr('disabled', 'disabled');
            container.find('input.deleteNo').attr('disabled', 'disabled');

            midas.ajaxWithProgress(container.find('div.deleteProgressBar'),
                container.find('div.deleteProgressMessage'),
                json.global.webroot + '/tracker/trend/delete', {
                    trendId: json.tracker.trendIds
                },
                midas.tracker.trendDeleted
            );
        });
        container.find('input.deleteNo').unbind('click').click(function () {
            $('div.MainDialog').dialog('close');
        });
    });

    $('a.toggleUnofficialVisibility').click(function () {
        if (midas.tracker.unofficialVisible) {
            $(this).find('.linkText').text('Show unofficial submissions');
            $(this).find('.toggleUnofficialIcon').removeClass('toHide').addClass('toShow');
        }
        else {
            $(this).find('.linkText').text('Hide unofficial submissions');
            $(this).find('.toggleUnofficialIcon').removeClass('toShow').addClass('toHide');
        }
        midas.tracker.unofficialVisible = !midas.tracker.unofficialVisible;
        var curveData = midas.tracker.extractCurveData(inputCurves);
        midas.tracker.renderChartArea(curveData, false);
    });
});

midas.tracker.trendDeleted = function (resp) {
    window.location = json.global.webroot + '/tracker/producer/view?producerId=' + json.tracker.producerId;
};

midas.tracker.updateBranchFilters = function () {
    midas.tracker.branchFilters = [];
    $.each($('.branchfilter'), function () {
        midas.tracker.branchFilters.push($(this).val());
    });
    //midas.tracker.branchFilter = $('.branchfilter:first').val();
    midas.tracker.renderChartArea(midas.tracker.extractCurveData(json.tracker.scalars), false);
};
<|endoftext|>