5

Working with Rappid I encountered an error in IE11 console:

Object doesn't support property or method 'contains'

This error is from an SVGElement not having that method. Same code in Chrome works.

Seems like I need to polyfill for this missing method, but according to MDN docs on contains it is supported from IE9 and up, but is not supported on SVGElement.

Edit: Here is a snippet - try to run in Chrome and in IE11

const joint = window.joint;

let graph = new joint.dia.Graph;

let paper = new joint.dia.Paper({
    width: 1500,   /*200,*/
    height: 1500,  /*200,*/
    el: $('.paper-container'),
    gridSize: 1,
    drawGrid: true,
    model: graph,
    //defaultLink: new joint.shapes.app.Link,
    //defaultConnectionPoint: joint.shapes.app.Link.connectionPoint,
    interactive: { linkMove: false }
});

$('.paper-container').append(paper.el);
paper.render();
    
var member = function(x, y, rank, name, background, textColor) {

    textColor = textColor || "#000";

    var cell = new joint.shapes.org.Member({
        position: { x: x, y: y },
        attrs: {
            '.card': { fill: background, stroke: 'none'},
            '.rank': { text: rank, fill: textColor, 'word-spacing': '-5px', 'letter-spacing': 0},
            '.name': { text: name, fill: textColor, 'font-size': 13, 'font-family': 'Arial', 'letter-spacing': 0 }
        }
    });
    graph.addCell(cell);
    return cell;
};

function link(source, target, breakpoints) {

    var cell = new joint.shapes.org.Arrow({
        source: { id: source.id },
        target: { id: target.id },
        vertices: breakpoints,
        attrs: {
            '.connection': {
                'fill': 'none',
                'stroke-linejoin': 'round',
                'stroke-width': '2',
                'stroke': '#4b4a67'
            }
        }

    });
    graph.addCell(cell);
    return cell;
}

var bart = member(300, 70, 'CEO', 'Bart Simpson', '#30d0c6');
var homer = member(90, 200, 'VP Marketing', 'Homer Simpson', '#7c68fd', '#f1f1f1');
var marge = member(300, 200, 'VP Sales', 'Marge Simpson', '#7c68fd', '#f1f1f1');
var lisa = member(500, 200, 'VP Production' , 'Lisa Simpson', '#7c68fd', '#f1f1f1');
var maggie = member(400, 350, 'Manager', 'Maggie Simpson', '#feb563');
var lenny = member(190, 350, 'Manager', 'Lenny Leonard', '#feb563');
var carl = member(190, 500, 'Manager', 'Carl Carlson', '#feb563');


link(bart, marge, [{x: 385, y: 180}]);
link(bart, homer, [{x: 385, y: 180}, {x: 175, y: 180}]);
link(bart, lisa, [{x: 385, y: 180}, {x: 585, y: 180}]);
link(homer, lenny, [{x:175 , y: 380}]);
link(homer, carl, [{x:175 , y: 530}]);
link(marge, maggie, [{x:385 , y: 380}]);

var rootNode = paper.el.querySelector('.joint-type-org-member');
var card = paper.el.querySelector('.joint-type-org-member .card');
console.log("rootNode.contains = ", rootNode.contains);
console.log("rootNode.contains(card) = ", rootNode.contains(card));
<script src="https://unpkg.com/@babel/polyfill@7.4.4/dist/polyfill.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://resources.jointjs.com/demos/joint/node_modules/lodash/lodash.js"></script>
<script src="https://resources.jointjs.com/demos/joint/node_modules/backbone/backbone.js"></script>

<link href="https://resources.jointjs.com/demos/joint/build/joint.css" rel="stylesheet"/>
<script src="https://resources.jointjs.com/demos/joint/build/joint.js"></script>



<div class="paper-container"></div>
ArielGro
  • 795
  • 1
  • 11
  • 24
  • Please make sure you have added the Polyfill (you found from [the link](https://github.com/FezVrasta/popper.js/issues/515#issuecomment-355064871)) before using the Contains method. I have created a sample using this polyfill, it seems that the contains error disappear. can you post the Enough code to reproduce the problem as in [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). – Zhi Lv Aug 22 '19 at 11:52
  • @ZhiLv-MSFT - thanks for the comment. I will try to get a minimal working example as soon as possible – ArielGro Aug 27 '19 at 05:41
  • @ZhiLv-MSFT - I added a snippet to the question (without the polyfill) and another one to my answer (with the polyfill). Run both snippets on Chrome and on IE11 and see the issue and the solution. Note that in both snippets I included the polyfill.js script before any other scripts – ArielGro Sep 01 '19 at 09:52

2 Answers2

5

Looking for a proper Polyfill I found this one

In case the link doesn't work, here is the code:

SVGElement.prototype.contains = function contains(node) {
    if (!(0 in arguments)) {
        throw new TypeError('1 argument is required');
    }

    do {
        if (this === node) {
            return true;
        }
    } while (node = node && node.parentNode);

    return false;
};

Edit
Here is the snippet from the question along with the polyfill suggested

const joint = window.joint;

let graph = new joint.dia.Graph;

let paper = new joint.dia.Paper({
    width: 1500,   /*200,*/
    height: 1500,  /*200,*/
    el: $('.paper-container'),
    gridSize: 1,
    drawGrid: true,
    model: graph,
    //defaultLink: new joint.shapes.app.Link,
    //defaultConnectionPoint: joint.shapes.app.Link.connectionPoint,
    interactive: { linkMove: false }
});

$('.paper-container').append(paper.el);
paper.render();
    
var member = function(x, y, rank, name, background, textColor) {

    textColor = textColor || "#000";

    var cell = new joint.shapes.org.Member({
        position: { x: x, y: y },
        attrs: {
            '.card': { fill: background, stroke: 'none'},
            '.rank': { text: rank, fill: textColor, 'word-spacing': '-5px', 'letter-spacing': 0},
            '.name': { text: name, fill: textColor, 'font-size': 13, 'font-family': 'Arial', 'letter-spacing': 0 }
        }
    });
    graph.addCell(cell);
    return cell;
};

function link(source, target, breakpoints) {

    var cell = new joint.shapes.org.Arrow({
        source: { id: source.id },
        target: { id: target.id },
        vertices: breakpoints,
        attrs: {
            '.connection': {
                'fill': 'none',
                'stroke-linejoin': 'round',
                'stroke-width': '2',
                'stroke': '#4b4a67'
            }
        }

    });
    graph.addCell(cell);
    return cell;
}

var bart = member(300, 70, 'CEO', 'Bart Simpson', '#30d0c6');
var homer = member(90, 200, 'VP Marketing', 'Homer Simpson', '#7c68fd', '#f1f1f1');
var marge = member(300, 200, 'VP Sales', 'Marge Simpson', '#7c68fd', '#f1f1f1');
var lisa = member(500, 200, 'VP Production' , 'Lisa Simpson', '#7c68fd', '#f1f1f1');
var maggie = member(400, 350, 'Manager', 'Maggie Simpson', '#feb563');
var lenny = member(190, 350, 'Manager', 'Lenny Leonard', '#feb563');
var carl = member(190, 500, 'Manager', 'Carl Carlson', '#feb563');



link(bart, marge, [{x: 385, y: 180}]);
link(bart, homer, [{x: 385, y: 180}, {x: 175, y: 180}]);
link(bart, lisa, [{x: 385, y: 180}, {x: 585, y: 180}]);
link(homer, lenny, [{x:175 , y: 380}]);
link(homer, carl, [{x:175 , y: 530}]);
link(marge, maggie, [{x:385 , y: 380}]);


if (window.SVGElement && !SVGElement.prototype.contains) {
  SVGElement.prototype.contains = function (node) {
    if (!(0 in arguments)) {
      throw new TypeError('1 argument is required');
    }

    do {
      if (this === node) {
        return true;
      }
    } while (node = node && node.parentNode);

    return false;
  };
}

var rootNode = paper.el.querySelector('.joint-type-org-member');
var card = paper.el.querySelector('.joint-type-org-member .card');
console.log("rootNode.contains = ", rootNode.contains);
console.log("rootNode.contains(card) = ", rootNode.contains(card));
<script src="https://unpkg.com/@babel/polyfill@7.4.4/dist/polyfill.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://resources.jointjs.com/demos/joint/node_modules/lodash/lodash.js"></script>
<script src="https://resources.jointjs.com/demos/joint/node_modules/backbone/backbone.js"></script>

<link href="https://resources.jointjs.com/demos/joint/build/joint.css" rel="stylesheet"/>
<script src="https://resources.jointjs.com/demos/joint/build/joint.js"></script>



<div class="paper-container"></div>
ArielGro
  • 795
  • 1
  • 11
  • 24
  • Do you mean `while (node == node && node.parentNode)` instead of `while (node = node && node.parentNode)` ? – Hugo Oct 27 '20 at 14:28
  • @Hugo - no. it is not what I mean. First, the code is taken from a link check that link. Second, the way it is written it means that `node` gets the value of `node.parentNode` if `node` is defined, and once it isn't defined, we exit the loop. Third, in your version, `node == node && node.parentNode` is equivalent to `true && node.parentNode` and that is redundent... Hope it is clearer now. I hope I'm not coming out aggressive in my reply - writing is harder than talking ;) – ArielGro Oct 28 '20 at 10:40
  • Okay thanks for clearing up! Just ran into lint errors when I tried this but I see now - thank you :) – Hugo Oct 28 '20 at 11:03
  • @Hugo - sure thing.. what lint error did you get? which linter are you using? – ArielGro Oct 28 '20 at 23:53
  • @ArielGo I'm vue-cli-service lint, it suggested adding an extra bracket around the while condition, prefer rest parameters and other really minor things, code work still works - thanks – Hugo Oct 29 '20 at 10:56
0

Here is also another polyfill that is slightly simpler. That seems to work for me on IE11

if (!SVGElement.prototype.contains) {
   SVGElement.prototype.contains = HTMLDivElement.prototype.contains;
}

I found this polyfill here

Liem
  • 730
  • 8
  • 15