<commit_before>// VVVV.js -- Visual Web Client Programming
// (c) 2011 Matthias Zauner
// VVVV.js is freely distributable under the MIT license.
// Additional authors of sub components are mentioned at the specific code locations.

var gl;
var defaultShaderAttributes = [ "PosO", "TexCd" ];
var defaultShaderUniforms = [ "tP", "tV" ];

VVVV.Types.VertexBuffer = function(position, texCoords) {

  this.positionBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(position), gl.STATIC_DRAW);

  this.texCoordBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW);

}

VVVV.Types.Mesh = function() {
  this.vertexBuffer = null;
  this.indexBuffer = null;
  this.numIndices = 0;
}

VVVV.Types.Layer = function() {
  this.mesh = null;
  this.textures = [];
  this.shaderProgram = null;
  this.uniforms = {};
  this.attributePositions = {};
  this.transform = mat4.create();
  mat4.identity(this.transform);

  this.toString = function() {
    return "Layer";
  }
}

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 NODE: FileTexture (EX9.Texture)
 Author(s): Matthias Zauner
 Original Node Author(s): VVVV Group
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

VVVV.Nodes.FileTexture = function(id, graph) {
  this.constructor(id, "FileTexture (EX9.Texture)", graph);

  this.meta = {
    authors: ['Matthias Zauner'],
    original_authors: ['VVVV Group'],
    credits: [],
    compatibility_issues: ['Always loads in background', 'No reload pin', 'No preload pin (preloading handled by browser)', 'No up and running pin', 'No texture info outputs']
  };

  this.auto_evaluate = true;

  this.filenamePin = this.addInputPin("Filename", [""], this);
  this.outputPin = this.addOutputPin("Texture Out", [], this);

  var textures = [];

  this.evaluate = function() {
    if (!gl)
      return;

    if (this.filenamePin.pinIsChanged()) {
      var maxSize = this.getMaxInputSliceCount();
      for (var i=0; i<maxSize; i++) {
        var filename = this.filenamePin.getValue(i);
        textures[i] = gl.createTexture();
        textures[i].image = new Image();
        textures[i].image.onload = (function(j) {
          return function() {  // this is to create a new scope within the loop. see "javascript closure in for loops" http://www.mennovanslooten.nl/blog/post/62
            gl.bindTexture(gl.TEXTURE_2D, textures[j]);
            //gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[j].image);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
            gl.bindTexture(gl.TEXTURE_2D, null);
          }
        })(i);
        textures[i].image.src = filename;

        this.outputPin.setValue(i, textures[i]);
      }
    }

  }

}
VVVV.Nodes.FileTexture.prototype = new VVVV.Core.Node();

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 NODE: Quad (DX9)
 Author(s): Matthias Zauner
 Original Node Author(s): VVVV Group
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

VVVV.Nodes.Quad = function(id, graph) {
  this.constructor(id, "Quad (DX9)", graph);

  this.meta = {
    authors: ['Matthias Zauner'],
    original_authors: ['VVVV Group'],
    credits: [],
    compatibility_issues: ['No Sampler States and Render States', 'No texture transform', 'No texture coord mapping', 'No enable pin']
  };

  this.auto_evaluate = true;

  this.addInputPin("Transform", [], this);
  this.addInputPin("Texture", [], this);
  this.addInputPin("Color", ["1.0, 1.0, 1.0, 1.0"], this);

  this.addOutputPin("Layer", [], this);

  var initialized = false;
  var layers = [];
  var mesh = null;
  var shaderProgram = null;

  this.evaluate = function() {

    if (!gl)
      return;

    if (!initialized) {

      var vertices = [
         0.5,  0.5,  0.0,
        -0.5,  0.5,  0.0,
         0.5, -0.5,  0.0,
        -0.5, -0.5,  0.0
      ];

      var texCoords = [
        1.0, 0.0,
        0.0, 0.0,
        1.0, 1.0,
        0.0, 1.0
      ];

      vertexBuffer = new VVVV.Types.VertexBuffer(vertices, texCoords);
      mesh = new VVVV.Types.Mesh();
      mesh.vertexBuffer = vertexBuffer;
      mesh.indexBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indexBuffer);
      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([ 0, 1, 2, 1, 3, 2 ]), gl.STATIC_DRAW);
      mesh.numIndices = 6;

      // shaders

      var fragmentShaderCode = "#ifdef GL_ES\n";
      fragmentShaderCode += "precision highp float;\n";
      fragmentShaderCode += "#endif\n";
      fragmentShaderCode += "uniform vec4 col; uniform int useTexture; varying vec2 vs2psTexCd; uniform sampler2D Samp0; void main(void) { gl_FragColor = col; if (useTexture>0) gl_FragColor = gl_FragColor*texture2D(Samp0, vs2psTexCd);  }";
      var vertexShaderCode = "attribute vec3 PosO; attribute vec2 TexCd; uniform mat4 tW; uniform mat4 tV; uniform mat4 tP; varying vec2 vs2psTexCd; void main(void) { gl_Position = tP * tV * tW * vec4(PosO, 1.0); vs2psTexCd = TexCd; }";
      var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
      gl.shaderSource(fragmentShader, fragmentShaderCode);
      gl.compileShader(fragmentShader);

      if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
        alert(gl.getShaderInfoLog(fragmentShader));
      }
      var vertexShader = gl.createShader(gl.VERTEX_SHADER);
      gl.shaderSource(vertexShader, vertexShaderCode);
      gl.compileShader(vertexShader);

      if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
        alert(gl.getShaderInfoLog(vertexShader));
      }

      shaderProgram = gl.createProgram();
      gl.attachShader(shaderProgram, vertexShader);
      gl.attachShader(shaderProgram, fragmentShader);
      gl.linkProgram(shaderProgram);

      if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
        alert("Could not initialise shaders");
      }

	  var num = gl.getProgramParameter(shaderProgram,gl.ACTIVE_UNIFORMS);
	  for (var u = 0; u < num; u++)
	  {
		var inf = gl.getActiveUniform(shaderProgram,u);
	  }

      var maxSize = this.getMaxInputSliceCount();
      for (var j=0; j<maxSize; j++) {
        layers[j] = new VVVV.Types.Layer();
        layers[j].mesh = mesh;
        layers[j].shaderProgram = shaderProgram;

        for (var i=0; i<defaultShaderAttributes.length; i++) {
          layers[j].attributePositions[defaultShaderAttributes[i]] = gl.getAttribLocation(shaderProgram, defaultShaderAttributes[i]);
        }

        for (var i=0; i<defaultShaderUniforms.length; i++) {
          layers[j].uniforms[defaultShaderUniforms[i]] = { position: gl.getUniformLocation(shaderProgram, defaultShaderUniforms[i]), value: undefined };
        }
      }

    }

    var colorChanged = this.inputPins["Color"].pinIsChanged();
    var transformChanged = this.inputPins["Transform"].pinIsChanged();
    var textureChanged = this.inputPins["Texture"].pinIsChanged();

    var maxSize = this.getMaxInputSliceCount();

    if (colorChanged) {
      for (var i=0; i<maxSize; i++) {
        var color = this.inputPins["Color"].getValue(i);
        var rgba = _(color.split(',')).map(function(x) { return parseFloat(x) });
        layers[i].uniforms['col'] = { position: gl.getUniformLocation(shaderProgram, 'col'), value: new Float32Array(rgba), setter: 'gl.uniform4fv' };
      }
    }

    if (true) {
      for (var i=0; i<maxSize; i++) {
        var transform = this.inputPins["Transform"].getValue(i);
        if (transform!=undefined)
          layers[i].transform = transform;
        else
          mat4.identity(layers[i].transform);
        layers[i].uniforms['tW'] = { position: gl.getUniformLocation(shaderProgram, 'tW'), value: layers[i].transform, setter: 'gl.uniformMatrix4fv' };
      }
    }

    if (textureChanged) {
      for (var i=0; i<maxSize; i++) {
        console.log('setting texture for layer '+i);
        tex = this.inputPins["Texture"].getValue(i);
        if (tex!=undefined) {
          layers[i].textures[0] = { position: gl.getUniformLocation(shaderProgram, "Samp0"), texture: tex };
          layers[i].uniforms["useTexture"] = { position: gl.getUniformLocation(shaderProgram, 'useTexture'), value: 1, setter: 'gl.uniform1i' };
        }
        else
          layers[i].uniforms["useTexture"] = { position: gl.getUniformLocation(shaderProgram, 'useTexture'), value: 0, setter: 'gl.uniform1i' };
      }
    }

    for (var i=0; i<maxSize; i++) {
      this.outputPins["Layer"].setValue(i, layers[i]);
    }

    initialized = true;
  }

}
VVVV.Nodes.Quad.prototype = new VVVV.Core.Node();

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 NODE: Renderer (EX9)
 Author(s): Matthias Zauner
 Original Node Author(s): VVVV Group
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

VVVV.Nodes.RendererWebGL = function(id, graph) {
  this.constructor(id, "Renderer (EX9)", graph);

  this.meta = {
    authors: ['Matthias Zauner'],
    original_authors: ['VVVV Group'],
    credits: [],
    compatibility_issues: ['No Clear Pin', 'No Background color pin', 'Backbuffer width and height defined by canvas size', 'No Fullscreen', 'No Enable Pin', 'No Aspect Ration and Viewport transform', 'No mouse output', 'No backbuffer dimesions output', 'No WebGL (EX9) Output Pin']
  };

  this.auto_evaluate = true;

  this.addInputPin("Layers", [], this);
  this.addInputPin("View Transform", [], this);
  this.addInputPin("Projection Transform", [], this);

  this.initialize = function() {
    if (!this.invisiblePins["Descriptive Name"])
      return;

    var selector = this.invisiblePins["Descriptive Name"].getValue(0);
    if (selector==undefined || selector=="")
      return;
    var canvas = $(selector);

    if (!canvas)
      return;

    try {
      gl = canvas.get(0).getContext("experimental-webgl");
      gl.viewportWidth = parseInt(canvas.get(0).width);
      gl.viewportHeight = parseInt(canvas.get(0).height);
    } catch (e) {
      console.log(e);
    }
    if (!gl) {
        alert("Oh gosh, can't initialize WebGL. If you're on Chrome, try launching like this: chrome.exe --ignore-gpu-blacklist . If you're on Firefox 4, go to page about:config and try to set webgl-force-enable to true.");
        return;
    }

    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    //gl.enable(gl.DEPTH_TEST);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  }

  this.evaluate = function() {
    if (gl==undefined)
      return;

    var layers = this.inputPins["Layers"].values;
    var pMatrix = this.inputPins["Projection Transform"].getValue(0);
    var vMatrix = this.inputPins["View Transform"].getValue(0);

    if (pMatrix==undefined) {
      pMatrix = mat4.create();
      mat4.ortho(-1, 1, -1, 1, -100, 100, pMatrix);
    }

    if (vMatrix==undefined) {
      vMatrix = mat4.create();
      mat4.identity(vMatrix);
    }

    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    var currentShaderProgram = null;

    _(layers).each(function(layer) {
      if (currentShaderProgram!=layer.shaderProgram) {
        gl.useProgram(layer.shaderProgram);
        currentShaderProgram = layer.shaderProgram;
      }

      gl.enableVertexAttribArray(layer.attributePositions["PosO"]);
      gl.bindBuffer(gl.ARRAY_BUFFER, layer.mesh.vertexBuffer.positionBuffer);
      gl.vertexAttribPointer(layer.attributePositions["PosO"], 3, gl.FLOAT, false, 0, 0);

      gl.enableVertexAttribArray(layer.attributePositions["TexCd"]);
      gl.bindBuffer(gl.ARRAY_BUFFER, layer.mesh.vertexBuffer.texCoordBuffer);
      gl.vertexAttribPointer(layer.attributePositions["TexCd"], 2, gl.FLOAT, false, 0, 0);

      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, layer.mesh.indexBuffer);
      gl.uniformMatrix4fv(layer.uniforms["tP"].position, false, pMatrix);
      gl.uniformMatrix4fv(layer.uniforms["tV"].position, false, vMatrix);
      _(layer.uniforms).each(function(u) {
        if (u.value==undefined)
          return;
        switch (u.setter) {
          case "gl.uniformMatrix4fv": gl.uniformMatrix4fv(u.position, false, u.value); break;
          case "gl.uniform4fv": gl.uniform4fv(u.position, u.value); break;
          case "gl.uniform1i": gl.uniform1i(u.position, u.value); break;
        }
      });

      if (layer.textures.length>0) {
        var t = layer.textures[0];
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, t.texture);
        gl.uniform1i(t.position, 0);
      }

      gl.drawElements(gl.TRIANGLES, layer.mesh.numIndices, gl.UNSIGNED_BYTE, 0);
    });

  }

}
VVVV.Nodes.RendererWebGL.prototype = new VVVV.Core.Node();<commit_msg>creates new data structure VVVV.Types.ShaderProgram, which bundles shader information; uses this in Quad and Renderer; paves way for dynamic Shader node<commit_after>// VVVV.js -- Visual Web Client Programming
// (c) 2011 Matthias Zauner
// VVVV.js is freely distributable under the MIT license.
// Additional authors of sub components are mentioned at the specific code locations.

var gl;
var defaultShaderAttributes = [ "PosO", "TexCd" ];
var defaultShaderUniforms = [ "tP", "tV" ];

VVVV.Types.VertexBuffer = function(position, texCoords) {

  this.positionBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(position), gl.STATIC_DRAW);

  this.texCoordBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW);

}

VVVV.Types.Mesh = function() {
  this.vertexBuffer = null;
  this.indexBuffer = null;
  this.numIndices = 0;
}

VVVV.Types.Layer = function() {
  this.mesh = null;
  this.textures = [];
  this.shader = null;
  this.uniforms = {};
  this.transform = mat4.create();
  mat4.identity(this.transform);

  this.toString = function() {
    return "Layer";
  }
}

VVVV.Types.ShaderProgram = function() {

  this.uniformSpecs = {};
  this.attributeSpecs = {};

  var vertexShader;
  var fragmentShader;

  this.shaderProgram;

  this.setVertexShader = function(code) {
    vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, code);
    gl.compileShader(vertexShader);

    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
      alert(gl.getShaderInfoLog(vertexShader));
    }
  }

  this.setFragmentShader =function(code) {
    fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, code);
    gl.compileShader(fragmentShader);

    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
      alert(gl.getShaderInfoLog(fragmentShader));
    }
  }

  this.setup = function() {
    this.shaderProgram = gl.createProgram();
    gl.attachShader(this.shaderProgram, vertexShader);
    gl.attachShader(this.shaderProgram, fragmentShader);
    gl.linkProgram(this.shaderProgram);

    if (!gl.getProgramParameter(this.shaderProgram, gl.LINK_STATUS)) {
      alert("Could not initialise shaders");
    }
  }

}

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 NODE: FileTexture (EX9.Texture)
 Author(s): Matthias Zauner
 Original Node Author(s): VVVV Group
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

VVVV.Nodes.FileTexture = function(id, graph) {
  this.constructor(id, "FileTexture (EX9.Texture)", graph);

  this.meta = {
    authors: ['Matthias Zauner'],
    original_authors: ['VVVV Group'],
    credits: [],
    compatibility_issues: ['Always loads in background', 'No reload pin', 'No preload pin (preloading handled by browser)', 'No up and running pin', 'No texture info outputs']
  };

  this.auto_evaluate = true;

  this.filenamePin = this.addInputPin("Filename", [""], this);
  this.outputPin = this.addOutputPin("Texture Out", [], this);

  var textures = [];

  this.evaluate = function() {
    if (!gl)
      return;

    if (this.filenamePin.pinIsChanged()) {
      var maxSize = this.getMaxInputSliceCount();
      for (var i=0; i<maxSize; i++) {
        var filename = this.filenamePin.getValue(i);
        textures[i] = gl.createTexture();
        textures[i].image = new Image();
        textures[i].image.onload = (function(j) {
          return function() {  // this is to create a new scope within the loop. see "javascript closure in for loops" http://www.mennovanslooten.nl/blog/post/62
            gl.bindTexture(gl.TEXTURE_2D, textures[j]);
            //gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textures[j].image);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
            gl.bindTexture(gl.TEXTURE_2D, null);
          }
        })(i);
        textures[i].image.src = filename;

        this.outputPin.setValue(i, textures[i]);
      }
    }

  }

}
VVVV.Nodes.FileTexture.prototype = new VVVV.Core.Node();

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 NODE: Quad (DX9)
 Author(s): Matthias Zauner
 Original Node Author(s): VVVV Group
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

VVVV.Nodes.Quad = function(id, graph) {
  this.constructor(id, "Quad (DX9)", graph);

  this.meta = {
    authors: ['Matthias Zauner'],
    original_authors: ['VVVV Group'],
    credits: [],
    compatibility_issues: ['No Sampler States and Render States', 'No texture transform', 'No texture coord mapping', 'No enable pin']
  };

  this.auto_evaluate = true;

  this.addInputPin("Transform", [], this);
  this.addInputPin("Texture", [], this);
  this.addInputPin("Color", ["1.0, 1.0, 1.0, 1.0"], this);

  this.addOutputPin("Layer", [], this);

  var initialized = false;
  var layers = [];
  var mesh = null;
  var shader = null;

  this.evaluate = function() {

    if (!gl)
      return;

    if (!initialized) {

      var vertices = [
         0.5,  0.5,  0.0,
        -0.5,  0.5,  0.0,
         0.5, -0.5,  0.0,
        -0.5, -0.5,  0.0
      ];

      var texCoords = [
        1.0, 0.0,
        0.0, 0.0,
        1.0, 1.0,
        0.0, 1.0
      ];

      vertexBuffer = new VVVV.Types.VertexBuffer(vertices, texCoords);
      mesh = new VVVV.Types.Mesh();
      mesh.vertexBuffer = vertexBuffer;
      mesh.indexBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indexBuffer);
      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([ 0, 1, 2, 1, 3, 2 ]), gl.STATIC_DRAW);
      mesh.numIndices = 6;

      // shaders

      var fragmentShaderCode = "#ifdef GL_ES\n";
      fragmentShaderCode += "precision highp float;\n";
      fragmentShaderCode += "#endif\n";
      fragmentShaderCode += "uniform vec4 col; uniform int useTexture; varying vec2 vs2psTexCd; uniform sampler2D Samp0; void main(void) { gl_FragColor = col; if (useTexture>0) gl_FragColor = gl_FragColor*texture2D(Samp0, vs2psTexCd);  }";
      var vertexShaderCode = "attribute vec3 PosO; attribute vec2 TexCd; uniform mat4 tW; uniform mat4 tV; uniform mat4 tP; varying vec2 vs2psTexCd; void main(void) { gl_Position = tP * tV * tW * vec4(PosO, 1.0); vs2psTexCd = TexCd; }";

      shader = new VVVV.Types.ShaderProgram();
      shader.setFragmentShader(fragmentShaderCode);
      shader.setVertexShader(vertexShaderCode);
      shader.setup();

      for (var i=0; i<defaultShaderAttributes.length; i++) {
        shader.attributeSpecs[defaultShaderAttributes[i]] = {semantic: null, varname: defaultShaderAttributes[i], position: gl.getAttribLocation(shader.shaderProgram, defaultShaderAttributes[i]) };
      }

      for (var i=0; i<defaultShaderUniforms.length; i++) {
        shader.uniformSpecs[defaultShaderUniforms[i]] = { semantic: null, varname: defaultShaderUniforms[i], position: gl.getUniformLocation(shader.shaderProgram, defaultShaderUniforms[i]) };
      }

      shader.uniformSpecs['col'] = { position: gl.getUniformLocation(shader.shaderProgram, 'col'), setter: 'gl.uniform4fv' };
      shader.uniformSpecs['tW'] = { position: gl.getUniformLocation(shader.shaderProgram, 'tW'), setter: 'gl.uniformMatrix4fv' };
      shader.uniformSpecs['useTexture'] = { position: gl.getUniformLocation(shader.shaderProgram, 'useTexture'), setter: 'gl.uniform1i' };

      var maxSize = this.getMaxInputSliceCount();
      for (var j=0; j<maxSize; j++) {
        layers[j] = new VVVV.Types.Layer();
        layers[j].mesh = mesh;
        layers[j].shader = shader;

        for (var i=0; i<defaultShaderUniforms.length; i++) {
          layers[j].uniforms[defaultShaderUniforms[i]] = { uniformSpec: shader.uniformSpecs[defaultShaderUniforms[i]], value: undefined };
        }
        layers[j].uniforms['col'] = { uniformSpec: shader.uniformSpecs['col'], value: undefined };
        layers[j].uniforms['tW'] = { uniformSpec: shader.uniformSpecs['tW'], value: undefined };
        layers[j].uniforms['useTexture'] = { uniformSpec: shader.uniformSpecs['useTexture'], value: undefined };

      }

    }

    var colorChanged = this.inputPins["Color"].pinIsChanged();
    var transformChanged = this.inputPins["Transform"].pinIsChanged();
    var textureChanged = this.inputPins["Texture"].pinIsChanged();

    var maxSize = this.getMaxInputSliceCount();

    if (colorChanged) {
      for (var i=0; i<maxSize; i++) {
        var color = this.inputPins["Color"].getValue(i);
        var rgba = _(color.split(',')).map(function(x) { return parseFloat(x) });
        layers[i].uniforms['col'].value = new Float32Array(rgba);
      }
    }

    if (true) {
      for (var i=0; i<maxSize; i++) {
        var transform = this.inputPins["Transform"].getValue(i);
        if (transform!=undefined)
          layers[i].transform = transform;
        else
          mat4.identity(layers[i].transform);
        layers[i].uniforms['tW'].value = layers[i].transform;
      }
    }

    if (textureChanged) {
      for (var i=0; i<maxSize; i++) {
        console.log('setting texture for layer '+i);
        tex = this.inputPins["Texture"].getValue(i);
        if (tex!=undefined) {
          layers[i].textures[0] = { position: gl.getUniformLocation(layers[i].shader.shaderProgram, "Samp0"), texture: tex };
          layers[i].uniforms["useTexture"].value = 1;
        }
        else
          layers[i].uniforms["useTexture"].value = 0;
      }
    }

    for (var i=0; i<maxSize; i++) {
      this.outputPins["Layer"].setValue(i, layers[i]);
    }

    initialized = true;
  }

}
VVVV.Nodes.Quad.prototype = new VVVV.Core.Node();

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 NODE: Renderer (EX9)
 Author(s): Matthias Zauner
 Original Node Author(s): VVVV Group
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

VVVV.Nodes.RendererWebGL = function(id, graph) {
  this.constructor(id, "Renderer (EX9)", graph);

  this.meta = {
    authors: ['Matthias Zauner'],
    original_authors: ['VVVV Group'],
    credits: [],
    compatibility_issues: ['No Clear Pin', 'No Background color pin', 'Backbuffer width and height defined by canvas size', 'No Fullscreen', 'No Enable Pin', 'No Aspect Ration and Viewport transform', 'No mouse output', 'No backbuffer dimesions output', 'No WebGL (EX9) Output Pin']
  };

  this.auto_evaluate = true;

  this.addInputPin("Layers", [], this);
  this.addInputPin("View Transform", [], this);
  this.addInputPin("Projection Transform", [], this);

  this.initialize = function() {
    if (!this.invisiblePins["Descriptive Name"])
      return;

    var selector = this.invisiblePins["Descriptive Name"].getValue(0);
    if (selector==undefined || selector=="")
      return;
    var canvas = $(selector);

    if (!canvas)
      return;

    try {
      gl = canvas.get(0).getContext("experimental-webgl");
      gl.viewportWidth = parseInt(canvas.get(0).width);
      gl.viewportHeight = parseInt(canvas.get(0).height);
    } catch (e) {
      console.log(e);
    }
    if (!gl) {
        alert("Oh gosh, can't initialize WebGL. If you're on Chrome, try launching like this: chrome.exe --ignore-gpu-blacklist . If you're on Firefox 4, go to page about:config and try to set webgl-force-enable to true.");
        return;
    }

    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    //gl.enable(gl.DEPTH_TEST);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  }

  this.evaluate = function() {
    if (gl==undefined)
      return;

    var layers = this.inputPins["Layers"].values;
    var pMatrix = this.inputPins["Projection Transform"].getValue(0);
    var vMatrix = this.inputPins["View Transform"].getValue(0);

    if (pMatrix==undefined) {
      pMatrix = mat4.create();
      mat4.ortho(-1, 1, -1, 1, -100, 100, pMatrix);
    }

    if (vMatrix==undefined) {
      vMatrix = mat4.create();
      mat4.identity(vMatrix);
    }

    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    var currentShaderProgram = null;

    _(layers).each(function(layer) {
      if (currentShaderProgram!=layer.shader.shaderProgram) {
        gl.useProgram(layer.shader.shaderProgram);
        currentShaderProgram = layer.shader.shaderProgram;
      }

      gl.enableVertexAttribArray(layer.shader.attributeSpecs["PosO"].position);
      gl.bindBuffer(gl.ARRAY_BUFFER, layer.mesh.vertexBuffer.positionBuffer);
      gl.vertexAttribPointer(layer.shader.attributeSpecs["PosO"].position, 3, gl.FLOAT, false, 0, 0);

      gl.enableVertexAttribArray(layer.shader.attributeSpecs["TexCd"].position);
      gl.bindBuffer(gl.ARRAY_BUFFER, layer.mesh.vertexBuffer.texCoordBuffer);
      gl.vertexAttribPointer(layer.shader.attributeSpecs["TexCd"].position, 2, gl.FLOAT, false, 0, 0);

      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, layer.mesh.indexBuffer);
      gl.uniformMatrix4fv(layer.shader.uniformSpecs["tP"].position, false, pMatrix);
      gl.uniformMatrix4fv(layer.shader.uniformSpecs["tV"].position, false, vMatrix);
      _(layer.uniforms).each(function(u) {
        if (u.value==undefined)
          return;
        switch (u.uniformSpec.setter) {
          case "gl.uniformMatrix4fv": gl.uniformMatrix4fv(u.uniformSpec.position, false, u.value); break;
          case "gl.uniform4fv": gl.uniform4fv(u.uniformSpec.position, u.value); break;
          case "gl.uniform1i": gl.uniform1i(u.uniformSpec.position, u.value); break;
        }
      });

      if (layer.textures.length>0) {
        var t = layer.textures[0];
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, t.texture);
        gl.uniform1i(t.position, 0);
      }

      gl.drawElements(gl.TRIANGLES, layer.mesh.numIndices, gl.UNSIGNED_BYTE, 0);
    });

  }

}
VVVV.Nodes.RendererWebGL.prototype = new VVVV.Core.Node();<|endoftext|>


<commit_before>jest.dontMock('../StoreDependencyMixin.js');

describe('StoreDependencyMixin', () => {
  let StoreDependencyMixin;

  beforeEach(() => {
    StoreDependencyMixin = require('../StoreDependencyMixin.js');
  });

  describe('propTypes', () => {
    it('has propTypes if a dependency specifices them');
  });

  describe('componentWillMount', () => {
    it('registers a callback with the dispatcher');

    it('calculates and sets initial state');
  });

  describe('componentWillReceiveProps', () => {
    it('calculates and sets state');

    it('doesnt recalculate fields that dont use props');
  });

  describe('componentDidUpdate', () => {
    it('has a componentDidUpdate if a field uses state');

    it('bails out if only store state changed');

    it('only recalculates fields that use state');
  });

  describe('handleDispatch', () => {
    it('waits for all stores affected by the actionType');

    it('only updates fields affected by the actionType');
  });

  describe('componentWillUnmount', () => {
    it('unregisters its dispatcher callback');
  });
});
<commit_msg>fix lint errors<commit_after>jest.dontMock('../StoreDependencyMixin.js');

describe('StoreDependencyMixin', () => {
  // let StoreDependencyMixin;

  beforeEach(() => {
    // StoreDependencyMixin = require('../StoreDependencyMixin.js');
  });

  describe('propTypes', () => {
    it('has propTypes if a dependency specifices them');
  });

  describe('componentWillMount', () => {
    it('registers a callback with the dispatcher');

    it('calculates and sets initial state');
  });

  describe('componentWillReceiveProps', () => {
    it('calculates and sets state');

    it('doesnt recalculate fields that dont use props');
  });

  describe('componentDidUpdate', () => {
    it('has a componentDidUpdate if a field uses state');

    it('bails out if only store state changed');

    it('only recalculates fields that use state');
  });

  describe('handleDispatch', () => {
    it('waits for all stores affected by the actionType');

    it('only updates fields affected by the actionType');
  });

  describe('componentWillUnmount', () => {
    it('unregisters its dispatcher callback');
  });
});
<|endoftext|>


<commit_before>// @flow

import React from 'react'
import {SectionList} from 'react-native'
import {connect} from 'react-redux'
import {type ReduxState} from '../../flux'
import {updatePrintJobs} from '../../flux/parts/stoprint'
import {type PrintJob, STOPRINT_HELP_PAGE} from '../../lib/stoprint'
import {
	ListRow,
	ListSeparator,
	ListSectionHeader,
	Detail,
	Title,
} from '../components/list'
import type {TopLevelViewPropsType} from '../types'
import delay from 'delay'
import openUrl from '../components/open-url'
import {StoprintErrorView, StoprintNoticeView} from './components'
import groupBy from 'lodash/groupBy'
import toPairs from 'lodash/toPairs'
import sortBy from 'lodash/sortBy'

type ReactProps = TopLevelViewPropsType

type ReduxStateProps = {
	jobs: Array<PrintJob>,
	error: ?string,
	loading: boolean,
	loginState: string,
}

type ReduxDispatchProps = {
	updatePrintJobs: () => Promise<any>,
}

type Props = ReactProps & ReduxDispatchProps & ReduxStateProps

class PrintJobsView extends React.PureComponent<Props> {
	static navigationOptions = {
		title: 'Print Jobs',
		headerBackTitle: 'Jobs',
	}

	componentDidMount() {
		this.refresh()
	}

	refresh = async (): any => {
		let start = Date.now()

		await this.fetchData()
		// console.log('data returned')

		// wait 0.5 seconds – if we let it go at normal speed, it feels broken.
		let elapsed = start - Date.now()
		if (elapsed < 500) {
			await delay(500 - elapsed)
		}
	}

	fetchData = () => this.props.updatePrintJobs()

	keyExtractor = (item: PrintJob) => item.id.toString()

	openSettings = () => this.props.navigation.navigate('SettingsView')

	handleJobPress = (job: PrintJob) => {
		if (job.statusFormatted === 'Pending Release') {
			this.props.navigation.navigate('PrinterListView', {job: job})
		} else {
			this.props.navigation.navigate('PrintJobReleaseView', {job: job})
		}
	}

	renderItem = ({item}: {item: PrintJob}) => (
		<ListRow onPress={() => this.handleJobPress(item)}>
			<Title>{item.documentName}</Title>
			<Detail>
				{item.usageTimeFormatted} • {item.usageCostFormatted} •{' '}
				{item.totalPages} pages • {item.statusFormatted}
			</Detail>
		</ListRow>
	)

	renderSectionHeader = ({section: {title}}: any) => (
		<ListSectionHeader title={title} />
	)

	render() {
		if (this.props.error) {
			return (
				<StoprintErrorView
					navigation={this.props.navigation}
					refresh={this.refresh}
				/>
			)
		}
		if (this.props.loginState !== 'logged-in') {
			return (
				<StoprintNoticeView
					buttonText="Open Settings"
					header="You are not logged in"
					onPress={this.openSettings}
					text="You must be logged in to your St. Olaf student account to access this feature"
				/>
			)
		} else if (this.props.jobs.length === 0) {
			return (
				<StoprintNoticeView
					buttonText="Install Stoprint"
					header="Nothing to Print!"
					onPress={() => openUrl(STOPRINT_HELP_PAGE)}
					refresh={this.refresh}
					text="Need help getting started?"
				/>
			)
		}
		const grouped = groupBy(this.props.jobs, j => j.statusFormatted || 'Other')
		let groupedJobs = toPairs(grouped).map(([title, data]) => ({
			title,
			data,
		}))
		let sortedGroupedJobs = sortBy(groupedJobs, [
			group => group.title !== 'Pending Release', // puts 'Pending Release' jobs at the top
		])
		return (
			<SectionList
				ItemSeparatorComponent={ListSeparator}
				keyExtractor={this.keyExtractor}
				onRefresh={this.refresh}
				refreshing={this.props.loading}
				renderItem={this.renderItem}
				renderSectionHeader={this.renderSectionHeader}
				sections={sortedGroupedJobs}
			/>
		)
	}
}

function mapStateToProps(state: ReduxState): ReduxStateProps {
	return {
		jobs: state.stoprint ? state.stoprint.jobs : [],
		error: state.stoprint ? state.stoprint.error : null,
		loading: state.stoprint ? state.stoprint.loadingJobs : false,
		loginState: state.settings ? state.settings.loginState : 'logged-out',
	}
}

function mapDispatchToProps(dispatch): ReduxDispatchProps {
	return {
		updatePrintJobs: () => dispatch(updatePrintJobs()),
	}
}

export const ConnectedPrintJobsView = connect(
	mapStateToProps,
	mapDispatchToProps,
)(PrintJobsView)
<commit_msg>call fetchData instead of refresh in StoprintNotice and Error views<commit_after>// @flow

import React from 'react'
import {SectionList} from 'react-native'
import {connect} from 'react-redux'
import {type ReduxState} from '../../flux'
import {updatePrintJobs} from '../../flux/parts/stoprint'
import {type PrintJob, STOPRINT_HELP_PAGE} from '../../lib/stoprint'
import {
	ListRow,
	ListSeparator,
	ListSectionHeader,
	Detail,
	Title,
} from '../components/list'
import type {TopLevelViewPropsType} from '../types'
import delay from 'delay'
import openUrl from '../components/open-url'
import {StoprintErrorView, StoprintNoticeView} from './components'
import groupBy from 'lodash/groupBy'
import toPairs from 'lodash/toPairs'
import sortBy from 'lodash/sortBy'

type ReactProps = TopLevelViewPropsType

type ReduxStateProps = {
	jobs: Array<PrintJob>,
	error: ?string,
	loading: boolean,
	loginState: string,
}

type ReduxDispatchProps = {
	updatePrintJobs: () => Promise<any>,
}

type Props = ReactProps & ReduxDispatchProps & ReduxStateProps

class PrintJobsView extends React.PureComponent<Props> {
	static navigationOptions = {
		title: 'Print Jobs',
		headerBackTitle: 'Jobs',
	}

	componentDidMount() {
		this.refresh()
	}

	refresh = async (): any => {
		let start = Date.now()

		await this.fetchData()
		// console.log('data returned')

		// wait 0.5 seconds – if we let it go at normal speed, it feels broken.
		let elapsed = start - Date.now()
		if (elapsed < 500) {
			await delay(500 - elapsed)
		}
	}

	fetchData = () => this.props.updatePrintJobs()

	keyExtractor = (item: PrintJob) => item.id.toString()

	openSettings = () => this.props.navigation.navigate('SettingsView')

	handleJobPress = (job: PrintJob) => {
		if (job.statusFormatted === 'Pending Release') {
			this.props.navigation.navigate('PrinterListView', {job: job})
		} else {
			this.props.navigation.navigate('PrintJobReleaseView', {job: job})
		}
	}

	renderItem = ({item}: {item: PrintJob}) => (
		<ListRow onPress={() => this.handleJobPress(item)}>
			<Title>{item.documentName}</Title>
			<Detail>
				{item.usageTimeFormatted} • {item.usageCostFormatted} •{' '}
				{item.totalPages} pages • {item.statusFormatted}
			</Detail>
		</ListRow>
	)

	renderSectionHeader = ({section: {title}}: any) => (
		<ListSectionHeader title={title} />
	)

	render() {
		if (this.props.error) {
			return (
				<StoprintErrorView
					navigation={this.props.navigation}
					refresh={this.fetchData}
				/>
			)
		}
		if (this.props.loginState !== 'logged-in') {
			return (
				<StoprintNoticeView
					buttonText="Open Settings"
					header="You are not logged in"
					onPress={this.openSettings}
					text="You must be logged in to your St. Olaf student account to access this feature"
				/>
			)
		} else if (this.props.jobs.length === 0) {
			return (
				<StoprintNoticeView
					buttonText="Install Stoprint"
					header="Nothing to Print!"
					onPress={() => openUrl(STOPRINT_HELP_PAGE)}
					refresh={this.fetchData}
					text="Need help getting started?"
				/>
			)
		}
		const grouped = groupBy(this.props.jobs, j => j.statusFormatted || 'Other')
		let groupedJobs = toPairs(grouped).map(([title, data]) => ({
			title,
			data,
		}))
		let sortedGroupedJobs = sortBy(groupedJobs, [
			group => group.title !== 'Pending Release', // puts 'Pending Release' jobs at the top
		])
		return (
			<SectionList
				ItemSeparatorComponent={ListSeparator}
				keyExtractor={this.keyExtractor}
				onRefresh={this.refresh}
				refreshing={this.props.loading}
				renderItem={this.renderItem}
				renderSectionHeader={this.renderSectionHeader}
				sections={sortedGroupedJobs}
			/>
		)
	}
}

function mapStateToProps(state: ReduxState): ReduxStateProps {
	return {
		jobs: state.stoprint ? state.stoprint.jobs : [],
		error: state.stoprint ? state.stoprint.error : null,
		loading: state.stoprint ? state.stoprint.loadingJobs : false,
		loginState: state.settings ? state.settings.loginState : 'logged-out',
	}
}

function mapDispatchToProps(dispatch): ReduxDispatchProps {
	return {
		updatePrintJobs: () => dispatch(updatePrintJobs()),
	}
}

export const ConnectedPrintJobsView = connect(
	mapStateToProps,
	mapDispatchToProps,
)(PrintJobsView)
<|endoftext|>


<commit_before>import set from 'cerebral-addons/set'
import when from 'cerebral-addons/when'
import addItem from '../actions/addItem.js'
import postItem from '../actions/postItem.js'
import removeItem from '../actions/removeItem.js'
import updateItem from '../actions/updateItem.js'
import storeItemsInLocalStorage from '../actions/storeItemsInLocalStorage'
import setItemSaving from '../factories/setItemSaving'

export default [
  when('input:/title'), {
    true: [
      addItem,
      set('state:/app.newItemTitle', ''),
      setItemSaving(true),
      postItem, {
        success: [
          updateItem
        ],
        error: [
          removeItem
        ]
      },
      setItemSaving(false),
      storeItemsInLocalStorage
    ],
    false: []
  }
]
<commit_msg>changed to checking state before adding item<commit_after>import set from 'cerebral-addons/set'
import when from 'cerebral-addons/when'
import addItem from '../actions/addItem.js'
import postItem from '../actions/postItem.js'
import removeItem from '../actions/removeItem.js'
import updateItem from '../actions/updateItem.js'
import storeItemsInLocalStorage from '../actions/storeItemsInLocalStorage'
import setItemSaving from '../factories/setItemSaving'

export default [
  when('state:/app.newItemTitle'), {
    true: [
      addItem,
      set('state:/app.newItemTitle', ''),
      setItemSaving(true),
      postItem, {
        success: [
          updateItem
        ],
        error: [
          removeItem
        ]
      },
      setItemSaving(false),
      storeItemsInLocalStorage
    ],
    false: []
  }
]
<|endoftext|>


<commit_before>import axios from 'axios'
import store from '@/store'

export const BASE_URL = "http://localhost:8080/rest/"

class HttpClient {

    get(path, params = {}, responseType = 'json') {
        return http({
            method: "GET",
            url: path,
            baseURL: BASE_URL,
            params,
            responseType,
            headers: headers()
        })
    }

    post(path, data) {
        return http({
            method: "post",
            url: path,
            baseURL: BASE_URL,
            responseType: 'json',
            headers: headers(),
            data: data
        })
    }

    put(path, data) {
        return http({
            method: "put",
            url: path,
            baseURL: BASE_URL,
            responseType: 'json',
            headers: headers(),
            data: data
        })
    }

    delete(path) {
        return http({
            method: "delete",
            url: path,
            baseURL: BASE_URL,
            responseType: 'json',
            headers: headers()
        })
    }
}

function http() {
    return wrapPromise(axios(...arguments))
}

function wrapPromise(promise) {
    return new Promise((resolve, reject) => {
        promise.then(resolve).catch(reason => reject(wrapError(reason)))
    })
}

function wrapError(reason) {
    if (!reason.response) {
        return new HttpError("Http client error.")
    }
    if (reason.response.data && reason.response.data.message){
        return new HttpError(reason.response.data.message, reason.response.status)
    }
    return new HttpError(`Http server error: ${reason.response.status}.`, reason.response.status)
}

function headers() {
    let token = store.state.auth.token
    let headers = {}
    if (token) {
        headers["Authorization"] = `bearer ${token}`
    }
    return headers
}

class HttpError extends Error {

    constructor(message, statusCode) {
        super(message)
        this.statusCode = statusCode
    }
}

export default new HttpClient()<commit_msg>Infer server protocol and authority from URL<commit_after>import axios from 'axios'
import store from '@/store'

export const PORT = 8080
export const BASE_PATH = "rest/"

class HttpClient {

    get(path, params = {}, responseType = 'json') {
        return http({
            method: "GET",
            url: path,
            baseURL: baseUrl(),
            params,
            responseType,
            headers: headers()
        })
    }

    post(path, data) {
        return http({
            method: "post",
            url: path,
            baseURL: baseUrl(),
            responseType: 'json',
            headers: headers(),
            data: data
        })
    }

    put(path, data) {
        return http({
            method: "put",
            url: path,
            baseURL: baseUrl(),
            responseType: 'json',
            headers: headers(),
            data: data
        })
    }

    delete(path) {
        return http({
            method: "delete",
            url: path,
            baseURL: baseUrl(),
            responseType: 'json',
            headers: headers()
        })
    }
}

function http() {
    return wrapPromise(axios(...arguments))
}

function wrapPromise(promise) {
    return new Promise((resolve, reject) => {
        promise.then(resolve).catch(reason => reject(wrapError(reason)))
    })
}

function wrapError(reason) {
    if (!reason.response) {
        return new HttpError("Http client error.")
    }
    if (reason.response.data && reason.response.data.message){
        return new HttpError(reason.response.data.message, reason.response.status)
    }
    return new HttpError(`Http server error: ${reason.response.status}.`, reason.response.status)
}

function headers() {
    let token = store.state.auth.token
    let headers = {}
    if (token) {
        headers["Authorization"] = `bearer ${token}`
    }
    return headers
}

function baseUrl() {
    return `${window.location.protocol}//${window.location.hostname}:${PORT}/${BASE_PATH}`
}

class HttpError extends Error {

    constructor(message, statusCode) {
        super(message)
        this.statusCode = statusCode
    }
}

export default new HttpClient()<|endoftext|>


<commit_before>import is_nil from 'lodash.isnil';
import is_number from 'lodash.isnumber';
import noop from 'lodash.noop';

function normalize_scale(scale) {
	if (is_nil(scale)) {
		scale = 1;
	}
	return is_number(scale) ? {x: scale, y: scale} : scale;
}

export default (coordinates, options = {}) => {
	const onRender = is_nil(options.onRender) ? noop : options.onRender;
	const onSceneChanged = is_nil(options.onSceneChanged) ? noop : options.onSceneChanged;
	let scale = normalize_scale(options.scale);
	let scene = null;
	let visible = is_nil(options.visible) ? true : options.visible;
	let zIndex = is_nil(options.zIndex) ? 0 : options.zIndex;
	return {
		zIndex() {
			return zIndex;
		},
		setZIndex(value) {
			if (zIndex !== value) {
				zIndex = value;
				if (!is_nil(scene)) {
					// make the scene to sort its children
					scene.add(this);
				}
			}
			return this;
		},
		scene() {
			return scene;
		},
		setScene(s) {
			if (!is_nil(scene)) {
				const tmp = scene;
				scene = null;
				tmp.remove(this);
			}
			if (!is_nil(s) && scene !== s) {
				scene = s;
				scene.add(this);
				onSceneChanged.call(this, scene);
			}
			return this;
		},
		scale() {
			return scale;
		},
		setScale(f) {
			scale = is_number(f) ? {x: f, y: f} : f;
			return this;
		},
		show() {
			visible = true;
			return this;
		},
		hide() {
			visible = false;
			return this;
		},
		visible() {
			return visible;
		},
		setVisible(visibility) {
			visible = visibility;
			return this;
		},
		render(screen) {
			if (visible) {
				screen.save();
				screen.setScale(scale);
				screen.clipRect(coordinates.rect());
				screen.translate(coordinates.position());
				onRender.call(this, screen, scene, coordinates.localRect());
				screen.restore();
			}
			return this;
		}
	};
}
<commit_msg>Fix clip<commit_after>import is_nil from 'lodash.isnil';
import is_number from 'lodash.isnumber';
import noop from 'lodash.noop';

function normalize_scale(scale) {
	if (is_nil(scale)) {
		scale = 1;
	}
	return is_number(scale) ? {x: scale, y: scale} : scale;
}

export default (coordinates, options = {}) => {
	const onRender = is_nil(options.onRender) ? noop : options.onRender;
	const onSceneChanged = is_nil(options.onSceneChanged) ? noop : options.onSceneChanged;
	let scale = normalize_scale(options.scale);
	let scene = null;
	let visible = is_nil(options.visible) ? true : options.visible;
	let zIndex = is_nil(options.zIndex) ? 0 : options.zIndex;
	return {
		zIndex() {
			return zIndex;
		},
		setZIndex(value) {
			if (zIndex !== value) {
				zIndex = value;
				if (!is_nil(scene)) {
					// make the scene to sort its children
					scene.add(this);
				}
			}
			return this;
		},
		scene() {
			return scene;
		},
		setScene(s) {
			if (!is_nil(scene)) {
				const tmp = scene;
				scene = null;
				tmp.remove(this);
			}
			if (!is_nil(s) && scene !== s) {
				scene = s;
				scene.add(this);
				onSceneChanged.call(this, scene);
			}
			return this;
		},
		scale() {
			return scale;
		},
		setScale(f) {
			scale = is_number(f) ? {x: f, y: f} : f;
			return this;
		},
		show() {
			visible = true;
			return this;
		},
		hide() {
			visible = false;
			return this;
		},
		visible() {
			return visible;
		},
		setVisible(visibility) {
			visible = visibility;
			return this;
		},
		render(screen) {
			if (visible) {
				screen.save();
				screen.setScale(scale);
				screen.translate(coordinates.position());
				screen.clipRect(coordinates.localRect());
				onRender.call(this, screen, scene, coordinates.localRect());
				screen.restore();
			}
			return this;
		}
	};
}
<|endoftext|>


<commit_before>/* global describe */
/* global beforeEach */
/* global it */
/* global inject */
/* global expect */
/* global jasmine */
/* global module */
/* global _ */
'use strict';

describe("search.dao.js", function() {
  // search parameters
  var searchTerm = 'elasticsearch bloopers';
  var dataAcquisitionProjectId = 'ela2018';
  var SearchDao, ElasticSearchClient, Principal;
  var filter = {};
  var elasticSearchType = 'studies';
  var page = 1;
  var pageSize = 5;

  // variables injected into search.dao service
  var clientId;

  // captured parameter for ElasticSearchClient#search
  var capturedQuery = null;

  beforeEach(function() {
    module('metadatamanagementApp');

    inject(function(_SearchDao_, _ElasticSearchClient_, _Principal_, _clientId_) {
      SearchDao = _SearchDao_;
      ElasticSearchClient = _ElasticSearchClient_;
      Principal = _Principal_;
      clientId = _clientId_;

      spyOn(ElasticSearchClient, 'search').and.callFake(function(query) {
        capturedQuery = query;
      });
    });
  });

  it('should always apply default query settings', function() {
    SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

    expect(capturedQuery.preference).toEqual(clientId);
    expect(capturedQuery.index).toEqual(elasticSearchType);
    expect(capturedQuery.type).toEqual(elasticSearchType);
    expect(capturedQuery.body._source).toBeDefined();
    expect(capturedQuery.body.sort).toBeDefined();
    expect(capturedQuery.body.from).toEqual((page - 1) * pageSize);
    expect(capturedQuery.body.size).toEqual(pageSize);
  });

  it('should add the searched term if provided', function() {
    SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

    var predicate = {
      constant_score: {
        filter: {
          match: {
            all: {
              query: searchTerm,
              operator: 'AND',
              minimum_should_match: '100%',
              zero_terms_query: 'NONE',
              boost: 1
            }
          }
        }
      }
    };

    var generatedFilter = _.find(capturedQuery.body.query.bool.must, predicate);
    expect(generatedFilter).toBeDefined();
  });

  it('should add a "match_all" clause if no search term is provided', function() {
    SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

    var predicate = {
      match_all: {}
    };

    var generatedFilter = _.find(capturedQuery.body.query.bool.must, predicate);

    expect(generatedFilter).toBeDefined();
  });

  describe('::dataAcquisitionProjectId filter', function() {
    var predicate = {
      bool: {
        should: [{
          term: {
            dataAcquisitionProjectId: dataAcquisitionProjectId
          }
        }, {
          term: {
            studyIds: 'stu-' + dataAcquisitionProjectId + '$'
          }
        }]
      }
    };

    it('should add a "dataAcquisitionProjectId" filter if a project id is provided', function() {
      SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);
      expect(generatedFilter).toBeDefined();
    });

    it('should not add a "dataAcquisitionProjectId" filter if no project id is provided', function() {
      SearchDao.search(undefined, page, undefined, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);
      expect(generatedFilter).toBeUndefined();
    });
  });

  it('should exclude ids if specified', inject(function() {
    SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize, 'ela2005');

    expect(capturedQuery.body.query.bool.must_not.terms.id).toEqual('ela2005');
  }));

  it('should add a type clause if an elasticsearch type is not provided', function() {
    SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, null, pageSize);
    expect(capturedQuery.body.aggs.countByType.terms.field).toEqual('_type')
  });

  it('should not add a type clause if an elasticsearch type is provided', function() {
    SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);
    var result = _.get(capturedQuery, 'body.aggs.countByType.terms.field');
    expect(result).toBeUndefined();
  });

  describe('::release filter', function() {
    var predicate = {
      exists: {
        field: 'release'
      }
    };

    it('should add a release filter if is not a publisher, admin or data provider', function() {
      spyOn(Principal, 'hasAnyAuthority').and.returnValue(false);
      SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);

      expect(generatedFilter).toBeDefined();
    });

    it('should not add release filter if user is a publisher, admin or data provider', function() {
      spyOn(Principal, 'hasAnyAuthority').and.returnValue(true);
      SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);

      expect(generatedFilter).toBeUndefined();
    });
  });

  describe('::dataProvider filter', function() {
    var predicate = {
      'bool': {
        'must': [{
          'term': {'configuration.dataProviders': 'dataProviderUser'}
        }]
      }
    };

    it('should add a data provider filter if user is only a data provider', function() {
      spyOn(Principal, 'hasAnyAuthority').and.returnValue(false);
      spyOn(Principal, 'loginName').and.returnValue('dataProviderUser');

      SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);

      expect(generatedFilter).toBeDefined();
    });

    it('should not add a data provider filter if user is admin or publisher', function() {
      spyOn(Principal, 'hasAnyAuthority').and.returnValue(true);

      SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);

      expect(generatedFilter).toBeUndefined();
    });
  });
});
<commit_msg>#1842 Added more tests to search.dao.spec to increase line and branch coverage<commit_after>/* global describe */
/* global beforeEach */
/* global it */
/* global inject */
/* global expect */
/* global jasmine */
/* global module */
/* global _ */
'use strict';

describe("search.dao.js", function() {
  // search parameters
  var searchTerm = 'elasticsearch bloopers';
  var dataAcquisitionProjectId = 'ela2018';
  var SearchDao, ElasticSearchClient, Principal;
  var filter = {};
  var elasticSearchType = 'studies';
  var page = 1;
  var pageSize = 5;

  // variables injected into search.dao service
  var clientId;
  var SearchHelperService;

  // captured parameter for ElasticSearchClient#search
  var capturedQuery = null;

  beforeEach(function() {
    module('metadatamanagementApp');

    inject(function(_SearchDao_, _ElasticSearchClient_, _Principal_, _clientId_, _SearchHelperService_, _LanguageService_) {
      SearchDao = _SearchDao_;
      ElasticSearchClient = _ElasticSearchClient_;
      Principal = _Principal_;
      clientId = _clientId_;
      SearchHelperService = _SearchHelperService_;

      spyOn(ElasticSearchClient, 'search').and.callFake(function(query) {
        capturedQuery = query;
      });

      spyOn(_LanguageService_, 'getCurrentInstantly').and.returnValue('en');
    });
  });

  it('should always apply default query settings', function() {
    SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

    expect(capturedQuery.preference).toEqual(clientId);
    expect(capturedQuery.index).toEqual(elasticSearchType);
    expect(capturedQuery.type).toEqual(elasticSearchType);
    expect(capturedQuery.body._source).toBeDefined();
    expect(capturedQuery.body.sort).toBeDefined();
    expect(capturedQuery.body.from).toEqual((page - 1) * pageSize);
    expect(capturedQuery.body.size).toEqual(pageSize);
  });

  it('should add the searched term if provided', function() {
    SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

    var predicate = {
      constant_score: {
        filter: {
          match: {
            all: {
              query: searchTerm,
              operator: 'AND',
              minimum_should_match: '100%',
              zero_terms_query: 'NONE',
              boost: 1
            }
          }
        }
      }
    };

    var generatedFilter = _.find(capturedQuery.body.query.bool.must, predicate);
    expect(generatedFilter).toBeDefined();
  });

  it('should add a "match_all" clause if no search term is provided', function() {
    SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

    var predicate = {
      match_all: {}
    };

    var generatedFilter = _.find(capturedQuery.body.query.bool.must, predicate);

    expect(generatedFilter).toBeDefined();
  });

  describe('::dataAcquisitionProjectId filter', function() {
    var predicate = {
      bool: {
        should: [{
          term: {
            dataAcquisitionProjectId: dataAcquisitionProjectId
          }
        }, {
          term: {
            studyIds: 'stu-' + dataAcquisitionProjectId + '$'
          }
        }]
      }
    };

    it('should add a "dataAcquisitionProjectId" filter if a project id is provided', function() {
      SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);
      expect(generatedFilter).toBeDefined();
    });

    it('should not add a "dataAcquisitionProjectId" filter if no project id is provided', function() {
      SearchDao.search(undefined, page, undefined, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);
      expect(generatedFilter).toBeUndefined();
    });
  });

  it('should exclude ids if specified', inject(function() {
    SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize, 'ela2005');

    expect(capturedQuery.body.query.bool.must_not.terms.id).toEqual('ela2005');
  }));

  it('should add a type clause if an elasticsearch type is not provided', function() {
    SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, null, pageSize);
    expect(capturedQuery.body.aggs.countByType.terms.field).toEqual('_type')
  });

  it('should not add a type clause if an elasticsearch type is provided', function() {
    SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);
    var result = _.get(capturedQuery, 'body.aggs.countByType.terms.field');
    expect(result).toBeUndefined();
  });

  describe('::release filter', function() {
    var predicate = {
      exists: {
        field: 'release'
      }
    };

    it('should add a release filter if is not a publisher, admin or data provider', function() {
      spyOn(Principal, 'hasAnyAuthority').and.returnValue(false);
      SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);

      expect(generatedFilter).toBeDefined();
    });

    it('should not add release filter if user is a publisher, admin or data provider', function() {
      spyOn(Principal, 'hasAnyAuthority').and.returnValue(true);
      SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);

      expect(generatedFilter).toBeUndefined();
    });
  });

  describe('::dataProvider filter', function() {
    var predicate = {
      'bool': {
        'must': [{
          'term': {'configuration.dataProviders': 'dataProviderUser'}
        }]
      }
    };

    it('should add a data provider filter if user is only a data provider', function() {
      spyOn(Principal, 'hasAnyAuthority').and.returnValue(false);
      spyOn(Principal, 'loginName').and.returnValue('dataProviderUser');

      SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);

      expect(generatedFilter).toBeDefined();
    });

    it('should not add a data provider filter if user is admin or publisher', function() {
      spyOn(Principal, 'hasAnyAuthority').and.returnValue(true);

      SearchDao.search(undefined, page, dataAcquisitionProjectId, filter, elasticSearchType, pageSize);

      var generatedFilter = _.find(capturedQuery.body.query.bool.filter, predicate);

      expect(generatedFilter).toBeUndefined();
    });
  });

  describe('::apply filter', function() {
    it('should apply default filters if some were given', function() {
      spyOn(SearchHelperService, 'createTermFilters').and.callThrough();
      var surveyFilter = {
        survey: 'sur-' + dataAcquisitionProjectId + '-sy1'
      };
      SearchDao.search(undefined, page, dataAcquisitionProjectId, surveyFilter, elasticSearchType, pageSize);

      expect(SearchHelperService.createTermFilters).toHaveBeenCalled();
    });
  });

  describe('::should query filters', function() {
    var searchTerm = 'a-search-term';

    var buildPredicate = function(fieldName, searchTerm) {
      var predicate = {
        constant_score: {
          filter: {
            match: {}
          }
        }
      };

      predicate.constant_score.filter.match[fieldName] = {
        query: searchTerm
      };
      return predicate;
    };

    var findQueryItem = function(capturedQuery, predicate) {
      return _.find(capturedQuery.body.query.bool.should, predicate);
    };

    it('should set "should" filters for "study" type', function() {
      SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, 'studies', pageSize);

      expect(findQueryItem(capturedQuery, buildPredicate('title.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('title.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('surveyDesign.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('surveyDesign.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('surveyDataType.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('surveyDataType.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('id.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('authors.firstName.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('authors.middleName.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('authors.lastName.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('description.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('description.en.ngrams', searchTerm))).toBeDefined();
    });

    it('should set "should" filters for "surveys" type', function() {
      SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, 'surveys', pageSize);

      expect(findQueryItem(capturedQuery, buildPredicate('title.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('title.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('dataType.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('dataType.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('surveyMethod.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('surveyMethod.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('id.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('population.description.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('population.description.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('population.title.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('population.title.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('sample.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('sample.en.ngrams', searchTerm))).toBeDefined();
    });

    it('should set "should" filters for "instruments" type', function() {
      SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, 'instruments', pageSize);

      expect(findQueryItem(capturedQuery, buildPredicate('description.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('description.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('id.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('type.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('title.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('title.en.ngrams', searchTerm))).toBeDefined();
    });

    it('should set "should" filters for "questions" type', function() {
      SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, 'questions', pageSize);

      expect(findQueryItem(capturedQuery, buildPredicate('instrument.description.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('instrument.description.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('id.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('number.edge_ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('type.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('type.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('questionText.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('questionText.en.ngrams', searchTerm))).toBeDefined();
    });

    it('should set "should" filters for "data_sets" type', function() {
      SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, 'data_sets', pageSize);

      expect(findQueryItem(capturedQuery, buildPredicate('description.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('description.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('id.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('type.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('type.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('surveys.title.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('surveys.title.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('subDataSets.accessWays.ngrams', searchTerm))).toBeDefined();
    });

    it('should set "should" filters for "variables" type', function() {
      SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, 'variables', pageSize);

      expect(findQueryItem(capturedQuery, buildPredicate('label.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('label.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('name.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('id.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('dataType.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('dataType.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('scaleLevel.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('scaleLevel.en.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('surveys.title.de.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('surveys.title.en.ngrams', searchTerm))).toBeDefined();
    });

    it('should set "should" filters for "related_publications" type', function() {
      SearchDao.search(searchTerm, page, dataAcquisitionProjectId, filter, 'related_publications', pageSize);

      expect(findQueryItem(capturedQuery, buildPredicate('title.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('authors.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('id.ngrams', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('year', searchTerm))).toBeDefined();
      expect(findQueryItem(capturedQuery, buildPredicate('sourceReference.ngrams', searchTerm))).toBeDefined();
    });
  });
});
<|endoftext|>


<commit_before><commit_msg>Fix div typo<commit_after><|endoftext|>


<commit_before>steal('can/util', 'can/observe/sort', 'can/view/mustache', function(can) {

module("can/observe/sort");

test("list events", 12, function(){

	var list = new can.Observe.List([
		{name: 'Justin'},
		{name: 'Brian'},
		{name: 'Austin'},
		{name: 'Mihael'}])
	list.comparator = 'name';
	list.sort();
	// events on a list
	// - move - item from one position to another
	//          due to changes in elements that change the sort order
	// - add (items added to a list)
	// - remove (items removed from a list)
	// - reset (all items removed from the list)
	// - change something happened

	// a move directly on this list
	list.bind('move', function(ev, item, newPos, oldPos){
		ok(true,"move called");
		equals(item.name, "Zed");
		equals(newPos, 3);
		equals(oldPos, 0);
	});

	// a remove directly on this list
	list.bind('remove', function(ev, items, oldPos){
		ok(true,"remove called");
		equals(items.length,1);
		equals(items[0].name, 'Alexis');
		equals(oldPos, 0, "put in right spot")
	})
	list.bind('add', function(ev, items, newLength){
		ok(true,"add called");
		equals(items.length,1);
		equals(items[0].name, 'Alexis');
		// .push returns the new length not the current position
		equals(newLength, 4, "got new length");
	});

	list.push({name: 'Alexis'});

	// now lets remove alexis ...
	list.splice(0,1);
	list[0].attr('name',"Zed")
});

test("list sort with func", 1, function(){

	var list = new can.Observe.List([
		{priority: 4, name: "low"},
		{priority: 1, name: "high"},
		{priority: 2, name: "middle"},
		{priority: 3, name: "mid"}])

	list.sort(function(a, b){
		return a.priority > b.priority;
	});
	equals(list[0].name, 'high');
});

test("live binding with comparator (#170)", function() {
	var renderer = can.view.mustache('
{{#items}}
{{text}}
{{/items}}
'),
		el = document.createElement('div'),
		items = new can.Observe.List([{
			text : 'First'
		}]);

	el.appendChild(renderer({
		items : items
	}));

	equals(el.getElementsByTagName('li').length, 1, "Found one li");

	items.push({
		text : 'Second'
	});

	equals(el.getElementsByTagName('li').length, 2, "Live binding rendered second li");
});

})();<commit_msg>Fix test, sort function always needs to return an integer<commit_after>steal('can/util', 'can/observe/sort', 'can/view/mustache', function(can) {

module("can/observe/sort");

test("list events", 12, function(){

	var list = new can.Observe.List([
		{name: 'Justin'},
		{name: 'Brian'},
		{name: 'Austin'},
		{name: 'Mihael'}])
	list.comparator = 'name';
	list.sort();
	// events on a list
	// - move - item from one position to another
	//          due to changes in elements that change the sort order
	// - add (items added to a list)
	// - remove (items removed from a list)
	// - reset (all items removed from the list)
	// - change something happened

	// a move directly on this list
	list.bind('move', function(ev, item, newPos, oldPos){
		ok(true,"move called");
		equals(item.name, "Zed");
		equals(newPos, 3);
		equals(oldPos, 0);
	});

	// a remove directly on this list
	list.bind('remove', function(ev, items, oldPos){
		ok(true,"remove called");
		equals(items.length,1);
		equals(items[0].name, 'Alexis');
		equals(oldPos, 0, "put in right spot")
	})
	list.bind('add', function(ev, items, newLength){
		ok(true,"add called");
		equals(items.length,1);
		equals(items[0].name, 'Alexis');
		// .push returns the new length not the current position
		equals(newLength, 4, "got new length");
	});

	list.push({name: 'Alexis'});

	// now lets remove alexis ...
	list.splice(0,1);
	list[0].attr('name',"Zed")
});

test("list sort with func", 1, function(){

	var list = new can.Observe.List([
		{priority: 4, name: "low"},
		{priority: 1, name: "high"},
		{priority: 2, name: "middle"},
		{priority: 3, name: "mid"}])

	list.sort(function(a, b){
		// Sort functions always need to return the -1/0/1 integers
		if(a.priority  b.priority ? 1 : 0;
	});
	equals(list[0].name, 'high');
});

test("live binding with comparator (#170)", function() {
	var renderer = can.view.mustache('
{{#items}}
{{text}}
{{/items}}
'),
		el = document.createElement('div'),
		items = new can.Observe.List([{
			text : 'First'
		}]);

	el.appendChild(renderer({
		items : items
	}));

	equals(el.getElementsByTagName('li').length, 1, "Found one li");

	items.push({
		text : 'Second'
	});

	equals(el.getElementsByTagName('li').length, 2, "Live binding rendered second li");
});

})();<|endoftext|>


<commit_before>/*!
 *  opentok-whiteboard (http://github.com/aullman/opentok-whiteboard)
 *
 *  Shared Whiteboard that works with OpenTok
 *
 *  @Author: Adam Ullman (http://github.com/aullman)
 *  @Copyright (c) 2014 Adam Ullman
 *  @License: Released under the MIT license (http://opensource.org/licenses/MIT)
**/
var OpenTokWhiteboard=angular.module("opentok-whiteboard",["opentok"]).directive("otWhiteboard",["OTSession","$window",function(o,t){return{restrict:"E",template:'<canvas></canvas>
<input type="button" ng-class="{OT_color: true, OT_selected: c[\'background-color\'] === color}" ng-repeat="c in colors" ng-style="c" ng-click="changeColor(c)"></input><input type="button" ng-click="erase()" ng-class="{OT_erase: true, OT_selected: erasing}" value="Eraser"></input><input type="button" ng-click="capture()" class="OT_capture" value="{{captureText}}"></input><input type="button" ng-click="undo()" class="OT_capture" value="Undo"></input><input type="button" ng-click="redo()" class="OT_capture" value="Redo"></input><input type="button" ng-click="clear()" class="OT_clear" value="Clear"></input>',link:function(t,e,n){var a,c,r=e.context.querySelector("canvas"),s=(e.context.querySelector("select"),e.context.querySelector("input"),{dragging:!1}),u=0,l=[],d=[],p=[],h=[],g=/(iPad|iPhone|iPod)/g.test(navigator.userAgent);paper.setup(r),t.colors=[{"background-color":"black"},{"background-color":"blue"},{"background-color":"red"},{"background-color":"green"},{"background-color":"orange"},{"background-color":"purple"},{"background-color":"brown"}],t.captureText=g?"Email":"Capture",t.strokeCap="round",t.strokeJoin="round",r.width=n.width||e.width(),r.height=n.height||e.height(),a||(a=r.getContext("2d"));var f=function(){a.save(),a.setTransform(1,0,0,1,0,0),a.clearRect(0,0,r.width,r.height),a.restore()};t.changeColor=function(o){t.color=o["background-color"],t.lineWidth=2,t.erasing=!1},t.changeColor(t.colors[Math.floor(Math.random()*t.colors.length)]),t.clear=function(){f(),o.session&&o.session.signal({type:"otWhiteboard_clear"})},t.erase=function(){t.lineWidth=50,t.erasing=!0},t.capture=function(){g?window.location.href="mailto:?subject=Whiteboard&Body=":window.open(r.toDataURL("image/png"))},t.undo=function(){if(l.length){var o=l.pop();m(o),d.push(o),W("otWhiteboard_undo",o)}};var m=function(o){for(i=o.start-o.count;i<o.start;i++)p[i].show=0;f(),p.forEach(function(o){k(o)})};t.redo=function(){if(d.length){var o=d.pop();v(o),l.push(o),W("otWhiteboard_redo",o)}};var b,v=function(o){for(i=o.start-o.count;i<o.start;i++)p[i].show=1;f(),p.forEach(function(o){k(o)})},k=function(o){window.path.add(o.toX,o.toY),p.push(o)},w=function(o){o.forEach(function(o){k(o),p.push(o)})},y=function(t,e,n){for(var i=e.slice(),a=function(o){o&&TB.error(o)};i.length;){var c=i.splice(0,Math.min(i.length,32)),r={type:t,data:JSON.stringify(c)};n&&(r.to=n),o.session.signal(r,a)}},W=function(t,e){o.session&&(h.push(e),b||(b=setTimeout(function(){y(t,h),h=[],b=null},100)))};angular.element(document).on("keyup",function(o){o.ctrlKey&&(90===o.keyCode&&t.undo(),89===o.keyCode&&t.redo())}),angular.element(r).on("mousedown mousemove mouseup mouseout touchstart touchmove touchend touchcancel",function(n){if("mousemove"!==n.type&&"touchmove"!==n.type||s.dragging){n.preventDefault();var i,a=angular.element(r).offset(),c=r.width/e.width(),h=r.height/e.height(),g=n.offsetX||n.originalEvent.pageX-a.left||n.originalEvent.touches[0].pageX-a.left,f=n.offsetY||n.originalEvent.pageY-a.top||n.originalEvent.touches[0].pageY-a.top,m=g*c,b=f*h,v=t.erasing?"pen":"eraser";switch(n.type){case"mousedown":case"touchstart":s.dragging=!0,s.lastX=m,s.lastY=b,window.path&&(window.path.selected=!1),window.path=new paper.Path,path.strokeColor=t.color,path.strokeWidth=t.lineWidth,path.strokeCap=t.strokeCap,path.strokeJoin=t.strokeJoin,"pen"==v&&(path.blendMode="destination-out"),i=new paper.Point(m,b),path.moveTo(i);break;case"mousemove":case"touchmove":if(g=n.offsetX||n.originalEvent.pageX-a.left||n.originalEvent.touches[0].pageX-a.left,f=n.offsetY||n.originalEvent.pageY-a.top||n.originalEvent.touches[0].pageY-a.top,m=g*c,b=f*h,s.dragging){var w={id:o.session&&o.session.connection&&o.session.connection.connectionId,fromX:s.lastX,fromY:s.lastY,toX:m,toY:b,mode:v,color:t.color,lineWidth:t.lineWidth,show:1};u++,d=[],k(w),p.push(w),s.lastX=m,s.lastY=b,W("otWhiteboard_update",w)}break;case"touchcancel":case"mouseup":case"touchend":case"mouseout":window.path.smooth(),s.dragging=!1,u&&(i=p.length,l.push({start:i,count:u}),u=0)}}}),o.session&&o.session.on({"signal:otWhiteboard_update":function(e){e.from.connectionId!==o.session.connection.connectionId&&(w(JSON.parse(e.data)),t.$emit("otWhiteboardUpdate"))},"signal:otWhiteboard_undo":function(e){e.from.connectionId!==o.session.connection.connectionId&&(JSON.parse(e.data).forEach(function(o){m(o)}),t.$emit("otWhiteboardUpdate"))},"signal:otWhiteboard_redo":function(e){e.from.connectionId!==o.session.connection.connectionId&&(JSON.parse(e.data).forEach(function(o){v(o)}),t.$emit("otWhiteboardUpdate"))},"signal:otWhiteboard_history":function(o){c&&c!==o.from.connectionId||(c=o.from.connectionId,w(JSON.parse(o.data)),t.$emit("otWhiteboardUpdate"))},"signal:otWhiteboard_clear":function(t){t.from.connectionId!==o.session.connection.connectionId&&f()},connectionCreated:function(t){p.length>0&&t.connection.connectionId!==o.session.connection.connectionId&&y("otWhiteboard_history",p,t.connection)}})}}}]);<commit_msg>Gulped<commit_after>/*!
 *  opentok-whiteboard (http://github.com/aullman/opentok-whiteboard)
 *
 *  Shared Whiteboard that works with OpenTok
 *
 *  @Author: Adam Ullman (http://github.com/aullman)
 *  @Copyright (c) 2014 Adam Ullman
 *  @License: Released under the MIT license (http://opensource.org/licenses/MIT)
**/
var OpenTokWhiteboard=angular.module("opentok-whiteboard",["opentok"]).directive("otWhiteboard",["OTSession","$window",function(o,e){return{restrict:"E",template:'<canvas></canvas>
<input type="button" ng-class="{OT_color: true, OT_selected: c[\'background-color\'] === color}" ng-repeat="c in colors" ng-style="c" ng-click="changeColor(c)"></input><input type="button" ng-click="erase()" ng-class="{OT_erase: true, OT_selected: erasing}" value="Eraser"></input><input type="button" ng-click="capture()" class="OT_capture" value="{{captureText}}"></input><input type="button" ng-click="undo()" class="OT_capture" value="Undo"></input><input type="button" ng-click="redo()" class="OT_capture" value="Redo"></input><input type="button" ng-click="clear()" class="OT_clear" value="Clear"></input>',link:function(e,t,n){var a,i,c=t.context.querySelector("canvas"),r=(t.context.querySelector("select"),t.context.querySelector("input"),{dragging:!1}),s=0,u=[],l=[],d=[],p=[],h=/(iPad|iPhone|iPod)/g.test(navigator.userAgent);paper.setup(c),e.colors=[{"background-color":"black"},{"background-color":"blue"},{"background-color":"red"},{"background-color":"green"},{"background-color":"orange"},{"background-color":"purple"},{"background-color":"brown"}],e.captureText=h?"Email":"Capture",e.strokeCap="round",e.strokeJoin="round",c.width=n.width||t.width(),c.height=n.height||t.height(),a||(a=c.getContext("2d"));var g=function(){paper.project.clear(),paper.view.update()};e.changeColor=function(o){e.color=o["background-color"],e.lineWidth=2,e.erasing=!1},e.changeColor(e.colors[Math.floor(Math.random()*e.colors.length)]),e.clear=function(){g(),o.session&&o.session.signal({type:"otWhiteboard_clear"})},e.erase=function(){e.lineWidth=50,e.erasing=!0},e.capture=function(){h?window.location.href="mailto:?subject=Whiteboard&Body=":window.open(c.toDataURL("image/png"))},e.undo=function(){if(u.length){var o=u.pop();f(o),l.push(o),y("otWhiteboard_undo",o)}};var f=function(o){o.visible=!1,paper.view.update()};e.redo=function(){if(l.length){var o=l.pop();v(o),u.push(o),y("otWhiteboard_redo",o)}};var m,v=function(o){o.visible=!0,paper.view.update()},b=function(o){window.path.add(o.toX,o.toY),d.push(o)},w=function(o){o.forEach(function(o){b(o),d.push(o)})},k=function(e,t,n){for(var a=t.slice(),i=function(o){o&&TB.error(o)};a.length;){var c=a.splice(0,Math.min(a.length,32)),r={type:e,data:JSON.stringify(c)};n&&(r.to=n),o.session.signal(r,i)}},y=function(e,t){o.session&&(p.push(t),m||(m=setTimeout(function(){k(e,p),p=[],m=null},100)))};angular.element(document).on("keyup",function(o){o.ctrlKey&&(90===o.keyCode&&e.undo(),89===o.keyCode&&e.redo())}),angular.element(c).on("mousedown mousemove mouseup mouseout touchstart touchmove touchend touchcancel",function(n){if("mousemove"!==n.type&&"touchmove"!==n.type||r.dragging){n.preventDefault();var a,i=angular.element(c).offset(),p=c.width/t.width(),h=c.height/t.height(),g=n.offsetX||n.originalEvent.pageX-i.left||n.originalEvent.touches[0].pageX-i.left,f=n.offsetY||n.originalEvent.pageY-i.top||n.originalEvent.touches[0].pageY-i.top,m=g*p,v=f*h,w=e.erasing?"pen":"eraser";switch(n.type){case"mousedown":case"touchstart":r.dragging=!0,r.lastX=m,r.lastY=v,window.path&&(window.path.selected=!1),window.path=new paper.Path,path.strokeColor=e.color,path.strokeWidth=e.lineWidth,path.strokeCap=e.strokeCap,path.strokeJoin=e.strokeJoin,"pen"==w&&(path.blendMode="destination-out"),a=new paper.Point(m,v),path.moveTo(a);break;case"mousemove":case"touchmove":if(g=n.offsetX||n.originalEvent.pageX-i.left||n.originalEvent.touches[0].pageX-i.left,f=n.offsetY||n.originalEvent.pageY-i.top||n.originalEvent.touches[0].pageY-i.top,m=g*p,v=f*h,r.dragging){var k={id:o.session&&o.session.connection&&o.session.connection.connectionId,fromX:r.lastX,fromY:r.lastY,toX:m,toY:v,mode:w,color:e.color,lineWidth:e.lineWidth,show:1};s++,l=[],b(k),d.push(k),r.lastX=m,r.lastY=v,y("otWhiteboard_update",k)}break;case"touchcancel":case"mouseup":case"touchend":case"mouseout":window.path.smooth(),r.dragging=!1,s&&(a=d.length,u.push(window.path),s=0)}}}),o.session&&o.session.on({"signal:otWhiteboard_update":function(t){t.from.connectionId!==o.session.connection.connectionId&&(w(JSON.parse(t.data)),e.$emit("otWhiteboardUpdate"))},"signal:otWhiteboard_undo":function(t){t.from.connectionId!==o.session.connection.connectionId&&(JSON.parse(t.data).forEach(function(o){f(o)}),e.$emit("otWhiteboardUpdate"))},"signal:otWhiteboard_redo":function(t){t.from.connectionId!==o.session.connection.connectionId&&(JSON.parse(t.data).forEach(function(o){v(o)}),e.$emit("otWhiteboardUpdate"))},"signal:otWhiteboard_history":function(o){i&&i!==o.from.connectionId||(i=o.from.connectionId,w(JSON.parse(o.data)),e.$emit("otWhiteboardUpdate"))},"signal:otWhiteboard_clear":function(e){e.from.connectionId!==o.session.connection.connectionId&&g()},connectionCreated:function(e){d.length>0&&e.connection.connectionId!==o.session.connection.connectionId&&k("otWhiteboard_history",d,e.connection)}})}}}]);<|endoftext|>