<commit_before>define([
	'goo/util/gizmos/Gizmo',
	'goo/entities/components/MeshDataComponent',
	'goo/entities/components/MeshRendererComponent',
	'goo/renderer/MeshData',
	'goo/util/MeshBuilder',
	'goo/shapes/Sphere',
	'goo/shapes/Torus',
	'goo/renderer/Material',
	'goo/entities/EntityUtils',
	'goo/math/Vector3',
	'goo/math/Matrix3x3',
	'goo/math/Transform',
	'goo/renderer/Renderer',
	'goo/math/Ray'
], function(
	Gizmo,
	MeshDataComponent,
	MeshRendererComponent,
	MeshData,
	MeshBuilder,
	Sphere,
	Torus,
	Material,
	EntityUtils,
	Vector3,
	Matrix3x3,
	Transform,
	Renderer,
	Ray
) {
	'use strict';
	function RotationGizmo() {
		Gizmo.call(this, 'RotationGizmo');
		this._ballMesh = new Sphere(32, 32, 1.1);
		this._torusMesh = new Torus(64, 8, 0.12);

		this._buildBall();
		this._buildTorus(0);
		this._buildTorus(1);
		this._buildTorus(2);

		this._rotation = new Matrix3x3();
		this._rotationScale = 4;
		this._axis = new Vector3();
		this._direction = new Vector3();

		this._ray = new Ray();
		this._m1 = new Matrix3x3();
		this._m2 = new Matrix3x3();

		//TODO: create a function that does this sort of thing
		this.snap = false;
		this.accumulatedRotationX = 0;
		this.accumulatedRotationY = 0;
		this.accumulatedRotationThorX = 0;
		this.accumulatedRotationThorY = 0;
		this.accumulatedRotationThorZ = 0;
		this.oldAngleX = 0;
		this.oldAngleY = 0;
		this.oldAngleZ = 0;
	}
	RotationGizmo.prototype = Object.create(Gizmo.prototype);

	RotationGizmo.prototype.activate = function(props) {
		Gizmo.prototype.activate.call(this, props);

		var worldCenter = this._v0,
			pickedPoint = this._v1,
			rotationDirection = this._v2,
			axis = this._axis,
			ray = this._ray;

		if(this._activeHandle.axis < 3) {
			// Get rotation axis
			axis.setv([Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z][this._activeHandle.axis]);
			this.transform.rotation.applyPost(axis);

			// Get rotation center
			worldCenter.setv(Vector3.ZERO);
			this.transform.matrix.applyPostPoint(worldCenter);

			// Get picked point in world space (sort of)
			Renderer.mainCamera.getPickRay(
				props.x,
				props.y,
				1,1,
				ray
			);
			pickedPoint.setv(ray.origin).subv(worldCenter);
			var d = pickedPoint.length() * 0.9;
			pickedPoint.setv(ray.direction).muld(d,d,d).addv(ray.origin);

			// Get vector from center to picked point, cross it with rotation axis and get drag direction
			rotationDirection.setv(pickedPoint).subv(worldCenter);
			Vector3.cross(axis, rotationDirection, rotationDirection);
			rotationDirection.addv(pickedPoint);
			Renderer.mainCamera.getScreenCoordinates(
				rotationDirection,
				1,1,
				this._direction
			);
			this._direction.sub_d(props.x, 1-props.y, 0);
			this._direction.y *= -1;

			this._direction.z = 0;
			this._direction.normalize();
		}
	};

	RotationGizmo.prototype.process = function() {
		var op = this._mouse.oldPosition;
		var p = this._mouse.position;
		var dx = p[0] - op[0];
		var dy = p[1] - op[1];
		if(this._activeHandle.axis === 3) {
			this._rotateOnScreen(dx, dy);
		} else {
			this._rotateOnAxis(dx, dy);
		}

		op[0] = p[0];
		op[1] = p[1];
		this.updateTransforms();
		this.dirty = false;

		if(this.onChange instanceof Function) {
			this.onChange(this.transform.rotation);
		}
	};

	RotationGizmo.prototype._rotateOnScreen = function(dx, dy) {
		this._rotation.setIdentity();

		if (this.snap && false) { // snap in this mode is confusing
			this.accumulatedRotationY += dx * this._rotationScale;
			this.accumulatedRotationX += dy * this._rotationScale;

			var angleLimit = Math.PI / 8;

			if (this.accumulatedRotationX > angleLimit) {
				this.accumulatedRotationX -= angleLimit;
				this._rotation.rotateX(angleLimit);
			} else if (this.accumulatedRotationX < 0) {
				this.accumulatedRotationX += angleLimit;
				this._rotation.rotateX(-angleLimit);
			}

			if (this.accumulatedRotationY > angleLimit) {
				this.accumulatedRotationY -= angleLimit;
				this._rotation.rotateY(angleLimit);
			} else if (this.accumulatedRotationY < 0) {
				this.accumulatedRotationY += angleLimit;
				this._rotation.rotateY(-angleLimit);
			}
		} else {
			this._rotation.rotateY(dx * this._rotationScale);
			this._rotation.rotateX(dy * this._rotationScale);
		}

		var camMat = Renderer.mainCamera.getViewMatrix().data;
		var camRotation = this._m1, screenRotation = this._m2;

		camRotation.set(
			camMat[0], camMat[1], camMat[2],
			camMat[4], camMat[5], camMat[6],
			camMat[8], camMat[9], camMat[10]
		);
		screenRotation.set(camRotation).invert();
		screenRotation.combine(this._rotation);
		screenRotation.combine(camRotation);

		Matrix3x3.combine(
			screenRotation,
			this.transform.rotation,
			this.transform.rotation
		);
	};
	// --- experimental functions go here
	function step (size) {
		return function (x) {
			return Math.floor(x / size) * size;
		}
	}

	var step8thpi = step(Math.PI / 8);

	function inter(x, fromStart, fromEnd, toStart, toEnd) {
		var fraction = (x - fromStart) / (fromEnd - fromStart);
		return fraction * (toEnd - toStart) + toStart;
	}

	function inclinedType1 (size, t) {
		return function (x) {
			x += size / 2 + t;
			if (x < 0) {
				x -= size + t*2;
				x *= -1;
				var intr = Math.floor(x / size) * size;
				var frac = x % size - t;

				return -(frac < t || frac > size - t ?
					intr + inter(frac, -t, t, 0, size) - size :
					intr);
			} else {
				var intr = Math.floor(x / size) * size;
				var frac = x % size - t;

				return frac < t || frac > size - t ?
					intr + inter(frac, -t, t, 0, size) - size :
					intr;
			}
		}
	}

	function inclinedType2 (size, t) {
		return function (x) {
			var z = x % size;
			z += z < 0 ? size : 0;
			if (z < t) {
				return x - z;
			} else if (z > size - t) {
				return x + size - z;
			}
			return x;
		}
	}

	var inclined8thpi = inclinedType2(Math.PI / 4, Math.PI / 32);
	var identitate = function(x) { return x; };
	var simpleSmooth = function(x) { x *= 10; return x + Math.sin(x); };
	var tranFun = inclined8thpi;
	// ---

	RotationGizmo.prototype._rotateOnAxis = function(dx, dy) {
		this._rotation.setIdentity();

		var sum = (dx * this._direction.x) + (dy * this._direction.y);
		sum *= this._rotationScale;

		if (this.snap) {
			switch(this._activeHandle.axis) {
				case 0:
					this.accumulatedRotationThorX += sum;
					var newAngleX = tranFun(this.accumulatedRotationThorX);
					this._rotation.rotateX(newAngleX - this.oldAngleX);
					this.oldAngleX = newAngleX;
					break;
				case 1:
					this.accumulatedRotationThorY += sum;
					var newAngleY = tranFun(this.accumulatedRotationThorY);
					this._rotation.rotateY(newAngleY - this.oldAngleY);
					this.oldAngleY = newAngleY;
					break;
				case 2:
					this.accumulatedRotationThorZ += sum;
					var newAngleZ = tranFun(this.accumulatedRotationThorZ);
					this._rotation.rotateZ(newAngleZ - this.oldAngleZ);
					this.oldAngleZ = newAngleZ;
					break;
			}
		} else {
			switch(this._activeHandle.axis) {
				case 0:
					this.accumulatedRotationThorX += sum;
					var newAngleX = this.accumulatedRotationThorX;
					this._rotation.rotateX(newAngleX - this.oldAngleX);
					this.oldAngleX = newAngleX;
					break;
				case 1:
					this.accumulatedRotationThorY += sum;
					var newAngleY = this.accumulatedRotationThorY;
					this._rotation.rotateY(newAngleY - this.oldAngleY);
					this.oldAngleY = newAngleY;
					break;
				case 2:
					this.accumulatedRotationThorZ += sum;
					var newAngleZ = this.accumulatedRotationThorZ;
					this._rotation.rotateZ(newAngleZ - this.oldAngleZ);
					this.oldAngleZ = newAngleZ;
					break;
			}
		}
		Matrix3x3.combine(
			this.transform.rotation,
			this._rotation,
			this.transform.rotation
		);
	};

	RotationGizmo.prototype._buildBall = function() {
		var transform = new Transform();
		transform.scale.setd(1.2, 1.2, 1.2);
		this.renderables.push({
			meshData: this._ballMesh,
			materials: [this._buildMaterialForAxis(3)],
			transform: new Transform(),
			id: Gizmo.registerHandle({ type: 'Rotate', axis: 3 })
		});
	};

	RotationGizmo.prototype._buildTorus = function(dim) {
		var transform = new Transform();
		transform.scale.setd(1.6, 1.6, 1.6);
		if(dim === 0) {
			transform.setRotationXYZ(0, Math.PI/2, 0);
		} else if (dim === 1) {
			transform.setRotationXYZ(Math.PI/2, 0, 0);
		}

		this.renderables.push({
			meshData: this._torusMesh,
			materials: [this._buildMaterialForAxis(dim)],
			transform: transform,
			id: Gizmo.registerHandle({ type: 'Rotate', axis: dim })
		});
	};

	return RotationGizmo;
});<commit_msg>Adjusted rotation gizmo mesh to be easier to pick<commit_after>define([
	'goo/util/gizmos/Gizmo',
	'goo/entities/components/MeshDataComponent',
	'goo/entities/components/MeshRendererComponent',
	'goo/renderer/MeshData',
	'goo/util/MeshBuilder',
	'goo/shapes/Sphere',
	'goo/shapes/Torus',
	'goo/renderer/Material',
	'goo/entities/EntityUtils',
	'goo/math/Vector3',
	'goo/math/Matrix3x3',
	'goo/math/Transform',
	'goo/renderer/Renderer',
	'goo/math/Ray'
], function(
	Gizmo,
	MeshDataComponent,
	MeshRendererComponent,
	MeshData,
	MeshBuilder,
	Sphere,
	Torus,
	Material,
	EntityUtils,
	Vector3,
	Matrix3x3,
	Transform,
	Renderer,
	Ray
) {
	'use strict';
	function RotationGizmo() {
		Gizmo.call(this, 'RotationGizmo');
		this._ballMesh = new Sphere(32, 32, 1.1);
		this._torusMesh = new Torus(64, 8, 0.18);

		this._buildBall();
		this._buildTorus(0);
		this._buildTorus(1);
		this._buildTorus(2);

		this._rotation = new Matrix3x3();
		this._rotationScale = 4;
		this._axis = new Vector3();
		this._direction = new Vector3();

		this._ray = new Ray();
		this._m1 = new Matrix3x3();
		this._m2 = new Matrix3x3();

		//TODO: create a function that does this sort of thing
		this.snap = false;
		this.accumulatedRotationX = 0;
		this.accumulatedRotationY = 0;
		this.accumulatedRotationThorX = 0;
		this.accumulatedRotationThorY = 0;
		this.accumulatedRotationThorZ = 0;
		this.oldAngleX = 0;
		this.oldAngleY = 0;
		this.oldAngleZ = 0;
	}
	RotationGizmo.prototype = Object.create(Gizmo.prototype);

	RotationGizmo.prototype.activate = function(props) {
		Gizmo.prototype.activate.call(this, props);

		var worldCenter = this._v0,
			pickedPoint = this._v1,
			rotationDirection = this._v2,
			axis = this._axis,
			ray = this._ray;

		if(this._activeHandle.axis < 3) {
			// Get rotation axis
			axis.setv([Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z][this._activeHandle.axis]);
			this.transform.rotation.applyPost(axis);

			// Get rotation center
			worldCenter.setv(Vector3.ZERO);
			this.transform.matrix.applyPostPoint(worldCenter);

			// Get picked point in world space (sort of)
			Renderer.mainCamera.getPickRay(
				props.x,
				props.y,
				1,1,
				ray
			);
			pickedPoint.setv(ray.origin).subv(worldCenter);
			var d = pickedPoint.length() * 0.9;
			pickedPoint.setv(ray.direction).muld(d,d,d).addv(ray.origin);

			// Get vector from center to picked point, cross it with rotation axis and get drag direction
			rotationDirection.setv(pickedPoint).subv(worldCenter);
			Vector3.cross(axis, rotationDirection, rotationDirection);
			rotationDirection.addv(pickedPoint);
			Renderer.mainCamera.getScreenCoordinates(
				rotationDirection,
				1,1,
				this._direction
			);
			this._direction.sub_d(props.x, 1-props.y, 0);
			this._direction.y *= -1;

			this._direction.z = 0;
			this._direction.normalize();
		}
	};

	RotationGizmo.prototype.process = function() {
		var op = this._mouse.oldPosition;
		var p = this._mouse.position;
		var dx = p[0] - op[0];
		var dy = p[1] - op[1];
		if(this._activeHandle.axis === 3) {
			this._rotateOnScreen(dx, dy);
		} else {
			this._rotateOnAxis(dx, dy);
		}

		op[0] = p[0];
		op[1] = p[1];
		this.updateTransforms();
		this.dirty = false;

		if(this.onChange instanceof Function) {
			this.onChange(this.transform.rotation);
		}
	};

	RotationGizmo.prototype._rotateOnScreen = function(dx, dy) {
		this._rotation.setIdentity();

		if (this.snap && false) { // snap in this mode is confusing
			this.accumulatedRotationY += dx * this._rotationScale;
			this.accumulatedRotationX += dy * this._rotationScale;

			var angleLimit = Math.PI / 8;

			if (this.accumulatedRotationX > angleLimit) {
				this.accumulatedRotationX -= angleLimit;
				this._rotation.rotateX(angleLimit);
			} else if (this.accumulatedRotationX < 0) {
				this.accumulatedRotationX += angleLimit;
				this._rotation.rotateX(-angleLimit);
			}

			if (this.accumulatedRotationY > angleLimit) {
				this.accumulatedRotationY -= angleLimit;
				this._rotation.rotateY(angleLimit);
			} else if (this.accumulatedRotationY < 0) {
				this.accumulatedRotationY += angleLimit;
				this._rotation.rotateY(-angleLimit);
			}
		} else {
			this._rotation.rotateY(dx * this._rotationScale);
			this._rotation.rotateX(dy * this._rotationScale);
		}

		var camMat = Renderer.mainCamera.getViewMatrix().data;
		var camRotation = this._m1, screenRotation = this._m2;

		camRotation.set(
			camMat[0], camMat[1], camMat[2],
			camMat[4], camMat[5], camMat[6],
			camMat[8], camMat[9], camMat[10]
		);
		screenRotation.set(camRotation).invert();
		screenRotation.combine(this._rotation);
		screenRotation.combine(camRotation);

		Matrix3x3.combine(
			screenRotation,
			this.transform.rotation,
			this.transform.rotation
		);
	};
	// --- experimental functions go here
	function step (size) {
		return function (x) {
			return Math.floor(x / size) * size;
		};
	}

	var step8thpi = step(Math.PI / 8);

	function inter(x, fromStart, fromEnd, toStart, toEnd) {
		var fraction = (x - fromStart) / (fromEnd - fromStart);
		return fraction * (toEnd - toStart) + toStart;
	}

	function inclinedType1 (size, t) {
		return function (x) {
			x += size / 2 + t;
			if (x < 0) {
				x -= size + t*2;
				x *= -1;
				var intr = Math.floor(x / size) * size;
				var frac = x % size - t;

				return -(frac < t || frac > size - t ?
					intr + inter(frac, -t, t, 0, size) - size :
					intr);
			} else {
				var intr = Math.floor(x / size) * size;
				var frac = x % size - t;

				return frac < t || frac > size - t ?
					intr + inter(frac, -t, t, 0, size) - size :
					intr;
			}
		};
	}

	function inclinedType2 (size, t) {
		return function (x) {
			var z = x % size;
			z += z < 0 ? size : 0;
			if (z < t) {
				return x - z;
			} else if (z > size - t) {
				return x + size - z;
			}
			return x;
		};
	}

	var inclined8thpi = inclinedType2(Math.PI / 4, Math.PI / 32);
	var identitate = function(x) { return x; };
	var simpleSmooth = function(x) { x *= 10; return x + Math.sin(x); };
	var tranFun = inclined8thpi;
	// ---

	RotationGizmo.prototype._rotateOnAxis = function(dx, dy) {
		this._rotation.setIdentity();

		var sum = (dx * this._direction.x) + (dy * this._direction.y);
		sum *= this._rotationScale;

		if (this.snap) {
			switch(this._activeHandle.axis) {
				case 0:
					this.accumulatedRotationThorX += sum;
					var newAngleX = tranFun(this.accumulatedRotationThorX);
					this._rotation.rotateX(newAngleX - this.oldAngleX);
					this.oldAngleX = newAngleX;
					break;
				case 1:
					this.accumulatedRotationThorY += sum;
					var newAngleY = tranFun(this.accumulatedRotationThorY);
					this._rotation.rotateY(newAngleY - this.oldAngleY);
					this.oldAngleY = newAngleY;
					break;
				case 2:
					this.accumulatedRotationThorZ += sum;
					var newAngleZ = tranFun(this.accumulatedRotationThorZ);
					this._rotation.rotateZ(newAngleZ - this.oldAngleZ);
					this.oldAngleZ = newAngleZ;
					break;
			}
		} else {
			switch(this._activeHandle.axis) {
				case 0:
					this.accumulatedRotationThorX += sum;
					var newAngleX = this.accumulatedRotationThorX;
					this._rotation.rotateX(newAngleX - this.oldAngleX);
					this.oldAngleX = newAngleX;
					break;
				case 1:
					this.accumulatedRotationThorY += sum;
					var newAngleY = this.accumulatedRotationThorY;
					this._rotation.rotateY(newAngleY - this.oldAngleY);
					this.oldAngleY = newAngleY;
					break;
				case 2:
					this.accumulatedRotationThorZ += sum;
					var newAngleZ = this.accumulatedRotationThorZ;
					this._rotation.rotateZ(newAngleZ - this.oldAngleZ);
					this.oldAngleZ = newAngleZ;
					break;
			}
		}
		Matrix3x3.combine(
			this.transform.rotation,
			this._rotation,
			this.transform.rotation
		);
	};

	RotationGizmo.prototype._buildBall = function() {
		var transform = new Transform();
		transform.scale.setd(1.2, 1.2, 1.2);
		this.renderables.push({
			meshData: this._ballMesh,
			materials: [this._buildMaterialForAxis(3)],
			transform: new Transform(),
			id: Gizmo.registerHandle({ type: 'Rotate', axis: 3 })
		});
	};

	RotationGizmo.prototype._buildTorus = function(dim) {
		var transform = new Transform();
		transform.scale.setd(1.7, 1.7, 1.7);
		if(dim === 0) {
			transform.setRotationXYZ(0, Math.PI/2, 0);
		} else if (dim === 1) {
			transform.setRotationXYZ(Math.PI/2, 0, 0);
		}

		this.renderables.push({
			meshData: this._torusMesh,
			materials: [this._buildMaterialForAxis(dim)],
			transform: transform,
			id: Gizmo.registerHandle({ type: 'Rotate', axis: dim })
		});
	};

	return RotationGizmo;
});<|endoftext|>


<commit_before>var $ = require('jquery');
var matchesSelector = require('matches-selector');
var elementIsVisible = require('kwf/commonjs/element/is-visible');
var benchmarkBox = require('kwf/commonjs/benchmark/box');

var enableOnReadyConsoleProfile = false;

/* fn: fn,
 * scope: scope,
 * options: options || {},
 * num: unique number, //used to mark in initDone
 * selector: selector, // null if onContentReady
 * */
var readyElHandlers = []; //for onElement*
var onReadyState;  //if callOnContentReady should skip 'defer' callbacks or execute only 'defer' callbacks
                   //used on initial ready
var deferredStart = null; //used for timing deferred, required here because of multiple chunks
var onReadyIsCalling = false; //true while callOnContentReady is processing onReadyElQueue and we can add more to queue
var onReadyElQueue = []; //queue for onElementReady/Show/Hide/WidthChange calls
var elCacheBySelector = {};

var deferHandlerNum = null;
var addReadyHandler = function(onAction, selector, fn, options)
{
    if (!options) options = {};
    if (typeof options.defer == 'undefined') options.defer = true; //default defer=true
    readyElHandlers.push({
        selector: selector,
        fn: fn,
        options: options,
        num: readyElHandlers.length, //unique number
        onAction: onAction
    });
    //if initial call is already done redo for new added handlers
    if (onReadyState == 'calledDefer' || (!(options && options.defer) && onReadyState == 'calledNonDefer')) {
        if (!deferHandlerNum) {
            deferHandlerNum = [];
            setTimeout(function() {
                //additionally added handlers need to be called async so priorty can be used correctly (we wait to get more handlers added)
                //needed for Frontend.defer.js
                var hndlerNum = deferHandlerNum;
                deferHandlerNum = null; //set to null before calling callOnContentReady as that might cause addReadyHandler calls
                callOnContentReady(document.body, { action: 'render', handlerNum: hndlerNum });
            }, 1);
        }
        deferHandlerNum.push(readyElHandlers.length-1);
    }
};

var callOnContentReady = function(renderedEl, options)
{
    benchmarkBox.count('callOnContentReady');
    if (!options) options = {};
    if (typeof options.newRender != 'undefined') {
        //backwards compatibility, for callOnContentReady call
        options.action = options.newRender ? 'render' : 'show';
        delete options.newRender;
    }
    if (!options.action) {
        if (typeof console != 'undefined' && console.warn) console.warn('Please set option action on callOnContentReady');
        options.action = 'render';
    }
    if (!renderedEl) {
        if (typeof console != 'undefined' && console.warn) console.warn('Please pass element argument on callOnContentReady');
        renderedEl = document.body;
    }
    if (renderedEl.dom) renderedEl = renderedEl.dom; //ExtJS Element (hopefully)
    if (renderedEl.jquery) {
        renderedEl.each(function(){ callOnContentReady(this, options); });
        return;
    }

    //add entries to onReadyElQueue, depending on renderedEl
    var onActions;
    if (options.action == 'render') {
        onActions = ['render', 'show', 'widthChange', 'contentReady'];
    } else if (options.action == 'show') {
        onActions = ['show', 'widthChange', 'contentReady'];
    } else if (options.action == 'hide') {
        onActions = ['hide'];
    } else if (options.action == 'widthChange') {
        onActions = ['widthChange', 'contentReady'];
    }

    var html = false;
    for (var i = 0; i < readyElHandlers.length; i++) {
        var hndl = readyElHandlers[i];
        if (options.handlerNum && $.inArray(hndl.num, options.handlerNum) == -1) {
            continue;
        }

        //onReadyState gets set before callOnContentReady(body)
        //can not be part of options as it would be missing in recursive calls
        if (onReadyState == 'callNonDefer') {
            if (hndl.options.defer) {
                continue;
            }
        } else if (onReadyState == 'callDefer') {
            if (!hndl.options.defer) {
                continue;
            }
        }

        if (hndl.options.checkVisibility) {
            if (renderedEl != document.body && !elementIsVisible(renderedEl)) {
                if (options.action == 'render' && hndl.selector && elCacheBySelector[hndl.selector]) {
                    //mark cache as dirty as we don't query (and update the selector) as the renderedEl is invisible
                    //TODO don't always mark as dirty especially when we have multiple handlers with same selector
                    elCacheBySelector[hndl.selector].dirty = true;
                }
                continue;
            }
            //if checkVisibility is activated, don't skip based on onActions as
            //even a widthChange action could make an element visible (media queries)
        } else {
            if ($.inArray(hndl.onAction, onActions) == -1) {
                continue;
            }
        }

        if (options.action == 'render' && !html) {
            var t = benchmarkBox.now();
            html = renderedEl.innerHTML;
            benchmarkBox.time('innerHTML', benchmarkBox.now()-t);
        }

        var useSelectorCache;
        if (options.action != 'render' || !hndl.selector) {
            useSelectorCache = true;
        } else {
            if (onReadyState == 'callDefer' && renderedEl == document.body && elCacheBySelector[hndl.selector]) {
                useSelectorCache = true;
            } else {
                var t = benchmarkBox.now();
                var m = hndl.selector.match(/^[a-z]*\.([a-z]+)/i);
                //do a stupid text search on the selector, using that we can skip query for many selectors that don't exist in the current el
                if (m && html.indexOf(m[1]) == -1) {
                    useSelectorCache = true;
                    if (!elCacheBySelector[hndl.selector]) {
                        elCacheBySelector[hndl.selector] = [];
                    }
                } else {
                    useSelectorCache = false;
                }
                benchmarkBox.time('checkInnerHtml', benchmarkBox.now()-t);
            }
        }

        if (useSelectorCache && elCacheBySelector[hndl.selector] != undefined
            && elCacheBySelector[hndl.selector].length && !elCacheBySelector[hndl.selector].dirty
        ) {
            benchmarkBox.count('queryCache');
            var els = [];
            for (var j=0; j<elCacheBySelector[hndl.selector].length; j++) {
                if (renderedEl == document.body ||
                    renderedEl == elCacheBySelector[hndl.selector][j] ||
                    $.contains(renderedEl, elCacheBySelector[hndl.selector][j])
                ) {
                    els.push(elCacheBySelector[hndl.selector][j]);
                }
            }
        } else if (!hndl.selector) {
            var els = $.makeArray($(renderedEl));
        } else {
            var t = benchmarkBox.now();
            var els = $.makeArray($(renderedEl).find(hndl.selector));
            if (matchesSelector(renderedEl, hndl.selector)) {
                els.push(renderedEl);
            }
            benchmarkBox.time('query', benchmarkBox.now() - t);
            if (!elCacheBySelector[hndl.selector]) {
                elCacheBySelector[hndl.selector] = els;
            } else {
                for(var j=0; j<els.length; ++j) {
                    if ($.inArray(els[j], elCacheBySelector[hndl.selector]) == -1) {
                        elCacheBySelector[hndl.selector].push(els[j]);
                    }
                }
            }
        }

        for (var j = 0; j< els.length; ++j) {

            var alreadyInQueue = false;
            $.each(onReadyElQueue, function(indx, queueEntry) {
                if (queueEntry.num == hndl.num && els[j] == queueEntry.el) {
                    alreadyInQueue = true;
                }
            });

            if (!alreadyInQueue) {
                var parentsCount = 0;
                var n = els[j];
                while (n = n.parentNode) {
                    parentsCount++;
                }
                benchmarkBox.count('readyEl');
                onReadyElQueue.push({
                    el: els[j],
                    fn: hndl.fn,
                    options: hndl.options,
                    num: hndl.num,
                    callerOptions: options,
                    onAction: hndl.onAction,
                    selector: hndl.selector,
                    priority: hndl.options.priority || 0,
                    parentsCount: parentsCount
                });
            }
        }
    }

    //sort onReadyElQueue
    var t = benchmarkBox.now();
    onReadyElQueue.sort(function sortOnReadyElQueue(a, b) {
        if (a.priority != b.priority) {
            return a.priority - b.priority;
        } else {
            if (a.parentsCount != b.parentsCount) {
                return a.parentsCount - b.parentsCount;
            } else {
                return a.num - b.num;
            }
        }
    });
    benchmarkBox.time('sort', benchmarkBox.now() - t);

    if (onReadyIsCalling) {
        return;
    }

    onReadyIsCalling = true;

    //call the callback of an element ready handler
    function callQueueFn(queueEntry, config)
    {
        var t = benchmarkBox.now();
        var el = queueEntry.el;
        if (queueEntry.onAction != 'contentReady') {
            el = $(el);
        }
        queueEntry.fn.call(queueEntry.options.scope || window, el, config);
        var fnName = queueEntry.fn.name;
        if (!fnName) {
            fnName = 'unknown';
        }

        benchmarkBox.subTime(
            'on'+queueEntry.onAction.charAt(0).toUpperCase() + queueEntry.onAction.slice(1),
            'fn: '+fnName,
            benchmarkBox.now()-t
        );
    };

    //process one entry of the readyElQueue
    //own function so it can be called in sync or in deferred chunks
    function processOnReadyElQueueEntry()
    {
        var queueEntry = onReadyElQueue.shift();
        var el = queueEntry.el;
        if (queueEntry.onAction == 'render') {
            if (queueEntry.options.checkVisibility && !elementIsVisible(el)) {
                return;
            }
            if (!el.initDone) el.initDone = {};
            if (el.initDone[queueEntry.num]) {
                return;
            }
            el.initDone[queueEntry.num] = true;
            var config = {};
            var configEl = $(el).find('> input[type="hidden"]');
            if (configEl.length) {
                try {
                    var v = configEl.get(0).value;
                    if (v.substr(0, 1) == '{' || v.substr(0, 1) == '[') {
                        config = JSON.parse(v);
                    }
                } catch (err) {}
            }
            callQueueFn(queueEntry, config);
        } else if (queueEntry.onAction == 'show') {
            if (elementIsVisible(el)) {
                callQueueFn(queueEntry);
            }
        } else if (queueEntry.onAction == 'hide') {
            if (!elementIsVisible(el)) {
                callQueueFn(queueEntry);
            }
        } else if (queueEntry.onAction == 'widthChange') {
            if (!queueEntry.options.checkVisibility || elementIsVisible(el)) {
                callQueueFn(queueEntry);
            }
        } else if (queueEntry.onAction == 'contentReady') {
            var options = {
                newRender: (queueEntry.callerOptions.action == 'render'),
                action: queueEntry.callerOptions.action
            };
            callQueueFn(queueEntry, options);
        }
    }

    if (onReadyState == 'callDefer') {
        var processNext = function processNext() {
            benchmarkBox.count('chunks');
            var t = benchmarkBox.now();
            while (onReadyElQueue.length && benchmarkBox.now()-t < 50) {
                processOnReadyElQueueEntry();
            }
            if (onReadyElQueue.length) {
                setTimeout(processNext, 1);
            } else {
                onReadyIsCalling = false;
                benchmarkBox.time('time', benchmarkBox.now()-deferredStart);
                if (enableOnReadyConsoleProfile) console.profileEnd();
                benchmarkBox.create({
                    type: 'onReady defer'
                });
            }
        };
        processNext();
    } else {
        while (onReadyElQueue.length) {
            processOnReadyElQueueEntry();
        }
        onReadyIsCalling = false;
    }

};

$(document).ready(function() {
    if ($(document.body).is('.kwfUp-frontend')) {
        if (!document.body) {
            //this happens if a redirect by changing location in JS is done
            //in that case no contentReady needs to be called
            return;
        }
        var t = benchmarkBox.now();
        if (enableOnReadyConsoleProfile) console.profile("callOnContentReady body");
        onReadyState = 'callNonDefer';
        callOnContentReady(document.body, { action: 'render' });
        onReadyState = 'calledNonDefer';
        if (enableOnReadyConsoleProfile) console.profileEnd();
        benchmarkBox.time('time', benchmarkBox.now()-t);
        benchmarkBox.create({
            type: 'onReady'
        });
        setTimeout(function() {
            deferredStart = benchmarkBox.now();
            if (enableOnReadyConsoleProfile) console.profile("callOnContentReady body deferred");
            onReadyState = 'callDefer';
            callOnContentReady(document.body, { action: 'render' });
            onReadyState = 'calledDefer';
        }, 10);

        var timeoutId;
        $(window).resize(function() {
            if (timeoutId) {
                clearTimeout(timeoutId);
            }
            timeoutId = setTimeout(function() {
                callOnContentReady(document.body, { action: 'widthChange' } );
            }, 100);
        });
    }
});

module.exports = {

    /**
    * Add a callback function that gets called once for every element that appears
    * in the dom tree
    *
    * If an input type="hidden" is found directly under the element it's value gets passed
    * as config (json decoded)
    *
    * @param element selector
    * @param callback function
    * @param options see onContentReady options, additionally checkVisibility (boolean, only call onElementReady when element is visible)
    */
    onRender: function(selector, fn, options) {
        if (arguments.length == 4) {
            var scope = arguments[2];
            var options = arguments[3];
            options.scope = scope;
        }
        addReadyHandler('render', selector, fn, options);
    },

    onShow: function(selector, fn,  options) {
        addReadyHandler('show', selector, fn, options);
    },

    onHide: function(selector, fn, options) {
        addReadyHandler('hide', selector, fn, options);
    },

    onResize: function(selector, fn, options) {
        addReadyHandler('widthChange', selector, fn, options);
    },

    /**
    * Register a function that will be called when content is loaded or shown
    * @param callback function (passed arguments: el, options (newRender=bool))
    * @param options supported are: priority (integer, higher number means it's called after all with lower number, default 0)
    */
    onContentReady: function(fn, options) {
        if (arguments.length == 3) {
            var scope = arguments[1];
            var options = arguments[2];
            options.scope = scope;
        }
        addReadyHandler('contentReady', null, fn, options);
    },

    /**
    * @param element the added/changed dom element
    * @param options newRender (bool): if new elements have been added to the dom or just visiblity/width changed
    */
    callOnContentReady: function(renderedEl, options)
    {
        callOnContentReady(renderedEl, options);
    }
};
<commit_msg>Leak callOnContentReady into window.prefix.Kwf<commit_after>var $ = require('jquery');
var matchesSelector = require('matches-selector');
var elementIsVisible = require('kwf/commonjs/element/is-visible');
var benchmarkBox = require('kwf/commonjs/benchmark/box');

var enableOnReadyConsoleProfile = false;

/* fn: fn,
 * scope: scope,
 * options: options || {},
 * num: unique number, //used to mark in initDone
 * selector: selector, // null if onContentReady
 * */
var readyElHandlers = []; //for onElement*
var onReadyState;  //if callOnContentReady should skip 'defer' callbacks or execute only 'defer' callbacks
                   //used on initial ready
var deferredStart = null; //used for timing deferred, required here because of multiple chunks
var onReadyIsCalling = false; //true while callOnContentReady is processing onReadyElQueue and we can add more to queue
var onReadyElQueue = []; //queue for onElementReady/Show/Hide/WidthChange calls
var elCacheBySelector = {};

var deferHandlerNum = null;
var addReadyHandler = function(onAction, selector, fn, options)
{
    if (!options) options = {};
    if (typeof options.defer == 'undefined') options.defer = true; //default defer=true
    readyElHandlers.push({
        selector: selector,
        fn: fn,
        options: options,
        num: readyElHandlers.length, //unique number
        onAction: onAction
    });
    //if initial call is already done redo for new added handlers
    if (onReadyState == 'calledDefer' || (!(options && options.defer) && onReadyState == 'calledNonDefer')) {
        if (!deferHandlerNum) {
            deferHandlerNum = [];
            setTimeout(function() {
                //additionally added handlers need to be called async so priorty can be used correctly (we wait to get more handlers added)
                //needed for Frontend.defer.js
                var hndlerNum = deferHandlerNum;
                deferHandlerNum = null; //set to null before calling callOnContentReady as that might cause addReadyHandler calls
                callOnContentReady(document.body, { action: 'render', handlerNum: hndlerNum });
            }, 1);
        }
        deferHandlerNum.push(readyElHandlers.length-1);
    }
};

var callOnContentReady = function(renderedEl, options)
{
    benchmarkBox.count('callOnContentReady');
    if (!options) options = {};
    if (typeof options.newRender != 'undefined') {
        //backwards compatibility, for callOnContentReady call
        options.action = options.newRender ? 'render' : 'show';
        delete options.newRender;
    }
    if (!options.action) {
        if (typeof console != 'undefined' && console.warn) console.warn('Please set option action on callOnContentReady');
        options.action = 'render';
    }
    if (!renderedEl) {
        if (typeof console != 'undefined' && console.warn) console.warn('Please pass element argument on callOnContentReady');
        renderedEl = document.body;
    }
    if (renderedEl.dom) renderedEl = renderedEl.dom; //ExtJS Element (hopefully)
    if (renderedEl.jquery) {
        renderedEl.each(function(){ callOnContentReady(this, options); });
        return;
    }

    //add entries to onReadyElQueue, depending on renderedEl
    var onActions;
    if (options.action == 'render') {
        onActions = ['render', 'show', 'widthChange', 'contentReady'];
    } else if (options.action == 'show') {
        onActions = ['show', 'widthChange', 'contentReady'];
    } else if (options.action == 'hide') {
        onActions = ['hide'];
    } else if (options.action == 'widthChange') {
        onActions = ['widthChange', 'contentReady'];
    }

    var html = false;
    for (var i = 0; i < readyElHandlers.length; i++) {
        var hndl = readyElHandlers[i];
        if (options.handlerNum && $.inArray(hndl.num, options.handlerNum) == -1) {
            continue;
        }

        //onReadyState gets set before callOnContentReady(body)
        //can not be part of options as it would be missing in recursive calls
        if (onReadyState == 'callNonDefer') {
            if (hndl.options.defer) {
                continue;
            }
        } else if (onReadyState == 'callDefer') {
            if (!hndl.options.defer) {
                continue;
            }
        }

        if (hndl.options.checkVisibility) {
            if (renderedEl != document.body && !elementIsVisible(renderedEl)) {
                if (options.action == 'render' && hndl.selector && elCacheBySelector[hndl.selector]) {
                    //mark cache as dirty as we don't query (and update the selector) as the renderedEl is invisible
                    //TODO don't always mark as dirty especially when we have multiple handlers with same selector
                    elCacheBySelector[hndl.selector].dirty = true;
                }
                continue;
            }
            //if checkVisibility is activated, don't skip based on onActions as
            //even a widthChange action could make an element visible (media queries)
        } else {
            if ($.inArray(hndl.onAction, onActions) == -1) {
                continue;
            }
        }

        if (options.action == 'render' && !html) {
            var t = benchmarkBox.now();
            html = renderedEl.innerHTML;
            benchmarkBox.time('innerHTML', benchmarkBox.now()-t);
        }

        var useSelectorCache;
        if (options.action != 'render' || !hndl.selector) {
            useSelectorCache = true;
        } else {
            if (onReadyState == 'callDefer' && renderedEl == document.body && elCacheBySelector[hndl.selector]) {
                useSelectorCache = true;
            } else {
                var t = benchmarkBox.now();
                var m = hndl.selector.match(/^[a-z]*\.([a-z]+)/i);
                //do a stupid text search on the selector, using that we can skip query for many selectors that don't exist in the current el
                if (m && html.indexOf(m[1]) == -1) {
                    useSelectorCache = true;
                    if (!elCacheBySelector[hndl.selector]) {
                        elCacheBySelector[hndl.selector] = [];
                    }
                } else {
                    useSelectorCache = false;
                }
                benchmarkBox.time('checkInnerHtml', benchmarkBox.now()-t);
            }
        }

        if (useSelectorCache && elCacheBySelector[hndl.selector] != undefined
            && elCacheBySelector[hndl.selector].length && !elCacheBySelector[hndl.selector].dirty
        ) {
            benchmarkBox.count('queryCache');
            var els = [];
            for (var j=0; j<elCacheBySelector[hndl.selector].length; j++) {
                if (renderedEl == document.body ||
                    renderedEl == elCacheBySelector[hndl.selector][j] ||
                    $.contains(renderedEl, elCacheBySelector[hndl.selector][j])
                ) {
                    els.push(elCacheBySelector[hndl.selector][j]);
                }
            }
        } else if (!hndl.selector) {
            var els = $.makeArray($(renderedEl));
        } else {
            var t = benchmarkBox.now();
            var els = $.makeArray($(renderedEl).find(hndl.selector));
            if (matchesSelector(renderedEl, hndl.selector)) {
                els.push(renderedEl);
            }
            benchmarkBox.time('query', benchmarkBox.now() - t);
            if (!elCacheBySelector[hndl.selector]) {
                elCacheBySelector[hndl.selector] = els;
            } else {
                for(var j=0; j<els.length; ++j) {
                    if ($.inArray(els[j], elCacheBySelector[hndl.selector]) == -1) {
                        elCacheBySelector[hndl.selector].push(els[j]);
                    }
                }
            }
        }

        for (var j = 0; j< els.length; ++j) {

            var alreadyInQueue = false;
            $.each(onReadyElQueue, function(indx, queueEntry) {
                if (queueEntry.num == hndl.num && els[j] == queueEntry.el) {
                    alreadyInQueue = true;
                }
            });

            if (!alreadyInQueue) {
                var parentsCount = 0;
                var n = els[j];
                while (n = n.parentNode) {
                    parentsCount++;
                }
                benchmarkBox.count('readyEl');
                onReadyElQueue.push({
                    el: els[j],
                    fn: hndl.fn,
                    options: hndl.options,
                    num: hndl.num,
                    callerOptions: options,
                    onAction: hndl.onAction,
                    selector: hndl.selector,
                    priority: hndl.options.priority || 0,
                    parentsCount: parentsCount
                });
            }
        }
    }

    //sort onReadyElQueue
    var t = benchmarkBox.now();
    onReadyElQueue.sort(function sortOnReadyElQueue(a, b) {
        if (a.priority != b.priority) {
            return a.priority - b.priority;
        } else {
            if (a.parentsCount != b.parentsCount) {
                return a.parentsCount - b.parentsCount;
            } else {
                return a.num - b.num;
            }
        }
    });
    benchmarkBox.time('sort', benchmarkBox.now() - t);

    if (onReadyIsCalling) {
        return;
    }

    onReadyIsCalling = true;

    //call the callback of an element ready handler
    function callQueueFn(queueEntry, config)
    {
        var t = benchmarkBox.now();
        var el = queueEntry.el;
        if (queueEntry.onAction != 'contentReady') {
            el = $(el);
        }
        queueEntry.fn.call(queueEntry.options.scope || window, el, config);
        var fnName = queueEntry.fn.name;
        if (!fnName) {
            fnName = 'unknown';
        }

        benchmarkBox.subTime(
            'on'+queueEntry.onAction.charAt(0).toUpperCase() + queueEntry.onAction.slice(1),
            'fn: '+fnName,
            benchmarkBox.now()-t
        );
    };

    //process one entry of the readyElQueue
    //own function so it can be called in sync or in deferred chunks
    function processOnReadyElQueueEntry()
    {
        var queueEntry = onReadyElQueue.shift();
        var el = queueEntry.el;
        if (queueEntry.onAction == 'render') {
            if (queueEntry.options.checkVisibility && !elementIsVisible(el)) {
                return;
            }
            if (!el.initDone) el.initDone = {};
            if (el.initDone[queueEntry.num]) {
                return;
            }
            el.initDone[queueEntry.num] = true;
            var config = {};
            var configEl = $(el).find('> input[type="hidden"]');
            if (configEl.length) {
                try {
                    var v = configEl.get(0).value;
                    if (v.substr(0, 1) == '{' || v.substr(0, 1) == '[') {
                        config = JSON.parse(v);
                    }
                } catch (err) {}
            }
            callQueueFn(queueEntry, config);
        } else if (queueEntry.onAction == 'show') {
            if (elementIsVisible(el)) {
                callQueueFn(queueEntry);
            }
        } else if (queueEntry.onAction == 'hide') {
            if (!elementIsVisible(el)) {
                callQueueFn(queueEntry);
            }
        } else if (queueEntry.onAction == 'widthChange') {
            if (!queueEntry.options.checkVisibility || elementIsVisible(el)) {
                callQueueFn(queueEntry);
            }
        } else if (queueEntry.onAction == 'contentReady') {
            var options = {
                newRender: (queueEntry.callerOptions.action == 'render'),
                action: queueEntry.callerOptions.action
            };
            callQueueFn(queueEntry, options);
        }
    }

    if (onReadyState == 'callDefer') {
        var processNext = function processNext() {
            benchmarkBox.count('chunks');
            var t = benchmarkBox.now();
            while (onReadyElQueue.length && benchmarkBox.now()-t < 50) {
                processOnReadyElQueueEntry();
            }
            if (onReadyElQueue.length) {
                setTimeout(processNext, 1);
            } else {
                onReadyIsCalling = false;
                benchmarkBox.time('time', benchmarkBox.now()-deferredStart);
                if (enableOnReadyConsoleProfile) console.profileEnd();
                benchmarkBox.create({
                    type: 'onReady defer'
                });
            }
        };
        processNext();
    } else {
        while (onReadyElQueue.length) {
            processOnReadyElQueueEntry();
        }
        onReadyIsCalling = false;
    }

};

if ('kwfUp-'.length) {
    var ns = 'kwfUp-'.substr(0, 'kwfUp-'.length-1);
    if (typeof window[ns].Kwf == 'undefined') window[ns].Kwf = {};
    window[ns].Kwf.callOnContentReady = callOnContentReady;
} else {
    if (typeof window.Kwf == 'undefined') window.Kwf = {};
    window.Kwf.callOnContentReady = callOnContentReady;
}

$(document).ready(function() {
    if ($(document.body).is('.kwfUp-frontend')) {
        if (!document.body) {
            //this happens if a redirect by changing location in JS is done
            //in that case no contentReady needs to be called
            return;
        }
        var t = benchmarkBox.now();
        if (enableOnReadyConsoleProfile) console.profile("callOnContentReady body");
        onReadyState = 'callNonDefer';
        callOnContentReady(document.body, { action: 'render' });
        onReadyState = 'calledNonDefer';
        if (enableOnReadyConsoleProfile) console.profileEnd();
        benchmarkBox.time('time', benchmarkBox.now()-t);
        benchmarkBox.create({
            type: 'onReady'
        });
        setTimeout(function() {
            deferredStart = benchmarkBox.now();
            if (enableOnReadyConsoleProfile) console.profile("callOnContentReady body deferred");
            onReadyState = 'callDefer';
            callOnContentReady(document.body, { action: 'render' });
            onReadyState = 'calledDefer';
        }, 10);

        var timeoutId;
        $(window).resize(function() {
            if (timeoutId) {
                clearTimeout(timeoutId);
            }
            timeoutId = setTimeout(function() {
                callOnContentReady(document.body, { action: 'widthChange' } );
            }, 100);
        });
    }
});

module.exports = {

    /**
    * Add a callback function that gets called once for every element that appears
    * in the dom tree
    *
    * If an input type="hidden" is found directly under the element it's value gets passed
    * as config (json decoded)
    *
    * @param element selector
    * @param callback function
    * @param options see onContentReady options, additionally checkVisibility (boolean, only call onElementReady when element is visible)
    */
    onRender: function(selector, fn, options) {
        if (arguments.length == 4) {
            var scope = arguments[2];
            var options = arguments[3];
            options.scope = scope;
        }
        addReadyHandler('render', selector, fn, options);
    },

    onShow: function(selector, fn,  options) {
        addReadyHandler('show', selector, fn, options);
    },

    onHide: function(selector, fn, options) {
        addReadyHandler('hide', selector, fn, options);
    },

    onResize: function(selector, fn, options) {
        addReadyHandler('widthChange', selector, fn, options);
    },

    /**
    * Register a function that will be called when content is loaded or shown
    * @param callback function (passed arguments: el, options (newRender=bool))
    * @param options supported are: priority (integer, higher number means it's called after all with lower number, default 0)
    */
    onContentReady: function(fn, options) {
        if (arguments.length == 3) {
            var scope = arguments[1];
            var options = arguments[2];
            options.scope = scope;
        }
        addReadyHandler('contentReady', null, fn, options);
    },

    /**
    * @param element the added/changed dom element
    * @param options newRender (bool): if new elements have been added to the dom or just visiblity/width changed
    */
    callOnContentReady: function(renderedEl, options)
    {
        callOnContentReady(renderedEl, options);
    }
};
<|endoftext|>


<commit_before>angular.module('cat-buddy', [
  'ngRoute',
  'cat-buddy.services',
  'cat-buddy.search-cats',
  'cat-buddy.saved-cats'
])
.config(function($routeProvider) {
  $routeProvider
    .when('/search/cats', {
      templateUrl: 'app/search/cat/searchCats.html',
      controller: 'SearchCatsController'
    })
    .when('/saved/cats', {
      templateUrl: 'app/saved/cat/savedCats.html',
      controller: 'SavedCatsController'
    })
    .otherwise({
      redirectTo: '/search/cats'
    });
});<commit_msg>Add infinite-scroll module to client dependencies<commit_after>angular.module('cat-buddy', [
  'ngRoute',
  'infinite-scroll',
  'cat-buddy.services',
  'cat-buddy.search-cats',
  'cat-buddy.saved-cats'
])
.config(function($routeProvider) {
  $routeProvider
    .when('/search/cats', {
      templateUrl: 'app/search/cat/searchCats.html',
      controller: 'SearchCatsController'
    })
    .when('/saved/cats', {
      templateUrl: 'app/saved/cat/savedCats.html',
      controller: 'SavedCatsController'
    })
    .otherwise({
      redirectTo: '/search/cats'
    });
});<|endoftext|>


<commit_before>Template.registerHelper("activeRoute", function(route) {
	var currentRoute = Router.current().route.getName();
	return currentRoute === route ? " active" : "";
});

Template.registerHelper("calendarTime", function(date) {
	if(date) {
		return moment(date).calendar();
	}
	return "Unknown";
});

Template.registerHelper("equals", function(a, b) {
	return a === b;
});

Template.navigation.events({
	"click #logout": function(e) {
		Meteor.logout(function(error) {
			if(error) {
				alert(error);
			}
			else {
				Router.go("login");
			}
		});
	}
});

Template.login.events({
	"click #facebookLogin": function(e) {
		Meteor.loginWithFacebook(function(error) {
			if(error) {
				alert(error);
			}
			else {
				Router.go("target");
			}
		});
	},
	"click #googleLogin": function(e) {
		Meteor.loginWithGoogle(function(error) {
			if(error) {
				alert(error);
			}
			else {
				Router.go("target");
			}
		});
	}
});

Template.target.helpers({
	"target": function() {
		return Meteor.users.findOne(Meteor.user().target).profile.name;
	},
	"actions": function() {
		return Actions.find({}, {sort: {"timestamp": -1}}).fetch();
	},
	"message": function() {
		var a = "Unknown";
		var m = "claims to have killed";
		var t = "Unknown";
		var c = "";
		var assassin = Meteor.users.findOne(this.assassin);
		var target = Meteor.users.findOne(this.target);

		if(this.assassin === Meteor.userId()) {a = "You"; m = "claim to have killed";}
		else if(assassin) {a = assassin.profile.name;}

		if(this.target === Meteor.userId()) {t = "You"; c = '
Is this correct? Yes / No';}
		else if(target) {t = target.profile.name;}
		if(this.confirmed) {m = "killed"; c = "";}

		return "" + a + " " + m + " " + t + "" + c;
	}
});

Template.target.events({
	"click #logout": function() {
		Meteor.logout(function(error) {
			if(error) {
				alert(error);
			}
			else {
				Router.go("login");
			}
		});
	}
});

Template.leaderboard.helpers({
	"userList": function() {
		return Meteor.users.find({"inGame": true}, {sort: {"kills": -1}}).fetch();
	}
});<commit_msg>Call confirmKill on click<commit_after>Template.registerHelper("activeRoute", function(route) {
	var currentRoute = Router.current().route.getName();
	return currentRoute === route ? " active" : "";
});

Template.registerHelper("calendarTime", function(date) {
	if(date) {
		return moment(date).calendar();
	}
	return "Unknown";
});

Template.registerHelper("equals", function(a, b) {
	return a === b;
});

Template.navigation.events({
	"click #logout": function(e) {
		Meteor.logout(function(error) {
			if(error) {
				alert(error);
			}
			else {
				Router.go("login");
			}
		});
	}
});

Template.login.events({
	"click #facebookLogin": function(e) {
		Meteor.loginWithFacebook(function(error) {
			if(error) {
				alert(error);
			}
			else {
				Router.go("target");
			}
		});
	},
	"click #googleLogin": function(e) {
		Meteor.loginWithGoogle(function(error) {
			if(error) {
				alert(error);
			}
			else {
				Router.go("target");
			}
		});
	}
});

Template.target.helpers({
	"target": function() {
		return Meteor.users.findOne(Meteor.user().target).profile.name;
	},
	"actions": function() {
		return Actions.find({}, {sort: {"timestamp": -1}}).fetch();
	},
	"message": function() {
		var a = "Unknown";
		var m = "claims to have killed";
		var t = "Unknown";
		var c = "";
		var assassin = Meteor.users.findOne(this.assassin);
		var target = Meteor.users.findOne(this.target);

		if(this.assassin === Meteor.userId()) {a = "You"; m = "claim to have killed";}
		else if(assassin) {a = assassin.profile.name;}

		if(this.target === Meteor.userId()) {t = "You"; c = '
Is this correct? Yes / No';}
		else if(target) {t = target.profile.name;}
		if(this.confirmed) {m = "killed"; c = "";}

		return "" + a + " " + m + " " + t + "" + c;
	}
});

Template.target.events({
	"click #confirmKill": function(e) {
		e.preventDefault();
		Meteor.call("confirmKill", this._id);
	},
	"click #denyKill": function(e) {
		e.preventDefault();
		// TODO: denyKill
	}
});

Template.leaderboard.helpers({
	"userList": function() {
		return Meteor.users.find({"inGame": true}, {sort: {"kills": -1}}).fetch();
	}
});<|endoftext|>


<commit_before>/*
 * geoserve - Ronaldo Barbachano June 2013
 * http://redcapmedia.com
 */

Meteor.startup(function(){
    createMap();
    marker_sub = Meteor.subscribe("allMarkers");
    Deps.autorun(function(){
        if(marker_sub.ready()){
            groups_sub = Meteor.subscribe("allGroups"),
            marker_types_sub = Meteor.subscribe("allMarkerTypes"),
            services_sub = Meteor.subscribe("allServices");

            if(marker_types_sub.ready() && groups_sub.ready() && services_sub.ready()){
                // this sets the new loc prematurely?
                var curMarker = Session.get('selected_marker');
                if(curMarker){
                    // load marker services and all services - but also need to trigger this when creating a new record...
                   if(typeof marker_services_sub == 'undefined'){
                        marker_services_sub = Meteor.subscribe("allMarkerServices");
                        var q = markers.findOne({_id:curMarker}).loc;
                        setMapCenter(q);
                        lookForMarkers();
                    }else if(marker_services_sub.ready()){
                        console.log('cur marker set inside of autorun');
                        var q = markers.findOne({_id: curMarker});
                        if(q)
                            if(typeof q['loc'] != 'undefined')
                                setMapCenter(q['loc']);
                            else{
                                console.log('problem with mongo loc query');
                                setMapCenter([0,0]);
                            }
                        lookForMarkers();
                    }
                // probably show something that allows us to edit the selected marker?
                }else{
                    var mCheck = markers.find({},{}).fetch();
                    // maybe not 'create the map new each time?
                    if(typeof map === 'undefined' && !mCheck){
                        createMap();
                        setMapCenter([0,0]);
                    }else if (mCheck){
                        var emCheck = mCheck.pop();
                        if(typeof emCheck != 'undefined')
                            emCheck = emCheck['loc'];
                        else{
                            alert('It appears you are running geoserve for the first time!');
                            // ideally show the add marker screen
                            emCheck = [0,0];
                        }
                        setMapCenter(emCheck);
                    }else
                        setMapCenter([0,0]);
                    lookForMarkers();
                }
            }
        }
    });

});

/*
 *   END Meteor.startup()
 */

/*
 *
 * Template Events
 *
 */

// Deals with navigation showing/hiding elements; going to create screen/edit screen, and geolocation button.

Template.loggedInMenu.events({
    'click .groupAdd' : function(evt,tmpl){
        Template.loggedInMenu.rendered();
        $('div#the_markers').hide();
        $('div#marker_edit').hide();
        $('div#groups').show();
    },
    'click .showMarkers' : function(evt,tmpl){
        Template.loggedInMenu.rendered();
        $('div#groups').hide();
        $('div#the_markers').show();
        if(Session.get('selected_marker'))
            $('div#marker_edit').show();

    },
    'click .markerEditShow': function(evt,tmpl){
        Template.loggedInMenu.rendered();
        $('div#groups').hide();
        $('div#marker_edit').show();
    },
    'click .markerAddShow': function(evt,tmpl){
        Template.loggedInMenu.rendered();
        $('div#groups').hide();
        $('div#marker_add').show();
        $('div#the_markers').hide();
        $('div#marker_edit').hide();
    },
    'click .settingsShow': function(evt,tmpl){
        Template.loggedInMenu.rendered();
        $('div#groups').hide();
        $('div#user_settings').show();
    },
    'click .geolocate': function(evt,tmpl){
        if(navigator.geolocation){
            navigator.geolocation.getCurrentPosition(successFunction, errorFunction);
        }else{
            alert('Could not geolocate');
        }
    }
});

// adds a new 'group' and stores userid as record 'owner'

Template.add_group.events({
    'click input.add_group': function(evt,tmpl){
        var record ={},elements = tmpl.findAll(".group_visibility"),checked_element = undefined;
        record.owner = Meteor.userId();
        record.name = tmpl.find(".group_title").value;
        record.desc = tmpl.find(".group_desc").value;

        // properly determines the checked element for similarlly classed values
        for (var i=0, len=elements.length; i<len; ++i)
            if (elements[i].checked) var checked_element =  elements[i].value;

        record.visibility = (typeof checked_element !== 'undefined'? checked_element: 'private');

        var record_id = groups.insert(record);
        Session.set('selected_group',record_id);

    }
});

// adds a new marker from title/address + group, geocodes it and stores x,y
// TODO : Interactive screen if multiple addresses are returned in geolookup - more rhobust address completion etc.

Template.add_marker.events({
    'click input.add_marker' : function(evt,tmpl){
    /*

        ADD NEW marker
            1) Geocode Address
            2) Store data to database for marker.

    */
        if(typeof geocoder == 'undefined'){
              geocoder = new google.maps.Geocoder();
              console.log('trying to make geocoder');
              console.log(geocoder);

        }
        if(typeof geocoder != 'undefined' && Meteor.userId()){
            var geo_term=tmpl.find(".marker_address").value;
            geocoder.geocode({'address':geo_term},function(results,status){
                results = results[0];
                if(status == google.maps.GeocoderStatus.OK){
                    map.setCenter(results.geometry.location);
                    var record ={};
                    record.name = tmpl.find(".marker_name").value;
                    record.type = tmpl.find(".marker_type").value;
                    record.group = tmpl.find(".marker_group").value;
                    // set loc field to geometry locations given in geocoder
                    record.loc = [results.geometry.location.jb,results.geometry.location.kb];
                    // set owner field to person who created it so they may re-edit what they have created
                    record.owner = Meteor.userId();
                    console.log(record);
                    var record_id = markers.insert(record);

                    Session.set('selected_marker',record_id);
                    lookForMarkers();
                    //lookForMarkers([results.geometry.location.jb,results.geometry.location.kb]);
                    //document.getElementById('.marker_address').value = '';
                }else{
                /*
                    Would you like to insert this marker anyway?
                */
                    alert('Could not geocode location.. please check for internet connection');
                    // show input fields..
                }
            });
            // From here let server build the marker and update client.
            $('#marker_add').hide();

            // show the button to add another marker
            $('.markerAddShow').show();

            // remove fields from session to avoid accidental field duplication/reentry
        }else if(!Meteor.userId()){
            alert('You must be logged in before you can add new markers');
        }
        else{
            // ask to insert a location without a geocoder?
            alert('Gmaps does not seem to be loaded');

        }
    }
});

// Handles edit /deleting markers
// TODO Remove all associated services when removing a marker, create server side methods for secure deletion etc.

Template.groups.events({
    'click .edit_group': function(evt,tmpl){
        console.log('edit group');
        // weird bug.. click was only getting the first classed element...
        if(!Session.equals('selected_group',evt.target.id))
            Session.set('selected_group',evt.target.id);
    },
    // DELETE A GROUP!
    'click input.del_group': function(evt,tmpl){
        console.log('delete this group');
        var group_id = evt.target.id;

        if( group_id && typeof group_id === 'string' && group_id != ''){
            groups.remove({_id:group_id});
            //var q = groups.remove({_id:group_id,owner:Meteor.userId()});
        }
    }
}
);

Template.markers.events({
    'click input.del_marker' : function(evt,tmpl){
        markers.remove({_id:tmpl.data._id});
        $('#marker_add'),show();
    },
    'click a.edit_marker' :function(evt,tmpl){
        /* set session and show marker editor if admin*/
        // probably use the index to look for the term eventually...
        var latlng = new google.maps.LatLng(tmpl.data.loc[0], tmpl.data.loc[1]);
        map.setCenter(latlng);
        var curMarker = Session.get('selected_marker');
        if(curMarker != tmpl.data._id){
            console.log('Session: selected_marker set to ' + tmpl.data._id);
            Session.set('selected_marker',tmpl.data._id);
        }
        $('div#groups').hide();
    }
});

Template.edit_marker.events = {
    'click input.del_marker' : function(evt,tmpl){
        markers.remove({_id:tmpl.data._id});
        // refresh the overlays
        // eventually use SESSION variable to keep track of how to filter the markers
        // based on the user settings/permissions etc.
        lookForMarkers();
    },
    'click .del_marker_service' : function(evt,tmpl){
        marker_services.remove({_id: tmpl.find('.del_marker_service').id});
    }
};

// handles creating a new service (adding it to the services collection)
// adding a service to a marker (creating a record in marker_services that refers to the other collections)
// removing a service from a marker (removing the record from marker_services)

Template.services_offered.events({
    'click input.new_service' : function(evt,tmpl){
        if(Meteor.userId()){
            var new_service = tmpl.find('.new_service_input').value,
            record = {title:new_service,owner:Meteor.userId()};
            services.insert(record);
        }else{
            alert('Must be logged in to create new services to add to markers');
        }
        console.log(record);
    },
    'click input.add_service' : function(evt,tmpl){
        console.log('adding this service');
        var new_service = tmpl.find('.add_services'),
            record = {},
            marker_id = Session.get('selected_marker');
        if(marker_id){
            record.service = new_service.options[new_service.selectedIndex].id;
            record.marker_id = marker_id;
            // make sure no DUPES!!
            marker_services.insert(record);
            // owner? possibly agency? not super needed...
        }else{
            alert('No selected marker to apply new service to');
        }
    },
    'click .del_marker_service' : function(evt,tmpl){
        marker_services.remove({_id: tmpl.find('.del_marker_service').id});
    }
});

/*
 *
 *
 *   Template Functions
 *
 */

Template.groups.selectedGroup = function(evt,tmpl){
    var group_id = Session.get('selected_group');
    console.log('in selected group');
    if(Meteor.userId() && group_id){
        var q =groups.findOne({_id: group_id }), q2=group_codes.find({owner:Meteor.userId(),group_id:group_id});
        q2 = q2.fetch();
        if(q2.length > 0)
            // return the codes so template renders them ...
            console.log(q2);
        else
            console.log('no codes');
        return q;
    }
};

Template.groups.selected_visibility = function(evt,tmpl){
    // check to see if element is selected or not ?
    var group_id = Session.get('selected_group');
    if(Meteor.userId() && group_id){
        // just return entire html block with the select menu and the appropriate value selected SUCH A PITA!!!
        for(var n = 0,vis = ['public','private','invite'],result='',q=groups.findOne({_id: group_id},{visibility:1}); n< vis.length;n++)
            result += '<input type="radio" name="group_visbility" class="group_visibility" id="gv_'+vis[n]+'" value="'+vis[n]+'" '+(vis[n] == q.visibility ? ' CHECKED ':'' )+'  ><label>'+vis[n]+'</label>';

        return result;
    }
}

Template.editor_group.selectedGroup = Template.groups.selectedGroup;

Template.edit_marker.canEdit = function(evt,tmpl){
    var user_id = Meteor.userId(), marker_id = Session.get('selected_marker'), can_edit = Session.get('can_edit');
    // kinda insecure... probably destroy session if user_id isn't around ...
    if(can_edit == marker_id && user_id)
        return true;
    else if(marker_id && user_id)
        Meteor.call('canEdit',marker_id,function(error,result){ if(result) Session.set('can_edit',result); });
    return false;
}

Template.group_menu.userGroups = function(evt,tmpl){
    var q = groups.find({'owner' : Meteor.userId()});
    q = q.fetch();
    return q;
};

Template.add_marker.userGroups = Template.group_menu.userGroups;

Template.add_marker.markerTypes = function(evt,tmpl){
    var q = marker_types.find({},{});
    q = q.fetch();
    return q;
};

Template.services_offered.services = function(evt,tmpl){
    if(typeof services_sub != 'undefined')
        if(services_sub.ready()){
            var q = services.find({},{});
            q = q.fetch();
            return q;
        }else
            console.log('services sub not ready');
};

Template.edit_marker.currentServices = function(evt,tmpl){
    var curMarker = Session.get('selected_marker');
    if(curMarker){
        var currentServ = marker_services.find({marker_id: curMarker});
        currentServ = currentServ.fetch();
        if(currentServ){
            // next link up with services to get titles...
            for(var i = 0;i<currentServ.length;i++){
                var q = services.findOne({_id: currentServ[i].service});
                if(typeof q.title != 'undefined')
                    currentServ[i].title = q.title;
            }
            return currentServ;
        }
    }
};

/*
 *
 *
 *   Logged in menu template functions  to generate menu for markers, and also to handle the selected marker
 *   session
 *
 */

Template.loggedInMenu.marker_index = function(evt,tmpl){
// get User. something to filter this find
    return markers.find({},{});
};

Template.loggedInMenu.selectedMarker = function(evt,tmpl){
    var curMarker = Session.get('selected_marker');
    if(curMarker){
        var q = markers.findOne({_id: curMarker});
       return q;
    }
}

/*
 *
 *
 *  Template rendered functions
 *
 */
Template.loggedInMenu.rendered = function(evt,tmpl){
    $('div#marker_add').hide();
    $('div#user_settings').hide();
    if(!Session.get('selected_group'))
        $('div#groups').hide();
    if(!Session.get('selected_marker'))
        $('div#marker_edit').hide();

};

Template.edit_marker.rendered = function(evt,tmpl){
    $('div#groups').hide();
}

Template.groups.rendered = function(evt,tmpl){
//alert('groups rendered');
            $('.add_group').hide();

};

Template.add_group.rendered = function(evt,tmpl){
    console.log('group added');
};
<commit_msg>fixed services inside of selected marker<commit_after>/*
 * geoserve - Ronaldo Barbachano June 2013
 * http://redcapmedia.com
 */

Meteor.startup(function(){
    createMap();
    marker_sub = Meteor.subscribe("allMarkers");
    Deps.autorun(function(){
        if(marker_sub.ready()){
            groups_sub = Meteor.subscribe("allGroups"),
            marker_types_sub = Meteor.subscribe("allMarkerTypes"),
            services_sub = Meteor.subscribe("allServices");
            marker_services_sub = Meteor.subscribe("allMarkerServices");
            if(marker_types_sub.ready() && groups_sub.ready() && services_sub.ready() && marker_services_sub.ready()){
                // this sets the new loc prematurely?
                var curMarker = Session.get('selected_marker');
                if(curMarker){
                    // load marker services and all services - but also need to trigger this when creating a new record...

                    console.log('cur marker set inside of autorun');
                    var q = markers.findOne({_id: curMarker});
                    if(q)
                        if(typeof q['loc'] != 'undefined')
                            setMapCenter(q['loc']);
                        else{
                            console.log('problem with mongo loc query');
                            setMapCenter([0,0]);
                        }
                    lookForMarkers();

                // probably show something that allows us to edit the selected marker?
                }else{
                    var mCheck = markers.find({},{}).fetch();
                    // maybe not 'create the map new each time?
                    if(typeof map === 'undefined' && !mCheck){
                        createMap();
                        setMapCenter([0,0]);
                    }else if (mCheck){
                        var emCheck = mCheck.pop();
                        if(typeof emCheck != 'undefined')
                            emCheck = emCheck['loc'];
                        else{
                            alert('It appears you are running geoserve for the first time!');
                            // ideally show the add marker screen
                            emCheck = [0,0];
                        }
                        setMapCenter(emCheck);
                    }else
                        setMapCenter([0,0]);
                    lookForMarkers();
                }
            }
        }
    });

});

/*
 *   END Meteor.startup()
 */

/*
 *
 * Template Events
 *
 */

// Deals with navigation showing/hiding elements; going to create screen/edit screen, and geolocation button.

Template.loggedInMenu.events({
    'click .groupAdd' : function(evt,tmpl){
        Template.loggedInMenu.rendered();
        $('div#the_markers').hide();
        $('div#marker_edit').hide();
        $('div#groups').show();
    },
    'click .showMarkers' : function(evt,tmpl){
        Template.loggedInMenu.rendered();
        $('div#groups').hide();
        $('div#the_markers').show();
        if(Session.get('selected_marker'))
            $('div#marker_edit').show();

    },
    'click .markerEditShow': function(evt,tmpl){
        Template.loggedInMenu.rendered();
        $('div#groups').hide();
        $('div#marker_edit').show();
    },
    'click .markerAddShow': function(evt,tmpl){
        Template.loggedInMenu.rendered();
        $('div#groups').hide();
        $('div#marker_add').show();
        $('div#the_markers').hide();
        $('div#marker_edit').hide();
    },
    'click .settingsShow': function(evt,tmpl){
        Template.loggedInMenu.rendered();
        $('div#groups').hide();
        $('div#user_settings').show();
    },
    'click .geolocate': function(evt,tmpl){
        if(navigator.geolocation){
            navigator.geolocation.getCurrentPosition(successFunction, errorFunction);
        }else{
            alert('Could not geolocate');
        }
    }
});

// adds a new 'group' and stores userid as record 'owner'

Template.add_group.events({
    'click input.add_group': function(evt,tmpl){
        var record ={},elements = tmpl.findAll(".group_visibility"),checked_element = undefined;
        record.owner = Meteor.userId();
        record.name = tmpl.find(".group_title").value;
        record.desc = tmpl.find(".group_desc").value;

        // properly determines the checked element for similarlly classed values
        for (var i=0, len=elements.length; i<len; ++i)
            if (elements[i].checked) var checked_element =  elements[i].value;

        record.visibility = (typeof checked_element !== 'undefined'? checked_element: 'private');

        var record_id = groups.insert(record);
        Session.set('selected_group',record_id);

    }
});

// adds a new marker from title/address + group, geocodes it and stores x,y
// TODO : Interactive screen if multiple addresses are returned in geolookup - more rhobust address completion etc.

Template.add_marker.events({
    'click input.add_marker' : function(evt,tmpl){
    /*

        ADD NEW marker
            1) Geocode Address
            2) Store data to database for marker.

    */
        if(typeof geocoder == 'undefined'){
              geocoder = new google.maps.Geocoder();
              console.log('trying to make geocoder');
              console.log(geocoder);

        }
        if(typeof geocoder != 'undefined' && Meteor.userId()){
            var geo_term=tmpl.find(".marker_address").value;
            geocoder.geocode({'address':geo_term},function(results,status){
                results = results[0];
                if(status == google.maps.GeocoderStatus.OK){
                    map.setCenter(results.geometry.location);
                    var record ={};
                    record.name = tmpl.find(".marker_name").value;
                    record.type = tmpl.find(".marker_type").value;
                    record.group = tmpl.find(".marker_group").value;
                    // set loc field to geometry locations given in geocoder
                    record.loc = [results.geometry.location.jb,results.geometry.location.kb];
                    // set owner field to person who created it so they may re-edit what they have created
                    record.owner = Meteor.userId();
                    console.log(record);
                    var record_id = markers.insert(record);

                    Session.set('selected_marker',record_id);
                    lookForMarkers();
                    //lookForMarkers([results.geometry.location.jb,results.geometry.location.kb]);
                    //document.getElementById('.marker_address').value = '';
                }else{
                /*
                    Would you like to insert this marker anyway?
                */
                    alert('Could not geocode location.. please check for internet connection');
                    // show input fields..
                }
            });
            // From here let server build the marker and update client.
            $('#marker_add').hide();

            // show the button to add another marker
            $('.markerAddShow').show();

            // remove fields from session to avoid accidental field duplication/reentry
        }else if(!Meteor.userId()){
            alert('You must be logged in before you can add new markers');
        }
        else{
            // ask to insert a location without a geocoder?
            alert('Gmaps does not seem to be loaded');

        }
    }
});

// Handles edit /deleting markers
// TODO Remove all associated services when removing a marker, create server side methods for secure deletion etc.

Template.groups.events({
    'click .edit_group': function(evt,tmpl){
        console.log('edit group');
        // weird bug.. click was only getting the first classed element...
        if(!Session.equals('selected_group',evt.target.id))
            Session.set('selected_group',evt.target.id);
    },
    // DELETE A GROUP!
    'click input.del_group': function(evt,tmpl){
        console.log('delete this group');
        var group_id = evt.target.id;

        if( group_id && typeof group_id === 'string' && group_id != ''){
            groups.remove({_id:group_id});
            //var q = groups.remove({_id:group_id,owner:Meteor.userId()});
        }
    }
}
);

Template.markers.events({
    'click input.del_marker' : function(evt,tmpl){
        markers.remove({_id:tmpl.data._id});
        $('#marker_add'),show();
    },
    'click a.edit_marker' :function(evt,tmpl){
        /* set session and show marker editor if admin*/
        // probably use the index to look for the term eventually...
        var latlng = new google.maps.LatLng(tmpl.data.loc[0], tmpl.data.loc[1]);
        map.setCenter(latlng);
        var curMarker = Session.get('selected_marker');
        if(curMarker != tmpl.data._id){
            console.log('Session: selected_marker set to ' + tmpl.data._id);
            Session.set('selected_marker',tmpl.data._id);
        }
        $('div#groups').hide();
    }
});

Template.edit_marker.events = {
    'click input.del_marker' : function(evt,tmpl){
        markers.remove({_id:tmpl.data._id});
        // refresh the overlays
        // eventually use SESSION variable to keep track of how to filter the markers
        // based on the user settings/permissions etc.
        lookForMarkers();
    },
    'click .del_marker_service' : function(evt,tmpl){
        marker_services.remove({_id: tmpl.find('.del_marker_service').id});
    }
};

// handles creating a new service (adding it to the services collection)
// adding a service to a marker (creating a record in marker_services that refers to the other collections)
// removing a service from a marker (removing the record from marker_services)

Template.services_offered.events({
    'click input.new_service' : function(evt,tmpl){
        if(Meteor.userId()){
            var new_service = tmpl.find('.new_service_input').value,
            record = {title:new_service,owner:Meteor.userId()};
            services.insert(record);
        }else{
            alert('Must be logged in to create new services to add to markers');
        }
        console.log(record);
    },
    'click input.add_service' : function(evt,tmpl){
        console.log('adding this service');
        var new_service = tmpl.find('.add_services'),
            record = {},
            marker_id = Session.get('selected_marker');
        if(marker_id){
            record.service = new_service.options[new_service.selectedIndex].id;
            record.marker_id = marker_id;
            // make sure no DUPES!!
            marker_services.insert(record);
            // owner? possibly agency? not super needed...
        }else{
            alert('No selected marker to apply new service to');
        }
    },
    'click .del_marker_service' : function(evt,tmpl){
        marker_services.remove({_id: tmpl.find('.del_marker_service').id});
    }
});

/*
 *
 *
 *   Template Functions
 *
 */

Template.groups.selectedGroup = function(evt,tmpl){
    var group_id = Session.get('selected_group');
    console.log('in selected group');
    if(Meteor.userId() && group_id){
        var q =groups.findOne({_id: group_id }), q2=group_codes.find({owner:Meteor.userId(),group_id:group_id});
        q2 = q2.fetch();
        if(q2.length > 0)
            // return the codes so template renders them ...
            console.log(q2);
        else
            console.log('no codes');
        return q;
    }
};

Template.groups.selected_visibility = function(evt,tmpl){
    // check to see if element is selected or not ?
    var group_id = Session.get('selected_group');
    if(Meteor.userId() && group_id){
        // just return entire html block with the select menu and the appropriate value selected SUCH A PITA!!!
        for(var n = 0,vis = ['public','private','invite'],result='',q=groups.findOne({_id: group_id},{visibility:1}); n< vis.length;n++)
            result += '<input type="radio" name="group_visbility" class="group_visibility" id="gv_'+vis[n]+'" value="'+vis[n]+'" '+(vis[n] == q.visibility ? ' CHECKED ':'' )+'  ><label>'+vis[n]+'</label>';

        return result;
    }
}

Template.editor_group.selectedGroup = Template.groups.selectedGroup;

Template.edit_marker.canEdit = function(evt,tmpl){
    var user_id = Meteor.userId(), marker_id = Session.get('selected_marker'), can_edit = Session.get('can_edit');
    // kinda insecure... probably destroy session if user_id isn't around ...
    if(can_edit == marker_id && user_id)
        return true;
    else if(marker_id && user_id)
        Meteor.call('canEdit',marker_id,function(error,result){ if(result) Session.set('can_edit',result); });
    return false;
}

Template.group_menu.userGroups = function(evt,tmpl){
    var q = groups.find({'owner' : Meteor.userId()});
    q = q.fetch();
    return q;
};

Template.add_marker.userGroups = Template.group_menu.userGroups;

Template.add_marker.markerTypes = function(evt,tmpl){
    var q = marker_types.find({},{});
    q = q.fetch();
    return q;
};

Template.services_offered.services = function(evt,tmpl){
    if(typeof services_sub != 'undefined')
        if(services_sub.ready()){
            var q = services.find({},{});
            q = q.fetch();
            return q;
        }else
            console.log('services sub not ready');
};

Template.edit_marker.currentServices = function(evt,tmpl){
    var curMarker = Session.get('selected_marker');
    if(curMarker){
        var currentServ = marker_services.find({marker_id: curMarker});
        currentServ = currentServ.fetch();
        if(currentServ){
            // next link up with services to get titles...
            for(var i = 0;i<currentServ.length;i++){
                var q = services.findOne({_id: currentServ[i].service});
                if(typeof q.title != 'undefined')
                    currentServ[i].title = q.title;
            }
            return currentServ;
        }
    }
};

/*
 *
 *
 *   Logged in menu template functions  to generate menu for markers, and also to handle the selected marker
 *   session
 *
 */

Template.loggedInMenu.marker_index = function(evt,tmpl){
// get User. something to filter this find
    return markers.find({},{});
};

Template.loggedInMenu.selectedMarker = function(evt,tmpl){
    var curMarker = Session.get('selected_marker');
    if(curMarker){
        var q = markers.findOne({_id: curMarker});
       return q;
    }
}

/*
 *
 *
 *  Template rendered functions
 *
 */
Template.loggedInMenu.rendered = function(evt,tmpl){
    $('div#marker_add').hide();
    $('div#user_settings').hide();
    if(!Session.get('selected_group'))
        $('div#groups').hide();
    if(!Session.get('selected_marker'))
        $('div#marker_edit').hide();

};

Template.edit_marker.rendered = function(evt,tmpl){
    $('div#groups').hide();
}

Template.groups.rendered = function(evt,tmpl){
//alert('groups rendered');
            $('.add_group').hide();

};

Template.add_group.rendered = function(evt,tmpl){
    console.log('group added');
};
<|endoftext|>


<commit_before>import * as ohamt from "ohamt";

import * as rrb from "rrb-vector";

import { VNode } from './vnode';

import { q } from './construct';

import { prettyXML } from "./pretty";

import { forEach, into } from "./transducers";

// helpers ---------------

function Value(type, name, value) {
	this._type = type;
	this._name = name;
	this._value = value;
}

Value.prototype.__is_Value = true;

Value.prototype.get = function(){
	return this._value;
};

Value.prototype[Symbol.iterator] = function*(){
	yield this;
};

Value.prototype.values = function(){
	return this[Symbol.iterator]();
};

Value.prototype.count = function(){
	return 0;
};

Value.prototype.size = 0;

Value.prototype.toString = function(root = true, json = false) {
	var str = this._value + "";
	if(this._type == 3 && json) return '"'+str+'"';
	return str;
};

function _restore(next,node){
	next._type = node._type;
	next._name = node._name;
	next.$attrs = node.$attrs;
	next._ns = node._ns;
	return next;
}

function _elemToString(e){
	const attrFunc = (z,v,k) => {
		return z += " "+k+"=\""+v+"\"";
	};
	let str = "<"+e._name;
	let ns = e._ns;
	if(ns) str += " xmlns" + (ns.prefix ? ":" + ns.prefix : "") + "=\"" + ns.uri + "\"";
	str = e.$attrs.reduce(attrFunc,str);
	if(e.size > 0){
		str += ">";
		for(let c of e.values()){
			str += c.toString(false);
		}
		str += "</"+e._name+">";
	} else {
		str += "/>";
	}
	return str;
}

var OrderedMap = ohamt.empty.constructor;

OrderedMap.prototype.__is_Map = true;

OrderedMap.prototype.toString = function(root = true, json = false){
	var str = "";
	var type = this._type;
	const docAttrFunc = (z,v,k) =>
		z += k=="DOCTYPE" ? "<!"+k+" "+v+">" : "<?"+k+" "+v+"?>";
	const objFunc = (kv) => "\""+kv[0]+"\":"+kv[1].toString(false,true);
	if(type==1) {
		str += _elemToString(this);
	} else if(type==3 || type == 12){
		str += this.toString();
	} else  if(type == 6){
		str += "{";
		str += into(this,forEach(objFunc),[]).join(",");
		str += "}";
	} else if(type==9){
		str = this.$attrs.reduce(docAttrFunc,str);
		for(let c of this.values()){
			str += c.toString(false);
		}
	}
	return root ? prettyXML(str) : str;
};

var List = rrb.empty.constructor;

List.prototype.__is_List = true;

List.prototype.toString = function(root = true, json = false){
	var str = "[";
	for(var i=0,l = this.size; i < l; ){
		str += this.get(i).toString(false,true);
		i++;
		if(i<l) str += ",";
	}
	return str + "]";
};

// -----------------------

export function ivalue(type, name, value){
	return new Value(type, name, value);
}

export function vnode(inode, parent, depth, indexInParent){
	return new VNode(inode, inode._type, inode._ns ? q(inode._ns.uri, inode._name) : inode._name, inode._value, parent, depth, indexInParent);
}

export function emptyINode(type, name, attrs, ns) {
    var inode = type == 5 ? rrb.empty.beginMutation() : ohamt.make().beginMutation();
    inode._type = type;
    inode._name = name;
    inode.$attrs = attrs;
	inode._ns = ns;
    return inode;
}

export function emptyAttrMap(init){
	var attrs = ohamt.empty.beginMutation();
	if(init) for(var k in init) attrs = attrs.set(k,init[k]);
	return attrs;
}

export function get(inode, idx){
	return inode.get(idx);
}

export function next(inode,node){
	return inode.next(node.name,node.inode);
}

export function push(inode, val, type){
	type = type || inode._type;
	if(type == 1 || type == 9){
		return _restore(inode.push(val), inode);
	} else if(type == 5) {
		return _restore(inode.push(val[1]), inode);
	} else if(type == 6){
		return _restore(inode.set(val[0],val[1]), inode);
	}
	return inode;
}

export function set(inode,key,val){
	return _restore(inode.set(key,val), inode);
}

export function removeChild(inode,child,type){
	type = type || inode._type;
	var key = child.name, val = child.inode;
	if(type == 1 || type == 9){
		return _restore(inode.removeValue(key, val), inode);
	} else if(type == 5 || type == 6){
		return _restore(inode.remove(key), inode);
	}
	return inode;
}

export function cached(inode,type){
}

export function keys(inode,type){
	return inode.keys();
}

export function values(inode){
	return inode.values();
}

export function finalize(inode){
	if(inode.$attrs) inode.$attrs = inode.$attrs.endMutation();
	return inode.endMutation();
}

export function setAttribute(inode,key,val){
	if(inode.$attrs) inode.$attrs = inode.$attrs.set(key,val);
	return inode;
}

export function count(inode){
	return inode.count();
}

export function first(inode){
	return inode.first();
}

export function last(inode){
	return inode.last();
}

export function attrEntries(inode){
	return inode.$attrs.entries();
}

export function modify(inode,node,ref,type) {
	type = type || inode._type;
	if(type == 1 || type == 9){
		if (ref !== undefined) {
			return _restore(inode.insertBefore([ref.name,ref.inode],[node.name,node.inode]), inode);
		} else {
			// FIXME check the parent type
			return _restore(inode.push([node.name,node.inode]), inode);
		}
	} else if(type == 5){
		if (ref !== undefined) {
			return _restore(inode.insertBefore(ref,node.inode), inode);
		} else {
			return _restore(inode.push(node.inode), inode);
		}
	} else if(type == 6){
		return _restore(inode.set(node.name,node.inode), inode);
	}
	return inode;
}

export function stringify(inode){
	return inode.toString();
}
<commit_msg>reverted pvnode<commit_after>import * as ohamt from "ohamt";

import * as rrb from "rrb-vector";

import { ensureRoot, q } from './construct';

import { VNodeIterator } from './access';

import { prettyXML } from "./pretty";

import { forEach, into } from "./transducers";

export function Value(type, name, value) {
	this._type = type;
	this._name = name;
	this._value = value;
}

Value.prototype.__is_Value = true;

Value.prototype.get = function(){
	return this._value;
};

Value.prototype[Symbol.iterator] = function*(){
	yield this;
};

Value.prototype.values = function(){
	return this[Symbol.iterator]();
};

Value.prototype.count = function(){
	return 0;
};

Value.prototype.size = 0;

Value.prototype.toString = function(root = true, json = false) {
	var str = this._value + "";
	if(this._type == 3 && json) return '"'+str+'"';
	return str;
};

export function ivalue(type, name, value){
	return new Value(type, name, value);
}

// TODO create iterator that yields a node seq
// position() should overwrite get(), but the check should be name or indexInParent
VNode.prototype[Symbol.iterator] = function(){
	return new VNodeIterator(this.values(),this, vnode);
};

VNode.prototype.get = function(idx){
	var val = this._get(idx);
	if(!val) return [];
	val = val.constructor == Array ? val : [val];
	return new VNodeIterator(val[Symbol.iterator](), this, vnode);
};

export function VNode(inode,type,name,value,parent,depth,indexInParent){
	this.inode = inode;
	this.type = type;
	this.name = name;
	this.value = value;
	this.parent = parent;
	this.depth = depth | 0;
	this.indexInParent = indexInParent;
}

VNode.prototype.__is_VNode = true;

VNode.prototype.toString = function(){
	var root = ensureRoot(this);
	return root.inode.toString();
};

VNode.prototype._get = function(idx){
	return this.inode.get(idx);
};

VNode.prototype.count = function(){
	if(typeof this.inode == "function") return 0;
	return this.inode.count();
};

VNode.prototype.keys = function(){
	return this.inode.keys();
};

VNode.prototype.values = function(){
	return this.inode.values();
};

VNode.prototype.first = function(){
	return this.inode.first();
};

VNode.prototype.last = function(){
	return this.inode.last();
};

VNode.prototype.next = function(node){
	var inode = node.inode;
	return this.inode.next(inode._name,inode);
};

VNode.prototype.push = function(child){
	var type = this.type, name = child.name, val = child.inode;
	this.inode = restoreNode(this.inode.push([name,val]), this.inode);
	return this;
};

VNode.prototype.set = function(key,val){
	this.inode = restoreNode(this.inode.set(key,val), this.inode);
	return this;
};

VNode.prototype.removeChild = function(child){
	var type = this.type, key = child.name, val = child.inode;
	if(type == 1 || type == 9){
		this.inode = restoreNode(this.inode.removeValue(key, val), this.inode);
	} else if(type == 5 || type == 6){
		this.inode = restoreNode(this.inode.remove(key), this.inode);
	}
	return this;
};

VNode.prototype.modify = function(node,ref) {
	var pinode = this.inode;
	var type = this.type;
	if(type == 1 || type == 9){
		if (ref !== undefined) {
			this.inode = restoreNode(pinode.insertBefore([ref.name,ref.inode],[node.name,node.inode]), pinode);
		} else {
			// FIXME check the parent type
			this.inode = restoreNode(pinode.push([node.name,node.inode]), pinode);
		}
	} else if(type == 5){
		if (ref !== undefined) {
			this.inode = restoreNode(pinode.insertBefore(ref,node.inode), pinode);
		} else {
			this.inode = restoreNode(pinode.push(node.inode), pinode);
		}
	} else if(type == 6){
		this.inode = restoreNode(pinode.set(node.name,node.inode), pinode);
	}
	return this;
};

VNode.prototype.finalize = function(){
	this.inode.$attrs = this.inode.$attrs.endMutation();
	this.inode = this.inode.endMutation();
	return this;
};

VNode.prototype.setAttribute = function(key,value,ref){
	// ignore ref for now
	this.inode.$attrs = this.inode.$attrs.set(key,value);
	return this;
};

export function vnode(inode, parent, depth, indexInParent){
	return new VNode(inode, inode._type, inode._ns ? q(inode._ns.uri, inode._name) : inode._name, inode._value, parent, depth, indexInParent);
}

// hitch this on VNode for reuse
VNode.prototype.vnode = vnode;

VNode.prototype.ivalue = ivalue;

export function emptyINode(type, name, attrs, ns) {
    var inode = type == 5 ? rrb.empty.beginMutation() : ohamt.make().beginMutation();
    inode._type = type;
    inode._name = name;
    inode.$attrs = attrs;
	inode._ns = ns;
    return inode;
}

export function restoreNode(next,node){
	next._type = node._type;
	next._name = node._name;
	next.$attrs = node.$attrs;
	next._ns = node._ns;
	return next;
}

export function emptyAttrMap(init){
	var attrs = ohamt.empty.beginMutation();
	if(init) for(var k in init) attrs = attrs.set(k,init[k]);
	return attrs;
}

export function push(inode,val){
	var type = inode._type;
	if(type == 1 || type == 9) {
		return inode.push(val);
	} else if(type == 5) {
		return inode.push(val[1]);
	} else  if(type == 6) {
		return inode.set(val[0],val[1]);
	}
	return inode;
}

export function finalize(inode){
	if(inode.$attrs) inode.$attrs = inode.$attrs.endMutation();
	return inode.endMutation();
}

export function setAttribute(inode,key,val){
	if(inode.$attrs) inode.$attrs = inode.$attrs.set(key,val);
	return inode;
}

export function count(inode){
	return inode.count();
}

export function first(inode){
	return inode.first();
}

export function attrEntries(inode){
	return inode.$attrs.entries();
}

function elemToString(e){
	const attrFunc = (z,v,k) => {
		return z += " "+k+"=\""+v+"\"";
	};
	let str = "<"+e._name;
	let ns = e._ns;
	if(ns) str += " xmlns" + (ns.prefix ? ":" + ns.prefix : "") + "=\"" + ns.uri + "\"";
	str = e.$attrs.reduce(attrFunc,str);
	if(e.size > 0){
		str += ">";
		for(let c of e.values()){
			str += c.toString(false);
		}
		str += "</"+e._name+">";
	} else {
		str += "/>";
	}
	return str;
}

var OrderedMap = ohamt.empty.constructor;

OrderedMap.prototype.__is_Map = true;

OrderedMap.prototype.toString = function(root = true, json = false){
	var str = "";
	var type = this._type;
	const docAttrFunc = (z,v,k) =>
		z += k=="DOCTYPE" ? "<!"+k+" "+v+">" : "<?"+k+" "+v+"?>";
	const objFunc = (kv) => "\""+kv[0]+"\":"+kv[1].toString(false,true);
	if(type==1) {
		str += elemToString(this);
	} else if(type==3 || type == 12){
		str += this.toString();
	} else  if(type == 6){
		str += "{";
		str += into(this,forEach(objFunc),[]).join(",");
		str += "}";
	} else if(type==9){
		str = this.$attrs.reduce(docAttrFunc,str);
		for(let c of this.values()){
			str += c.toString(false);
		}
	}
	return root ? prettyXML(str) : str;
};

var List = rrb.empty.constructor;

List.prototype.__is_List = true;

List.prototype.toString = function(root = true, json = false){
	var str = "[";
	for(var i=0,l = this.size; i < l; ){
		str += this.get(i).toString(false,true);
		i++;
		if(i<l) str += ",";
	}
	return str + "]";
};

List.prototype.values = function(){
	return this[Symbol.iterator]();
};
<|endoftext|>