<commit_before>AUI.add('tree-data', function(A) {

var L = A.Lang,
	isArray = L.isArray,
	isObject = L.isObject,
	isString = L.isString,
	isUndefined = L.isUndefined,

	AFTER = 'after',
	APPEND = 'append',
	BEFORE = 'before',
	BOUNDING_BOX = 'boundingBox',
	CHILDREN = 'children',
	CONTAINER = 'container',
	DOT = '.',
	ID = 'id',
	INDEX = 'index',
	NEXT_SIBLING = 'nextSibling',
	NODE = 'node',
	OWNER_TREE = 'ownerTree',
	PARENT_NODE = 'parentNode',
	PREV_SIBLING = 'prevSibling',
	PREVIOUS_SIBLING = 'previousSibling',
	TREE = 'tree',
	TREE_DATA = 'tree-data',

	nodeSetter = function(v) {
		return A.get(v);
	},

	isTreeNode = function(v) {
		return ( v instanceof A.TreeNode );
	},

	getCN = A.ClassNameManager.getClassName,

	CSS_TREE_NODE = getCN(TREE, NODE);

/*
* AUI TreeData
*
* Contains the logic to handle the data of the tree.
* Basic DOM methods (append/remove/insert) and
* indexing management for the children.
*/
function TreeData(config) {
	TreeData.superclass.constructor.apply(this, arguments);
}

A.mix(TreeData, {
	NAME: TREE_DATA,

	ATTRS: {
		container: {
			setter: nodeSetter
		},

		// childNodes
		children: {
			value: [],
			validador: isArray,
			setter: function(v) {
				return this._setChildren(v);
			}
		},

		index: {
			value: {}
		}
	}
});

A.extend(TreeData, A.Component, {
	/*
	* Lifecycle
	*/
	initializer: function() {
		var instance = this;

		// binding on initializer, needed before .render() phase
		instance.publish('move');
		instance.publish('collapseAll', { defaultFn: instance._collapseAll });
		instance.publish('expandAll', { defaultFn: instance._expandAll });
		instance.publish('append', { defaultFn: instance._appendChild });
		instance.publish('remove', { defaultFn: instance._removeChild });

		TreeData.superclass.initializer.apply(this, arguments);
	},

	/*
	* Index methods
	*/
	getNodeById: function(uid) {
		var instance = this;

		return instance.get(INDEX)[uid];
	},

	isRegistered: function(node) {
		var instance = this;

		return !!(instance.get(INDEX)[ node.get(ID) ]);
	},

	updateReferences: function(node, parentNode, ownerTree) {
		var instance = this;
		var oldParent = node.get(PARENT_NODE);
		var oldOwnerTree = node.get(OWNER_TREE);
		var moved = oldParent && (oldParent != parentNode);

		if (oldParent) {

			if (moved) {
				// when moved update the oldParent children
				var children = oldParent.get(CHILDREN);

				A.Array.removeItem(children, instance);

				oldParent.set(CHILDREN, children);
			}

			oldParent.unregisterNode(node);
		}

		if (oldOwnerTree) {
			oldOwnerTree.unregisterNode(node);
		}

		// update parent reference when registered
		node.set(PARENT_NODE, parentNode);

		// update the ownerTree of the node
		node.set(OWNER_TREE, ownerTree);

		if (parentNode) {
			// register the new node on the parentNode index
			parentNode.registerNode(node);
		}

		if (ownerTree) {
			// register the new node to the ownerTree index
			ownerTree.registerNode(node);
		}

		if (oldOwnerTree != ownerTree) {
			// when change the OWNER_TREE update the children references also
			node.eachChildren(function(child) {
				instance.updateReferences(child, child.get(PARENT_NODE), ownerTree);
			});
		}

		// trigger move event
		if (moved) {
			var output = instance.getEventOutputMap(node);

			output.tree.oldParent = oldParent;
			output.tree.oldOwnerTree = oldOwnerTree;

			instance.bubbleEvent('move', output);
		}
	},

	refreshIndex: function() {
		var instance = this;

		// reset index
		instance.updateIndex({});

		// get all descendent children - deep
		instance.eachChildren(function(node) {
			instance.registerNode(node);
		}, true);
	},

	registerNode: function(node) {
		var instance = this;
		var uid = node.get(ID);
		var index = instance.get(INDEX);

		if (uid) {
			index[uid] = node;
		}

		instance.updateIndex(index);
	},

	updateIndex: function(index) {
		var instance = this;

		if (index) {
			instance.set(INDEX, index);
		}
	},

	unregisterNode: function(node) {
		var instance = this;
		var index = instance.get(INDEX);

		delete index[ node.get(ID) ];

		instance.updateIndex(index);
	},

	/*
	* Methods
	*/
	collapseAll: function() {
		var instance = this;
		var output = instance.getEventOutputMap(instance);

		instance.fire('collapseAll', output);
	},

	_collapseAll: function(event) {
		var instance = this;

		instance.eachChildren(function(node) {
			node.collapse();
		}, true);
	},

	expandAll: function() {
		var instance = this;
		var output = instance.getEventOutputMap(instance);

		instance.fire('expandAll', output);
	},

	_expandAll: function(event) {
		var instance = this;

		instance.eachChildren(function(node) {
			node.expand();
		}, true);
	},

	selectAll: function() {
		var instance = this;

		instance.eachChildren(function(child) {
			child.select();
		}, true);
	},

	unselectAll: function() {
		var instance = this;

		instance.eachChildren(function(child) {
			child.unselect();
		}, true);
	},

	eachChildren: function(fn, deep) {
		var instance = this;
		var children = instance.getChildren(deep);

		A.Array.each(children, function(node) {
			if (node) {
				fn.apply(instance, arguments);
			}
		});
	},

	eachParent: function(fn) {
		var instance = this;
		var parentNode = instance.get(PARENT_NODE);

		while (parentNode) {
			if (parentNode) {
				fn.apply(instance, [parentNode]);
			}
			parentNode = parentNode.get(PARENT_NODE);
		}
	},

	bubbleEvent: function(eventType, args, cancelBubbling, stopActionPropagation) {
		var instance = this;

		// event.stopActionPropagation == undefined, invoke the event native action
		instance.fire(eventType, args);

		if (!cancelBubbling) {
			var parentNode = instance.get(PARENT_NODE);

			// Avoid execution of the native action (private methods) while propagate
			// for example: private _appendChild() is invoked only on the first level of the bubbling
			// the intention is only invoke the user callback on parent nodes.
			args = args || {};

			if (isUndefined(stopActionPropagation)) {
				stopActionPropagation = true;
			}

			args.stopActionPropagation = stopActionPropagation;

			while(parentNode) {
				parentNode.fire(eventType, args);
				parentNode = parentNode.get(PARENT_NODE)
			}
		}
	},

	createNode: function(options) {
		var instance = this;
		var classType = options.type;

		if (isString(classType) && A.TreeNode.nodeTypes) {
			classType = A.TreeNode.nodeTypes[classType];
		}

		if (!classType) {
			classType = A.TreeNode;
		}

		return new classType(options);
	},

	appendChild: function(node, cancelBubbling) {
		var instance = this;
		var output = instance.getEventOutputMap(node);

		instance.bubbleEvent('append', output, cancelBubbling);
	},

	_appendChild: function(event) {
		// stopActionPropagation while bubbling
		if (event.stopActionPropagation) {
			return false;
		}

		var instance = this;
		var node = event.tree.node;
		var ownerTree = instance.get(OWNER_TREE);
		var children = instance.get(CHILDREN);

		// updateReferences first
		instance.updateReferences(node, instance, ownerTree);
		// and then set the children, to have the appendChild propagation
		// the PARENT_NODE references should be updated
		var length = children.push(node);
		instance.set(CHILDREN, children);

		// updating prev/nextSibling attributes
		var prevIndex = length - 2;
		var prevSibling = instance.item(prevIndex);

		node.set(NEXT_SIBLING, null);
		node.set(PREV_SIBLING, prevSibling);

		instance.get(CONTAINER).append(
			node.get(BOUNDING_BOX)
		);

		// render node after it's appended
		node.render();
	},

	item: function(index) {
		var instance = this;

		return instance.get(CHILDREN)[index];
	},

	indexOf: function(node) {
		var instance = this;

		return A.Array.indexOf( instance.get(CHILDREN), node );
	},

	hasChildNodes: function() {
		return ( this.get(CHILDREN).length > 0 );
	},

	getChildren: function(deep) {
		var instance = this;
		var cNodes = [];
		var children = instance.get(CHILDREN);

		cNodes = cNodes.concat(children);

		if (deep) {
			instance.eachChildren(function(child) {
				cNodes = cNodes.concat( child.getChildren(deep) );
			});
		}

		return cNodes;
	},

	getEventOutputMap: function(node) {
		var instance = this;

		return {
			tree: {
				instance: instance,
				node: node || instance
			}
		};
	},

	removeChild: function(node) {
		var instance = this;
		var output = instance.getEventOutputMap(node);

		instance.bubbleEvent('remove', output);
	},

	_removeChild: function(event) {
		// stopActionPropagation while bubbling
		if (event.stopActionPropagation) {
			return false;
		}

		var instance = this;
		var node = event.tree.node;
		var ownerTree = instance.get(OWNER_TREE);

		if (instance.isRegistered(node)) {
			// update parent reference when removed
			node.set(PARENT_NODE, null);

			// unregister the node
			instance.unregisterNode(node);

			// no parent, no ownerTree
			node.set(OWNER_TREE, null);

			if (ownerTree) {
				// unregister the removed node from the tree index
				ownerTree.unregisterNode(node);
			}

			// remove child from the container
			node.get(BOUNDING_BOX).remove();

			var children = instance.get(CHILDREN);

			A.Array.removeItem(children, node);
			instance.set(CHILDREN, children);
		}
	},

	empty: function() {
		var instance = this;

		instance.eachChildren(function(node) {
			var parentNode = node.get(PARENT_NODE);

			if (parentNode) {
				parentNode.removeChild(node);
			}
		});
	},

	insert: function(treeNode, refTreeNode, where) {
		var instance = this;
		refTreeNode = refTreeNode || this;

		if (refTreeNode == treeNode) {
			return false; // NOTE: return
		}
		var refParentTreeNode = refTreeNode.get(PARENT_NODE);

		if (treeNode && refParentTreeNode) {
			var nodeBoundinBox = treeNode.get(BOUNDING_BOX);
			var refBoundinBox = refTreeNode.get(BOUNDING_BOX);
			var ownerTree = refTreeNode.get(OWNER_TREE);

			if (where == 'before') {
				refBoundinBox.placeBefore(nodeBoundinBox);
			}
			else if (where == 'after') {
				refBoundinBox.placeAfter(nodeBoundinBox);
			}

			var refSiblings = [];
			// using the YUI selector to regenerate the index based on the real dom
			// this avoid misscalculations on the nodes index number
			var DOMChildren = refParentTreeNode.get(BOUNDING_BOX).all('> ul > li');

			DOMChildren.each(function(child) {
				refSiblings.push( A.Widget.getByNode(child) );
			});

			// updating prev/nextSibling attributes
			treeNode.set(
				NEXT_SIBLING,
				A.Widget.getByNode( nodeBoundinBox.get(NEXT_SIBLING) )
			);
			treeNode.set(
				PREV_SIBLING,
				A.Widget.getByNode( nodeBoundinBox.get(PREVIOUS_SIBLING) )
			);

			// update all references
			refTreeNode.updateReferences(treeNode, refParentTreeNode, ownerTree);

			// updating refParentTreeNode childTreeNodes
			refParentTreeNode.set(CHILDREN, refSiblings);
		}

		// render treeNode after it's inserted
		treeNode.render();

		// invoking insert event
		var output = refTreeNode.getEventOutputMap(treeNode);

		output.tree.refTreeNode = refTreeNode;

		refTreeNode.bubbleEvent('insert', output);
	},

	insertAfter: function(treeNode, refTreeNode) {
		refTreeNode.insert(treeNode, refTreeNode, 'after');
	},

	insertBefore: function(treeNode, refTreeNode) {
		refTreeNode.insert(treeNode, refTreeNode, 'before');
	},

	getNodeByChild: function(child) {
		var instance = this;
		var treeNodeEl = child.ancestor(DOT+CSS_TREE_NODE);

		return instance.getNodeById( treeNodeEl.attr(ID) );
	},

	/*
	* Setters
	*/
	_setChildren: function(v) {
		var instance = this;
		var childNodes = [];

		A.Array.each(v, function(node) {
			if (node) {
				if (!isTreeNode(node) && isObject(node)) {
					// creating node from json
					node = instance.createNode(node);
				}

				// before render the node, make sure the PARENT_NODE references are updated
				// this is required on the render phase of the TreeNode (_createNodeContainer)
				// to propagate the appendChild callback
				node.render();

				// avoid duplicated children on the childNodes list
				if (A.Array.indexOf(childNodes, node) == -1) {
					childNodes.push(node);
				}
			}
		});

		return childNodes;
	}
});

A.TreeData = TreeData;

}, '@VERSION', { requires: [ 'aui-base' ] });<commit_msg>TreeData extends from A.Widget instead of A.Component (We need to fix this later to make it extend from A.Component)<commit_after>AUI.add('tree-data', function(A) {

var L = A.Lang,
	isArray = L.isArray,
	isObject = L.isObject,
	isString = L.isString,
	isUndefined = L.isUndefined,

	AFTER = 'after',
	APPEND = 'append',
	BEFORE = 'before',
	BOUNDING_BOX = 'boundingBox',
	CHILDREN = 'children',
	CONTAINER = 'container',
	DOT = '.',
	ID = 'id',
	INDEX = 'index',
	NEXT_SIBLING = 'nextSibling',
	NODE = 'node',
	OWNER_TREE = 'ownerTree',
	PARENT_NODE = 'parentNode',
	PREV_SIBLING = 'prevSibling',
	PREVIOUS_SIBLING = 'previousSibling',
	TREE = 'tree',
	TREE_DATA = 'tree-data',

	nodeSetter = function(v) {
		return A.get(v);
	},

	isTreeNode = function(v) {
		return ( v instanceof A.TreeNode );
	},

	getCN = A.ClassNameManager.getClassName,

	CSS_TREE_NODE = getCN(TREE, NODE);

/*
* AUI TreeData
*
* Contains the logic to handle the data of the tree.
* Basic DOM methods (append/remove/insert) and
* indexing management for the children.
*/
function TreeData(config) {
	TreeData.superclass.constructor.apply(this, arguments);
}

A.mix(TreeData, {
	NAME: TREE_DATA,

	ATTRS: {
		container: {
			setter: nodeSetter
		},

		// childNodes
		children: {
			value: [],
			validador: isArray,
			setter: function(v) {
				return this._setChildren(v);
			}
		},

		index: {
			value: {}
		}
	}
});

A.extend(TreeData, A.Widget, {
	/*
	* Lifecycle
	*/
	initializer: function() {
		var instance = this;

		// binding on initializer, needed before .render() phase
		instance.publish('move');
		instance.publish('collapseAll', { defaultFn: instance._collapseAll });
		instance.publish('expandAll', { defaultFn: instance._expandAll });
		instance.publish('append', { defaultFn: instance._appendChild });
		instance.publish('remove', { defaultFn: instance._removeChild });

		TreeData.superclass.initializer.apply(this, arguments);
	},

	/*
	* Index methods
	*/
	getNodeById: function(uid) {
		var instance = this;

		return instance.get(INDEX)[uid];
	},

	isRegistered: function(node) {
		var instance = this;

		return !!(instance.get(INDEX)[ node.get(ID) ]);
	},

	updateReferences: function(node, parentNode, ownerTree) {
		var instance = this;
		var oldParent = node.get(PARENT_NODE);
		var oldOwnerTree = node.get(OWNER_TREE);
		var moved = oldParent && (oldParent != parentNode);

		if (oldParent) {

			if (moved) {
				// when moved update the oldParent children
				var children = oldParent.get(CHILDREN);

				A.Array.removeItem(children, instance);

				oldParent.set(CHILDREN, children);
			}

			oldParent.unregisterNode(node);
		}

		if (oldOwnerTree) {
			oldOwnerTree.unregisterNode(node);
		}

		// update parent reference when registered
		node.set(PARENT_NODE, parentNode);

		// update the ownerTree of the node
		node.set(OWNER_TREE, ownerTree);

		if (parentNode) {
			// register the new node on the parentNode index
			parentNode.registerNode(node);
		}

		if (ownerTree) {
			// register the new node to the ownerTree index
			ownerTree.registerNode(node);
		}

		if (oldOwnerTree != ownerTree) {
			// when change the OWNER_TREE update the children references also
			node.eachChildren(function(child) {
				instance.updateReferences(child, child.get(PARENT_NODE), ownerTree);
			});
		}

		// trigger move event
		if (moved) {
			var output = instance.getEventOutputMap(node);

			output.tree.oldParent = oldParent;
			output.tree.oldOwnerTree = oldOwnerTree;

			instance.bubbleEvent('move', output);
		}
	},

	refreshIndex: function() {
		var instance = this;

		// reset index
		instance.updateIndex({});

		// get all descendent children - deep
		instance.eachChildren(function(node) {
			instance.registerNode(node);
		}, true);
	},

	registerNode: function(node) {
		var instance = this;
		var uid = node.get(ID);
		var index = instance.get(INDEX);

		if (uid) {
			index[uid] = node;
		}

		instance.updateIndex(index);
	},

	updateIndex: function(index) {
		var instance = this;

		if (index) {
			instance.set(INDEX, index);
		}
	},

	unregisterNode: function(node) {
		var instance = this;
		var index = instance.get(INDEX);

		delete index[ node.get(ID) ];

		instance.updateIndex(index);
	},

	/*
	* Methods
	*/
	collapseAll: function() {
		var instance = this;
		var output = instance.getEventOutputMap(instance);

		instance.fire('collapseAll', output);
	},

	_collapseAll: function(event) {
		var instance = this;

		instance.eachChildren(function(node) {
			node.collapse();
		}, true);
	},

	expandAll: function() {
		var instance = this;
		var output = instance.getEventOutputMap(instance);

		instance.fire('expandAll', output);
	},

	_expandAll: function(event) {
		var instance = this;

		instance.eachChildren(function(node) {
			node.expand();
		}, true);
	},

	selectAll: function() {
		var instance = this;

		instance.eachChildren(function(child) {
			child.select();
		}, true);
	},

	unselectAll: function() {
		var instance = this;

		instance.eachChildren(function(child) {
			child.unselect();
		}, true);
	},

	eachChildren: function(fn, deep) {
		var instance = this;
		var children = instance.getChildren(deep);

		A.Array.each(children, function(node) {
			if (node) {
				fn.apply(instance, arguments);
			}
		});
	},

	eachParent: function(fn) {
		var instance = this;
		var parentNode = instance.get(PARENT_NODE);

		while (parentNode) {
			if (parentNode) {
				fn.apply(instance, [parentNode]);
			}
			parentNode = parentNode.get(PARENT_NODE);
		}
	},

	bubbleEvent: function(eventType, args, cancelBubbling, stopActionPropagation) {
		var instance = this;

		// event.stopActionPropagation == undefined, invoke the event native action
		instance.fire(eventType, args);

		if (!cancelBubbling) {
			var parentNode = instance.get(PARENT_NODE);

			// Avoid execution of the native action (private methods) while propagate
			// for example: private _appendChild() is invoked only on the first level of the bubbling
			// the intention is only invoke the user callback on parent nodes.
			args = args || {};

			if (isUndefined(stopActionPropagation)) {
				stopActionPropagation = true;
			}

			args.stopActionPropagation = stopActionPropagation;

			while(parentNode) {
				parentNode.fire(eventType, args);
				parentNode = parentNode.get(PARENT_NODE)
			}
		}
	},

	createNode: function(options) {
		var instance = this;
		var classType = options.type;

		if (isString(classType) && A.TreeNode.nodeTypes) {
			classType = A.TreeNode.nodeTypes[classType];
		}

		if (!classType) {
			classType = A.TreeNode;
		}

		return new classType(options);
	},

	appendChild: function(node, cancelBubbling) {
		var instance = this;
		var output = instance.getEventOutputMap(node);

		instance.bubbleEvent('append', output, cancelBubbling);
	},

	_appendChild: function(event) {
		// stopActionPropagation while bubbling
		if (event.stopActionPropagation) {
			return false;
		}

		var instance = this;
		var node = event.tree.node;
		var ownerTree = instance.get(OWNER_TREE);
		var children = instance.get(CHILDREN);

		// updateReferences first
		instance.updateReferences(node, instance, ownerTree);
		// and then set the children, to have the appendChild propagation
		// the PARENT_NODE references should be updated
		var length = children.push(node);
		instance.set(CHILDREN, children);

		// updating prev/nextSibling attributes
		var prevIndex = length - 2;
		var prevSibling = instance.item(prevIndex);

		node.set(NEXT_SIBLING, null);
		node.set(PREV_SIBLING, prevSibling);

		instance.get(CONTAINER).append(
			node.get(BOUNDING_BOX)
		);

		// render node after it's appended
		node.render();
	},

	item: function(index) {
		var instance = this;

		return instance.get(CHILDREN)[index];
	},

	indexOf: function(node) {
		var instance = this;

		return A.Array.indexOf( instance.get(CHILDREN), node );
	},

	hasChildNodes: function() {
		return ( this.get(CHILDREN).length > 0 );
	},

	getChildren: function(deep) {
		var instance = this;
		var cNodes = [];
		var children = instance.get(CHILDREN);

		cNodes = cNodes.concat(children);

		if (deep) {
			instance.eachChildren(function(child) {
				cNodes = cNodes.concat( child.getChildren(deep) );
			});
		}

		return cNodes;
	},

	getEventOutputMap: function(node) {
		var instance = this;

		return {
			tree: {
				instance: instance,
				node: node || instance
			}
		};
	},

	removeChild: function(node) {
		var instance = this;
		var output = instance.getEventOutputMap(node);

		instance.bubbleEvent('remove', output);
	},

	_removeChild: function(event) {
		// stopActionPropagation while bubbling
		if (event.stopActionPropagation) {
			return false;
		}

		var instance = this;
		var node = event.tree.node;
		var ownerTree = instance.get(OWNER_TREE);

		if (instance.isRegistered(node)) {
			// update parent reference when removed
			node.set(PARENT_NODE, null);

			// unregister the node
			instance.unregisterNode(node);

			// no parent, no ownerTree
			node.set(OWNER_TREE, null);

			if (ownerTree) {
				// unregister the removed node from the tree index
				ownerTree.unregisterNode(node);
			}

			// remove child from the container
			node.get(BOUNDING_BOX).remove();

			var children = instance.get(CHILDREN);

			A.Array.removeItem(children, node);
			instance.set(CHILDREN, children);
		}
	},

	empty: function() {
		var instance = this;

		instance.eachChildren(function(node) {
			var parentNode = node.get(PARENT_NODE);

			if (parentNode) {
				parentNode.removeChild(node);
			}
		});
	},

	insert: function(treeNode, refTreeNode, where) {
		var instance = this;
		refTreeNode = refTreeNode || this;

		if (refTreeNode == treeNode) {
			return false; // NOTE: return
		}
		var refParentTreeNode = refTreeNode.get(PARENT_NODE);

		if (treeNode && refParentTreeNode) {
			var nodeBoundinBox = treeNode.get(BOUNDING_BOX);
			var refBoundinBox = refTreeNode.get(BOUNDING_BOX);
			var ownerTree = refTreeNode.get(OWNER_TREE);

			if (where == 'before') {
				refBoundinBox.placeBefore(nodeBoundinBox);
			}
			else if (where == 'after') {
				refBoundinBox.placeAfter(nodeBoundinBox);
			}

			var refSiblings = [];
			// using the YUI selector to regenerate the index based on the real dom
			// this avoid misscalculations on the nodes index number
			var DOMChildren = refParentTreeNode.get(BOUNDING_BOX).all('> ul > li');

			DOMChildren.each(function(child) {
				refSiblings.push( A.Widget.getByNode(child) );
			});

			// updating prev/nextSibling attributes
			treeNode.set(
				NEXT_SIBLING,
				A.Widget.getByNode( nodeBoundinBox.get(NEXT_SIBLING) )
			);
			treeNode.set(
				PREV_SIBLING,
				A.Widget.getByNode( nodeBoundinBox.get(PREVIOUS_SIBLING) )
			);

			// update all references
			refTreeNode.updateReferences(treeNode, refParentTreeNode, ownerTree);

			// updating refParentTreeNode childTreeNodes
			refParentTreeNode.set(CHILDREN, refSiblings);
		}

		// render treeNode after it's inserted
		treeNode.render();

		// invoking insert event
		var output = refTreeNode.getEventOutputMap(treeNode);

		output.tree.refTreeNode = refTreeNode;

		refTreeNode.bubbleEvent('insert', output);
	},

	insertAfter: function(treeNode, refTreeNode) {
		refTreeNode.insert(treeNode, refTreeNode, 'after');
	},

	insertBefore: function(treeNode, refTreeNode) {
		refTreeNode.insert(treeNode, refTreeNode, 'before');
	},

	getNodeByChild: function(child) {
		var instance = this;
		var treeNodeEl = child.ancestor(DOT+CSS_TREE_NODE);

		return instance.getNodeById( treeNodeEl.attr(ID) );
	},

	/*
	* Setters
	*/
	_setChildren: function(v) {
		var instance = this;
		var childNodes = [];

		A.Array.each(v, function(node) {
			if (node) {
				if (!isTreeNode(node) && isObject(node)) {
					// creating node from json
					node = instance.createNode(node);
				}

				// before render the node, make sure the PARENT_NODE references are updated
				// this is required on the render phase of the TreeNode (_createNodeContainer)
				// to propagate the appendChild callback
				node.render();

				// avoid duplicated children on the childNodes list
				if (A.Array.indexOf(childNodes, node) == -1) {
					childNodes.push(node);
				}
			}
		});

		return childNodes;
	}
});

A.TreeData = TreeData;

}, '@VERSION', { requires: [ 'aui-base' ] });<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

define(function (require, exports) {
    "use strict";

    var Promise = require("bluebird");

    var os = require("adapter/os"),
        events = require("js/events"),
        locks = require("js/locks"),
        policy = require("js/actions/policy");

    /**
     * Add a keyboard shortcut command. Registers the handler function and sets
     * the appropriate keyboard propagation policy.
     *
     * @param {string|number} key Single character string or number representing keyCode
     * @param {{shift: boolean=, control: boolean=, alt: boolean=, command: boolean=}} modifiers
     * @param {function()} fn Nullary function triggered by the keyboard shortcut
     * @param {string=} id Named identifier of this shortcut, used for later removal
     * @param {boolean=} capture Whether the shortcut should be handled during
     *  bubble (default) or capture phase
     * @return {Promise}
     */
    var addShortcutCommand = function (key, modifiers, fn, id, capture) {
        var shortcutStore = this.flux.store("shortcut");
        if (shortcutStore.getByID(id)) {
            return Promise.resolve();
        }

        if (typeof key === "string") {
            key = key.toLowerCase();
        }

        return this.transfer(policy.addKeydownPolicy, false, key, modifiers)
            .bind(this)
            .then(function (policyID) {
                var payload = {
                    id: id,
                    capture: !!capture,
                    key: key,
                    modifiers: modifiers,
                    fn: fn,
                    policy: policyID
                };

                this.dispatch(events.shortcut.ADD_SHORTCUT, payload);

                return policyID;
            });
    };

    /**
     * Remove a keyboard shortcut command. Unregisters the handler function and unsets
     * the appropriate keyboard propagation policy.
     *
     * @param {!string} id Name of shortcut to remove
     * @return {Promise}
     */
    var removeShortcutCommand = function (id) {
        var shortcutStore = this.flux.store("shortcut"),
            shortcut = shortcutStore.getByID(id);

        if (!shortcut) {
            return Promise.resolve();
        }

        return this.transfer(policy.removeKeyboardPolicies, shortcut.policy, true)
            .bind(this)
            .then(function () {
                this.dispatch(events.shortcut.REMOVE_SHORTCUT, {
                    id: id
                });
            });
    };

    /**
     * Registers a keydown event handlers on the browser window in order to
     * dispatch shortcut commands.
     *
     * @return {Promise}
     */
    var beforeStartupCommand = function () {
        var shortcutStore = this.flux.store("shortcut");

        var _getKeyDownHandlerForPhase = function (capture) {
            return function (event) {
                // If an HTML element is focused, only attempt to match the shortcut
                // if there are modifiers other than shift.
                if (event.target !== document.body &&
                    (event.detail.modifierBits === os.eventModifiers.NONE ||
                        event.detail.modifierBits === os.eventModifiers.SHIFT)) {
                    return;
                }

                var handlers = shortcutStore.matchShortcuts(event.detail, capture);
                handlers.forEach(function (handler) {
                    handler(event);
                });
            };
        };

        window.addEventListener("adapterKeydown", _getKeyDownHandlerForPhase(true), true);
        window.addEventListener("adapterKeydown", _getKeyDownHandlerForPhase(false), false);

        os.on(os.notifierKind.KEYBOARDFOCUS_CHANGED, function (event) {
            // Our keyboard shortcuts ONLY work when there is no active HTML
            // element. So we have to be careful to ensure that HTML elements
            // are only active while they're in active use. This blurs the active
            // element whenever the CEF application loses focus so that shortcuts
            // still work even when that happens.
            if (event.isActive === false) {
                document.activeElement.blur();
            }
        });

        return Promise.resolve();
    };

    var addShortcut = {
        command: addShortcutCommand,
        reads: [],
        writes: [locks.PS_APP, locks.JS_SHORTCUT, locks.JS_POLICY]
    };

    var removeShortcut = {
        command: removeShortcutCommand,
        reads: [],
        writes: [locks.PS_APP, locks.JS_SHORTCUT]
    };

    var beforeStartup = {
        command: beforeStartupCommand,
        reads: [locks.JS_SHORTCUT],
        writes: []
    };

    exports.addShortcut = addShortcut;
    exports.removeShortcut = removeShortcut;
    exports.beforeStartup = beforeStartup;
});
<commit_msg>Add JS_POLICY lock to removeShortcut<commit_after>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

define(function (require, exports) {
    "use strict";

    var Promise = require("bluebird");

    var os = require("adapter/os"),
        events = require("js/events"),
        locks = require("js/locks"),
        policy = require("js/actions/policy");

    /**
     * Add a keyboard shortcut command. Registers the handler function and sets
     * the appropriate keyboard propagation policy.
     *
     * @param {string|number} key Single character string or number representing keyCode
     * @param {{shift: boolean=, control: boolean=, alt: boolean=, command: boolean=}} modifiers
     * @param {function()} fn Nullary function triggered by the keyboard shortcut
     * @param {string=} id Named identifier of this shortcut, used for later removal
     * @param {boolean=} capture Whether the shortcut should be handled during
     *  bubble (default) or capture phase
     * @return {Promise}
     */
    var addShortcutCommand = function (key, modifiers, fn, id, capture) {
        var shortcutStore = this.flux.store("shortcut");
        if (shortcutStore.getByID(id)) {
            return Promise.resolve();
        }

        if (typeof key === "string") {
            key = key.toLowerCase();
        }

        return this.transfer(policy.addKeydownPolicy, false, key, modifiers)
            .bind(this)
            .then(function (policyID) {
                var payload = {
                    id: id,
                    capture: !!capture,
                    key: key,
                    modifiers: modifiers,
                    fn: fn,
                    policy: policyID
                };

                this.dispatch(events.shortcut.ADD_SHORTCUT, payload);

                return policyID;
            });
    };

    /**
     * Remove a keyboard shortcut command. Unregisters the handler function and unsets
     * the appropriate keyboard propagation policy.
     *
     * @param {!string} id Name of shortcut to remove
     * @return {Promise}
     */
    var removeShortcutCommand = function (id) {
        var shortcutStore = this.flux.store("shortcut"),
            shortcut = shortcutStore.getByID(id);

        if (!shortcut) {
            return Promise.resolve();
        }

        return this.transfer(policy.removeKeyboardPolicies, shortcut.policy, true)
            .bind(this)
            .then(function () {
                this.dispatch(events.shortcut.REMOVE_SHORTCUT, {
                    id: id
                });
            });
    };

    /**
     * Registers a keydown event handlers on the browser window in order to
     * dispatch shortcut commands.
     *
     * @return {Promise}
     */
    var beforeStartupCommand = function () {
        var shortcutStore = this.flux.store("shortcut");

        var _getKeyDownHandlerForPhase = function (capture) {
            return function (event) {
                // If an HTML element is focused, only attempt to match the shortcut
                // if there are modifiers other than shift.
                if (event.target !== document.body &&
                    (event.detail.modifierBits === os.eventModifiers.NONE ||
                        event.detail.modifierBits === os.eventModifiers.SHIFT)) {
                    return;
                }

                var handlers = shortcutStore.matchShortcuts(event.detail, capture);
                handlers.forEach(function (handler) {
                    handler(event);
                });
            };
        };

        window.addEventListener("adapterKeydown", _getKeyDownHandlerForPhase(true), true);
        window.addEventListener("adapterKeydown", _getKeyDownHandlerForPhase(false), false);

        os.on(os.notifierKind.KEYBOARDFOCUS_CHANGED, function (event) {
            // Our keyboard shortcuts ONLY work when there is no active HTML
            // element. So we have to be careful to ensure that HTML elements
            // are only active while they're in active use. This blurs the active
            // element whenever the CEF application loses focus so that shortcuts
            // still work even when that happens.
            if (event.isActive === false) {
                document.activeElement.blur();
            }
        });

        return Promise.resolve();
    };

    var addShortcut = {
        command: addShortcutCommand,
        reads: [],
        writes: [locks.PS_APP, locks.JS_SHORTCUT, locks.JS_POLICY]
    };

    var removeShortcut = {
        command: removeShortcutCommand,
        reads: [],
        writes: [locks.PS_APP, locks.JS_SHORTCUT, locks.JS_POLICY]
    };

    var beforeStartup = {
        command: beforeStartupCommand,
        reads: [locks.JS_SHORTCUT],
        writes: []
    };

    exports.addShortcut = addShortcut;
    exports.removeShortcut = removeShortcut;
    exports.beforeStartup = beforeStartup;
});
<|endoftext|>


<commit_before>'use strict';

var path = require('path'),
  generators = require('yeoman-generator'),
  helpers = generators.test,
  assert = generators.assert,
  appFiles = [
    'README.md',
    'app.js',
    '.gitignore',
    '.eslintrc',
    'csscomb.json'
  ],
  folders = [
    'gulpfile.js',
    'gulp/tasks/default.js',
    'gulp/tasks/fonts.js',
    'gulp/tasks/media.js',
    'gulp/tasks/scripts.js',
    'gulp/tasks/styles.js',
    'gulp/tasks/watch.js',
    'gulp/util/components.js',
    'gulp/util/folders.js'
  ],
  packageJsonFile = 'package.json';

/**
 * run the generator with various options
 * @param {object} options (note: could be empty obj)
 * @param {Function} done async callback
 */
function runGenerator(options, done) {
  helpers.run(path.join(__dirname, 'index.js'))
    .withArguments(['newapp'])
    .withOptions(options)
    .withPrompts({ description: 'My new clay app instance', keywords: 'keyword1,keyword2'})
    .on('end', done);
}

describe('clay app', function () {
  describe('defaults', function () {
    before(function (done) {
      runGenerator({}, done);
    });

    describe('clay app - `package.json`', function () {
      before(function () {
        assert.file(packageJsonFile);
      });

      it('adds name to package.json', function () {
        assert.JSONFileContent(packageJsonFile, {name: 'newapp'});
      });

      it('adds description to package.json', function () {
        assert.JSONFileContent(packageJsonFile, {description:'My new clay app instance'});
      });

      it('adds keywords to package.json', function () {
        assert.JSONFileContent(packageJsonFile, {keywords: 'keyword1,keyword2'});
      });

    });

    it('generates a gulpfile.js, gulp/tasks, & gulp/util folders', function () {
      assert.file(folders);
    });

    it('generates application specific files', function () {
      assert.file(appFiles);
    });

  });
});
<commit_msg>App: Tests - Added README specific test<commit_after>'use strict';

var path = require('path'),
  generators = require('yeoman-generator'),
  helpers = generators.test,
  assert = generators.assert,
  appFiles = [
    'app.js',
    '.gitignore',
    '.eslintrc',
    'csscomb.json'
  ],
  folders = [
    'gulpfile.js',
    'gulp/tasks/default.js',
    'gulp/tasks/fonts.js',
    'gulp/tasks/media.js',
    'gulp/tasks/scripts.js',
    'gulp/tasks/styles.js',
    'gulp/tasks/watch.js',
    'gulp/util/components.js',
    'gulp/util/folders.js'
  ],
  packageJsonFile = 'package.json';

/**
 * run the generator with various options
 * @param {object} options (note: could be empty obj)
 * @param {Function} done async callback
 */
function runGenerator(options, done) {
  helpers.run(path.join(__dirname, 'index.js'))
    .withArguments(['newapp'])
    .withOptions(options)
    .withPrompts({ description: 'My new clay app instance', keywords: 'keyword1,keyword2'})
    .on('end', done);
}

describe('clay app', function () {
  describe('defaults', function () {
    before(function (done) {
      runGenerator({}, done);
    });

    describe('clay app - `package.json`', function () {
      before(function () {
        assert.file(packageJsonFile);
      });

      it('adds name to package.json', function () {
        assert.JSONFileContent(packageJsonFile, {name: 'newapp'});
      });

      it('adds description to package.json', function () {
        assert.JSONFileContent(packageJsonFile, {description:'My new clay app instance'});
      });

      it('adds keywords to package.json', function () {
        assert.JSONFileContent(packageJsonFile, {keywords: 'keyword1,keyword2'});
      });

    });

    it('generates a gulpfile.js, gulp/tasks, & gulp/util folders', function () {
      assert.file(folders);
    });

    it('generates application specific files', function () {
      assert.file(appFiles);
    });

    it('adds name to README', function () {
      var file = 'README.md';

      assert.file(file);
      assert.fileContent(file, /newapp/);
    });

  });
});
<|endoftext|>


<commit_before><commit_msg>Updated algorithm for age matching<commit_after><|endoftext|>


<commit_before>"use strict";

var sparql = "#Tool: jgonsior-tree \n" +
	'SELECT ?class ?classLabel ?subclass ?subclassLabel WHERE { ?class wdt:P279* wd:Q18616576 . ?subclass wdt:P279 ?class SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }}';

var treeData = [
	{
		"name": "/",
		"parent": null,
		"children": [],
	}
];

$.getJSON('https://query.wikidata.org/sparql', {
	query: sparql
}).done(function (data) {
	$.each(data.results, function (binding, bindings) {
		$.each(bindings, function (key, value) {
			//check if parent exists already in tree

			var children = {};
			children.name = value.classLabel.value;
			children.parent = "/";
			children.children = [];
			treeData[0].children.push([children]);
		});
	});

// ************** Generate the tree diagram	 *****************
	var margin = {top: 20, right: 120, bottom: 20, left: 120},
		width = 960 - margin.right - margin.left,
		height = 500 - margin.top - margin.bottom;

	var i = 0,
		duration = 750,
		root;

	var tree = d3.layout.tree()
		.size([height, width]);

	var diagonal = d3.svg.diagonal()
		.projection(function (d) {
			return [d.y, d.x];
		});

	var svg = d3.select("body").append("svg")
		.attr("width", width + margin.right + margin.left)
		.attr("height", height + margin.top + margin.bottom)
		.append("g")
		.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

	root = treeData[0];
	root.x0 = height / 2;
	root.y0 = 0;

	update(root);

	d3.select(self.frameElement).style("height", "500px");

	function update(source) {

		// Compute the new tree layout.
		var nodes = tree.nodes(root).reverse(),
			links = tree.links(nodes);

		// Normalize for fixed-depth.
		nodes.forEach(function (d) {
			d.y = d.depth * 180;
		});

		// Update the nodes…
		var node = svg.selectAll("g.node")
			.data(nodes, function (d) {
				return d.id || (d.id = ++i);
			});

		// Enter any new nodes at the parent's previous position.
		var nodeEnter = node.enter().append("g")
			.attr("class", "node")
			.attr("transform", function (d) {
				return "translate(" + source.y0 + "," + source.x0 + ")";
			})
			.on("click", click);

		nodeEnter.append("circle")
			.attr("r", 1e-6)
			.style("fill", function (d) {
				return d._children ? "lightsteelblue" : "#fff";
			});

		nodeEnter.append("text")
			.attr("x", function (d) {
				return d.children || d._children ? -13 : 13;
			})
			.attr("dy", ".35em")
			.attr("text-anchor", function (d) {
				return d.children || d._children ? "end" : "start";
			})
			.text(function (d) {
				return d.name;
			})
			.style("fill-opacity", 1e-6);

		// Transition nodes to their new position.
		var nodeUpdate = node.transition()
			.duration(duration)
			.attr("transform", function (d) {
				return "translate(" + d.y + "," + d.x + ")";
			});

		nodeUpdate.select("circle")
			.attr("r", 10)
			.style("fill", function (d) {
				return d._children ? "lightsteelblue" : "#fff";
			});

		nodeUpdate.select("text")
			.style("fill-opacity", 1);

		// Transition exiting nodes to the parent's new position.
		var nodeExit = node.exit().transition()
			.duration(duration)
			.attr("transform", function (d) {
				return "translate(" + source.y + "," + source.x + ")";
			})
			.remove();

		nodeExit.select("circle")
			.attr("r", 1e-6);

		nodeExit.select("text")
			.style("fill-opacity", 1e-6);

		// Update the links…
		var link = svg.selectAll("path.link")
			.data(links, function (d) {
				return d.target.id;
			});

		// Enter any new links at the parent's previous position.
		link.enter().insert("path", "g")
			.attr("class", "link")
			.attr("d", function (d) {
				var o = {x: source.x0, y: source.y0};
				return diagonal({source: o, target: o});
			});

		// Transition links to their new position.
		link.transition()
			.duration(duration)
			.attr("d", diagonal);

		// Transition exiting nodes to the parent's new position.
		link.exit().transition()
			.duration(duration)
			.attr("d", function (d) {
				var o = {x: source.x, y: source.y};
				return diagonal({source: o, target: o});
			})
			.remove();

		// Stash the old positions for transition.
		nodes.forEach(function (d) {
			d.x0 = d.x;
			d.y0 = d.y;
		});
	}

// Toggle children on click.
	function click(d) {
		if (d.children) {
			d._children = d.children;
			d.children = null;
		} else {
			d.children = d._children;
			d._children = null;
		}
		update(d);
	}
});

<commit_msg>Implemented a search in array function for javascript -> this languag is SO broken!!<commit_after>"use strict";

var sparql = "#Tool: jgonsior-tree \n" +
	'SELECT ?class ?classLabel ?subclass ?subclassLabel WHERE { ?class wdt:P279* wd:Q18616576 . ?subclass wdt:P279 ?class SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }}';

var treeData = [
	{
		"name": "/",
		"parent": null,
		"children": [],
	}
];

function inArray(element, array) {
	var ret = -1;
	$.each(array, function (key, value) {
		if (value.qid === element.qid) {
			return (ret = key);
		}
	});
	return ret;
}

function insertToTree(tree, node) {
	//check if parent exists already in tree
	if (inArray(node, tree.children) === -1) {
		tree.children.push(node);
	}
}

$.getJSON('https://query.wikidata.org/sparql', {
	query: sparql
}).done(function (data) {
	$.each(data.results, function (binding, bindings) {
		$.each(bindings, function (key, value) {
			var element = {};
			element.name = value.classLabel.value;
			element.parent = "/";
			element.children = [];
			element.qid = value.class.value;
			insertToTree(treeData[0], element);
		});
	});

	console.log(treeData);

// ************** Generate the tree diagram	 *****************
	var margin = {top: 20, right: 120, bottom: 20, left: 120},
		width = 960 - margin.right - margin.left,
		height = 1000 - margin.top - margin.bottom;

	var i = 0,
		duration = 750,
		root;

	var tree = d3.layout.tree()
		.size([height, width]);

	var diagonal = d3.svg.diagonal()
		.projection(function (d) {
			return [d.y, d.x];
		});

	var svg = d3.select("body").append("svg")
		.attr("width", width + margin.right + margin.left)
		.attr("height", height + margin.top + margin.bottom)
		.append("g")
		.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

	root = treeData[0];
	root.x0 = height / 2;
	root.y0 = 0;

	update(root);

	d3.select(self.frameElement).style("height", "500px");

	function update(source) {

		// Compute the new tree layout.
		var nodes = tree.nodes(root).reverse(),
			links = tree.links(nodes);

		// Normalize for fixed-depth.
		nodes.forEach(function (d) {
			d.y = d.depth * 180;
		});

		// Update the nodes…
		var node = svg.selectAll("g.node")
			.data(nodes, function (d) {
				return d.id || (d.id = ++i);
			});

		// Enter any new nodes at the parent's previous position.
		var nodeEnter = node.enter().append("g")
			.attr("class", "node")
			.attr("transform", function (d) {
				return "translate(" + source.y0 + "," + source.x0 + ")";
			})
			.on("click", click);

		nodeEnter.append("circle")
			.attr("r", 1e-6)
			.style("fill", function (d) {
				return d._children ? "lightsteelblue" : "#fff";
			});

		nodeEnter.append("text")
			.attr("x", function (d) {
				return d.children || d._children ? -13 : 13;
			})
			.attr("dy", ".35em")
			.attr("text-anchor", function (d) {
				return d.children || d._children ? "end" : "start";
			})
			.text(function (d) {
				return d.name;
			})
			.style("fill-opacity", 1e-6);

		// Transition nodes to their new position.
		var nodeUpdate = node.transition()
			.duration(duration)
			.attr("transform", function (d) {
				return "translate(" + d.y + "," + d.x + ")";
			});

		nodeUpdate.select("circle")
			.attr("r", 10)
			.style("fill", function (d) {
				return d._children ? "lightsteelblue" : "#fff";
			});

		nodeUpdate.select("text")
			.style("fill-opacity", 1);

		// Transition exiting nodes to the parent's new position.
		var nodeExit = node.exit().transition()
			.duration(duration)
			.attr("transform", function (d) {
				return "translate(" + source.y + "," + source.x + ")";
			})
			.remove();

		nodeExit.select("circle")
			.attr("r", 1e-6);

		nodeExit.select("text")
			.style("fill-opacity", 1e-6);

		// Update the links…
		var link = svg.selectAll("path.link")
			.data(links, function (d) {
				return d.target.id;
			});

		// Enter any new links at the parent's previous position.
		link.enter().insert("path", "g")
			.attr("class", "link")
			.attr("d", function (d) {
				var o = {x: source.x0, y: source.y0};
				return diagonal({source: o, target: o});
			});

		// Transition links to their new position.
		link.transition()
			.duration(duration)
			.attr("d", diagonal);

		// Transition exiting nodes to the parent's new position.
		link.exit().transition()
			.duration(duration)
			.attr("d", function (d) {
				var o = {x: source.x, y: source.y};
				return diagonal({source: o, target: o});
			})
			.remove();

		// Stash the old positions for transition.
		nodes.forEach(function (d) {
			d.x0 = d.x;
			d.y0 = d.y;
		});
	}

// Toggle children on click.
	function click(d) {
		if (d.children) {
			d._children = d.children;
			d.children = null;
		} else {
			d.children = d._children;
			d._children = null;
		}
		update(d);
	}
});

<|endoftext|>


<commit_before>import Service from '@ember/service';
import { getOwner } from '@ember/application';
import $ from 'jquery';
import { getErrorMessage } from 'open-event-frontend/utils/errors';
import { buildUrl } from 'open-event-frontend/utils/url';
import httpStatus from 'npm:http-status';
import objectToFormData from 'npm:object-to-formdata';
import fetch from 'fetch';
import { clone, assign, merge } from 'lodash';
const bodyAllowedIn = ['PATCH', 'POST', 'PUT'];

export default Service.extend({

  defaultConfig: {
    data              : null,
    headers           : {},
    adapter           : 'adapter:application',
    isExternal        : false,
    isFormData        : false,
    isFile            : false,
    queryParams       : {},
    withoutPrefix     : false,
    replaceHeaders    : false,
    skipDataTransform : false
  },

  getFetchOptions(url, method, data = null, config = {}) {
    config = merge(clone(this.defaultConfig), config);

    const adapter = getOwner(this).lookup(config.adapter);
    const fetchOptions = !config.isExternal ? adapter.ajaxOptions() : {};

    data = data || config.data || null;

    if (!config.isExternal) {
      if (!url.startsWith('/')) {
        url = `/${url}`;
      }
      url = config.withoutPrefix ? `${adapter.host}${url}` : `${adapter.urlPrefix()}${url}`;
    }

    fetchOptions.headers = config.replaceHeaders ? config.header : merge(fetchOptions.headers, config.headers);
    fetchOptions.method = method;

    if (data) {
      if (bodyAllowedIn.includes(method)) {
        if (config.skipDataTransform) {
          fetchOptions.body = data;
        } else {
          if (config.isFormData) {
            fetchOptions.body = objectToFormData(data);
          } else if (config.isFile) {
            delete fetchOptions.headers['Content-Type'];
            fetchOptions.body = data;
          } else {
            fetchOptions.headers['Content-Type'] = 'application/json';
            fetchOptions.body = JSON.stringify(data);
          }
        }
      } else {
        config.queryParams = config.queryParams || {};
        assign(config.queryParams, data);
      }
    }

    config.queryParams = config.queryParams || {};

    if (config.authToken) {
      fetchOptions.headers.Authorization = config.authToken;
    }

    url = buildUrl(url, config.queryParams, false);

    return {
      url, fetchOptions
    };
  },

  async makePromise(urlPath, method, data = null, config = {}) {

    const { url, fetchOptions } = this.getFetchOptions(urlPath, method, data, config);

    const response = await fetch(url, fetchOptions);
    let parsedResponse = null;
    try {
      parsedResponse = await response.json();
    } catch (jsonFailure) {
      try {
        parsedResponse = await response.text();
      } catch (e) {
        console.warn('loader.parseFailed', response, e);
      }
    }

    if (!response.ok) {
      const defaultMessage = httpStatus[response.status];
      if (parsedResponse) {
        throw parsedResponse;
      }
      throw new Error(
        getErrorMessage(
          response.statusText,
          defaultMessage
            ? `${response.status} - ${defaultMessage}`
            : `Could not make ${fetchOptions.type} request to ${fetchOptions.url}`
        )
      );
    }
    return parsedResponse;
  },

  load(url, config = {}) {
    return this.makePromise(url, 'GET', null, config);
  },

  post(url, data = null, config = {}) {
    return this.makePromise(url, 'POST', data, config);
  },

  put(url, data = null, config = {}) {
    return this.makePromise(url, 'PUT', data, config);
  },

  patch(url, data = null, config = {}) {
    return this.makePromise(url, 'PATCH', data, config);
  },

  delete(url, config = {}) {
    return this.makePromise(url, 'DELETE', null, config);
  },

  uploadFile(urlPath, source, onProgressUpdate = null, config = {}, method = 'POST') {
    return new Promise((resolve, reject) => {
      if (
        !((window.File && source instanceof window.File)
          || (window.Blob && source instanceof window.Blob)
          || source.jquery
          || source.nodeType
          || ($(source).prop('tagName') === 'INPUT' && $(source).attr('type') === 'file'))
      ) {
        return reject('service:loader.uploadFile can only be used for an input, blob or File.');
      }

      if (source.jquery || source.nodeType) {
        const [{ files }] = $(source);
        if (files.length === 0) {
          return reject('no_files_selected');
        }
        if (!config.fileName) {
          config.fileName = $(source).attr('name');
        }
        source = files[0];
      }

      let formData = new FormData();
      formData.append(config.fileName, source);
      config.skipDataTransform = true;

      const { url, fetchOptions } = this.getFetchOptions(urlPath, method, formData, config);
      const xhr = new XMLHttpRequest();
      xhr.open(fetchOptions.method || 'get', url);
      let headers = fetchOptions.headers || {};
      for (let k in headers) {
        // https://stackoverflow.com/a/39281156/6870128
        if (k !== 'Content-Type' && headers.hasOwnProperty(k)) {
          xhr.setRequestHeader(k, fetchOptions.headers[k]);
        }
      }
      xhr.onload = e => resolve(e.target.responseText);
      xhr.onerror = reject;
      if (xhr.upload && onProgressUpdate) {xhr.upload.onprogress = onProgressUpdate}
      xhr.send(fetchOptions.body);
    });
  }
});
<commit_msg>Loader service: Add downloadFile method (#2540)<commit_after>import Service from '@ember/service';
import { getOwner } from '@ember/application';
import $ from 'jquery';
import { getErrorMessage } from 'open-event-frontend/utils/errors';
import { buildUrl } from 'open-event-frontend/utils/url';
import httpStatus from 'npm:http-status';
import objectToFormData from 'npm:object-to-formdata';
import fetch from 'fetch';
import { clone, assign, merge } from 'lodash';
const bodyAllowedIn = ['PATCH', 'POST', 'PUT'];

export default Service.extend({

  defaultConfig: {
    data              : null,
    headers           : {},
    adapter           : 'adapter:application',
    isExternal        : false,
    isFormData        : false,
    isFile            : false,
    queryParams       : {},
    withoutPrefix     : false,
    replaceHeaders    : false,
    skipDataTransform : false
  },

  getFetchOptions(url, method, data = null, config = {}) {
    config = merge(clone(this.defaultConfig), config);

    const adapter = getOwner(this).lookup(config.adapter);
    const fetchOptions = !config.isExternal ? adapter.ajaxOptions() : {};

    data = data || config.data || null;

    if (!config.isExternal) {
      if (!url.startsWith('/')) {
        url = `/${url}`;
      }
      url = config.withoutPrefix ? `${adapter.host}${url}` : `${adapter.urlPrefix()}${url}`;
    }

    fetchOptions.headers = config.replaceHeaders ? config.header : merge(fetchOptions.headers, config.headers);
    fetchOptions.method = method;

    if (data) {
      if (bodyAllowedIn.includes(method)) {
        if (config.skipDataTransform) {
          fetchOptions.body = data;
        } else {
          if (config.isFormData) {
            fetchOptions.body = objectToFormData(data);
          } else if (config.isFile) {
            delete fetchOptions.headers['Content-Type'];
            fetchOptions.body = data;
          } else {
            fetchOptions.headers['Content-Type'] = 'application/json';
            fetchOptions.body = JSON.stringify(data);
          }
        }
      } else {
        config.queryParams = config.queryParams || {};
        assign(config.queryParams, data);
      }
    }

    config.queryParams = config.queryParams || {};

    if (config.authToken) {
      fetchOptions.headers.Authorization = config.authToken;
    }

    url = buildUrl(url, config.queryParams, false);

    return {
      url, fetchOptions
    };
  },

  async makePromise(urlPath, method, data = null, config = {}) {

    const { url, fetchOptions } = this.getFetchOptions(urlPath, method, data, config);

    const response = await fetch(url, fetchOptions);
    let parsedResponse = null;
    try {
      parsedResponse = await response.json();
    } catch (jsonFailure) {
      try {
        parsedResponse = await response.text();
      } catch (e) {
        console.warn('loader.parseFailed', response, e);
      }
    }

    if (!response.ok) {
      const defaultMessage = httpStatus[response.status];
      if (parsedResponse) {
        throw parsedResponse;
      }
      throw new Error(
        getErrorMessage(
          response.statusText,
          defaultMessage
            ? `${response.status} - ${defaultMessage}`
            : `Could not make ${fetchOptions.type} request to ${fetchOptions.url}`
        )
      );
    }
    return parsedResponse;
  },

  load(url, config = {}) {
    return this.makePromise(url, 'GET', null, config);
  },

  post(url, data = null, config = {}) {
    return this.makePromise(url, 'POST', data, config);
  },

  put(url, data = null, config = {}) {
    return this.makePromise(url, 'PUT', data, config);
  },

  patch(url, data = null, config = {}) {
    return this.makePromise(url, 'PATCH', data, config);
  },

  delete(url, config = {}) {
    return this.makePromise(url, 'DELETE', null, config);
  },

  uploadFile(urlPath, source, onProgressUpdate = null, config = {}, method = 'POST') {
    return new Promise((resolve, reject) => {
      if (
        !((window.File && source instanceof window.File)
          || (window.Blob && source instanceof window.Blob)
          || source.jquery
          || source.nodeType
          || ($(source).prop('tagName') === 'INPUT' && $(source).attr('type') === 'file'))
      ) {
        return reject('service:loader.uploadFile can only be used for an input, blob or File.');
      }

      if (source.jquery || source.nodeType) {
        const [{ files }] = $(source);
        if (files.length === 0) {
          return reject('no_files_selected');
        }
        if (!config.fileName) {
          config.fileName = $(source).attr('name');
        }
        source = files[0];
      }

      let formData = new FormData();
      formData.append(config.fileName, source);
      config.skipDataTransform = true;

      const { url, fetchOptions } = this.getFetchOptions(urlPath, method, formData, config);
      const xhr = new XMLHttpRequest();
      xhr.open(fetchOptions.method || 'get', url);
      let headers = fetchOptions.headers || {};
      for (let k in headers) {
        // https://stackoverflow.com/a/39281156/6870128
        if (k !== 'Content-Type' && headers.hasOwnProperty(k)) {
          xhr.setRequestHeader(k, fetchOptions.headers[k]);
        }
      }
      xhr.onload = e => resolve(e.target.responseText);
      xhr.onerror = reject;
      if (xhr.upload && onProgressUpdate) {xhr.upload.onprogress = onProgressUpdate}
      xhr.send(fetchOptions.body);
    });
  },
  downloadFile(urlPath,  onProgressUpdate = null, config = {}, method = 'GET') {
    return new Promise((resolve, reject) => {
      const { url, fetchOptions } = this.getFetchOptions(urlPath, method, null, config);
      const xhr = new XMLHttpRequest();

      xhr.responseType = 'blob';
      xhr.open(fetchOptions.method || 'get', url);
      xhr.onload =  e => {
        const anchor = document.createElement('a');
        anchor.style.display = 'none';
        anchor.href = e.target.responseURL;
        anchor.click();
        resolve('success');
      };
      xhr.onerror = reject;
      if (onProgressUpdate) {xhr.onprogress = onProgressUpdate}
      xhr.send();
    });
  }
});
<|endoftext|>


<commit_before>// highly adapted for codemiror jshint

(function () {
  "use strict";
  function forEach(arr, f) {
    for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
  }

  function arrayContains(arr, item) {
    if (!Array.prototype.indexOf) {
      var i = arr.length;
      while (i--) {
        if (arr[i] === item) {
          return true;
        }
      }
      return false;
    }
    return arr.indexOf(item) != -1;
  }

  CodeMirror.contextHint = function(editor) {
    // Find the token at the cursor
    var cur = editor.getCursor(), token = editor.getTokenAt(cur), tprop = token;
    // If it's not a 'word-style' token, ignore the token.
    // If it is a property, find out what it is a property of.

    var list  = new Array();
    var clist = getCompletions(token,editor) ;
    for( var i = 0 ; i < clist.length ; i++)
    {
        list.push(
                {
                    str  : clist[i],
                    type : "context",
                    from : {line: cur.line, ch: token.start},
                    to   : {line: cur.line, ch: token.end}
                }
            )

    }
    return list;
  }

  // find all 'words' of current cell
  function getAllTokens(editor)
  {
    var found = [];
    // get all text remove and split it before dot and at space
    // keep the dot for completing token that also start with dot
    var candidates = editor.getValue()
        .replace(/[. ]/g,"\n")
        .split('\n');
    // append to arry if not already (the function)
    function maybeAdd(str) {
      if (!arrayContains(found, str)) found.push(str);
    }

    // append to arry if not already
    // (here we do it )
    for( var c in candidates )
    {
        if(candidates[c].length >= 1){
        maybeAdd(candidates[c]);}
    }
    return found;

  }

  function getCompletions(token,editor)
  {
    var candidates = getAllTokens(editor);
    // filter all token that have a common start (but nox exactly) the lenght of the current token
    var prependchar ='';
    if(token.string.indexOf('.') == 0)
    {
        prependchar = '.'
    }
    var lambda = function(x){
        x = prependchar+x;
        return (x.indexOf(token.string)==0 && x != token.string)};
    var filterd = candidates.filter(lambda);
    for( var i in filterd)
    {
        // take care of reappending '.' at the beginning
        filterd[i] = prependchar+filterd[i];
    }
    return filterd;
  }
})();
<commit_msg>fix and retab javascript<commit_after>// highly adapted for codemiror jshint

(function () {
    "use strict";
    function forEach(arr, f) {
        for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
    }

    function arrayContains(arr, item) {
        if (!Array.prototype.indexOf) {
            var i = arr.length;
            while (i--) {
                if (arr[i] === item) {return true;}
            }
            return false;
        }
        return arr.indexOf(item) != -1;
    }

    CodeMirror.contextHint = function(editor) {
        // Find the token at the cursor
        var cur = editor.getCursor(), token = editor.getTokenAt(cur), tprop = token;
        // If it's not a 'word-style' token, ignore the token.
        // If it is a property, find out what it is a property of.
        var list = new Array();
        var clist = getCompletions(token,editor);
        for(var i = 0 ; i < clist.length ; i++)
        {
            list.push(
                { str  : clist[i],
                  type : "context",
                  from : {line: cur.line, ch: token.start},
                  to   : {line: cur.line, ch: token.end} })
        }
        return list;
    }

    // find all 'words' of current cell
    function getAllTokens(editor)
    {
        var found = [];
        // get all text remove and split it before dot and at space
        // keep the dot for completing token that also start with dot
        var candidates = editor.getValue()
                .replace(/[.]/g," .")
                .replace(/[ ]/g,"\n")
                .split('\n');
        // append to arry if not already (the function)
        function maybeAdd(str) {
            if (!arrayContains(found, str)) found.push(str);
        }
        // append to arry if not already
        // (here we do it )
        for( var c in candidates )
        {
            if(candidates[c].length >= 1){
            maybeAdd(candidates[c]);}
        }
        return found;
    }

    function getCompletions(token,editor)
    {
        var candidates = getAllTokens(editor);
        // filter all token that have a common start (but nox exactly) the lenght of the current token
        var lambda = function(x){
            return (x.indexOf(token.string)==0 && x != token.string)
            };
        var filterd = candidates.filter(lambda);
        return filterd;
    }
})();
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import Subheader from 'material-ui/Subheader';
import {Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui/Table';
import IdField from './IdField';

class Tasks extends Component {
  constructor(props) {
    super(props);
    this.state = {
      tasks: []
    };
  }

  loadTasks() {
    fetch('/api/tasks', {
      accept: 'application/json'
    })
      .then((response) => {
        return response.json();
      })
      .then((tasks) => {
        this.setState({
          tasks: tasks
        });
      })
      .catch((error) => {
        console.error(error);
      });
  }

  componentDidMount() {
    this.loadTasks();
    setInterval(this.loadTasks.bind(this), 1000);
  }

  render() {
    var tasks;
    if(!this.state.tasks || !this.state.tasks.length) {
      tasks =

    } else {
      tasks =

          <Subheader>Tasks</Subheader>

            <TableHeader>
              <TableRow>
                <TableHeaderColumn>ID</TableHeaderColumn>
                <TableHeaderColumn>Image</TableHeaderColumn>
                <TableHeaderColumn>Message</TableHeaderColumn>
                <TableHeaderColumn>State</TableHeaderColumn>
              </TableRow>
            </TableHeader>
            <TableBody>
              {this.state.tasks.map((task, index) => (
                <TableRow key={index}>
                  <TableRowColumn><IdField value={task.ID}></IdField></TableRowColumn>
                  <TableRowColumn>{task.Spec.ContainerSpec.Image}</TableRowColumn>
                  <TableRowColumn>{task.Status.Message}</TableRowColumn>
                  <TableRowColumn>{task.Status.State}</TableRowColumn>
                </TableRow>
              ))}
            </TableBody>

    }

    return (

        {tasks}

    );
  }
}

export default Tasks;

<commit_msg>feat: Display task error message if present<commit_after>import React, { Component } from 'react';
import Subheader from 'material-ui/Subheader';
import {Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui/Table';
import IdField from './IdField';

class Tasks extends Component {
  constructor(props) {
    super(props);
    this.state = {
      tasks: []
    };
  }

  loadTasks() {
    fetch('/api/tasks', {
      accept: 'application/json'
    })
      .then((response) => {
        return response.json();
      })
      .then((tasks) => {
        this.setState({
          tasks: tasks
        });
      })
      .catch((error) => {
        console.error(error);
      });
  }

  componentDidMount() {
    this.loadTasks();
    setInterval(this.loadTasks.bind(this), 1000);
  }

  render() {
    var tasks;
    if(!this.state.tasks || !this.state.tasks.length) {
      tasks =

    } else {
      tasks =

          <Subheader>Tasks</Subheader>

            <TableHeader>
              <TableRow>
                <TableHeaderColumn>ID</TableHeaderColumn>
                <TableHeaderColumn>Image</TableHeaderColumn>
                <TableHeaderColumn>Message</TableHeaderColumn>
                <TableHeaderColumn>State</TableHeaderColumn>
              </TableRow>
            </TableHeader>
            <TableBody>
              {this.state.tasks.map((task, index) => (
                <TableRow key={index}>
                  <TableRowColumn><IdField value={task.ID}></IdField></TableRowColumn>
                  <TableRowColumn>{task.Spec.ContainerSpec.Image}</TableRowColumn>
                  <TableRowColumn>{task.Status.Message}</TableRowColumn>
                  <TableRowColumn>{task.Status.State}
{task.Status.Err}</TableRowColumn>
                </TableRow>
              ))}
            </TableBody>

    }

    return (

        {tasks}

    );
  }
}

export default Tasks;

<|endoftext|>


<commit_before>/* globals
    ClipboardJS,
    inventreeFormDataUpload,
    inventreeGet,
    launchModalForm,
    user_settings,
*/

/* exported
    attachClipboard,
    enableDragAndDrop,
    exportFormatOptions,
    inventreeDocReady,
    inventreeLoad,
    inventreeSave,
*/

function attachClipboard(selector, containerselector, textElement) {
    // set container
    if (containerselector) {
        containerselector = document.getElementById(containerselector);
    } else {
        containerselector = document.body;
    }

    var text = null;

    // set text-function
    if (textElement) {
        text = function() {
            return document.getElementById(textElement).textContent;
        };
    } else {
        text = function(trigger) {
            var content = trigger.parentElement.parentElement.textContent;
            return content.trim();
        };
    }

    // create Clipboard
    // eslint-disable-next-line no-unused-vars
    var cis = new ClipboardJS(selector, {
        text: text,
        container: containerselector
    });
}

/**
 * Return a standard list of export format options *
 */
function exportFormatOptions() {
    return [
        {
            value: 'csv',
            display_name: 'CSV',
        },
        {
            value: 'tsv',
            display_name: 'TSV',
        },
        {
            value: 'xls',
            display_name: 'XLS',
        },
        {
            value: 'xlsx',
            display_name: 'XLSX',
        },
    ];
}

function inventreeDocReady() {
    /* Run this function when the HTML document is loaded.
     * This will be called for every page that extends "base.html"
     */

    window.addEventListener('dragover', function(e) {
        e = e || event;
        e.preventDefault();
    }, false);

    window.addEventListener('drop', function(e) {
        e = e || event;
        e.preventDefault();
    }, false);

    /* Add drag-n-drop functionality to any element
     * marked with the class 'dropzone'
     */
    $('.dropzone').on('dragenter', function(event) {

        // TODO - Only indicate that a drop event will occur if a file is being dragged
        var transfer = event.originalEvent.dataTransfer;

        // eslint-disable-next-line no-constant-condition
        if (true || isFileTransfer(transfer)) {
            $(this).addClass('dragover');
        }
    });

    $('.dropzone').on('dragleave drop', function() {
        $(this).removeClass('dragover');
    });

    // Callback to launch the 'About' window
    $('#launch-about').click(function() {
        var modal = $('#modal-about');

        modal.modal({
            backdrop: 'static',
            keyboard: true,
        });

        modal.modal('show');
    });

    // Callback to launch the 'Database Stats' window
    $('#launch-stats').click(function() {
        launchModalForm('/stats/', {
            no_post: true,
        });
    });

    // Initialize clipboard-buttons
    attachClipboard('.clip-btn');
    attachClipboard('.clip-btn', 'modal-about');
    attachClipboard('.clip-btn-version', 'modal-about', 'about-copy-text');

    // Add autocomplete to the search-bar
    if ($('#search-bar').exists()) {
        $('#search-bar').autocomplete({
            source: function(request, response) {

                var params = {
                    search: request.term,
                    limit: user_settings.SEARCH_PREVIEW_RESULTS,
                    offset: 0,
                };

                if (user_settings.SEARCH_HIDE_INACTIVE_PARTS) {
                    // Limit to active parts
                    params.active = true;
                }

                $.ajax({
                    url: '/api/part/',
                    data: params,
                    success: function(data) {

                        var transformed = $.map(data.results, function(el) {
                            return {
                                label: el.full_name,
                                id: el.pk,
                                thumbnail: el.thumbnail,
                                data: el,
                            };
                        });
                        response(transformed);
                    },
                    error: function() {
                        response([]);
                    }
                });
            },
            create: function() {
                $(this).data('ui-autocomplete')._renderItem = function(ul, item) {

                    var html = `

                             ${item.label}

                    `;

                    if (user_settings.SEARCH_SHOW_STOCK_LEVELS) {
                        html += partStockLabel(
                            item.data,
                            {
                                classes: 'badge-right',
                            }
                        );
                    }

                    html += '
';

                    return $('
').append(html).appendTo(ul);
                };
            },
            select: function( event, ui ) {
                window.location = '/part/' + ui.item.id + '/';
            },
            minLength: 2,
            classes: {
                'ui-autocomplete': 'dropdown-menu search-menu',
            },
            position: {
                my : "right top",
                at: "right bottom"
            }
        });
    }

    // Generate brand-icons
    $('.brand-icon').each(function(i, obj) {
        loadBrandIcon($(this), $(this).attr('brand_name'));
    });

    // Callback for "admin view" button
    $('#admin-button, .admin-button').click(function() {
        var url = $(this).attr('url');

        location.href = url;
    });

    // Display any cached alert messages
    showCachedAlerts();

    // Start notification background worker to check every 5 seconds if notifications are available
    var notificationRunner = setInterval(notificationCheck, 5000);

    // also run when the focus returns
    $(document).on('focus', function(e){
        notificationCheck();
    });
}

/**
 * The notification checker is initiated when the doc is loaded. It checks if there are unread notifications
 * if unread messages exist the alert flag is raised by making it visible
 **/
var current_alert_state = false;
function notificationCheck() {
    // only refresh state if in focus
    if (document.hasFocus()) {
    inventreeGet(
        '/api/notifications/',
        {
            read: false,
        },
        {
            success: function(response) {
                if (response.length == 0) {
                    if (current_alert_state == true){
                        $("#notification-alert").addClass("d-none");
                        current_alert_state = false;
                    }
                } else {
                    if (current_alert_state == false){
                        $("#notification-alert").removeClass("d-none");
                        current_alert_state = true;
                    }
                }
            }
        }
    );
    }
}

function isFileTransfer(transfer) {
    /* Determine if a transfer (e.g. drag-and-drop) is a file transfer
     */

    return transfer.files.length > 0;
}

function enableDragAndDrop(element, url, options) {
    /* Enable drag-and-drop file uploading for a given element.

    Params:
        element - HTML element lookup string e.g. "#drop-div"
        url - URL to POST the file to
        options - object with following possible values:
            label - Label of the file to upload (default='file')
            data - Other form data to upload
            success - Callback function in case of success
            error - Callback function in case of error
            method - HTTP method
    */

    var data = options.data || {};

    $(element).on('drop', function(event) {

        var transfer = event.originalEvent.dataTransfer;

        var label = options.label || 'file';

        var formData = new FormData();

        // Add the extra data
        for (var key in data) {
            formData.append(key, data[key]);
        }

        if (isFileTransfer(transfer)) {
            formData.append(label, transfer.files[0]);

            inventreeFormDataUpload(
                url,
                formData,
                {
                    success: function(data, status, xhr) {
                        console.log('Uploaded file via drag-and-drop');
                        if (options.success) {
                            options.success(data, status, xhr);
                        }
                    },
                    error: function(xhr, status, error) {
                        console.log('File upload failed');
                        if (options.error) {
                            options.error(xhr, status, error);
                        }
                    },
                    method: options.method || 'POST',
                }
            );
        } else {
            console.log('Ignoring drag-and-drop event (not a file)');
        }
    });
}

/**
 * Save a key:value pair to local storage
 * @param {String} name - settting key
 * @param {String} value - setting value
 */
function inventreeSave(name, value) {

    var key = `inventree-${name}`;
    localStorage.setItem(key, value);
}

/**
 * Retrieve a key:value pair from local storage
 * @param {*} name - setting key
 * @param {*} defaultValue - default value (returned if no matching key:value pair is found)
 * @returns
 */
function inventreeLoad(name, defaultValue) {

    var key = `inventree-${name}`;

    var value = localStorage.getItem(key);

    if (value == null) {
        return defaultValue;
    } else {
        return value;
    }
}

function loadBrandIcon(element, name) {
    // check if icon exists
    var icon = window.FontAwesome.icon({prefix: 'fab', iconName: name});

    if (icon) {
        // add icon to button
        element.addClass('fab fa-' + name);
    }
}

// Convenience function to determine if an element exists
$.fn.exists = function() {
    return this.length !== 0;
};
<commit_msg>make more compact<commit_after>/* globals
    ClipboardJS,
    inventreeFormDataUpload,
    inventreeGet,
    launchModalForm,
    user_settings,
*/

/* exported
    attachClipboard,
    enableDragAndDrop,
    exportFormatOptions,
    inventreeDocReady,
    inventreeLoad,
    inventreeSave,
*/

function attachClipboard(selector, containerselector, textElement) {
    // set container
    if (containerselector) {
        containerselector = document.getElementById(containerselector);
    } else {
        containerselector = document.body;
    }

    var text = null;

    // set text-function
    if (textElement) {
        text = function() {
            return document.getElementById(textElement).textContent;
        };
    } else {
        text = function(trigger) {
            var content = trigger.parentElement.parentElement.textContent;
            return content.trim();
        };
    }

    // create Clipboard
    // eslint-disable-next-line no-unused-vars
    var cis = new ClipboardJS(selector, {
        text: text,
        container: containerselector
    });
}

/**
 * Return a standard list of export format options *
 */
function exportFormatOptions() {
    return [
        {
            value: 'csv',
            display_name: 'CSV',
        },
        {
            value: 'tsv',
            display_name: 'TSV',
        },
        {
            value: 'xls',
            display_name: 'XLS',
        },
        {
            value: 'xlsx',
            display_name: 'XLSX',
        },
    ];
}

function inventreeDocReady() {
    /* Run this function when the HTML document is loaded.
     * This will be called for every page that extends "base.html"
     */

    window.addEventListener('dragover', function(e) {
        e = e || event;
        e.preventDefault();
    }, false);

    window.addEventListener('drop', function(e) {
        e = e || event;
        e.preventDefault();
    }, false);

    /* Add drag-n-drop functionality to any element
     * marked with the class 'dropzone'
     */
    $('.dropzone').on('dragenter', function(event) {

        // TODO - Only indicate that a drop event will occur if a file is being dragged
        var transfer = event.originalEvent.dataTransfer;

        // eslint-disable-next-line no-constant-condition
        if (true || isFileTransfer(transfer)) {
            $(this).addClass('dragover');
        }
    });

    $('.dropzone').on('dragleave drop', function() {
        $(this).removeClass('dragover');
    });

    // Callback to launch the 'About' window
    $('#launch-about').click(function() {
        var modal = $('#modal-about');

        modal.modal({
            backdrop: 'static',
            keyboard: true,
        });

        modal.modal('show');
    });

    // Callback to launch the 'Database Stats' window
    $('#launch-stats').click(function() {
        launchModalForm('/stats/', {
            no_post: true,
        });
    });

    // Initialize clipboard-buttons
    attachClipboard('.clip-btn');
    attachClipboard('.clip-btn', 'modal-about');
    attachClipboard('.clip-btn-version', 'modal-about', 'about-copy-text');

    // Add autocomplete to the search-bar
    if ($('#search-bar').exists()) {
        $('#search-bar').autocomplete({
            source: function(request, response) {

                var params = {
                    search: request.term,
                    limit: user_settings.SEARCH_PREVIEW_RESULTS,
                    offset: 0,
                };

                if (user_settings.SEARCH_HIDE_INACTIVE_PARTS) {
                    // Limit to active parts
                    params.active = true;
                }

                $.ajax({
                    url: '/api/part/',
                    data: params,
                    success: function(data) {

                        var transformed = $.map(data.results, function(el) {
                            return {
                                label: el.full_name,
                                id: el.pk,
                                thumbnail: el.thumbnail,
                                data: el,
                            };
                        });
                        response(transformed);
                    },
                    error: function() {
                        response([]);
                    }
                });
            },
            create: function() {
                $(this).data('ui-autocomplete')._renderItem = function(ul, item) {

                    var html = `

                             ${item.label}

                    `;

                    if (user_settings.SEARCH_SHOW_STOCK_LEVELS) {
                        html += partStockLabel(
                            item.data,
                            {
                                classes: 'badge-right',
                            }
                        );
                    }

                    html += '
';

                    return $('
').append(html).appendTo(ul);
                };
            },
            select: function( event, ui ) {
                window.location = '/part/' + ui.item.id + '/';
            },
            minLength: 2,
            classes: {
                'ui-autocomplete': 'dropdown-menu search-menu',
            },
            position: {
                my : "right top",
                at: "right bottom"
            }
        });
    }

    // Generate brand-icons
    $('.brand-icon').each(function(i, obj) {
        loadBrandIcon($(this), $(this).attr('brand_name'));
    });

    // Callback for "admin view" button
    $('#admin-button, .admin-button').click(function() {
        var url = $(this).attr('url');

        location.href = url;
    });

    // Display any cached alert messages
    showCachedAlerts();

    // Start notification background worker to check every 5 seconds if notifications are available
    var notificationRunner = setInterval(notificationCheck, 5000);

    // also run when the focus returns
    $(document).on('focus', function(e){
        notificationCheck();
    });
}

/**
 * The notification checker is initiated when the doc is loaded. It checks if there are unread notifications
 * if unread messages exist the alert flag is raised by making it visible
 **/
var current_alert_state = false;
function notificationCheck() {
    // only refresh state if in focus
    if (document.hasFocus()) {
        inventreeGet(
            '/api/notifications/',
            {
                read: false,
            },
            {
                success: function(response) {
                    if (response.length == 0) {
                        $("#notification-alert").addClass("d-none");
                    } else {
                        $("#notification-alert").removeClass("d-none");
                    }
                }
            }
        );
    }
}

function isFileTransfer(transfer) {
    /* Determine if a transfer (e.g. drag-and-drop) is a file transfer
     */

    return transfer.files.length > 0;
}

function enableDragAndDrop(element, url, options) {
    /* Enable drag-and-drop file uploading for a given element.

    Params:
        element - HTML element lookup string e.g. "#drop-div"
        url - URL to POST the file to
        options - object with following possible values:
            label - Label of the file to upload (default='file')
            data - Other form data to upload
            success - Callback function in case of success
            error - Callback function in case of error
            method - HTTP method
    */

    var data = options.data || {};

    $(element).on('drop', function(event) {

        var transfer = event.originalEvent.dataTransfer;

        var label = options.label || 'file';

        var formData = new FormData();

        // Add the extra data
        for (var key in data) {
            formData.append(key, data[key]);
        }

        if (isFileTransfer(transfer)) {
            formData.append(label, transfer.files[0]);

            inventreeFormDataUpload(
                url,
                formData,
                {
                    success: function(data, status, xhr) {
                        console.log('Uploaded file via drag-and-drop');
                        if (options.success) {
                            options.success(data, status, xhr);
                        }
                    },
                    error: function(xhr, status, error) {
                        console.log('File upload failed');
                        if (options.error) {
                            options.error(xhr, status, error);
                        }
                    },
                    method: options.method || 'POST',
                }
            );
        } else {
            console.log('Ignoring drag-and-drop event (not a file)');
        }
    });
}

/**
 * Save a key:value pair to local storage
 * @param {String} name - settting key
 * @param {String} value - setting value
 */
function inventreeSave(name, value) {

    var key = `inventree-${name}`;
    localStorage.setItem(key, value);
}

/**
 * Retrieve a key:value pair from local storage
 * @param {*} name - setting key
 * @param {*} defaultValue - default value (returned if no matching key:value pair is found)
 * @returns
 */
function inventreeLoad(name, defaultValue) {

    var key = `inventree-${name}`;

    var value = localStorage.getItem(key);

    if (value == null) {
        return defaultValue;
    } else {
        return value;
    }
}

function loadBrandIcon(element, name) {
    // check if icon exists
    var icon = window.FontAwesome.icon({prefix: 'fab', iconName: name});

    if (icon) {
        // add icon to button
        element.addClass('fab fa-' + name);
    }
}

// Convenience function to determine if an element exists
$.fn.exists = function() {
    return this.length !== 0;
};
<|endoftext|>


<commit_before>var Matrix4    = require("./math").mat4
var Vector3    = require("./math").vec3
var Quaternion = require("./math").quat
var Euler      = require("./math").euler

var representations = {
  player: require("./obj3d/player")
}

function getEntityRepresentation (me, entity) {
  if (me.context.id == entity.context.id) return
  return representations.player
}

function Stage (engine) {
  this.engine = engine
  this.cbs = {}
  this.el = document.createElement("div")
  this.el.className = "stage noselect"
  this.mpos = {x:0, y:0}

  this.el.addEventListener("contextmenu", function(e) {
    e.preventDefault()
  })

  this.init()
}

Stage.prototype = {
  init: function init() {
    this.scene = new THREE.Scene()
    this.camera = new THREE.PerspectiveCamera(50, 0, 1, 1000)
    this.renderer = new THREE.WebGLRenderer()
    this.emap = {}

    var el = this.el
    while (el.firstChild) {
      el.removeChild(el.firstChild)
    }
    el.appendChild(this.renderer.domElement)

    this.resize()

    for (var angle = 0; angle < 360; angle += 90) {
      var p = new representations.player(null, null, Math.max(Math.random() * 0xFFFFFF, 0xFF))
      p.o3d.position.x = Math.cos(angle * Math.PI / 180) * 5
      p.o3d.position.z = -Math.sin(angle * Math.PI / 180) * 5
      this.scene.add(p.o3d)
    }
  },

  resize: function resize() {
    var rect = this.el.getBoundingClientRect()
    this.camera.aspect = rect.width / rect.height
    this.camera.updateProjectionMatrix()
    this.renderer.setSize(rect.width, rect.height)
  },

  update: function update(dt) {
    var me = this.engine.you()

    if (!me) {
      console.log("no me")
      return this.renderer.render(this.scene, this.camera)
    }

    this.camera.rotation.copy(new Euler(-me.euler.y, -me.euler.x, 0, "YXZ"))
    this.camera.position.copy(me.position)

    // Diff the entities in the engine and add and or update, or remove them.
    var map = this.emap
    var imap = {}
    var entities = this.engine.entities
    var rep

    for (var i=0; i<entities.length; i++) {
      var e = entities[i]
      imap[e.id] = true

      if (map[e.id]) continue

      var Representation = getEntityRepresentation.call(this, me, e)
      if (Representation) {
        rep = new Representation(e)
        this.scene.add(rep.o3d)
      }
      else {
        rep = {entity: e}
      }

      map[e.id] = rep
      console.log("Added entity", e.id)
    }

    var ids = Object.keys(map)
    for (var i=0; i<ids.length; i++) {
      var id = ids[i]
      rep = map[id]

      if (imap[id]) {
        if (rep.update) rep.update(dt)
        console.log("Updated entity", rep.entity.id)
        continue
      }

      this.scene.remove(rep.o3d)
      delete map[id]
      ids.splice(i, 1)
      i--
      console.log("Removed entity", rep.entity.id)
    }

    console.log("---")

    this.renderer.render(this.scene, this.camera)
  }
}

module.exports = Stage<commit_msg>Minor fixies.<commit_after>var Matrix4    = require("./math").mat4
var Vector3    = require("./math").vec3
var Quaternion = require("./math").quat
var Euler      = require("./math").euler

var representations = {
  player: require("./obj3d/player")
}

function getEntityRepresentation (me, entity) {
  if (me && me.context.id == entity.context.id) return
  return representations.player
}

function Stage (engine) {
  this.engine = engine
  this.cbs = {}
  this.el = document.createElement("div")
  this.el.className = "stage noselect"
  this.mpos = {x:0, y:0}

  this.el.addEventListener("contextmenu", function(e) {
    e.preventDefault()
  })

  this.init()
}

Stage.prototype = {
  init: function init() {
    this.scene = new THREE.Scene()
    this.camera = new THREE.PerspectiveCamera(50, 0, 1, 1000)
    this.renderer = new THREE.WebGLRenderer()
    this.emap = {}

    var el = this.el
    while (el.firstChild) {
      el.removeChild(el.firstChild)
    }
    el.appendChild(this.renderer.domElement)

    this.resize()

    for (var angle = 0; angle < 360; angle += 90) {
      var p = new representations.player(null, null, Math.max(Math.random() * 0xFFFFFF, 0xFF))
      p.o3d.position.x = Math.cos(angle * Math.PI / 180) * 5
      p.o3d.position.z = -Math.sin(angle * Math.PI / 180) * 5
      this.scene.add(p.o3d)
    }
  },

  resize: function resize() {
    var rect = this.el.getBoundingClientRect()
    this.camera.aspect = rect.width / rect.height
    this.camera.updateProjectionMatrix()
    this.renderer.setSize(rect.width, rect.height)
  },

  update: function update(dt) {
    var me = this.engine.you()

    if (me) {
      this.camera.rotation.copy(new Euler(-me.euler.y, -me.euler.x, 0, "YXZ"))
      this.camera.position.copy(me.position)
    }

    // Diff the entities in the engine and add and or update, or remove them.
    var map = this.emap
    var imap = {}
    var entities = this.engine.entities
    var rep

    for (var i=0; i<entities.length; i++) {
      var e = entities[i]
      imap[e.id] = true

      if (map[e.id]) continue

      var Representation = getEntityRepresentation.call(this, me, e)
      if (Representation) {
        rep = new Representation(e)
        this.scene.add(rep.o3d)
      }
      else {
        rep = {entity: e}
      }

      map[e.id] = rep
    }

    var ids = Object.keys(map)
    for (var i=0; i<ids.length; i++) {
      var id = ids[i]
      rep = map[id]

      if (imap[id]) {
        if (rep.update) rep.update(dt)
        continue
      }

      this.scene.remove(rep.o3d)
      delete map[id]
      ids.splice(i, 1)
      i--
    }

    this.renderer.render(this.scene, this.camera)
  }
}

module.exports = Stage<|endoftext|>