MediaWiki:VisNetwork.js

From KIproBatt Wiki
Revision as of 07:01, 15 March 2022 by Simon Stier (talk | contribs)

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
$(document).ready(function() {

    $.getScript('https://unpkg.com/vis-network/standalone/umd/vis-network.min.js').done(function() {
    	var pathId = 0;
    	var newNodes = {};
    	var editNodes = {};
    	var editDeletedEdges = {};
    	var editDeletedNodes = {};
    	
    	$(".visNetworkGraph").each(function(index) {
        if ($('.visNetworkGraph').length) { //check if div element(s) exist
            var input = JSON.parse(this.innerHTML);
			
            // create an array with nodes
            var nodes = new vis.DataSet([]);
            // create an array with edges
            var edges = new vis.DataSet([]);
            //colors for the graph
            var colors = [];
            var oldGroups = {};
			var givenDiv = this;
			givenDiv.style.position = "relative";
			givenDiv.style.display = "inline-block";
			

			
            function getColor() {
                return "hsl(" + 360 * Math.random() + ',' +
                    (25 + 70 * Math.random()) + '%,' +
                    (85 + 10 * Math.random()) + '%)';
            }

            var h = Math.random();
            var golden = 0.618033988749895;
            function randomHSL() {
            	h += golden;
            	h %= 1;
            	//~~(360 * Math.random())
                return "hsla(" + (360 * h) + "," +
                    "70%," +
                    "80%,1)";
            }

            for (var i = 0; i < input.properties.length; i++) {
                colors.push(randomHSL());
            }

            function isLabelSet(id) {
                node = nodes.get(id);
                if (node === null) return false;
                else return id;
            }

            //var colors = ['#ff7878', '#73ff77', '#e878ff', '#ffae57', '#80f8ff', '#ffff75', '#adadad', '#b482ff'];

            nodes.add({
                id: input.root,
                label: input.root, //todo: query display title
                color: '#6dbfa9'
            });

            //Creates API query Url with the given root and properties
            function createUrl(root, properties) {
                var url = `/w/api.php?action=ask&query=[[${encodeURIComponent(root)}]]`;
                var propertiesVar = '';
                for (var i = 0; i < properties.length; i++) {
                    propertiesVar += '|?' + encodeURIComponent(properties[i]);

                }

                url = url + propertiesVar + '&format=json';
                return url;
            }

            //Makes an API call with the given parameters and adds the results to the nodes and edges datasets.
            //With a given nodeID the edges are set to the nodeID, else they are set to the root node.
            function fetchData(root, properties, nodeID, setGroup, setColor) {
                fetch(createUrl(root, properties))
                    .then(response => response.json())
                    .then(data => {
                    	if (!nodeID && root){ //first query on root node
                    		var rootNode = nodes.get(root);
                    		rootNode.url = data.query.results[root].fullurl;
                    		if (data.query.results[root].displaytitle) rootNode.label = data.query.results[root].displaytitle;
                    	}
                        for (var i = 0; i < properties.length; i++) {
                            for (var j = 0; j < data.query.results[root].printouts[properties[i]].length; j++) {
                            
                            	
                            	//define colors
                                if(!(properties[i] in legendColors) && setColor) {legendColors[properties[i]] = colors[i]; }
                                else {setColor = legendColors[properties[i]]; colors[i] = legendColors[properties[i]]; colors[i] = legendColors[properties[i]];}
                                //define id and label. use displaytitle if available. Use string representation of non-page properties
                                var id = "";
                                var label = "";
                                if (data.query.results[root].printouts[properties[i]][j].fulltext) id = data.query.results[root].printouts[properties[i]][j].fulltext;
                                else if(data.query.results[root].printouts[properties[i]][j].value) id = '' + data.query.results[root].printouts[properties[i]][j].value + ' ' + data.query.results[root].printouts[properties[i]][j].unit;  
                                else id = data.query.results[root].printouts[properties[i]][j].toString();
                                if (data.query.results[root].printouts[properties[i]][j].displaytitle) label = data.query.results[root].printouts[properties[i]][j].displaytitle;
                                if (label === "") label = id;
								
                                if (isLabelSet(id) === false) {

                                    if (setGroup && setColor) {
                                        nodes.add({
                                            id: id,
                                            label: label,
                                            color: setColor,
                                            group: setGroup[0],
                                            hidden: false,
                                            url: data.query.results[root].printouts[properties[i]][j].fullurl,
                                            oncontext: true,
                                        });
                                        oldGroups["" + id] = setGroup[0];
                                    } else {
                                        nodes.add({
                                            id: id,
                                            label: label,
                                            color: colors[i],
                                            group: properties[i],
                                            hidden: false,
                                            url: data.query.results[root].printouts[properties[i]][j].fullurl
                                        });
                                        oldGroups["" + id] = properties[i];
                                    }
                                    if (nodeID) {
                                        edges.add({
                                            from: nodeID,
                                            to: id,
                                            label: properties[i],
                                            color: colors[i],
                                            group: properties[i]
                                        });
                                    } else {
                                        edges.add({
                                            from: input.root,
                                            to: id,
                                            label: properties[i],
                                            color: colors[i],
                                            group: properties[i]
                                        });
                                    }
                                    
                                } else {
                                    edges.add({
                                        from: nodeID,
                                        to: isLabelSet(id),
                                        label: properties[i],
                                        color: setColor,
                                        group: properties[i]
                                    });
                                }
                            }
                        }
                        network.setOptions(options);
                        network.body.emitter.emit('_dataChanged');
                        network.redraw();
                        
                    });
            }
            fetchData(input.root, input.properties);
            // create a network
            var container = this; //document.getElementById("visNetworkGraph");
            var data = {
                nodes: nodes,
                edges: edges,
            };
            var options = {
                width: "100%",
                height: "100%",
                interaction: {
                    hover: true
                },
                manipulation: {
                    enabled: true,
                    editEdge: false,
                    deleteNode: function (data, callback) {deleteSelectedNode(data, callback)}.bind(this),
                    deleteEdge: function (data, callback) {deleteSelectedEdge(data, callback)}.bind(this),
                    addNode: function (data, callback) {
                    	
        // filling in the popup DOM elements
        document.getElementById("node-operation").innerText = "Add Node";
        dragElement(document.getElementById("node-popUp"));
        editNode(data, clearNodePopUp, callback);
      },
      addEdge: function (data, callback) {
        if (data.from == data.to) {
          var r = confirm("Do you want to connect the node to itself?");
          if (r != true) {
            callback(null);
            return;
          }
        }
        document.getElementById("edge-operation").innerText = "Add Edge";
        dragElement(document.getElementById("edge-popUp"));
        editEdgeWithoutDrag(data, callback);
      },
          },
                edges: {
                    arrows: {
                        to: {
                            enabled: true
                        },
                        //from:{enabled: true}
                    }
                },
                groups: {
                    useDefaultGroups: false
                },
                physics: {
                    stabilization: {
                        enabled: true,
                    },
                    barnesHut: {
                        gravitationalConstant: -40000,
                        centralGravity: 0,
                        springLength: 0,
                        springConstant: 0.5,
                        damping: 1,
                        avoidOverlap: 0
                    },
                    maxVelocity: 5
                },

            };
            //Creates groups in the options and sets them all to hidden:false.
            for (var i = 0; i < input.properties.length; i++) {
                options.groups[input.properties[i]] = {
                    hidden: false
                };
            }
            var network = new vis.Network(container, data, options);
            



function getAllEdgesBetween(node1,node2) {
    return edges.get().filter(function (edge) {
        return (edge.from === node1 && edge.to === node2 )|| (edge.from === node2 && edge.to === node1);
    });
}

function getAllCombs(arrays){
    var numberOfCombs = 1;
    for(var i=0; i<arrays.length; i++){
        numberOfCombs = numberOfCombs * arrays[i].length;
    }
    var allCombs = new Array(numberOfCombs);
    for(var i=0; i<allCombs.length; i++){
        allCombs[i] = new Array(arrays.length);
    }
    
    for(var i=0; i<arrays.length; i++){
        var current = arrays[i];
        for(var c=0; c<numberOfCombs; c++){
 
            for(var j=0; j<current.length; j++){
                allCombs[c][i] = current[c%current.length];
                
            }
        }
    }
	
    return allCombs;
}
 
function getEdgePathsForPath(path){
  var arraysOfEdgesForNodeInPath = [];
  for(var i=1; i<path.length; i++){
    var edgesBetween = getAllEdgesBetween(path[i-1], path[i]);
    var localedgesBetween = edgesBetween.slice();
    arraysOfEdgesForNodeInPath.push(localedgesBetween);
  }
  var allEdgePaths = getAllCombs(arraysOfEdgesForNodeInPath);
return allEdgePaths;
}

function reverseLabel(label){
  if(label[0] == "-"){
    return label.substring(1);
  }
  else{
    return "-" + label;
  }
}

function getEdgeLabelStringsForPath(path){
  var allEdgePaths = getEdgePathsForPath(path);
  var allStrings = new Array(allEdgePaths.length);
  for(var i=0; i<allEdgePaths.length; i++){
    var s = "";
    for(var j=0; j<allEdgePaths[i].length;j++){
      
      var edge = allEdgePaths[i][j];
      var label = edge.label;
      var nodeId1 = path[j];
      var nodeId2 = path[j+1];
      if(edge.to == nodeId1 && edge.from == nodeId2){
        label = reverseLabel(label);
      }
      if(j == (allEdgePaths[i].length - 1)){
         s = s + label;
      }
      else{
         s = s + label + ".";
      }
     
      
    }
    allStrings[i] = s;
  }
  return allStrings;
}

function getAllStringsForAllPaths(paths){
  var arrayOfAllStrings = [];
  for(var i=0; i<paths.length;i++){
    var path = paths[i];
    var allStrings = getEdgeLabelStringsForPath(path);
    arrayOfAllStrings.push(allStrings);
  }
return arrayOfAllStrings;
}



function removeItem(arr, value) {
  var index = arr.indexOf(value);
  if (index > -1) {
    arr.splice(index, 1);
  }
  return arr;
}




function findAllPaths(startNode, endNode){
    var visitedNodes = [];
    var currentPath = [];
    var allPaths =  [];
    dfs(startNode, endNode, currentPath, allPaths, visitedNodes);
    return allPaths;
}

function dfs(start, end, currentPath, allPaths, visitedNodes){
    if(visitedNodes.includes(start)) return;
    visitedNodes.push(start);
    currentPath.push(start);
    if(start == end){
    	var localCurrentPath = currentPath.slice();
        allPaths.push(localCurrentPath);
        removeItem(visitedNodes, start);
        currentPath.pop();
        return;
    }
    
    var neighbours = network.getConnectedNodes(start);
    for(var i = 0; i < neighbours.length; i++){    
        var current = neighbours[i];
        dfs(current, end, currentPath, allPaths, visitedNodes);
    }

    currentPath.pop();
    removeItem(visitedNodes, start);

}





            
            

            //This function deletes all children of a given node.
            function getAllReachableNodesTo(nodeId, excludeIds, reachableNodes) {

                if (reachableNodes.includes(nodeId) || excludeIds.includes(nodeId)) { return;}
                var children = network.getConnectedNodes(nodeId);
                reachableNodes.push(nodeId);
                for (var i = 0; i < children.length; i++) {
                    getAllReachableNodesTo(children[i], excludeIds, reachableNodes);
                    //if(excludeIds.includes(children[i]))continue;
                    //reachableNodes.push(children[i]);
                }
            }
            
            function deleteNodesChildren(nodeId, deleteEdge) {
                var excludedIds = [];
                if(deleteEdge === true){
                	console.log("deleteEdge true")
                }else{
                	excludedIds.push(nodeId);
                }
                var reachableNodesTo = [];
                getAllReachableNodesTo(input.root, excludedIds, reachableNodesTo);
                var nodesToDelete = [];
                var allIds = nodes.getIds();

                for (var i = 0; i < allIds.length; i++) {
                    if (reachableNodesTo.includes(allIds[i])) continue;
                    if (allIds[i] == nodeId) {
                    	deleteEdges(nodeId);
                    	continue;
                    }
                    nodesToDelete.push(allIds[i]);
                    deleteEdges(allIds[i]);
                    nodes.remove(allIds[i]);
                    delete oldGroups["" + allIds[i]];
                    delete objClickedProps["" + allIds[i]];
                }

                return nodesToDelete;
            }
            
			function deleteEdges(nodeID){
				var fromEdges = edges.get({
                    filter: function (item) {
                        return item.from == nodeID;
                    }
                });
                
        		for(var j = 0; j < fromEdges.length; j++){
        			edges.remove(fromEdges[j]);
        		}
			}
			var nodesClicked = [];
			var tip = '<p><strong>Hinweis:</strong> Um sich einen Pfad zwischen zwei Knoten ausgeben zu lassen, <em>Strg</em> gedrückt halten und die gewünschten zwei Knoten mit der <em>linken Maustaste</em> anklicken. </p>'
			this.insertAdjacentHTML('afterbegin', tip);
			
			network.on("click", function(params) {
				
                if (params.nodes[0] && params.event.srcEvent.ctrlKey) {
                	
                	if(nodesClicked.length < 2){
                		nodesClicked.push(params.nodes[0]);
                	}
                	if(nodesClicked.length == 2 && nodesClicked[0] != nodesClicked[1]){
                		var foundPaths = findAllPaths(nodesClicked[0],nodesClicked[1]);
                		//.querySelector('[id^="poll-"]').id;
                		if(document.querySelectorAll('[id^="fullPath"]')){
                			for(var i=0; i < document.querySelectorAll('[id^="fullPath"]').length; i++){
                				document.querySelectorAll('[id^="fullPath"]')[i].remove();
                			}
                		}
                		var element = '<div id="fullPath'+ pathId +'"></div>'
						givenDiv.children[0].insertAdjacentHTML('afterend', element);

                		var allStringsArray = getAllStringsForAllPaths(foundPaths);
                		
                		var stringDiv = givenDiv.querySelector('#fullPath' + pathId);
                		
                		if(foundPaths.length == 1){stringDiv.innerHTML = "<strong>Gefundener Pfad:</strong><br>"}else{stringDiv.innerHTML = "<strong>Gefundene Pfade:</strong><br>"}
                		
                		for(var s=0; s<foundPaths.length; s++){
                			if(foundPaths.length == 1){var pathNumb = ""}else{var pathNumb = "<strong>" + (s+1) + ". Pfad:</strong> <br>"}
                			
                			stringDiv.innerHTML += pathNumb + "<strong>Knoten: </strong>";
						  for(var t=0; t<foundPaths[s].length; t++){
						    var currentFoundPath = foundPaths[s][t];
						    
						    if(t == (foundPaths[s].length - 1)){
						         stringDiv.innerHTML = stringDiv.innerHTML + currentFoundPath + " ";
						    }
						    else{
						         stringDiv.innerHTML = stringDiv.innerHTML + currentFoundPath + " - ";
						    }
						  }
						  stringDiv.innerHTML += "<br>"
						  stringDiv.innerHTML += "<strong>Kanten:</strong> "
						  for(var t=0; t<allStringsArray[s].length; t++){
						    var currentString = allStringsArray[s][t];
						    var currentFoundPath = foundPaths[s][t];
						    var stringDiv = givenDiv.querySelector('#fullPath' + pathId);
						    stringDiv.innerHTML = stringDiv.innerHTML + currentString;
						  }
						  stringDiv.innerHTML += "<br>"
						}

                		nodesClicked = [];
						
                	}
                	if(nodesClicked[0] === nodesClicked[1] || nodesClicked.length > 2){
                	nodesClicked = [];
                	}
                	
                	
                }
				pathId++;
			});

			$(document).keyup(function(event) {
			   if(!event.ctrlKey){
			   	nodesClicked = [];
			   }
			});
			
			
			
			
			

            var contextCreatedProps = [];

            network.on("doubleClick", function(params) {
				
                if (params.nodes[0]) {
                	
                	var conManNodes = network.getConnectedNodes(params.nodes[0], 'to');
                	
	                var onlyConManNodes = true;
	                for(var i = 0; i < conManNodes.length;i++){
	                
	                
	                if(!(nodes.get(conManNodes[i]).oncontext || nodes.get(conManNodes[i]).manually)){
	                	onlyConManNodes = false;
	                }
	                }
                	
                	//Node is expanded -> delete it and all nodes related to its expansion
                    if (network.getConnectedNodes(params.nodes[0]).length > 1 && onlyConManNodes == false) {
                        deleteNodesChildren(params.nodes[0]);
                        for (var i = 0; i < contextCreatedProps.length; i++) {
                            var noNodesInNetwork = true;
                            for (var j = 0; j < nodes.getIds().length; j++) {
                                if (contextCreatedProps[i] == nodes.get(nodes.getIds()[j]).group) {
                                    noNodesInNetwork = false;
                                }
                            }
                            if (noNodesInNetwork === true) {
                                givenDiv.querySelector('#' + contextCreatedProps[i]).remove();
                                contextCreatedProps.splice(contextCreatedProps.indexOf(contextCreatedProps[i]), 1);
                                i--;
                            }
                        }
                        delete objClickedProps["" + params.nodes[0]];
                        
                        //nodesArray.splice(nodesArray.indexOf(params.nodes[0]), 1);
                    } else {
                    	//Node is unexpanded -> expand it
                        var nodeById = nodes.get(params.nodes[0]);
                        fetchData(nodeById.id, input.properties, params.nodes[0]);
                        //nodesArray.push(params.nodes[0]);
                    }

                }
            });
            
            function newGroup(node, legendGroup) {
                
                nodes.update({
                    id: node,
                    group: legendGroup
                });


                var connectedNodes = network.getConnectedNodes(node, 'to');

                for (var i = 0; i < connectedNodes.length; i++) {
                    newGroup(connectedNodes[i], legendGroup);
                }
            }

			//Checks, if a node has a path over visible edges to the root node.
			//If not, the nodes gets hidden
			function setNodeVisibilityByVisiblePath(nodeId, rootNodeId){
				if (nodeId == rootNodeId) return true; //root is always visible
				var node = nodes.get(nodeId);
				if (node.visited) return !node.hidden //prevent circles. ToDo: Reuse results between runs
				node.visited = true;
				node.hidden = true;
				var connectedEdgesIds = network.getConnectedEdges(nodeId);
				var connectedEdges = edges.get(connectedEdgesIds);
				connectedEdges.forEach(function(edge) {
					if (edge.hidden) return; //don't follow hidden edges
                    var connectedNodesIds = network.getConnectedNodes(edge.id);
                    var connectedNodes = nodes.get(connectedNodesIds);
                    connectedNodes.forEach(function(connectedNode) {
                    	if (connectedNode.id == nodeId) return; //prevent self evaluation
                    	if (setNodeVisibilityByVisiblePath(connectedNode.id, rootNodeId)) {
                    		node.hidden = false; //set node visible, if at least one connected node is visible
                    	}
                    });
                });
                node.physics = !node.hidden;//disable physics for hidden nodes
                return !node.hidden;
			}

            function legendFunctionality() {

                var legendGroup;
                var group;
                var nodeChildren;
                legendGroup = this.parentNode.childNodes[1].innerHTML;
                
                
                var strategy = "strategy2"
                
                if (strategy == "strategy2"){
                	//A node is visible if at least one path over visible edges to the root node exists.
                	options.groups[legendGroup].hidden = !options.groups[legendGroup].hidden; //toggle state
                	if(options.groups[legendGroup].hidden) this.parentNode.childNodes[1].style.background = '#FFFFFF';
                	else this.parentNode.childNodes[1].style.background = '#DEF';
                	//update all edges
                	edges.forEach(function(edge) {
                    	edge.hidden = options.groups[edge.label].hidden;
                    	edge.physics = !edge.hidden;
                	});
                	//reset nodes
                    nodes.forEach(function(node) {
                    	node.hidden = false;
                    	node.physics = !node.hidden;
                    	node.visited = false;
                    });
                    //check each node
                    nodes.forEach(function(node) {
                    	setNodeVisibilityByVisiblePath(node.id, input.root)
                    	//reset visited state. Todo: Reuse visited nodes between runs
                    	nodes.forEach(function(node) {
                    		node.visited = false;
                    	});
                    });
                }
                
                network.setOptions(options);
                network.body.emitter.emit('_dataChanged');
                network.redraw();

                var allFalse = Object.keys(options.groups).every(function(k) {
                    if (k === 'useDefaultGroups') {
                        return true
                    }
                    return options.groups[k].hidden === false
                });
                if (allFalse === true) {
                    /*oldGroups = {};*/
                }
            };

            var legendDiv = document.createElement("div");
            this.append(legendDiv);
            legendDiv.style.width = '100%';
            legendDiv.style.position = 'relative';
            legendDiv.style.display = 'inline-block';
            
            legendDiv.id = "legendContainer";
            var legendColors = {};
            for (var i = 0; i < input.properties.length; i++) {
                legendColors[input.properties[i]] = colors[i];
                var propertyContainer = document.createElement("div");
                var propertyColor = document.createElement("div");
                var propertyName = document.createElement("div");

                propertyContainer.className = "legend-element-container";
                propertyContainer.id = input.properties[i];

                propertyColor.className = "color-container";

                propertyName.className = "name-container";

                propertyColor.style.float = "left";
                propertyName.style.float = "left";
                propertyColor.style.border = "1px solid black";
                propertyName.style.border = "1px solid black";

                propertyColor.style.background = colors[i];
                propertyColor.innerHTML = "";
                propertyName.innerHTML = input.properties[i];

                propertyColor.style.width = "30px";
                propertyColor.style.height = "30px";
                propertyName.style.height = "30px";
                propertyName.style.background = '#DEF';

                //propertyName.text-align = 'center';
                propertyContainer.paddinng = '5px 5px 5px 5px';

                propertyName.addEventListener("click", legendFunctionality);
                propertyColor.addEventListener("click", legendFunctionality);

                legendDiv.append(propertyContainer);
                propertyContainer.append(propertyColor);
                propertyContainer.append(propertyName);

            }

            var ul = document.createElement("ul");
            ul.className = 'custom-menu';
            document.body.append(ul);
            objClickedProps = {};
            objColors = {};
            var start = 0;
            

            network.on("oncontext", function(params) {
            	params.event.preventDefault();
            	var timeNow = Date.now();
            	var timeDiff = timeNow - start
            	if(timeDiff > 300){
            		start = Date.now();
                console.log(nodes.get(network.getNodeAt({ x: params.pointer.DOM.x, y: params.pointer.DOM.y })));
                
				//console.log(edges.get(network.getEdgeAt({ x: params.pointer.DOM.x, y: params.pointer.DOM.y })));
                
                $('.custom-menu').each( function(index) {
                while (this.lastElementChild) {
                    this.removeChild(this.lastElementChild);
                }});
                if(!(network.getEdgeAt({ x: params.pointer.DOM.x, y: params.pointer.DOM.y }) && network.getNodeAt({ x: params.pointer.DOM.x, y: params.pointer.DOM.y }))){
                if(edges.get(network.getEdgeAt({ x: params.pointer.DOM.x, y: params.pointer.DOM.y })).from){
                	params.event.preventDefault();
      
                	if(edges.get(network.getEdgeAt({ x: params.pointer.DOM.x, y: params.pointer.DOM.y })).label == 'Category'){
                			
                				var li = document.createElement("li");
                        		li.innerHTML = '' + '\uD83D\uDD17' + ' ' + edges.get(network.getEdgeAt({ x: params.pointer.DOM.x, y: params.pointer.DOM.y })).to;

                                li.addEventListener("click", function NewTab() {
                                 window.open('/wiki/' + edges.get(network.getEdgeAt({ x: params.pointer.DOM.x, y: params.pointer.DOM.y })).to);
                                });
                                ul.prepend(li);}else{
                                var li = document.createElement("li");
                        		li.innerHTML = '' + '\uD83D\uDD17' + ' ' + edges.get(network.getEdgeAt({ x: params.pointer.DOM.x, y: params.pointer.DOM.y })).label;

                                li.addEventListener("click", function NewTab() {
                                 window.open('/wiki/' + 'Property:' + edges.get(network.getEdgeAt({ x: params.pointer.DOM.x, y: params.pointer.DOM.y })).label);
                                });
                                ul.prepend(li);
                                }
                        $(".custom-menu").finish().toggle(100).css({
                        top: params.event.pageY + "px",
                        left: params.event.pageX + "px",
                        display: "block"
                    }); 
                }
                }
                if (network.getNodeAt({
                        x: params.pointer.DOM.x,
                        y: params.pointer.DOM.y
                    })) {
                    params.event.preventDefault();
					
					const nodeID = nodes.get(network.getNodeAt({x: params.pointer.DOM.x,y: params.pointer.DOM.y})).id;
					const subject = nodeID.split("#")[0];
					var subObject = "";
					if (nodeID.split("#")[1]) {
						subObject = nodeID.split("#")[1].replace(" ", "_");
					}
					//inverse properties are only available in html format
					const query = `/w/api.php?action=smwbrowse&browse=subject&params={"subject":"${encodeURIComponent(subject)}","subobject":"${subObject}","options":{"showAll":"true"}, "ns":0, "type":"html"}&format=json`;

                    fetch(query) 
                        .then(response => response.json())
                        .then(data => {
                        	var selected_node =  nodes.get(network.getNodeAt({
                            	x: params.pointer.DOM.x,
                            	y: params.pointer.DOM.y
                        	}));
                        	if (selected_node.url){
                        		
                        		var li = document.createElement("li");
                        		li.innerHTML = '' + '\uD83D\uDD17' + ' ' + selected_node.label;

                                li.addEventListener("click", function NewTab() {
                                 window.open(selected_node.url);
                                });
                                
                                ul.prepend(li);
                        		
                        	}
                        	var page_properties = [];
                        	$html = $(data.query);
							$html.find("div.smwb-propvalue").each(function(){
								$prop = $(this).find("div.smwb-prophead a");
								//var propName = $prop.text();
								//var propName = $prop.attr('title').replace("Property:", "");
								var propName = "";
								if ($prop.attr('title') === "Special:Categories") propName += "Category";
								else propName += $prop.attr('href').split("Property:")[1].split("&")[0];
								page_properties.push(propName);
								//console.log(propName);
								$(this).find("div.smwb-propval span.smwb-value").each(function(){
									var value = $(this).find("a").attr("title");
									//console.log("-> " + value);
								});
							})
							$html.find("div.smwb-ipropvalue").each(function(){
								$prop = $(this).find("div.smwb-prophead a");
								//var propName = $prop.text();
								//var propName = $prop.attr('title').replace("Property:", "");
								var propName = "-";
								if ($prop.attr('title') === "Special:Categories") propName += "Category";
								else propName += $prop.attr('href').split("Property:")[1].split("&")[0];
								page_properties.push(propName);
								//console.log(propName);
								$(this).find("div.smwb-propval span.smwb-ivalue").each(function(){
									var value = $(this).find("a").attr("title");
									//console.log("-> " + value);
								});
							})
							for (var i = 0; i < page_properties.length; i++) {
	                            if (!page_properties[i].startsWith("_")) {
	                                 var li = document.createElement("li");
	                                 li.dataset.action = page_properties[i].replaceAll('_',' ');
	                                 li.innerHTML = page_properties[i].replaceAll('_',' ');
	                                 ul.append(li);
	                            }
	                        }
	                        
                        	/* old: use json result */
                        	/*
                        	var page_properties = data.query.data; //normal page
                        	if (selected_node.id.includes('#')) { //subobject
                        		for (var i = 0; i < data.query.sobj.length; i++) { 
                        			if (data.query.sobj[i].subject.endsWith(selected_node.id.split('#').pop().replace(' ',''))){
                        				page_properties = data.query.sobj[i].data
                        				break;
                        			}
                        		}
                        	}
	                        for (var i = 0; i < page_properties.length; i++) {
	                            if (!page_properties[i].property.startsWith("_")) {
	                                 var li = document.createElement("li");
	                                 li.dataset.action = page_properties[i].property.replaceAll('_',' ');
	                                 li.innerHTML = page_properties[i].property.replaceAll('_',' ');
	                                 ul.append(li);
	                            }
	                        }*/

                            $(".custom-menu li").click(function() {

                                var clickedProperty = [$(this).attr("data-action")]
                                
                                var clickedPropertyColor = randomHSL();
                                
                                if(!(clickedProperty in legendColors)){legendColors[clickedProperty] = clickedPropertyColor; }else{clickedPropertyColor = legendColors[clickedProperty]; }

                                

                                if (objColors[clickedProperty]) {
                                    clickedPropertyColor = objColors[clickedProperty]
                                } else {
                                    objColors[clickedProperty] = clickedPropertyColor;
                                }


                                if (!objClickedProps[nodes.get(network.getNodeAt({
                                        x: params.pointer.DOM.x,
                                        y: params.pointer.DOM.y
                                    })).id]) {
                                    objClickedProps[nodes.get(network.getNodeAt({
                                        x: params.pointer.DOM.x,
                                        y: params.pointer.DOM.y
                                    })).id] = new Array();
                                }



                                if (!objClickedProps["" + nodes.get(network.getNodeAt({
                                        x: params.pointer.DOM.x,
                                        y: params.pointer.DOM.y
                                    })).id].includes(clickedProperty[0])) {
                                    fetchData(nodes.get(network.getNodeAt({
                                        x: params.pointer.DOM.x,
                                        y: params.pointer.DOM.y
                                    })).id, clickedProperty, nodes.get(network.getNodeAt({
                                        x: params.pointer.DOM.x,
                                        y: params.pointer.DOM.y
                                    })).id, clickedProperty, clickedPropertyColor)
                                    objClickedProps["" + nodes.get(network.getNodeAt({
                                        x: params.pointer.DOM.x,
                                        y: params.pointer.DOM.y
                                    })).id].push(clickedProperty[0]);
                                }

                                if (!(contextCreatedProps.includes(clickedProperty[0]) || input.properties.includes(clickedProperty[0]) /*|| legendColors[clickedProperty[0]]*/ )) {

                                    contextCreatedProps.push(clickedProperty[0]);

                                    options.groups[clickedProperty] = {
                                        hidden: false
                                    };

                                    var propertyContainer = document.createElement("div");
                                    var propertyColor = document.createElement("div");
                                    var propertyName = document.createElement("div");
                                    

                                    propertyContainer.className = "legend-element-container";
                                    propertyContainer.id = clickedProperty;

                                    propertyColor.className = "color-container";

                                    propertyName.className = "name-container";

                                    propertyColor.style.float = "left";
                                    propertyName.style.float = "left";
                                    propertyColor.style.border = "1px solid black";
                                    propertyName.style.border = "1px solid black";
                                    propertyContainer.style = "margin-right: 5px";


                                    propertyColor.style.background = clickedPropertyColor;
                                    propertyColor.innerHTML = "";
                                    propertyName.innerHTML = clickedProperty;

                                    propertyColor.style.width = "30px";
                                    propertyColor.style.height = "30px";
                                    propertyName.style.height = "30px";
                                    propertyName.style.background = '#DEF';

                                    //propertyName.text-align = 'center';
                                    propertyName.margin = 'auto 5px auto 5px';

                                    propertyName.addEventListener("click", legendFunctionality);
                                    propertyColor.addEventListener("click", legendFunctionality);


                                    legendDiv.append(propertyContainer);
                                    propertyContainer.append(propertyColor);
                                    propertyContainer.append(propertyName);

                                }

                                $(".custom-menu").hide(100);
                            });
                        });

                    $(".custom-menu").finish().toggle(100).css({
                        top: params.event.pageY + "px",
                        left: params.event.pageX + "px",
                        display: "block"
                    });
                }
            }
            });
            // If the document is clicked somewhere
            $(document).bind("mousedown", function(e) {

                // If the clicked element is not the menu
                if (!$(e.target).parents(".custom-menu").length > 0) {

                    // Hide it
                    $(".custom-menu").hide(100);
                }
            });
           
function editNode(data, cancelAction, callback) {
	var newNodeActive = true;
  document.getElementById("node-label").value = data.label;
  document.getElementById("node-saveButton").onclick = saveNodeData.bind(
    this,
    data,
    callback
  );
  document.getElementById("node-cancelButton").onclick = cancelAction.bind(
    this,
    callback
  );
  //document.getElementById("node-popUp")

  	
  	$('canvas').on('click', function(e) {
  		if(newNodeActive === true){
    $("#node-popUp").css({
                        top: e.pageY + "px",
                        left: e.pageX + "px",
                        display: "block"
                        });}
                        newNodeActive = false;
                        
});

}

// Callback passed as parameter is ignored
function clearNodePopUp() {
  document.getElementById("node-saveButton").onclick = null;
  document.getElementById("node-cancelButton").onclick = null;
  document.getElementById("node-popUp").style.display = "none";
}

function cancelNodeEdit(callback) {
  clearNodePopUp();
  callback(null);
}

function saveNodeData(data, callback) {
  data.label = document.getElementById("node-label").value;
  data.id = document.getElementById("node-label").value;
  data.hidden = false;
  data.physics = false;
  document.getElementById("node-label").value = "";
  clearNodePopUp();
  callback(data);
}

function editEdgeWithoutDrag(data, callback) {
	var newEdgeActive = true;
  // filling in the popup DOM elements
  document.getElementById("edge-label").value = data.label;
    /*if(data.from === "H.1"){
  	console.log("here");
  	return;}*/
  document.getElementById("edge-saveButton").onclick = saveEdgeData.bind(
    this,
    data,
    callback
  );
  document.getElementById("edge-cancelButton").onclick = cancelEdgeEdit.bind(
    this,
    callback
  );
  
  $('canvas').on('click', function(e) {
  		if(newEdgeActive === true){
    $("#edge-popUp").css({
                        top: e.pageY + "px",
                        left: e.pageX + "px",
                        display: "block"
                        });}
                        newEdgeActive = false;
});
  //document.getElementById("edge-popUp").style.display = "block";
}

function clearEdgePopUp() {
  document.getElementById("edge-saveButton").onclick = null;
  document.getElementById("edge-cancelButton").onclick = null;
  document.getElementById("edge-popUp").style.display = "none";
}

function cancelEdgeEdit(callback) {
  clearEdgePopUp();
  callback(null);
}

function isLabelReversed(label){
  if(label[0] == "-"){
    return true;
  }
  else{
    return false;
  }
}






var pageBool;
async function pageExists(id){
	
	await fetch('/w/api.php?action=parse&page='+ id +'&prop=wikitext&format=json')
                        .then(response => response.json())
                        .then(data => {
                        	
                        	if(data.error){
                        		pageBool = false;
                        	}else{
                        		pageBool = true;
                        	}
                        	
                        })
	return pageBool;
}

var wikiText = "";
var semantic = "";
async function editWikiText(node){
		await fetch('/w/api.php?action=parse&page='+ node +'&prop=wikitext&format=json')
                        .then(response => response.json())
                        .then(data => {
                        wikiText = data.parse.wikitext['*'];
                        semantic = "";
						if(wikiText.search(/(\{\{Semantic\/[^}]*[\r\n]*\}[\r\n]*\})/g) >= 0){
						//var edgeStringFound = wikiText.search(re) >= 0;
						const found = wikiText.match(/(\{\{Semantic\/[^}]*[\r\n]*\}[\r\n]*\})/g);
						
						var newWikiText = wikiText;
						for(var i=0; i<found.length;i++){
							if(i == found.length-1){
								semantic += found[i];
								newWikiText = newWikiText.replace(/(\{\{Semantic\/[^}]*[\r\n]*\}[\r\n]*\}[\r\n]*\}[\r\n]*\})/g, "");
							}else{
								semantic += found[i];
								newWikiText = newWikiText.replace(found[i], "");
							}
						}
						wikiText = newWikiText;
						
						


						}
});
return [semantic, wikiText];
}



async function saveEdgeData(data, callback) {
  if (typeof data.to === "object") data.to = data.to.id;
  if (typeof data.from === "object") data.from = data.from.id;
  
  data.label = document.getElementById("edge-label").value;
  options.groups[data.label] = {hidden: false};
  var toNode = nodes.get(data.to);
  var fromNode = nodes.get(data.from);
  fromNode.physics = true;
  toNode.physics = true;
  delete fromNode.x;
  delete fromNode.y;
  delete toNode.x;
  delete toNode.y;
  if(!toNode.group){toNode.group = data.label}
  if(!fromNode.group){fromNode.group = data.label}
  if(legendColors[data.label]){data.color = legendColors[data.label];}else{data.color = randomHSL(); }
  if(!toNode.color){toNode.color = data.color; toNode.manually = true;}
  if(!fromNode.color){fromNode.color = data.color; fromNode.manually = true;}
  
  if(!(contextCreatedProps.includes(data.label) || input.properties.includes(data.label))){
  	contextCreatedProps.push(data.label);
	var propertyContainer = document.createElement("div");
    var propertyColor = document.createElement("div");
    var propertyName = document.createElement("div");
    

    propertyContainer.className = "legend-element-container";
    propertyContainer.id = data.label;

    propertyColor.className = "color-container";

    propertyName.className = "name-container";

    propertyColor.style.float = "left";
    propertyName.style.float = "left";
    propertyColor.style.border = "1px solid black";
    propertyName.style.border = "1px solid black";
    propertyContainer.style = "margin-right: 5px";


    propertyColor.style.background = data.color;
    propertyColor.innerHTML = "";
    propertyName.innerHTML = data.label;

    propertyColor.style.width = "30px";
    propertyColor.style.height = "30px";
    propertyName.style.height = "30px";
    propertyName.style.background = '#DEF';

    //propertyName.text-align = 'center';
    propertyName.margin = 'auto 5px auto 5px';

    propertyName.addEventListener("click", legendFunctionality);
    propertyColor.addEventListener("click", legendFunctionality);


    legendDiv.append(propertyContainer);
    propertyContainer.append(propertyColor);
    propertyContainer.append(propertyName);
  	legendColors[data.label] = data.color;
  }
  if(isLabelReversed(data.label)){
  	if(await pageExists(fromNode.id) === false){
  		if(!(newNodes[fromNode.id])){
  			newNodes[fromNode.id] = '' + '{{Semantic/Element' + 
									'|label=' + fromNode.label +
									'|description=test' + 
									'|relations=';
  		}
  
  	}

  	if(await pageExists(toNode.id) === true){
  	var splitWikiText = await editWikiText(toNode.id);
  		if(editNodes[toNode.id]){
  			editNodes[toNode.id] += '' + '{{Semantic/Link'+
								'|property=' + reverseLabel(data.label) +
								'|value=' + fromNode.id +
								'}}' + '';
  			
  		}else{
  			if(splitWikiText[0]){
  				editNodes[toNode.id] = splitWikiText[1] + splitWikiText[0] + '{{Semantic/Link'+
								'|property=' + reverseLabel(data.label) +
								'|value=' + fromNode.id +
								'}}' + '';
  			}else{
	  		editNodes[toNode.id] = splitWikiText[1] + '{{Semantic/Element' + 
									'|label=' + toNode.label +
									'|description=test' + 
									'|relations='+ 
	  								'{{Semantic/Link'+
									'|property=' + reverseLabel(data.label) +
									'|value=' + fromNode.id +
									'}}' + '';
  			}
  		}
  	}else{
  		if(newNodes[toNode.id]){
  			newNodes[toNode.id] += '' + '{{Semantic/Link'+
								'|property=' + reverseLabel(data.label) +
								'|value=' + fromNode.id +
								'}}' + '';
  		}else{
	  		newNodes[toNode.id] = '' + '{{Semantic/Element' + 
									'|label=' + toNode.label +
									'|description=test' + 
									'|relations={{Semantic/Link'+
									'|property=' + reverseLabel(data.label) +
									'|value=' + fromNode.id +
									'}}'+
									'';
  		}
  	}

  }else{
  	
  	if(await pageExists(toNode.id) === false){
  		if(!(newNodes[toNode.id])){
  		newNodes[toNode.id] = '' + '{{Semantic/Element' + 
									'|label=' + toNode.label +
									'|description=test' + 
									'|relations=';
  		}
  	}
  	if(await pageExists(fromNode.id) === true){
  		var splitWikiText = await editWikiText(fromNode.id);
  		if(editNodes[fromNode.id]){
  			editNodes[fromNode.id] += '' + '{{Semantic/Link'+
									'|property=' + data.label +
									'|value=' + toNode.id +
									'}}' + '';
  		}else{
  			if(splitWikiText[0]){
  				editNodes[fromNode.id] = splitWikiText[1] +  splitWikiText[0] + '{{Semantic/Link'+
									'|property=' + data.label +
									'|value=' + toNode.id +
									'}}' + '';
  			}else{
	  		editNodes[fromNode.id] = splitWikiText[1] + '{{Semantic/Element' + 
									'|label=' + fromNode.label +
									'|description=test' + 
									'|relations='+
	  								'{{Semantic/Link'+
									'|property=' + data.label +
									'|value=' + toNode.id +
									'}}' + '';
  			}
  		}
  	}else{
  		if(newNodes[fromNode.id]){
  			newNodes[fromNode.id] += '' + '{{Semantic/Link'+
									'|property=' + data.label +
									'|value=' + toNode.id +
									'}}' + '';
  			
  		}else{
	  		newNodes[fromNode.id] = '' + '{{Semantic/Element' + 
									'|label=' + fromNode.label +
									'|description=test' + 
									'|relations={{Semantic/Link'+
									'|property=' + data.label +
									'|value=' + toNode.id +
									'}}'+
									'';
									
  		}
  	}

  }

  //console.log(toNode);
  //console.log(fromNode);
  
	console.log(editNodes);
	console.log(newNodes);
  
  clearEdgePopUp();
  callback(data);
  network.setOptions(options);
  network.body.emitter.emit('_dataChanged');
  network.redraw();
}
    		var saveBtn= document.createElement("button");
            saveBtn.addEventListener("click", saveGraphChanges);
            saveBtn.innerHTML = "Speichern";
            saveBtn.style.width = "auto";
            saveBtn.style.height = "auto";

			givenDiv.appendChild(saveBtn);
			 function saveGraphChanges() {
				var alertString = "";
				OO.ui.confirm( 'Änderungen übernehmen?' ).done( async function ( confirmed ) {
				    if ( confirmed ) {
				for (const [key, value] of Object.entries(newNodes)) {
				  var params = {
							action: 'edit',
							title: '' + key,
							appendtext: '' + value + '}}',
							format: 'json'
						},
						api = new mw.Api();
					
					await api.postWithToken( 'csrf', params ).done( function ( data ) {
						console.log( data );
						alertString += "Seite " + key + " erstellt!\r\n"
					} );
				}
				
				for (const [key, value] of Object.entries(editNodes)) {
				  var params = {
							action: 'edit',
							title: '' + key,
							text: '' + value + '}}',
							format: 'json'
						},
						api = new mw.Api();
					
					await api.postWithToken( 'csrf', params ).done( function ( data ) {
						console.log( data );
						alertString += "Seite " + key + " bearbeitet!\r\n"
					} );
				}
				
				for (const [key, value] of Object.entries(editDeletedEdges)) {
				  var params = {
							action: 'edit',
							title: '' + key,
							text: '' + value,
							format: 'json'
						},
						api = new mw.Api();
					
					await api.postWithToken( 'csrf', params ).done( function ( data ) {
						console.log( data );
						alertString += "Auf der Seite " + key + " wurde ein Attribut gelöscht!\r\n"
					} );
				}
				
				for (const [key, value] of Object.entries(editDeletedNodes)) {
				  var params = {
									action: 'delete',
									title: '' + key,
									format: 'json'
								},
								api = new mw.Api();
							await api.postWithToken( 'csrf', params ).done( function ( data ) {
								console.log( data );
								alertString += "Seite " + key + " wurde gelöscht!\r\n"
							} );
				}
				console.log( alertString );
				// Example: Customize the displayed actions at the time the window is opened.
				var messageDialog = new OO.ui.MessageDialog();
				
				// Create and append a window manager.
				var windowManager = new OO.ui.WindowManager();
				$( 'body' ).append( windowManager.$element );
				
				// Add the dialog to the window manager.
				windowManager.addWindows( [ messageDialog ] );
				
				// Configure the message dialog when it is opened with the window manager's openWindow() method.
				
				windowManager.openWindow( messageDialog, {
				  title: 'Folgende Änderugnen wurden übernommen:',
				  message: '' + alertString,
				  verbose: true,
				  actions: [
				    {
				      action: 'accept',
				      label: 'Okay',
				      flags: 'primary'
				    }
				  ]
				});
				/*OO.ui.alert( "" + alertString ).done( function () {
				    console.log( alertString );
				} );*/
				
				    } else {
				        
				    }
				    
				} );
				

			}
			



function deleteSelectedNode(data, callback){
	console.log(contextCreatedProps);
	deleteNodesChildren(data.nodes[0]);
	nodes.remove(data.nodes[0]);
                        for (var i = 0; i < contextCreatedProps.length; i++) {
                            var noNodesInNetwork = true;
                            for (var j = 0; j < nodes.getIds().length; j++) {
                                if (contextCreatedProps[i] == nodes.get(nodes.getIds()[j]).group) {
                                	
                                    noNodesInNetwork = false;
                                }
                            }
                            if (noNodesInNetwork === true) {
                            	
                                givenDiv.querySelector('#' + contextCreatedProps[i]).remove();
                                contextCreatedProps.splice(contextCreatedProps.indexOf(contextCreatedProps[i]), 1);
                                i--;
                            }
                        }

                        
    					delete oldGroups["" + data.nodes[0]];
                        
                        delete objClickedProps["" + data.nodes[0]];
                        callback();
                        document.querySelector('.vis-delete').remove();
						editDeletedNodes[""+data.nodes[0]] = "";
						delete newNodes[""+data.nodes[0]];
						delete editNodes[""+data.nodes[0]];
						console.log(editDeletedNodes);

}

async function deleteSelectedEdge(data, callback){
	var edgeToNode = edges.get(data.edges[0]).to;
	var edgeFromNode = edges.get(data.edges[0]).from;
	var edgeLabel = edges.get(data.edges[0]).label;
	console.log(edgeLabel);
	edges.remove(data.edges[0]);
	deleteNodesChildren(edgeToNode, true);
	deleteNodesChildren(edgeFromNode, true);
	
	for (var i = 0; i < contextCreatedProps.length; i++) {
                            var noNodesInNetwork = true;
                            for (var j = 0; j < nodes.getIds().length; j++) {
                                if (contextCreatedProps[i] == nodes.get(nodes.getIds()[j]).group) {
                                	
                                    noNodesInNetwork = false;
                                }
                            }
                            if (noNodesInNetwork === true) {
                            	
                                givenDiv.querySelector('#' + contextCreatedProps[i]).remove();
                                contextCreatedProps.splice(contextCreatedProps.indexOf(contextCreatedProps[i]), 1);
                                i--;
                            }
                        }
	
	if(edgeLabel[0] == "-"){
	if(await pageExists(edgeToNode) === true){
		await fetch('/w/api.php?action=parse&page='+ edgeToNode +'&prop=wikitext&format=json')
                        .then(response => response.json())
                        .then(data => {
                        var wikiText = data.parse.wikitext['*'];
						console.log(wikiText);
						
                        var edgeString = `(\{\{Semantic\/Link[\\r\\n]*\\|[\\r\\n]*property=`+reverseLabel(edgeLabel)+`[\\r\\n]*\\|[\\r\\n]*value=`+edgeFromNode+`[\\r\\n]*\\}[\\r\\n]*\\}[\\r\\n]*)`
						//var edgeString = '(\\{\\{Semantic\/Element[^}]*[\\r\\n]*\\}[\\r\\n]*\\}[\\r\\n]*[\\r\\n]*\\}[\\r\\n]*\\})'
						var re = new RegExp(edgeString,"g");
                        
                        var edgeStringFound = wikiText.search(re) >= 0;
                        
                        if(edgeStringFound){
                        	if(editDeletedEdges[""+ edgeToNode]){
                        	var newWikiText = editDeletedEdges[""+ edgeToNode].replace(re, "");	
                        	editDeletedEdges[""+ edgeToNode] = newWikiText;
                        	}else{
                        	var newWikiText = wikiText.replace(re, "");
                        	console.log(newWikiText)
                        	editDeletedEdges[""+ edgeToNode] = newWikiText;
                        	}
    						
                        }
                        
                        if(newNodes[""+edgeToNode]){
                        	
                        	var newWikiText = newNodes[""+edgeToNode].replace(re, "");
                        	newNodes[""+edgeToNode] = newWikiText;

                        }
                        
                        if(editNodes[""+edgeToNode]){
                        	
                        	var newWikiText = editNodes[""+edgeToNode].replace(re, "");
                        	editNodes[""+edgeToNode] = newWikiText;
                        	
                        }

                        });}else{
                        	if(network.getConnectedNodes(edgeToNode).length == 0){
                        	delete newNodes[""+edgeToNode];
                        	}else{
                        		var edgeString = `(\{\{Semantic\/Link[\\r\\n]*\\|[\\r\\n]*property=`+reverseLabel(edgeLabel)+`[\\r\\n]*\\|[\\r\\n]*value=`+edgeFromNode+`[\\r\\n]*\\}[\\r\\n]*\\}[\\r\\n]*)`;

                        		var re = new RegExp(edgeString,"g");
                        		var wikiText = newNodes[""+edgeToNode];
                        		var newWikiText = wikiText.replace(re,"");
                        		newNodes[""+edgeToNode] = newWikiText;
                        	}
                        }
	}else{
		if(await pageExists(edgeFromNode) === true){
	await fetch('/w/api.php?action=parse&page='+ edgeFromNode +'&prop=wikitext&format=json')
                        .then(response => response.json())
                        .then(data => {
                        	var wikiText = data.parse.wikitext['*'];
						console.log(wikiText);
						
                        var edgeString = `(\{\{Semantic\/Link[\\r\\n]*\\|[\\r\\n]*property=`+edgeLabel+`[\\r\\n]*\\|[\\r\\n]*value=`+edgeToNode+`[\\r\\n]*\\}[\\r\\n]*\\}[\\r\\n]*)`;
						//var edgeString = '(\\{\\{Semantic\/Element[^}]*[\\r\\n]*\\}[\\r\\n]*\\}[\\r\\n]*[\\r\\n]*\\}[\\r\\n]*\\})'
						var re = new RegExp(edgeString,"g");
                        
                        var edgeStringFound = wikiText.search(re) >= 0;
                        
                        if(edgeStringFound){
                        	if(editDeletedEdges[""+ edgeFromNode]){
                        	var newWikiText = editDeletedEdges[""+ edgeFromNode].replace(re, "");	
                        	editDeletedEdges[""+ edgeFromNode] = newWikiText;
                        	}else{
                        	var newWikiText = wikiText.replace(re, "");
                        	console.log(newWikiText)
                        	editDeletedEdges[""+ edgeFromNode] = newWikiText;
                        	}
    						
                        }
                        
                        if(newNodes[""+edgeFromNode]){
                        	
                        	var newWikiText = newNodes[""+edgeFromNode].replace(re, "");
                        	newNodes[""+edgeFromNode] = newWikiText;

                        }
                        
                        if(editNodes[""+edgeFromNode]){
                        	
                        	var newWikiText = editNodes[""+edgeFromNode].replace(re, "");
                        	editNodes[""+edgeFromNode] = newWikiText;
                        	
                        }

                        	
                        });}else{
                        	if(network.getConnectedNodes(edgeFromNode).length == 0){
                        	delete newNodes[""+edgeFromNode];
                        	}else{
                        		var edgeString = `(\{\{Semantic\/Link[\\r\\n]*\\|[\\r\\n]*property=`+edgeLabel+`[\\r\\n]*\\|[\\r\\n]*value=`+edgeToNode+`[\\r\\n]*\\}[\\r\\n]*\\}[\\r\\n]*)`;

                        		var re = new RegExp(edgeString,"g");
                        		var wikiText = newNodes[""+edgeFromNode];
                        		var newWikiText = wikiText.replace(re,"");
                        		newNodes[""+edgeFromNode] = newWikiText;
                        	}
                        	console.log(newNodes);
                        }
                        
	}
		
	
	
	
	console.log(editDeletedEdges);
	//nodes.remove(edges.get(data.edges[0]).to);
	
	callback(data);
	document.querySelector('.vis-delete').remove();
	console.log(objClickedProps);
    console.log(oldGroups);
}

var editHtml = '' + 

'<div id="node-popUp">' + 
'  <span id="node-operation" style="cursor: move;">node</span> <br />' + 
'  <table style="margin: auto">' + 
'    <tbody>' + 
'      <tr>' + 
'        <td>label</td>' + 
'        <td><input id="node-label" value="" /></td>' + 
'      </tr>' + 
'    </tbody>' + 
'  </table>' + 
'  <input type="button" value="save" id="node-saveButton" />' + 
'  <input type="button" value="cancel" id="node-cancelButton" />' + 
'</div>' +
'' + 
'<div id="edge-popUp">' + 
'  <span id="edge-operation" style="cursor: move;">edge</span> <br />' + 
'  <table style="margin: auto">' + 
'    <tbody>' + 
'      <tr>' + 
'        <td>label</td>' + 
'        <td><input id="edge-label" value="" /></td>' + 
'      </tr>' + 
'    </tbody>' + 
'  </table>' + 
'  <input type="button" value="save" id="edge-saveButton" />' + 
'  <input type="button" value="cancel" id="edge-cancelButton" />' + 
'</div>' +
'';




var editHtmlDiv = document.createElement("div");
editHtmlDiv.innerHTML = editHtml;
document.body.appendChild(editHtmlDiv);







//dragElement(document.getElementById("node-popUp"));
//dragElement(document.getElementById("edge-popUp"));

function dragElement(elmnt) {
  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  if (document.getElementById(elmnt.id)) {
  	
    // if present, the header is where you move the DIV from:
    document.getElementById("node-operation").onmousedown = dragMouseDown;
    document.getElementById("edge-operation").onmousedown = dragMouseDown;
  } else {
    // otherwise, move the DIV from anywhere inside the DIV:
    elmnt.onmousedown = dragMouseDown;
  }

  function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    // call a function whenever the cursor moves:
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    // set the element's new position:
    elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  }

  function closeDragElement() {
    // stop moving when mouse button is released:
    document.onmouseup = null;
    document.onmousemove = null;
  }
}


        }
    	});
    });

});