<commit_before>"use strict";
// Helper function for creating a pointer
function setPointer(name, obj){
  return obj.jsav.pointer(name, obj,{visible: true,
                anchor: "left top",
                myAnchor: "right bottom",
                left: 20,
                top: -20});
}

jQuery.fn.rotate = function(degrees) {
    $(this).css({'-webkit-transform' : 'rotate('+ degrees +'deg)',
                 '-moz-transform' : 'rotate('+ degrees +'deg)',
                 '-ms-transform' : 'rotate('+ degrees +'deg)',
                 'transform' : 'rotate('+ degrees +'deg)'});
};

// Elements of the queue are stored in the first n positions of the array..
(function ($) {
  var jsav = new JSAV("AQueueFirstNposCON");
  // Relative offsets
  var leftMargin = 300;
  var topMargin = 35;
  var minusOne = jsav.ds.array(["-1"],{top: topMargin + 70, left: leftMargin + 30});
  minusOne.hide();
  var arr = jsav.ds.array([12,45,5,81,"", "", "", ""],{indexed:true, top: topMargin, left: leftMargin});
  jsav.umsg("Assume that there are n elements in the queue. By analogy to the array-based list implementation, we could require that all elements of the queue be stored in the first n positions of the array.");
  jsav.displayInit();
  var rearPointer = jsav.pointer("rear", arr, {targetIndex : 0});
  var frontPointer = jsav.pointer("front", arr, {targetIndex : 3});
  arr.highlight(3);
  jsav.umsg(" If we choose the rear element of the queue to be in position 0, then dequeue operations require only θ(1) time because the front element of the queue (the one being removed) is the last element in the array.");
  jsav.step();
  arr.highlight(0);
  arr.highlight(1);
  arr.highlight(2);
  jsav.umsg("However, enqueue operations will require θ(n) time, because the n elements currently in the queue must each be shifted one position in the array.");
  jsav.step();
  arr.unhighlight();
  rearPointer.target(arr, {relativeIndex : 3, targetIndex : 3});
  frontPointer.target(arr, {relativeIndex : 0, targetIndex : 0});
  jsav.umsg("If instead we chose the rear element of the queue to be in position n-1, then an enqueue operation is equivalent to an append operation on a list. This requires only θ(1) time.");
  jsav.step();
  jsav.umsg("But now, a dequeue operation requires θ(n) time, because all of the elements must be shifted down by one position to retain the property that the remaining $n-1$ queue elements reside in the first n-1 positions of the array.");
  jsav.step();
  jsav.step();
  jsav.recorded();
}(jQuery));

// The contents of the queue will be permitted to drift within the array.
(function ($) {
  var jsav = new JSAV("AQueueDriftposCON");

  // Relative offsets
  var leftMargin = 250;
  var topMargin = 25;
  jsav.umsg("A far more efficient implementation can be obtained by relaxing the requirement that all elements of the queue must be in the first $n$~positions of the array. We will still require that the queue be stored be in contiguous array positions, but the contents of the queue will be permitted to drift within the array, as illustrated by the following slides ");
  jsav.displayInit();
  var arr = jsav.ds.array([20,5,12,17, "", "", "", "", "", "", "", ""],{left:leftMargin, top:topMargin});
  var rearPointer =  jsav.pointer("rear", arr, {targetIndex : 3});
  var frontPointer =  jsav.pointer("front", arr, {targetIndex : 0});
  jsav.umsg(" The queue after the initial four numbers 20, 5, 12, and 17 have been inserted");
  jsav.step();
  frontPointer.target(arr, {relativeIndex : 1, targetIndex : 1});
  arr.value(0, "");
  arr.highlight(0);
  jsav.umsg("dequeue operation");
  jsav.step();
  frontPointer.target(arr, {relativeIndex : 2, targetIndex : 2});
  arr.value(1, "");
  arr.unhighlight(0);
  arr.highlight(1);
  jsav.umsg("dequeue operation");
  frontPointer.target(arr, {relativeIndex : 2, targetIndex : 2});
  jsav.step();
  arr.value(4, "3");
  arr.unhighlight(1);
  arr.highlight(4);
  jsav.umsg("dequeue operation");
  rearPointer.target(arr, {relativeIndex : 4, targetIndex : 4});
  jsav.umsg("enqueue(3)");
  jsav.step();
  arr.value(5, "30");
  arr.unhighlight(4);
  arr.highlight(5);
  jsav.umsg("dequeue operation");
  rearPointer.target(arr, {relativeIndex : 5, targetIndex : 5});
  jsav.umsg("enqueue(30)");
  jsav.step();
  arr.value(6, "4");
  arr.unhighlight(5);
  arr.highlight(6);
  rearPointer.target(arr, {relativeIndex : 6, targetIndex : 6});
  jsav.umsg("enqueue(4)");
  jsav.step();
  arr.unhighlight(6);
  jsav.umsg("Now, both the enqueue and the dequeue operations can be performed in θ(1) time because no other elements in the queue need be moved.");
  jsav.step();
  jsav.recorded();
}(jQuery));

// A problem that queue runs out of space..
(function ($) {
  var jsav = new JSAV("AQueueBadCON");

  // Relative offsets
  var leftMargin = 250;
  var topMargin = 25;
  var arr = jsav.ds.array([20,5,12,17, "", "", "", "", "", "", "", ""],{left:leftMargin, top:topMargin});
  var rearPointer =  jsav.pointer("rear", arr, {targetIndex : 3});
  var frontPointer =  jsav.pointer("front", arr, {targetIndex : 0});
  jsav.umsg("This implementation raises a new problem. Assume that the front element of the queue is initially at position~0, and that elements are added to successively higher-numbered positions in the array.");
  jsav.displayInit();
  frontPointer.target(arr, {relativeIndex : 1, targetIndex : 1});
  arr.value(0, "");
  arr.highlight(0);
  jsav.umsg(" When elements are removed from the queue, the front index increases. ");
  jsav.step();
  frontPointer.target(arr, {relativeIndex : 2, targetIndex : 2});
  arr.value(1, "");
  arr.unhighlight(0);
  arr.highlight(1);
  jsav.umsg("dequeue operation");
  frontPointer.target(arr, {relativeIndex : 2, targetIndex : 2});
  jsav.step();
  arr.value(4, "3");
  arr.unhighlight(1);
  arr.highlight(4);
  jsav.umsg("dequeue operation");
  rearPointer.target(arr, {relativeIndex : 4, targetIndex : 4});
  jsav.umsg("enqueue(3)");
  jsav.step();
  arr.value(5, "30");
  arr.unhighlight(4);
  arr.highlight(5);
  jsav.umsg("dequeue operation");
  rearPointer.target(arr, {relativeIndex : 5, targetIndex : 5});
  jsav.umsg("enqueue(30)");
  jsav.step();
  jsav.umsg("Over time, the entire queue will drift toward the higher-numbered positions in the array.");
  jsav.step();
  arr.value(2, "");
  arr.value(6, "4");
  arr.value(7, "55");
  arr.value(8, "37");
  arr.value(9, "11");
  arr.value(10, "26");
  arr.value(11, "32");
  arr.unhighlight(5);
  arr.highlight(2);
  arr.highlight(6);
  arr.highlight(7);
  arr.highlight(8);
  arr.highlight(9);
  arr.highlight(10);
  arr.highlight(11);
  frontPointer.target(arr, {relativeIndex : 3, targetIndex : 3});
  rearPointer.target(arr, {relativeIndex : 11, targetIndex : 11});
  jsav.umsg("enqueue(4), enqueue(55), enqueue(37), enqueue(11), enqueue(26), enqueue(32)");
  jsav.step();
  arr.unhighlight(2);
  arr.unhighlight(6);
  arr.unhighlight(7);
  arr.unhighlight(8);
  arr.unhighlight(9);
  arr.unhighlight(10);
  arr.unhighlight(11);
  jsav.umsg("Once an element is inserted into the highest-numbered position in the array, the queue has run out of space.");
  jsav.step();
  jsav.umsg("This happens despite the fact that there might be free positions at the low end of the array where elements have previously been removed from the queue.");
  arr.highlight(0);
  arr.highlight(1);
  arr.highlight(2);
  jsav.recorded();
}(jQuery));

(function($){
  function sin(x){
    return Math.sin(x*Math.PI/180);
  }
  function cos(x){
    return Math.cos(x*Math.PI/180);
  }
  var Circular = function(jsav, cx, cy, r1, r2, options){
    this.jsav = jsav;
    this.cx = cx;
    this.cy = cy;
    this.r1 = r1;
    this.r2 = r2;
    var defaultOptions = {};
    this.options = $.extend(defaultOptions, options);
    this.circle1 = this.jsav.g.circle(cx, cy, r1, this.options);
    this.circle2 = this.jsav.g.circle(cx, cy, r2, this.options);
    this.lines = [];
    this.values = [];
    var name = "test test";

    var i = 0, x1, y1, x2, y2, label, degree = 0, step = 30;
    while(degree < 360){
      x1 = cx + r1 * cos(degree);
      y1 = cy + r1 * sin(degree);
      x2 = cx + r2 * cos(degree);
      y2 = cy + r2 * sin(degree);
      this.lines[i] = (this.jsav.g.line(x1, y1, x2, y2 , this.options));
      label = this.jsav.label(" ");
      label.css({'position' : 'absolute',
                 left : cx + (r1+r2)/2 * cos(degree + 15) - 20 + 'px',
                 top : cy + (r1+r2)/2 * sin(degree + 15) - 10 + 'px', width : '40px', height:'20px', 'text-align': 'center'});
      this.values[i] = label;
      i++;
      degree += 30;
    }
  };
  Circular.prototype.value = JSAV.anim(function(index, value){
    var oldval = this.values[index].element.html();
    this.values[index].element.html(value);
    return [index, oldval];
  });
  Circular.prototype.pointer = function(name, index){
  var degree = 15 + 30 * index;
  var left = cos(degree)*((this.r2 - this.r1)/2*1.8);
  var top = sin(degree)*((this.r2 - this.r1)/2*1.8);
  var fx, fy;
  var tx = this.r2*cos(degree) + this.cx;
  var ty = this.r2*sin(degree) + this.cy;
  if(degree + 15 < 180){
    left = tx + 25 * cos(degree + 15) -20;
    top = ty + 25 * sin(degree + 15);
  }else{
    left = tx + 25 * cos(degree + 15) -20;
    top = ty + 25 * sin(degree + 15) - 22;
  }
  var pointer = {};
  pointer.label = this.jsav.label(name,{relativeTo: this.values[index], anchor: "center",
                          myAnchor: "center",
                          left: 0,
                          top: 0, width : 40});
  pointer.label.element.css({left : left, top : top});
  this.value(index, top.toFixed(0));
  if(degree + 15 < 180){
    fx = pointer.label.element.position().left + pointer.label.element.outerWidth()/2;
    fy = pointer.label.element.position().top;
  }else{
    fx = pointer.label.element.position().left + pointer.label.element.outerWidth()/2;
    fy = pointer.label.element.position().top + pointer.label.element.outerHeight();
  }
  pointer.arrow = this.jsav.g.line(fx, fy, tx, ty, {"stroke-width" : 2, "arrow-end":"classic-wide-long"});
  return pointer;
}

  JSAV.ext.circular = function(cx, cy, r1, r2, options) {
    return new Circular(this, cx, cy, r1, r2, $.extend({}, options));
  };
}(jQuery));

(function($){
  var jsav = new JSAV("AQueueCircularCON");

  // Relative offsets
  var cx = 400;
  var cy = 120;
  var cir = jsav.circular(cx, cy, 50, 100, {"stroke-width" : 2});
  jsav.umsg("The circular queue with array positions increasing in the clockwise direction.");
  jsav.displayInit();
  cir.value(8, "20");
  cir.value(9, "5");
  cir.value(10, "12");
  cir.value(11, "17");
  var frontP = cir.pointer("front", 8);
  var rearP = cir.pointer("rear", 11);
  jsav.umsg("The queue after the initial four numbers 20, 5, 12, and 17 have been inserted.");
  jsav.step();
  cir.value(8, " ");
  cir.value(9, " ");
  cir.value(0, "3");
  cir.value(1, "30");
  cir.value(2, "4");
  cir.value(10, "12");
  cir.value(11, "17");
  frontP.arrow.hide();
  frontP.label.hide();
  rearP.arrow.hide();
  rearP.label.hide();
  cir.pointer("front", 10);
  cir.pointer("rear", 2);
  jsav.umsg("The queue after elements 20 and 5 are deleted, following which 3, 30, and 4 are inserted.");
  jsav.step();
  jsav.recorded();
}(jQuery));

<commit_msg>Update Queue AVs<commit_after>"use strict";
// Helper function for creating a pointer
function setPointer(name, obj){
  return obj.jsav.pointer(name, obj,{visible: true,
                anchor: "left top",
                myAnchor: "right bottom",
                left: 20,
                top: -20});
}

jQuery.fn.rotate = function(degrees) {
    $(this).css({'-webkit-transform' : 'rotate('+ degrees +'deg)',
                 '-moz-transform' : 'rotate('+ degrees +'deg)',
                 '-ms-transform' : 'rotate('+ degrees +'deg)',
                 'transform' : 'rotate('+ degrees +'deg)'});
};

// Elements of the queue are stored in the first n positions of the array..
(function ($) {
  var jsav = new JSAV("AQueueFirstNposCON");
  // Relative offsets
  var leftMargin = 300;
  var topMargin = 35;
  var minusOne = jsav.ds.array(["-1"],{top: topMargin + 70, left: leftMargin + 30});
  minusOne.hide();
  var arr = jsav.ds.array([12,45,5,81,"", "", "", ""],{indexed:true, top: topMargin, left: leftMargin});
  jsav.umsg("Assume that there are n elements in the queue. By analogy to the array-based list implementation, we could require that all elements of the queue be stored in the first n positions of the array.");
  jsav.displayInit();
  var rearPointer = jsav.pointer("rear", arr, {targetIndex : 0});
  var frontPointer = jsav.pointer("front", arr, {targetIndex : 3});
  arr.highlight(3);
  jsav.umsg(" If we choose the rear element of the queue to be in position 0, then dequeue operations require only θ(1) time because the front element of the queue (the one being removed) is the last element in the array.");
  jsav.step();
  arr.highlight(0);
  arr.highlight(1);
  arr.highlight(2);
  jsav.umsg("However, enqueue operations will require θ(n) time, because the n elements currently in the queue must each be shifted one position in the array.");
  jsav.step();
  arr.unhighlight();
  rearPointer.target(arr, {relativeIndex : 3, targetIndex : 3});
  frontPointer.target(arr, {relativeIndex : 0, targetIndex : 0});
  jsav.umsg("If instead we chose the rear element of the queue to be in position n-1, then an enqueue operation is equivalent to an append operation on a list. This requires only θ(1) time.");
  jsav.step();
  jsav.umsg("But now, a dequeue operation requires θ(n) time, because all of the elements must be shifted down by one position to retain the property that the remaining $n-1$ queue elements reside in the first n-1 positions of the array.");
  jsav.step();
  jsav.step();
  jsav.recorded();
}(jQuery));

// The contents of the queue will be permitted to drift within the array.
(function ($) {
  var jsav = new JSAV("AQueueDriftposCON");

  // Relative offsets
  var leftMargin = 250;
  var topMargin = 25;
  jsav.umsg("A far more efficient implementation can be obtained by relaxing the requirement that all elements of the queue must be in the first $n$~positions of the array. We will still require that the queue be stored be in contiguous array positions, but the contents of the queue will be permitted to drift within the array, as illustrated by the following slides ");
  jsav.displayInit();
  var arr = jsav.ds.array([20,5,12,17, "", "", "", "", "", "", "", ""],{left:leftMargin, top:topMargin});
  var rearPointer =  jsav.pointer("rear", arr, {targetIndex : 3});
  var frontPointer =  jsav.pointer("front", arr, {targetIndex : 0});
  jsav.umsg(" The queue after the initial four numbers 20, 5, 12, and 17 have been inserted");
  jsav.step();
  frontPointer.target(arr, {relativeIndex : 1, targetIndex : 1});
  arr.value(0, "");
  arr.highlight(0);
  jsav.umsg("dequeue operation");
  jsav.step();
  frontPointer.target(arr, {relativeIndex : 2, targetIndex : 2});
  arr.value(1, "");
  arr.unhighlight(0);
  arr.highlight(1);
  jsav.umsg("dequeue operation");
  frontPointer.target(arr, {relativeIndex : 2, targetIndex : 2});
  jsav.step();
  arr.value(4, "3");
  arr.unhighlight(1);
  arr.highlight(4);
  jsav.umsg("dequeue operation");
  rearPointer.target(arr, {relativeIndex : 4, targetIndex : 4});
  jsav.umsg("enqueue(3)");
  jsav.step();
  arr.value(5, "30");
  arr.unhighlight(4);
  arr.highlight(5);
  jsav.umsg("dequeue operation");
  rearPointer.target(arr, {relativeIndex : 5, targetIndex : 5});
  jsav.umsg("enqueue(30)");
  jsav.step();
  arr.value(6, "4");
  arr.unhighlight(5);
  arr.highlight(6);
  rearPointer.target(arr, {relativeIndex : 6, targetIndex : 6});
  jsav.umsg("enqueue(4)");
  jsav.step();
  arr.unhighlight(6);
  jsav.umsg("Now, both the enqueue and the dequeue operations can be performed in θ(1) time because no other elements in the queue need be moved.");
  jsav.step();
  jsav.recorded();
}(jQuery));

// A problem that queue runs out of space..
(function ($) {
  var jsav = new JSAV("AQueueBadCON");

  // Relative offsets
  var leftMargin = 250;
  var topMargin = 25;
  var arr = jsav.ds.array([20,5,12,17, "", "", "", "", "", "", "", ""],{left:leftMargin, top:topMargin});
  var rearPointer =  jsav.pointer("rear", arr, {targetIndex : 3});
  var frontPointer =  jsav.pointer("front", arr, {targetIndex : 0});
  jsav.umsg("This implementation raises a new problem. Assume that the front element of the queue is initially at position~0, and that elements are added to successively higher-numbered positions in the array.");
  jsav.displayInit();
  frontPointer.target(arr, {relativeIndex : 1, targetIndex : 1});
  arr.value(0, "");
  arr.highlight(0);
  jsav.umsg(" When elements are removed from the queue, the front index increases. ");
  jsav.step();
  frontPointer.target(arr, {relativeIndex : 2, targetIndex : 2});
  arr.value(1, "");
  arr.unhighlight(0);
  arr.highlight(1);
  jsav.umsg("dequeue operation");
  frontPointer.target(arr, {relativeIndex : 2, targetIndex : 2});
  jsav.step();
  arr.value(4, "3");
  arr.unhighlight(1);
  arr.highlight(4);
  jsav.umsg("dequeue operation");
  rearPointer.target(arr, {relativeIndex : 4, targetIndex : 4});
  jsav.umsg("enqueue(3)");
  jsav.step();
  arr.value(5, "30");
  arr.unhighlight(4);
  arr.highlight(5);
  jsav.umsg("dequeue operation");
  rearPointer.target(arr, {relativeIndex : 5, targetIndex : 5});
  jsav.umsg("enqueue(30)");
  jsav.step();
  jsav.umsg("Over time, the entire queue will drift toward the higher-numbered positions in the array.");
  jsav.step();
  arr.value(2, "");
  arr.value(6, "4");
  arr.value(7, "55");
  arr.value(8, "37");
  arr.value(9, "11");
  arr.value(10, "26");
  arr.value(11, "32");
  arr.unhighlight(5);
  arr.highlight(2);
  arr.highlight(6);
  arr.highlight(7);
  arr.highlight(8);
  arr.highlight(9);
  arr.highlight(10);
  arr.highlight(11);
  frontPointer.target(arr, {relativeIndex : 3, targetIndex : 3});
  rearPointer.target(arr, {relativeIndex : 11, targetIndex : 11});
  jsav.umsg("enqueue(4), enqueue(55), enqueue(37), enqueue(11), enqueue(26), enqueue(32)");
  jsav.step();
  arr.unhighlight(2);
  arr.unhighlight(6);
  arr.unhighlight(7);
  arr.unhighlight(8);
  arr.unhighlight(9);
  arr.unhighlight(10);
  arr.unhighlight(11);
  jsav.umsg("Once an element is inserted into the highest-numbered position in the array, the queue has run out of space.");
  jsav.step();
  jsav.umsg("This happens despite the fact that there might be free positions at the low end of the array where elements have previously been removed from the queue.");
  arr.highlight(0);
  arr.highlight(1);
  arr.highlight(2);
  jsav.recorded();
}(jQuery));

// JSAV extension for circular queue.
(function($){
  function sin(x){
    return Math.sin(x*Math.PI/180);
  }
  function cos(x){
    return Math.cos(x*Math.PI/180);
  }
  var Circular = function(jsav, cx, cy, r1, r2, options){
    this.jsav = jsav;
    this.cx = cx;
    this.cy = cy;
    this.r1 = r1;
    this.r2 = r2;
    var defaultOptions = {};
    this.options = $.extend(defaultOptions, options);
    var x1, y1, x2, y2, x3, y3, x4, y4, label,
		i = 0, theta = 0, step = 30, pathString;
    this.path = [];
	this.labels = [];
    while(theta < 360){
      x1 = cx + r1 * cos(theta);
      y1 = cy + r1 * sin(theta);
      x2 = cx + r2 * cos(theta);
      y2 = cy + r2 * sin(theta);
      theta += 30;
      x3 = cx + r2 * cos(theta);
      y3 = cy + r2 * sin(theta);
      x4 = cx + r1 * cos(theta);
      y4 = cy + r1 * sin(theta);
      theta -= 30;
      pathString = "M" + x2 + "," + y2;
      pathString += " A" + r2 + "," + r2 + " 1 0,1 " + x3 + "," + y3;
      pathString += " L" + x4 + "," + y4;
      pathString += " A" + r1 + "," + r1 + " 1 0,0 " + x1 + "," + y1;
      this.path[i] = this.jsav.g.path(pathString, this.options);
      label = this.jsav.label(" ");
      label.css({'position' : 'absolute',
                 left : cx + (r1+r2)/2 * cos(theta + 15) - 20 + 'px',
                 top : cy + (r1+r2)/2 * sin(theta + 15) - 10 + 'px', width : '40px', height:'20px', 'text-align': 'center'});
      this.labels[i] = label;
      i++;
      theta += 30;
	}
  };

  Circular.prototype.value = JSAV.anim(function(index, value){
    console.log(this.labels);
    var oldval = this.labels[index].element.html();
    this.labels[index].element.html(value);
    return [index, oldval];
  });
  Circular.prototype.highlight = function(index){
    this.path[index]._setattrs({"fill" : "yellow", "opacity" : "0.5"});
  }
  Circular.prototype.unhighlight = function(index){
    this.path[index]._setattrs({"fill" : "none", "opacity" : "1.0"});
  }
  Circular.prototype.pointer = function(name, index){
    var degree = 15 + 30 * index;
    var left = cos(degree)*((this.r2 - this.r1)/2*1.8);
    var top = sin(degree)*((this.r2 - this.r1)/2*1.8);
    var fx, fy;
    var tx = this.r2*cos(degree) + this.cx;
    var ty = this.r2*sin(degree) + this.cy;
    left = tx + 25 * cos(degree + 15) -20;
    if(degree + 15 < 180){
      top = ty + 25 * sin(degree + 15);
    }else{
      top = ty + 25 * sin(degree + 15) - 22;
    }
    var pointer = {};
    pointer.label = this.jsav.label(name,{relativeTo: this.labels[index], anchor: "center",
                            myAnchor: "center",
                            left: 0,
                            top: 0, width : 40});
    pointer.label.element.css({left : left, top : top});
    fx = pointer.label.element.position().left + pointer.label.element.outerWidth()/2;
    if(degree + 15 < 180){
      fy = pointer.label.element.position().top;
    }else{
      fy = pointer.label.element.position().top + pointer.label.element.outerHeight();
    }
    pointer.arrow = this.jsav.g.line(fx, fy, tx, ty, {"stroke-width" : 2, "arrow-end":"classic-wide-long"});
    return pointer;
  }

  JSAV.ext.circular = function(cx, cy, r1, r2, options) {
    return new Circular(this, cx, cy, r1, r2, $.extend({}, options));
  };
}(jQuery));

// Array-based circular queue
(function($){
  var jsav = new JSAV("AQueueCircularCON");

  // center coordinate
  var cx = 400, cy = 120;
  // radius
  var r1 = 50, r2 = 100;
  var fx = cx, fy = cy - r2 - 15;
  var tx = cx + r2 + 15, ty = cy;
  var fx1 = fx + 70, ty2 = ty - 70;
  var path = "M" + fx + "," + fy;
      path += " C" + fx1 + "," + fy;
      path += " " + tx + "," + ty2;
      path += " " + tx + "," + ty;
  var curve = jsav.g.path(path, {"stroke-width" : 2, "arrow-end" : "classic-wide-long"});
  var cir = jsav.circular(cx, cy, r1, r2, {"stroke-width" : 2});
  jsav.umsg("The circular queue with array positions increasing in the clockwise direction.");
  jsav.displayInit();
  curve.hide();
  cir.value(8, "20");
  cir.value(9, "5");
  cir.value(10, "12");
  cir.value(11, "17");
  var frontP = cir.pointer("front", 8);
  var rearP = cir.pointer("rear", 11);
  jsav.umsg("The queue after the initial four numbers 20, 5, 12, and 17 have been inserted.");
  jsav.step();
  cir.value(8, " ");
  cir.value(9, " ");
  cir.value(0, "3");
  cir.value(1, "30");
  cir.value(2, "4");
  cir.value(10, "12");
  cir.value(11, "17");
  frontP.arrow.hide();
  frontP.label.hide();
  rearP.arrow.hide();
  rearP.label.hide();
  cir.pointer("front", 10);
  cir.pointer("rear", 2);
  jsav.umsg("The queue after elements 20 and 5 are deleted, following which 3, 30, and 4 are inserted.");
  jsav.step();
  jsav.recorded();
}(jQuery));

<|endoftext|>


<commit_before><commit_msg>make sure test blog has handle<commit_after><|endoftext|>


<commit_before>/*    Copyright 2016-2019 Firewalla Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename);

const util = require('util');

const sem = require('../sensor/SensorEventManager.js').getInstance();

const Sensor = require('./Sensor.js').Sensor;
const cp = require('child_process');

const Firewalla = require('../net2/Firewalla');

const xml2jsonBinary = Firewalla.getFirewallaHome() + "/extension/xml2json/xml2json." + Firewalla.getPlatform();

const SysManager = require('../net2/SysManager.js')
const sysManager = new SysManager()
const networkTool = require('../net2/NetworkTool')();

class NmapSensor extends Sensor {
  constructor() {
    super();
    this.interfaces = null;
    this.enabled = true; // very basic feature, always enabled

    let p = require('../net2/MessageBus.js');
    this.publisher = new p('info', 'Scan:Done', 10);
  }

  static _handleAddressEntry(address, host) {
    switch (address.addrtype) {
      case "ipv4":
        host.ipv4Addr = address.addr;
        break;
      case "mac":
        host.mac = address.addr;
        host.macVendor = address.vendor || "Unknown";
        break;
      default:
        break;
    }
  }

  static _handlePortEntry(portJson, host) {
    if (!host.ports)
      host.ports = [];

    let thisPort = {};

    thisPort.protocol = portJson.protocol;
    thisPort.port = portJson.portid;

    if (portJson.service) {
      thisPort.serviceName = portJson.service.name;
    }

    if (portJson.state) {
      thisPort.state = portJson.state.state;
    }

    host.ports.push(thisPort);
  }

  //TODO: parse more payloads from nmap script
  static _handleScriptTable(tableJSON, script) {

  }

  static _handleHostScript(scriptJSON, host) {
    if (!host.scripts)
      host.scripts = [];

    let script = {};

    script.id = scriptJSON.id;

    let table = scriptJSON.table;

    if (table) {
      script.key = table.key;

      if (table.elem && table.elem.constructor === Array) {
        table.elem.forEach((x) => {
          switch (x.key) {
            case "state":
              script.state = x["#content"];
              break;
            case "disclosure":
              script.disclosure = x["#content"];
              break;
            case "title":
              script.title = x["#content"];
              break;
            default:
          }
        });
      }
    }

    host.scripts.push(script);
  }

  static parseNmapHostResult(hostResult) {
    let host = {};

    if (hostResult.hostnames &&
      hostResult.hostnames.constructor === Object) {
      host.hostname = hostResult.hostnames.hostname.name;
      host.hostnameType = hostResult.hostnames.hostname.type;
    }

    let address = hostResult.address;

    if (address && address.constructor === Object) {
      // one address only
      NmapSensor._handleAddressEntry(address, host);
    } else if (address && address.constructor === Array) {
      // multiple addresses
      address.forEach((a) => NmapSensor._handleAddressEntry(a, host));
    }

    let port = hostResult.ports && hostResult.ports.port;

    if (port && port.constructor === Object) {
      // one port only
      NmapSensor._handlePortEntry(port, host);
    } else if (port && port.constructor === Array) {
      // multiple ports
      port.forEach((p) => NmapSensor._handlePortEntry(p));
    }

    if (hostResult.os && hostResult.os.osmatch) {
      host.os_match = hostResult.os.osmatch.name;
      host.os_accuracy = hostResult.os.osmatch.accuracy;
      host.os_class = JSON.stringify(hostResult.os.osmatch.osclass);
    }

    if (hostResult.uptime) {
      host.uptime = hostResult.uptime.seconds;
    }

    let hs = hostResult.hostscript;
    if (hs && hs.script &&
      hs.script.constructor === Object) {
      NmapSensor._handleHostScript(hs.script, host);
    } else if (hs && hs.script &&
      hs.script.constructor === Array) {
      hs.script.forEach((hr) => NmapSensor._handleHostScript(hr, host));
    }

    return host;
  }

  getNetworkRanges() {
    return this.interfaces && this.interfaces.map((x) => {
      return { range: networkTool.capSubnet(x.subnet), intf_mac: x.mac_address }
    })
  }

  run() {
    this.interfaces = sysManager.getMonitoringInterfaces();
    process.nextTick(() => {
      this.checkAndRunOnce(false);
    });
    setInterval(() => {
      this.checkAndRunOnce(false);
    }, 1000 * 60 * 120); // every 120 minutes, slow scan
    setInterval(() => {
      this.checkAndRunOnce(true);
    }, 1000 * 60 * 5); // every 5 minutes, fast scan
  }

  checkAndRunOnce(fastMode) {
    if (this.isSensorEnabled()) {
      let range = this.getNetworkRanges()
      return this.runOnce(fastMode, range)
    }
  }

  runOnce(fastMode, networkRanges) {
    if (!networkRanges)
      return Promise.reject(new Error("network range is required"));

    return Promise.all(networkRanges.map(({ range, intf_mac }) => {

      log.info("Scanning network", range, "to detect new devices...");

      try {
        range = networkTool.capSubnet(range)
      } catch (e) {
        log.error('Error reducing scan range:', range, fastMode, e);
        return Promise.resolve(); // Skipping this scan
      }

      let cmd = fastMode
        ? util.format('sudo nmap -sn -PO --host-timeout 30s  %s -oX - | %s', range, xml2jsonBinary)
        : util.format('sudo nmap -sU --host-timeout 200s --script nbstat.nse -p 137 %s -oX - | %s', range, xml2jsonBinary);

      return NmapSensor.scan(cmd)
        .then((hosts) => {
          log.info("Analyzing scan result...");

          if (hosts.length === 0) {
            log.info("No device is found for network", range);
            return;
          }
          hosts.forEach((h) => {
            log.debug("Found device:", h.ipv4Addr);
            this._processHost(h, intf_mac);
          })

        }).catch((err) => {
          log.error("Failed to scan:", err);
        });
    })).then(() => {
      setTimeout(() => {
        log.info("publish Scan:Done after scan is finished")
        this.publisher.publish("DiscoveryEvent", "Scan:Done", '0', {});
      }, 3 * 1000)

      Firewalla.isBootingComplete()
        .then((result) => {
          if (!result) {
            setTimeout(() => {
              log.info("publish Scan:Done after scan is finished")
              this.publisher.publish("DiscoveryEvent", "Scan:Done", '0', {});
            }, 7 * 1000)
          }
        })
    });
  }

  _processHost(host, intf_mac) {
    if (!host.mac) {
      for (const intf of this.interfaces) {
        const intfName = intf.name;
        if (host.ipv4Addr && host.ipv4Addr === sysManager.myIp(intfName)) {
          host.mac = sysManager.myMAC(intfName)
        } else if (host.ipv4Addr && host.ipv4Addr === sysManager.myWifiIp(intfName)) {
          host.mac = sysManager.myWifiMAC(intfName);
        } else if (host.ipv4Addr && host.ipv4Addr === sysManager.myIp2(intfName)) {
          return // do nothing on secondary ip
        } else {
          log.error("Invalid MAC Address for host", host);
          return
        }
      }
    }

    if (host && host.mac) {
      const hostInfo = {
        ipv4: host.ipv4Addr,
        ipv4Addr: host.ipv4Addr,
        mac: host.mac,
        macVendor: host.macVendor,
        intf_mac: intf_mac,
        from: "nmap"
      };

      if (host.macVendor === 'Unknown') {
        delete hostInfo.macVendor;
      }

      sem.emitEvent({
        type: "DeviceUpdate",
        message: `Found a device via NmapSensor ${hostInfo.ipv4} ${hostInfo.mac}`,
        suppressEventLogging: true,
        suppressAlarm: this.suppressAlarm,
        host: hostInfo
      });
    }
  }

  isSensorEnabled() {
    return this.enabled;
  }

  static scan(cmd) {
    log.info("Running command:", cmd);

    return new Promise((resolve, reject) => {
      cp.exec(cmd, (err, stdout, stderr) => {

        if (err || stderr) {
          reject(err || new Error(stderr));
          return;
        }

        let findings = null;
        try {
          findings = JSON.parse(stdout);
        } catch (err) {
          reject(err);
        }

        if (!findings) {
          reject(new Error("Invalid nmap scan result,", cmd));
          return;
        }

        let hostsJSON = findings.nmaprun && findings.nmaprun.host;

        if (!hostsJSON) {
          reject(new Error("Invalid nmap scan result,", cmd));
          return;
        }

        if (hostsJSON.constructor !== Array) {
          hostsJSON = [hostsJSON];
        }

        let hosts = hostsJSON.map(NmapSensor.parseNmapHostResult);

        resolve(hosts);
      })
    });

  }
}

module.exports = NmapSensor;
<commit_msg>add missing arg<commit_after>/*    Copyright 2016-2019 Firewalla Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename);

const util = require('util');

const sem = require('../sensor/SensorEventManager.js').getInstance();

const Sensor = require('./Sensor.js').Sensor;
const cp = require('child_process');

const Firewalla = require('../net2/Firewalla');

const xml2jsonBinary = Firewalla.getFirewallaHome() + "/extension/xml2json/xml2json." + Firewalla.getPlatform();

const SysManager = require('../net2/SysManager.js')
const sysManager = new SysManager()
const networkTool = require('../net2/NetworkTool')();

class NmapSensor extends Sensor {
  constructor() {
    super();
    this.interfaces = null;
    this.enabled = true; // very basic feature, always enabled

    let p = require('../net2/MessageBus.js');
    this.publisher = new p('info', 'Scan:Done', 10);
  }

  static _handleAddressEntry(address, host) {
    switch (address.addrtype) {
      case "ipv4":
        host.ipv4Addr = address.addr;
        break;
      case "mac":
        host.mac = address.addr;
        host.macVendor = address.vendor || "Unknown";
        break;
      default:
        break;
    }
  }

  static _handlePortEntry(portJson, host) {
    if (!host.ports)
      host.ports = [];

    let thisPort = {};

    thisPort.protocol = portJson.protocol;
    thisPort.port = portJson.portid;

    if (portJson.service) {
      thisPort.serviceName = portJson.service.name;
    }

    if (portJson.state) {
      thisPort.state = portJson.state.state;
    }

    host.ports.push(thisPort);
  }

  //TODO: parse more payloads from nmap script
  static _handleScriptTable(tableJSON, script) {

  }

  static _handleHostScript(scriptJSON, host) {
    if (!host.scripts)
      host.scripts = [];

    let script = {};

    script.id = scriptJSON.id;

    let table = scriptJSON.table;

    if (table) {
      script.key = table.key;

      if (table.elem && table.elem.constructor === Array) {
        table.elem.forEach((x) => {
          switch (x.key) {
            case "state":
              script.state = x["#content"];
              break;
            case "disclosure":
              script.disclosure = x["#content"];
              break;
            case "title":
              script.title = x["#content"];
              break;
            default:
          }
        });
      }
    }

    host.scripts.push(script);
  }

  static parseNmapHostResult(hostResult) {
    let host = {};

    if (hostResult.hostnames &&
      hostResult.hostnames.constructor === Object) {
      host.hostname = hostResult.hostnames.hostname.name;
      host.hostnameType = hostResult.hostnames.hostname.type;
    }

    let address = hostResult.address;

    if (address && address.constructor === Object) {
      // one address only
      NmapSensor._handleAddressEntry(address, host);
    } else if (address && address.constructor === Array) {
      // multiple addresses
      address.forEach((a) => NmapSensor._handleAddressEntry(a, host));
    }

    let port = hostResult.ports && hostResult.ports.port;

    if (port && port.constructor === Object) {
      // one port only
      NmapSensor._handlePortEntry(port, host);
    } else if (port && port.constructor === Array) {
      // multiple ports
      port.forEach((p) => NmapSensor._handlePortEntry(p, host));
    }

    if (hostResult.os && hostResult.os.osmatch) {
      host.os_match = hostResult.os.osmatch.name;
      host.os_accuracy = hostResult.os.osmatch.accuracy;
      host.os_class = JSON.stringify(hostResult.os.osmatch.osclass);
    }

    if (hostResult.uptime) {
      host.uptime = hostResult.uptime.seconds;
    }

    let hs = hostResult.hostscript;
    if (hs && hs.script &&
      hs.script.constructor === Object) {
      NmapSensor._handleHostScript(hs.script, host);
    } else if (hs && hs.script &&
      hs.script.constructor === Array) {
      hs.script.forEach((hr) => NmapSensor._handleHostScript(hr, host));
    }

    return host;
  }

  getNetworkRanges() {
    return this.interfaces && this.interfaces.map((x) => {
      return { range: networkTool.capSubnet(x.subnet), intf_mac: x.mac_address }
    })
  }

  run() {
    this.interfaces = sysManager.getMonitoringInterfaces();
    process.nextTick(() => {
      this.checkAndRunOnce(false);
    });
    setInterval(() => {
      this.checkAndRunOnce(false);
    }, 1000 * 60 * 120); // every 120 minutes, slow scan
    setInterval(() => {
      this.checkAndRunOnce(true);
    }, 1000 * 60 * 5); // every 5 minutes, fast scan
  }

  checkAndRunOnce(fastMode) {
    if (this.isSensorEnabled()) {
      let range = this.getNetworkRanges()
      return this.runOnce(fastMode, range)
    }
  }

  runOnce(fastMode, networkRanges) {
    if (!networkRanges)
      return Promise.reject(new Error("network range is required"));

    return Promise.all(networkRanges.map(({ range, intf_mac }) => {

      log.info("Scanning network", range, "to detect new devices...");

      try {
        range = networkTool.capSubnet(range)
      } catch (e) {
        log.error('Error reducing scan range:', range, fastMode, e);
        return Promise.resolve(); // Skipping this scan
      }

      let cmd = fastMode
        ? util.format('sudo nmap -sn -PO --host-timeout 30s  %s -oX - | %s', range, xml2jsonBinary)
        : util.format('sudo nmap -sU --host-timeout 200s --script nbstat.nse -p 137 %s -oX - | %s', range, xml2jsonBinary);

      return NmapSensor.scan(cmd)
        .then((hosts) => {
          log.info("Analyzing scan result...");

          if (hosts.length === 0) {
            log.info("No device is found for network", range);
            return;
          }
          hosts.forEach((h) => {
            log.debug("Found device:", h.ipv4Addr);
            this._processHost(h, intf_mac);
          })

        }).catch((err) => {
          log.error("Failed to scan:", err);
        });
    })).then(() => {
      setTimeout(() => {
        log.info("publish Scan:Done after scan is finished")
        this.publisher.publish("DiscoveryEvent", "Scan:Done", '0', {});
      }, 3 * 1000)

      Firewalla.isBootingComplete()
        .then((result) => {
          if (!result) {
            setTimeout(() => {
              log.info("publish Scan:Done after scan is finished")
              this.publisher.publish("DiscoveryEvent", "Scan:Done", '0', {});
            }, 7 * 1000)
          }
        })
    });
  }

  _processHost(host, intf_mac) {
    if (!host.mac) {
      for (const intf of this.interfaces) {
        const intfName = intf.name;
        if (host.ipv4Addr && host.ipv4Addr === sysManager.myIp(intfName)) {
          host.mac = sysManager.myMAC(intfName)
        } else if (host.ipv4Addr && host.ipv4Addr === sysManager.myWifiIp(intfName)) {
          host.mac = sysManager.myWifiMAC(intfName);
        } else if (host.ipv4Addr && host.ipv4Addr === sysManager.myIp2(intfName)) {
          return // do nothing on secondary ip
        } else {
          log.error("Invalid MAC Address for host", host);
          return
        }
      }
    }

    if (host && host.mac) {
      const hostInfo = {
        ipv4: host.ipv4Addr,
        ipv4Addr: host.ipv4Addr,
        mac: host.mac,
        macVendor: host.macVendor,
        intf_mac: intf_mac,
        from: "nmap"
      };

      if (host.macVendor === 'Unknown') {
        delete hostInfo.macVendor;
      }

      sem.emitEvent({
        type: "DeviceUpdate",
        message: `Found a device via NmapSensor ${hostInfo.ipv4} ${hostInfo.mac}`,
        suppressEventLogging: true,
        suppressAlarm: this.suppressAlarm,
        host: hostInfo
      });
    }
  }

  isSensorEnabled() {
    return this.enabled;
  }

  static scan(cmd) {
    log.info("Running command:", cmd);

    return new Promise((resolve, reject) => {
      cp.exec(cmd, (err, stdout, stderr) => {

        if (err || stderr) {
          reject(err || new Error(stderr));
          return;
        }

        let findings = null;
        try {
          findings = JSON.parse(stdout);
        } catch (err) {
          reject(err);
        }

        if (!findings) {
          reject(new Error("Invalid nmap scan result,", cmd));
          return;
        }

        let hostsJSON = findings.nmaprun && findings.nmaprun.host;

        if (!hostsJSON) {
          reject(new Error("Invalid nmap scan result,", cmd));
          return;
        }

        if (hostsJSON.constructor !== Array) {
          hostsJSON = [hostsJSON];
        }

        let hosts = hostsJSON.map(NmapSensor.parseNmapHostResult);

        resolve(hosts);
      })
    });

  }
}

module.exports = NmapSensor;
<|endoftext|>


<commit_before>sap.ui.define([
   'rootui5/panel/Controller',
   'sap/ui/model/json/JSONModel',
   'sap/ui/unified/ColorPickerPopover',
   'sap/m/Button',
   'sap/m/Table'
], function (GuiPanelController, JSONModel, ColorPickerPopover, Button, Table) {

   "use strict";
   var count = 0;
   return GuiPanelController.extend("rootui5.fitpanel.controller.FitPanel", {

         //function called from GuiPanelController
      onPanelInit : function() {
         var id = this.getView().getId();
         this.inputId = "";
         var opText = this.getView().byId("OperationText");
         var data = {
               //fDataSet:[ { fId:"1", fSet: "----" } ],
               fSelectDataId: "2",
               // fMinRange: -4,
               // fMaxRange: 4,
               fStep: 0.01,
               fRange: [-4,4],
               fUpdateRange: [-4,4]
         };
         this.getView().setModel(new JSONModel(data));
         this._data = data;
      },

      // Assign the new JSONModel to data
      OnWebsocketMsg: function(handle, msg){

         if(msg.startsWith("MODEL:")){
            var json = msg.substr(6);
            var data = JSROOT.parse(json);

            if(data) {
               this.getView().setModel(new JSONModel(data));
               this._data = data;

               this.copyModel = JSROOT.extend({},data);
            }
         }
         else {
         }

      },

      //Fitting Button
      doFit: function() {
         //Keep the #times the button is clicked
         count++;
         //Data is a new model. With getValue() we select the value of the parameter specified from id
         var data = this.getView().getModel().getData();
         //var func = this.getView().byId("TypeXY").getValue();
         var func = this.getView().byId("selectedOpText").getText();
         //We pass the value from func to C++ fRealFunc
         data.fRealFunc = func;

         //Refresh the model
         this.getView().getModel().refresh();
         //Each time we click the button, we keep the current state of the model
         this.copyModel[count] = JSROOT.extend({},data);

         if (this.websocket)
            this.websocket.Send('DOFIT:'+this.getView().getModel().getJSON());

      },

      onPanelExit: function(){

      },

      resetPanel: function(oEvent){

         if(!this.copyModel) return;

         JSROOT.extend(this._data, this.copyModel);
         this.getView().getModel().updateBindings();
         this.byId("selectedOpText").setText("gaus");
         this.byId("OperationText").setValue("");
         return;
      },

      backPanel: function() {
         //Each time we click the button, we go one step back
         count--;
         if(count < 0) return;
         if(!this.copyModel[count]) return;

         JSROOT.extend(this._data, this.copyModel[count]);
         this.getView().getModel().updateBindings();
         return;
      },

      backPanel: function() {
         //Each time we click the button, we go one step back
         count--;
         if(count < 0) return;
         if(!this.copyModel[count]) return;

         JSROOT.extend(this._data, this.copyModel[count]);
         this.getView().getModel().updateBindings();
         return;
      },

     //Change the input text field. When a function is seleced, it appears on the text input field and
     //on the text area.
       onTypeXYChange: function(){
         var data = this.getView().getModel().getData();
         var linear = this.getView().getModel().getData().fSelectXYId;
         data.fFuncChange = linear;
         this.getView().getModel().refresh();

         //updates the text area and text in selected tab, depending on the choice in TypeXY ComboBox
         var func = this.getView().byId("TypeXY").getValue();
         this.byId("OperationText").setValueLiveUpdate();
         this.byId("OperationText").setValue(func);
         this.byId("selectedOpText").setText(func);
       },

        operationTextChange: function(oEvent) {
         var newValue = oEvent.getParameter("value");
         this.byId("selectedOpText").setText(newValue);
       },

      //change the combo box in Minimization Tab --- Method depending on Radio Buttons values
      selectRB: function(){

         var data = this.getView().getModel().getData();
         var lib = this.getView().getModel().getData().fLibrary;

         // same code as initialization
         data.fMethodMin = data.fMethodMinAll[parseInt(lib)];

         // refresh all UI elements
         this.getView().getModel().refresh();
         console.log("Method = ", data.fMethodMinAll[parseInt(lib)]);

    },
      //Change the combobox in Type Function
      //When the Type (TypeFunc) is changed (Predef etc) then the combobox with the funtions (TypeXY),
      //is also changed
      selectTypeFunc: function(){

         var data = this.getView().getModel().getData();

         var typeXY = this.getView().getModel().getData().fSelectTypeId;
         var dataSet = this.getView().getModel().getData().fSelectDataId;
         console.log("typeXY = " + dataSet);

         data.fTypeXY = data.fTypeXYAll[parseInt(typeXY)];

         this.getView().getModel().refresh();
         console.log("Type = ", data.fTypeXYAll[parseInt(typeXY)]);
      },

      //Change the selected checkbox of Draw Options
      //if Do not Store is selected then No Drawing is also selected
      storeChange: function(){
         var data = this.getView().getModel().getData();
         var fDraw = this.getView().byId("noStore").getSelected();
         console.log("fDraw = ", fDraw);
         data.fNoStore = fDraw;
         this.getView().getModel().refresh();
         console.log("fNoDrawing ", data.fNoStore);
      },

      setParametersDialog: function(){
         var aColumnData = [{
            columnId: "Name"
         },
         {
            columnId: "Fix"
         },
         {
            columnId: "Bound"
         },
         {
            columnId: "Value"
         },
         {
            columnId: "Min"
         },
         {
            columnId: "Range"
         },
         {
            columnId: "Max"
         },
         {
            columnId: "Steps"
         },
         {
            columnId: "Errors"
         }];

         var colModel = new sap.ui.model.json.JSONModel();
         colModel.setData({
            columns: aColumnData
         });

         var oPersonalizationDialog = sap.ui.xmlfragment("localapp.view.SetParameters", this);
         this.getView().addDependent(oPersonalizationDialog);
         oPersonalizationDialog.open();
         var func = this.getView().byId("selectedOpText").getText();
         var oTable = new sap.m.Table({});
         oTable.setModel(colModel);

         oTable.bindAggregation("columns", "/columns", function(index, context) {
            return new sap.m.Column({
               header: new sap.m.Label({
                  text: context.getObject().columnId
               }),
            });
         });

         oTable.bindItems("/rows", function(index, context) {
            var obj = context.getObject();
            var row = new sap.m.ColumnListItem();

            for(var k in obj) {
               row.addCell(new sap.m.Text({
                  text: obj[k]
               }));
            }

            return row;
         });

         oTable.placeAt("content");

         // if (func == "gaus"){
         //    var par = 3;
         //    for (var i=0; i<par; i++){
         //       for (var j=0; j<8; j++){

         //       }
         //       //oPersonalizationDialog.addContent(new sap.m.Title)
         //    }
         // }
         // for (var i=0; i<5; i++){
         //    oTable.addContent(new sap.m.Label({
         //       text: "label",
         //       columns: [ new sap.m.Column({
         //          header: new sap.m.Text
         //       })

         //       ]
         //    }));
         //    oPersonalizationDialog.addContent(new sap.m.Text({
         //       text: "text"
         //    }));
         // }

      },

      //Cancel Button on Set Parameters Dialog Box
      onCancel: function(oEvent){
         oEvent.getSource().close();
      },

      colorPicker: function (oEvent) {
         this.inputId = oEvent.getSource().getId();
         if (!this.oColorPickerPopover) {
            this.oColorPickerPopover = new sap.ui.unified.ColorPickerPopover({
               colorString: "blue",
               mode: sap.ui.unified.ColorPickerMode.HSL,
               change: this.handleChange.bind(this)
            });
         }
         this.oColorPickerPopover.openBy(oEvent.getSource());
      },

      handleChange: function (oEvent) {
         var oView = this.getView();
         //oView.byId(this.inputId).setValue(oEvent.getParameter("colorString"));
         this.inputId = "";
         var color = oEvent.getParameter("colorString");
      },

      updateRange: function() {
         var data = this.getView().getModel().getData();
         var range = this.getView().byId("Slider").getRange();
         console.log("Slider " + range);

         //We pass the values from range array in JS to C++ fRange array
         data.fUpdateRange[0] = range[0];
         data.fUpdateRange[1] = range[1];
      },

   });

   return
});
<commit_msg>WebFitPanel6: Apply css file <commit_after>sap.ui.define([
   'rootui5/panel/Controller',
   'sap/ui/model/json/JSONModel',
   'sap/ui/unified/ColorPickerPopover',
   'sap/m/Button',
   'sap/m/Table'
], function (GuiPanelController, JSONModel, ColorPickerPopover, Button, Table) {

   "use strict";
   var count = 0;
   return GuiPanelController.extend("rootui5.fitpanel.controller.FitPanel", {

         //function called from GuiPanelController
      onPanelInit : function() {

         JSROOT.loadScript('rootui5sys/fitpanel/style/style.css');

         var id = this.getView().getId();
         this.inputId = "";
         var opText = this.getView().byId("OperationText");
         var data = {
               //fDataSet:[ { fId:"1", fSet: "----" } ],
               fSelectDataId: "2",
               // fMinRange: -4,
               // fMaxRange: 4,
               fStep: 0.01,
               fRange: [-4,4],
               fUpdateRange: [-4,4]
         };
         this.getView().setModel(new JSONModel(data));
         this._data = data;
      },

      // Assign the new JSONModel to data
      OnWebsocketMsg: function(handle, msg){

         if(msg.startsWith("MODEL:")){
            var json = msg.substr(6);
            var data = JSROOT.parse(json);

            if(data) {
               this.getView().setModel(new JSONModel(data));
               this._data = data;

               this.copyModel = JSROOT.extend({},data);
            }
         }
         else {
         }

      },

      //Fitting Button
      doFit: function() {
         //Keep the #times the button is clicked
         count++;
         //Data is a new model. With getValue() we select the value of the parameter specified from id
         var data = this.getView().getModel().getData();
         //var func = this.getView().byId("TypeXY").getValue();
         var func = this.getView().byId("selectedOpText").getText();
         //We pass the value from func to C++ fRealFunc
         data.fRealFunc = func;

         //Refresh the model
         this.getView().getModel().refresh();
         //Each time we click the button, we keep the current state of the model
         this.copyModel[count] = JSROOT.extend({},data);

         if (this.websocket)
            this.websocket.Send('DOFIT:'+this.getView().getModel().getJSON());

      },

      onPanelExit: function(){

      },

      resetPanel: function(oEvent){

         if(!this.copyModel) return;

         JSROOT.extend(this._data, this.copyModel);
         this.getView().getModel().updateBindings();
         this.byId("selectedOpText").setText("gaus");
         this.byId("OperationText").setValue("");
         return;
      },

      backPanel: function() {
         //Each time we click the button, we go one step back
         count--;
         if(count < 0) return;
         if(!this.copyModel[count]) return;

         JSROOT.extend(this._data, this.copyModel[count]);
         this.getView().getModel().updateBindings();
         return;
      },

      backPanel: function() {
         //Each time we click the button, we go one step back
         count--;
         if(count < 0) return;
         if(!this.copyModel[count]) return;

         JSROOT.extend(this._data, this.copyModel[count]);
         this.getView().getModel().updateBindings();
         return;
      },

     //Change the input text field. When a function is seleced, it appears on the text input field and
     //on the text area.
       onTypeXYChange: function(){
         var data = this.getView().getModel().getData();
         var linear = this.getView().getModel().getData().fSelectXYId;
         data.fFuncChange = linear;
         this.getView().getModel().refresh();

         //updates the text area and text in selected tab, depending on the choice in TypeXY ComboBox
         var func = this.getView().byId("TypeXY").getValue();
         this.byId("OperationText").setValueLiveUpdate();
         this.byId("OperationText").setValue(func);
         this.byId("selectedOpText").setText(func);
       },

        operationTextChange: function(oEvent) {
         var newValue = oEvent.getParameter("value");
         this.byId("selectedOpText").setText(newValue);
       },

      //change the combo box in Minimization Tab --- Method depending on Radio Buttons values
      selectRB: function(){

         var data = this.getView().getModel().getData();
         var lib = this.getView().getModel().getData().fLibrary;

         // same code as initialization
         data.fMethodMin = data.fMethodMinAll[parseInt(lib)];

         // refresh all UI elements
         this.getView().getModel().refresh();
         console.log("Method = ", data.fMethodMinAll[parseInt(lib)]);

    },
      //Change the combobox in Type Function
      //When the Type (TypeFunc) is changed (Predef etc) then the combobox with the funtions (TypeXY),
      //is also changed
      selectTypeFunc: function(){

         var data = this.getView().getModel().getData();

         var typeXY = this.getView().getModel().getData().fSelectTypeId;
         var dataSet = this.getView().getModel().getData().fSelectDataId;
         console.log("typeXY = " + dataSet);

         data.fTypeXY = data.fTypeXYAll[parseInt(typeXY)];

         this.getView().getModel().refresh();
         console.log("Type = ", data.fTypeXYAll[parseInt(typeXY)]);
      },

      //Change the selected checkbox of Draw Options
      //if Do not Store is selected then No Drawing is also selected
      storeChange: function(){
         var data = this.getView().getModel().getData();
         var fDraw = this.getView().byId("noStore").getSelected();
         console.log("fDraw = ", fDraw);
         data.fNoStore = fDraw;
         this.getView().getModel().refresh();
         console.log("fNoDrawing ", data.fNoStore);
      },

      setParametersDialog: function(){
         var aColumnData = [{
            columnId: "Name"
         },
         {
            columnId: "Fix"
         },
         {
            columnId: "Bound"
         },
         {
            columnId: "Value"
         },
         {
            columnId: "Min"
         },
         {
            columnId: "Range"
         },
         {
            columnId: "Max"
         },
         {
            columnId: "Steps"
         },
         {
            columnId: "Errors"
         }];

         var colModel = new sap.ui.model.json.JSONModel();
         colModel.setData({
            columns: aColumnData
         });

         var oPersonalizationDialog = sap.ui.xmlfragment("localapp.view.SetParameters", this);
         this.getView().addDependent(oPersonalizationDialog);
         oPersonalizationDialog.open();
         var func = this.getView().byId("selectedOpText").getText();
         var oTable = new sap.m.Table({});
         oTable.setModel(colModel);

         oTable.bindAggregation("columns", "/columns", function(index, context) {
            return new sap.m.Column({
               header: new sap.m.Label({
                  text: context.getObject().columnId
               }),
            });
         });

         oTable.bindItems("/rows", function(index, context) {
            var obj = context.getObject();
            var row = new sap.m.ColumnListItem();

            for(var k in obj) {
               row.addCell(new sap.m.Text({
                  text: obj[k]
               }));
            }

            return row;
         });

         oTable.placeAt("content");

         // if (func == "gaus"){
         //    var par = 3;
         //    for (var i=0; i<par; i++){
         //       for (var j=0; j<8; j++){

         //       }
         //       //oPersonalizationDialog.addContent(new sap.m.Title)
         //    }
         // }
         // for (var i=0; i<5; i++){
         //    oTable.addContent(new sap.m.Label({
         //       text: "label",
         //       columns: [ new sap.m.Column({
         //          header: new sap.m.Text
         //       })

         //       ]
         //    }));
         //    oPersonalizationDialog.addContent(new sap.m.Text({
         //       text: "text"
         //    }));
         // }

      },

      //Cancel Button on Set Parameters Dialog Box
      onCancel: function(oEvent){
         oEvent.getSource().close();
      },

      colorPicker: function (oEvent) {
         this.inputId = oEvent.getSource().getId();
         if (!this.oColorPickerPopover) {
            this.oColorPickerPopover = new sap.ui.unified.ColorPickerPopover({
               colorString: "blue",
               mode: sap.ui.unified.ColorPickerMode.HSL,
               change: this.handleChange.bind(this)
            });
         }
         this.oColorPickerPopover.openBy(oEvent.getSource());
      },

      handleChange: function (oEvent) {
         var oView = this.getView();
         //oView.byId(this.inputId).setValue(oEvent.getParameter("colorString"));
         this.inputId = "";
         var color = oEvent.getParameter("colorString");
      },

      updateRange: function() {
         var data = this.getView().getModel().getData();
         var range = this.getView().byId("Slider").getRange();
         console.log("Slider " + range);

         //We pass the values from range array in JS to C++ fRange array
         data.fUpdateRange[0] = range[0];
         data.fUpdateRange[1] = range[1];
      },

   });

   return
});
<|endoftext|>


<commit_before>/*
 Copyright 2012 - $Date $ by PeopleWare n.v.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

define(["dojo/_base/declare", "dojo/dom-style",
        "dijit/layout/LayoutContainer", "../_PersistentObjectEditPane", "dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin",
        "dojo/text!./PersistentObjectButtonEditPane.html", "dojo/i18n!./nls/labels",
        "ppwcode-vernacular-persistence/PersistentObject", "ppwcode-vernacular-persistence/AuditableObject",
        "ppwcode-util-oddsAndEnds/log/logger!",

         "dijit/layout/ContentPane",
        "ppwcode-vernacular-persistence/ui/auditableInfoPane/AuditableInfoPane",
        "dijit/form/Button",
        "xstyle/css!./PersistentObjectButtonEditPane.css"],
  function(declare, domStyle,
           LayoutContainer, _PersistentObjectEditPane, _TemplatedMixin, _WidgetsInTemplateMixin,
           template, labels,
           PersistentObject, AuditableObject,
           logger) {

    return declare([LayoutContainer, _PersistentObjectEditPane, _TemplatedMixin, _WidgetsInTemplateMixin], {
      // summary:
      //    Widget that extends _PersistentObjectEditPane with an actual presentation.
      //    There are buttons to control the edit cycle on the bottom of the pane.
      //    The content will show a scrollbar if it is to high or wide.
      // description:
      //    This is a ./_PersistentObjectEditPane.
      //    The widget shows buttons to go the edit mode, cancel or save an edit,
      //    and delete the persistent object.
      //    The actual actions are done by a refresher, creator, saver, and remover
      //    function.
      //    Intended to wrap around a _SemanticObjectPane, which can be injected with
      //    set("contentPane").
      //    If this contentPane has a css width, it is copied to this when set.
      //
      //    On any change of the target, we reevaluate the button display.

      templateString: template,
      labels: labels,

      design: "headline",

      getTargetType: function() {
        // summary:
        //    PersistentObject if there is no persistentObjectDetail. The target type of
        //    the persistentObjectPane otherwise.
        return this.persistentObjectPane ? this.persistentObjectPane.getTargetType() : PersistentObject;
      },

      // persistentObjectPane: ppwcode/semantics/_SemanticObjectPane
      //    An _SemanticObjectPane that displays the target.
      persistentObjectPane: null,

      _contentPane: null,
      _errorPane: null,
      _auditableInfo: null,
      _btnEdit: null,
      _btnCancel: null,
      _btnSave: null,
      _btnDelete: null,

      _poListener: null,

      postCreate: function() {
        this._setButtonsStyles(this.NOTARGET);
        if (! this.get("target")) { // TODO is this really necessary? why? write a comment
          this.set("target", null);
        }
      },

      destroy: function() {
        this._beingDestroyed = true;
        this.set("target", null);
        // will also destroy _auditableInfo, if there still is one
        this.inherited(arguments);
      },

      _wrappedDetails: function() {
        var result = [];
        if (this.persistentObjectPane) {
          result.push(this.persistentObjectPane);
        }
        result.push(this._auditableInfo);
        return result;
      },

      _propagateTarget: function(/*PersistentObject*/ po) {
        // summary:
        //    Set the target on the persistentObjectPane and _auditableInfo

        var self = this;
        if (self.get("persistentObjectPane")) {
          self.get("persistentObjectPane").set("target", po);
          if (self.opener) {
            self.get("persistentObjectPane").set("opener", self.opener);
          }
        }
        var ao = po && po.isInstanceOf(AuditableObject) ? po : null;
        // TODO invisible if there is no target
        self._auditableInfo.set("target", ao);
        if (self._poListener) {
          self._poListener.remove();
          self._poListener = null;
        }
        if (po) {
          self._poListener = po.watch(function() {
            self._setButtonsStyles(self.get("stylePresentationMode"));
          });
          self.own(self._poListener);
        }
      },

      _setOpenerAttr: function(opener) {
        this.opener = opener;
        if (this.get("persistentObjectPane")) {
          this.get("persistentObjectPane").set("opener", this.opener);
        }
      },

      _setPersistentObjectPaneAttr: function(poPane) {
        // summary:
        //    Set the persistentObjectPane. If it has a target, and we have no target,
        //    that becomes are new target.
        // description:
        //    Note that the old persistentObjectPane was not created by us,
        //    and thus also is not destroyed by us!

        // TODO poDetail target type is a PersistentObject

        // might be called implicity by constructor of WidgetBase
        var oldPoPane = this.get("persistentObjectPane");
        if (oldPoPane) {
          oldPoPane.set("target", null);
          // no destroy of oldPoDetail; we didn't create it; if we do, we have to!
          this._contentPane.removeChild(oldPoPane);
          oldPoPane.destroyRecursive();
        }
        this._set("persistentObjectPane", poPane);
        if (poPane) {
          var poPaneWidth = domStyle.get(poPane.domNode, "width");
          if (!poPaneWidth) {
            logger.info("poPane has no width set.");
          }
          else {
            domStyle.set(this.domNode, "width", (poPaneWidth + 16) + "px"); // see css: 16px padding
          }
          this._contentPane.addChild(poPane);
          // new detail might already have a target
          var ourPo = this.get("target");
          var wrappedPo = poPane.get("target");
          if (ourPo) {
            poPane.set("target", ourPo);
          }
          else if (wrappedPo) {
            this.set("target", wrappedPo);
          }
          // else we both have null targets; ok
        }
        this.resize();
      },

      validate: function() {
        // TODO this is not functional in this version
        // TODO: standard Widget function?
        if (this.get("presentationMode") === this.EDIT) {
          var poPane = this.get("persistentObjectPane");
          if (poPane && poPane.validate) {
            return poPane.validate();
          }
          else {
            return true;
          }
        }
        else {
          return true;
        }
      },

      _setButtonsStyles: function(stylePresentationMode) {
        // Set the button style.
        this._c_pre(function() { return stylePresentationMode && this.stylePresentationModes.indexOf(stylePresentationMode) >= 0; });

        var po = this.get("target");
        var busy = (stylePresentationMode === this.BUSY);
        this._setVisible(this._btnEdit, stylePresentationMode === this.VIEW && (po.get("editable") || po.get("deletable")), false);
        this._setVisible(this._btnCancel, this.isInEditMode(), busy);
        this._setVisible(this._btnDelete, this.isInEditMode() && po.get("deletable") && po.get("persistenceId"), busy);
        this._setVisible(this._btnSave, this.isInEditMode() && (po.get("editable") || !po.get("persistenceId")), busy);
      },

      _localPresentationModeChange: function(presentationMode) {
        this._setButtonsStyles(this.get("stylePresentationMode"));
      },

      _setVisible: function (/*Button*/ button, /*Boolean*/ condition, /*Boolean*/ busy) {
        // IDEA use FX
        if (button && button.domNode) {
          var displayStyle = condition ? "inline-block" : "none";
          domStyle.set(button.domNode, "display", displayStyle);
          button.set("disabled", !condition || busy);
        }
        // TODO should listen to editable and deletable
      }

  });

});
<commit_msg>fix we need to blur the last field edited: if it viewmodel update is triggered by onChange, we need the blur to update the viewmodel<commit_after>/*
 Copyright 2012 - $Date $ by PeopleWare n.v.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

define(["dojo/_base/declare", "dojo/dom-style",
        "dijit/layout/LayoutContainer", "../_PersistentObjectEditPane", "dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin",
        "dojo/text!./PersistentObjectButtonEditPane.html", "dojo/i18n!./nls/labels",
        "ppwcode-vernacular-persistence/PersistentObject", "ppwcode-vernacular-persistence/AuditableObject",
        "ppwcode-util-oddsAndEnds/log/logger!",

         "dijit/layout/ContentPane",
        "ppwcode-vernacular-persistence/ui/auditableInfoPane/AuditableInfoPane",
        "dijit/form/Button",
        "xstyle/css!./PersistentObjectButtonEditPane.css"],
  function(declare, domStyle,
           LayoutContainer, _PersistentObjectEditPane, _TemplatedMixin, _WidgetsInTemplateMixin,
           template, labels,
           PersistentObject, AuditableObject,
           logger) {

    return declare([LayoutContainer, _PersistentObjectEditPane, _TemplatedMixin, _WidgetsInTemplateMixin], {
      // summary:
      //    Widget that extends _PersistentObjectEditPane with an actual presentation.
      //    There are buttons to control the edit cycle on the bottom of the pane.
      //    The content will show a scrollbar if it is to high or wide.
      // description:
      //    This is a ./_PersistentObjectEditPane.
      //    The widget shows buttons to go the edit mode, cancel or save an edit,
      //    and delete the persistent object.
      //    The actual actions are done by a refresher, creator, saver, and remover
      //    function.
      //    Intended to wrap around a _SemanticObjectPane, which can be injected with
      //    set("contentPane").
      //    If this contentPane has a css width, it is copied to this when set.
      //
      //    On any change of the target, we reevaluate the button display.

      templateString: template,
      labels: labels,

      design: "headline",

      getTargetType: function() {
        // summary:
        //    PersistentObject if there is no persistentObjectDetail. The target type of
        //    the persistentObjectPane otherwise.
        return this.persistentObjectPane ? this.persistentObjectPane.getTargetType() : PersistentObject;
      },

      // persistentObjectPane: ppwcode/semantics/_SemanticObjectPane
      //    An _SemanticObjectPane that displays the target.
      persistentObjectPane: null,

      _contentPane: null,
      _errorPane: null,
      _auditableInfo: null,
      _btnEdit: null,
      _btnCancel: null,
      _btnSave: null,
      _btnDelete: null,

      _poListener: null,

      postCreate: function() {
        this._setButtonsStyles(this.NOTARGET);
        if (! this.get("target")) { // TODO is this really necessary? why? write a comment
          this.set("target", null);
        }
      },

      destroy: function() {
        this._beingDestroyed = true;
        this.set("target", null);
        // will also destroy _auditableInfo, if there still is one
        this.inherited(arguments);
      },

      _wrappedDetails: function() {
        var result = [];
        if (this.persistentObjectPane) {
          result.push(this.persistentObjectPane);
        }
        result.push(this._auditableInfo);
        return result;
      },

      _propagateTarget: function(/*PersistentObject*/ po) {
        // summary:
        //    Set the target on the persistentObjectPane and _auditableInfo

        var self = this;
        if (self.get("persistentObjectPane")) {
          self.get("persistentObjectPane").set("target", po);
          if (self.opener) {
            self.get("persistentObjectPane").set("opener", self.opener);
          }
        }
        var ao = po && po.isInstanceOf(AuditableObject) ? po : null;
        // TODO invisible if there is no target
        self._auditableInfo.set("target", ao);
        if (self._poListener) {
          self._poListener.remove();
          self._poListener = null;
        }
        if (po) {
          self._poListener = po.watch(function() {
            self._setButtonsStyles(self.get("stylePresentationMode"));
          });
          self.own(self._poListener);
        }
      },

      _setOpenerAttr: function(opener) {
        this.opener = opener;
        if (this.get("persistentObjectPane")) {
          this.get("persistentObjectPane").set("opener", this.opener);
        }
      },

      _setPersistentObjectPaneAttr: function(poPane) {
        // summary:
        //    Set the persistentObjectPane. If it has a target, and we have no target,
        //    that becomes are new target.
        // description:
        //    Note that the old persistentObjectPane was not created by us,
        //    and thus also is not destroyed by us!

        // TODO poDetail target type is a PersistentObject

        // might be called implicity by constructor of WidgetBase
        var oldPoPane = this.get("persistentObjectPane");
        if (oldPoPane) {
          oldPoPane.set("target", null);
          // no destroy of oldPoDetail; we didn't create it; if we do, we have to!
          this._contentPane.removeChild(oldPoPane);
          oldPoPane.destroyRecursive();
        }
        this._set("persistentObjectPane", poPane);
        if (poPane) {
          var poPaneWidth = domStyle.get(poPane.domNode, "width");
          if (!poPaneWidth) {
            logger.info("poPane has no width set.");
          }
          else {
            domStyle.set(this.domNode, "width", (poPaneWidth + 16) + "px"); // see css: 16px padding
          }
          this._contentPane.addChild(poPane);
          // new detail might already have a target
          var ourPo = this.get("target");
          var wrappedPo = poPane.get("target");
          if (ourPo) {
            poPane.set("target", ourPo);
          }
          else if (wrappedPo) {
            this.set("target", wrappedPo);
          }
          // else we both have null targets; ok
        }
        this.resize();
      },

      validate: function() {
        // TODO this is not functional in this version
        // TODO: standard Widget function?
        if (this.get("presentationMode") === this.EDIT) {
          var poPane = this.get("persistentObjectPane");
          if (poPane && poPane.validate) {
            return poPane.validate();
          }
          else {
            return true;
          }
        }
        else {
          return true;
        }
      },

      save: function() {
        // summary:
        //   Override: before we save, put the focus on the button, to make sure
        //   that the last edited field has lost focus. This might be necessary
        //   (onChange) to propagate changes from the field to the viewmodel object.
        this._btnSave.focus();
        this.inherited(arguments);
      },

      _setButtonsStyles: function(stylePresentationMode) {
        // Set the button style.
        this._c_pre(function() { return stylePresentationMode && this.stylePresentationModes.indexOf(stylePresentationMode) >= 0; });

        var po = this.get("target");
        var busy = (stylePresentationMode === this.BUSY);
        this._setVisible(this._btnEdit, stylePresentationMode === this.VIEW && (po.get("editable") || po.get("deletable")), false);
        this._setVisible(this._btnCancel, this.isInEditMode(), busy);
        this._setVisible(this._btnDelete, this.isInEditMode() && po.get("deletable") && po.get("persistenceId"), busy);
        this._setVisible(this._btnSave, this.isInEditMode() && (po.get("editable") || !po.get("persistenceId")), busy);
      },

      _localPresentationModeChange: function(presentationMode) {
        this._setButtonsStyles(this.get("stylePresentationMode"));
      },

      _setVisible: function (/*Button*/ button, /*Boolean*/ condition, /*Boolean*/ busy) {
        // IDEA use FX
        if (button && button.domNode) {
          var displayStyle = condition ? "inline-block" : "none";
          domStyle.set(button.domNode, "display", displayStyle);
          button.set("disabled", !condition || busy);
        }
        // TODO should listen to editable and deletable
      }

  });

});
<|endoftext|>


<commit_before>angular
    .module('app.guild')
    .directive('wlfgProgressGuild', wlfgProgressGuild);

wlfgProgressGuild.$inject = ['__env', 'progress'];
function wlfgProgressGuild(__env, progress) {
    var directive = {
        link: link,
        restrict: 'A',
        templateUrl: 'app/guild/directive/progress/guild.progress.directive.html'
    };
    return directive;

    function link(scope, element, attrs) {
        scope.$watch(attrs.wlfgProgressGuild, function(progress){
            if (progress) {
                scope.progressTooltip = [];
                scope.progressName = __env.tiers[__env.tiers.current].name;
                scope.progressTotal = __env.tiers[__env.tiers.current].bosses.length;
                scope.progress = progress;
                if (attrs.region && attrs.realm && attrs.name) {
                    scope.progressTooltipLoad = false;
                    angular.forEach(__env.tiers[__env.tiers.current].bosses, function(value, key) {
                        scope.progressTooltip.push({difficulty: 'common', 'boss': 'N: '+value});
                    });
                } else {
                    buildTooltip();
                }
            } else {
                scope.progress = {};
                scope.progressTooltip = [];
                scope.progressName = __env.tiers[__env.tiers.current].name;
                angular.forEach(__env.tiers[__env.tiers.current].bosses, function(value, key) {
                    scope.progressTooltip.push({difficulty: 'common', 'boss': 'N: '+value});
                });
            }
        });

        scope.loadTooltip = function() {
            if (!scope.progressTooltipLoad) {
                scope.progressTooltipLoad = true;
                progress.get({tier: __env.tiers.current, raid: __env.tiers[__env.tiers.current].name, region: attrs.region, realm: attrs.realm, name: attrs.name}, function (progress) {
                    scope.progress = progress;
                    changeTooltip();
                });
            }
        };

        function buildTooltip() {
            var progress = scope.progress;
            if (progress) {
                angular.forEach(__env.tiers[__env.tiers.current].bosses, function(value, key) {
                    if (progress.mythic && progress.mythic[value] && progress.mythic[value].timestamps && progress.mythic[value].timestamps.length > 0) {
                        scope.progressTooltip.push({difficulty: 'legendary', 'boss': 'M: '+value});
                    } else if (progress.heroic && progress.heroic[value] && progress.heroic[value].timestamps && progress.heroic[value].timestamps.length > 0) {
                        scope.progressTooltip.push({difficulty: 'epic', 'boss': 'H: '+value});
                    } else if (progress.normal && progress.normal[value] && progress.normal[value].timestamps && progress.normal[value].timestamps.length > 0) {
                        scope.progressTooltip.push({difficulty: 'rare', 'boss': 'N: '+value});
                    } else {
                         scope.progressTooltip.push({difficulty: 'common', 'boss': 'N: '+value});
                    }
                });
            } else {
                angular.forEach(__env.tiers[__env.tiers.current].bosses, function(value, key) {
                    scope.progressTooltip.push({difficulty: 'common', 'boss': 'N: '+value});
                });
            }
        }

        function changeTooltip() {
            var progress = scope.progress;
            if (progress) {
                angular.forEach(__env.tiers[__env.tiers.current].bosses, function(value, key) {
                    if (progress.mythic && progress.mythic[value] && progress.mythic[value].timestamps && progress.mythic[value].timestamps.length > 0) {
                        scope.progressTooltip[key].difficulty = "legendary";
                    } else if (progress.heroic && progress.heroic[value] && progress.heroic[value].timestamps && progress.heroic[value].timestamps.length > 0) {
                        scope.progressTooltip[key].difficulty = "epic";
                    } else if (progress.normal && progress.normal[value] && progress.normal[value].timestamps && progress.normal[value].timestamps.length > 0) {
                        scope.progressTooltip[key].difficulty = "rare";
                    } else {
                        scope.progressTooltip[key].difficulty = "common";
                    }
                });
            }
        }
    }
}<commit_msg>Fix progressTotal<commit_after>angular
    .module('app.guild')
    .directive('wlfgProgressGuild', wlfgProgressGuild);

wlfgProgressGuild.$inject = ['__env', 'progress'];
function wlfgProgressGuild(__env, progress) {
    var directive = {
        link: link,
        restrict: 'A',
        templateUrl: 'app/guild/directive/progress/guild.progress.directive.html'
    };
    return directive;

    function link(scope, element, attrs) {
        scope.$watch(attrs.wlfgProgressGuild, function(progress){
            if (progress) {
                scope.progressTooltip = [];
                scope.progressName = __env.tiers[__env.tiers.current].name;
                scope.progressTotal = __env.tiers[__env.tiers.current].bosses.length;
                scope.progress = progress;
                if (attrs.region && attrs.realm && attrs.name) {
                    scope.progressTooltipLoad = false;
                    angular.forEach(__env.tiers[__env.tiers.current].bosses, function(value, key) {
                        scope.progressTooltip.push({difficulty: 'common', 'boss': 'N: '+value});
                    });
                } else {
                    buildTooltip();
                }
            } else {
                scope.progress = {};
                scope.progressTooltip = [];
                scope.progressName = __env.tiers[__env.tiers.current].name;
                scope.progressTotal = __env.tiers[__env.tiers.current].bosses.length;
                angular.forEach(__env.tiers[__env.tiers.current].bosses, function(value, key) {
                    scope.progressTooltip.push({difficulty: 'common', 'boss': 'N: '+value});
                });
            }
        });

        scope.loadTooltip = function() {
            if (!scope.progressTooltipLoad) {
                scope.progressTooltipLoad = true;
                progress.get({tier: __env.tiers.current, raid: __env.tiers[__env.tiers.current].name, region: attrs.region, realm: attrs.realm, name: attrs.name}, function (progress) {
                    scope.progress = progress;
                    changeTooltip();
                });
            }
        };

        function buildTooltip() {
            var progress = scope.progress;
            if (progress) {
                angular.forEach(__env.tiers[__env.tiers.current].bosses, function(value, key) {
                    if (progress.mythic && progress.mythic[value] && progress.mythic[value].timestamps && progress.mythic[value].timestamps.length > 0) {
                        scope.progressTooltip.push({difficulty: 'legendary', 'boss': 'M: '+value});
                    } else if (progress.heroic && progress.heroic[value] && progress.heroic[value].timestamps && progress.heroic[value].timestamps.length > 0) {
                        scope.progressTooltip.push({difficulty: 'epic', 'boss': 'H: '+value});
                    } else if (progress.normal && progress.normal[value] && progress.normal[value].timestamps && progress.normal[value].timestamps.length > 0) {
                        scope.progressTooltip.push({difficulty: 'rare', 'boss': 'N: '+value});
                    } else {
                         scope.progressTooltip.push({difficulty: 'common', 'boss': 'N: '+value});
                    }
                });
            } else {
                angular.forEach(__env.tiers[__env.tiers.current].bosses, function(value, key) {
                    scope.progressTooltip.push({difficulty: 'common', 'boss': 'N: '+value});
                });
            }
        }

        function changeTooltip() {
            var progress = scope.progress;
            if (progress) {
                angular.forEach(__env.tiers[__env.tiers.current].bosses, function(value, key) {
                    if (progress.mythic && progress.mythic[value] && progress.mythic[value].timestamps && progress.mythic[value].timestamps.length > 0) {
                        scope.progressTooltip[key].difficulty = "legendary";
                    } else if (progress.heroic && progress.heroic[value] && progress.heroic[value].timestamps && progress.heroic[value].timestamps.length > 0) {
                        scope.progressTooltip[key].difficulty = "epic";
                    } else if (progress.normal && progress.normal[value] && progress.normal[value].timestamps && progress.normal[value].timestamps.length > 0) {
                        scope.progressTooltip[key].difficulty = "rare";
                    } else {
                        scope.progressTooltip[key].difficulty = "common";
                    }
                });
            }
        }
    }
}<|endoftext|>


<commit_before>/* eslint-env browser */

import * as project from './lib/project';

export let graphData;

// TODO: Hook this up to the log out button on the graph view. It is currently not hooked up to anything,
// but functions properly
document.addEventListener('DOMContentLoaded', () => {
  project.addProjectAnchorClickHandler();

  document.getElementById('logOut').addEventListener('click', () => {
    document.location.href = '/logout';
  });
  document.getElementById('backButton').addEventListener('click', () => {

    // If the current div is the d3Container

    if (document.querySelector('#hierarchy').classList.contains('hidden')) {

      toggle(document.querySelector('#d3Container'));

      toggle(document.querySelector('#hierarchy'));

    } else {

      toggle(document.querySelector('#projects'));

      toggle(document.querySelector('#hierarchy'));

      toggle(document.querySelector('#backButton'));
    }
});
});

/**
 * Query the page for a set of elements given a CSS selector.
 *
 * @param selector CSS selector
 * @returns {*} Array of matched elements
 */
export function querySelectorAll (selector) {
  return Array.from(document.querySelectorAll(selector));
}

/**
 * Toggles the visibility of the passed in element.
 *
 * @param element the element that will be hidden/displayed
 */
export function toggle (element) {
  if (element.classList.contains('hidden')) {
    element.classList.remove('hidden');
  } else {
    element.classList.add('hidden');
  }
}

/**
 * Makes an AJAX request to the provided endpoint for the project graph.
 *
 * @param projectId
 * @returns {*}
 */
export function getGraph (projectId) {
  // TODO: Refactor to use the request module and promises
  return new Promise((resolve, reject) => {
    let httpRequest = new XMLHttpRequest();
    httpRequest.onreadystatechange = () => {
      if (httpRequest.readyState === XMLHttpRequest.DONE) {
        if (httpRequest.status === 200) {
          resolve(JSON.parse(httpRequest.responseText));
        } else {
          console.log('There was a problem requesting to the graph endpoint.');
          reject({status: httpRequest.status, response: httpRequest.responseText});
        }
      }
    };
    httpRequest.open('GET', '?project=' + projectId);
    httpRequest.send();
  });
}
<commit_msg>fixed creepy lint errors<commit_after>/* eslint-env browser */

import * as project from './lib/project';

export let graphData;

// TODO: Hook this up to the log out button on the graph view. It is currently not hooked up to anything,
// but functions properly
document.addEventListener('DOMContentLoaded', () => {
  project.addProjectAnchorClickHandler();
  document.getElementById('logOut').addEventListener('click', () => {
    document.location.href = '/logout';
  });
  document.getElementById('backButton').addEventListener('click', () => {
    // If the current div is the d3Container
    if (document.querySelector('#hierarchy').classList.contains('hidden')) {
      toggle(document.querySelector('#d3Container'));
      toggle(document.querySelector('#hierarchy'));
    } else {
      toggle(document.querySelector('#projects'));
      toggle(document.querySelector('#hierarchy'));
      toggle(document.querySelector('#backButton'));
    }
  });
});

/**
 * Query the page for a set of elements given a CSS selector.
 *
 * @param selector CSS selector
 * @returns {*} Array of matched elements
 */
export function querySelectorAll (selector) {
  return Array.from(document.querySelectorAll(selector));
}

/**
 * Toggles the visibility of the passed in element.
 *
 * @param element the element that will be hidden/displayed
 */
export function toggle (element) {
  if (element.classList.contains('hidden')) {
    element.classList.remove('hidden');
  } else {
    element.classList.add('hidden');
  }
}

/**
 * Makes an AJAX request to the provided endpoint for the project graph.
 *
 * @param projectId
 * @returns {*}
 */
export function getGraph (projectId) {
  // TODO: Refactor to use the request module and promises
  return new Promise((resolve, reject) => {
    let httpRequest = new XMLHttpRequest();
    httpRequest.onreadystatechange = () => {
      if (httpRequest.readyState === XMLHttpRequest.DONE) {
        if (httpRequest.status === 200) {
          resolve(JSON.parse(httpRequest.responseText));
        } else {
          console.log('There was a problem requesting to the graph endpoint.');
          reject({status: httpRequest.status, response: httpRequest.responseText});
        }
      }
    };
    httpRequest.open('GET', '?project=' + projectId);
    httpRequest.send();
  });
}
<|endoftext|>


<commit_before>// Jenny
//
// Callbacks:
//   jenny:toggle:action_class
//   jenny:loading:action_class
//   jenny:failed:action_class
//   jenny:loaded:action_class
//   jenny:cancel:action_class
//
// TODO: need post-request callbacks

var Jenny = {
	debug: false,

	toggleElement: function(el) {
		Jenny.toggle(parseInt(el.readAttribute('new_record')),
		             el.readAttribute('header_id'),
		             el.readAttribute('link_id'),
		             el.readAttribute('form_id'));
	},

	// Handles typical jenny toggles
	toggle: function(new_record, header_id, link_id, form_id) {
		var header = $(header_id);
		var link = $(link_id);
		var form = $(form_id);

		if (new_record) {
			if (link)
	        	link.toggle();
	        if (!form.visible())
		      Effect.BlindDown(form_id, { duration: .3 });
		    else
		      Effect.BlindUp(form_id, { duration: .3 });
		} else {
			var formVisible = form.visible();

	        if (!formVisible) {
		    	Effect.BlindDown(form_id, { duration: .3 });
				formVisible = true;
			} else {
		    	Effect.BlindUp(form_id, { duration: .3 });
				formVisible = false;
			}

			if (header)
			{
	        	if (!formVisible)
			    	Effect.BlindDown(header_id, { duration: .3 });
				else
		    		Effect.BlindUp(header_id, { duration: .3 });
			}
		}

		Form.reset(form_id);

		if (form.hasClassName('form_error'))
		{
			form.removeClassName('form_error');
		}

		$$('# ' + form_id + ' .error').each(function(e){e.remove();});

		if (form.getStyle('display') == 'block' && form.down('.focus'))
		{
			form.auto_focus();
		}

		var formClass = "";
		document.fire("jenny:toggle:" + formClass, {form:form});
	},

	// Handles a typical jenny app_form
	handleForm: function(form) {
		var url = form.readAttribute('action');
		var formClass = form.readAttribute('jennytype');

		if (Jenny.debug)
			console.log('JENNY:CB:' + formClass + ' -> ' + url);

	    new Ajax.Request(url, {
	      asynchronous: true,
	      evalScripts: true,
	      method: form.readAttribute('method'),
	      parameters: form.serialize(),
	      onLoading: function() {
		  	form.down('.submit').hide();
		  	form.down('img.loading').show();
			document.fire("jenny:loading:" + formClass, {form:form});
	      },
	      onFailure: function(response) {
		  	form.down('.submit').show();
		  	form.down('img.loading').hide();
			document.fire("jenny:failed:" + formClass, {form:form});
	      },
	      onSuccess: function(response){
		    // Handled in the RJS
			document.fire("jenny:loaded:" + formClass, {form:form});
	      }
	   });
    },

    handleCancelForm: function(form) {
		var formClass = form.readAttribute('jennytype');
		Jenny.toggleElement(form);
		document.fire("jenny:cancel:" + formClass, {form:form});
	}
};

// Generic jenny form
document.on('submit', 'form.jenny_form', function(e, el) {
	Jenny.handleForm(el);
	e.stop();
});

document.on('click', 'a.new_task_list_link', function(e, el) {
	Jenny.toggleElement(el);
	e.stop();
});

// Jenny cancel on create
document.on('click', 'a.inline_form_create_cancel', function(e, el) {
	Jenny.handleCancelForm(el.up('form')); // hide form
	e.stop();
});

// Jenny cancel on update
document.on('click', 'a.inline_form_update_cancel', function(e, el) {
	Jenny.handleCancelForm(el.up('form')); // hide form
	e.stop();
});
<commit_msg>Rearrange jenny event stop<commit_after>// Jenny
//
// Callbacks:
//   jenny:toggle:action_class
//   jenny:loading:action_class
//   jenny:failed:action_class
//   jenny:loaded:action_class
//   jenny:cancel:action_class
//
// TODO: need post-request callbacks

var Jenny = {
	debug: false,

	toggleElement: function(el) {
		Jenny.toggle(parseInt(el.readAttribute('new_record')),
		             el.readAttribute('header_id'),
		             el.readAttribute('link_id'),
		             el.readAttribute('form_id'));
	},

	// Handles typical jenny toggles
	toggle: function(new_record, header_id, link_id, form_id) {
		var header = $(header_id);
		var link = $(link_id);
		var form = $(form_id);

		if (new_record) {
			if (link)
	        	link.toggle();
	        if (!form.visible())
		      Effect.BlindDown(form_id, { duration: .3 });
		    else
		      Effect.BlindUp(form_id, { duration: .3 });
		} else {
			var formVisible = form.visible();

	        if (!formVisible) {
		    	Effect.BlindDown(form_id, { duration: .3 });
				formVisible = true;
			} else {
		    	Effect.BlindUp(form_id, { duration: .3 });
				formVisible = false;
			}

			if (header)
			{
	        	if (!formVisible)
			    	Effect.BlindDown(header_id, { duration: .3 });
				else
		    		Effect.BlindUp(header_id, { duration: .3 });
			}
		}

		Form.reset(form_id);

		if (form.hasClassName('form_error'))
		{
			form.removeClassName('form_error');
		}

		$$('# ' + form_id + ' .error').each(function(e){e.remove();});

		if (form.getStyle('display') == 'block' && form.down('.focus'))
		{
			form.auto_focus();
		}

		var formClass = "";
		document.fire("jenny:toggle:" + formClass, {form:form});
	},

	// Handles a typical jenny app_form
	handleForm: function(form) {
		var url = form.readAttribute('action');
		var formClass = form.readAttribute('jennytype');

		if (Jenny.debug)
			console.log('JENNY:CB:' + formClass + ' -> ' + url);

	    new Ajax.Request(url, {
	      asynchronous: true,
	      evalScripts: true,
	      method: form.readAttribute('method'),
	      parameters: form.serialize(),
	      onLoading: function() {
		  	form.down('.submit').hide();
		  	form.down('img.loading').show();
			document.fire("jenny:loading:" + formClass, {form:form});
	      },
	      onFailure: function(response) {
		  	form.down('.submit').show();
		  	form.down('img.loading').hide();
			document.fire("jenny:failed:" + formClass, {form:form});
	      },
	      onSuccess: function(response){
		    // Handled in the RJS
			document.fire("jenny:loaded:" + formClass, {form:form});
	      }
	   });
    },

    handleCancelForm: function(form) {
		var formClass = form.readAttribute('jennytype');
		Jenny.toggleElement(form);
		document.fire("jenny:cancel:" + formClass, {form:form});
	}
};

// Generic jenny form
document.on('submit', 'form.jenny_form', function(e, el) {
  e.stop();
  Jenny.handleForm(el);
});

document.on('click', 'a.new_task_list_link', function(e, el) {
  e.stop();
  Jenny.toggleElement(el);
});

// Jenny cancel on create
document.on('click', 'a.inline_form_create_cancel', function(e, el) {
  e.stop();
  Jenny.handleCancelForm(el.up('form')); // hide form
});

// Jenny cancel on update
document.on('click', 'a.inline_form_update_cancel', function(e, el) {
  e.stop();
  Jenny.handleCancelForm(el.up('form')); // hide form
});
<|endoftext|>