<commit_before>(function() {
  var canvas = this.__canvas = new fabric.Canvas('c', { selection: false });
  fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
  var active, isDown, origX, origY;
  var mode = 'select';
  var id = 'a';

  document.getElementById("select").onclick = function() {
    document.getElementById(mode).style.border = '2px solid white';
    mode = 'select';
    this.style.border = '2px solid black';
  };

  document.getElementById("component").onclick = function() {
    document.getElementById(mode).style.border = '2px solid white';
    mode = 'component';
    this.style.border = '2px solid black';
  };

  document.getElementById("sync").onclick = function() {
    document.getElementById(mode).style.border = '2px solid white';
    mode = 'sync';
    this.style.border = '2px solid black';
  };

  document.getElementById("downloadsvg").onclick = function () {
    var a = document.getElementById("download");
    a.download = "reo.svg";
    a.href = 'data:image/svg+xml;base64,' + window.btoa(canvas.toSVG());
    a.click();
  };

  document.getElementById("downloadpng").onclick = function () {
    var a = document.getElementById("download");
    a.download = "reo.png";
    a.href = canvas.toDataURL('image/png');
    a.click();
  };

  function makeCircle(left, top) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 5,
      radius: 12,
      fill: '#fff',
      stroke: '#000',
      hasBorders: false,
      hasControls: false,
      class: 'node',
      component: main
    });

    // give the node an identifier and increment it for the next node
    c.set({'id': id});
    id = ((parseInt(id, 36)+1).toString(36)).replace(/[0-9]/g,'a');

    // these are the channels that are connected to this node
    c.linesIn = [];
    c.linesOut = [];

    return c;
  } //makeCircle

  function drawLine(x1, y1, x2, y2) {
    // create a line...
    var line = new fabric.Line([x1, y1, x2, y2], {
      fill: '#000',
      stroke: '#000',
      strokeWidth: 5,
      hasBorders: false,
      hasControls: false,
      selectable: false,
      hoverCursor: 'default',
      class: 'line'
    });

    // ...an arrowhead...
    var a = new fabric.Triangle({
      left: x2,
      top: y2,
      width: 20,
      height: 20,
      angle: calcArrowAngle(x1,y1,x2,y2),
      fill: '#000',
      hasBorders: false,
      hasControls: false,
      selectable: false,
      hoverCursor: 'default'
    });

    // ...and two circles
    var c1 = makeCircle(x1,y1);
    var c2 = makeCircle(x2,y2);

    // ...link them all together
    line.set({'arrow': a, 'circle1': c1, 'circle2': c2});
    a.set({'line': line});
    c1.linesOut.push(line);
    c2.linesIn.push(line);
    updateNode(c1);
    updateNode(c2);

    // magic
    updateLine(line, 2);

    // draw everything on the canvas
    canvas.add(line,a,c1,c2);
    canvas.renderAll();

    return line;
  } //drawLine

  function updateNode(node) {
    if (node.linesIn.length) {
      if (node.linesOut.length)
        node.set({'nodetype':'mixed','fill':'#ff5'});
      else
        node.set({'nodetype':'drain','fill':'#f55'});
    }
    else
      node.set({'nodetype':'source','fill':'#55f'});
  }

  function updateLine(line, end) {
    // we first have to reset the end coordinates
    var x1 = line.circle1.get('left');
    var y1 = line.circle1.get('top');
    var x2 = line.circle2.get('left');
    var y2 = line.circle2.get('top');
    line.set({'x1':x1, 'y1':y1, 'x2':x2, 'y2':y2});

    if (x1 == x2 && y1 == y2) {
      line.arrow.set({'left': line.get('x2'), 'top': line.get('y2')});
    }
    else {
      // calculate the position of the arrow
      var length = Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2));
      length = length - 22;//circle2.get('radius') - circle2.get('stroke');
      var x = Math.atan(Math.abs(y1-y2)/Math.abs(x1-x2));
      if (end) {
        if (x2 > x1) {
          line.set({'x2': x1 + length * Math.cos(x)});
        } else {
          line.set({'x2': x1 - length * Math.cos(x)});
        }
        if (y2 > y1) {
          line.set({'y2': y1 + length * Math.sin(x)});
        } else {
          line.set({'y2': y1 - length * Math.sin(x)});
        }
      }
      line.arrow.set({'left': line.get('x2'), 'top': line.get('y2')});
      var angle = calcArrowAngle(line.get('x1'), line.get('y1'), line.get('x2'), line.get('y2'));
      line.arrow.set({'angle': angle});
    }

    canvas.renderAll();
  } //updateLine

  // calculate the correct angle for the arrowhead
  function calcArrowAngle(x1, y1, x2, y2) {
    var angle = 0, x, y;
    x = (x2 - x1);
    y = (y2 - y1);

    if (x === 0) {
      angle = (y === 0) ? 0 : (y > 0) ? Math.PI / 2 : Math.PI * 3 / 2;
    } else if (y === 0) {
      angle = (x > 0) ? 0 : Math.PI;
    } else {
      angle = (x < 0) ? Math.atan(y / x) + Math.PI : (y < 0) ? Math.atan(y / x) + (2 * Math.PI) : Math.atan(y / x);
    }

    return ((angle * 180 / Math.PI) + 90) % 360;
  } //calcArrowAngle

  function enumerate() {
    document.getElementById('text').innerHTML = "";
    canvas.forEachObject(function(obj) {
      if (obj.class == 'node')
        document.getElementById('text').innerHTML += obj.id + " ";
    });
  }

  function updateText() {
    var s = '';
    // TODO: traverse id's
    canvas.forEachObject(function(obj) {
      if (obj.type == "line")
        s += 'sync(' + obj.circle1.id + ',' + obj.circle2.id + ') ';
    });
    document.getElementById('text').innerHTML = s;
  }

  function snapToComponent(node,comp) {
    var right = comp.left + comp.width;
    var bottom = comp.top + comp.height;
    if (node.left > right) // right side
      node.set({'left': right});
    if (node.left < comp.left) // left side
      node.set({'left': comp.left});
    if (node.top > bottom) // bottom side
      node.set({'top': bottom});
    if (node.top < comp.top) // top side
      node.set({'top': comp.top});
    node.setCoords();
    for (i = 0; i < node.linesIn.length; i++) {
      updateLine(node.linesIn[i], 2);
    }
    for (i = 0; i < node.linesOut.length; i++) {
      updateLine(node.linesOut[i], 1);
    }
  }

  function snapOutComponent(node, comp, connectednode) {
    var right = comp.left + comp.width;
    var bottom = comp.top + comp.height;
    if (connectednode.left > right) // right side
      node.set({left: right});
    if (connectednode.left < comp.left) // left side
      node.set({left: comp.left});
    if (connectednode.top > bottom) // bottom side
      node.set({top: bottom});
    if (connectednode.top < comp.top)
      node.set({top: comp.top});
    node.setCoords();
  }

  canvas.on('object:moving', function(e) {
    var p = e.target;
    p.setCoords();
  }); //object:moving

  canvas.on('object:added', function(e) {
    updateText();
  }); //object:added

  canvas.on('object:removed', function(e) {
    updateText();
  }); //object:added

  canvas.on('mouse:down', function(e) {
    isDown = true;
    if (canvas.getActiveObject())
      return;
    var pointer = canvas.getPointer(e.e);
    if (mode == 'sync') {
      var line = drawLine(pointer.x,pointer.y,pointer.x,pointer.y);
      snapToComponent(line.circle1,main);
      canvas.setActiveObject(line.circle2);
      updateLine(line,2);
    }
    if (mode == 'component') {
      origX = pointer.x;
      origY = pointer.y;
      var comp = drawComponent(pointer.x,pointer.y,pointer.x,pointer.y);
      canvas.setActiveObject(comp);
    }
  }); //mouse:down

  canvas.on('mouse:move', function(e){
    if (!isDown)
      return;
    var p = canvas.getActiveObject();
    if (!p)
      return;
    var pointer = canvas.getPointer(e.e);
    if (p.class == 'component') {
      if (origX > pointer.x)
        p.set({left:pointer.x});
      if (origY > pointer.y)
        p.set({top:pointer.y});
      p.set({width:Math.abs(origX - pointer.x)});
      p.set({height:Math.abs(origY - pointer.y)});
      p.setCoords();
      p.label.set({left: p.left + (p.width/2), top: p.top - 15});

    }
    if (p.class == 'node') {
      p.set({'left': pointer.x, 'top': pointer.y});
      p.setCoords();
      canvas.forEachObject(function(obj) {
        if (obj !== p && obj.get('type') === "circle" && p.intersectsWithObject(obj)) {
          if(Math.abs(p.left-obj.left) < 10 && Math.abs(p.top-obj.top) < 10) {
            p.set({'left': obj.getLeft(), 'top': obj.getTop()});
            p.setCoords();
          }
        }
      });
      for (i = 0; i < p.linesIn.length; i++)
        updateLine(p.linesIn[i], 2);
      for (i = 0; i < p.linesOut.length; i++)
        updateLine(p.linesOut[i], 1);
    }
    canvas.renderAll();
  }); //mouse:move

  canvas.on('mouse:up', function(e){
    isDown = false;
    var p = canvas.getActiveObject();
    if (p) {
      if (p.class == 'node') {
        p.setCoords();
        p.set({component:main});
        canvas.forEachObject(function(obj) {
          if (!obj || obj.get('id') == p.get('id') || (obj.get('class') !== 'node' && obj.get('class') !== 'component'))
            return;
          if (p.intersectsWithObject(obj)) {
            if (obj.get('class') == 'node') {
              if(Math.abs(p.left-obj.left) < 10 && Math.abs(p.top-obj.top) < 10) {
                for (i = 0; i < p.linesIn.length; i++) {
                  p.linesIn[i].circle2 = obj;
                  obj.linesIn.push(p.linesIn[i]);
                }
                for (i = 0; i < p.linesOut.length; i++) {
                  p.linesOut[i].circle1 = obj;
                  obj.linesOut.push(p.linesOut[i]);
                }
                canvas.remove(p);
                updateNode(obj);
                obj.bringToFront();
                canvas.renderAll();
              }
            }
            if (obj.get('class') == 'component') {
              if (obj.size < p.component.size) {
                p.component = obj;
              }
            }
          }
        });
        snapToComponent(p,p.component);
        for (j = 0; j < p.linesIn.length; j++) {
          if (p.linesIn[j].circle1.component.size < p.component.size)
            snapOutComponent(p.linesIn[j].circle1,p.linesIn[j].circle1.component,p);
          p.linesIn[j].circle1.component = p.component;
          snapToComponent(p.linesIn[j].circle1,p.component);
          updateLine(p.linesIn[j], 2);
        }
        for (k = 0; k < p.linesOut.length; k++) {
          if (p.linesOut[k].circle2.component.size < p.component.size)
            snapOutComponent(p.linesOut[k].circle2,p.linesOut[k].circle2.component,p);
          p.linesOut[k].circle2.component = p.component;
          snapToComponent(p.linesOut[k].circle2,p.component);
          updateLine(p.linesOut[k], 1);
        }
        canvas.deactivateAll();
        canvas.calcOffset();
      }
      if (p.class == 'component') {
        canvas.sendToBack(p);
      }
    }
  });

  // Double-click event handler
  var doubleClick = function (obj, handler) {
    return function () {
      if (obj.clicked) handler(obj);
      else {
        obj.clicked = true;
        setTimeout(function () {
          obj.clicked = false;
        }, 500);
      }
    };
  };

  function drawComponent(x1,y1,x2,y2) {
    var width = (x2 - x1);
    var height = (y2 - y1);
    var left = x1;
    var top = y1;

    var label = new fabric.IText('name', {
      left: left + (width / 2),
      top: top - 15,
      fontSize: 32
    });

    var rect = new fabric.Rect({
      left: left,
      top: top,
      width: width,
      height, height,
      size: width * height,
      fill: 'transparent',
      stroke: '#000',
      strokeWidth: 1,
      hoverCursor: 'default',
      originX: 'left',
      originY: 'top',
      label: label,
      hasBorders: false,
      hasControls: false,
      class: 'component'
    });

    // give the component an identifier and increment it for the next one
    rect.set({'id': id});
    id = ((parseInt(id, 36)+1).toString(36)).replace(/[0-9]/g,'a');

    label.on('mousedown', doubleClick(label, function (obj) {
      label.enterEditing();
      label.selectAll();
    }));

    canvas.add(rect,label);
    rect.setCoords();
    canvas.renderAll();
    return rect;
  }

  var main = drawComponent(50,50,750,550);
  main.set({id:'main',hasBorders:false,hasControls:false,selectable:false});
  document.getElementById("select").click();
  drawLine(100,100,200,100);
  drawLine(300,100,400,100);

})();

<commit_msg>Fixed label coordinates<commit_after>(function() {
  var canvas = this.__canvas = new fabric.Canvas('c', { selection: false });
  fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
  var active, isDown, origX, origY;
  var mode = 'select';
  var id = 'a';

  document.getElementById("select").onclick = function() {
    document.getElementById(mode).style.border = '2px solid white';
    mode = 'select';
    this.style.border = '2px solid black';
  };

  document.getElementById("component").onclick = function() {
    document.getElementById(mode).style.border = '2px solid white';
    mode = 'component';
    this.style.border = '2px solid black';
  };

  document.getElementById("sync").onclick = function() {
    document.getElementById(mode).style.border = '2px solid white';
    mode = 'sync';
    this.style.border = '2px solid black';
  };

  document.getElementById("downloadsvg").onclick = function () {
    var a = document.getElementById("download");
    a.download = "reo.svg";
    a.href = 'data:image/svg+xml;base64,' + window.btoa(canvas.toSVG());
    a.click();
  };

  document.getElementById("downloadpng").onclick = function () {
    var a = document.getElementById("download");
    a.download = "reo.png";
    a.href = canvas.toDataURL('image/png');
    a.click();
  };

  function makeCircle(left, top) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 5,
      radius: 12,
      fill: '#fff',
      stroke: '#000',
      hasBorders: false,
      hasControls: false,
      class: 'node',
      component: main
    });

    // give the node an identifier and increment it for the next node
    c.set({'id': id});
    id = ((parseInt(id, 36)+1).toString(36)).replace(/[0-9]/g,'a');

    // these are the channels that are connected to this node
    c.linesIn = [];
    c.linesOut = [];

    return c;
  } //makeCircle

  function drawLine(x1, y1, x2, y2) {
    // create a line...
    var line = new fabric.Line([x1, y1, x2, y2], {
      fill: '#000',
      stroke: '#000',
      strokeWidth: 5,
      hasBorders: false,
      hasControls: false,
      selectable: false,
      hoverCursor: 'default',
      class: 'line'
    });

    // ...an arrowhead...
    var a = new fabric.Triangle({
      left: x2,
      top: y2,
      width: 20,
      height: 20,
      angle: calcArrowAngle(x1,y1,x2,y2),
      fill: '#000',
      hasBorders: false,
      hasControls: false,
      selectable: false,
      hoverCursor: 'default'
    });

    // ...and two circles
    var c1 = makeCircle(x1,y1);
    var c2 = makeCircle(x2,y2);

    // ...link them all together
    line.set({'arrow': a, 'circle1': c1, 'circle2': c2});
    a.set({'line': line});
    c1.linesOut.push(line);
    c2.linesIn.push(line);
    updateNode(c1);
    updateNode(c2);

    // magic
    updateLine(line, 2);

    // draw everything on the canvas
    canvas.add(line,a,c1,c2);
    canvas.renderAll();

    return line;
  } //drawLine

  function updateNode(node) {
    if (node.linesIn.length) {
      if (node.linesOut.length)
        node.set({'nodetype':'mixed','fill':'#ff5'});
      else
        node.set({'nodetype':'drain','fill':'#f55'});
    }
    else
      node.set({'nodetype':'source','fill':'#55f'});
  }

  function updateLine(line, end) {
    // we first have to reset the end coordinates
    var x1 = line.circle1.get('left');
    var y1 = line.circle1.get('top');
    var x2 = line.circle2.get('left');
    var y2 = line.circle2.get('top');
    line.set({'x1':x1, 'y1':y1, 'x2':x2, 'y2':y2});

    if (x1 == x2 && y1 == y2) {
      line.arrow.set({'left': line.get('x2'), 'top': line.get('y2')});
    }
    else {
      // calculate the position of the arrow
      var length = Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2));
      length = length - 22;//circle2.get('radius') - circle2.get('stroke');
      var x = Math.atan(Math.abs(y1-y2)/Math.abs(x1-x2));
      if (end) {
        if (x2 > x1) {
          line.set({'x2': x1 + length * Math.cos(x)});
        } else {
          line.set({'x2': x1 - length * Math.cos(x)});
        }
        if (y2 > y1) {
          line.set({'y2': y1 + length * Math.sin(x)});
        } else {
          line.set({'y2': y1 - length * Math.sin(x)});
        }
      }
      line.arrow.set({'left': line.get('x2'), 'top': line.get('y2')});
      var angle = calcArrowAngle(line.get('x1'), line.get('y1'), line.get('x2'), line.get('y2'));
      line.arrow.set({'angle': angle});
    }

    canvas.renderAll();
  } //updateLine

  // calculate the correct angle for the arrowhead
  function calcArrowAngle(x1, y1, x2, y2) {
    var angle = 0, x, y;
    x = (x2 - x1);
    y = (y2 - y1);

    if (x === 0) {
      angle = (y === 0) ? 0 : (y > 0) ? Math.PI / 2 : Math.PI * 3 / 2;
    } else if (y === 0) {
      angle = (x > 0) ? 0 : Math.PI;
    } else {
      angle = (x < 0) ? Math.atan(y / x) + Math.PI : (y < 0) ? Math.atan(y / x) + (2 * Math.PI) : Math.atan(y / x);
    }

    return ((angle * 180 / Math.PI) + 90) % 360;
  } //calcArrowAngle

  function enumerate() {
    document.getElementById('text').innerHTML = "";
    canvas.forEachObject(function(obj) {
      if (obj.class == 'node')
        document.getElementById('text').innerHTML += obj.id + " ";
    });
  }

  function updateText() {
    var s = '';
    // TODO: traverse id's
    canvas.forEachObject(function(obj) {
      if (obj.type == "line")
        s += 'sync(' + obj.circle1.id + ',' + obj.circle2.id + ') ';
    });
    document.getElementById('text').innerHTML = s;
  }

  function snapToComponent(node,comp) {
    var right = comp.left + comp.width;
    var bottom = comp.top + comp.height;
    if (node.left > right) // right side
      node.set({'left': right});
    if (node.left < comp.left) // left side
      node.set({'left': comp.left});
    if (node.top > bottom) // bottom side
      node.set({'top': bottom});
    if (node.top < comp.top) // top side
      node.set({'top': comp.top});
    node.setCoords();
    for (i = 0; i < node.linesIn.length; i++) {
      updateLine(node.linesIn[i], 2);
    }
    for (i = 0; i < node.linesOut.length; i++) {
      updateLine(node.linesOut[i], 1);
    }
  }

  function snapOutComponent(node, comp, connectednode) {
    var right = comp.left + comp.width;
    var bottom = comp.top + comp.height;
    if (connectednode.left > right) // right side
      node.set({left: right});
    if (connectednode.left < comp.left) // left side
      node.set({left: comp.left});
    if (connectednode.top > bottom) // bottom side
      node.set({top: bottom});
    if (connectednode.top < comp.top)
      node.set({top: comp.top});
    node.setCoords();
  }

  canvas.on('object:moving', function(e) {
    var p = e.target;
    p.setCoords();
  }); //object:moving

  canvas.on('object:added', function(e) {
    updateText();
  }); //object:added

  canvas.on('object:removed', function(e) {
    updateText();
  }); //object:added

  canvas.on('mouse:down', function(e) {
    isDown = true;
    if (canvas.getActiveObject())
      return;
    var pointer = canvas.getPointer(e.e);
    if (mode == 'sync') {
      var line = drawLine(pointer.x,pointer.y,pointer.x,pointer.y);
      snapToComponent(line.circle1,main);
      canvas.setActiveObject(line.circle2);
      updateLine(line,2);
    }
    if (mode == 'component') {
      origX = pointer.x;
      origY = pointer.y;
      var comp = drawComponent(pointer.x,pointer.y,pointer.x,pointer.y);
      canvas.setActiveObject(comp);
    }
  }); //mouse:down

  canvas.on('mouse:move', function(e){
    if (!isDown)
      return;
    var p = canvas.getActiveObject();
    if (!p)
      return;
    var pointer = canvas.getPointer(e.e);
    if (p.class == 'component') {
      if (origX > pointer.x)
        p.set({left:pointer.x});
      if (origY > pointer.y)
        p.set({top:pointer.y});
      p.set({width:Math.abs(origX - pointer.x)});
      p.set({height:Math.abs(origY - pointer.y)});
      p.setCoords();
      p.label.set({left: p.left + (p.width/2), top: p.top - 15});
      p.label.setCoords();
    }
    if (p.class == 'node') {
      p.set({'left': pointer.x, 'top': pointer.y});
      p.setCoords();
      canvas.forEachObject(function(obj) {
        if (obj !== p && obj.get('type') === "circle" && p.intersectsWithObject(obj)) {
          if(Math.abs(p.left-obj.left) < 10 && Math.abs(p.top-obj.top) < 10) {
            p.set({'left': obj.getLeft(), 'top': obj.getTop()});
            p.setCoords();
          }
        }
      });
      for (i = 0; i < p.linesIn.length; i++)
        updateLine(p.linesIn[i], 2);
      for (i = 0; i < p.linesOut.length; i++)
        updateLine(p.linesOut[i], 1);
    }
    canvas.renderAll();
  }); //mouse:move

  canvas.on('mouse:up', function(e){
    isDown = false;
    var p = canvas.getActiveObject();
    if (p) {
      if (p.class == 'node') {
        p.setCoords();
        p.set({component:main});
        canvas.forEachObject(function(obj) {
          if (!obj || obj.get('id') == p.get('id') || (obj.get('class') !== 'node' && obj.get('class') !== 'component'))
            return;
          if (p.intersectsWithObject(obj)) {
            if (obj.get('class') == 'node') {
              if(Math.abs(p.left-obj.left) < 10 && Math.abs(p.top-obj.top) < 10) {
                for (i = 0; i < p.linesIn.length; i++) {
                  p.linesIn[i].circle2 = obj;
                  obj.linesIn.push(p.linesIn[i]);
                }
                for (i = 0; i < p.linesOut.length; i++) {
                  p.linesOut[i].circle1 = obj;
                  obj.linesOut.push(p.linesOut[i]);
                }
                canvas.remove(p);
                updateNode(obj);
                obj.bringToFront();
                canvas.renderAll();
              }
            }
            if (obj.get('class') == 'component') {
              if (obj.size < p.component.size) {
                p.component = obj;
              }
            }
          }
        });
        snapToComponent(p,p.component);
        for (j = 0; j < p.linesIn.length; j++) {
          if (p.linesIn[j].circle1.component.size < p.component.size)
            snapOutComponent(p.linesIn[j].circle1,p.linesIn[j].circle1.component,p);
          p.linesIn[j].circle1.component = p.component;
          snapToComponent(p.linesIn[j].circle1,p.component);
          updateLine(p.linesIn[j], 2);
        }
        for (k = 0; k < p.linesOut.length; k++) {
          if (p.linesOut[k].circle2.component.size < p.component.size)
            snapOutComponent(p.linesOut[k].circle2,p.linesOut[k].circle2.component,p);
          p.linesOut[k].circle2.component = p.component;
          snapToComponent(p.linesOut[k].circle2,p.component);
          updateLine(p.linesOut[k], 1);
        }
        canvas.deactivateAll();
        canvas.calcOffset();
      }
      if (p.class == 'component') {
        canvas.sendToBack(p);
      }
    }
  });

  // Double-click event handler
  var doubleClick = function (obj, handler) {
    return function () {
      if (obj.clicked) handler(obj);
      else {
        obj.clicked = true;
        setTimeout(function () {
          obj.clicked = false;
        }, 500);
      }
    };
  };

  function drawComponent(x1,y1,x2,y2) {
    var width = (x2 - x1);
    var height = (y2 - y1);
    var left = x1;
    var top = y1;

    var label = new fabric.IText('name', {
      left: left + (width / 2),
      top: top - 15,
      fontSize: 32
    });

    var rect = new fabric.Rect({
      left: left,
      top: top,
      width: width,
      height, height,
      size: width * height,
      fill: 'transparent',
      stroke: '#000',
      strokeWidth: 1,
      hoverCursor: 'default',
      originX: 'left',
      originY: 'top',
      label: label,
      hasBorders: false,
      hasControls: false,
      class: 'component'
    });

    // give the component an identifier and increment it for the next one
    rect.set({'id': id});
    id = ((parseInt(id, 36)+1).toString(36)).replace(/[0-9]/g,'a');

    label.on('mousedown', doubleClick(label, function (obj) {
      label.enterEditing();
      label.selectAll();
    }));

    canvas.add(rect,label);
    rect.setCoords();
    canvas.renderAll();
    return rect;
  }

  var main = drawComponent(50,50,750,550);
  main.set({id:'main',hasBorders:false,hasControls:false,selectable:false});
  main.label.set({'text': 'main'});
  document.getElementById("select").click();
  drawLine(100,100,200,100);
  drawLine(300,100,400,100);

})();

<|endoftext|>


<commit_before>import $ from 'jquery';
import Tooltip from '../Tooltip.js';
import { onMessage, addMessage } from '../messageQueue.js';
import { getCurrentScene } from '../currentScene.js';

export default class {
  constructor() {
    this.$frame = $('#game');
  }
  start() {
    this.messageBox = $('
');
    this.$frame.append(this.messageBox);
    onMessage((message) => this.displayMessage(message));
    addMessage(getCurrentScene().descriptionMessage());
  }
  displayMessage(message) {
    this.messageBox.children('.to-hide').removeClass('to-hide').addClass('disabled');

    this.messageBox.append(message);

    if (message.hasClass('scene-description')) {
      this.messageBox.children(':not(.disabled)').addClass('to-hide');
    }

    for (var el of this.messageBox.find(".tooltip")) {
      new Tooltip(el);
    }
    this.$frame.scrollTop(this.$frame[0].scrollHeight);

  }
}
<commit_msg>Only add tooltips to new messages<commit_after>import $ from 'jquery';
import Tooltip from '../Tooltip.js';
import { onMessage, addMessage } from '../messageQueue.js';
import { getCurrentScene } from '../currentScene.js';

export default class {
  constructor() {
    this.$frame = $('#game');
  }
  start() {
    this.messageBox = $('
');
    this.$frame.append(this.messageBox);
    onMessage((message) => this.displayMessage(message));
    addMessage(getCurrentScene().descriptionMessage());
  }
  displayMessage(message) {
    this.messageBox.children('.to-hide').removeClass('to-hide').addClass('disabled');

    this.messageBox.append(message);

    message.find(".tooltip").each((index, el) => {
      new Tooltip(el);
    });

    if (message.hasClass('scene-description')) {
      this.messageBox.children(':not(.disabled)').addClass('to-hide');
    }

    this.$frame.scrollTop(this.$frame[0].scrollHeight);

  }
}
<|endoftext|>


<commit_before>FLOW.MonitoringDataTableView = FLOW.View.extend({
  showingDetailsDialog: false,
  cursorStart: null,

  pageNumber: function(){
	return FLOW.router.surveyedLocaleController.get('pageNumber');
  }.property('FLOW.router.surveyedLocaleController.pageNumber'),

  showDetailsDialog: function (evt) {
	FLOW.surveyInstanceControl.set('content', FLOW.store.findQuery(FLOW.SurveyInstance, {
		surveyedLocaleId: evt.context.get('keyId')
	}));
    this.toggleProperty('showingDetailsDialog');
  },

  showApprovalStatusColumn: function () {
      return FLOW.Env.enableDataApproval;
  }.property(),

  closeDetailsDialog: function () {
    this.toggleProperty('showingDetailsDialog');
  },

  showSurveyInstanceDetails: function (evt) {
    FLOW.questionAnswerControl.doQuestionAnswerQuery(evt.context.get('keyId'));
    $('.si_details').hide();
    $('tr[data-flow-id="si_details_' + evt.context.get('keyId') + '"]').show();
  },

  findSurveyedLocale: function (evt) {
	  var ident = this.get('identifier'),
	      displayName = this.get('displayName'),
	      sgId = FLOW.selectedControl.get('selectedSurveyGroup'),
	      cursorType = FLOW.metaControl.get('cursorType'),
        criteria = {};

	  if (ident) {
		  criteria.identifier = ident;
	  }

	  if (displayName) {
		  criteria.displayName = displayName;
	  }

	  if (sgId) {
		  criteria.surveyGroupId = sgId.get('keyId');
	  }

	  if (this.get('cursorStart')) {
		criteria.since = this.get('cursorStart');
	  }
      FLOW.router.surveyedLocaleController.populate(criteria);
  },

  doNextPage: function () {
	var cursorArray, cursorStart;
	cursorArray = FLOW.router.surveyedLocaleController.get('sinceArray');
	cursorStart = cursorArray.length > 0 ? cursorArray[cursorArray.length - 1] : null;
	this.set('cursorStart', cursorStart);
    this.findSurveyedLocale();
    FLOW.router.surveyedLocaleController.set('pageNumber', FLOW.router.surveyedLocaleController.get('pageNumber') + 1);
  },

  doPrevPage: function () {
	var cursorArray, cursorStart;
	cursorArray = FLOW.router.surveyedLocaleController.get('sinceArray');
	cursorStart = cursorArray.length - 3 > -1 ? cursorArray[cursorArray.length - 3] : null;
	this.set('cursorStart', cursorStart);
    this.findSurveyedLocale();
    FLOW.router.surveyedLocaleController.set('pageNumber', FLOW.router.surveyedLocaleController.get('pageNumber') - 1);
  },

  hasNextPage: function () {
    return FLOW.metaControl.get('numSLLoaded') == 20;
  }.property('FLOW.metaControl.numSLLoaded'),

  hasPrevPage: function () {
    return FLOW.router.surveyedLocaleController.get('pageNumber');
  }.property('FLOW.router.surveyedLocaleController.pageNumber'),
});

/**
 * View of each row/data point in the monitoring data tab
 */
FLOW.DataPointView = FLOW.View.extend({
    templateName: 'navData/monitoring-data-row',

    approvalStatus: [{label: Ember.String.loc('_pending'), value: 'PENDING'}, { label: Ember.String.loc('_approved'), value: 'APPROVED' },{ label: Ember.String.loc('_rejected'), value: 'REJECTED'}],

    showDataApprovalBlock: false,

    showSurveyedLocaleDeleteButton: function() {
        return FLOW.router.surveyedLocaleController.get('userCanDelete');
    }.property(),

    showApprovalStatusColumn: function () {
        return this.get('parentView').get('showApprovalStatusColumn');
    }.property(),

    dataPointApprovals: function () {
        var approvals = FLOW.router.dataPointApprovalController.get('content');
        if(!approvals) {
            return;
        }

        var surveyedLocaleId = this.content && this.content.get('keyId');
        return approvals.filterProperty('surveyedLocaleId', surveyedLocaleId);
    }.property('FLOW.router.dataPointApprovalController.content.@each'),

    /*
     * Derive the approvalStepId for the next approval (in ordered approvals)
     */
    nextApprovalStepId: function () {
        var approvals = this.get('dataPointApprovals');
        var steps = FLOW.router.approvalStepsController.get('content');
        var nextStepId;
        steps.forEach(function (step) {
            var stepApprovals = approvals.filterProperty('approvalStepId', step.get('keyId'));
            if(!nextStepId && (Ember.empty(stepApprovals) || stepApprovals[0].get('status') === 'PENDING')) {
                nextStepId = step.get('keyId');
            }
        });
        return nextStepId;
    }.property('this.dataPointApprovals'),

    /*
     * return true if there are any of the approvals rejected in this set
     */
    hasRejectedApproval: function () {
        var approvals = this.get('dataPointApprovals');
        return !Ember.empty(approvals.filterProperty('status', 'REJECTED'));
    }.property('this.dataPointApprovals'),

    loadDataPointApprovalObserver: function () {
        if(!this.get('showDataApprovalBlock')) {
            return; // do nothing when hiding approval block
        }

        var dataPoint = this.get('content');
        if (dataPoint) {
            FLOW.router.dataPointApprovalController.loadBySurveyedLocaleId(dataPoint.get('keyId'));
        }
    }.observes('this.showDataApprovalBlock'),

    toggleShowDataApprovalBlock: function () {
        this.toggleProperty('showDataApprovalBlock');
    },
});

/**
 * View to render the status of a data point in the approval
 * status cell of each data point / row
 */
FLOW.DataPointApprovalStatusView = FLOW.View.extend({
    content: null,

    latestApprovalStepTitle: function () {
        var stepsController = FLOW.router.get('approvalStepsController');
        if(stepsController.get('firstObject')) {
            return stepsController.get('firstObject').get('title');
        }
    }.property(),
});

/**
 * The data approval view for each approval step of a data point
 */
FLOW.DataPointApprovalView = FLOW.View.extend({
    step: null,

    dataPoint: null,

    dataPointApproval: function () {
        var approvals = this.get('parentView').get('dataPointApprovals');
        var defaultApproval = Ember.Object.create({ status: 'PENDING', comment: null});

        if(Ember.empty(approvals)) {
            return defaultApproval;
        }

        var stepId = this.step && this.step.get('keyId');
        var approval = approvals.filterProperty('approvalStepId', stepId).get('firstObject');

        return approval || defaultApproval;
    }.property('this.parentView.dataPointApprovals'),

    isApprovedStep: function () {
        var dataPointApproval = this.get('dataPointApproval');
        return dataPointApproval && dataPointApproval.get('keyId');
    }.property('this.dataPointApproval'),

    /*
     * Enable the approval fields based on whether or not approval steps
     * should be executed in order
     */
    showApprovalFields: function () {
        if(this.get('parentView').get('hasRejectedApproval')) {
            return false;
        }

        var approvalGroup = FLOW.router.approvalGroupController.get('content');
        if(approvalGroup && approvalGroup.get('ordered')) {
            return this.step.get('keyId') === this.get('parentView').get('nextApprovalStepId');
        } else {
            // this is for unordered approval steps. show fields for
            // all steps so that its possible to approve any step
            return true;
        }
    }.property('this.parentView.nextApprovalStepId'),

    /*
     *  Submit data approval properties to controller
     */
    submitDataPointApproval: function (event) {

        var dataPointApproval = this.get('dataPointApproval');
        if(dataPointApproval.get('keyId')) {
            FLOW.router.dataPointApprovalController.update(dataPointApproval);
        } else {
            dataPointApproval.surveyedLocaleId = this.get('dataPoint').get('keyId');
            dataPointApproval.approvalStepId = this.get('step').get('keyId');
            dataPointApproval.approverUserName = null;

            FLOW.router.dataPointApprovalController.add(dataPointApproval);
        }
    },
});<commit_msg>[#1664] Refactor `nextApprovalStepId` property to use `FLOW.ApprovalStep.order` property<commit_after>FLOW.MonitoringDataTableView = FLOW.View.extend({
  showingDetailsDialog: false,
  cursorStart: null,

  pageNumber: function(){
	return FLOW.router.surveyedLocaleController.get('pageNumber');
  }.property('FLOW.router.surveyedLocaleController.pageNumber'),

  showDetailsDialog: function (evt) {
	FLOW.surveyInstanceControl.set('content', FLOW.store.findQuery(FLOW.SurveyInstance, {
		surveyedLocaleId: evt.context.get('keyId')
	}));
    this.toggleProperty('showingDetailsDialog');
  },

  showApprovalStatusColumn: function () {
      return FLOW.Env.enableDataApproval;
  }.property(),

  closeDetailsDialog: function () {
    this.toggleProperty('showingDetailsDialog');
  },

  showSurveyInstanceDetails: function (evt) {
    FLOW.questionAnswerControl.doQuestionAnswerQuery(evt.context.get('keyId'));
    $('.si_details').hide();
    $('tr[data-flow-id="si_details_' + evt.context.get('keyId') + '"]').show();
  },

  findSurveyedLocale: function (evt) {
	  var ident = this.get('identifier'),
	      displayName = this.get('displayName'),
	      sgId = FLOW.selectedControl.get('selectedSurveyGroup'),
	      cursorType = FLOW.metaControl.get('cursorType'),
        criteria = {};

	  if (ident) {
		  criteria.identifier = ident;
	  }

	  if (displayName) {
		  criteria.displayName = displayName;
	  }

	  if (sgId) {
		  criteria.surveyGroupId = sgId.get('keyId');
	  }

	  if (this.get('cursorStart')) {
		criteria.since = this.get('cursorStart');
	  }
      FLOW.router.surveyedLocaleController.populate(criteria);
  },

  doNextPage: function () {
	var cursorArray, cursorStart;
	cursorArray = FLOW.router.surveyedLocaleController.get('sinceArray');
	cursorStart = cursorArray.length > 0 ? cursorArray[cursorArray.length - 1] : null;
	this.set('cursorStart', cursorStart);
    this.findSurveyedLocale();
    FLOW.router.surveyedLocaleController.set('pageNumber', FLOW.router.surveyedLocaleController.get('pageNumber') + 1);
  },

  doPrevPage: function () {
	var cursorArray, cursorStart;
	cursorArray = FLOW.router.surveyedLocaleController.get('sinceArray');
	cursorStart = cursorArray.length - 3 > -1 ? cursorArray[cursorArray.length - 3] : null;
	this.set('cursorStart', cursorStart);
    this.findSurveyedLocale();
    FLOW.router.surveyedLocaleController.set('pageNumber', FLOW.router.surveyedLocaleController.get('pageNumber') - 1);
  },

  hasNextPage: function () {
    return FLOW.metaControl.get('numSLLoaded') == 20;
  }.property('FLOW.metaControl.numSLLoaded'),

  hasPrevPage: function () {
    return FLOW.router.surveyedLocaleController.get('pageNumber');
  }.property('FLOW.router.surveyedLocaleController.pageNumber'),
});

/**
 * View of each row/data point in the monitoring data tab
 */
FLOW.DataPointView = FLOW.View.extend({
    templateName: 'navData/monitoring-data-row',

    approvalStatus: [{label: Ember.String.loc('_pending'), value: 'PENDING'}, { label: Ember.String.loc('_approved'), value: 'APPROVED' },{ label: Ember.String.loc('_rejected'), value: 'REJECTED'}],

    showDataApprovalBlock: false,

    showSurveyedLocaleDeleteButton: function() {
        return FLOW.router.surveyedLocaleController.get('userCanDelete');
    }.property(),

    showApprovalStatusColumn: function () {
        return this.get('parentView').get('showApprovalStatusColumn');
    }.property(),

    dataPointApprovals: function () {
        var approvals = FLOW.router.dataPointApprovalController.get('content');
        if(!approvals) {
            return;
        }

        var surveyedLocaleId = this.content && this.content.get('keyId');
        return approvals.filterProperty('surveyedLocaleId', surveyedLocaleId);
    }.property('FLOW.router.dataPointApprovalController.content.@each'),

    /*
     * Derive the approvalStepId for the next approval (in ordered approvals)
     */
    nextApprovalStepId: function () {
        var approvals = this.get('dataPointApprovals');
        var steps = FLOW.router.approvalStepsController.get('arrangedContent');
        var lastApprovedStepOrder = -1;

        approvals.forEach(function (approval) {
            var step = steps.filterProperty('keyId',
                                approval.get('approvalStepId')).get('firstObject');
            if (approval.get('status') === 'APPROVED' &&
                    step && (step.get('order') > lastApprovedStepOrder)) {
                lastApprovedStepOrder = step.get('order');
            }
        });

        var nextStep = steps.filterProperty('order', ++lastApprovedStepOrder).get('firstObject');
        return nextStep && nextStep.get('keyId');
    }.property('this.dataPointApprovals'),

    /*
     * return true if there are any of the approvals rejected in this set
     */
    hasRejectedApproval: function () {
        var approvals = this.get('dataPointApprovals');
        return !Ember.empty(approvals.filterProperty('status', 'REJECTED'));
    }.property('this.dataPointApprovals'),

    loadDataPointApprovalObserver: function () {
        if(!this.get('showDataApprovalBlock')) {
            return; // do nothing when hiding approval block
        }

        var dataPoint = this.get('content');
        if (dataPoint) {
            FLOW.router.dataPointApprovalController.loadBySurveyedLocaleId(dataPoint.get('keyId'));
        }
    }.observes('this.showDataApprovalBlock'),

    toggleShowDataApprovalBlock: function () {
        this.toggleProperty('showDataApprovalBlock');
    },
});

/**
 * View to render the status of a data point in the approval
 * status cell of each data point / row
 */
FLOW.DataPointApprovalStatusView = FLOW.View.extend({
    content: null,

    latestApprovalStepTitle: function () {
        var stepsController = FLOW.router.get('approvalStepsController');
        if(stepsController.get('firstObject')) {
            return stepsController.get('firstObject').get('title');
        }
    }.property(),
});

/**
 * The data approval view for each approval step of a data point
 */
FLOW.DataPointApprovalView = FLOW.View.extend({
    step: null,

    dataPoint: null,

    dataPointApproval: function () {
        var approvals = this.get('parentView').get('dataPointApprovals');
        var defaultApproval = Ember.Object.create({ status: null, comment: null});

        if(Ember.empty(approvals)) {
            return defaultApproval;
        }

        var stepId = this.step && this.step.get('keyId');
        var approval = approvals.filterProperty('approvalStepId', stepId).get('firstObject');

        return approval || defaultApproval;
    }.property('this.parentView.dataPointApprovals'),

    isApprovedStep: function () {
        var dataPointApproval = this.get('dataPointApproval');
        return dataPointApproval && dataPointApproval.get('keyId');
    }.property('this.dataPointApproval'),

    /*
     * Enable the approval fields based on whether or not approval steps
     * should be executed in order
     */
    showApprovalFields: function () {
        if(this.get('parentView').get('hasRejectedApproval')) {
            return false;
        }

        var approvalGroup = FLOW.router.approvalGroupController.get('content');
        if(approvalGroup && approvalGroup.get('ordered')) {
            var nextStepId = this.get('parentView').get('nextApprovalStepId');
            if (nextStepId) {
                return this.step.get('keyId') === nextStepId;
            } else {
                return false;
            }
        } else {
            // this is for unordered approval steps. show fields for
            // all steps so that its possible to approve any step
            return true;
        }
    }.property('this.parentView.nextApprovalStepId'),

    /*
     *  Submit data approval properties to controller
     */
    submitDataPointApproval: function (event) {

        var dataPointApproval = this.get('dataPointApproval');
        if(dataPointApproval.get('keyId')) {
            FLOW.router.dataPointApprovalController.update(dataPointApproval);
        } else {
            dataPointApproval.surveyedLocaleId = this.get('dataPoint').get('keyId');
            dataPointApproval.approvalStepId = this.get('step').get('keyId');
            dataPointApproval.approverUserName = null;

            FLOW.router.dataPointApprovalController.add(dataPointApproval);
        }
    },
});<|endoftext|>


<commit_before>module.exports = function(file, api, options) {
  const j = api.jscodeshift;
  const root = j(file.source);

  function moveQUnitImportsFromEmberQUnit() {
    let emberQUnitImports = root.find(j.ImportDeclaration, { source: { value: 'ember-qunit' } });
    // Find `module` and `test` imports
    let migrateToQUnitImport = ['module', 'test', 'skip', 'todo'];

    let specifiers = new Set(['module']);
    // Replace old with new test helpers imports
    emberQUnitImports
      .find(j.ImportSpecifier)
      .filter(p => migrateToQUnitImport.includes(p.node.imported.name))
      .forEach(p => specifiers.add(p.node.imported.name))
      .remove();

    let qunitImports = root.find(j.ImportDeclaration, { source: { value: 'qunit' } });
    qunitImports.find(j.ImportSpecifier).forEach(p => specifiers.add(p.node.imported.name));

    if (specifiers.size === 0) {
      return;
    }

    if (qunitImports.size() === 0) {
      // Add new `import from 'qunit'` node
      let newQUnitImport = j.importDeclaration([], j.literal('qunit'));
      emberQUnitImports.insertBefore(newQUnitImport);
      qunitImports = j(newQUnitImport);
    }

    qunitImports.get('specifiers').replace(
      Array.from(specifiers)
        .sort()
        .map(s => j.importSpecifier(j.identifier(s)))
    );
  }

  function updateToNewEmberQUnitImports() {
    let mapping = {
      moduleFor: 'setupTest',
      moduleForComponent: 'setupRenderingTest',
      moduleForModel: 'setupTest',
    };

    let emberQUnitImports = root.find(j.ImportDeclaration, { source: { value: 'ember-qunit' } });

    // Collect all imports from ember-qunit into local array
    let specifiers = new Set();
    emberQUnitImports
      .find(j.ImportSpecifier)
      .forEach(p => {
        // Map them to the new imports
        let importName = p.node.imported.name;
        let mappedName = mapping[importName] || importName;

        // If importName is `moduleForComponent` determine if we need
        // `setupTest` (unit) or `setupRenderingTest` (integration)
        if (importName === 'moduleForComponent') {
          root
            .find(j.ExpressionStatement, {
              expression: {
                callee: { name: 'moduleForComponent' },
              },
            })
            .forEach(p => {
              let [, , setupType] = parseModule(p);
              specifiers.add(setupType);
            });
        } else {
          specifiers.add(mappedName);
        }
      })
      // Remove all existing import specifiers
      .remove();

    ['render', 'clearRender'].forEach(type => {
      let usages = findTestHelperUsageOf(root, type);
      if (usages.size() > 0) {
        specifiers.add(type);
      }
    });

    emberQUnitImports
      .get('specifiers')
      .replace(Array.from(specifiers).map(s => j.importSpecifier(j.identifier(s))));
  }

  function findTestHelperUsageOf(collection, property) {
    return collection.find(j.ExpressionStatement, {
      expression: {
        callee: {
          object: {
            type: 'ThisExpression',
          },
          property: {
            name: property,
          },
        },
      },
    });
  }

  function parseModule(p) {
    let calleeName = p.node.expression.callee.name;
    // Find the moduleName and the module's options
    let moduleName, subject, options;
    let calleeArguments = p.node.expression.arguments.slice();
    let lastArgument = calleeArguments[calleeArguments.length - 1];
    if (lastArgument.type === 'ObjectExpression') {
      options = calleeArguments.pop();
    }
    moduleName = calleeArguments[1] || calleeArguments[0];

    let setupIdentifier = 'setupTest';
    if (options) {
      let hasIntegration = options.properties.some(p => p.key.name === 'integration');

      if (calleeName === `moduleForComponent`) {
        if (hasIntegration) {
          setupIdentifier = 'setupRenderingTest';
        } else {
          subject = j.literal(`component:${calleeArguments[0].value}`);
        }
      } else if (calleeName === 'moduleForModel') {
        subject = j.literal(`model:${calleeArguments[0].value}`);
      } else if (!hasIntegration) {
        subject = calleeArguments[0];
      }
    }

    return [moduleName, options, setupIdentifier, subject];
  }

  function updateModuleForToNestedModule() {
    const POSSIBLE_MODULES = [
      { expression: { callee: { name: 'moduleFor' } } },
      { expression: { callee: { name: 'moduleForComponent' } } },
      { expression: { callee: { name: 'moduleForModel' } } },
    ];

    function isModuleDefinition(nodePath) {
      return POSSIBLE_MODULES.some(matcher => j.match(nodePath, matcher));
    }

    const LIFE_CYCLE_METHODS = [
      { key: { name: 'before' }, value: { type: 'FunctionExpression' } },
      { key: { name: 'beforeEach' }, value: { type: 'FunctionExpression' } },
      { key: { name: 'afterEach' }, value: { type: 'FunctionExpression' } },
      { key: { name: 'after' }, value: { type: 'FunctionExpression' } },
    ];

    function isLifecycleHook(nodePath) {
      return LIFE_CYCLE_METHODS.some(matcher => j.match(nodePath, matcher));
    }

    function createModule(p) {
      let [moduleName, options, setupType, subject] = parseModule(p);

      // Create the new `module(moduleName, function(hooks) {});` invocation
      let callback = j.functionExpression(
        null /* no function name */,
        [j.identifier('hooks')],
        j.blockStatement([
          j.expressionStatement(j.callExpression(j.identifier(setupType), [j.identifier('hooks')])),
        ])
      );
      let moduleInvocation = j.expressionStatement(
        j.callExpression(j.identifier('module'), [moduleName, callback])
      );

      if (options) {
        options.properties.forEach(property => {
          if (isLifecycleHook(property)) {
            let lifecycleStatement = j.expressionStatement(
              j.callExpression(j.memberExpression(j.identifier('hooks'), property.key), [
                property.value,
              ])
            );

            // preserve any comments that were present
            lifecycleStatement.comments = property.comments;

            callback.body.body.push(lifecycleStatement);
          }
        });
      }

      return [moduleInvocation, callback.body.body, setupType, subject];
    }

    function processRenderingTest(testExpression) {
      let isTest = j.match(testExpression, { expression: { callee: { name: 'test' } } });
      if (!isTest) {
        return;
      }

      // mark the test function as an async function
      testExpression.expression.arguments[1].async = true;
      let testExpressionCollection = j(testExpression);

      // Transform to await render() or await clearRender()
      ['render', 'clearRender'].forEach(type => {
        findTestHelperUsageOf(testExpressionCollection, type).forEach(p => {
          let expression = p.get('expression');

          let awaitExpression = j.awaitExpression(
            j.callExpression(j.identifier(type), expression.node.arguments)
          );
          expression.replace(awaitExpression);
        });
      });

      // Migrate `this._element` -> `this.element`
      testExpressionCollection
        .find(j.MemberExpression, {
          object: {
            type: 'ThisExpression',
          },
          property: {
            name: '_element',
          },
        })
        .forEach(p => {
          let property = p.get('property');
          property.node.name = 'element';
        });
    }

    function processSubject(testExpression, subject) {
      let thisDotSubjectUsage = j(testExpression).find(j.CallExpression, {
        callee: {
          type: 'MemberExpression',
          object: {
            type: 'ThisExpression',
          },
          property: {
            name: 'subject',
          },
        },
      });

      if (thisDotSubjectUsage.size() === 0) {
        return;
      }

      thisDotSubjectUsage.forEach(p => {
        let options = p.node.arguments[0];
        let [subjectType, subjectName] = subject.value.split(':');
        let isSingletonSubject = !['model', 'component'].includes(subjectType);

        // if we don't have `options` and the type is a singleton type
        // use `this.owner.lookup(subject)`
        if (!options && isSingletonSubject) {
          p.replace(
            j.callExpression(
              j.memberExpression(
                j.memberExpression(j.thisExpression(), j.identifier('owner')),
                j.identifier('lookup')
              ),
              [subject]
            )
          );
        } else if (subjectType === 'model') {
          p.replace(
            j.callExpression(
              j.memberExpression(
                j.callExpression(
                  j.memberExpression(
                    j.memberExpression(j.thisExpression(), j.identifier('owner')),
                    j.identifier('lookup')
                  ),
                  [j.literal('service:store')]
                ),
                j.identifier('createRecord')
              ),
              [j.literal(subjectName), options].filter(Boolean)
            )
          );
        } else {
          p.replace(
            j.callExpression(
              j.memberExpression(
                j.callExpression(
                  j.memberExpression(
                    j.memberExpression(j.thisExpression(), j.identifier('owner')),
                    j.identifier('factoryFor')
                  ),
                  [subject]
                ),
                j.identifier('create')
              ),
              [options].filter(Boolean)
            )
          );
        }
      });
    }

    let programPath = root.get('program');
    let bodyPath = programPath.get('body');

    let bodyReplacement = [];
    let currentModuleCallbackBody, currentTestType, currentSubject;
    bodyPath.each(expressionPath => {
      let expression = expressionPath.node;
      if (isModuleDefinition(expressionPath)) {
        let result = createModule(expressionPath);
        bodyReplacement.push(result[0]);
        currentModuleCallbackBody = result[1];
        currentTestType = result[2];
        currentSubject = result[3];
      } else if (currentModuleCallbackBody) {
        currentModuleCallbackBody.push(expression);

        if (currentTestType === 'setupRenderingTest') {
          processRenderingTest(expression);
        } else if (currentTestType === 'setupTest') {
          processSubject(expression, currentSubject);
        }
      } else {
        bodyReplacement.push(expression);
      }
    });

    bodyPath.replace(bodyReplacement);
  }

  function updateLookupCalls() {
    root
      .find(j.MemberExpression, {
        object: {
          object: { type: 'ThisExpression' },
          property: { name: 'container' },
        },
        property: { name: 'lookup' },
      })
      .forEach(path => {
        let thisDotOwner = j.memberExpression(j.thisExpression(), j.identifier('owner'));
        path.replace(j.memberExpression(thisDotOwner, path.value.property));
      });
  }

  function updateRegisterCalls() {
    root
      .find(j.MemberExpression, {
        object: {
          object: { type: 'ThisExpression' },
          property: { name: 'registry' },
        },
        property: { name: 'register' },
      })
      .forEach(path => {
        let thisDotOwner = j.memberExpression(j.thisExpression(), j.identifier('owner'));
        path.replace(j.memberExpression(thisDotOwner, path.value.property));
      });

    root
      .find(j.MemberExpression, {
        object: { type: 'ThisExpression' },
        property: { name: 'register' },
      })
      .forEach(path => {
        let thisDotOwner = j.memberExpression(j.thisExpression(), j.identifier('owner'));
        path.replace(j.memberExpression(thisDotOwner, path.value.property));
      });
  }

  function updateInjectCalls() {
    root
      .find(j.CallExpression, {
        callee: {
          type: 'MemberExpression',
          object: {
            object: {
              type: 'ThisExpression',
            },
            property: {
              name: 'inject',
            },
          },
        },
      })
      .forEach(p => {
        let injectType = p.node.callee.property.name;
        let injectedName = p.node.arguments[0].value;
        let localName = injectedName;
        if (p.node.arguments[1]) {
          let options = p.node.arguments[1];
          let as = options.properties.find(property => property.key.name === 'as');
          if (as) {
            localName = as.value.value;
          }
        }
        let assignment = j.assignmentExpression(
          '=',
          j.memberExpression(j.thisExpression(), j.identifier(localName)),
          j.callExpression(
            j.memberExpression(
              j.memberExpression(j.thisExpression(), j.identifier('owner')),
              j.identifier('lookup')
            ),
            [j.literal(`${injectType}:${injectedName}`)]
          )
        );

        p.replace(assignment);
      });
  }

  const printOptions = options.printOptions || { quote: 'single' };

  // Find `ember-qunit` imports
  let emberQUnitImports = root.find(j.ImportDeclaration, { source: { value: 'ember-qunit' } });
  if (emberQUnitImports.size() === 0) {
    return file.source;
  }

  moveQUnitImportsFromEmberQUnit();
  updateToNewEmberQUnitImports();
  updateModuleForToNestedModule();
  updateLookupCalls();
  updateRegisterCalls();
  updateInjectCalls();

  return root.toSource(printOptions);
};
<commit_msg>Avoid transforming `this.subject` when custom `this.subject` is present.<commit_after>module.exports = function(file, api, options) {
  const j = api.jscodeshift;
  const root = j(file.source);

  function moveQUnitImportsFromEmberQUnit() {
    let emberQUnitImports = root.find(j.ImportDeclaration, { source: { value: 'ember-qunit' } });
    // Find `module` and `test` imports
    let migrateToQUnitImport = ['module', 'test', 'skip', 'todo'];

    let specifiers = new Set(['module']);
    // Replace old with new test helpers imports
    emberQUnitImports
      .find(j.ImportSpecifier)
      .filter(p => migrateToQUnitImport.includes(p.node.imported.name))
      .forEach(p => specifiers.add(p.node.imported.name))
      .remove();

    let qunitImports = root.find(j.ImportDeclaration, { source: { value: 'qunit' } });
    qunitImports.find(j.ImportSpecifier).forEach(p => specifiers.add(p.node.imported.name));

    if (specifiers.size === 0) {
      return;
    }

    if (qunitImports.size() === 0) {
      // Add new `import from 'qunit'` node
      let newQUnitImport = j.importDeclaration([], j.literal('qunit'));
      emberQUnitImports.insertBefore(newQUnitImport);
      qunitImports = j(newQUnitImport);
    }

    qunitImports.get('specifiers').replace(
      Array.from(specifiers)
        .sort()
        .map(s => j.importSpecifier(j.identifier(s)))
    );
  }

  function updateToNewEmberQUnitImports() {
    let mapping = {
      moduleFor: 'setupTest',
      moduleForComponent: 'setupRenderingTest',
      moduleForModel: 'setupTest',
    };

    let emberQUnitImports = root.find(j.ImportDeclaration, { source: { value: 'ember-qunit' } });

    // Collect all imports from ember-qunit into local array
    let specifiers = new Set();
    emberQUnitImports
      .find(j.ImportSpecifier)
      .forEach(p => {
        // Map them to the new imports
        let importName = p.node.imported.name;
        let mappedName = mapping[importName] || importName;

        // If importName is `moduleForComponent` determine if we need
        // `setupTest` (unit) or `setupRenderingTest` (integration)
        if (importName === 'moduleForComponent') {
          root
            .find(j.ExpressionStatement, {
              expression: {
                callee: { name: 'moduleForComponent' },
              },
            })
            .forEach(p => {
              let [, , setupType] = parseModule(p);
              specifiers.add(setupType);
            });
        } else {
          specifiers.add(mappedName);
        }
      })
      // Remove all existing import specifiers
      .remove();

    ['render', 'clearRender'].forEach(type => {
      let usages = findTestHelperUsageOf(root, type);
      if (usages.size() > 0) {
        specifiers.add(type);
      }
    });

    emberQUnitImports
      .get('specifiers')
      .replace(Array.from(specifiers).map(s => j.importSpecifier(j.identifier(s))));
  }

  function findTestHelperUsageOf(collection, property) {
    return collection.find(j.ExpressionStatement, {
      expression: {
        callee: {
          object: {
            type: 'ThisExpression',
          },
          property: {
            name: property,
          },
        },
      },
    });
  }

  function parseModule(p) {
    let calleeName = p.node.expression.callee.name;
    // Find the moduleName and the module's options
    let moduleName, subject, options, hasCustomSubject;
    let calleeArguments = p.node.expression.arguments.slice();
    let lastArgument = calleeArguments[calleeArguments.length - 1];
    if (lastArgument.type === 'ObjectExpression') {
      options = calleeArguments.pop();
    }
    moduleName = calleeArguments[1] || calleeArguments[0];

    let setupIdentifier = 'setupTest';
    if (options) {
      let hasIntegration = options.properties.some(p => p.key.name === 'integration');

      if (calleeName === `moduleForComponent`) {
        if (hasIntegration) {
          setupIdentifier = 'setupRenderingTest';
        } else {
          subject = j.literal(`component:${calleeArguments[0].value}`);
        }
      } else if (calleeName === 'moduleForModel') {
        subject = j.literal(`model:${calleeArguments[0].value}`);
      } else if (!hasIntegration) {
        subject = calleeArguments[0];
      }

      hasCustomSubject = options.properties.some(p => p.key.name === 'subject');
    }

    return [moduleName, options, setupIdentifier, subject, hasCustomSubject];
  }

  function updateModuleForToNestedModule() {
    const POSSIBLE_MODULES = [
      { expression: { callee: { name: 'moduleFor' } } },
      { expression: { callee: { name: 'moduleForComponent' } } },
      { expression: { callee: { name: 'moduleForModel' } } },
    ];

    function isModuleDefinition(nodePath) {
      return POSSIBLE_MODULES.some(matcher => j.match(nodePath, matcher));
    }

    const LIFE_CYCLE_METHODS = [
      { key: { name: 'before' }, value: { type: 'FunctionExpression' } },
      { key: { name: 'beforeEach' }, value: { type: 'FunctionExpression' } },
      { key: { name: 'afterEach' }, value: { type: 'FunctionExpression' } },
      { key: { name: 'after' }, value: { type: 'FunctionExpression' } },
    ];

    function isLifecycleHook(nodePath) {
      return LIFE_CYCLE_METHODS.some(matcher => j.match(nodePath, matcher));
    }

    function createModule(p) {
      let [moduleName, options, setupType, subject, hasCustomSubject] = parseModule(p);

      // Create the new `module(moduleName, function(hooks) {});` invocation
      let callback = j.functionExpression(
        null /* no function name */,
        [j.identifier('hooks')],
        j.blockStatement([
          j.expressionStatement(j.callExpression(j.identifier(setupType), [j.identifier('hooks')])),
        ])
      );
      let moduleInvocation = j.expressionStatement(
        j.callExpression(j.identifier('module'), [moduleName, callback])
      );

      if (options) {
        options.properties.forEach(property => {
          if (isLifecycleHook(property)) {
            let lifecycleStatement = j.expressionStatement(
              j.callExpression(j.memberExpression(j.identifier('hooks'), property.key), [
                property.value,
              ])
            );

            // preserve any comments that were present
            lifecycleStatement.comments = property.comments;

            callback.body.body.push(lifecycleStatement);
          }
        });
      }

      return [moduleInvocation, callback.body.body, setupType, subject, hasCustomSubject];
    }

    function processRenderingTest(testExpression) {
      let isTest = j.match(testExpression, { expression: { callee: { name: 'test' } } });
      if (!isTest) {
        return;
      }

      // mark the test function as an async function
      testExpression.expression.arguments[1].async = true;
      let testExpressionCollection = j(testExpression);

      // Transform to await render() or await clearRender()
      ['render', 'clearRender'].forEach(type => {
        findTestHelperUsageOf(testExpressionCollection, type).forEach(p => {
          let expression = p.get('expression');

          let awaitExpression = j.awaitExpression(
            j.callExpression(j.identifier(type), expression.node.arguments)
          );
          expression.replace(awaitExpression);
        });
      });

      // Migrate `this._element` -> `this.element`
      testExpressionCollection
        .find(j.MemberExpression, {
          object: {
            type: 'ThisExpression',
          },
          property: {
            name: '_element',
          },
        })
        .forEach(p => {
          let property = p.get('property');
          property.node.name = 'element';
        });
    }

    function processSubject(testExpression, subject) {
      let thisDotSubjectUsage = j(testExpression).find(j.CallExpression, {
        callee: {
          type: 'MemberExpression',
          object: {
            type: 'ThisExpression',
          },
          property: {
            name: 'subject',
          },
        },
      });

      if (thisDotSubjectUsage.size() === 0) {
        return;
      }

      thisDotSubjectUsage.forEach(p => {
        let options = p.node.arguments[0];
        let [subjectType, subjectName] = subject.value.split(':');
        let isSingletonSubject = !['model', 'component'].includes(subjectType);

        // if we don't have `options` and the type is a singleton type
        // use `this.owner.lookup(subject)`
        if (!options && isSingletonSubject) {
          p.replace(
            j.callExpression(
              j.memberExpression(
                j.memberExpression(j.thisExpression(), j.identifier('owner')),
                j.identifier('lookup')
              ),
              [subject]
            )
          );
        } else if (subjectType === 'model') {
          p.replace(
            j.callExpression(
              j.memberExpression(
                j.callExpression(
                  j.memberExpression(
                    j.memberExpression(j.thisExpression(), j.identifier('owner')),
                    j.identifier('lookup')
                  ),
                  [j.literal('service:store')]
                ),
                j.identifier('createRecord')
              ),
              [j.literal(subjectName), options].filter(Boolean)
            )
          );
        } else {
          p.replace(
            j.callExpression(
              j.memberExpression(
                j.callExpression(
                  j.memberExpression(
                    j.memberExpression(j.thisExpression(), j.identifier('owner')),
                    j.identifier('factoryFor')
                  ),
                  [subject]
                ),
                j.identifier('create')
              ),
              [options].filter(Boolean)
            )
          );
        }
      });
    }

    let programPath = root.get('program');
    let bodyPath = programPath.get('body');

    let bodyReplacement = [];
    let currentModuleCallbackBody, currentTestType, currentSubject, currentHasCustomSubject;
    bodyPath.each(expressionPath => {
      let expression = expressionPath.node;
      if (isModuleDefinition(expressionPath)) {
        let result = createModule(expressionPath);
        bodyReplacement.push(result[0]);
        currentModuleCallbackBody = result[1];
        currentTestType = result[2];
        currentSubject = result[3];
        currentHasCustomSubject = result[4];
      } else if (currentModuleCallbackBody) {
        currentModuleCallbackBody.push(expression);

        if (currentTestType === 'setupRenderingTest') {
          processRenderingTest(expression);
        } else if (currentTestType === 'setupTest' && !currentHasCustomSubject) {
          processSubject(expression, currentSubject);
        }
      } else {
        bodyReplacement.push(expression);
      }
    });

    bodyPath.replace(bodyReplacement);
  }

  function updateLookupCalls() {
    root
      .find(j.MemberExpression, {
        object: {
          object: { type: 'ThisExpression' },
          property: { name: 'container' },
        },
        property: { name: 'lookup' },
      })
      .forEach(path => {
        let thisDotOwner = j.memberExpression(j.thisExpression(), j.identifier('owner'));
        path.replace(j.memberExpression(thisDotOwner, path.value.property));
      });
  }

  function updateRegisterCalls() {
    root
      .find(j.MemberExpression, {
        object: {
          object: { type: 'ThisExpression' },
          property: { name: 'registry' },
        },
        property: { name: 'register' },
      })
      .forEach(path => {
        let thisDotOwner = j.memberExpression(j.thisExpression(), j.identifier('owner'));
        path.replace(j.memberExpression(thisDotOwner, path.value.property));
      });

    root
      .find(j.MemberExpression, {
        object: { type: 'ThisExpression' },
        property: { name: 'register' },
      })
      .forEach(path => {
        let thisDotOwner = j.memberExpression(j.thisExpression(), j.identifier('owner'));
        path.replace(j.memberExpression(thisDotOwner, path.value.property));
      });
  }

  function updateInjectCalls() {
    root
      .find(j.CallExpression, {
        callee: {
          type: 'MemberExpression',
          object: {
            object: {
              type: 'ThisExpression',
            },
            property: {
              name: 'inject',
            },
          },
        },
      })
      .forEach(p => {
        let injectType = p.node.callee.property.name;
        let injectedName = p.node.arguments[0].value;
        let localName = injectedName;
        if (p.node.arguments[1]) {
          let options = p.node.arguments[1];
          let as = options.properties.find(property => property.key.name === 'as');
          if (as) {
            localName = as.value.value;
          }
        }
        let assignment = j.assignmentExpression(
          '=',
          j.memberExpression(j.thisExpression(), j.identifier(localName)),
          j.callExpression(
            j.memberExpression(
              j.memberExpression(j.thisExpression(), j.identifier('owner')),
              j.identifier('lookup')
            ),
            [j.literal(`${injectType}:${injectedName}`)]
          )
        );

        p.replace(assignment);
      });
  }

  const printOptions = options.printOptions || { quote: 'single' };

  // Find `ember-qunit` imports
  let emberQUnitImports = root.find(j.ImportDeclaration, { source: { value: 'ember-qunit' } });
  if (emberQUnitImports.size() === 0) {
    return file.source;
  }

  moveQUnitImportsFromEmberQUnit();
  updateToNewEmberQUnitImports();
  updateModuleForToNestedModule();
  updateLookupCalls();
  updateRegisterCalls();
  updateInjectCalls();

  return root.toSource(printOptions);
};
<|endoftext|>


<commit_before>$('document').ready(function () {
    'use strict';

    var FD = {};

    FD.P_3072 = '8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006119df';

    FD.DEFAULT_RAND_LENGTH = 768;
    FD.DEFAULT_SERVER = 'http://localhost:8081/api/modexp/';

    FD.randHexString = function (length) {
        length = length === undefined ? FD.DEFAULT_RAND_LENGTH : length;
        var retval = '';
        while (retval.length < length) {
            var value = Math.floor(Math.random() * 256);
            retval += value < 10 ? '0' + value.toString(16) : value.toString(16);
        }
        return retval;
    };

    FD.appendTo = function (field, value) {
        var curval = $(field).val().toString();
        if (curval.length === 0) {
            $(field).val(value);
        } else if (curval.endsWith(',')) {
            $(field).val(curval + '\n' + value);
        } else if (curval.endsWith(',\n')) {
            $(field).val(curval + value);
        } else if (curval.endsWith('\n')) {
            $(field).val(curval + ',' + value);
        } else {
            $(field).val(curval + ',\n' + value);
        }
    };

    FD.injectVerificatum = function () {
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = 'http://www.verificatum.com/files/vjsc-1.1.0.js'; // @todo errorhandling!
        $('body').append(script);
        window.BigInt.modexp = window.BigInt.modexpVerificatum;
        $('#btn-verificatum').prop('disabled', true);
    };

    FD.stringToList = function (val) {
        if (val.length === 0) {
            return [];
        } else {
            return val.replace(/\s+/gm, '').split(',');
        }
    };

    FD.parseFields = function() {
        var data = {};
        data.defaultBase = $('#input-base-default').val().length > 0 ? $('#input-base-default').val() : undefined;
        data.defaultExponent = $('#input-exponent-default').val().length > 0 ? $('#input-exponent-default').val() : undefined;
        data.defaultModulus = $('#input-modulus-default').val().length > 0 ? $('#input-modulus-default').val() : undefined;

        var bases = FD.stringToList($('#input-bases').val());
        var exponents = FD.stringToList($('#input-exponents').val());
        var moduli = FD.stringToList($('#input-moduli').val());

        if (bases.length !== exponents.length || bases.length !== moduli.length) {
            throw 'Inequal amount of bases, exponents and moduli entered!';
        }

        data.modexps = [];
        for (var i = 0; i < bases.length; i++) {
            data.modexps.push([bases[i], exponents[i], moduli[i]]);
        }

        return data;
    };

    FD.getServer = function (field) {
        return $(field).val().length > 0 ? $(field).val() : FD.DEFAULT_SERVER;
    };

    FD.createGlyph = function (glyph) {
        var s = document.createElement('span');
        s.setAttribute('aria-hidden', true);

        switch (glyph) {
            case 'ok':
                s.setAttribute('class', 'glyphicon glyphicon-ok');
                break;
            case 'nok':
                s.setAttribute('class', 'glyphicon glyphicon-remove');
                break;
            case 'time':
                s.setAttribute('class', 'glyphicon glyphicon-time');
                break;
            case 'down':
                s.setAttribute('class', 'glyphicon glyphicon-arrow-down');
                break;
            case 'up':
                s.setAttribute('class', 'glyphicon glyphicon-arrow-up');
                break;

        }
        return s;
    };

    FD.showResults = function () {
        $('#div-no-results').hide();
        $('#div-results').show();
    };

    FD.hideResults = function () {
        $('#div-results').hide();
        $('#div-no-results').show();
    };

    FD.resetResults = function () {
        $('#form-results').trigger('reset');
        $('#div-results').hide();
        $('#div-no-results').show();

        $('#div-time-remote').hide();
        $('#p-time-remote').remove();
        $('#div-time-local').hide();
        $('#p-time-local').remove();
        $('#div-time-difference').hide();
        $('#p-time-difference').remove();
        $('#div-equal').hide();
        $('#p-equal').remove();

        $('#div-results-remote').hide();
        $('#h-results-remote').remove();
        $('#input-results-remote').val('');
        $('#div-results-local').hide();
        $('#h-results-local').remove();
        $('#input-results-local').val('');
    };

    FD.showRemoteTime = function (time, better) {
        $('#p-time-remote').remove();
        var p = document.createElement('p');
        p.id = 'p-time-remote';

        if (better === undefined) {
            p.appendChild(document.createTextNode('Remote calculation took ' + time + ' ms.'));
        } else if (better) {
            p.setAttribute('class', 'text-success');
            p.appendChild(FD.createGlyph('down'));
            p.appendChild(document.createTextNode('\xa0Remote calculation took ' + time + ' ms.'));
        } else {
            p.setAttribute('class', 'text-danger');
            p.appendChild(FD.createGlyph('up'));
            p.appendChild(document.createTextNode('\xa0Remote calculation took ' + time + ' ms.'));
        }
        $('#div-time-remote').append(p);
        $('#div-time-remote').show();
    };

    FD.showLocalTime = function (time, better) {
        $('#p-time-local').remove();
        var p = document.createElement('p');
        p.id = 'p-time-local';

        if (better === undefined) {
            p.appendChild(document.createTextNode('In-browser calculation took ' + time + ' ms.'));
        } else if (better) {
            p.setAttribute('class', 'text-success');
            p.appendChild(FD.createGlyph('down'));
            p.appendChild(document.createTextNode('\xa0In-browser calculation took ' + time + ' ms.'));
        } else {
            p.setAttribute('class', 'text-danger');
            p.appendChild(FD.createGlyph('up'));
            p.appendChild(document.createTextNode('\xa0In-browser calculation took ' + time + ' ms.'));
        }
        $('#div-time-local').append(p);
        $('#div-time-local').show();
    };

    FD.showDifference = function (time1, time2) {
        var factor = time1 >= time2 ? Math.ceil(time1/time2*100)/100 : Math.ceil(time2/time1*100)/100;

        $('#p-time-difference').remove();
        var p = document.createElement('p');
        p.id = 'p-time-difference';
        p.appendChild(FD.createGlyph('time'));
        p.appendChild(document.createTextNode('\xa0Difference: ' + Math.abs(time1 - time2) + ' ms (' + factor +' times).'));
        $('#div-time-difference').append(p);
        $('#div-time-difference').show();
    };

    FD.showEqual = function (result1, result2) {
        $('#p-equal').remove();
        var p = document.createElement('p');
        p.id = 'p-equal';

        if ((result1 === undefined && result2 !== undefined) ||
                (result2 === undefined && result1 !== undefined) ||
                result1.toLowerCase() !== result2.toLowerCase())
        {
            p.setAttribute('class', 'text-danger');
            p.appendChild(FD.createGlyph('nok'));
            p.appendChild(document.createTextNode('\xa0The results differ!'));
        } else {
            p.setAttribute('class', 'text-success');
            p.appendChild(FD.createGlyph('ok'));
            p.appendChild(document.createTextNode('\xa0Both results are equal!'));
        }

        $('#div-equal').append(p);
        $('#div-equal').show();
    };

    FD.showRemoteResult = function (result, count) {
        $('#h-results-remote').remove();
        var h = document.createElement('h4');
        h.id = 'h-results-remote';
        h.appendChild(document.createTextNode('Remote Results (' + count + '):'));
        $('#div-results-remote-title').append(h);

        $('#input-results-remote').val(result.toLowerCase());
        $('#div-results-remote').show();
    };

    FD.showLocalResult = function (result, count) {
        $('#h-results-local').remove();
        var h = document.createElement('h4');
        h.id = 'h-results-local';
        h.appendChild(document.createTextNode('Local Results (' + count + '):'));
        $('#div-results-local-title').append(h);

        $('#input-results-local').val(result.toLowerCase());
        $('#div-results-local').show();
    };

    window.FD = FD;
});<commit_msg>implemented overriding with default values<commit_after>$('document').ready(function () {
    'use strict';

    var FD = {};

    FD.P_3072 = '8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006119df';

    FD.DEFAULT_RAND_LENGTH = 768;
    FD.DEFAULT_SERVER = 'http://localhost:8081/api/modexp/';

    FD.randHexString = function (length) {
        length = length === undefined ? FD.DEFAULT_RAND_LENGTH : length;
        var retval = '';
        while (retval.length < length) {
            var value = Math.floor(Math.random() * 256);
            retval += value < 10 ? '0' + value.toString(16) : value.toString(16);
        }
        return retval;
    };

    FD.appendTo = function (field, value) {
        var curval = $(field).val().toString();
        if (curval.length === 0) {
            $(field).val(value);
        } else if (curval.endsWith(',')) {
            $(field).val(curval + '\n' + value);
        } else if (curval.endsWith(',\n')) {
            $(field).val(curval + value);
        } else if (curval.endsWith('\n')) {
            $(field).val(curval + ',' + value);
        } else {
            $(field).val(curval + ',\n' + value);
        }
    };

    FD.injectVerificatum = function () {
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = 'http://www.verificatum.com/files/vjsc-1.1.0.js'; // @todo errorhandling!
        $('body').append(script);
        window.BigInt.modexp = window.BigInt.modexpVerificatum;
        $('#btn-verificatum').prop('disabled', true);
    };

    FD.stringToList = function (val) {
        if (val.length === 0) {
            return [];
        } else {
            return val.replace(/\s+/gm, '').split(',');
        }
    };

    FD.parseFields = function () {
        var data = {};
        data.defaultBase = $('#input-base-default').val().length > 0 ? $('#input-base-default').val() : undefined;
        data.defaultExponent = $('#input-exponent-default').val().length > 0 ? $('#input-exponent-default').val() : undefined;
        data.defaultModulus = $('#input-modulus-default').val().length > 0 ? $('#input-modulus-default').val() : undefined;

        var bases = FD.stringToList($('#input-bases').val());
        var exponents = FD.stringToList($('#input-exponents').val());
        var moduli = FD.stringToList($('#input-moduli').val());

        if (bases.length !== exponents.length || bases.length !== moduli.length) {
            throw 'Inequal amount of bases, exponents and moduli entered!';
        }

        data.modexps = [];
        for (var i = 0; i < bases.length; i++) {
            data.modexps.push([bases[i] === '' ? data.defaultBase : bases[i],
                exponents[i] === '' ? data.defaultExponent : exponents[i],
                moduli[i] === '' ? data.defaultModulus : moduli[i]]);
        }
        return data;
    };

    FD.getServer = function (field) {
        return $(field).val().length > 0 ? $(field).val() : FD.DEFAULT_SERVER;
    };

    FD.createGlyph = function (glyph) {
        var s = document.createElement('span');
        s.setAttribute('aria-hidden', true);

        switch (glyph) {
            case 'ok':
                s.setAttribute('class', 'glyphicon glyphicon-ok');
                break;
            case 'nok':
                s.setAttribute('class', 'glyphicon glyphicon-remove');
                break;
            case 'time':
                s.setAttribute('class', 'glyphicon glyphicon-time');
                break;
            case 'down':
                s.setAttribute('class', 'glyphicon glyphicon-arrow-down');
                break;
            case 'up':
                s.setAttribute('class', 'glyphicon glyphicon-arrow-up');
                break;

        }
        return s;
    };

    FD.showResults = function () {
        $('#div-no-results').hide();
        $('#div-results').show();
    };

    FD.hideResults = function () {
        $('#div-results').hide();
        $('#div-no-results').show();
    };

    FD.resetResults = function () {
        $('#form-results').trigger('reset');
        $('#div-results').hide();
        $('#div-no-results').show();

        $('#div-time-remote').hide();
        $('#p-time-remote').remove();
        $('#div-time-local').hide();
        $('#p-time-local').remove();
        $('#div-time-difference').hide();
        $('#p-time-difference').remove();
        $('#div-equal').hide();
        $('#p-equal').remove();

        $('#div-results-remote').hide();
        $('#h-results-remote').remove();
        $('#input-results-remote').val('');
        $('#div-results-local').hide();
        $('#h-results-local').remove();
        $('#input-results-local').val('');
    };

    FD.showRemoteTime = function (time, better) {
        $('#p-time-remote').remove();
        var p = document.createElement('p');
        p.id = 'p-time-remote';

        if (better === undefined) {
            p.appendChild(document.createTextNode('Remote calculation took ' + time + ' ms.'));
        } else if (better) {
            p.setAttribute('class', 'text-success');
            p.appendChild(FD.createGlyph('down'));
            p.appendChild(document.createTextNode('\xa0Remote calculation took ' + time + ' ms.'));
        } else {
            p.setAttribute('class', 'text-danger');
            p.appendChild(FD.createGlyph('up'));
            p.appendChild(document.createTextNode('\xa0Remote calculation took ' + time + ' ms.'));
        }
        $('#div-time-remote').append(p);
        $('#div-time-remote').show();
    };

    FD.showLocalTime = function (time, better) {
        $('#p-time-local').remove();
        var p = document.createElement('p');
        p.id = 'p-time-local';

        if (better === undefined) {
            p.appendChild(document.createTextNode('In-browser calculation took ' + time + ' ms.'));
        } else if (better) {
            p.setAttribute('class', 'text-success');
            p.appendChild(FD.createGlyph('down'));
            p.appendChild(document.createTextNode('\xa0In-browser calculation took ' + time + ' ms.'));
        } else {
            p.setAttribute('class', 'text-danger');
            p.appendChild(FD.createGlyph('up'));
            p.appendChild(document.createTextNode('\xa0In-browser calculation took ' + time + ' ms.'));
        }
        $('#div-time-local').append(p);
        $('#div-time-local').show();
    };

    FD.showDifference = function (time1, time2) {
        var factor = time1 >= time2 ? Math.ceil(time1 / time2 * 100) / 100 : Math.ceil(time2 / time1 * 100) / 100;

        $('#p-time-difference').remove();
        var p = document.createElement('p');
        p.id = 'p-time-difference';
        p.appendChild(FD.createGlyph('time'));
        p.appendChild(document.createTextNode('\xa0Difference: ' + Math.abs(time1 - time2) + ' ms (' + factor + ' times).'));
        $('#div-time-difference').append(p);
        $('#div-time-difference').show();
    };

    FD.showEqual = function (result1, result2) {
        $('#p-equal').remove();
        var p = document.createElement('p');
        p.id = 'p-equal';

        if ((result1 === undefined && result2 !== undefined) ||
                (result2 === undefined && result1 !== undefined) ||
                result1.toLowerCase() !== result2.toLowerCase())
        {
            p.setAttribute('class', 'text-danger');
            p.appendChild(FD.createGlyph('nok'));
            p.appendChild(document.createTextNode('\xa0The results differ!'));
        } else {
            p.setAttribute('class', 'text-success');
            p.appendChild(FD.createGlyph('ok'));
            p.appendChild(document.createTextNode('\xa0Both results are equal!'));
        }

        $('#div-equal').append(p);
        $('#div-equal').show();
    };

    FD.showRemoteResult = function (result, count) {
        $('#h-results-remote').remove();
        var h = document.createElement('h4');
        h.id = 'h-results-remote';
        h.appendChild(document.createTextNode('Remote Results (' + count + '):'));
        $('#div-results-remote-title').append(h);

        $('#input-results-remote').val(result.toLowerCase());
        $('#div-results-remote').show();
    };

    FD.showLocalResult = function (result, count) {
        $('#h-results-local').remove();
        var h = document.createElement('h4');
        h.id = 'h-results-local';
        h.appendChild(document.createTextNode('Local Results (' + count + '):'));
        $('#div-results-local-title').append(h);

        $('#input-results-local').val(result.toLowerCase());
        $('#div-results-local').show();
    };

    window.FD = FD;
});<|endoftext|>


<commit_before>/**
 *@author Ludvig Boström <c13lbm>
 *@revision: Andreas Savva <ens15asa>
 *           Benjamin Björklund <c13bbd>
 *           Tobias Estefors <dv13tes>
 *
 *@note: This class is rendered from TeacherViewSubmission.js
 */

var StudentList = React.createClass({

    submissions: null,
    participants: null,

    // This method is called after the method "render".
    componentDidMount: function () {
        var newTableObject = document.getElementById("students-table");
        sorttable.makeSortable(newTableObject);
        var table11_Props = {
            filters_row_index: 1,
            remember_grid_values: true
        };
        setFilterGrid("students-table", table11_Props);
    },

    // Method that is called when a user clicks on a submission (a table row).
    // It creates a new interface for submission grading..
    clickhandle: function (user, event) {
        var student = [{
            "studentID":user.studentID,
            "studentName":user.firstName + " " + user.lastName,
            "courseID":user.courseID,
            "assignmentID":user.assignmentID,
            "teacherName":user.teacherName}];
        document.getElementById("courseContent").innerHTML = "";
        ReactDOM.render(<RenderHandle studentArray={student} idArray={this.props.idArray} scale={this.props.scale} />, document.getElementById("courseContent"));
    },

    componentWillMount: function () {
        this.submissions = this.props.submissions;
        this.participants = this.props.participants;
    },

    render: function () {

        var tmp = this;
        var userList = this.participants.map(function (user) {
            console.log(user);
            var studentSubmission=null;
            var path = "assignments/" + user.assignmentID + "/submissions/" + user.studentID + "/videos/";
            studentSubmission = path + 'submission.webm';
            console.log(studentSubmission);
            var date = new Date(user.submissionDate);
            var sourceVid = studentSubmission==null ? "images/placeholder.webm" : studentSubmission;
            return (

                    <video id="thumbNail" height="54" width="96" src={sourceVid} preload="auto"/>
                    {user.firstName + " " + user.lastName}
                    {date.getFullYear() + "-" + (date.getMonth()+1/*Months start from 0)*/ + "-" + date.getDate())}
                    {user.grade.grade}

            );

        });
        return (

                            Student
                            Date
                            Grade

                            {userList}

        );
    }
});

window.StudentList = StudentList;<commit_msg>Removed an array<commit_after>/**
 *@author Ludvig Boström <c13lbm>
 *@revision: Andreas Savva <ens15asa>
 *           Benjamin Björklund <c13bbd>
 *           Tobias Estefors <dv13tes>
 *
 *@note: This class is rendered from TeacherViewSubmission.js
 */

var StudentList = React.createClass({

    submissions: null,
    participants: null,

    // This method is called after the method "render".
    componentDidMount: function () {
        var newTableObject = document.getElementById("students-table");
        sorttable.makeSortable(newTableObject);
        var table11_Props = {
            filters_row_index: 1,
            remember_grid_values: true
        };
        setFilterGrid("students-table", table11_Props);
    },

    // Method that is called when a user clicks on a submission (a table row).
    // It creates a new interface for submission grading..
    clickhandle: function (user, event) {
        var student = [{
            "studentID":user.studentID,
            "studentName":user.firstName + " " + user.lastName,
            "courseID":user.courseID,
            "assignmentID":user.assignmentID,
            "teacherName":user.teacherName}];
        document.getElementById("courseContent").innerHTML = "";
        ReactDOM.render(<RenderHandle studentArray={student} idArray={this.props.idArray} scale={this.props.scale} />, document.getElementById("courseContent"));
    },

    componentWillMount: function () {
        this.submissions = this.props.submissions;
        this.participants = this.props.participants;
    },

    render: function () {

        var tmp = this;
        var userList = this.submissions.map(function (user) {
            console.log(user);
            var path = "assignments/" + user.assignmentID + "/submissions/" + user.studentID + "/videos/";
            var studentSubmission = path + 'submission.webm';
            var date = new Date(user.submissionDate);
            return (

                    <video id="thumbNail" height="54" width="96" src={sourceVid} preload="auto"/>
                    <video width="96" height="54" class="clip-thumbnail">
                        <source src={studentSubmission} type="video/webm"/>
                        <source src="images/placeholder.webm" type="video/webm"/>
                    </video>
                    {user.firstName + " " + user.lastName}
                    {date.getFullYear() + "-" + (date.getMonth()+1/*Months start from 0)*/ + "-" + date.getDate())}
                    {user.grade.grade}

            );

        });
        return (

                            Student
                            Date
                            Grade

                            {userList}

        );
    }
});

window.StudentList = StudentList;<|endoftext|>