Clone Ports ID

by Roman Bruckner

HTML

<html>
<head>
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/3.4.4/joint.css" />
</head>
<body>
      <!-- content -->
      <div id="paper"></div>

      <!-- dependencies -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.4.0/backbone.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/3.4.4/joint.js"></script>
    
    </body>
</html>

JavaScript

// NOTE!:
// graph.cloneSubgraph() won't work because it won't change source and target port id.
// ui.Clipboard won't work because of cloneSubgraph()

const graph = new joint.dia.Graph({}, {
  cellNamespace: joint.shapes
});
const paper = new joint.dia.Paper({
  el: document.getElementById('paper'),
  width: 600,
  height: 600,
  gridSize: 20,
  model: graph,
  async: true,
  sorting: joint.dia.Paper.sorting.APPROX,
  cellViewNamespace: joint.shapes
});

const Rect = joint.shapes.standard.Rectangle.define('Rect', {
    ports: {
        items: [{}, {}]
    }
}, {
    initialize: function(options) {
        if (!options || !options.id) {
            if (!options) options = {};
            const id = options.id = this.generateId();
            this.set('id', id, { silent: true });
        }
        this._initializePorts();
        joint.dia.Cell.prototype.initialize.call(this, options);
    },
    _isValidPortId: function(id) {
        return (typeof id === 'string') && id.startsWith(this.id);
        // return id !== null && id !== undefined && !joint.util.isObject(id);
    },
    generatePortId() {
        return `${this.id}:${this.generateId()}`;
    },
    // Note: this change can be added to the JointJS right now
    // The existing ID can not be passed to the constructor of the clone
    clone: function(opt) {

        opt = opt || {};

        if (!opt.deep) {                    
            // Shallow cloning.
            var clone =  new this.constructor(joint.util.omit(this.attributes, ['id', 'embeds', 'parent']));
            // var clone = Backbone.Model.prototype.clone.apply(this, arguments);
            // We don't want the clone to have the same ID as the original.
            // clone.set('id', this.generateId());
            // A shallow cloned element does not carry over the original embeds.
            // clone.unset('embeds');
            // And can not be embedded in any cell
            // as the clone is not part of the graph.
            //...