Only allow Links to be copied if se

Is there a quick way within GoJS to only allow links that are contiguously connected by selected Nodes to be copied? Otherwise, if a Link is selected in isolation from other nodes that aren’t selected, they will not be copied. Because right now, i’m having an issue with isolated Links being copied and pasted into the diagram at times. If I select 2 nodes or a network of nodes that are connected by links, I can copy and paste them with their connected arcs duplicated successfully. However, if an isolated link gets selected among the list without a connecting selected node, than that link will be copied+pasted with undefined “from/to” pointers, because their related nodes weren’t selected prior to the copying operation.

I know i can set copyable to the linkTemplate to false, but that will disable copying+pasting of Links completely. However, I want to copy links that are contigously connected by other selected nodes. Must copyable per Link be set/reset manually everytime ChangedSelection is being done, and i have to perform my own manual Graph search code for each selected node to determine which arcs are copyable? Is there a manual before “pre-copy-to-clipboard/pre-paste” event that I can hook into to modify what Links gets copied or not? Short of, perhaps, manually removing isolated links after the pasting is done?.

Actually, this might be a little safer:

Override copyParts so that it modifies the collection, by removing all the links you do not want to copy. That way you aren’t copying parts and then deleting them immediately.

myDiagram.copyParts = function(coll, diagram, check) {
  var toRemove = [];
  coll.each(function(p) {
    if (p instanceof go.Link && (p.fromNode === null || p.toNode === null)) toRemove.push(p);
  });
  for (var i = 0; i < toRemove.length; i++) {
    coll.remove(toRemove[i])
  }
  return go.Diagram.prototype.copyParts.call(this, coll, diagram, check);
};

However…
This method doens’t trigger when I use CTRL+C selection, or CTRL+drag selection… I need to account for both cases.

Ok, this method handles CTRL+C case. Is this overwrite implementation correct? Do i need to return a value? From the docs, it seems like there’s no return data type, so I didn’t return anything.

myDiagram.commandHandler.copyToClipboard = function(coll) {

    var toRemove = [];
    
      coll.each(function(p) {
    
        if (p instanceof go.Link && (p.fromNode === null || !p.fromNode.isSelected || p.toNode === null || !p.toNode.isSelected )) toRemove.push(p);
      });
      for (var i = 0; i < toRemove.length; i++) {
        
        coll.remove(toRemove[i]);
      }
    
    go.CommandHandler.prototype.copyToClipboard.call(this, coll);
}

Hmmm…this seems to “solve” the case for CTRL+drag as well…even though when i console traced the method, it doesn’t seem to run at all for CTRL+drag situations.

That’s odd because I was testing using CTRL+C, but I do see that there’s an issue with CTRL+drag

Yes, CTRL+drag does not call copyToClipboard or use the clipboard.

Try this instead:

myDiagram.copyParts = function(coll, diagram, check) {
  var map = go.Diagram.prototype.copyParts.call(this, coll, diagram, check);
  var toRemove = [];
  map.each(function(kvp) {
    var p = kvp.key;
    if (p instanceof go.Link && (p.fromNode === null || p.toNode === null)) toRemove.push(p);
  });
  for (var i = 0; i < toRemove.length; i++) {
    map.remove(toRemove[i])
  }
  return map;
};

Like i said, the function copyParts doesn’t run at all for me, whether i use Ctrl+alt drag or CTRL+c. Fyi, i’m using v1.6.1 though, not the latest 1.6.9. Not sure if there were any changes regarding this aspect.

Anyway, there doesn’t seem to be any problems anymore for the code ‘fix’ i did though (using commahdHandler overwrite instead). Just strangely works atm.

Oops, I’m very sorry, I was using a method that isn’t overridable in the compiled library.

A much simpler solution, now that I look at it, is just to override canCopy. You could override it for Links and then call the base Part functionality like this:

go.Link.prototype.canCopy = function() {
  if ((this.fromNode === null || this.toNode === null)) return false;
  return go.Part.prototype.canCopy.call(this);
}

(Overriding it for all parts would require subclassing Part, but you can avoid that in your case. Subclassing example if you need it)

One really should not be modifying the prototypes of any of the GoJS or JavaScript classes.

There are other examples of subclassing the Link class in various samples. Basically:

  function CustomLink()
    go.Link.call(this);
  };
  go.Diagram.inherit(CustomLink, go.Link);

  CustomLink.prototype.canCopy = function() {
    if (this.fromNode === null || !this.fromNode.isSelected ||
       this.toNode === null || !this.toNode.isSelected) return false;
    return go.Link.prototype.canCopy.call(this);
  };

And then use CustomLink instead of go.Link in your link template(s).