<commit_before>/////
// Calculate node radius based on size of area and number of nodes
window.calculateAvatarRadius = function(width, height, opinions) {
  var ratio_filled = .3, r

  r = Math.sqrt(width * height / opinions.length * ratio_filled)/2
  r = Math.min(r, width/2, height/2)

  // Travis: what's the purpose of this?
  if (opinions.length > 10) {
    // Now round r up until it fits perfectly within height
    var times_fit = height / (2*r)
    r = (height / (Math.floor(times_fit))) / 2 - .001
  }

  return r
}

//////
// Uses a d3-based physics simulation to calculate a reasonable layout
// of avatars within a given area.

window.positionAvatars = function(width, height, opinions) {
  width = width || 400
  height = height || 70

  var opinions = opinions.slice()
                   .sort(function (a,b) {return a.stance-b.stance}),
      n = opinions.length,
      r = calculateAvatarRadius(width, height, opinions),
      x_force_mult = 2,
      y_force_mult = height <= 100 ? 2 : 6,
      nodes, force, ticks = 0

  // Initialize positions of each node
  nodes = d3.range(opinions.length).map(function(i) {
    var radius = opinions[i].radius || r

    if(parseFloat(opinions[i].icon.style.width) != radius * 2)
      opinions[i].icon.style.width = opinions[i].icon.style.height = radius*2 + 'px'

    opinions[i].x_target = (opinions[i].stance + 1)/2 * width

    // Travis: I'm finding that different initial conditions work
    // better at different scales.
    //   - Give large numbers of avatars some good initial spacing
    //   - Small numbers of avatars can be more precisely placed for quick
    //     convergence with little churn
    x = opinions.length > 10 ? radius + (width- 2 * radius) * (i / n) : opinions[i].x_target
    y = opinions.length == 1 ? height - radius : radius + Math.random() * (height - 2 * radius)

    return {
      index: i,
      radius: radius,
      x: x,
      y: y
    }
  })

  // see https://github.com/mbostock/d3/wiki/Force-Layout for docs
  force = d3.layout.force()
    .nodes(nodes)
    .on("tick", tick)
    .on('end', end)
    .gravity(0)
    .charge(0)
    .chargeDistance(0)
    .start()

  // Called after the simulation stops
  function end() {
    total_energy = calculate_global_energy()
    console.log('Simulation complete after ' + ticks + ' ticks. ' +
                'Energy of system could be reduced by at most ' + total_energy + ' by global sort.')
  }

  // One iteration of the simulation
  function tick(e) {

    var q, i = 0, some_node_moved = false

    //////
    // Repel colliding nodes
    // A quadtree helps efficiently detect collisions
    q = d3.geom.quadtree(nodes)
    while (++i < n)
      q.visit(collide(nodes[i]))

    //////
    // Apply standard forces
    nodes.forEach(function(o, i) {

      // Push node toward its desired x-position
      o.x += e.alpha * (x_force_mult * width  * .001) * (opinions[o.index].x_target - o.x)

      // Push node downwards
      o.y += e.alpha * y_force_mult

      // Ensure node is still within the bounding box
      o.x = Math.max(o.radius, Math.min(width  - o.radius, o.x))
      o.y = Math.max(o.radius, Math.min(height - o.radius, o.y))

      // Re-position dom element...if it's moved enough
      if ( !opinions[i].icon.style.left || Math.abs( parseFloat(opinions[i].icon.style.left) - (o.x - o.radius)) > .1 ){
        opinions[i].icon.style.left = o.x - o.radius + 'px'
        some_node_moved = true
      }

      if ( !opinions[i].icon.style.top || Math.abs( parseFloat(opinions[i].icon.style.top) - (o.y - o.radius)) > .1 ) {
        opinions[i].icon.style.top  = o.y - o.radius + 'px'
        some_node_moved = true
      }
    })

    ticks += 1

    // Complete the simulation if we've reached a steady state
    if (!some_node_moved) force.stop()

  }

  function collide(node) {

    return function(quad, x1, y1, x2, y2) {
      if (quad.leaf && quad.point && quad.point !== node) {
        var dx = node.x - quad.point.x,
            dy = node.y - quad.point.y,
            dist = Math.sqrt(dx * dx + dy * dy),
            combined_r = node.radius + quad.point.radius

        // Transpose two points in the same neighborhood if it would reduce energy of system
        // 10 is not a principled threshold.
        if ( energy_reduced_by_swap(node, quad.point) > 10) {
          swap_position(node, quad.point)
          dx *= -1; dy *= -1
        }

        // repel both points equally in opposite directions if they overlap
        if (dist < combined_r) {
          var separate_by, offset_x, offset_y
          separate_by = dist == 0 ? 1 : ( dist - combined_r ) / dist
          offset_x = dx * separate_by * .6,
          offset_y = dy * separate_by * .6

          node.x -= offset_x
          node.y -= offset_y
          quad.point.x += offset_x
          quad.point.y += offset_y
        }
      }

      // Visit subregions if we could possibly have a collision there
      // Travis: I understand what the 16 *does* but not the significance
      //         of the particular value. Does 16 make sense for all
      //         avatar sizes and sizes of the bounding box?
      var neighborhood_radius = node.radius + 16,
          nx1 = node.x - neighborhood_radius,
          nx2 = node.x + neighborhood_radius,
          ny1 = node.y - neighborhood_radius,
          ny2 = node.y + neighborhood_radius

      return x1 > nx2
          || x2 < nx1
          || y1 > ny2
          || y2 < ny1
    }
  }

  // Check if system energy would be reduced if two nodes' positions would
  // be swapped. We square the difference in order to favor large differences
  // for one vs small differences for the pair.
  function energy_reduced_by_swap(p1, p2) {
    var p1_jealousy = Math.pow(p1.x - opinions[p1.index].x_target, 2) -
                      Math.pow(p2.x - opinions[p1.index].x_target, 2),
        p2_jealousy = Math.pow(p2.x - opinions[p2.index].x_target, 2) -
                      Math.pow(p1.x - opinions[p2.index].x_target, 2)

    return p1_jealousy + p2_jealousy
  }

  // Swaps the positions of two nodes
  var position_props = ['x', 'y', 'px', 'py']
  function swap_position(p1, p2) {
    var swap
    for(var i=0; i < position_props.length; i++){
      swap = p1[position_props[i]]
      p1[position_props[i]] = p2[position_props[i]]
      p2[position_props[i]] = swap
    }
  }

  ///////////////////////////////////////////////////////
  // The rest of these methods are only used for testing
  ///////////////////////////////////////////////////////

  // Calculates the reduction in global energy that a sort would have,
  // where global energy is the sum across all nodes of the square of their
  // distance from desired x position. We square the difference in order
  // to favor large differences for individuals over small differences for
  // many.
  function calculate_global_energy() {
    var energy_unsorted = 0,
        energy_sorted = 0,
        sorted = global_sort(false)

    for (var i = 0; i < nodes.length; i++){
      energy_sorted   += Math.pow(sorted[i].x - opinions[sorted[i].index].x_target, 2)
      energy_unsorted += Math.pow( nodes[i].x - opinions[nodes[i].index].x_target , 2)
    }

    return Math.sqrt(energy_unsorted) - Math.sqrt(energy_sorted)
  }

  //////
  // global_sort
  //
  // Given a set of simulated face positions, reassigns avatars to the positions based on
  // stance to enforce a global ordering.
  // This method is visually jarring, so using it to sort nodes in place should be
  // used as little as possible.
  function global_sort(sort_in_place) {
    if (sort_in_place === undefined) sort_in_place = true

    // Create one node list sorted by x position
    x_sorted_nodes = nodes.slice()
                  .sort(function (a,b) {return a.x-b.x})
    // ... and another sorted by desired x position
    desired_x_sorted_nodes = nodes.slice()
                  .sort(function (a,b) {return opinions[a.index].x_target - opinions[b.index].x_target})

    // Create a new dummy set of nodes optimally arranged
    new_nodes = []
    for (var i = 0; i < nodes.length; i++){
      new_nodes.push({
        // assign the avatar...
        index: desired_x_sorted_nodes[i].index,
        radius: desired_x_sorted_nodes[i].radius,
        weight: desired_x_sorted_nodes[i].weight,
        // ...to a good position
        x: x_sorted_nodes[i].x,
        y: x_sorted_nodes[i].y,
        px: x_sorted_nodes[i].px,
        py: x_sorted_nodes[i].py
      })
    }

    // Walk through nodes and reassign the faces given
    // the optimal assignments discovered earlier. We
    // can't assign nodes=new_nodes because the layout
    // depends on nodes pointing to the same object.
    if (sort_in_place){
      var props = ['index', 'radius', 'x', 'y', 'px', 'py', 'weight']
      for (var i = 0; i < nodes.length; i++)
        for (var j = 0; j < props.length; j++)
          nodes[i][props[j]] = new_nodes[i][props[j]]
    }
    return new_nodes
  }

}

<commit_msg>.<commit_after>/////
// Calculate node radius based on size of area and number of nodes
window.calculateAvatarRadius = function(width, height, opinions) {
  var ratio_filled = .3, r

  r = Math.sqrt(width * height / opinions.length * ratio_filled)/2
  r = Math.min(r, width/2, height/2)

  // Travis: what's the purpose of this?
  if (opinions.length > 10) {
    // Now round r up until it fits perfectly within height
    var times_fit = height / (2*r)
    r = (height / (Math.floor(times_fit))) / 2 - .001
  }

  return r
}

//////
// Uses a d3-based physics simulation to calculate a reasonable layout
// of avatars within a given area.

window.positionAvatars = function(width, height, opinions) {
  width = width || 400
  height = height || 70

  var opinions = opinions.slice()
                   .sort(function (a,b) {return a.stance-b.stance}),
      n = opinions.length,
      r = calculateAvatarRadius(width, height, opinions),
      x_force_mult = 2,
      y_force_mult = height <= 100 ? 2 : 6,
      nodes, force, ticks = 0

  // Initialize positions of each node
  nodes = d3.range(opinions.length).map(function(i) {
    var radius = opinions[i].radius || r

    if(parseFloat(opinions[i].icon.style.width) != radius * 2)
      opinions[i].icon.style.width = opinions[i].icon.style.height = radius*2 + 'px'

    opinions[i].x_target = (opinions[i].stance + 1)/2 * width

    // Travis: I'm finding that different initial conditions work
    // better at different scales.
    //   - Give large numbers of avatars some good initial spacing
    //   - Small numbers of avatars can be more precisely placed for quick
    //     convergence with little churn
    x = opinions.length > 10 ? radius + (width- 2 * radius) * (i / n) : opinions[i].x_target
    y = opinions.length == 1 ? height - radius : radius + Math.random() * (height - 2 * radius)

    return {
      index: i,
      radius: radius,
      x: x,
      y: y
    }
  })

  // see https://github.com/mbostock/d3/wiki/Force-Layout for docs
  force = d3.layout.force()
    .nodes(nodes)
    .on("tick", tick)
    .on('end', end)
    .gravity(0)
    .charge(0)
    .chargeDistance(0)
    .start()

  // Called after the simulation stops
  function end() {
    total_energy = calculate_global_energy()
    console.log('Simulation complete after ' + ticks + ' ticks. ' +
                'Energy of system could be reduced by at most ' + total_energy + ' by global sort.')
  }

  // One iteration of the simulation
  function tick(e) {

    var q, i = 0, some_node_moved = false

    //////
    // Repel colliding nodes
    // A quadtree helps efficiently detect collisions
    q = d3.geom.quadtree(nodes)
    while (++i < n)
      q.visit(collide(nodes[i]))

    //////
    // Apply standard forces
    nodes.forEach(function(o, i) {

      // Push node toward its desired x-position
      o.x += e.alpha * (x_force_mult * width  * .001) * (opinions[o.index].x_target - o.x)

      // Push node downwards
      o.y += e.alpha * y_force_mult

      // Ensure node is still within the bounding box
      o.x = Math.max(o.radius, Math.min(width  - o.radius, o.x))
      o.y = Math.max(o.radius, Math.min(height - o.radius, o.y))

      // Re-position dom element...if it's moved enough
      if ( !opinions[i].icon.style.left || Math.abs( parseFloat(opinions[i].icon.style.left) - (o.x - o.radius)) > .1 ){
        opinions[i].icon.style.left = o.x - o.radius + 'px'
        some_node_moved = true
      }

      if ( !opinions[i].icon.style.top || Math.abs( parseFloat(opinions[i].icon.style.top) - (o.y - o.radius)) > .1 ) {
        opinions[i].icon.style.top  = o.y - o.radius + 'px'
        some_node_moved = true
      }
    })

    ticks += 1

    // Complete the simulation if we've reached a steady state
    if (!some_node_moved) force.stop()

  }

  function collide(node) {

    return function(quad, x1, y1, x2, y2) {
      if (quad.leaf && quad.point && quad.point !== node) {
        var dx = node.x - quad.point.x,
            dy = node.y - quad.point.y,
            dist = Math.sqrt(dx * dx + dy * dy),
            combined_r = node.radius + quad.point.radius

        // Transpose two points in the same neighborhood if it would reduce energy of system
        // 10 is not a principled threshold.
        if ( energy_reduced_by_swap(node, quad.point) > 10) {
          swap_position(node, quad.point)
          dx *= -1; dy *= -1
        }

        // repel both points equally in opposite directions if they overlap
        if (dist < combined_r) {
          var separate_by, offset_x, offset_y
          separate_by = dist == 0 ? 1 : ( dist - combined_r ) / dist
          offset_x = dx * separate_by * .6,
          offset_y = dy * separate_by * .6

          node.x -= offset_x
          node.y -= offset_y
          quad.point.x += offset_x
          quad.point.y += offset_y
        }
      }

      // Visit subregions if we could possibly have a collision there
      // Travis: I understand what the 16 *does* but not the significance
      //         of the particular value. Does 16 make sense for all
      //         avatar sizes and sizes of the bounding box?
      var neighborhood_radius = node.radius + 16,
          nx1 = node.x - neighborhood_radius,
          nx2 = node.x + neighborhood_radius,
          ny1 = node.y - neighborhood_radius,
          ny2 = node.y + neighborhood_radius

      return x1 > nx2
          || x2 < nx1
          || y1 > ny2
          || y2 < ny1
    }
  }

  // Check if system energy would be reduced if two nodes' positions would
  // be swapped. We square the difference in order to favor large differences
  // for one vs small differences for the pair.
  function energy_reduced_by_swap(p1, p2) {
    // how much does each point covet the other's location, over their own?
    var p1_jealousy = Math.pow(p1.x - opinions[p1.index].x_target, 2) -
                      Math.pow(p2.x - opinions[p1.index].x_target, 2),
        p2_jealousy = Math.pow(p2.x - opinions[p2.index].x_target, 2) -
                      Math.pow(p1.x - opinions[p2.index].x_target, 2)

    return p1_jealousy + p2_jealousy
  }

  // Swaps the positions of two nodes
  var position_props = ['x', 'y', 'px', 'py']
  function swap_position(p1, p2) {
    var swap
    for(var i=0; i < position_props.length; i++){
      swap = p1[position_props[i]]
      p1[position_props[i]] = p2[position_props[i]]
      p2[position_props[i]] = swap
    }
  }

  ///////////////////////////////////////////////////////
  // The rest of these methods are only used for testing
  ///////////////////////////////////////////////////////

  // Calculates the reduction in global energy that a sort would have,
  // where global energy is the sum across all nodes of the square of their
  // distance from desired x position. We square the difference in order
  // to favor large differences for individuals over small differences for
  // many.
  function calculate_global_energy() {
    var energy_unsorted = 0,
        energy_sorted = 0,
        sorted = global_sort(false)

    for (var i = 0; i < nodes.length; i++){
      energy_sorted   += Math.pow(sorted[i].x - opinions[sorted[i].index].x_target, 2)
      energy_unsorted += Math.pow( nodes[i].x - opinions[nodes[i].index].x_target , 2)
    }

    return Math.sqrt(energy_unsorted) - Math.sqrt(energy_sorted)
  }

  //////
  // global_sort
  //
  // Given a set of simulated face positions, reassigns avatars to the positions based on
  // stance to enforce a global ordering.
  // This method is visually jarring, so using it to sort nodes in place should be
  // used as little as possible.
  function global_sort(sort_in_place) {
    if (sort_in_place === undefined) sort_in_place = true

    // Create one node list sorted by x position
    x_sorted_nodes = nodes.slice()
                  .sort(function (a,b) {return a.x-b.x})
    // ... and another sorted by desired x position
    desired_x_sorted_nodes = nodes.slice()
                  .sort(function (a,b) {return opinions[a.index].x_target - opinions[b.index].x_target})

    // Create a new dummy set of nodes optimally arranged
    new_nodes = []
    for (var i = 0; i < nodes.length; i++){
      new_nodes.push({
        // assign the avatar...
        index: desired_x_sorted_nodes[i].index,
        radius: desired_x_sorted_nodes[i].radius,
        weight: desired_x_sorted_nodes[i].weight,
        // ...to a good position
        x: x_sorted_nodes[i].x,
        y: x_sorted_nodes[i].y,
        px: x_sorted_nodes[i].px,
        py: x_sorted_nodes[i].py
      })
    }

    // Walk through nodes and reassign the faces given
    // the optimal assignments discovered earlier. We
    // can't assign nodes=new_nodes because the layout
    // depends on nodes pointing to the same object.
    if (sort_in_place){
      var props = ['index', 'radius', 'x', 'y', 'px', 'py', 'weight']
      for (var i = 0; i < nodes.length; i++)
        for (var j = 0; j < props.length; j++)
          nodes[i][props[j]] = new_nodes[i][props[j]]
    }
    return new_nodes
  }

}

<|endoftext|>


<commit_before>var test = require('tape');

// this test will ensure we are implementing a particular API method
// If you had a new method, it will first fail, you will have to write a test
// for it
test('AlgoliaSearch client API spec', function(t) {
  t.plan(1);

  var filter = require('lodash-compat/collection/filter');
  var functions = require('lodash-compat/object/functions');

  var algoliasearch = require('../../../../');
  var onlyPublicProperties = require('../../../utils/only-public-properties');

  var client = algoliasearch('test', 'properties');

  var actualProperties = filter(functions(client), onlyPublicProperties).sort();

  var expectedProperties = [
    'Index',
    'addQueryInBatch',
    'addUserKey',
    'addUserKeyWithValidity',
    'updateUserKey',
    'clearCache',
    'copyIndex',
    'deleteIndex',
    'deleteUserKey',
    'getLogs',
    'getUserKeyACL',
    'initIndex',
    'listIndexes',
    'listUserKeys',
    'moveIndex',
    'search',
    'sendQueriesBatch',
    'setExtraHeader',
    'setRequestTimeout',
    'setSecurityTags',
    'setUserToken',
    'startQueriesBatch'];

  // Node.js only methods, not added conditionnaly because
  // they are still declared in other environments,
  // but they will throw
  expectedProperties = expectedProperties.concat([
    'destroy',
    'disableRateLimitForward',
    'disableSecuredAPIKey',
    'enableRateLimitForward',
    'useSecuredAPIKey',
    'generateSecuredApiKey'
  ]);

  expectedProperties = expectedProperties.sort();

  t.deepEqual(actualProperties, expectedProperties, 'We only implement what is tested');
});
<commit_msg>fix tests<commit_after>var test = require('tape');

// this test will ensure we are implementing a particular API method
// If you had a new method, it will first fail, you will have to write a test
// for it
test('AlgoliaSearch client API spec', function(t) {
  t.plan(1);

  var filter = require('lodash-compat/collection/filter');
  var functions = require('lodash-compat/object/functions');

  var algoliasearch = require('../../../../');
  var onlyPublicProperties = require('../../../utils/only-public-properties');

  var client = algoliasearch('test', 'properties');

  var actualProperties = filter(functions(client), onlyPublicProperties).sort();

  var expectedProperties = [
    'Index',
    'addQueryInBatch',
    'addUserKey',
    'addUserKeyWithValidity',
    'batch',
    'updateUserKey',
    'clearCache',
    'copyIndex',
    'deleteIndex',
    'deleteUserKey',
    'getLogs',
    'getUserKeyACL',
    'initIndex',
    'listIndexes',
    'listUserKeys',
    'moveIndex',
    'search',
    'sendQueriesBatch',
    'setExtraHeader',
    'setRequestTimeout',
    'setSecurityTags',
    'setUserToken',
    'startQueriesBatch'];

  // Node.js only methods, not added conditionnaly because
  // they are still declared in other environments,
  // but they will throw
  expectedProperties = expectedProperties.concat([
    'destroy',
    'disableRateLimitForward',
    'disableSecuredAPIKey',
    'enableRateLimitForward',
    'useSecuredAPIKey',
    'generateSecuredApiKey'
  ]);

  expectedProperties = expectedProperties.sort();

  t.deepEqual(actualProperties, expectedProperties, 'We only implement what is tested');
});
<|endoftext|>


<commit_before>// @flow
import React, { createContext, useState, type Node } from "react";

import type { DatasetFilteringMode } from "dashboard/dataset_view";
import type { APIMaybeUnimportedDataset, APIDatasetId } from "types/api_flow_types";
import { getDatastores, triggerDatasetCheck, getDatasets, getDataset } from "admin/admin_rest_api";
import { handleGenericError } from "libs/error_handling";
import UserLocalStorage from "libs/user_local_storage";
import * as Utils from "libs/utils";

type Options = {
  datasetFilteringMode?: DatasetFilteringMode,
  applyUpdatePredicate?: (datasets: Array<APIMaybeUnimportedDataset>) => boolean,
  isCalledFromCheckDatasets?: boolean,
};

type Context = {
  datasets: Array<APIMaybeUnimportedDataset>,
  isLoading: boolean,
  checkDatasets: () => Promise<void>,
  fetchDatasets: (options?: Options) => Promise<void>,
  updateDataset: (
    datasetId: APIDatasetId,
    datasetsToUpdate?: Array<APIMaybeUnimportedDataset>,
  ) => Promise<void>,
};

const oldWkDatasetsCacheKey = "wk.datasets";
const wkDatasetsCacheKey = "wk.datasets-v2";
export const datasetCache = {
  set(datasets: APIMaybeUnimportedDataset[]): void {
    UserLocalStorage.setItem(wkDatasetsCacheKey, JSON.stringify(datasets));
  },
  get(): APIMaybeUnimportedDataset[] {
    return Utils.parseAsMaybe(UserLocalStorage.getItem(wkDatasetsCacheKey)).getOrElse([]);
  },
  clear(): void {
    UserLocalStorage.removeItem(wkDatasetsCacheKey);
  },
};

export const DatasetCacheContext = createContext<Context>({
  datasets: [],
  isLoading: false,
  fetchDatasets: async () => {},
  checkDatasets: async () => {},
  updateDataset: async () => {},
});

export default function DatasetCacheProvider({ children }: { children: Node }) {
  const [datasets, setDatasets] = useState(datasetCache.get());
  const [isLoading, setIsLoading] = useState(false);
  async function fetchDatasets(options?: Options = {}): Promise<void> {
    const isCalledFromCheckDatasets = options.isCalledFromCheckDatasets || false;
    const datasetFilteringMode = options.datasetFilteringMode || "onlyShowReported";
    const applyUpdatePredicate = options.applyUpdatePredicate || (_datasets => true);

    if (isLoading && !isCalledFromCheckDatasets) return;

    try {
      setIsLoading(true);
      const mapFilterModeToUnreportedParameter = {
        showAllDatasets: null,
        onlyShowReported: false,
        onlyShowUnreported: true,
      };
      const newDatasets = await getDatasets(
        mapFilterModeToUnreportedParameter[datasetFilteringMode],
      );
      // Hotfix for https://github.com/scalableminds/webknossos/issues/5038
      // The deprecated cache key can still block a considerable amount of data in the localStorage (around 2 MB
      // for some wk instances while the localStorage quota is at 5 MB for Chrome).
      UserLocalStorage.removeItem(oldWkDatasetsCacheKey);
      UserLocalStorage.removeItem(oldWkDatasetsCacheKey, false);
      datasetCache.set(newDatasets);
      if (applyUpdatePredicate(newDatasets)) {
        setDatasets(newDatasets);
      }
    } catch (error) {
      handleGenericError(error);
    } finally {
      setIsLoading(false);
    }
  }
  async function checkDatasets() {
    if (isLoading) return;
    try {
      setIsLoading(true);
      const datastores = await getDatastores();
      await Promise.all(
        datastores
          .filter(ds => !ds.isForeign)
          .map(datastore =>
            // Catch potentially failing triggers, since these should not
            // block the subsequent fetch of datasets. Otherwise, one offline
            // datastore will stop the refresh for all datastores.
            triggerDatasetCheck(datastore.url).catch(() => {}),
          ),
      );
      await fetchDatasets({ isCalledFromCheckDatasets: true });
    } catch (error) {
      handleGenericError(error);
    } finally {
      setIsLoading(false);
    }
  }

  async function updateDataset(
    datasetId: APIDatasetId,
    datasetsToUpdate?: Array<APIMaybeUnimportedDataset>,
  ) {
    if (isLoading) return;
    try {
      setIsLoading(true);

      const updatedDataset = await getDataset(datasetId);

      if (datasetsToUpdate) {
        const newDatasets: Array<APIMaybeUnimportedDataset> = datasetsToUpdate.map(dataset => {
          if (
            dataset.name === datasetId.name &&
            dataset.owningOrganization === datasetId.owningOrganization
          ) {
            const { lastUsedByUser } = dataset;
            // $FlowFixMe[incompatible-type]
            return {
              ...updatedDataset,
              lastUsedByUser,
            };
          } else {
            return dataset;
          }
        });
        setDatasets(newDatasets);
      }

      const newInternalDatasets = datasets.map(dataset => {
        if (
          dataset.name === datasetId.name &&
          dataset.owningOrganization === datasetId.owningOrganization
        ) {
          return updatedDataset;
        } else {
          return dataset;
        }
      });
      datasetCache.set(newInternalDatasets);
      if (!datasetsToUpdate) setDatasets(newInternalDatasets);
    } catch (error) {
      handleGenericError(error);
    } finally {
      setIsLoading(false);
    }
  }

  return (
    <DatasetCacheContext.Provider
      value={{ datasets, isLoading, checkDatasets, fetchDatasets, updateDataset }}
    >
      {children}
    </DatasetCacheContext.Provider>
  );
}
<commit_msg>also clear new datasets cache key for global localStorage key (#5052)<commit_after>// @flow
import React, { createContext, useState, type Node } from "react";

import type { DatasetFilteringMode } from "dashboard/dataset_view";
import type { APIMaybeUnimportedDataset, APIDatasetId } from "types/api_flow_types";
import { getDatastores, triggerDatasetCheck, getDatasets, getDataset } from "admin/admin_rest_api";
import { handleGenericError } from "libs/error_handling";
import UserLocalStorage from "libs/user_local_storage";
import * as Utils from "libs/utils";

type Options = {
  datasetFilteringMode?: DatasetFilteringMode,
  applyUpdatePredicate?: (datasets: Array<APIMaybeUnimportedDataset>) => boolean,
  isCalledFromCheckDatasets?: boolean,
};

type Context = {
  datasets: Array<APIMaybeUnimportedDataset>,
  isLoading: boolean,
  checkDatasets: () => Promise<void>,
  fetchDatasets: (options?: Options) => Promise<void>,
  updateDataset: (
    datasetId: APIDatasetId,
    datasetsToUpdate?: Array<APIMaybeUnimportedDataset>,
  ) => Promise<void>,
};

const oldWkDatasetsCacheKey = "wk.datasets";
const wkDatasetsCacheKey = "wk.datasets-v2";
export const datasetCache = {
  set(datasets: APIMaybeUnimportedDataset[]): void {
    UserLocalStorage.setItem(wkDatasetsCacheKey, JSON.stringify(datasets));
  },
  get(): APIMaybeUnimportedDataset[] {
    return Utils.parseAsMaybe(UserLocalStorage.getItem(wkDatasetsCacheKey)).getOrElse([]);
  },
  clear(): void {
    UserLocalStorage.removeItem(wkDatasetsCacheKey);
  },
};

export const DatasetCacheContext = createContext<Context>({
  datasets: [],
  isLoading: false,
  fetchDatasets: async () => {},
  checkDatasets: async () => {},
  updateDataset: async () => {},
});

export default function DatasetCacheProvider({ children }: { children: Node }) {
  const [datasets, setDatasets] = useState(datasetCache.get());
  const [isLoading, setIsLoading] = useState(false);
  async function fetchDatasets(options?: Options = {}): Promise<void> {
    const isCalledFromCheckDatasets = options.isCalledFromCheckDatasets || false;
    const datasetFilteringMode = options.datasetFilteringMode || "onlyShowReported";
    const applyUpdatePredicate = options.applyUpdatePredicate || (_datasets => true);

    if (isLoading && !isCalledFromCheckDatasets) return;

    try {
      setIsLoading(true);
      const mapFilterModeToUnreportedParameter = {
        showAllDatasets: null,
        onlyShowReported: false,
        onlyShowUnreported: true,
      };
      const newDatasets = await getDatasets(
        mapFilterModeToUnreportedParameter[datasetFilteringMode],
      );
      // Hotfix for https://github.com/scalableminds/webknossos/issues/5038
      // The deprecated cache key can still block a considerable amount of data in the localStorage (around 2 MB
      // for some wk instances while the localStorage quota is at 5 MB for Chrome).
      UserLocalStorage.removeItem(oldWkDatasetsCacheKey);
      UserLocalStorage.removeItem(oldWkDatasetsCacheKey, false);
      // Previously, the datasets key was used globally. Now, it's tied to the current organization,
      // which is why we can clear the global key (isOrganizationSpecific==false).
      UserLocalStorage.removeItem(wkDatasetsCacheKey, false);
      datasetCache.set(newDatasets);
      if (applyUpdatePredicate(newDatasets)) {
        setDatasets(newDatasets);
      }
    } catch (error) {
      handleGenericError(error);
    } finally {
      setIsLoading(false);
    }
  }
  async function checkDatasets() {
    if (isLoading) return;
    try {
      setIsLoading(true);
      const datastores = await getDatastores();
      await Promise.all(
        datastores
          .filter(ds => !ds.isForeign)
          .map(datastore =>
            // Catch potentially failing triggers, since these should not
            // block the subsequent fetch of datasets. Otherwise, one offline
            // datastore will stop the refresh for all datastores.
            triggerDatasetCheck(datastore.url).catch(() => {}),
          ),
      );
      await fetchDatasets({ isCalledFromCheckDatasets: true });
    } catch (error) {
      handleGenericError(error);
    } finally {
      setIsLoading(false);
    }
  }

  async function updateDataset(
    datasetId: APIDatasetId,
    datasetsToUpdate?: Array<APIMaybeUnimportedDataset>,
  ) {
    if (isLoading) return;
    try {
      setIsLoading(true);

      const updatedDataset = await getDataset(datasetId);

      if (datasetsToUpdate) {
        const newDatasets: Array<APIMaybeUnimportedDataset> = datasetsToUpdate.map(dataset => {
          if (
            dataset.name === datasetId.name &&
            dataset.owningOrganization === datasetId.owningOrganization
          ) {
            const { lastUsedByUser } = dataset;
            // $FlowFixMe[incompatible-type]
            return {
              ...updatedDataset,
              lastUsedByUser,
            };
          } else {
            return dataset;
          }
        });
        setDatasets(newDatasets);
      }

      const newInternalDatasets = datasets.map(dataset => {
        if (
          dataset.name === datasetId.name &&
          dataset.owningOrganization === datasetId.owningOrganization
        ) {
          return updatedDataset;
        } else {
          return dataset;
        }
      });
      datasetCache.set(newInternalDatasets);
      if (!datasetsToUpdate) setDatasets(newInternalDatasets);
    } catch (error) {
      handleGenericError(error);
    } finally {
      setIsLoading(false);
    }
  }

  return (
    <DatasetCacheContext.Provider
      value={{ datasets, isLoading, checkDatasets, fetchDatasets, updateDataset }}
    >
      {children}
    </DatasetCacheContext.Provider>
  );
}
<|endoftext|>


<commit_before>(function($){

  $.PMX.QueryField = function(el) {
    var base = this;

    base.$el = $(el);
    base.previousTerm = '';

    base.bindEvents = function() {
      base.$el.on('keyup', base.handleChange);
    };

    base.handleChange = function() {
      if (base.getTerm().length > 2 && base.getTerm() !== base.previousTerm) {
        base.changeCallback.call(base, base.getTerm());
        base.previousTerm = base.getTerm();
      }
    };

    base.onChange = function(callback) {
      base.changeCallback = callback;
    };

    base.getTerm = function() {
      return base.$el.val();
    };
  };

  $.PMX.SearchResults = function(url, limit) {
    var base = this;

    base.url = url;
    base.limit = limit;
    base.templatesXhr = null;
    base.localImagesXhr = null;
    base.remoteImagesXhr = null;

    base.fetch = function(term) {
      if (base.templatesXhr) { base.templatesXhr.abort(); }
      if (base.localImagesXhr) { base.localImagesXhr.abort(); }
      if (base.remoteImagesXhr) { base.remoteImagesXhr.abort(); }

      base.templatesXhr = base.fetchForType(term, 'template');
      base.localImagesXhr = base.fetchForType(term, 'local_image');
      base.remoteImagesXhr = base.fetchForType(term, 'remote_image');
    };

    base.templates = function(callback) {
      base.templatesXhr.done(function(response, status) {
        callback.call(this, response.templates);
      });
    };

    base.localImages = function(callback) {
      base.localImagesXhr.done(function(response, status) {
        callback.call(this, response.local_images);
      });
    };

    base.remoteImages = function(callback) {
      base.remoteImagesXhr.done(function(response, status) {
        callback.call(this, response.remote_images);
      });
    };

    base.fetchForType = function(term, type) {
      return $.ajax({
        url: base.url,
        data: {
          'search_result_set[q]': term,
          'search_result_set[type]': type,
          'search_result_set[limit]': base.limit
        }
      });
    };
  };

  $.PMX.FilterableList = function(el, options) {
    var base = this;

    base.$el = $(el);

    base.defaultOptions = {
      $queryField: base.$el.find('input.query-field'),
      queryFormSelector: 'form.search-form',
      $queryForm: base.$el.find('form.search-form'),
      limit: 40,
      $localImageResults: base.$el.find('.local-image-results'),
      $remoteImageResults: base.$el.find('.remote-image-results'),
      $templateResults: base.$el.find('.template-results'),
      $resultHeadings: base.$el.find('.search-title'),
      remoteImageResultTemplate: Handlebars.compile($('#remote_image_result_template').html()),
      localImageResultTemplate: Handlebars.compile($('#local_image_result_template').html()),
      templateResultTemplate: Handlebars.compile($('#template_result_template').html()),
      loadingTemplate: Handlebars.compile($('#loading_row_template').html()),
      noResultsTemplate: Handlebars.compile($('#no_results_row_template').html()),
      trackingAction: 'not-given',
      tagDropdownSelector: 'select.image-tag-select',
      chosenDropdownSelector: '.chosen-container'
    };

    base.init = function(){
      base.options = $.extend({}, base.defaultOptions, options);
      base.queryField = new $.PMX.QueryField(base.options.$queryField);
      base.queryField.bindEvents();
      base.searchResults = new $.PMX.SearchResults(base.resultsEndpoint(), base.options.limit);

      base.bindEvents();
    };

    base.bindEvents = function() {
      base.queryField.onChange(base.fetchResults);
      base.$el.on('submit', base.options.queryFormSelector, base.handleSubmit);
      base.$el.on('click', base.options.chosenDropdownSelector, base.fetchTags);
    };

    base.handleSubmit = function(e) {
      e.preventDefault();
      base.fetchResults(base.queryField.getTerm());
    };

    base.handleQueryChange = function(e) {
      base.fetchResults();
    };

    base.fetchResults = function(term) {
      base.displayLoadingIndicators();
      base.options.$resultHeadings.css('display', 'block');
      PMX.Tracker.trackEvent('search', base.options.trackingAction, term);

      base.searchResults.fetch(term);
      base.searchResults.templates(base.loadTemplateResults);
      base.searchResults.localImages(base.loadLocalImageResults);
      base.searchResults.remoteImages(base.loadRemoteImageResults);
    };

    base.loadRemoteImageResults = function(images) {
      var resultsHtml = '';
      $.each(images, function(i, image) {
        resultsHtml += base.options.remoteImageResultTemplate(image);
      });
      base.options.$remoteImageResults.html(resultsHtml);
      base.displayTagDropdown();
    };

    base.loadLocalImageResults = function(images) {
      var resultsHtml = '';
      $.each(images, function(i, image) {
        resultsHtml += base.options.localImageResultTemplate(image);
      });
      base.options.$localImageResults.html(resultsHtml);
      base.displayTagDropdown();
    };

    base.loadTemplateResults = function(templates) {
      var resultsHtml = '';
      if (templates && templates.length) {
        $.each(templates, function(i, template) {
          resultsHtml += base.options.templateResultTemplate(template);
        });
      } else {
        resultsHtml = base.options.noResultsTemplate();
      }
      base.options.$templateResults.html(resultsHtml);
    };

    base.displayTagDropdown = function () {
      $(base.options.tagDropdownSelector).chosen({disable_search: true});
    };

    base.fetchTags = function (e) {
      var $elem = $(e.currentTarget),
          $resultRow = $elem.closest('.search-result-item'),
          $selectBox = $resultRow.find(base.options.tagDropdownSelector),
          loaded = $selectBox.data('loaded'),
          local_image = $resultRow.data('status-label') == 'Local';
      if (!loaded) {
        var tagsXhr = $.get(
          $(base.options.tagDropdownSelector).data('load-tags-endpoint'),
          { 'repo': $resultRow.data('title'), 'local_image': local_image }
        );

        tagsXhr.done(function (response) {
          $selectBox.empty();
          response.forEach(function (tag) {
            $selectBox.append('<option value="' + tag + '">' + tag + '</option>');
          });
          $selectBox.data('loaded', true);
          $selectBox.trigger("chosen:updated");
        });
      }
    };

    base.displayLoadingIndicators = function() {
      var forTemplates = base.options.loadingTemplate({loading_copy: 'Finding Templates'}),
          forLocalImages = base.options.loadingTemplate({loading_copy: 'Finding Images'}),
          forRemoteImages = base.options.loadingTemplate({loading_copy: 'Searching Docker Index'});
      base.options.$templateResults.html(forTemplates);
      base.options.$localImageResults.html(forLocalImages);
      base.options.$remoteImageResults.html(forRemoteImages);
    };

    base.resultsEndpoint = function() {
      return base.options.$queryForm.attr('action') + '.json';
    };
  };

  $.fn.filterableList = function(options){
    return this.each(function(){
      (new $.PMX.FilterableList(this, options)).init();
    });
  };

})(jQuery);
<commit_msg>adding template details modal display to filterable list jquery plugin<commit_after>//= require jquery.ui.dialog

(function($){

  $.PMX.QueryField = function(el) {
    var base = this;

    base.$el = $(el);
    base.previousTerm = '';

    base.bindEvents = function() {
      base.$el.on('keyup', base.handleChange);
    };

    base.handleChange = function() {
      if (base.getTerm().length > 2 && base.getTerm() !== base.previousTerm) {
        base.changeCallback.call(base, base.getTerm());
        base.previousTerm = base.getTerm();
      }
    };

    base.onChange = function(callback) {
      base.changeCallback = callback;
    };

    base.getTerm = function() {
      return base.$el.val();
    };
  };

  $.PMX.SearchResults = function(url, limit) {
    var base = this;

    base.url = url;
    base.limit = limit;
    base.templatesXhr = null;
    base.localImagesXhr = null;
    base.remoteImagesXhr = null;

    base.fetch = function(term) {
      if (base.templatesXhr) { base.templatesXhr.abort(); }
      if (base.localImagesXhr) { base.localImagesXhr.abort(); }
      if (base.remoteImagesXhr) { base.remoteImagesXhr.abort(); }

      base.templatesXhr = base.fetchForType(term, 'template');
      base.localImagesXhr = base.fetchForType(term, 'local_image');
      base.remoteImagesXhr = base.fetchForType(term, 'remote_image');
    };

    base.templates = function(callback) {
      base.templatesXhr.done(function(response, status) {
        callback.call(this, response.templates);
      });
    };

    base.localImages = function(callback) {
      base.localImagesXhr.done(function(response, status) {
        callback.call(this, response.local_images);
      });
    };

    base.remoteImages = function(callback) {
      base.remoteImagesXhr.done(function(response, status) {
        callback.call(this, response.remote_images);
      });
    };

    base.fetchForType = function(term, type) {
      return $.ajax({
        url: base.url,
        data: {
          'search_result_set[q]': term,
          'search_result_set[type]': type,
          'search_result_set[limit]': base.limit
        }
      });
    };
  };

  $.PMX.TemplateDetailsDialog = function(el, options) {
    var base = this;

    base.$el = $(el);
    base.xhr = null;

    base.defaultOptions = {
      $modalContents: $('#template-details-dialog'),
      $titlebarCloseButton: $('button.ui-dialog-titlebar-close')
    };

    base.init = function() {
      base.options = $.extend({}, base.defaultOptions, options);
      base.initiateDialog();
    };

    base.initiateDialog = function () {
      base.defaultOptions.$modalContents.dialog({
        dialogClass: 'template-details-dialog',
        autoOpen: false,
        modal: true,
        resizable: false,
        draggable: true,
        width: 860,
        position: ["top", 50],
        title: 'Template Details',
        close: base.handleClose,
        open: base.fetchTemplateDetails,
        buttons: [
          {
            text: "Dismiss",
            class: 'button-secondary',
            click: base.handleClose
          }
        ]
      });
    };

    base.handleClose = function () {
      base.defaultOptions.$modalContents.dialog("close");
      $('body').css('overflow', 'auto');
    };

    base.showTemplateDialog = function() {
      base.defaultOptions.$modalContents.dialog("open");
    };

    base.fetchTemplateDetails = function(event, ui) {
      if (base.xhr) {
        base.xhr.abort();
      }

      base.xhr = $.ajax({
        url: base.options.url,
        dataType: 'html'
      });

      base.xhr.done(function(response, status) {
        base.options.$modalContents.html(response);
      });
    }

  };

  $.PMX.FilterableList = function(el, options) {
    var base = this;

    base.$el = $(el);

    base.defaultOptions = {
      $queryField: base.$el.find('input.query-field'),
      queryFormSelector: 'form.search-form',
      $queryForm: base.$el.find('form.search-form'),
      limit: 40,
      $localImageResults: base.$el.find('.local-image-results'),
      $remoteImageResults: base.$el.find('.remote-image-results'),
      $templateResults: base.$el.find('.template-results'),
      $resultHeadings: base.$el.find('.search-title'),
      remoteImageResultTemplate: Handlebars.compile($('#remote_image_result_template').html()),
      localImageResultTemplate: Handlebars.compile($('#local_image_result_template').html()),
      templateResultTemplate: Handlebars.compile($('#template_result_template').html()),
      loadingTemplate: Handlebars.compile($('#loading_row_template').html()),
      noResultsTemplate: Handlebars.compile($('#no_results_row_template').html()),
      trackingAction: 'not-given',
      tagDropdownSelector: 'select.image-tag-select',
      chosenDropdownSelector: '.chosen-container',
      templateDetailsSelector: '.template-details-link'
    };

    base.init = function(){
      base.options = $.extend({}, base.defaultOptions, options);
      base.queryField = new $.PMX.QueryField(base.options.$queryField);
      base.queryField.bindEvents();
      base.searchResults = new $.PMX.SearchResults(base.resultsEndpoint(), base.options.limit);

      base.bindEvents();
    };

    base.bindEvents = function() {
      base.queryField.onChange(base.fetchResults);
      base.$el.on('submit', base.options.queryFormSelector, base.handleSubmit);
      base.$el.on('click', base.options.chosenDropdownSelector, base.fetchTags);
      base.$el.on('click', base.options.templateDetailsSelector, base.handleTemplateDetailsClick)
    };

    base.handleSubmit = function(e) {
      e.preventDefault();
      base.fetchResults(base.queryField.getTerm());
    };

    base.handleQueryChange = function(e) {
      base.fetchResults();
    };

    base.handleTemplateDetailsClick = function(e) {
      e.preventDefault();
      var origin = window.location.protocol + '//' + window.location.host,
          $elem = $(e.target),
          url = origin + '/templates/' + $elem.attr('data-template-id') + '/details',
          modal = new $.PMX.TemplateDetailsDialog(base.templateDetailsSelector, {url: url});

      modal.init();
      modal.showTemplateDialog()
    };

    base.fetchResults = function(term) {
      base.displayLoadingIndicators();
      base.options.$resultHeadings.css('display', 'block');
      PMX.Tracker.trackEvent('search', base.options.trackingAction, term);

      base.searchResults.fetch(term);
      base.searchResults.templates(base.loadTemplateResults);
      base.searchResults.localImages(base.loadLocalImageResults);
      base.searchResults.remoteImages(base.loadRemoteImageResults);
    };

    base.loadRemoteImageResults = function(images) {
      var resultsHtml = '';
      $.each(images, function(i, image) {
        resultsHtml += base.options.remoteImageResultTemplate(image);
      });
      base.options.$remoteImageResults.html(resultsHtml);
      base.displayTagDropdown();
    };

    base.loadLocalImageResults = function(images) {
      var resultsHtml = '';
      $.each(images, function(i, image) {
        resultsHtml += base.options.localImageResultTemplate(image);
      });
      base.options.$localImageResults.html(resultsHtml);
      base.displayTagDropdown();
    };

    base.loadTemplateResults = function(templates) {
      var resultsHtml = '';
      if (templates && templates.length) {
        $.each(templates, function(i, template) {
          resultsHtml += base.options.templateResultTemplate(template);
        });
      } else {
        resultsHtml = base.options.noResultsTemplate();
      }
      base.options.$templateResults.html(resultsHtml);
    };

    base.displayTagDropdown = function () {
      $(base.options.tagDropdownSelector).chosen({disable_search: true});
    };

    base.fetchTags = function (e) {
      var $elem = $(e.currentTarget),
          $resultRow = $elem.closest('.search-result-item'),
          $selectBox = $resultRow.find(base.options.tagDropdownSelector),
          loaded = $selectBox.data('loaded'),
          local_image = $resultRow.data('status-label') == 'Local';
      if (!loaded) {
        var tagsXhr = $.get(
          $(base.options.tagDropdownSelector).data('load-tags-endpoint'),
          { 'repo': $resultRow.data('title'), 'local_image': local_image }
        );

        tagsXhr.done(function (response) {
          $selectBox.empty();
          response.forEach(function (tag) {
            $selectBox.append('<option value="' + tag + '">' + tag + '</option>');
          });
          $selectBox.data('loaded', true);
          $selectBox.trigger("chosen:updated");
        });
      }
    };

    base.displayLoadingIndicators = function() {
      var forTemplates = base.options.loadingTemplate({loading_copy: 'Finding Templates'}),
          forLocalImages = base.options.loadingTemplate({loading_copy: 'Finding Images'}),
          forRemoteImages = base.options.loadingTemplate({loading_copy: 'Searching Docker Index'});
      base.options.$templateResults.html(forTemplates);
      base.options.$localImageResults.html(forLocalImages);
      base.options.$remoteImageResults.html(forRemoteImages);
    };

    base.resultsEndpoint = function() {
      return base.options.$queryForm.attr('action') + '.json';
    };
  };

  $.fn.filterableList = function(options){
    return this.each(function(){
      (new $.PMX.FilterableList(this, options)).init();
    });
  };

})(jQuery);
<|endoftext|>


<commit_before>'use strict';

module.exports = {
  options: {
    buildType: 'iso-serverless',
  }
};
<commit_msg>fix: make express bundling work<commit_after>'use strict';

module.exports = {
  options: {
    buildType: 'iso-serverless',
    modifyWebpackConfig(opts) {
      const config = opts.webpackConfig;

      if (opts.env.target === 'node') {
        config.plugins.push(
          new opts.webpackObject.ContextReplacementPlugin(
                                               // we want to replace context
            /express\/lib/,                    // and replace all searches in
                                               // express/lib/*
            resolve('node_modules'),           // to look in folder 'node_modules'
            {                                  // and return a map
              'ejs': 'ejs'                     // which resolves request for 'ejs'
            }                                  // to module 'ejs'
          )                                    // __webpack_require__(...)(mod)
          // we set `mod = 'ejs'`
        )
      }

      return config;
    },
  }
};
<|endoftext|>


<commit_before>$(document).ready(function(){

  // need to find the max data entry on the page and start incrementing from there
  $dataEntry = 0;
  $('.form-container-repeater').each(function() {
    if ($dataEntry < $(this).attr('data-entry')) {
      $dataEntry = parseInt($(this).attr('data-entry'));
    }
  });

  $('.form-container-survey').on("click", '.duplicate-form-container-repeater', function(e){
    e.preventDefault();
    e.stopPropagation();

    $scrollPosition = $(this).offset().top - 50;

    $formValidator.parsley().destroy();
    unbindChosenTypes();
    $('.datepicker').datepicker('destroy');

    // find and clone container
    var container = $(this).closest('.form-container-repeater');
    $clonedContainer = container.clone(true);

    // remove hidden field observation ids
    $($clonedContainer).find('.hidden-field-observation-id').remove();

    // collect all container items inside cloned container for iteration
    var containerItems = $($clonedContainer).find('.form-container-entry-item');

    // increment data-entry by 1 on every click
    $dataEntry = $dataEntry + 1;

    // loop through collected container items and update attributes with timestamps
    // CONTAINER ITEMS ARE RELATIVE TO CLONED CONTAINER, THINK OF CLONED CONTAINER AS A SECONDARY DOM OF ITS OWN.
    updateDom(containerItems, $dataEntry);

    // fix repeater container data-entry numbers
    $clonedContainer.attr("data-entry", $dataEntry);
    $clonedContainer.find(".form-container-repeater").attr("data-entry", $dataEntry);

    // set cloned container to display none for fading in
    $clonedContainer.attr("style", "display: none;").addClass("new-clone");
    cleartFilePreviewContainers($clonedContainer);

    // clear values
    clearValues($clonedContainer);

    // we need to stringiy and reset before appending to dom
    stringifyAndResetContainer($clonedContainer);
    $(container).after($clonedContainer);

    $newClone = $(".new-clone");

    $newClone.delay("100").fadeIn(1000).removeClass("new-clone");

    setTimeout(function() {
      $("html, body").animate({
        scrollTop: $scrollPosition
      }, 500);
    }, 200);

    bindChosenTypes();

    $formValidator.parsley();
    new $RequireSurveyInputData().inspectElements();
    $($('div.form-container-entry-item[data-required=true]').find('ul.parsley-errors-list')).remove();
    removeErrorBackground('radio');
    removeErrorBackground('checkbox');
    removeErrorBackground('checkboxes');
    removeUserSuccessClass();

    // bind maps
    setTimeout(function(){
      setupDefaultMaps();
      bindButtons();
      resetMapButtons();
    },500)
    // bind ConditionalLogic
    cl = new ConditionalLogic;
    cl.findRules();

    $(".datepicker").unbind().datepicker();
    $(".timepicki").unbind().timepicki({
      increase_direction: 'up',
      on_change: timepickValidate = function(element) {
        return $(element).parsley().validate();
      }
    });

    // binds previews
    window.showVideoPreview();
    window.documentPreview();
    window.fileDeleteEvent();

    if (window.location.pathname.match(/\/projects\/[\d+]\/hanuman\/surveys\/\d+\/\edit/)) {
      videos = $('[data-element-type=video]').last().find('.custom-cloudinary li a')
      documents = $('[data-element-type=document]').last().find('.custom-cloudinary li a')
      photos = $('[data-element-type=photo]').last().find('.custom-cloudinary li a')

      clearFileInputsValuesInEdit(videos ,"video");
      clearFileInputsValuesInEdit(documents, "document");
      clearFileInputsValuesInEdit(photos, "photo");
     }
  });

  function clearFileInputsValuesInEdit(files, type){
    while (files.length >= 1) {
      $(files[0]).click();
      files = $("[data-element-type="+type+"]").last().find('.custom-cloudinary li a')
    }
  }

  function cleartFilePreviewContainers(container){
    $($(container).find('.document-preview-container')).empty();
    $($(container).find('.video-preview-container')).empty();
  }

  function removeErrorBackground(type){
    $('div.form-container-entry-item[data-element-type='+ type +']').find('div.col-sm-7').removeAttr('style')
  }

  $('.form-container-survey').on('click', ".destroy-form-container-repeater", function(){
    var entry = $($(this).closest('.form-container-repeater')).attr('data-entry');
    var dataObservationId = $($(this).closest('.form-container-repeater')).attr('data-observation-id');
    $(".form-entry-item-container[data-entry=" + entry + "]").not('.form-entry-item-container[data-element-type=time]').remove();
    $removeContainer = $(this).closest('.form-container-repeater');

    setTimeout(function() {
      $("html, body").animate({
        scrollTop: $removeContainer.offset().top - 500
      }, 1000);
    }, 200);

    $removeContainer.fadeOut(
      2000,
      function() {
          $removeContainer.remove();
      }
    );

    if (window.location.pathname.match(/\/projects\/[\d+]\/hanuman\/surveys\/\d+\/edit/)) {
      var projectId = window.location.pathname.match(/\/projects\/(\d+)/)[1];
      var surveyId = window.location.pathname.match(/\/surveys\/(\d+)/)[1];

      $.ajax({
        url: "/projects/" + projectId + "/hanuman/surveys/" + surveyId + "/repeater_observation/" + dataObservationId + "/entry/"+ entry,
        method: "Delete"
      });
    }
    return false;
  });

  function resetMapButtons(){
    var map = $('.form-container-repeater').last().find('div.form-container-entry-item[data-element-type=map] div.map-buttons')
    $(map).find('a.edit-map').text('Pin a Location on Map')
    $(map).find('a.edit-map').attr('style','display: inline-block;')
    $(map).find('a.cancel-map').attr('style','display: none;')
  };

  function removeUserSuccessClass(){
    var types = ['checkboxes', 'checkbox', 'radio']
    setTimeout(function(){
      types.forEach(function(type){
        $($('.form-container-repeater').last().find('div.form-container-entry-item[data-element-type=' + type + '] .col-sm-7 input')).removeClass('user-success');
      })
    }, 2000)
  };

  function stringifyAndResetContainer(containerItems){
    for (var i = 0; i < containerItems.length; i++) {
      stringInput = $(containerItems[i]).prop('outerHTML');
      newInput = $.parseHTML(stringInput);
      $(containerItems[i]).replaceWith(newInput);
    }
  }

  function unbindChosenTypes(){
    $(".chosen-multiselect").chosen('destroy');
    $(".chosen-select").chosen('destroy');
    $(".bootstrap-checkbox-multiselect").multiselect('destroy');
  }

  function bindChosenTypes(){
    $('.attachinary-input').attachinary();
    $(".chosen-multiselect").chosen();
    $(".chosen-select").chosen();
    $(".bootstrap-checkbox-multiselect").multiselect();
  }

  function updateClonedInputs($clonedRepeater, dataEntry, timeStamp){
    $($clonedRepeater).attr('data-entry', dataEntry);
    var inputs = $($clonedRepeater).find('input');
    var lastInputIndex = inputs.length - 1;
    var index = 0;
    $(inputs[lastInputIndex]).attr("value", dataEntry);
    var parsleySubstrig = Math.random().toString(36).substring(13);
    inputs.each(function(){
      if ($(inputs[index]).attr('type') == 'file' || $(inputs[index]).attr('type') == 'document' || $(inputs[index]).attr('type') == 'photo' || $(inputs[index]).attr('type') == 'video') {
        $(inputs[index]).siblings('.attachinary_container').last().remove()
      }
      if ($(inputs[index]).attr('id')) {
        var idStamp = $(inputs[index]).attr("id").match(/\d+/)[0];
        var newTimeStamp = idStamp.concat(timeStamp);
        $(inputs[index]).attr("id", $(inputs[index]).attr("id").replace(/\d+/, newTimeStamp));
      }
      if ($(inputs[index]).attr('data-parsley-multiple')) {
        var newTimeStamp = parsleySubstrig.concat(timeStamp);
        $(inputs[index]).attr("data-parsley-multiple", $(inputs[index]).attr("data-parsley-multiple").replace(/(\d+)/, newTimeStamp));
      }
      if ($(inputs[index]).attr('name')) {
        var nameStamp = $(inputs[index]).attr("name").match(/\d+/)[0];
        var newTimeStamp = nameStamp.concat(timeStamp);
        $(inputs[index]).attr("name", $(inputs[index]).attr("name").replace(/\d+/, newTimeStamp));
      }
      index ++;
    });
  };

  function updateClonedSelects($clonedRepeater, timeStamp){
    var select = $($clonedRepeater).find('select');
    var index = 0;
    select.each(function(){
      if ($(select[index]).attr('id')) {
        var idStamp = $(select[index]).attr("id").match(/\d+/)[0];
        var newTimeStamp = idStamp.concat(timeStamp);
        $(select[index]).attr("id", $(select[index]).attr("id").replace(/(\d+)/, newTimeStamp));
      }
      if ($(select[index]).attr('name')) {
        var nameStamp = $(select[index]).attr("name").match(/\d+/)[0];
        var newTimeStamp = nameStamp.concat(timeStamp);
        $(select[index]).attr("name", $(select[index]).attr("name").replace(/(\d+)/, newTimeStamp));
      }

      index ++;
    });
  }

  function updateClonedLabels($clonedRepeater, timeStamp){
    var labels = $($clonedRepeater).find('label');
    var index = 0;
    labels.each(function(){
      if ($(labels[index]).attr("for")) {
        var forStamp = $(labels[index]).attr("for").match(/\d+/)[0];
        var newTimeStamp = forStamp.concat(timeStamp);
        $(labels[index]).attr("for", $(labels[index]).attr("for").replace(/(\d+)/, newTimeStamp));
      }
      index ++
    });
  }

  function updateClonedTextareas($clonedRepeater, timeStamp){
    var textareas = $($clonedRepeater).find('textarea');
    var index = 0;
    textareas.each(function(){
      if ($(textareas[index]).attr('id')) {
        var idStamp = $(textareas[index]).attr("id").match(/\d+/)[0];
        var newTimeStamp = idStamp.concat(timeStamp);
        $(textareas[index]).attr("id", $(textareas[index]).attr("id").replace(/(\d+)/, newTimeStamp));
      }
      if ($(textareas[index]).attr('name')) {
        var nameStamp = $(textareas[index]).attr("name").match(/\d+/)[0];
        var newTimeStamp = nameStamp.concat(timeStamp);
        $(textareas[index]).attr("name", $(textareas[index]).attr("name").replace(/(\d+)/, newTimeStamp));
      }
      $(textareas[index]).val("");
      index ++;
    });
  }

  function updateDom(clonedRepeater, dataEntry){
    var timeStamp = new Date().getTime();
    for (var i = 0; i < clonedRepeater.length; i++) {
      $($(clonedRepeater[i]).find('.latlong')).attr('id', "map".concat(timeStamp));
      updateClonedInputs(clonedRepeater[i], dataEntry, timeStamp);
      updateClonedLabels(clonedRepeater[i], timeStamp);
      updateClonedSelects(clonedRepeater[i], timeStamp);
      updateClonedTextareas(clonedRepeater[i], timeStamp);
      $($(clonedRepeater[i]).find('.chosen-container')).attr("id", "survey_observations_attributes_" + timeStamp + "_answer_chosen");
      timeStamp = new Date().getTime();
    };
  };

  function clearValues(clonedRepeater){
    for (var i = 0; i < clonedRepeater.length; i++) {
      $(clonedRepeater[i]).find("input[type=tel]").val("");
      $(clonedRepeater[i]).find("input[type=time]").val("");
      $(clonedRepeater[i]).find("input[type=date]").val("");
      textFields = $(clonedRepeater[i]).find(":text").val("");
      textAreas = $(clonedRepeater[i]).find("textarea").val("");
      // un-select dropdown
      selects = $(clonedRepeater[i]).find("select");
      $(selects).each(function() {
        $(this).val("");

        // if we don't add please select at this point the dropdown will show blank with no prompt
        if ($(this).find('option:contains("Please select")').length < 1) {
          $(this).prepend("<option value>Please select</option>");
        }
        if ($(this).hasClass('chosen')) {
          $(this).trigger("chosen:updated");
        }
      });
      multiselects = $(clonedRepeater[i]).find("select[multiple]");
      $(multiselects).each(function() {
        $('#' + $(this).attr('id') + ' option:selected').removeAttr("selected");
        if ($(this).hasClass('chosen-multiselect')) {
          $(this).trigger("chosen:updated");
        }
      });
      // uncheck all checkboxes
      checkboxes = $(clonedRepeater[i]).find(":checkbox");
      $(checkboxes).each(function() {
        $(this).prop('checked', false);
        });
      // un-select radio buttons
      radiobuttons = $(clonedRepeater[i]).find(":radio");
      $(radiobuttons).each(function() {
        $(this).prop('checked', false);
      });

      // trigger onchange event which is needed for embedded conditional logic
      $(clonedRepeater[i]).find('.form-control').trigger('change');
    };
  };
});
<commit_msg>added support for clearing number fields, re-ordered types alphabetically so keep code organized<commit_after>$(document).ready(function(){

  // need to find the max data entry on the page and start incrementing from there
  $dataEntry = 0;
  $('.form-container-repeater').each(function() {
    if ($dataEntry < $(this).attr('data-entry')) {
      $dataEntry = parseInt($(this).attr('data-entry'));
    }
  });

  $('.form-container-survey').on("click", '.duplicate-form-container-repeater', function(e){
    e.preventDefault();
    e.stopPropagation();

    $scrollPosition = $(this).offset().top - 50;

    $formValidator.parsley().destroy();
    unbindChosenTypes();
    $('.datepicker').datepicker('destroy');

    // find and clone container
    var container = $(this).closest('.form-container-repeater');
    $clonedContainer = container.clone(true);

    // remove hidden field observation ids
    $($clonedContainer).find('.hidden-field-observation-id').remove();

    // collect all container items inside cloned container for iteration
    var containerItems = $($clonedContainer).find('.form-container-entry-item');

    // increment data-entry by 1 on every click
    $dataEntry = $dataEntry + 1;

    // loop through collected container items and update attributes with timestamps
    // CONTAINER ITEMS ARE RELATIVE TO CLONED CONTAINER, THINK OF CLONED CONTAINER AS A SECONDARY DOM OF ITS OWN.
    updateDom(containerItems, $dataEntry);

    // fix repeater container data-entry numbers
    $clonedContainer.attr("data-entry", $dataEntry);
    $clonedContainer.find(".form-container-repeater").attr("data-entry", $dataEntry);

    // set cloned container to display none for fading in
    $clonedContainer.attr("style", "display: none;").addClass("new-clone");
    cleartFilePreviewContainers($clonedContainer);

    // clear values
    clearValues($clonedContainer);

    // we need to stringiy and reset before appending to dom
    stringifyAndResetContainer($clonedContainer);
    $(container).after($clonedContainer);

    $newClone = $(".new-clone");

    $newClone.delay("100").fadeIn(1000).removeClass("new-clone");

    setTimeout(function() {
      $("html, body").animate({
        scrollTop: $scrollPosition
      }, 500);
    }, 200);

    bindChosenTypes();

    $formValidator.parsley();
    new $RequireSurveyInputData().inspectElements();
    $($('div.form-container-entry-item[data-required=true]').find('ul.parsley-errors-list')).remove();
    removeErrorBackground('radio');
    removeErrorBackground('checkbox');
    removeErrorBackground('checkboxes');
    removeUserSuccessClass();

    // bind maps
    setTimeout(function(){
      setupDefaultMaps();
      bindButtons();
      resetMapButtons();
    },500)
    // bind ConditionalLogic
    cl = new ConditionalLogic;
    cl.findRules();

    $(".datepicker").unbind().datepicker();
    $(".timepicki").unbind().timepicki({
      increase_direction: 'up',
      on_change: timepickValidate = function(element) {
        return $(element).parsley().validate();
      }
    });

    // binds previews
    window.showVideoPreview();
    window.documentPreview();
    window.fileDeleteEvent();

    if (window.location.pathname.match(/\/projects\/[\d+]\/hanuman\/surveys\/\d+\/\edit/)) {
      videos = $('[data-element-type=video]').last().find('.custom-cloudinary li a')
      documents = $('[data-element-type=document]').last().find('.custom-cloudinary li a')
      photos = $('[data-element-type=photo]').last().find('.custom-cloudinary li a')

      clearFileInputsValuesInEdit(videos ,"video");
      clearFileInputsValuesInEdit(documents, "document");
      clearFileInputsValuesInEdit(photos, "photo");
     }
  });

  function clearFileInputsValuesInEdit(files, type){
    while (files.length >= 1) {
      $(files[0]).click();
      files = $("[data-element-type="+type+"]").last().find('.custom-cloudinary li a')
    }
  }

  function cleartFilePreviewContainers(container){
    $($(container).find('.document-preview-container')).empty();
    $($(container).find('.video-preview-container')).empty();
  }

  function removeErrorBackground(type){
    $('div.form-container-entry-item[data-element-type='+ type +']').find('div.col-sm-7').removeAttr('style')
  }

  $('.form-container-survey').on('click', ".destroy-form-container-repeater", function(){
    var entry = $($(this).closest('.form-container-repeater')).attr('data-entry');
    var dataObservationId = $($(this).closest('.form-container-repeater')).attr('data-observation-id');
    $(".form-entry-item-container[data-entry=" + entry + "]").not('.form-entry-item-container[data-element-type=time]').remove();
    $removeContainer = $(this).closest('.form-container-repeater');

    setTimeout(function() {
      $("html, body").animate({
        scrollTop: $removeContainer.offset().top - 500
      }, 1000);
    }, 200);

    $removeContainer.fadeOut(
      2000,
      function() {
          $removeContainer.remove();
      }
    );

    if (window.location.pathname.match(/\/projects\/[\d+]\/hanuman\/surveys\/\d+\/edit/)) {
      var projectId = window.location.pathname.match(/\/projects\/(\d+)/)[1];
      var surveyId = window.location.pathname.match(/\/surveys\/(\d+)/)[1];

      $.ajax({
        url: "/projects/" + projectId + "/hanuman/surveys/" + surveyId + "/repeater_observation/" + dataObservationId + "/entry/"+ entry,
        method: "Delete"
      });
    }
    return false;
  });

  function resetMapButtons(){
    var map = $('.form-container-repeater').last().find('div.form-container-entry-item[data-element-type=map] div.map-buttons')
    $(map).find('a.edit-map').text('Pin a Location on Map')
    $(map).find('a.edit-map').attr('style','display: inline-block;')
    $(map).find('a.cancel-map').attr('style','display: none;')
  };

  function removeUserSuccessClass(){
    var types = ['checkboxes', 'checkbox', 'radio']
    setTimeout(function(){
      types.forEach(function(type){
        $($('.form-container-repeater').last().find('div.form-container-entry-item[data-element-type=' + type + '] .col-sm-7 input')).removeClass('user-success');
      })
    }, 2000)
  };

  function stringifyAndResetContainer(containerItems){
    for (var i = 0; i < containerItems.length; i++) {
      stringInput = $(containerItems[i]).prop('outerHTML');
      newInput = $.parseHTML(stringInput);
      $(containerItems[i]).replaceWith(newInput);
    }
  }

  function unbindChosenTypes(){
    $(".chosen-multiselect").chosen('destroy');
    $(".chosen-select").chosen('destroy');
    $(".bootstrap-checkbox-multiselect").multiselect('destroy');
  }

  function bindChosenTypes(){
    $('.attachinary-input').attachinary();
    $(".chosen-multiselect").chosen();
    $(".chosen-select").chosen();
    $(".bootstrap-checkbox-multiselect").multiselect();
  }

  function updateClonedInputs($clonedRepeater, dataEntry, timeStamp){
    $($clonedRepeater).attr('data-entry', dataEntry);
    var inputs = $($clonedRepeater).find('input');
    var lastInputIndex = inputs.length - 1;
    var index = 0;
    $(inputs[lastInputIndex]).attr("value", dataEntry);
    var parsleySubstrig = Math.random().toString(36).substring(13);
    inputs.each(function(){
      if ($(inputs[index]).attr('type') == 'file' || $(inputs[index]).attr('type') == 'document' || $(inputs[index]).attr('type') == 'photo' || $(inputs[index]).attr('type') == 'video') {
        $(inputs[index]).siblings('.attachinary_container').last().remove()
      }
      if ($(inputs[index]).attr('id')) {
        var idStamp = $(inputs[index]).attr("id").match(/\d+/)[0];
        var newTimeStamp = idStamp.concat(timeStamp);
        $(inputs[index]).attr("id", $(inputs[index]).attr("id").replace(/\d+/, newTimeStamp));
      }
      if ($(inputs[index]).attr('data-parsley-multiple')) {
        var newTimeStamp = parsleySubstrig.concat(timeStamp);
        $(inputs[index]).attr("data-parsley-multiple", $(inputs[index]).attr("data-parsley-multiple").replace(/(\d+)/, newTimeStamp));
      }
      if ($(inputs[index]).attr('name')) {
        var nameStamp = $(inputs[index]).attr("name").match(/\d+/)[0];
        var newTimeStamp = nameStamp.concat(timeStamp);
        $(inputs[index]).attr("name", $(inputs[index]).attr("name").replace(/\d+/, newTimeStamp));
      }
      index ++;
    });
  };

  function updateClonedSelects($clonedRepeater, timeStamp){
    var select = $($clonedRepeater).find('select');
    var index = 0;
    select.each(function(){
      if ($(select[index]).attr('id')) {
        var idStamp = $(select[index]).attr("id").match(/\d+/)[0];
        var newTimeStamp = idStamp.concat(timeStamp);
        $(select[index]).attr("id", $(select[index]).attr("id").replace(/(\d+)/, newTimeStamp));
      }
      if ($(select[index]).attr('name')) {
        var nameStamp = $(select[index]).attr("name").match(/\d+/)[0];
        var newTimeStamp = nameStamp.concat(timeStamp);
        $(select[index]).attr("name", $(select[index]).attr("name").replace(/(\d+)/, newTimeStamp));
      }

      index ++;
    });
  }

  function updateClonedLabels($clonedRepeater, timeStamp){
    var labels = $($clonedRepeater).find('label');
    var index = 0;
    labels.each(function(){
      if ($(labels[index]).attr("for")) {
        var forStamp = $(labels[index]).attr("for").match(/\d+/)[0];
        var newTimeStamp = forStamp.concat(timeStamp);
        $(labels[index]).attr("for", $(labels[index]).attr("for").replace(/(\d+)/, newTimeStamp));
      }
      index ++
    });
  }

  function updateClonedTextareas($clonedRepeater, timeStamp){
    var textareas = $($clonedRepeater).find('textarea');
    var index = 0;
    textareas.each(function(){
      if ($(textareas[index]).attr('id')) {
        var idStamp = $(textareas[index]).attr("id").match(/\d+/)[0];
        var newTimeStamp = idStamp.concat(timeStamp);
        $(textareas[index]).attr("id", $(textareas[index]).attr("id").replace(/(\d+)/, newTimeStamp));
      }
      if ($(textareas[index]).attr('name')) {
        var nameStamp = $(textareas[index]).attr("name").match(/\d+/)[0];
        var newTimeStamp = nameStamp.concat(timeStamp);
        $(textareas[index]).attr("name", $(textareas[index]).attr("name").replace(/(\d+)/, newTimeStamp));
      }
      $(textareas[index]).val("");
      index ++;
    });
  }

  function updateDom(clonedRepeater, dataEntry){
    var timeStamp = new Date().getTime();
    for (var i = 0; i < clonedRepeater.length; i++) {
      $($(clonedRepeater[i]).find('.latlong')).attr('id', "map".concat(timeStamp));
      updateClonedInputs(clonedRepeater[i], dataEntry, timeStamp);
      updateClonedLabels(clonedRepeater[i], timeStamp);
      updateClonedSelects(clonedRepeater[i], timeStamp);
      updateClonedTextareas(clonedRepeater[i], timeStamp);
      $($(clonedRepeater[i]).find('.chosen-container')).attr("id", "survey_observations_attributes_" + timeStamp + "_answer_chosen");
      timeStamp = new Date().getTime();
    };
  };

  function clearValues(clonedRepeater){
    for (var i = 0; i < clonedRepeater.length; i++) {
      $(clonedRepeater[i]).find("input[type=date]").val("");
      $(clonedRepeater[i]).find("input[type=email]").val("");
      $(clonedRepeater[i]).find("input[type=number]").val("");
      $(clonedRepeater[i]).find("input[type=tel]").val("");
      $(clonedRepeater[i]).find("input[type=time]").val("");
      textFields = $(clonedRepeater[i]).find(":text").val("");
      textAreas = $(clonedRepeater[i]).find("textarea").val("");
      // un-select dropdown
      selects = $(clonedRepeater[i]).find("select");
      $(selects).each(function() {
        $(this).val("");

        // if we don't add please select at this point the dropdown will show blank with no prompt
        if ($(this).find('option:contains("Please select")').length < 1) {
          $(this).prepend("<option value>Please select</option>");
        }
        if ($(this).hasClass('chosen')) {
          $(this).trigger("chosen:updated");
        }
      });
      multiselects = $(clonedRepeater[i]).find("select[multiple]");
      $(multiselects).each(function() {
        $('#' + $(this).attr('id') + ' option:selected').removeAttr("selected");
        if ($(this).hasClass('chosen-multiselect')) {
          $(this).trigger("chosen:updated");
        }
      });
      // uncheck all checkboxes
      checkboxes = $(clonedRepeater[i]).find(":checkbox");
      $(checkboxes).each(function() {
        $(this).prop('checked', false);
        });
      // un-select radio buttons
      radiobuttons = $(clonedRepeater[i]).find(":radio");
      $(radiobuttons).each(function() {
        $(this).prop('checked', false);
      });

      // trigger onchange event which is needed for embedded conditional logic
      $(clonedRepeater[i]).find('.form-control').trigger('change');
    };
  };
});
<|endoftext|>


<commit_before>module('Generator tests')

test('Non allocating generator',function() {
	var Simple = Generator(function(v) { return v; }, { alloc: false });

	var s8 = Simple(8);
	equal(s8, 8);

})

test('Generator inherit from constructor defined on main constructor',function(){

	var _Shape = sinon.spy();
	var _Rectangle = sinon.spy();
	_Rectangle.bases = [_Shape];

	var Shape = Generator(_Shape);
	var Rectangle = Generator(_Rectangle);

	ok(!! Shape.__generator__)
	ok(!! _Shape.__generator__)
	ok(!! Rectangle.__generator__)
	ok(!! _Rectangle.__generator__)
	equal(Rectangle.bases.length, 1)
	equal(Rectangle.bases[0], _Shape)

	Rectangle(1,2,3,4);
	equal(_Shape.callCount,1)
	equal(_Rectangle.callCount,1)
	ok(_Shape.calledWith(1,2,3,4))
	ok(_Rectangle.calledWith(1,2,3,4))
})

test('Generator inherit from generator defined on main constructor',function(){

	var _Shape = sinon.spy();
	var Shape = Generator(_Shape);

	var _Rectangle = sinon.spy();
	_Rectangle.bases = [Shape];

	var Rectangle = Generator(_Rectangle);

	ok(!! Shape.__generator__)
	ok(!! _Shape.__generator__)
	ok(!! Rectangle.__generator__)
	ok(!! _Rectangle.__generator__)
	equal(Rectangle.bases.length, 1)
	equal(Rectangle.bases[0], _Shape)

	Rectangle(1,2,3,4);
	equal(_Shape.callCount,1)
	equal(_Rectangle.callCount,1)
	ok(_Shape.calledWith(1,2,3,4))
	ok(_Rectangle.calledWith(1,2,3,4))
})

test('Shape generator with parameters',function() {

	var NumberType = Resolver("essential")("Type").variant("Number");

	function _Shape() {}
	_Shape.args = [ ];

	function _Rectangle(width,height) {

	}
	_Rectangle.bases = [_Shape];
	_Rectangle.args = [ NumberType({name:"width",preset:true}), NumberType({name:"height",preset:true}) ]; //TODO NumberType({name:"width"}) optional: , default:  seed:
	_Rectangle.prototype.earlyFunc = function() {};

	var Shape = Generator(_Shape);
	var Rectangle = Generator(_Rectangle);

	Rectangle.prototype.getWidth = function() {
		return this.width;
	};

	equal(typeof Shape.info.options,'object');
	equal(Rectangle.bases, _Rectangle.bases);
	equal(Rectangle.args, _Rectangle.args);

	var s = Shape();
	var r55 = Rectangle(5,5);
	ok(r55 instanceof _Rectangle);
	ok(r55 instanceof Rectangle);
	ok(r55 instanceof _Shape);
	ok(r55 instanceof Shape);
	equal(Rectangle.prototype.getWidth, _Rectangle.prototype.getWidth);
	equal(typeof Rectangle.prototype.earlyFunc, 'function');
	equal(r55.width, 5);
	equal(r55.getWidth(), 5);

	/*
	Shape.mixin({
		sides: 0
	});

	Rectangle.mixin({
		sides: 2,
		getRatio: function() { return this.width / this.height; }
	});

	equal(_Shape.prototype.sides, 0);
	equal(s.sides, 0);
	equal(Rectangle.prototype.sides, 2);
	equal(r55.sides, 2);
	*/

	function _Circle(diameter) {

	}
	_Circle.prototype.earlyFunc = function() {};

	var Circle = Generator(_Circle,Shape,{
		args : [ NumberType({name:"diameter",preset:true}) ] //TODO NumberType({name:"width"}) optional: , default:  seed:
	});

	Circle.prototype.getWidth = function() {
		return this.diameter;
	};

	equal(Circle.bases.length, 1);
	equal(Circle.bases[0], _Shape);
	equal(Circle.info.options.args.length, 1);
	equal(typeof Circle.info.options.args[0], 'object');
	//TODO equal(_Circle.prototype.sides, 0);

	var c9 = Circle(9);
	ok(c9 instanceof _Circle);
	ok(c9 instanceof Circle);
	ok(c9 instanceof _Shape);
	ok(c9 instanceof Shape);
	equal(c9.diameter, 9);
	equal(c9.getWidth(), 9);

})

// inherit from generator not constructor

// Generator.set get declare on the prototype

test("Inherit from Builtin",function(){
	function _Test() {
		this.a = "a";

	}
	var Test = Generator(_Test,Array);
	_Test.prototype.b = function(){
		return "b";
	}

	var test = Test();
	debugger;
	ok(test.a);
	ok(test.b);
	ok(test.b());
	equal(test.length,0);
	test.push("d");
	equal(test.length,1);
});

<commit_msg>removed debugger<commit_after>module('Generator tests')

test('Non allocating generator',function() {
	var Simple = Generator(function(v) { return v; }, { alloc: false });

	var s8 = Simple(8);
	equal(s8, 8);

})

test('Generator inherit from constructor defined on main constructor',function(){

	var _Shape = sinon.spy();
	var _Rectangle = sinon.spy();
	_Rectangle.bases = [_Shape];

	var Shape = Generator(_Shape);
	var Rectangle = Generator(_Rectangle);

	ok(!! Shape.__generator__)
	ok(!! _Shape.__generator__)
	ok(!! Rectangle.__generator__)
	ok(!! _Rectangle.__generator__)
	equal(Rectangle.bases.length, 1)
	equal(Rectangle.bases[0], _Shape)

	Rectangle(1,2,3,4);
	equal(_Shape.callCount,1)
	equal(_Rectangle.callCount,1)
	ok(_Shape.calledWith(1,2,3,4))
	ok(_Rectangle.calledWith(1,2,3,4))
})

test('Generator inherit from generator defined on main constructor',function(){

	var _Shape = sinon.spy();
	var Shape = Generator(_Shape);

	var _Rectangle = sinon.spy();
	_Rectangle.bases = [Shape];

	var Rectangle = Generator(_Rectangle);

	ok(!! Shape.__generator__)
	ok(!! _Shape.__generator__)
	ok(!! Rectangle.__generator__)
	ok(!! _Rectangle.__generator__)
	equal(Rectangle.bases.length, 1)
	equal(Rectangle.bases[0], _Shape)

	Rectangle(1,2,3,4);
	equal(_Shape.callCount,1)
	equal(_Rectangle.callCount,1)
	ok(_Shape.calledWith(1,2,3,4))
	ok(_Rectangle.calledWith(1,2,3,4))
})

test('Shape generator with parameters',function() {

	var NumberType = Resolver("essential")("Type").variant("Number");

	function _Shape() {}
	_Shape.args = [ ];

	function _Rectangle(width,height) {

	}
	_Rectangle.bases = [_Shape];
	_Rectangle.args = [ NumberType({name:"width",preset:true}), NumberType({name:"height",preset:true}) ]; //TODO NumberType({name:"width"}) optional: , default:  seed:
	_Rectangle.prototype.earlyFunc = function() {};

	var Shape = Generator(_Shape);
	var Rectangle = Generator(_Rectangle);

	Rectangle.prototype.getWidth = function() {
		return this.width;
	};

	equal(typeof Shape.info.options,'object');
	equal(Rectangle.bases, _Rectangle.bases);
	equal(Rectangle.args, _Rectangle.args);

	var s = Shape();
	var r55 = Rectangle(5,5);
	ok(r55 instanceof _Rectangle);
	ok(r55 instanceof Rectangle);
	ok(r55 instanceof _Shape);
	ok(r55 instanceof Shape);
	equal(Rectangle.prototype.getWidth, _Rectangle.prototype.getWidth);
	equal(typeof Rectangle.prototype.earlyFunc, 'function');
	equal(r55.width, 5);
	equal(r55.getWidth(), 5);

	/*
	Shape.mixin({
		sides: 0
	});

	Rectangle.mixin({
		sides: 2,
		getRatio: function() { return this.width / this.height; }
	});

	equal(_Shape.prototype.sides, 0);
	equal(s.sides, 0);
	equal(Rectangle.prototype.sides, 2);
	equal(r55.sides, 2);
	*/

	function _Circle(diameter) {

	}
	_Circle.prototype.earlyFunc = function() {};

	var Circle = Generator(_Circle,Shape,{
		args : [ NumberType({name:"diameter",preset:true}) ] //TODO NumberType({name:"width"}) optional: , default:  seed:
	});

	Circle.prototype.getWidth = function() {
		return this.diameter;
	};

	equal(Circle.bases.length, 1);
	equal(Circle.bases[0], _Shape);
	equal(Circle.info.options.args.length, 1);
	equal(typeof Circle.info.options.args[0], 'object');
	//TODO equal(_Circle.prototype.sides, 0);

	var c9 = Circle(9);
	ok(c9 instanceof _Circle);
	ok(c9 instanceof Circle);
	ok(c9 instanceof _Shape);
	ok(c9 instanceof Shape);
	equal(c9.diameter, 9);
	equal(c9.getWidth(), 9);

})

// inherit from generator not constructor

// Generator.set get declare on the prototype

test("Inherit from Builtin",function(){
	function _Test() {
		this.a = "a";

	}
	var Test = Generator(_Test,Array);
	_Test.prototype.b = function(){
		return "b";
	}

	var test = Test();
	// debugger;
	ok(test.a);
	ok(test.b);
	ok(test.b());
	equal(test.length,0);
	test.push("d");
	equal(test.length,1);
});

<|endoftext|>


<commit_before><commit_msg>Update project speakingurl to 6.0.0<commit_after><|endoftext|>


<commit_before>var should = require('should');

var Store = require('../../../lib/store');

describe('Postgres: all Attributes', function(){
  var store;
  var database = 'all_attributes_test';

  before(function(next){
    beforePG(database, [
      'CREATE TABLE attribute_tests(char_attribute  varchar(255), float_attribute float, integer_attribute  integer, text_attribute text, boolean_attribute boolean, binary_attribute bytea, date_attribute date, datetime_attribute timestamp without time zone, time_attribute time)',
      "INSERT INTO attribute_tests VALUES('abcd', 2.3345, 3243, 'some text', true, 'some binary data', '2014-02-18', '2014-02-18 15:45:02', '15:45:01')"
    ], next);
  });

  before(function(){
    store = new Store({
      host: 'localhost',
      type: 'postgres',
      database: database,
      user: 'postgres',
      password: ''
    });

    store.Model('AttributeTest', function(){});

    store.on('exception', function(){});
  });

  after(function(next){
    afterPG(database, next);
  });

  it('have all attributes loaded', function(done){
    store.ready(function(){
      var AttributeTest = store.Model('AttributeTest');

      var attrs = AttributeTest.definition.attributes;

      attrs.should.have.property('char_attribute');
      attrs.should.have.property('float_attribute');
      attrs.should.have.property('integer_attribute');
      attrs.should.have.property('text_attribute');
      attrs.should.have.property('boolean_attribute');
      attrs.should.have.property('binary_attribute');
      attrs.should.have.property('date_attribute');
      attrs.should.have.property('datetime_attribute');
      attrs.should.have.property('time_attribute');

      done();
    });
  });

  it('casts all values', function(done){
    store.ready(function(){
      var AttributeTest = store.Model('AttributeTest');
      AttributeTest.limit(1).exec(function(record){
        record.char_attribute.should.be.equal('abcd');
        record.float_attribute.should.be.equal(2.3345);
        record.integer_attribute.should.be.equal(3243);
        record.text_attribute.should.be.equal('some text');
        record.boolean_attribute.should.be.equal(true);
        record.binary_attribute.should.be.eql(new Buffer('some binary data', 'utf-8'));
        record.date_attribute.toString().should.be.equal('2014-02-18');
        record.datetime_attribute.toJSON().should.be.equal('2014-02-18T14:45:02.000Z');
        record.time_attribute.toString().should.be.equal('15:45:01');
        done();
      });
    });
  });

});

<commit_msg>test bugfix: travis-ci timezone<commit_after>var should = require('should');

var Store = require('../../../lib/store');

describe('Postgres: all Attributes', function(){
  var store;
  var database = 'all_attributes_test';

  before(function(next){
    beforePG(database, [
      'CREATE TABLE attribute_tests(char_attribute  varchar(255), float_attribute float, integer_attribute  integer, text_attribute text, boolean_attribute boolean, binary_attribute bytea, date_attribute date, datetime_attribute timestamp without time zone, time_attribute time)',
      "INSERT INTO attribute_tests VALUES('abcd', 2.3345, 3243, 'some text', true, 'some binary data', '2014-02-18', '2014-02-18 15:45:02', '15:45:01')"
    ], next);
  });

  before(function(){
    store = new Store({
      host: 'localhost',
      type: 'postgres',
      database: database,
      user: 'postgres',
      password: ''
    });

    store.Model('AttributeTest', function(){});

    store.on('exception', function(){});
  });

  after(function(next){
    afterPG(database, next);
  });

  it('have all attributes loaded', function(done){
    store.ready(function(){
      var AttributeTest = store.Model('AttributeTest');

      var attrs = AttributeTest.definition.attributes;

      attrs.should.have.property('char_attribute');
      attrs.should.have.property('float_attribute');
      attrs.should.have.property('integer_attribute');
      attrs.should.have.property('text_attribute');
      attrs.should.have.property('boolean_attribute');
      attrs.should.have.property('binary_attribute');
      attrs.should.have.property('date_attribute');
      attrs.should.have.property('datetime_attribute');
      attrs.should.have.property('time_attribute');

      done();
    });
  });

  it('casts all values', function(done){
    store.ready(function(){
      var AttributeTest = store.Model('AttributeTest');
      AttributeTest.limit(1).exec(function(record){
        record.char_attribute.should.be.equal('abcd');
        record.float_attribute.should.be.equal(2.3345);
        record.integer_attribute.should.be.equal(3243);
        record.text_attribute.should.be.equal('some text');
        record.boolean_attribute.should.be.equal(true);
        record.binary_attribute.should.be.eql(new Buffer('some binary data', 'utf-8'));
        record.date_attribute.toString().should.be.equal('2014-02-18');

        if(new Date().getTimezoneOffset() == -60){ //my local test timezone
          record.datetime_attribute.toJSON().should.be.equal('2014-02-18T14:45:02.000Z');
        }else{ //travis-ci timezone
          record.datetime_attribute.toJSON().should.be.equal('2014-02-18T15:45:02.000Z');
        }

        record.time_attribute.toString().should.be.equal('15:45:01');
        done();
      });
    });
  });

});

<|endoftext|>


<commit_before>var InputEvent = require('../events');

var ProcessOverOutEvents = function (pointer)
{
    var currentlyOver = this._temp;

    var i;
    var gameObject;
    var justOut = [];
    var justOver = [];
    var stillOver = [];
    var previouslyOver = this._over[pointer.id];

    //  TODO - in a topOnly situation a new justOver entry at the top
    //  should clear all previous justOut entries

    //  Go through all objects the pointer was previously over, and see if it still is
    for (i = 0; i < previouslyOver.length; i++)
    {
        gameObject = previouslyOver[i];

        if (currentlyOver.indexOf(gameObject) === -1)
        {
            //  Not in the currentlyOver array
            justOut.push(gameObject);
        }
        else
        {
            //  In the currentlyOver array
            stillOver.push(gameObject);
        }
    }

    //  Go through the hit test results
    for (i = 0; i < currentlyOver.length; i++)
    {
        gameObject = currentlyOver[i];

        //  Is this newly over?

        if (previouslyOver.indexOf(gameObject) === -1)
        {
            justOver.push(gameObject);
        }
    }

    //  By this point the arrays are filled, so now we can process what happened...

    //  Process the Just Out objects
    var total = justOut.length;

    console.log('justOut', total);

    if (total > 0)
    {
        this.sortGameObjects(justOut);

        this.events.dispatch(new InputEvent.POINTER_OUT(pointer, justOut));

        //  Call onOut for everything in the justOut array
        for (i = 0; i < total; i++)
        {
            gameObject = justOut[i];

            if (!gameObject.input)
            {
                continue;
            }

            this.events.dispatch(new InputEvent.GAME_OBJECT_OUT(pointer, gameObject));

            gameObject.input.onOut(gameObject, pointer);

            if (this.topOnly)
            {
                console.log('break 1');
                break;
            }
        }
    }

    //  Process the Just Over objects
    total = justOver.length;

    console.log('justOver', total);

    if (total > 0)
    {
        this.sortGameObjects(justOver);

        this.events.dispatch(new InputEvent.POINTER_OVER(pointer, justOver));

        //  Call onOver for everything in the justOver array
        for (i = 0; i < total; i++)
        {
            gameObject = justOver[i];

            if (!gameObject.input)
            {
                continue;
            }

            this.events.dispatch(new InputEvent.GAME_OBJECT_OVER(pointer, gameObject));

            gameObject.input.onOver(gameObject, pointer, gameObject.input.localX, gameObject.input.localY);

            if (this.topOnly)
            {
                console.log('break 2');
                break;
            }
        }
    }

    //  Add the contents of justOver to the previously over array
    previouslyOver = stillOver.concat(justOver);

    //  Then sort it into display list order
    this._over[pointer.id] = this.sortGameObjects(previouslyOver);
};

module.exports = ProcessOverOutEvents;
<commit_msg>Working through some topOnly debug tests<commit_after>var InputEvent = require('../events');

var ProcessOverOutEvents = function (pointer)
{
    var currentlyOver = this._temp;

    var i;
    var gameObject;
    var justOut = [];
    var justOver = [];
    var stillOver = [];
    var previouslyOver = this._over[pointer.id];

    //  Go through all objects the pointer was previously over, and see if it still is.
    //  Splits the previouslyOver array into two parts: justOut and stillOver
    for (i = 0; i < previouslyOver.length; i++)
    {
        gameObject = previouslyOver[i];

        if (currentlyOver.indexOf(gameObject) === -1)
        {
            //  Not in the currentlyOver array, so must be outside of this object now
            justOut.push(gameObject);
        }
        else
        {
            //  In the currentlyOver array
            stillOver.push(gameObject);
        }
    }

    //  Go through the hit test results (the contents of currentlyOver)
    //  and if not in the previouslyOver array we know it's a new entry, so add to justOver
    for (i = 0; i < currentlyOver.length; i++)
    {
        gameObject = currentlyOver[i];

        //  Is this newly over?

        if (previouslyOver.indexOf(gameObject) === -1)
        {
            justOver.push(gameObject);
        }
    }

    //  By this point the arrays are filled, so now we can process what happened...

    //  In a topOnly situation a new justOver entry at the top
    //  should clear all previous justOut entries and ignore the rest of the stillOver entries

    if (this.topOnly && justOver.length)
    {
        this.sortGameObjects(justOver);

        //  Only the top-most one counts now, ignore the rest
        var topObject = justOver.shift();

        console.log('topOnly', topObject.name);

        justOver = [ topObject ];

        justOut = justOut.concat(stillOver);

        stillOver.length = 0;
    }

    //  Process the Just Out objects
    var total = justOut.length;

    if (total > 0)
    {
        this.sortGameObjects(justOut);

        this.events.dispatch(new InputEvent.POINTER_OUT(pointer, justOut));

        //  Call onOut for everything in the justOut array
        for (i = 0; i < total; i++)
        {
            gameObject = justOut[i];

            if (!gameObject.input)
            {
                continue;
            }

            this.events.dispatch(new InputEvent.GAME_OBJECT_OUT(pointer, gameObject));

            gameObject.input.onOut(gameObject, pointer);
        }
    }

    //  Process the Just Over objects
    total = justOver.length;

    if (total > 0)
    {
        this.sortGameObjects(justOver);

        this.events.dispatch(new InputEvent.POINTER_OVER(pointer, justOver));

        //  Call onOver for everything in the justOver array
        for (i = 0; i < total; i++)
        {
            gameObject = justOver[i];

            if (!gameObject.input)
            {
                continue;
            }

            this.events.dispatch(new InputEvent.GAME_OBJECT_OVER(pointer, gameObject));

            gameObject.input.onOver(gameObject, pointer, gameObject.input.localX, gameObject.input.localY);
        }
    }

    //  Add the contents of justOver to the previously over array
    previouslyOver = stillOver.concat(justOver);

    //  Then sort it into display list order
    this._over[pointer.id] = this.sortGameObjects(previouslyOver);
};

module.exports = ProcessOverOutEvents;
<|endoftext|>