<commit_before>var d3 = Object.assign({}, require("../../"), require("d3-array"), require("d3-random")),
    benchmark = require("benchmark");

var slice = Array.prototype.slice,
    shuffle = d3.shuffle;

var n = 0,
    m = 1000,
    r = d3.randomLogNormal(10),
    x = d3.randomUniform(0, 100),
    y = x,
    circles0 = d3.packSiblings(new Array(100).fill().map(() => ({r: r(), x: x(), y: y()}))),
    circles1 = circles0.slice().reverse();

function extendBasis(B, p) {
  var i, j;

  if (enclosesWeakAll(p, B)) return [p];

  // If we get here then B must have at least one element.
  for (i = 0; i < B.length; ++i) {
    if (enclosesNot(p, B[i])
        && enclosesWeakAll(encloseBasis2(B[i], p), B)) {
      return [B[i], p];
    }
  }

  // If we get here then B must have at least two elements.
  for (i = 0; i < B.length - 1; ++i) {
    for (j = i + 1; j < B.length; ++j) {
      if (enclosesNot(encloseBasis2(B[i], B[j]), p)
          && enclosesNot(encloseBasis2(B[i], p), B[j])
          && enclosesNot(encloseBasis2(B[j], p), B[i])
          && enclosesWeakAll(encloseBasis3(B[i], B[j], p), B)) {
        return [B[i], B[j], p];
      }
    }
  }

  // If we get here then something is very wrong.
  throw new Error;
}

function enclosesNot(a, b) {
  var dr = a.r - b.r, dx = b.x - a.x, dy = b.y - a.y;
  return dr < 0 || dr * dr < dx * dx + dy * dy;
}

function enclosesWeak(a, b) {
  var dr = a.r - b.r + 1e-6, dx = b.x - a.x, dy = b.y - a.y;
  return dr > 0 && dr * dr > dx * dx + dy * dy;
}

function enclosesWeakAll(a, B) {
  for (var i = 0; i < B.length; ++i) {
    if (!enclosesWeak(a, B[i])) {
      return false;
    }
  }
  return true;
}

function encloseBasis(B) {
  switch (B.length) {
    case 1: return encloseBasis1(B[0]);
    case 2: return encloseBasis2(B[0], B[1]);
    case 3: return encloseBasis3(B[0], B[1], B[2]);
  }
}

function encloseBasis1(a) {
  return {
    x: a.x,
    y: a.y,
    r: a.r
  };
}

function encloseBasis2(a, b) {
  var x1 = a.x, y1 = a.y, r1 = a.r,
      x2 = b.x, y2 = b.y, r2 = b.r,
      x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
      l = Math.sqrt(x21 * x21 + y21 * y21);
  return {
    x: (x1 + x2 + x21 / l * r21) / 2,
    y: (y1 + y2 + y21 / l * r21) / 2,
    r: (l + r1 + r2) / 2
  };
}

function encloseBasis3(a, b, c) {
  var x1 = a.x, y1 = a.y, r1 = a.r,
      x2 = b.x, y2 = b.y, r2 = b.r,
      x3 = c.x, y3 = c.y, r3 = c.r,
      a2 = x1 - x2,
      a3 = x1 - x3,
      b2 = y1 - y2,
      b3 = y1 - y3,
      c2 = r2 - r1,
      c3 = r3 - r1,
      d1 = x1 * x1 + y1 * y1 - r1 * r1,
      d2 = d1 - x2 * x2 - y2 * y2 + r2 * r2,
      d3 = d1 - x3 * x3 - y3 * y3 + r3 * r3,
      ab = a3 * b2 - a2 * b3,
      xa = (b2 * d3 - b3 * d2) / (ab * 2) - x1,
      xb = (b3 * c2 - b2 * c3) / ab,
      ya = (a3 * d2 - a2 * d3) / (ab * 2) - y1,
      yb = (a2 * c3 - a3 * c2) / ab,
      A = xb * xb + yb * yb - 1,
      B = 2 * (r1 + xa * xb + ya * yb),
      C = xa * xa + ya * ya - r1 * r1,
      r = -(A ? (B + Math.sqrt(B * B - 4 * A * C)) / (2 * A) : C / B);
  return {
    x: x1 + xa + xb * r,
    y: y1 + ya + yb * r,
    r: r
  };
}

function encloseCircular(L) {
  var i = 0, n = L.length, j = 0, B = [], p, e, k = 0;

  if (n) do {
    p = L[i];
    ++k;
    if (!(e && enclosesWeak(e, p))) {
      e = encloseBasis(B = extendBasis(B, p));
      j = i;
    }
    i = (i + 1) % n;
  } while (i != j);

  return e;
}

function encloseCircularShuffle(L) {
  var i = 0, n = shuffle(L = slice.call(L)).length, j = 0, B = [], p, e, k = 0;

  if (n) do {
    p = L[i];
    ++k;
    if (!(e && enclosesWeak(e, p))) {
      e = encloseBasis(B = extendBasis(B, p));
      j = i;
    }
    i = (i + 1) % n;
  } while (i != j);

  return e;
}

function encloseLazyShuffle(L) {
  var i = 0, j, n = (L = slice.call(L)).length, B = [], p, e;

  while (i < n) {
    p = L[j = i + (Math.random() * (n - i) | 0)], L[j] = L[i], L[i] = p;
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function encloseNoShuffle(L) {
  var i = 0, n = L.length, B = [], p, e;

  while (i < n) {
    p = L[i];
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function encloseShuffle(L) {
  var i = 0, n = shuffle(L = slice.call(L)).length, B = [], p, e;

  while (i < n) {
    p = L[i];
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function enclosePrePass(L) {
  var i, n = L.length, B = [], p, e;

  for (i = 0; i < n; ++i) {
    p = L[i];
    if (!(e && enclosesWeak(e, p))) e = encloseBasis(B = extendBasis(B, p));
  }

  for (i = 0; i < n;) {
    p = L[i];
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function enclosePrePassThenLazyShuffle(L) {
  var i, j, n = L.length, B = [], p, e;

  for (i = 0; i < n; ++i) {
    p = L[i];
    if (!(e && enclosesWeak(e, p))) e = encloseBasis(B = extendBasis(B, p));
  }

  for (i = 0; i < n;) {
    p = L[j = i + (Math.random() * (n - i) | 0)], L[j] = L[i], L[i] = p;
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function encloseShufflePrePass(L) {
  var i, n = shuffle(L = slice.call(L)).length, B = [], p, e;

  for (i = 0; i < n; ++i) {
    p = L[i];
    if (!(e && enclosesWeak(e, p))) e = encloseBasis(B = extendBasis(B, p));
  }

  for (i = 0; i < n;) {
    p = L[i];
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function encloseCompletePasses(L) {
  var i, n = L.length, B = [], p, e, dirty = false;

  do {
    for (i = 0, dirty = false; i < n; ++i) {
      p = L[i];
      if (!(e && enclosesWeak(e, p))) e = encloseBasis(B = extendBasis(B, p)), dirty = true;
    }
  } while (dirty);

  return e;
}

function encloseShuffleCompletePasses(L) {
  var i, n = shuffle(L = slice.call(L)).length, B = [], p, e, dirty = false;

  do {
    for (i = 0, dirty = false; i < n; ++i) {
      p = L[i];
      if (!(e && enclosesWeak(e, p))) e = encloseBasis(B = extendBasis(B, p)), dirty = true;
    }
  } while (dirty);

  return e;
}

(new benchmark.Suite)
    .add("encloseShufflePrePass (forward)", () => encloseShufflePrePass(circles0))
    .add("encloseShufflePrePass (reverse)", () => encloseShufflePrePass(circles1))
    .add("encloseShuffleCompletePasses (forward)", () => encloseShuffleCompletePasses(circles0))
    .add("encloseShuffleCompletePasses (reverse)", () => encloseShuffleCompletePasses(circles1))
    .add("enclosePrePass (forward)", () => enclosePrePass(circles0))
    .add("enclosePrePass (reverse)", () => enclosePrePass(circles1))
    .add("enclosePrePassThenLazyShuffle (forward)", () => enclosePrePassThenLazyShuffle(circles0))
    .add("enclosePrePassThenLazyShuffle (reverse)", () => enclosePrePassThenLazyShuffle(circles1))
    .add("encloseCompletePasses (forward)", () => encloseCompletePasses(circles0))
    .add("encloseCompletePasses (reverse)", () => encloseCompletePasses(circles1))
    .add("encloseShuffle (forward)", () => encloseShuffle(circles0))
    .add("encloseShuffle (reverse)", () => encloseShuffle(circles1))
    .add("encloseNoShuffle (forward)", () => encloseNoShuffle(circles0))
    .add("encloseNoShuffle (reverse)", () => encloseNoShuffle(circles1))
    .add("encloseLazyShuffle (forward)", () => encloseLazyShuffle(circles0))
    .add("encloseLazyShuffle (reverse)", () => encloseLazyShuffle(circles1))
    .add("encloseCircularShuffle (forward)", () => encloseCircularShuffle(circles0))
    .add("encloseCircularShuffle (reverse)", () => encloseCircularShuffle(circles1))
    .add("encloseCircular (forward)", () => encloseCircular(circles0))
    .add("encloseCircular (reverse)", () => encloseCircular(circles1))
    .on("cycle", event => console.log(event.target + ""))
    .run();
<commit_msg>Reorder tests.<commit_after>var d3 = Object.assign({}, require("../../"), require("d3-array"), require("d3-random")),
    benchmark = require("benchmark");

var slice = Array.prototype.slice,
    shuffle = d3.shuffle;

var n = 0,
    m = 1000,
    r = d3.randomLogNormal(10),
    x = d3.randomUniform(0, 100),
    y = x,
    circles0 = d3.packSiblings(new Array(100).fill().map(() => ({r: r(), x: x(), y: y()}))),
    circles1 = circles0.slice().reverse();

function extendBasis(B, p) {
  var i, j;

  if (enclosesWeakAll(p, B)) return [p];

  // If we get here then B must have at least one element.
  for (i = 0; i < B.length; ++i) {
    if (enclosesNot(p, B[i])
        && enclosesWeakAll(encloseBasis2(B[i], p), B)) {
      return [B[i], p];
    }
  }

  // If we get here then B must have at least two elements.
  for (i = 0; i < B.length - 1; ++i) {
    for (j = i + 1; j < B.length; ++j) {
      if (enclosesNot(encloseBasis2(B[i], B[j]), p)
          && enclosesNot(encloseBasis2(B[i], p), B[j])
          && enclosesNot(encloseBasis2(B[j], p), B[i])
          && enclosesWeakAll(encloseBasis3(B[i], B[j], p), B)) {
        return [B[i], B[j], p];
      }
    }
  }

  // If we get here then something is very wrong.
  throw new Error;
}

function enclosesNot(a, b) {
  var dr = a.r - b.r, dx = b.x - a.x, dy = b.y - a.y;
  return dr < 0 || dr * dr < dx * dx + dy * dy;
}

function enclosesWeak(a, b) {
  var dr = a.r - b.r + 1e-6, dx = b.x - a.x, dy = b.y - a.y;
  return dr > 0 && dr * dr > dx * dx + dy * dy;
}

function enclosesWeakAll(a, B) {
  for (var i = 0; i < B.length; ++i) {
    if (!enclosesWeak(a, B[i])) {
      return false;
    }
  }
  return true;
}

function encloseBasis(B) {
  switch (B.length) {
    case 1: return encloseBasis1(B[0]);
    case 2: return encloseBasis2(B[0], B[1]);
    case 3: return encloseBasis3(B[0], B[1], B[2]);
  }
}

function encloseBasis1(a) {
  return {
    x: a.x,
    y: a.y,
    r: a.r
  };
}

function encloseBasis2(a, b) {
  var x1 = a.x, y1 = a.y, r1 = a.r,
      x2 = b.x, y2 = b.y, r2 = b.r,
      x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
      l = Math.sqrt(x21 * x21 + y21 * y21);
  return {
    x: (x1 + x2 + x21 / l * r21) / 2,
    y: (y1 + y2 + y21 / l * r21) / 2,
    r: (l + r1 + r2) / 2
  };
}

function encloseBasis3(a, b, c) {
  var x1 = a.x, y1 = a.y, r1 = a.r,
      x2 = b.x, y2 = b.y, r2 = b.r,
      x3 = c.x, y3 = c.y, r3 = c.r,
      a2 = x1 - x2,
      a3 = x1 - x3,
      b2 = y1 - y2,
      b3 = y1 - y3,
      c2 = r2 - r1,
      c3 = r3 - r1,
      d1 = x1 * x1 + y1 * y1 - r1 * r1,
      d2 = d1 - x2 * x2 - y2 * y2 + r2 * r2,
      d3 = d1 - x3 * x3 - y3 * y3 + r3 * r3,
      ab = a3 * b2 - a2 * b3,
      xa = (b2 * d3 - b3 * d2) / (ab * 2) - x1,
      xb = (b3 * c2 - b2 * c3) / ab,
      ya = (a3 * d2 - a2 * d3) / (ab * 2) - y1,
      yb = (a2 * c3 - a3 * c2) / ab,
      A = xb * xb + yb * yb - 1,
      B = 2 * (r1 + xa * xb + ya * yb),
      C = xa * xa + ya * ya - r1 * r1,
      r = -(A ? (B + Math.sqrt(B * B - 4 * A * C)) / (2 * A) : C / B);
  return {
    x: x1 + xa + xb * r,
    y: y1 + ya + yb * r,
    r: r
  };
}

function encloseCircular(L) {
  var i = 0, n = L.length, j = 0, B = [], p, e, k = 0;

  if (n) do {
    p = L[i];
    ++k;
    if (!(e && enclosesWeak(e, p))) {
      e = encloseBasis(B = extendBasis(B, p));
      j = i;
    }
    i = (i + 1) % n;
  } while (i != j);

  return e;
}

function encloseCircularShuffle(L) {
  var i = 0, n = shuffle(L = slice.call(L)).length, j = 0, B = [], p, e, k = 0;

  if (n) do {
    p = L[i];
    ++k;
    if (!(e && enclosesWeak(e, p))) {
      e = encloseBasis(B = extendBasis(B, p));
      j = i;
    }
    i = (i + 1) % n;
  } while (i != j);

  return e;
}

function encloseLazyShuffle(L) {
  var i = 0, j, n = (L = slice.call(L)).length, B = [], p, e;

  while (i < n) {
    p = L[j = i + (Math.random() * (n - i) | 0)], L[j] = L[i], L[i] = p;
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function encloseNoShuffle(L) {
  var i = 0, n = L.length, B = [], p, e;

  while (i < n) {
    p = L[i];
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function encloseShuffle(L) {
  var i = 0, n = shuffle(L = slice.call(L)).length, B = [], p, e;

  while (i < n) {
    p = L[i];
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function enclosePrePass(L) {
  var i, n = L.length, B = [], p, e;

  for (i = 0; i < n; ++i) {
    p = L[i];
    if (!(e && enclosesWeak(e, p))) e = encloseBasis(B = extendBasis(B, p));
  }

  for (i = 0; i < n;) {
    p = L[i];
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function enclosePrePassThenLazyShuffle(L) {
  var i, j, n = (L = slice.call(L)).length, B = [], p, e;

  for (i = 0; i < n; ++i) {
    p = L[i];
    if (!(e && enclosesWeak(e, p))) e = encloseBasis(B = extendBasis(B, p));
  }

  for (i = 0; i < n;) {
    p = L[j = i + (Math.random() * (n - i) | 0)], L[j] = L[i], L[i] = p;
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function encloseShufflePrePass(L) {
  var i, n = shuffle(L = slice.call(L)).length, B = [], p, e;

  for (i = 0; i < n; ++i) {
    p = L[i];
    if (!(e && enclosesWeak(e, p))) e = encloseBasis(B = extendBasis(B, p));
  }

  for (i = 0; i < n;) {
    p = L[i];
    if (e && enclosesWeak(e, p)) ++i;
    else e = encloseBasis(B = extendBasis(B, p)), i = 0;
  }

  return e;
}

function encloseCompletePasses(L) {
  var i, n = L.length, B = [], p, e, dirty = false;

  do {
    for (i = 0, dirty = false; i < n; ++i) {
      p = L[i];
      if (!(e && enclosesWeak(e, p))) e = encloseBasis(B = extendBasis(B, p)), dirty = true;
    }
  } while (dirty);

  return e;
}

function encloseShuffleCompletePasses(L) {
  var i, n = shuffle(L = slice.call(L)).length, B = [], p, e, dirty = false;

  do {
    for (i = 0, dirty = false; i < n; ++i) {
      p = L[i];
      if (!(e && enclosesWeak(e, p))) e = encloseBasis(B = extendBasis(B, p)), dirty = true;
    }
  } while (dirty);

  return e;
}

(new benchmark.Suite)
    .add("encloseNoShuffle (forward)", () => encloseNoShuffle(circles0))
    .add("encloseNoShuffle (reverse)", () => encloseNoShuffle(circles1))
    .add("enclosePrePass (forward)", () => enclosePrePass(circles0))
    .add("enclosePrePass (reverse)", () => enclosePrePass(circles1))
    .add("encloseCompletePasses (forward)", () => encloseCompletePasses(circles0))
    .add("encloseCompletePasses (reverse)", () => encloseCompletePasses(circles1))
    .add("encloseCircular (forward)", () => encloseCircular(circles0))
    .add("encloseCircular (reverse)", () => encloseCircular(circles1))
    .add("encloseShufflePrePass (forward)", () => encloseShufflePrePass(circles0))
    .add("encloseShufflePrePass (reverse)", () => encloseShufflePrePass(circles1))
    .add("encloseShuffleCompletePasses (forward)", () => encloseShuffleCompletePasses(circles0))
    .add("encloseShuffleCompletePasses (reverse)", () => encloseShuffleCompletePasses(circles1))
    .add("enclosePrePassThenLazyShuffle (forward)", () => enclosePrePassThenLazyShuffle(circles0))
    .add("enclosePrePassThenLazyShuffle (reverse)", () => enclosePrePassThenLazyShuffle(circles1))
    .add("encloseShuffle (forward)", () => encloseShuffle(circles0))
    .add("encloseShuffle (reverse)", () => encloseShuffle(circles1))
    .add("encloseLazyShuffle (forward)", () => encloseLazyShuffle(circles0))
    .add("encloseLazyShuffle (reverse)", () => encloseLazyShuffle(circles1))
    .add("encloseCircularShuffle (forward)", () => encloseCircularShuffle(circles0))
    .add("encloseCircularShuffle (reverse)", () => encloseCircularShuffle(circles1))
    .on("cycle", event => console.log(event.target + ""))
    .run();
<|endoftext|>


<commit_before>var dl = require('datalib'),
    jsdom = require('jsdom'),
    canvasIO = require('vega-scenegraph/src/render/canvas'),
    parseStreams = require('../../src/parse/streams'),
    fs = require('fs');

describe('Streams', function() {
  var renderer = "canvas";

  function test(spec, interaction) {
    parseSpec(spec, function(chart) {
      jsdom.env("", function(err, window) {
        var document = window.document,
            body = d3.select(document).select('body').node(),
            isCanvas = (renderer === "canvas"),
            opt = {renderer: (renderer = (isCanvas = !isCanvas) ? "canvas" : "svg")};

        if (!isCanvas) opt.el = body;

        // HACK due to bug w/node-canvas+jsdom dropping attributes
        // so d3.select("canvas.marks") within Vega fails. So,
        // manually initialize the canvas view handler.
        var view = chart(opt),
            w = view.width(),
            h = view.height(),
            pad = view.padding(),
            tw = w + (pad ? pad.left + pad.right : 0),
            th = h + (pad ? pad.top + pad.bottom : 0),
            canvas, ctx;

        if (isCanvas) {
          body.innerHTML = "<canvas class=\"marks\"></canvas>";
          view._el = body;
          canvas = d3.select(body).select("canvas").node();
          canvas.width  = tw;
          canvas.height = th;
          ctx = canvas.getContext("2d");
          ctx.setTransform(1, 0, 0, 1, pad.left, pad.top);
          view._renderer.context(ctx);

          // Manually init handler
          view._handler = new canvasIO.Handler()
            .initialize(body, pad, view);
          parseStreams(view);
        }

        view.update();
        view._handler.scene(view.model().scene());
        interaction(view, d3.select(body).select('.marks').node(), mouseEvt);

        function mouseEvt(type, x, y, target) {
          if (isCanvas) target = canvas;

          var mm = document.createEvent("MouseEvents");
          mm.initMouseEvent("mousemove", true, true, window, null, x, y, x, y, false, false, false, false, target);

          var evt;
          if (type == "wheel") {
            var delta = Math.floor(Math.random() * 2) ? 1 : -1;
            var eventInit = { deltaX: -delta, deltaY: -delta, clientX: x, clientY: y, pageX: x, pageY: y }
            evt = new WheelEvent("wheel", eventInit);
          } else {
            var evt = document.createEvent("MouseEvents");
            evt.initMouseEvent(type, true, true, window, null, x, y, x, y, false, false, false, false, target);
          }

          target.dispatchEvent(mm);
          target.dispatchEvent(evt);

          if (isCanvas) {
            view._handler.mousemove(mm);
            if (view._handler[type]) view._handler[type](evt);
            else view._handler.fire(type, evt);
          }
        }
      });
    });
  }

  it('should propagate DOM events', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown", expr: "event" }]
      }, {
        name: "signalB",
        streams: [{ type: "mousedown", expr: "event.clientX" }]
      }, {
        name: "signalC",
        streams: [{ type: "mouseup", expr: "{x: event.clientX, y: event.clientY}"}]
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousedown', 350, 350, svg);
      expect(view.signal('signalA')).to.have.property("type", "mousedown");
      expect(view.signal('signalB')).to.equal(350);

      mouseEvt('mouseup', 275, 265, svg);
      expect(view.signal('signalC')).to.deep.equal({ x: 275, y: 265 });

      done();
    });
  });

  describe('Element Selector', function() {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "@mark1:mousedown", expr: "event.clientX" }]
      }, {
        name: "signalB",
        streams: [{ type: "@mark2:mousedown", expr: "event.clientY" }]
      }, {
        name: "signalC",
        streams: [{ type: "rect:mousedown", expr: "event.clientX" }]
      }, {
        name: "signalD",
        streams: [{ type: "group:mousedown", expr: "event.clientY" }]
      }],

      marks: [{
        name: "mark1",
        type: "rect",
        properties: {
          enter: {
            x: {value: 25},
            y: {value: 25},
            width: {value: 25},
            height: {value: 25},
            fill: {value: "red"}
          }
        }
      }, {
        name: "mark2",
        type: "group",
        properties: {
          enter: {
            x: {value: 75},
            y: {value: 75},
            width: {value: 25},
            height: {value: 25},
            fill: {value: "red"}
          }
        }
      }]
    };

    it('should respect names', function(done) {
      test(spec, function(view, svg, mouseEvt) {
        mouseEvt('mousedown', 50, 50, d3.select(svg).select('.mark-rect rect').node());
        expect(view.signal('signalA')).to.equal(50);
        expect(view.signal('signalB')).to.be.undefined;

        mouseEvt('mousedown', 75, 75, d3.select(svg).select('.mark-group rect').node());
        expect(view.signal('signalA')).to.equal(50);
        expect(view.signal('signalB')).to.equal(75);

        done();
      });
    });

    it('should respect mark types', function(done) {
      test(spec, function(view, svg, mouseEvt) {
        mouseEvt('mousedown', 50, 50, d3.select(svg).select('.mark-rect rect').node());
        expect(view.signal('signalC')).to.equal(50);
        expect(view.signal('signalD')).to.be.undefined;

        // mouseEvt('mousedown', 75, 75, d3.select(svg).select('.mark-group rect').node());
        // expect(view.signal('signalC')).to.equal(50);
        // expect(view.signal('signalD')).to.equal(75);

        done();
      });
    });

    // Can't set the d3.document context
    it.skip('should register on external targets', function(done) {
      test(spec, function(view, svg, mouseEvt) {
        mouseEvt('mousedown', 50, 50, d3.select(svg.parentNode).node());
        expect(view.signal('signalA')).to.be.undefined;
        expect(view.signal('signalB')).to.be.undefined;
        expect(view.signal('signalC')).to.be.undefined;
        expect(view.signal('signalD')).to.be.undefined;
        expect(view.signal('signalE')).to.equal("DIV");
        done();
      });
    });
  });

  it('should propagated signals', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown", expr: "event" }]
      }, {
        name: "signalB",
        streams: [{
          type: "signalA", expr: "signalA.clientX",
          scale: {name: "x", invert: true}
        }]
      }, {
        name: "signalC",
        expr: "signalA.clientX + 250",
        scale: {name: "x", invert: true}
      }],

      scales: [
        {
          name: "x",
          type: "time",
          domainMin: (new Date("Wed Dec 31 2014 16:00:00 GMT-0800 (PST)")).getTime(),
          domainMax: (new Date("Wed Dec 30 2015 16:00:00 GMT-0800 (PST)")).getTime(),
          range: "width"
        }
      ]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousedown', 350, 350, svg);
      expect(view.signal('signalA')).to.have.property("type", "mousedown");
      expect(view.signal('signalB').getTime())
        .to.equal(new Date("Sat Sep 12 2015 12:12:00 GMT-0700 (PDT)").getTime());
      expect(view.signal('signalC').getTime())
        .to.equal(new Date("Sat Mar 12 2016 11:12:00 GMT-0800 (PST)").getTime());
      done();
    });
  });

  it('should respect filters', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown[event.clientX > 200]", expr: "event" }]
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousedown', 190, 350, svg);
      expect(view.signal('signalA')).to.be.undefined;

      mouseEvt('mousedown', 200, 350, svg);
      expect(view.signal('signalA')).to.be.undefined;

      mouseEvt('mousedown', 201, 350, svg);
      expect(view.signal('signalA')).to.not.be.undefined;
      done();
    });
  });

  it('should propagate ordered streams', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "[mousedown, mouseup] > mousemove", expr: "event" }]
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousemove', 190, 100, svg);
      expect(view.signal('signalA')).to.be.undefined;

      mouseEvt('mousedown', 190, 100, svg);
      expect(view.signal('signalA')).to.be.undefined;

      mouseEvt('mousemove', 250, 350, svg);
      expect(view.signal('signalA')).to.have.property('clientX', 250);
      expect(view.signal('signalA')).to.have.property('clientY', 350);

      mouseEvt('mouseup', 250, 350, svg);
      mouseEvt('mousemove', 190, 100, svg);
      expect(view.signal('signalA')).to.have.property('clientX', 250);
      expect(view.signal('signalA')).to.have.property('clientY', 350);

      done();
    });
  });

  it('should propagate merged streams', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown, mouseup", expr: "event" }]
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousemove', 190, 100, svg);
      expect(view.signal('signalA')).to.be.undefined;

      mouseEvt('mousedown', 190, 100, svg);
      expect(view.signal('signalA')).to.have.property('clientX', 190);
      expect(view.signal('signalA')).to.have.property('clientY', 100);

      mouseEvt('mousemove', 250, 350, svg);
      expect(view.signal('signalA')).to.have.property('clientX', 190);
      expect(view.signal('signalA')).to.have.property('clientY', 100);

      mouseEvt('mouseup', 250, 350, svg);
      mouseEvt('mousemove', 190, 100, svg);
      expect(view.signal('signalA')).to.have.property('clientX', 250);
      expect(view.signal('signalA')).to.have.property('clientY', 350);

      done();
    });
  });

  it('should populate vgItem, vgX, and vgY', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown", expr: "event" }]
      }],

      marks: [{
        name: "mark1",
        type: "rect",
        properties: {
          enter: {
            x: {value: 25},
            y: {value: 25},
            width: {value: 25},
            height: {value: 25},
            fill: {value: "red"}
          }
        }
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousedown', 50, 50, d3.select(svg).select('.mark1 rect').node());
      var sgA = view.signal('signalA');
      expect(sgA).to.have.deep.property("vgItem.mark.marktype", "rect");
      expect(sgA).to.have.deep.property("vgItem.mark.def.name", "mark1");
      expect(sgA).to.have.deep.property("vgItem.x", 25);
      expect(sgA).to.have.deep.property("vgItem.fill", "red");
      expect(sgA).to.have.property("vgX");
      expect(sgA).to.have.property("vgY");
      done();
    });
  });

  it('should populate named ancestors', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown", expr: "event" }]
      }],

      marks: [{
        name: "mark1",
        type: "group",
        properties: {
          enter: {
            x: {value: 25},
            y: {value: 25},
            width: {value: 50},
            height: {value: 50},
            fill: {value: "red"}
          }
        },
        marks: [{
          name: "mark2",
          type: "rect",
          properties: {
            enter: {
              x: {value: 25},
              y: {value: 25},
              width: {value: 25},
              height: {value: 25},
              fill: {value: "green"}
            }
          }
        }]
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousedown', 50, 50, d3.select(svg).select('.mark-rect rect').node());
      var sgA = view.signal('signalA');

      expect(sgA).to.have.deep.property("vgItem.mark.marktype", "rect");
      expect(sgA).to.have.deep.property("vgItem.mark.def.name", "mark2");
      expect(sgA).to.have.deep.property("vgItem.x", 25);
      expect(sgA).to.have.deep.property("vgItem.fill", "green");
      expect(sgA).to.have.property("vgX");
      expect(sgA).to.have.property("vgY");

      expect(sgA).to.have.deep.property("vgMark2Item.mark.marktype", "rect");
      expect(sgA).to.have.deep.property("vgMark2Item.mark.def.name", "mark2");
      expect(sgA).to.have.deep.property("vgMark2Item.x", 25);
      expect(sgA).to.have.deep.property("vgMark2Item.fill", "green");

      expect(sgA).to.have.deep.property("vgMark1Item.mark.marktype", "group");
      expect(sgA).to.have.deep.property("vgMark1Item.mark.def.name", "mark1");
      expect(sgA).to.have.deep.property("vgMark1Item.x", 25);
      expect(sgA).to.have.deep.property("vgMark1Item.fill", "red");
      expect(sgA).to.have.property("vgMark1X");
      expect(sgA).to.have.property("vgMark1Y");

      done();
    });
  });

  describe('Custom Handlers', function() {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mouseup", expr: "event" }]
      }],

      marks: [{
        name: "mark1",
        type: "rect",
        properties: {
          enter: {
            x: {value: 25},
            y: {value: 25},
            width: {value: 50},
            height: {value: 50},
            fill: {value: "red"}
          }
        }
      }]
    };

    it('should turn on/off signal handlers', function(done) {
      var handler = chai.spy();

      test(spec, function(view, svg, mouseEvt) {
        view.onSignal('signalA', handler);

        mouseEvt('mouseup', 50, 50, d3.select(svg).select('.mark-rect rect').node());
        expect(handler).to.have.been.called.once;

        mouseEvt('mouseup', 150, 150, d3.select(svg).select('.mark-rect rect').node());
        expect(handler).to.have.been.called.twice;

        view.offSignal('signalA', handler);
        mouseEvt('mouseup', 200, 200, d3.select(svg).select('.mark-rect rect').node());
        expect(handler).to.have.been.called.twice;

        done();
      });
    });
  });
});<commit_msg>Strip canvas event stream tests for simplicity.<commit_after>var dl = require('datalib'),
    jsdom = require('jsdom'),
    canvasIO = require('vega-scenegraph/src/render/canvas'),
    parseStreams = require('../../src/parse/streams'),
    fs = require('fs');

describe('Streams', function() {
  function test(spec, interaction) {
    parseSpec(spec, function(chart) {
      jsdom.env("", function(err, window) {
        var document = window.document,
            body = d3.select(document).select('body').node();

        var view = chart({ el: body, renderer: 'svg' })
          .update();

        interaction(view, d3.select(body).select('.marks').node(), mouseEvt);

        function mouseEvt(type, x, y, target) {
          var mm = document.createEvent("MouseEvents");
          mm.initMouseEvent("mousemove", true, true, window, null, x, y, x, y, false, false, false, false, target);

          var evt;
          if (type == "wheel") {
            var delta = Math.floor(Math.random() * 2) ? 1 : -1;
            var eventInit = { deltaX: -delta, deltaY: -delta, clientX: x, clientY: y, pageX: x, pageY: y }
            evt = new WheelEvent("wheel", eventInit);
          } else {
            var evt = document.createEvent("MouseEvents");
            evt.initMouseEvent(type, true, true, window, null, x, y, x, y, false, false, false, false, target);
          }

          target.dispatchEvent(mm);
          target.dispatchEvent(evt);
        }
      });
    });
  }

  it('should propagate DOM events', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown", expr: "event" }]
      }, {
        name: "signalB",
        streams: [{ type: "mousedown", expr: "event.clientX" }]
      }, {
        name: "signalC",
        streams: [{ type: "mouseup", expr: "{x: event.clientX, y: event.clientY}"}]
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousedown', 350, 350, svg);
      expect(view.signal('signalA')).to.have.property("type", "mousedown");
      expect(view.signal('signalB')).to.equal(350);

      mouseEvt('mouseup', 275, 265, svg);
      expect(view.signal('signalC')).to.deep.equal({ x: 275, y: 265 });

      done();
    });
  });

  describe('Element Selector', function() {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "@mark1:mousedown", expr: "event.clientX" }]
      }, {
        name: "signalB",
        streams: [{ type: "@mark2:mousedown", expr: "event.clientY" }]
      }, {
        name: "signalC",
        streams: [{ type: "rect:mousedown", expr: "event.clientX" }]
      }, {
        name: "signalD",
        streams: [{ type: "group:mousedown", expr: "event.clientY" }]
      }],

      marks: [{
        name: "mark1",
        type: "rect",
        properties: {
          enter: {
            x: {value: 25},
            y: {value: 25},
            width: {value: 25},
            height: {value: 25},
            fill: {value: "red"}
          }
        }
      }, {
        name: "mark2",
        type: "group",
        properties: {
          enter: {
            x: {value: 75},
            y: {value: 75},
            width: {value: 25},
            height: {value: 25},
            fill: {value: "red"}
          }
        }
      }]
    };

    it('should respect names', function(done) {
      test(spec, function(view, svg, mouseEvt) {
        mouseEvt('mousedown', 50, 50, d3.select(svg).select('.mark1 rect').node());
        expect(view.signal('signalA')).to.equal(50);
        expect(view.signal('signalB')).to.be.undefined;

        mouseEvt('mousedown', 75, 75, d3.select(svg).select('.mark2 rect').node());
        expect(view.signal('signalA')).to.equal(50);
        expect(view.signal('signalB')).to.equal(75);

        done();
      });
    });

    it('should respect mark types', function(done) {
      test(spec, function(view, svg, mouseEvt) {
        mouseEvt('mousedown', 50, 50, d3.select(svg).select('.mark-rect rect').node());
        expect(view.signal('signalC')).to.equal(50);
        expect(view.signal('signalD')).to.be.undefined;

        mouseEvt('mousedown', 75, 75, d3.select(svg).select('.mark-group rect').node());
        expect(view.signal('signalC')).to.equal(50);
        expect(view.signal('signalD')).to.equal(75);

        done();
      });
    });

    // Can't set the d3.document context
    it.skip('should register on external targets', function(done) {
      test(spec, function(view, svg, mouseEvt) {
        mouseEvt('mousedown', 50, 50, d3.select(svg.parentNode).node());
        expect(view.signal('signalA')).to.be.undefined;
        expect(view.signal('signalB')).to.be.undefined;
        expect(view.signal('signalC')).to.be.undefined;
        expect(view.signal('signalD')).to.be.undefined;
        expect(view.signal('signalE')).to.equal("DIV");
        done();
      });
    });
  });

  it('should propagated signals', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown", expr: "event" }]
      }, {
        name: "signalB",
        streams: [{
          type: "signalA", expr: "signalA.clientX",
          scale: {name: "x", invert: true}
        }]
      }, {
        name: "signalC",
        expr: "signalA.clientX + 250",
        scale: {name: "x", invert: true}
      }],

      scales: [
        {
          name: "x",
          type: "time",
          domainMin: (new Date("Wed Dec 31 2014 16:00:00 GMT-0800 (PST)")).getTime(),
          domainMax: (new Date("Wed Dec 30 2015 16:00:00 GMT-0800 (PST)")).getTime(),
          range: "width"
        }
      ]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousedown', 350, 350, svg);
      expect(view.signal('signalA')).to.have.property("type", "mousedown");
      expect(view.signal('signalB').getTime())
        .to.equal(new Date("Sat Sep 12 2015 12:12:00 GMT-0700 (PDT)").getTime());
      expect(view.signal('signalC').getTime())
        .to.equal(new Date("Sat Mar 12 2016 11:12:00 GMT-0800 (PST)").getTime());
      done();
    });
  });

  it('should respect filters', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown[event.clientX > 200]", expr: "event" }]
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousedown', 190, 350, svg);
      expect(view.signal('signalA')).to.be.undefined;

      mouseEvt('mousedown', 200, 350, svg);
      expect(view.signal('signalA')).to.be.undefined;

      mouseEvt('mousedown', 201, 350, svg);
      expect(view.signal('signalA')).to.not.be.undefined;
      done();
    });
  });

  it('should propagate ordered streams', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "[mousedown, mouseup] > mousemove", expr: "event" }]
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousemove', 190, 100, svg);
      expect(view.signal('signalA')).to.be.undefined;

      mouseEvt('mousedown', 190, 100, svg);
      expect(view.signal('signalA')).to.be.undefined;

      mouseEvt('mousemove', 250, 350, svg);
      expect(view.signal('signalA')).to.have.property('clientX', 250);
      expect(view.signal('signalA')).to.have.property('clientY', 350);

      mouseEvt('mouseup', 250, 350, svg);
      mouseEvt('mousemove', 190, 100, svg);
      expect(view.signal('signalA')).to.have.property('clientX', 250);
      expect(view.signal('signalA')).to.have.property('clientY', 350);

      done();
    });
  });

  it('should propagate merged streams', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown, mouseup", expr: "event" }]
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousemove', 190, 100, svg);
      expect(view.signal('signalA')).to.be.undefined;

      mouseEvt('mousedown', 190, 100, svg);
      expect(view.signal('signalA')).to.have.property('clientX', 190);
      expect(view.signal('signalA')).to.have.property('clientY', 100);

      mouseEvt('mousemove', 250, 350, svg);
      expect(view.signal('signalA')).to.have.property('clientX', 190);
      expect(view.signal('signalA')).to.have.property('clientY', 100);

      mouseEvt('mouseup', 250, 350, svg);
      mouseEvt('mousemove', 190, 100, svg);
      expect(view.signal('signalA')).to.have.property('clientX', 250);
      expect(view.signal('signalA')).to.have.property('clientY', 350);

      done();
    });
  });

  it('should populate vgItem, vgX, and vgY', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown", expr: "event" }]
      }],

      marks: [{
        name: "mark1",
        type: "rect",
        properties: {
          enter: {
            x: {value: 25},
            y: {value: 25},
            width: {value: 25},
            height: {value: 25},
            fill: {value: "red"}
          }
        }
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousedown', 50, 50, d3.select(svg).select('.mark1 rect').node());
      var sgA = view.signal('signalA');
      expect(sgA).to.have.deep.property("vgItem.mark.marktype", "rect");
      expect(sgA).to.have.deep.property("vgItem.mark.def.name", "mark1");
      expect(sgA).to.have.deep.property("vgItem.x", 25);
      expect(sgA).to.have.deep.property("vgItem.fill", "red");
      expect(sgA).to.have.property("vgX");
      expect(sgA).to.have.property("vgY");
      done();
    });
  });

  it('should populate named ancestors', function(done) {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mousedown", expr: "event" }]
      }],

      marks: [{
        name: "mark1",
        type: "group",
        properties: {
          enter: {
            x: {value: 25},
            y: {value: 25},
            width: {value: 50},
            height: {value: 50},
            fill: {value: "red"}
          }
        },
        marks: [{
          name: "mark2",
          type: "rect",
          properties: {
            enter: {
              x: {value: 25},
              y: {value: 25},
              width: {value: 25},
              height: {value: 25},
              fill: {value: "green"}
            }
          }
        }]
      }]
    };

    test(spec, function(view, svg, mouseEvt) {
      mouseEvt('mousedown', 50, 50, d3.select(svg).select('.mark-rect rect').node());
      var sgA = view.signal('signalA');

      expect(sgA).to.have.deep.property("vgItem.mark.marktype", "rect");
      expect(sgA).to.have.deep.property("vgItem.mark.def.name", "mark2");
      expect(sgA).to.have.deep.property("vgItem.x", 25);
      expect(sgA).to.have.deep.property("vgItem.fill", "green");
      expect(sgA).to.have.property("vgX");
      expect(sgA).to.have.property("vgY");

      expect(sgA).to.have.deep.property("vgMark2Item.mark.marktype", "rect");
      expect(sgA).to.have.deep.property("vgMark2Item.mark.def.name", "mark2");
      expect(sgA).to.have.deep.property("vgMark2Item.x", 25);
      expect(sgA).to.have.deep.property("vgMark2Item.fill", "green");

      expect(sgA).to.have.deep.property("vgMark1Item.mark.marktype", "group");
      expect(sgA).to.have.deep.property("vgMark1Item.mark.def.name", "mark1");
      expect(sgA).to.have.deep.property("vgMark1Item.x", 25);
      expect(sgA).to.have.deep.property("vgMark1Item.fill", "red");
      expect(sgA).to.have.property("vgMark1X");
      expect(sgA).to.have.property("vgMark1Y");

      done();
    });
  });

  describe('Custom Handlers', function() {
    var spec = {
      signals: [{
        name: "signalA",
        streams: [{ type: "mouseup", expr: "event" }]
      }],

      marks: [{
        name: "mark1",
        type: "rect",
        properties: {
          enter: {
            x: {value: 25},
            y: {value: 25},
            width: {value: 50},
            height: {value: 50},
            fill: {value: "red"}
          }
        }
      }]
    };

    it('should turn on/off signal handlers', function(done) {
      var handler = chai.spy();

      test(spec, function(view, svg, mouseEvt) {
        view.onSignal('signalA', handler);

        mouseEvt('mouseup', 50, 50, d3.select(svg).select('.mark-rect rect').node());
        expect(handler).to.have.been.called.once;

        mouseEvt('mouseup', 150, 150, d3.select(svg).select('.mark-rect rect').node());
        expect(handler).to.have.been.called.twice;

        view.offSignal('signalA', handler);
        mouseEvt('mouseup', 200, 200, d3.select(svg).select('.mark-rect rect').node());
        expect(handler).to.have.been.called.twice;

        done();
      });
    });
  });
});<|endoftext|>


<commit_before>var expect = require('chai').expect,
    priorityQueue = require('../lib/priorityQueue');

describe('priorityQueue test', function() {

    var pq = priorityQueue().export();

    it('should be empty initially', function() {
        expect(pq.isEmpty()).to.be.equal(true);
        expect(pq.dequeue()).to.be.equal(null);
        expect(pq.front()).to.be.equal(null);
        expect(pq.back()).to.be.equal(null);
    });

    it('should queue elements', function() {
        pq.enqueue('john', 2);
        pq.enqueue('sam', 4);
        pq.enqueue('samantha', 1);
        pq.enqueue('rose', 7);
        expect(pq.enqueue.bind(pq, 'ivan', 'test')).to.throw({
            message: 'priority should be a number'
        });
        expect(pq.isEmpty()).to.be.equal(false);
    });

    it('should retreive front and back elements', function(){
        expect(pq.front()).to.be.equal('john');
        expect(pq.back()).to.be.equal('rose');
    });

    it('should dequeue an element', function() {
        expect(pq.dequeue()).to.be.equal('samantha');
    });

});<commit_msg>refactor test<commit_after>var expect = require('chai').expect,
    priorityQueue = require('../lib/priorityQueue');

describe('priorityQueue test', function() {

    var pq = priorityQueue().export();

    describe('when the queue is empty', function() {

        it('.isEmpty() should return true', function() {
            expect(pq.isEmpty()).to.be.equal(true);
        });

        it('.length() should return 0', function() {
            expect(pq.length()).to.be.equal(0);
        });

        it('.front(), .back() and .dequeue() should return null', function() {
            expect(pq.dequeue()).to.be.equal(null);
            expect(pq.front()).to.be.equal(null);
            expect(pq.back()).to.be.equal(null);
        });

        it('.enqueue() should queue elements', function() {
            pq.enqueue('john', 2);
            pq.enqueue('sam', 4);
            pq.enqueue('samantha', 1);
            pq.enqueue('rose', 7);
        });

        it('.enqueue() should throw an exception wheen priority is not a number', function() {
            expect(pq.enqueue.bind(pq, 'ivan', 'test')).to.throw({
                message: 'priority should be a number'
            });
        });

    });

    describe('when the queue is not empty', function() {

        it('.isEmpty() should return false', function() {
            expect(pq.isEmpty()).to.be.equal(false);
        });

        it('.length() should return a number bigger than 0', function() {
            expect(pq.length()).to.be.equal(4);
        });

        it('.front() should retreive the front element', function(){
            expect(pq.front()).to.be.equal('john');
        });

        it('.back() should retreive the back element', function(){
            expect(pq.back()).to.be.equal('rose');
        });

        it('.dequeue() should dequeue a high priority element', function() {
            expect(pq.dequeue()).to.be.equal('samantha');
            expect(pq.length()).to.be.equal(3);
        });

    });

});<|endoftext|>


<commit_before>$(function () {
    $("#tab").tabs({
        fit: true,
        border: true,
    });
    $(".tab-btn").click(function () {
        var title = $(this).find('a:first').text();
        var href = $(this).find('a:first').attr("href");
        $('#tab').tabs('add', {
            fit: true,
            title: title,
            closable: true,
            href: href,
        });
        return false;
    })

})<commit_msg>消除tab重复<commit_after>$(function () {
    $("#tab").tabs({
        fit: true,
        border: true,
    });
    $(".tab-btn").click(function () {
        var title = $(this).find('a:first').text();
        var href = $(this).find('a:first').attr("href");
        if ($('#tab').tabs('exists', title)) {
            $('#tab').tabs('select', title);
            return false;
        } else {
            $('#tab').tabs('add', {
                fit: true,
                title: title,
                closable: true,
                href: href,
            });
            return false;
        }

    })

})<|endoftext|>


<commit_before>import React from 'react'
import Radium from 'radium'
import { Button } from 'components'
import mediaQueries from 'styles/common'

const styles = {
  spacer: {
    height: '5em'
  },
  wrapper: {
    [mediaQueries.smallUp]: {
      display: 'none'
    },
    [mediaQueries.print]: {
      display: 'none'
    },
    [mediaQueries.mediumUp]: {
      display: 'initial',
      position: 'fixed',
      bottom: '1em',
      right: '1em'
    }
  },
  topButton: {
    marginBottom: '0.5em'
  }
}

const ExportButtons = Radium(props => {
  const { titleizedName } = props
  const pdfOptions = {
    filename: `${titleizedName || 'Workshop'}.pdf`,
    margin: 10,
    html2canvas: {
      useCORS: true,
      image: { type: 'png' },
      dpi: 192
    }
  }

  return (

        <Button
          style={styles.topButton}
          type="link"
          onClick={() =>
            window.html2pdf(
              document.querySelector('.markdown-body'),
              pdfOptions
            )}
        >
          Download
        </Button>
        <Button type="link" onClick={window.print}>
          Print
        </Button>

  )
})

export default ExportButtons
<commit_msg>Add loading spinner to download button<commit_after>import React, { Component } from 'react'
import Radium from 'radium'
import { Button } from 'components'
import mediaQueries from 'styles/common'

const styles = {
  spacer: {
    height: '5em'
  },
  wrapper: {
    [mediaQueries.smallUp]: {
      display: 'none'
    },
    [mediaQueries.print]: {
      display: 'none'
    },
    [mediaQueries.mediumUp]: {
      display: 'initial',
      position: 'fixed',
      bottom: '1em',
      right: '1em'
    }
  },
  topButton: {
    marginBottom: '0.5em'
  }
}

class ExportButtons extends Component {
  componentDidUpdate(_, previousState) {
    if (!previousState.downloadState && this.state.downloadState === 'loading') {
      this.downloadPdf()
    }
  }

  downloadPdf() {
    const { titleizedName } = this.props
    const pdfOptions = {
      filename: `${titleizedName || 'Workshop'}.pdf`,
      margin: 10,
      html2canvas: {
        useCORS: true,
        image: { type: 'png' },
        dpi: 192
      }
    }

    window.html2pdf(document.querySelector('.markdown-body'), pdfOptions)

    setTimeout(() => {
      this.setState({ downloadState: null })
    }, 6000)
  }

  render() {
    const { downloadState } = this.state

    return (

          <Button
            state={downloadState}
            style={styles.topButton}
            type="form"
            onClick={() => this.setState({ downloadState: 'loading' })}
          >
            Download
          </Button>
          <Button type="link" onClick={window.print}>
            Print
          </Button>

    )
  }
}

export default Radium(ExportButtons)
<|endoftext|>


<commit_before>'use strict';

var path = require('path');
var debug = require('debug')('generate:mocha');
var argv = require('minimist')(process.argv.slice(2), {
  alias: {tmpl: 't'},
  default: {
    tmpl: 'test.js'
  }
});

/**
 * Extend your generator with the features and settings of this
 * generator using the `.extendWith` method.
 *
 * ```js
 * app.extendWith(require('generate-mocha'));
 * ```
 * @param {Object} `app` generator instance
 * @api public
 */

module.exports = function(app, base) {
  if (this.isRegistered('generate-mocha')) return;
  debug('initializing <%s>, from <%s>', __filename, module.parent.id);

  var templates = path.resolve.bind(path, __dirname, 'templates');
  var rename = require('./lib/rename');
  var files = require('./lib/files');
  var utils = require('./lib/utils');

  /**
   * Register instance plugins
   */

  app
    .use(require('generate-defaults'))
    .use(require('generate-collections'))
    .use(utils.conflicts())
    .use(rename())
    .use(files());

  /**
   * Set options
   */

  app.option(base.options);
  app.option(argv);
  app.option({delims: ['<%', '%>']});
  app.option('renameFile', function(file) {
    file.stem = 'test';
    return file;
  });

  /**
   * Pipeline plugins
   */

  app.plugin('rename', rename);

  /**
   * Helpers
   */

  // app.helpers(require('template-helpers'));
  app.helper('camelcase', require('camel-case'));
  app.helper('relative', function(dest) {
    dest = path.resolve(dest || this.options.dest || '.');
    return dest !== this.app.cwd ? path.relative(dest, this.app.cwd) : './';
  });

  /**
   * Pre-load templates (needs to be done after collections are created)
   */

  app.task('templates', function(cb) {
    app.debug('loading templates');

    app.includes.option('renameKey', function(key, file) {
      return file ? file.stem : path.basename(key, path.extname(key));
    });

    app.includes('*.js', {cwd: templates('includes')});
    app.layouts('*.js', {cwd: templates('layouts')});
    app.templates('*.js', {
      cwd: templates(),
      renameKey: function(key, file) {
        return file ? file.basename : path.basename(key);
      }
    });

    app.debug('loaded templates');
    cb();
  });

  /**
   * Prompt the user for the `dest` to use
   */

  app.task('dest', function(cb) {
    app.question('dest', 'Destination directory?', {default: process.cwd()});
    app.ask('dest', {save: false}, function(err, answers) {
      if (err) return cb(err);
      app.option('dest', answers.dest);
      cb();
    });
  });

  /**
   * Initiate a prompt session that asks the user
   * which files to write to disk.
   */

  app.task('choose', ['templates', 'dest'], function(cb) {
    app.chooseFiles(app.options, cb);
  });

  /**
   * Write a `test.js` file to the user's working directory
   */

  app.task('test', ['templates', 'dest'], function(cb) {
    app.debug('generating default test.js file');
    app.fillin('dest', app.cwd);

    app.toStream('templates', filter(app.options))
      .pipe(app.renderFile('*', app.options))
      .pipe(app.renameFile(function(file) {
        file.stem = 'test';
        return file;
      }))
      .pipe(app.conflicts(app.option('dest')))
      .pipe(app.dest(app.option('dest')))
      .on('error', cb)
      .on('end', function() {
        app.npm.askInstall('mocha', cb);
      });
  });

  /**
   * Default question
   */

  app.task('default', ['test']);
};

/**
 * Filter files to be rendered
 */

function filter(opts) {
  if (Array.isArray(opts.files)) {
    return opts.files;
  }
  return function(key, file) {
    if (opts.tmpl === 'base' && file.stem === 'test-base') {
      file.basename = 'test.js';
      return true;
    }
    return opts.tmpl === key || utils.match(opts.tmpl, file);
  };
}
<commit_msg>fix var<commit_after>'use strict';

var path = require('path');
var debug = require('debug')('generate:mocha');
var utils = require('./lib/utils');
var argv = require('minimist')(process.argv.slice(2), {
  alias: {tmpl: 't'},
  default: {
    tmpl: 'test.js'
  }
});

/**
 * Extend your generator with the features and settings of this
 * generator using the `.extendWith` method.
 *
 * ```js
 * app.extendWith(require('generate-mocha'));
 * ```
 * @param {Object} `app` generator instance
 * @api public
 */

module.exports = function(app, base) {
  if (this.isRegistered('generate-mocha')) return;
  debug('initializing <%s>, from <%s>', __filename, module.parent.id);

  var templates = path.resolve.bind(path, __dirname, 'templates');
  var rename = require('./lib/rename');
  var files = require('./lib/files');
  var utils = require('./lib/utils');

  /**
   * Register instance plugins
   */

  app
    .use(require('generate-defaults'))
    .use(require('generate-collections'))
    .use(utils.conflicts())
    .use(rename())
    .use(files());

  /**
   * Set options
   */

  app.option(base.options);
  app.option(argv);
  app.option({delims: ['<%', '%>']});
  app.option('renameFile', function(file) {
    file.stem = 'test';
    return file;
  });

  /**
   * Pipeline plugins
   */

  app.plugin('rename', rename);

  /**
   * Helpers
   */

  // app.helpers(require('template-helpers'));
  app.helper('camelcase', require('camel-case'));
  app.helper('relative', function(dest) {
    dest = path.resolve(dest || this.options.dest || '.');
    return dest !== this.app.cwd ? path.relative(dest, this.app.cwd) : './';
  });

  /**
   * Pre-load templates (needs to be done after collections are created)
   */

  app.task('templates', function(cb) {
    app.debug('loading templates');

    app.includes.option('renameKey', function(key, file) {
      return file ? file.stem : path.basename(key, path.extname(key));
    });

    app.includes('*.js', {cwd: templates('includes')});
    app.layouts('*.js', {cwd: templates('layouts')});
    app.templates('*.js', {
      cwd: templates(),
      renameKey: function(key, file) {
        return file ? file.basename : path.basename(key);
      }
    });

    app.debug('loaded templates');
    cb();
  });

  /**
   * Prompt the user for the `dest` to use
   */

  app.task('dest', function(cb) {
    app.question('dest', 'Destination directory?', {default: process.cwd()});
    app.ask('dest', {save: false}, function(err, answers) {
      if (err) return cb(err);
      app.option('dest', answers.dest);
      cb();
    });
  });

  /**
   * Initiate a prompt session that asks the user
   * which files to write to disk.
   */

  app.task('choose', ['templates', 'dest'], function(cb) {
    app.chooseFiles(app.options, cb);
  });

  /**
   * Write a `test.js` file to the user's working directory
   */

  app.task('test', ['templates', 'dest'], function(cb) {
    app.debug('generating default test.js file');
    app.fillin('dest', app.cwd);

    app.toStream('templates', filter(app.options))
      .pipe(app.renderFile('*', app.options))
      .pipe(app.renameFile(function(file) {
        file.stem = 'test';
        return file;
      }))
      .pipe(app.conflicts(app.option('dest')))
      .pipe(app.dest(app.option('dest')))
      .on('error', cb)
      .on('end', function() {
        app.npm.askInstall('mocha', cb);
      });
  });

  /**
   * Default question
   */

  app.task('default', ['test']);
};

/**
 * Filter files to be rendered
 */

function filter(opts) {
  if (Array.isArray(opts.files)) {
    return opts.files;
  }
  return function(key, file) {
    if (opts.tmpl === 'base' && file.stem === 'test-base') {
      file.basename = 'test.js';
      return true;
    }
    return opts.tmpl === key || utils.match(opts.tmpl, file);
  };
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you 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.
 */

/*
 * Dependencies
 *
 * /dev/lib/jquery/plugins/jqmodal.sakai-edited.js
 * /dev/lib/misc/trimpath.template.js (TrimpathTemplates)
 */

/*global $ */

// Namespaces
require(["jquery", "sakai/sakai.api.core"], function($, sakai) {

    /**
     * @name sakai_global.pickeradvanced
     *
     * @class pickeradvanced
     *
     * @description
     * Advanced Picker widget

     * This is a general widget which aims to display an arbitriary number of
     * items, loading dynamically if the list is very long and return the
     * selected users in an object.
     *
     * @version 0.0.1
     * @param {String} tuid Unique id of the widget
     * @param {Boolean} showSettings Show the settings of the widget or not
     */
    sakai_global.pickeradvanced = function(tuid, showSettings) {
        var $rootel = $("#" + tuid);

        var $pickeradvanced_container = $("#pickeradvanced_container", $rootel);
        var $pickeradvanced_content_list = $("#pickeradvanced_content_list", $rootel);
        var $pickeradvanced_search_query = $("#pickeradvanced_search_query", $rootel);
        var $pickeradvanced_search_button = $("#pickeradvanced_search_button", $rootel);
        var $pickeradvanced_close_button = $("#pickeradvanced_close_button", $rootel);
        var $pickeradvanced_select_all_button = $("#pickeradvanced_select_all_button", $rootel);
        var $pickeradvanced_content_search_form = $("#pickeradvanced_content_search_form", $rootel);
        var $pickeradvanced_add_button = $("#pickeradvanced_add_button", $rootel);
        var $pickeradvanced_sort_on = $("#pickeradvanced_sort_on", $rootel);
        var $pickeradvanced_close_dialog = $(".pickeradvanced_close_dialog", $rootel);
        var $pickeradvanced_search_filter = $(".pickeradvanced_search_filter");

        var $pickeradvanced_error_template = $("#pickeradvanced_error_template", $rootel);
        var $pickeradvanced_content_search_pagetemplate = $("#pickeradvanced_content_search_pagetemplate", $rootel);
        var $pickeradvanced_content_search_listtemplate = $("#pickeradvanced_content_search_listtemplate", $rootel);

        var $pickeradvanced_search_titles = $(".pickeradvanced_search_titles", $rootel);
        var $pickeradvanced_search_files = $("#pickeradvanced_search_files", $rootel);

        var pickeradvanced_page = ".pickeradvanced_page";
        var pickeradvanced_content_search = "#pickeradvanced_content_search";

        var pickerlist = false;
        var firstTime = true;

        var pickerData = {
          "selected": {},
          "searchIn": sakai.config.URL.POOLED_CONTENT_SPECIFIC_USER,
          "currentElementCount": 0,
          "selectCount": 0,
          "mode": "search",
          "type": "people",
          "items": 50,
          "selectable": true,
          "sortOn": "lastName",
          "sortOrder": "asc"
        };

        /**
         * Reset
         * Resets the people picker to a default state
         * @returns void
         */
        var reset = function() {
            $(pickeradvanced_content_search).html("");
            $(pickeradvanced_content_search).unbind("scroll");
            pickerData.selected = {};
            pickerData.currentElementCount = 0;
            pickerData.selectCount = 0;
        };

        /**
         * Render
         * Renders the people picker
         * @param iConfig {String} Config element for the widget
         * @returns void
         */
        var render = function(iConfig) {
            // Merge user defined config with default
            for (var element in iConfig) {
                if (iConfig.hasOwnProperty(element) && pickerData.hasOwnProperty(element)) {
                    pickerData[element] = iConfig[element];
                }
            }

            // display the groups list, bind elements and submit a search
            $pickeradvanced_search_titles.hide();
            $(".pickeradvanced_selected_list").removeClass("pickeradvanced_selected_list"); // deselect anything that was selected
            $("#pickeradvanced_search_files_mylibrary").parent("li").addClass("pickeradvanced_selected_list");
            $pickeradvanced_sort_on.hide();
            $pickeradvanced_search_files.show();
            $("ul.pickeradvanced_search_" + pickerData["type"]).show();
            $pickeradvanced_search_query.focus();
            $pickeradvanced_search_button.click(submitSearch);
            $pickeradvanced_content_search_form.submit(submitSearch);
            $pickeradvanced_add_button.unbind("click");
            $pickeradvanced_add_button.bind("click", function(){
                addPeople();
            });
            submitSearch();
        };

        /**
         * RenderSearch
         * Renders the people picker with a specified set of data. The function uses
         * a search query initially, then does the paginating and subsequent requests
         * for data automatically
         * @param iSearchQuery {String} A Sakai search query
         * @returns void
         */
        var submitSearch = function() {
            reset();
            var parameters = {
                "q": sakai.api.Server.createSearchString($pickeradvanced_search_query.val()) || "*",
                "page": 0,
                "items": pickerData["items"],
                "userid": sakai.data.me.user.userid,
                "sortOn": pickerData["sortOn"],
                "sortOrder": pickerData["sortOrder"]
            };
            var searchURL = pickerData['searchIn'];
            addPage(parameters, searchURL);
            return false;
        };

        /**
         * addPage
         * Adds another page of search result to the picker's result list
         * @pageNumber {Int} The page we want to load
         * @url {String}     An object containing the search query elements
         */
        var addPage = function(parameters, url) {
            // Create new container for the bit we load. This is then appended to the
            // main container
            var $pl_pageContainer = $("

");

            // Display empty new container with loading anim
            $(pickeradvanced_content_search).append($pl_pageContainer);

            // Make the request
            $.ajax({
                url: url,
                data: parameters,
                type: "GET",
                dataType: "json",
                success: function(rawData) {
                    if (!rawData.results) {
                        rawData.results = rawData;
                    }
                    rawData.total = rawData.results.length;
                    rawData.sakai = sakai;

                    // Render the results data template
                    var pageHTML = sakai.api.Util.TemplateRenderer($pickeradvanced_content_search_pagetemplate, rawData);

                    // Remove loading animation
                    $pl_pageContainer = $(".pickeradvanced_page.pickeradvanced_page_list.loadinganim");
                    $pl_pageContainer.removeClass("loadinganim");

                    // Inject results into DOM
                    $pl_pageContainer.html(pageHTML);
                    // Wire loading the next page when user scrolls to the bottom of the list
                    if ((rawData.total > parameters.items) || (rawData.total === -1)) {

                        $(pickeradvanced_content_search).bind("scroll", function(e){
                            if ((e.target.scrollHeight - e.target.scrollTop - $(e.target).height() ) === 0) {
                                $(pickeradvanced_content_search).unbind("scroll");
                                parameters.page++;
                                addPage(parameters, url);
                            }
                        });

                    }

                    // Wire item selection
                    if (pickerData.selectable) {
                        $pickeradvanced_select_all_button.unbind("click");
                        $pickeradvanced_select_all_button.click(function(){
                            pickerData.selectCount = 0;
                            $('#pickeradvanced_content_search ul li').each(function(i) {
                                $(this).addClass("pickeradvanced_selected_user");
                                $(this).children("input").attr('checked', true);
                                pickerData.selectCount += 1;
                                pickerData["selected"][$(this).attr("id")] = rawData.results[i];
                                if ($pickeradvanced_add_button.is(":disabled")) {
                                    $pickeradvanced_add_button.removeAttr("disabled");
                                }
                            });
                        });
                        $("#pickeradvanced_page_" + parameters.page + " li").unbind("click");
                        $("#pickeradvanced_page_" + parameters.page + " li").bind("click", function(e){
                            // Check if user click on top of a link
                            if (e.target.tagName.toLowerCase() !== "a") {
                                // Remove from selected list
                                if ($(this).hasClass("pickeradvanced_selected_user")) {
                                    $(this).removeClass("pickeradvanced_selected_user");
                                    $(this).children("input").removeAttr('checked');
                                    delete pickerData["selected"][$(this).attr("id")];
                                    pickerData.selectCount -= 1;
                                    if (pickerData.selectCount < 1) {
                                        $pickeradvanced_add_button.attr("disabled", "disabled");
                                    }
                                } else {
                                    // Add to selected list
                                    $(this).addClass("pickeradvanced_selected_user");
                                    $(this).children("input").attr('checked', true);
                                    for (var j = 0; j < rawData.results.length; j++) {
                                        if (rawData.results[j]['_path'] && rawData.results[j]['_path'] == [$(this).attr("id")]) {
                                            pickerData.selectCount += 1;
                                            pickerData["selected"][$(this).attr("id")] = rawData.results[j];
                                            pickerData["selected"][$(this).attr("id")].entityType = "file";
                                        }
                                    }
                                    if ($pickeradvanced_add_button.is(":disabled")) {
                                        $pickeradvanced_add_button.removeAttr("disabled");
                                    }
                                }
                            }
                        });
                    }

                    // Wire sorting select dropdown
                    $pickeradvanced_sort_on.unbind("change");
                    $pickeradvanced_sort_on.bind("change", function(e){
                        // Reset everything
                        reset();

                        // Set config to new sort key
                        // Start from scratch
                        pickerData["sortOn"] = $(this).val().split("_")[0];
                        pickerData["sortOrder"] = $(this).val().split("_")[1];
                        submitSearch();

                    });
                },
                error: function(xhr, status, thrown) {

                    // If it's likely to be a genuine server error
                    if ($pl_pageContainer.length === 0) {
                        $pickeradvanced_content_search.html($pickeradvanced_error_template.html());
                    } else {
                        // Probably it's the last page of the result set
                        $pl_pageContainer.last().remove();
                    }
                }
            });
        };

        $pickeradvanced_container.jqm({
            modal: true,
            overlay: 20,
            zIndex: 5000,
            toTop: true
        });

        var addPeople = function() {
          // this value is a comma-delimited list
          // split it and get rid of any empty values in the array
          $pickeradvanced_container.jqmHide();
          $(window).trigger("finished.pickeradvanced.sakai", {"toAdd":pickerData["selected"]});
        };

        ////////////
        // Events //
        ////////////

        $(window).unbind("init.pickeradvanced.sakai");
        $(window).bind("init.pickeradvanced.sakai", function(e, config) {
            // position dialog box at users scroll position
            var htmlScrollPos = $("html").scrollTop();
            var docScrollPos = $(document).scrollTop();
            if (htmlScrollPos > 0) {
                $pickeradvanced_container.css({"top": htmlScrollPos + 130 + "px"});
            } else if (docScrollPos > 0) {
                $pickeradvanced_container.css({"top": docScrollPos + 130 + "px"});
            }

            firstTime = true;
            render(config.config);
            $pickeradvanced_container.jqmShow();
            pickerlist = config.list;
        });

        $pickeradvanced_close_dialog.unbind("click");
        $pickeradvanced_close_dialog.bind("click", function() {
            $pickeradvanced_container.jqmHide();
        });

        $pickeradvanced_close_button.unbind("click");
        $pickeradvanced_close_button.bind("click", function() {
            $pickeradvanced_container.jqmHide();
        });

        $pickeradvanced_search_filter.die("click");
        $pickeradvanced_search_filter.live("click", function() {
           $(".pickeradvanced_selected_list").removeClass("pickeradvanced_selected_list");
           $(this).parent("li").addClass("pickeradvanced_selected_list");
           debug.log($(this));
           if ( $( this ).attr( "data-search" ) === "all" ) {
               pickerData.searchIn = sakai.config.URL.SEARCH_ALL_FILES;
           } else if ($( this ).attr( "data-search" ) === "my" ) {
               pickerData.searchIn = sakai.config.URL.POOLED_CONTENT_SPECIFIC_USER;
           }
           $pickeradvanced_sort_on.hide();
           submitSearch();
        });

        // Reset to defaults
        reset();

        // Send out an event that says the widget is ready to
        // accept a search query to process and display. This event can be picked up
        // in a page JS code
        $(window).trigger("ready.pickeradvanced.sakai");

    };

    sakai.api.Widgets.widgetLoader.informOnLoad("pickeradvanced");
});
<commit_msg>SAKIII-4394 - Removing debug statement<commit_after>/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you 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.
 */

/*
 * Dependencies
 *
 * /dev/lib/jquery/plugins/jqmodal.sakai-edited.js
 * /dev/lib/misc/trimpath.template.js (TrimpathTemplates)
 */

/*global $ */

// Namespaces
require(["jquery", "sakai/sakai.api.core"], function($, sakai) {

    /**
     * @name sakai_global.pickeradvanced
     *
     * @class pickeradvanced
     *
     * @description
     * Advanced Picker widget

     * This is a general widget which aims to display an arbitriary number of
     * items, loading dynamically if the list is very long and return the
     * selected users in an object.
     *
     * @version 0.0.1
     * @param {String} tuid Unique id of the widget
     * @param {Boolean} showSettings Show the settings of the widget or not
     */
    sakai_global.pickeradvanced = function(tuid, showSettings) {
        var $rootel = $("#" + tuid);

        var $pickeradvanced_container = $("#pickeradvanced_container", $rootel);
        var $pickeradvanced_content_list = $("#pickeradvanced_content_list", $rootel);
        var $pickeradvanced_search_query = $("#pickeradvanced_search_query", $rootel);
        var $pickeradvanced_search_button = $("#pickeradvanced_search_button", $rootel);
        var $pickeradvanced_close_button = $("#pickeradvanced_close_button", $rootel);
        var $pickeradvanced_select_all_button = $("#pickeradvanced_select_all_button", $rootel);
        var $pickeradvanced_content_search_form = $("#pickeradvanced_content_search_form", $rootel);
        var $pickeradvanced_add_button = $("#pickeradvanced_add_button", $rootel);
        var $pickeradvanced_sort_on = $("#pickeradvanced_sort_on", $rootel);
        var $pickeradvanced_close_dialog = $(".pickeradvanced_close_dialog", $rootel);
        var $pickeradvanced_search_filter = $(".pickeradvanced_search_filter");

        var $pickeradvanced_error_template = $("#pickeradvanced_error_template", $rootel);
        var $pickeradvanced_content_search_pagetemplate = $("#pickeradvanced_content_search_pagetemplate", $rootel);
        var $pickeradvanced_content_search_listtemplate = $("#pickeradvanced_content_search_listtemplate", $rootel);

        var $pickeradvanced_search_titles = $(".pickeradvanced_search_titles", $rootel);
        var $pickeradvanced_search_files = $("#pickeradvanced_search_files", $rootel);

        var pickeradvanced_page = ".pickeradvanced_page";
        var pickeradvanced_content_search = "#pickeradvanced_content_search";

        var pickerlist = false;
        var firstTime = true;

        var pickerData = {
          "selected": {},
          "searchIn": sakai.config.URL.POOLED_CONTENT_SPECIFIC_USER,
          "currentElementCount": 0,
          "selectCount": 0,
          "mode": "search",
          "type": "people",
          "items": 50,
          "selectable": true,
          "sortOn": "lastName",
          "sortOrder": "asc"
        };

        /**
         * Reset
         * Resets the people picker to a default state
         * @returns void
         */
        var reset = function() {
            $(pickeradvanced_content_search).html("");
            $(pickeradvanced_content_search).unbind("scroll");
            pickerData.selected = {};
            pickerData.currentElementCount = 0;
            pickerData.selectCount = 0;
        };

        /**
         * Render
         * Renders the people picker
         * @param iConfig {String} Config element for the widget
         * @returns void
         */
        var render = function(iConfig) {
            // Merge user defined config with default
            for (var element in iConfig) {
                if (iConfig.hasOwnProperty(element) && pickerData.hasOwnProperty(element)) {
                    pickerData[element] = iConfig[element];
                }
            }

            // display the groups list, bind elements and submit a search
            $pickeradvanced_search_titles.hide();
            $(".pickeradvanced_selected_list").removeClass("pickeradvanced_selected_list"); // deselect anything that was selected
            $("#pickeradvanced_search_files_mylibrary").parent("li").addClass("pickeradvanced_selected_list");
            $pickeradvanced_sort_on.hide();
            $pickeradvanced_search_files.show();
            $("ul.pickeradvanced_search_" + pickerData["type"]).show();
            $pickeradvanced_search_query.focus();
            $pickeradvanced_search_button.click(submitSearch);
            $pickeradvanced_content_search_form.submit(submitSearch);
            $pickeradvanced_add_button.unbind("click");
            $pickeradvanced_add_button.bind("click", function(){
                addPeople();
            });
            submitSearch();
        };

        /**
         * RenderSearch
         * Renders the people picker with a specified set of data. The function uses
         * a search query initially, then does the paginating and subsequent requests
         * for data automatically
         * @param iSearchQuery {String} A Sakai search query
         * @returns void
         */
        var submitSearch = function() {
            reset();
            var parameters = {
                "q": sakai.api.Server.createSearchString($pickeradvanced_search_query.val()) || "*",
                "page": 0,
                "items": pickerData["items"],
                "userid": sakai.data.me.user.userid,
                "sortOn": pickerData["sortOn"],
                "sortOrder": pickerData["sortOrder"]
            };
            var searchURL = pickerData['searchIn'];
            addPage(parameters, searchURL);
            return false;
        };

        /**
         * addPage
         * Adds another page of search result to the picker's result list
         * @pageNumber {Int} The page we want to load
         * @url {String}     An object containing the search query elements
         */
        var addPage = function(parameters, url) {
            // Create new container for the bit we load. This is then appended to the
            // main container
            var $pl_pageContainer = $("

");

            // Display empty new container with loading anim
            $(pickeradvanced_content_search).append($pl_pageContainer);

            // Make the request
            $.ajax({
                url: url,
                data: parameters,
                type: "GET",
                dataType: "json",
                success: function(rawData) {
                    if (!rawData.results) {
                        rawData.results = rawData;
                    }
                    rawData.total = rawData.results.length;
                    rawData.sakai = sakai;

                    // Render the results data template
                    var pageHTML = sakai.api.Util.TemplateRenderer($pickeradvanced_content_search_pagetemplate, rawData);

                    // Remove loading animation
                    $pl_pageContainer = $(".pickeradvanced_page.pickeradvanced_page_list.loadinganim");
                    $pl_pageContainer.removeClass("loadinganim");

                    // Inject results into DOM
                    $pl_pageContainer.html(pageHTML);
                    // Wire loading the next page when user scrolls to the bottom of the list
                    if ((rawData.total > parameters.items) || (rawData.total === -1)) {

                        $(pickeradvanced_content_search).bind("scroll", function(e){
                            if ((e.target.scrollHeight - e.target.scrollTop - $(e.target).height() ) === 0) {
                                $(pickeradvanced_content_search).unbind("scroll");
                                parameters.page++;
                                addPage(parameters, url);
                            }
                        });

                    }

                    // Wire item selection
                    if (pickerData.selectable) {
                        $pickeradvanced_select_all_button.unbind("click");
                        $pickeradvanced_select_all_button.click(function(){
                            pickerData.selectCount = 0;
                            $('#pickeradvanced_content_search ul li').each(function(i) {
                                $(this).addClass("pickeradvanced_selected_user");
                                $(this).children("input").attr('checked', true);
                                pickerData.selectCount += 1;
                                pickerData["selected"][$(this).attr("id")] = rawData.results[i];
                                if ($pickeradvanced_add_button.is(":disabled")) {
                                    $pickeradvanced_add_button.removeAttr("disabled");
                                }
                            });
                        });
                        $("#pickeradvanced_page_" + parameters.page + " li").unbind("click");
                        $("#pickeradvanced_page_" + parameters.page + " li").bind("click", function(e){
                            // Check if user click on top of a link
                            if (e.target.tagName.toLowerCase() !== "a") {
                                // Remove from selected list
                                if ($(this).hasClass("pickeradvanced_selected_user")) {
                                    $(this).removeClass("pickeradvanced_selected_user");
                                    $(this).children("input").removeAttr('checked');
                                    delete pickerData["selected"][$(this).attr("id")];
                                    pickerData.selectCount -= 1;
                                    if (pickerData.selectCount < 1) {
                                        $pickeradvanced_add_button.attr("disabled", "disabled");
                                    }
                                } else {
                                    // Add to selected list
                                    $(this).addClass("pickeradvanced_selected_user");
                                    $(this).children("input").attr('checked', true);
                                    for (var j = 0; j < rawData.results.length; j++) {
                                        if (rawData.results[j]['_path'] && rawData.results[j]['_path'] == [$(this).attr("id")]) {
                                            pickerData.selectCount += 1;
                                            pickerData["selected"][$(this).attr("id")] = rawData.results[j];
                                            pickerData["selected"][$(this).attr("id")].entityType = "file";
                                        }
                                    }
                                    if ($pickeradvanced_add_button.is(":disabled")) {
                                        $pickeradvanced_add_button.removeAttr("disabled");
                                    }
                                }
                            }
                        });
                    }

                    // Wire sorting select dropdown
                    $pickeradvanced_sort_on.unbind("change");
                    $pickeradvanced_sort_on.bind("change", function(e){
                        // Reset everything
                        reset();

                        // Set config to new sort key
                        // Start from scratch
                        pickerData["sortOn"] = $(this).val().split("_")[0];
                        pickerData["sortOrder"] = $(this).val().split("_")[1];
                        submitSearch();

                    });
                },
                error: function(xhr, status, thrown) {

                    // If it's likely to be a genuine server error
                    if ($pl_pageContainer.length === 0) {
                        $pickeradvanced_content_search.html($pickeradvanced_error_template.html());
                    } else {
                        // Probably it's the last page of the result set
                        $pl_pageContainer.last().remove();
                    }
                }
            });
        };

        $pickeradvanced_container.jqm({
            modal: true,
            overlay: 20,
            zIndex: 5000,
            toTop: true
        });

        var addPeople = function() {
          // this value is a comma-delimited list
          // split it and get rid of any empty values in the array
          $pickeradvanced_container.jqmHide();
          $(window).trigger("finished.pickeradvanced.sakai", {"toAdd":pickerData["selected"]});
        };

        ////////////
        // Events //
        ////////////

        $(window).unbind("init.pickeradvanced.sakai");
        $(window).bind("init.pickeradvanced.sakai", function(e, config) {
            // position dialog box at users scroll position
            var htmlScrollPos = $("html").scrollTop();
            var docScrollPos = $(document).scrollTop();
            if (htmlScrollPos > 0) {
                $pickeradvanced_container.css({"top": htmlScrollPos + 130 + "px"});
            } else if (docScrollPos > 0) {
                $pickeradvanced_container.css({"top": docScrollPos + 130 + "px"});
            }

            firstTime = true;
            render(config.config);
            $pickeradvanced_container.jqmShow();
            pickerlist = config.list;
        });

        $pickeradvanced_close_dialog.unbind("click");
        $pickeradvanced_close_dialog.bind("click", function() {
            $pickeradvanced_container.jqmHide();
        });

        $pickeradvanced_close_button.unbind("click");
        $pickeradvanced_close_button.bind("click", function() {
            $pickeradvanced_container.jqmHide();
        });

        $pickeradvanced_search_filter.die("click");
        $pickeradvanced_search_filter.live("click", function() {
           $(".pickeradvanced_selected_list").removeClass("pickeradvanced_selected_list");
           $(this).parent("li").addClass("pickeradvanced_selected_list");
           if ( $( this ).attr( "data-search" ) === "all" ) {
               pickerData.searchIn = sakai.config.URL.SEARCH_ALL_FILES;
           } else if ($( this ).attr( "data-search" ) === "my" ) {
               pickerData.searchIn = sakai.config.URL.POOLED_CONTENT_SPECIFIC_USER;
           }
           $pickeradvanced_sort_on.hide();
           submitSearch();
        });

        // Reset to defaults
        reset();

        // Send out an event that says the widget is ready to
        // accept a search query to process and display. This event can be picked up
        // in a page JS code
        $(window).trigger("ready.pickeradvanced.sakai");

    };

    sakai.api.Widgets.widgetLoader.informOnLoad("pickeradvanced");
});
<|endoftext|>


<commit_before>import React, {useContext} from 'react';
import {StyleSheet, Text, Image, FlatList, View, TouchableHighlight} from 'react-native';
import {NavigationContext} from 'navigation-react';
import {NavigationBar} from 'navigation-react-native';

export default ({follows}) => {
  const {stateNavigator} = useContext(NavigationContext);
  return (
    <>
      <NavigationBar title="Notifications" barTintColor={Platform.OS === 'android' ? '#fff' : null} />
      <FlatList
        data={follows}
        keyExtractor={item => '' + item.id}
        contentInsetAdjustmentBehavior="automatic"
        style={styles.view}
        renderItem={({item: {id, name, logo}}) => (
          <TouchableHighlight
            underlayColor="white"
            onPress={() => {
              stateNavigator.navigate('timeline', {id});
          }}>
          <View style={styles.follow}>
            <View>
              <Image style={styles.logo} source={logo} />
              <View style={styles.details}>
              <Text style={styles.name}>{name}</Text>
              <Text>followed you.</Text>
              </View>
            </View>
          </View>
        </TouchableHighlight>
      )} />
    </>
  );
};

const styles = StyleSheet.create({
  view: {
    paddingLeft: 20,
    paddingRight: 20,
  },
  follow: {
    flexDirection: 'row',
    paddingTop: 10,
    paddingBottom: 15,
    borderBottomColor: '#ccd6dd',
    borderBottomWidth: 1,
  },
  icon: {
    marginRight: 10,
  },
  details: {
    flexDirection: 'row',
  },
  name: {
    fontWeight: 'bold',
    paddingRight: 4,
  },
  logo: {
    width: 35,
    height: 35,
    borderRadius: 17.5,
    marginRight: 5,
    marginBottom: 10,
  },
});
<commit_msg>Added missing import<commit_after>import React, {useContext} from 'react';
import {Platform, StyleSheet, Text, Image, FlatList, View, TouchableHighlight} from 'react-native';
import {NavigationContext} from 'navigation-react';
import {NavigationBar} from 'navigation-react-native';

export default ({follows}) => {
  const {stateNavigator} = useContext(NavigationContext);
  return (
    <>
      <NavigationBar title="Notifications" barTintColor={Platform.OS === 'android' ? '#fff' : null} />
      <FlatList
        data={follows}
        keyExtractor={item => '' + item.id}
        contentInsetAdjustmentBehavior="automatic"
        style={styles.view}
        renderItem={({item: {id, name, logo}}) => (
          <TouchableHighlight
            underlayColor="white"
            onPress={() => {
              stateNavigator.navigate('timeline', {id});
          }}>
          <View style={styles.follow}>
            <View>
              <Image style={styles.logo} source={logo} />
              <View style={styles.details}>
              <Text style={styles.name}>{name}</Text>
              <Text>followed you.</Text>
              </View>
            </View>
          </View>
        </TouchableHighlight>
      )} />
    </>
  );
};

const styles = StyleSheet.create({
  view: {
    paddingLeft: 20,
    paddingRight: 20,
  },
  follow: {
    flexDirection: 'row',
    paddingTop: 10,
    paddingBottom: 15,
    borderBottomColor: '#ccd6dd',
    borderBottomWidth: 1,
  },
  icon: {
    marginRight: 10,
  },
  details: {
    flexDirection: 'row',
  },
  name: {
    fontWeight: 'bold',
    paddingRight: 4,
  },
  logo: {
    width: 35,
    height: 35,
    borderRadius: 17.5,
    marginRight: 5,
    marginBottom: 10,
  },
});
<|endoftext|>