<commit_before>;(function($){
	
	var defaults = {
		handleSize: 10,
		handleColor: "red",
		handleLineWidth: 1,
		lineType: "draw", // can be "straight" or "draw"
		edgeType: function( sourceNode, targetNode ){
			return "node"; // can return "flat" for flat edges between nodes or "node" for intermediate node between them
		},
		loopAllowed: function( node ){
			return false;
		},
		nodeParams: function( sourceNode, targetNode ){
			return {};
		},
		edgeParams: function( sourceNode, targetNode ){
			return {};
		}
	};
	
	$.fn.cytoscapewebEdgehandles = function( params ){
		var fn = params;
		
		var functions = {
			destroy: function(){
				var $container = $(this);
				var data = $container.data("cyedgehandles");
				
				if( data == null ){
					return;
				}
				
				data.unbind();
				$container.data("cyedgehandles", {});
				
				return $container;
			},
			
			option: function(name, value){
				var $container = $(this);
				var data = $container.data("cyedgehandles");
				
				if( data == null ){
					return;
				}
				
				var options = data.options;
				
				if( value === undefined ){
					if( typeof name == typeof {} ){
						var newOpts = name;
						options = $.extend(true, {}, defaults, newOpts);
						data.options = options;
					} else {
						return options[ name ];
					}
				} else {
					options[ name ] = value;
				}
				
				return $container;
			},
				
			init: function(){
				var options = $.extend(true, {}, defaults, params); 
				var $container = $(this);
				var svg, cy;
				var handle;
				var line, linePoints;
				var mdownOnHandle = false;
				var grabbingNode = false;
				var hx, hy, hr;
				
				// write options to data
				var data = $container.data("cyedgehandles");
				if( data == null ){
					data = {};
				}
				data.options = options;
				
				function svgIsInCy( svgDomElement ){
					var $ele = $(svgDomElement);
					var inside = false;
					
					$ele.parents().each(function(){
						if( this == $container[0] ){
							inside = true;
						}
					});
					
					return inside;
				}
				
				function safelyRemoveCySvgChild( svgDomElement ){
					if( svgDomElement != null && svgIsInCy( svgDomElement ) ){
						svg.remove( svgDomElement );
					}
				}
				
				function resetToDefaultState(){
					safelyRemoveCySvgChild( handle );
					safelyRemoveCySvgChild( line );
					
//					// console.log("def state");
//					console.trace();
					
					cy.nodes()
						.removeClass("ui-cytoscapeweb-edgehandles-hover")
						.removeClass("ui-cytoscapeweb-edgehandles-source")
						.removeClass("ui-cytoscapeweb-edgehandles-target")
					;

					linePoints = null;
					
					cy.zooming(true).panning(true);
				}
				
				function makePreview( source, target ){
					makeEdges( true );
				}
				
				function removePreview( source, target ){
					source.edgesWith(target).filter(".ui-cytoscapeweb-edgehandles-preview").remove();
					
					target
						.neighborhood("node.ui-cytoscapeweb-edgehandles-preview")
						.closedNeighborhood(".ui-cytoscapeweb-edgehandles-preview")
						.remove();
					
				}
				
				function makeEdges( preview ){
					
					// console.log("make edges");
					
					var source = cy.nodes(".ui-cytoscapeweb-edgehandles-source");
					var targets = cy.nodes(".ui-cytoscapeweb-edgehandles-target");
					var classes = preview ? "ui-cytoscapeweb-edgehandles-preview" : "";
					
					if( source.size() == 0 || targets.size() == 0 ){
						return; // nothing to do :(
					}
					
					// just remove preview class if we already have the edges
					if( !preview && options.preview ){
						cy.elements(".ui-cytoscapeweb-edgehandles-preview").removeClass("ui-cytoscapeweb-edgehandles-preview");
						return;
					} else {
						// remove old previews
						cy.elements(".ui-cytoscapeweb-edgehandles-preview").remove();
					}
					
					targets.each(function(i, target){
						switch( options.edgeType( source, target ) ){
						case "node":
							
							var p1 = source.position(false);
							var p2 = target.position(false);
							var p = {
								x: (p1.x + p2.x)/2,
								y: (p1.y + p2.y)/2
							};
												
							var interNode = cy.add($.extend( true, {
								group: "nodes",
								position: p
							}, options.nodeParams(source, target) )).addClass(classes);

							cy.add($.extend( true, {
								group: "edges",
								data: {
									source: source.id(),
									target: interNode.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);
							
							cy.add($.extend( true, {
								group: "edges",
								data: {
									source: interNode.id(),
									target: target.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);
							
							break;
							
						case "flat":
						default:
							cy.add($.extend( true, {
								group: "edges",
								data: {
									source: source.id(),
									target: target.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);
							break;
						}
					});
					
					
				}
				
				$container.cytoscapeweb(function(e){
					cy = this;
					svg = $container.svg("get");
					
					var transformHandler;
					cy.bind("zoom pan", transformHandler = function(){
						safelyRemoveCySvgChild( handle );
					});
					
					var startHandler, hoverHandler, leaveHandler, grabNodeHandler, freeNodeHandler;
					cy.nodes().live("mouseover", startHandler = function(e){
						if( mdownOnHandle || grabbingNode || this.hasClass("ui-cytoscapeweb-edgehandles-preview") ){
							return; // don't override existing handle that's being dragged
							// also don't trigger when grabbing a node
						} 
						
						// console.log("node mover");
						
						var node = this;
						var source = this;
						var p = node.renderedPosition();
						var d = node.renderedDimensions();
						
						// remove old handle
						safelyRemoveCySvgChild( handle );
						
						hx = p.x;
						hy = p.y - d.height/2;
						hr = options.handleSize/2;
						
						// add new handle
						handle = svg.circle(hx, hy, hr, {
							fill: options.handleColor
						});
						var $handle = $(handle);
						
						function mdownHandler(e){
							if( e.button != 0 ){
								return; // sorry, no right clicks allowed 
							}
							
							mdownOnHandle = true;
							
							// console.log("handle mdown");
							
							e.preventDefault();
							node.unbind("mouseout", removeHandler);
							$handle.unbind("mouseout", removeHandler);
							
							node.addClass("ui-cytoscapeweb-edgehandles-source");
							
							function doneMoving(){
								var $this = $(this);
								mdownOnHandle = false;
								$(window).unbind("mousemove", moveHandler);
								
								makeEdges();
								resetToDefaultState();
							}
							
							$(window).one("mouseup blur", doneMoving).bind("mousemove", moveHandler);
							cy.zooming(false).panning(false);
						}
						
						function moveHandler(e){
							// console.log("move");
							
							var x = e.pageX - $container.offset().left;
							var y = e.pageY - $container.offset().top;
							
							safelyRemoveCySvgChild( line );
							
							var style = {
								stroke: options.handleColor,
								strokeWidth: options.handleLineWidth,
								fill: "none",
								"pointer-events": "none"
							};
							
							// draw line based on type
							switch( options.lineType ){
							case "straight":
								
								line = svg.line(hx, hy, x, y, style);
								
								break;
							case "draw":
							default:
								
								if( linePoints == null ){
									linePoints = [ [hx, hy], [x, y] ];
								} else {
									linePoints.push([ x, y ]);
								}
								
								line = svg.polyline(linePoints, style);
								
								break;
							}
							
							
						}
						
						function removeHandler(e){
							
							
							var newTargetIsHandle = e.toElement == handle;
							var newTargetIsNode = e.toElement == node._private.renderer.svg;
							
							if( newTargetIsHandle || newTargetIsNode ){
								return; // don't consider mouseout
							}
							
							// console.log("remove");
							
							resetToDefaultState();
							node.unbind("mouseout", removeHandler);
						}
						
						node.bind("mouseout", removeHandler);
						$handle.bind("mouseout", removeHandler);
						$handle.bind("mousedown", mdownHandler);<commit_msg>Remove race condition where handle can disappear in drawing line state<commit_after>;(function($){
	
	var defaults = {
		handleSize: 10,
		handleColor: "red",
		handleLineWidth: 1,
		lineType: "draw", // can be "straight" or "draw"
		edgeType: function( sourceNode, targetNode ){
			return "node"; // can return "flat" for flat edges between nodes or "node" for intermediate node between them
		},
		loopAllowed: function( node ){
			return false;
		},
		nodeParams: function( sourceNode, targetNode ){
			return {};
		},
		edgeParams: function( sourceNode, targetNode ){
			return {};
		}
	};
	
	$.fn.cytoscapewebEdgehandles = function( params ){
		var fn = params;
		
		var functions = {
			destroy: function(){
				var $container = $(this);
				var data = $container.data("cyedgehandles");
				
				if( data == null ){
					return;
				}
				
				data.unbind();
				$container.data("cyedgehandles", {});
				
				return $container;
			},
			
			option: function(name, value){
				var $container = $(this);
				var data = $container.data("cyedgehandles");
				
				if( data == null ){
					return;
				}
				
				var options = data.options;
				
				if( value === undefined ){
					if( typeof name == typeof {} ){
						var newOpts = name;
						options = $.extend(true, {}, defaults, newOpts);
						data.options = options;
					} else {
						return options[ name ];
					}
				} else {
					options[ name ] = value;
				}
				
				return $container;
			},
				
			init: function(){
				var options = $.extend(true, {}, defaults, params); 
				var $container = $(this);
				var svg, cy;
				var handle;
				var line, linePoints;
				var mdownOnHandle = false;
				var grabbingNode = false;
				var hx, hy, hr;
				
				// write options to data
				var data = $container.data("cyedgehandles");
				if( data == null ){
					data = {};
				}
				data.options = options;
				
				function svgIsInCy( svgDomElement ){
					var $ele = $(svgDomElement);
					var inside = false;
					
					$ele.parents().each(function(){
						if( this == $container[0] ){
							inside = true;
						}
					});
					
					return inside;
				}
				
				function safelyRemoveCySvgChild( svgDomElement ){
					if( svgDomElement != null && svgIsInCy( svgDomElement ) ){
						svg.remove( svgDomElement );
					}
				}
				
				function resetToDefaultState(){
//					console.log("resetToDefaultState");

					safelyRemoveCySvgChild( handle );
					safelyRemoveCySvgChild( line );
					
					cy.nodes()
						.removeClass("ui-cytoscapeweb-edgehandles-hover")
						.removeClass("ui-cytoscapeweb-edgehandles-source")
						.removeClass("ui-cytoscapeweb-edgehandles-target")
					;

					linePoints = null;
					
					cy.zooming(true).panning(true);
				}
				
				function makePreview( source, target ){
					makeEdges( true );
				}
				
				function removePreview( source, target ){
					source.edgesWith(target).filter(".ui-cytoscapeweb-edgehandles-preview").remove();
					
					target
						.neighborhood("node.ui-cytoscapeweb-edgehandles-preview")
						.closedNeighborhood(".ui-cytoscapeweb-edgehandles-preview")
						.remove();
					
				}
				
				function makeEdges( preview ){
					
					// console.log("make edges");
					
					var source = cy.nodes(".ui-cytoscapeweb-edgehandles-source");
					var targets = cy.nodes(".ui-cytoscapeweb-edgehandles-target");
					var classes = preview ? "ui-cytoscapeweb-edgehandles-preview" : "";
					
					if( source.size() == 0 || targets.size() == 0 ){
						return; // nothing to do :(
					}
					
					// just remove preview class if we already have the edges
					if( !preview && options.preview ){
						cy.elements(".ui-cytoscapeweb-edgehandles-preview").removeClass("ui-cytoscapeweb-edgehandles-preview");
						return;
					} else {
						// remove old previews
						cy.elements(".ui-cytoscapeweb-edgehandles-preview").remove();
					}
					
					targets.each(function(i, target){
						switch( options.edgeType( source, target ) ){
						case "node":
							
							var p1 = source.position(false);
							var p2 = target.position(false);
							var p = {
								x: (p1.x + p2.x)/2,
								y: (p1.y + p2.y)/2
							};
												
							var interNode = cy.add($.extend( true, {
								group: "nodes",
								position: p
							}, options.nodeParams(source, target) )).addClass(classes);

							cy.add($.extend( true, {
								group: "edges",
								data: {
									source: source.id(),
									target: interNode.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);
							
							cy.add($.extend( true, {
								group: "edges",
								data: {
									source: interNode.id(),
									target: target.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);
							
							break;
							
						case "flat":
						default:
							cy.add($.extend( true, {
								group: "edges",
								data: {
									source: source.id(),
									target: target.id()
								}
							}, options.edgeParams(source, target) )).addClass(classes);
							break;
						}
					});
					
					
				}
				
				$container.cytoscapeweb(function(e){
					cy = this;
					svg = $container.svg("get");
					
					var transformHandler;
					cy.bind("zoom pan", transformHandler = function(){
						safelyRemoveCySvgChild( handle );
					});
					
					var startHandler, hoverHandler, leaveHandler, grabNodeHandler, freeNodeHandler;
					cy.nodes().live("mouseover", startHandler = function(e){
						if( mdownOnHandle || grabbingNode || this.hasClass("ui-cytoscapeweb-edgehandles-preview") ){
							return; // don't override existing handle that's being dragged
							// also don't trigger when grabbing a node
						} 
						
						// console.log("node mover");
						
						var node = this;
						var source = this;
						var p = node.renderedPosition();
						var d = node.renderedDimensions();
						
						// remove old handle
						safelyRemoveCySvgChild( handle );
						
						hx = p.x;
						hy = p.y - d.height/2;
						hr = options.handleSize/2;
						
						// add new handle
						handle = svg.circle(hx, hy, hr, {
							fill: options.handleColor
						});
						var $handle = $(handle);
						
						function mdownHandler(e){
							if( e.button != 0 ){
								return; // sorry, no right clicks allowed 
							}
							
//							console.log("-- mdownHandler %o --", e);
							
							mdownOnHandle = true;
							
							e.preventDefault();
							node.unbind("mouseout", removeHandler);
							$handle.unbind("mouseout", removeHandler);
							
							node.addClass("ui-cytoscapeweb-edgehandles-source");
							
							function doneMoving(dmEvent){
//								console.log("doneMoving %o", dmEvent);
								
								var $this = $(this);
								mdownOnHandle = false;
								$(window).unbind("mousemove", moveHandler);
								
								makeEdges();
								resetToDefaultState();
							}
							
							$(window).one("mouseup blur", doneMoving).bind("mousemove", moveHandler);
							cy.zooming(false).panning(false);
						}
						
						function moveHandler(e){
							// console.log("move");
							
							var x = e.pageX - $container.offset().left;
							var y = e.pageY - $container.offset().top;
							
							safelyRemoveCySvgChild( line );
							
							var style = {
								stroke: options.handleColor,
								strokeWidth: options.handleLineWidth,
								fill: "none",
								"pointer-events": "none"
							};
							
							// draw line based on type
							switch( options.lineType ){
							case "straight":
								
								line = svg.line(hx, hy, x, y, style);
								
								break;
							case "draw":
							default:
								
								if( linePoints == null ){
									linePoints = [ [hx, hy], [x, y] ];
								} else {
									linePoints.push([ x, y ]);
								}
								
								line = svg.polyline(linePoints, style);
								
								break;
							}
							
							
						}
						
						function removeHandler(e){							
							var newTargetIsHandle = e.toElement == handle;
							var newTargetIsNode = e.toElement == node._private.renderer.svg;
							
							if( newTargetIsHandle || newTargetIsNode || mdownOnHandle ){
								return; // don't consider mouseout
							}
							
//							console.log("removeHandler %o", e);
							
							node.unbind("mouseout", removeHandler);
							resetToDefaultState();
						}
						
						node.bind("mouseout", removeHandler);
						$handle.bind("mouseout", removeHandler);
						$handle.bind("mousedown", mdownHandler);
{'fraction_non_alphanumeric': 0.13569776407093292, 'fraction_numerical': 0.002016487752802325, 'mean_word_length': 1.9407045692361353, 'pattern_counts': {'":': 10, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5822893', 'n_tokens_mistral': 8173, 'n_tokens_neox': 4963, 'n_words': 1087}