<commit_before>let fileName = '../js/ssProject.json'; // '../js/sampleGraphData.json'

// TODO: If a root id is passed, then we should add a relationship from the project node to the selected id node
// TODO: Add the project name as the first node in the nodes list of JSON being given

// get the data
d3.json(fileName, function (error, graphData) {
  if (error) {
    console.log(error);
  }

  let clickedOnce = false;  // For monitoring the click event on node
  let timer;                // For click event monitoring

  let width = 1000;
  let height = 800;
  let reducedOpacity = 0.2;

  // let nodes = {};
  let items = graphData.nodes;
  let itemRelations = graphData.edges;
  let relationsChecked = false;

  // Create a project node and add it to the items list
  let projectNode = { id: -1, name: graphData.name, image: '', type: -1 };
  items.unshift(projectNode);
  projectNode = items[0];

  // Map all node edges
  let nodeToEdgeMap = {};

  items.forEach(function (item) {
    nodeToEdgeMap[item.id] = {};
    nodeToEdgeMap[item.id].node = item;
    nodeToEdgeMap[item.id].edges = itemRelations.filter(function (relItem) {
      if (relItem.source === item.id) {
        return relItem; // Filter all of the edges that have this item source id
      }
    });

    item.noRelations = true;
  });
  console.log(nodeToEdgeMap);

  // Append the SVG object to the body
  // Add a group element within it to encompass all the nodes - this fixes the chrome
  let svg = d3.select('body').append('svg')
    .attr('width', '100%')
    .attr('height', height)
    .call(d3.behavior.zoom().scaleExtent([1, 10])
      .on('zoom', function () {
        svg.attr('transform', 'translate(' + d3.event.translate + ')' + ' scale(' + d3.event.scale + ')');
      }))
    .on('dblclick.zoom', null)  // To remove the double click zoom function
    .append('g');

  // ============ build the arrows ================
  svg.append('svg:defs').selectAll('marker')
    .data(['end'])      // Different link/path types can be defined here
    .enter().append('svg:marker')    // This section adds in the arrows
    .attr('id', String)
    .attr('viewBox', '0 -5 10 10')
    .attr('refX', 25)
    .attr('refY', -1.5)
    .attr('markerWidth', 6)
    .attr('markerHeight', 6)
    .attr('orient', 'auto')
    .append('svg:path')
    .attr('d', 'M0,-5L10,0L0,5')
    .attr('class', 'arrow');

  let force = d3.layout.force()
    .size([width, height])
    .linkDistance(100)  // sets the target distance between linked nodes to the specified value
    .charge(-1000)       // - value results in node repulsion, while + value results in node attraction
    .friction(0.8);     // closely approximates velocity decay

  updateGraph(rootID);  // Render the graph
  //collapseAll();
  /*
   * Updates the graph visuals
   * @param {Integer} rootId is the id of the element that is to be the root node coming off the project node
   */
  function updateGraph (passedId = -1) {
    if (!relationsChecked) {
      // For each relationship, add the target to the source node
      itemRelations.forEach(function (relItem) {
        // Find node object based on the relationship source id
        let srcNode = items.find(function (item) {
          return item.id === relItem.source;
        });

        // Set the relationship source and target values
        // Note - Use objects only and not just ids of the nodes
        relItem.source = srcNode;
        relItem.target = items.find(function (item) {
          return item.id === relItem.target;
        });

        addDownstreamItemToNode(srcNode, relItem);  // Check if downstream items array exists
      });

      // Check if there are relations for each node and set a flag
      items.forEach(function (item) {
        if (typeof item.downstream === 'undefined') {
          item.noRelations = true;
        } else {
          item.noRelations = (item.downstream.length === 0);
        }
      });

      relationsChecked = true;
    }

    // Checks to see if a node id was passed
    if (passedId !== -1) {
      // Get the root item from the items list
      let rootItem = items.find(function (item) {
        return item.id === passedId;
      });
      // Add an edge from the project node to the passed node
      itemRelations.unshift({id: 0, source: projectNode, target: rootItem, type: -1});

      addDownstreamItemToNode(projectNode, itemRelations[0]);  // Add downstream item to project node
    }

    // Set the force nodes, edges and start the graph
    force
      .nodes(graphData.nodes)
      .links(graphData.edges)
      .on('tick', tick)
      .start();

    // ============ edges combined with the arrows ===========
    let path = svg.append('svg:g').selectAll('path')
      .data(force.links())
      .enter().append('svg:path')
      .attr('id', function (d) {
        return d.id;  // Add an id element to each edge
      })
      .attr('class', thisPath => {
        let result = 'link';
        // Check the type and add a style according to type
        result = (thisPath.type === -1) ? result + ' link-dot' : result;
        result = (thisPath.type === 8) ? ' link-dash' : result;

        return result;
      })
      .attr('marker-end', 'url(#end)');

    // ============ Node Properties Definition ===========
    let node = svg.selectAll('.node')
      .data(force.nodes())
      .enter()
      .append('g')
      .attr('id', function (d) {
        return d.id;  // Add an id element to each node
      })
      .attr('class', function (thisNode) {
        // Add projectRoot class if the node is the project node
        return thisNode.id === -1 ? 'node projectRoot' : 'node';
      })
      .call(force.drag)
      .on('click', function (d) {
        if (clickedOnce) {
          nodeDoubleClick(d);  // Call the single click function
        } else {
          timer = setTimeout(function () {
            nodeClick(d); // Call the double click function
          }, 175);
          clickedOnce = true;
        }
      });

    projectNode.fixed = true;  // Set the project Node to be fixed and not moving
    projectNode.x = height / 2;
    projectNode.y = width / 2;

    // White rectangle behind text configuration
    node.append('rect')
      .attr('x', -8)
      .attr('y', -9)
      .attr('height', 19)
      .attr('width', 120)
      .style('opacity', 0.80);

    // Circle at node behind icon configuration
    node.append('circle')
      .attr('x', '-14px')
      .attr('y', '-14px')
      .attr('r', 13)
      .style('opacity', 0.80);

    // Image in the node circle configuration
    node.append('image')
      .attr('xlink:href', function (n) {
        return n.image;
      })
      .attr('x', '-9px')
      .attr('y', '-9px')
      .attr('height', '18px')
      .attr('width', '18px');

    // Add Text for hovering that shows full filename
    node.append('svg:title')
      .text(function (d) {
        return (d.id + ' - ' + d.name);
      });

    // Add the name of the node as text
    node.append('text')
      .attr('x', 18)
      .attr('dy', '.35em')
      .attr('class', 'nodeText')
      .text(function (d) {
        // Limit the length of the name text
        return d.name.length > 18 ? d.name.substring(0, 15) + '...' : d.name;
      });

    // ============= Node Path Definitions ==============
    /*
     * For every shift of the graph, this gets called.
     * It updates the location of the nodes and edges.
     *
     * @param {Object} e
     */
    function tick (e) {
      path.attr('d', function (d) {
        let dx = d.target.x - d.source.x;
        let dy = d.target.y - d.source.y;
        let dr = Math.sqrt(dx * dx + dy * dy);

        return 'M' + d.source.x + ',' + d.source.y + 'A' +
          dr + ',' + dr + ' 0 0,1 ' + d.target.x + ',' + d.target.y;
      });

      // Move the edge depending on node location
      node.attr('transform', function (d) {
        return 'translate(' + d.x + ',' + d.y + ')';
      });

      let k = 10 * e.alpha; // For the node offset

      // This section pushes sources up and targets down to form a weak tree-like structure.
      path.each(function (d) {
        d.source.x -= k;
        d.target.x += k;
      }).attr('x1', function (d) { return d.source.x; })
        .attr('y1', function (d) { return d.source.y; })
        .attr('x2', function (d) { return d.target.x; })
        .attr('y2', function (d) { return d.target.y; });

      // This sets the node position
      node.attr('cx', function (d) { return 5 * d.x; })
          .attr('cy', function (d) { return d.y; });
    }

    //
    // ============ Toggle highlighting nodes on single click ===========
    //
    /**
     * This function handles the logic for highlighting and un-highlighting nodes on single-click
     */
    function nodeClick (d) {
      console.log('===== Click Fired =====');
      d.isSelected = true; // Sets the node you clicked on to have a "selected" flag.
      let highlightedCount = -1; // this will count how many downstream nodes are highlighted.
      highlightedCount = downstreamHighlightCheck(d, highlightedCount);
      // If there are no downstream items and d is highlighted, un-highlight it.
      if (d.isHighlighted) {
        if (d.downstream && (highlightedCount !== d.downstream.length)) {
          highlightNodes(d);
        } else {
          unHighlightNodes(d);
        }
      } else {
        highlightNodes(d);
      }
      clickedOnce = false;  // This is for resetting the click flag
    }

    /**
     * This function will un-highlight d and the array of downstream nodes for d. This will NOT
     * un-highlight a node if all of it's children are highlighted (cycle checking)
     * @param {object} d
     */

    // TODO : Keep nodes with two highlighted upstream nodes highlighted on un-highlight with a count
    function unHighlightNodes (d) {
      d.isHighlighted = false;
      node.style('opacity', function (curNode) {
        let count = -1;
        if (d.downstream) {
          for (let i = 0; i < d.downstream.length; i++) {
            if (d.downstream[i].id === curNode.id) {
              downstreamHighlightCheck(curNode, count); // check downstream items for highlighting
            }
            if (count !== d.downstream.length && d.downstream[i].id === curNode.id) {
              curNode.isHighlighted = false;
            }
          }
        }
        return curNode.isHighlighted ? 1 : reducedOpacity;
      });

      path.style('opacity', function (curPath) {
        return (curPath.source.isHighlighted && curPath.target.isHighlighted) ? 1 : reducedOpacity;
      });
    }

    /**
     * This function will highlight the selected node "d" then highlight the nodes in it's downstream array
     * @param {object} d
     */
    function highlightNodes (d) {
      d.isHighlighted = true;
      node.style('opacity', function (curNode) {
        if (!d.noRelations) {
          for (let i = 0; i < d.downstream.length; i++) {
            if (d.downstream[i].id === curNode.id) {
              curNode.isHighlighted = true;
            }
          }
        }
        return curNode.isHighlighted ? 1 : reducedOpacity;
      });

      path.style('opacity', function (curPath) {
        return (curPath.source.isHighlighted && curPath.target.isHighlighted) ? 1 : reducedOpacity;
      });
    }

    /**
     * This function checks all the downstream items of your array to see if they are highlighted. This prevents
     * issues when we have a cycle and are un-highlighting nodes.
     * @param {object} d
     * @param {int} count
     */
    function downstreamHighlightCheck (d, count) {
      // This checks whether we should be highlighting or un-highlighting nodes
      d3.selectAll('g.node')  // Loops through all nodes and checks if they have downstream relations
        .each(function (curNode) {
          if (!d.noRelations) {
            for (let i = 0; i < d.downstream.length; i++) {
              // If the index matches and the node is already highlighted, increase our count.
              if (d.downstream[i].id === curNode.id) {
                if (curNode.isHighlighted) {
                  if (count === -1) {
                    count = 1;
                  } else {
                    count++;
                  }
                }
              }
            }
          }
        });
      return count;
    }

    // ============ Toggle collapsing nodes on Double click ===========
    /*
     * Node double click event hides all of the children nodes for double clicked node.
     *
     * @param {Object} clickedNode is the node that was clicked on
     */
    function nodeDoubleClick (clickedNode) {
      console.log('===== Double Click Fired =====');
      clickedOnce = false;  // For resetting the clickedOnce flag
      clearTimeout(timer);  // Reset the timer for click event
      collapse(clickedNode);
    }

    /*
     * Adds a downstream item and downstream edge to a given Node
     *
     * @param {Object} nodeItem is a node item
     * @param {Object} edge is an edge object that is going to be added to the nodeItem
     */
    function addDownstreamItemToNode (nodeItem, edge) {
      // Check if downstream items array exists
      if (typeof nodeItem.downstream === 'undefined') {
        nodeItem.downstream = [];
      }
      nodeItem.downstream.push(edge.target);  // Add the target ID to list of downstream items

      // Check if downstream Edges array exists
      if (typeof nodeItem.downstreamEdges === 'undefined') {
        nodeItem.downstreamEdges = [];
      }
      nodeItem.downstreamEdges.push(edge);  // Add the target ID to list of downstream items
      nodeItem.noRelations = false;
    }

    /*
     * Collapses all of the graph nodes downstream from the selected node
     *
     * param {Object} root is the object that is selected and whose downstream items will be toggled
     */
    function collapse (root) {
      console.log('Collapse Initiated');
      // Hide the node
      if (root.downstream && root.downstreamEdges) {
        root.downstream.forEach(function (item) {
          let selItem = d3.select("[id='" + item.id + "']");
          selItem.style('opacity', (selItem.style('opacity') == 0) ? 1 : 0);
        });

        root.downstreamEdges.forEach(function (item) {
          let selItem = d3.select("[id='" + item.id + "']");
          selItem.style('opacity', (selItem.style('opacity') == 0) ? 1 : 0);
        });
      }
    }
  }

  /*
   * Hides all of the graph nodes except the root id
   */
  /*
   * Hides all of the graph nodes except the root id
   */
  function collapseAll () {
    svg.selectAll('.node').style('opacity', function (item) {
      return item.id !== -1 ? 0 : 1;
    });
    d3.select('projectRoot').style('opacity', 1);  // Show the project node
    projectNode.downstream.forEach(function (item) {
      d3.select("[id='" + item.id + "']").style('opacity', 1);
    });

    let paths = svg.selectAll('path');
    paths.style('opacity', 0);
    projectNode.downstreamEdges.forEach(function (item) {
      d3.select("[id='" + item.id + "']").style('opacity', 1);
    });
  }
});
<commit_msg>Added a relationship between project node and selected node<commit_after>let fileName = '../js/ssProject.json'; // '../js/sampleGraphData.json'

// TODO: If a root id is passed, then we should add a relationship from the project node to the selected id node
// TODO: Add the project name as the first node in the nodes list of JSON being given

// get the data
d3.json(fileName, function (error, graphData) {
  if (error) {
    console.log(error);
  }

  let clickedOnce = false;  // For monitoring the click event on node
  let timer;                // For click event monitoring

  let width = 1000;
  let height = 800;
  let reducedOpacity = 0.2;

  // let nodes = {};
  let items = graphData.nodes;
  let itemRelations = graphData.edges;
  let relationsChecked = false;

  // Create a project node and add it to the items list
  let projectNode = { id: -1, name: graphData.name, image: '', type: -1 };
  items.unshift(projectNode);
  itemRelations.push({ id: -1, source: -1, target: rootID, type: -1 });
  projectNode = items[0];

  // ++++++++++++ Map all node edges +++++++++++++
  // nodeToEdgeMap is an array that uses id as the index for direct access
  let nodeToEdgeMap = {};

  items.forEach(function (item) {
    nodeToEdgeMap[item.id] = {};
    nodeToEdgeMap[item.id].node = item;
    nodeToEdgeMap[item.id].edges = itemRelations.filter(function (relItem) {
      if (relItem.source === item.id) {
        return relItem; // Filter all of the edges that have this item source id
      }
    });

    item.noRelations = true;
  });

  // Append the SVG object to the body
  // Add a group element within it to encompass all the nodes - this fixes the chrome
  let svg = d3.select('body').append('svg')
    .attr('width', '100%')
    .attr('height', height)
    .call(d3.behavior.zoom().scaleExtent([1, 10])
      .on('zoom', function () {
        svg.attr('transform', 'translate(' + d3.event.translate + ')' + ' scale(' + d3.event.scale + ')');
      }))
    .on('dblclick.zoom', null)  // To remove the double click zoom function
    .append('g');

  // ============ build the arrows ================
  svg.append('svg:defs').selectAll('marker')
    .data(['end'])      // Different link/path types can be defined here
    .enter().append('svg:marker')    // This section adds in the arrows
    .attr('id', String)
    .attr('viewBox', '0 -5 10 10')
    .attr('refX', 25)
    .attr('refY', -1.5)
    .attr('markerWidth', 6)
    .attr('markerHeight', 6)
    .attr('orient', 'auto')
    .append('svg:path')
    .attr('d', 'M0,-5L10,0L0,5')
    .attr('class', 'arrow');

  let force = d3.layout.force()
    .size([width, height])
    .linkDistance(100)  // sets the target distance between linked nodes to the specified value
    .charge(-1000)       // - value results in node repulsion, while + value results in node attraction
    .friction(0.8);     // closely approximates velocity decay

  updateGraph(rootID);  // Render the graph
  //collapseAll();
  /*
   * Updates the graph visuals
   * @param {Integer} rootId is the id of the element that is to be the root node coming off the project node
   */
  function updateGraph (passedId = -1) {
    if (!relationsChecked) {
      // For each relationship, add the target to the source node
      itemRelations.forEach(function (relItem) {
        // Find node object based on the relationship source id
        let srcNode = items.find(function (item) {
          return item.id === relItem.source;
        });

        // Set the relationship source and target values
        // Note - Use objects only and not just ids of the nodes
        relItem.source = srcNode;
        relItem.target = items.find(function (item) {
          return item.id === relItem.target;
        });

        addDownstreamItemToNode(srcNode, relItem);  // Check if downstream items array exists
      });

      // Check if there are relations for each node and set a flag
      items.forEach(function (item) {
        if (typeof item.downstream === 'undefined') {
          item.noRelations = true;
        } else {
          item.noRelations = (item.downstream.length === 0);
        }
      });

      relationsChecked = true;
    }

    // Checks to see if a node id was passed
    if (passedId !== -1) {
      // Get the root item from the items list
      let rootItem = items.find(function (item) {
        return item.id === passedId;
      });
      // Add an edge from the project node to the passed node
      itemRelations.unshift({id: 0, source: projectNode, target: rootItem, type: -1});

      addDownstreamItemToNode(projectNode, itemRelations[0]);  // Add downstream item to project node
    }

    // Set the force nodes, edges and start the graph
    force
      .nodes(graphData.nodes)
      .links(graphData.edges)
      .on('tick', tick)
      .start();

    // ============ edges combined with the arrows ===========
    let path = svg.append('svg:g').selectAll('path')
      .data(force.links())
      .enter().append('svg:path')
      .attr('id', function (d) {
        return d.id;  // Add an id element to each edge
      })
      .attr('class', thisPath => {
        let result = 'link';
        // Check the type and add a style according to type
        result = (thisPath.type === -1) ? result + ' link-dot' : result;
        result = (thisPath.type === 8) ? ' link-dash' : result;

        return result;
      })
      .attr('marker-end', 'url(#end)');

    // ============ Node Properties Definition ===========
    let node = svg.selectAll('.node')
      .data(force.nodes())
      .enter()
      .append('g')
      .attr('id', function (d) {
        return d.id;  // Add an id element to each node
      })
      .attr('class', function (thisNode) {
        // Add projectRoot class if the node is the project node
        return thisNode.id === -1 ? 'node projectRoot' : 'node';
      })
      .call(force.drag)
      .on('click', function (d) {
        if (clickedOnce) {
          nodeDoubleClick(d);  // Call the single click function
        } else {
          timer = setTimeout(function () {
            nodeClick(d); // Call the double click function
          }, 175);
          clickedOnce = true;
        }
      });

    projectNode.fixed = true;  // Set the project Node to be fixed and not moving
    projectNode.x = height / 2;
    projectNode.y = width / 2;

    // White rectangle behind text configuration
    node.append('rect')
      .attr('x', -8)
      .attr('y', -9)
      .attr('height', 19)
      .attr('width', 120)
      .style('opacity', 0.80);

    // Circle at node behind icon configuration
    node.append('circle')
      .attr('x', '-14px')
      .attr('y', '-14px')
      .attr('r', 13)
      .style('opacity', 0.80);

    // Image in the node circle configuration
    node.append('image')
      .attr('xlink:href', function (n) {
        return n.image;
      })
      .attr('x', '-9px')
      .attr('y', '-9px')
      .attr('height', '18px')
      .attr('width', '18px');

    // Add Text for hovering that shows full filename
    node.append('svg:title')
      .text(function (d) {
        return (d.id + ' - ' + d.name);
      });

    // Add the name of the node as text
    node.append('text')
      .attr('x', 18)
      .attr('dy', '.35em')
      .attr('class', 'nodeText')
      .text(function (d) {
        // Limit the length of the name text
        return d.name.length > 18 ? d.name.substring(0, 15) + '...' : d.name;
      });

    // ============= Node Path Definitions ==============
    /*
     * For every shift of the graph, this gets called.
     * It updates the location of the nodes and edges.
     *
     * @param {Object} e
     */
    function tick (e) {
      path.attr('d', function (d) {
        let dx = d.target.x - d.source.x;
        let dy = d.target.y - d.source.y;
        let dr = Math.sqrt(dx * dx + dy * dy);

        return 'M' + d.source.x + ',' + d.source.y + 'A' +
          dr + ',' + dr + ' 0 0,1 ' + d.target.x + ',' + d.target.y;
      });

      // Move the edge depending on node location
      node.attr('transform', function (d) {
        return 'translate(' + d.x + ',' + d.y + ')';
      });

      let k = 10 * e.alpha; // For the node offset

      // This section pushes sources up and targets down to form a weak tree-like structure.
      path.each(function (d) {
        d.source.x -= k;
        d.target.x += k;
      }).attr('x1', function (d) { return d.source.x; })
        .attr('y1', function (d) { return d.source.y; })
        .attr('x2', function (d) { return d.target.x; })
        .attr('y2', function (d) { return d.target.y; });

      // This sets the node position
      node.attr('cx', function (d) { return 5 * d.x; })
          .attr('cy', function (d) { return d.y; });
    }

    //
    // ============ Toggle highlighting nodes on single click ===========
    //
    /**
     * This function handles the logic for highlighting and un-highlighting nodes on single-click
     */
    function nodeClick (d) {
      console.log('===== Click Fired =====');
      d.isSelected = true; // Sets the node you clicked on to have a "selected" flag.
      let highlightedCount = -1; // this will count how many downstream nodes are highlighted.
      highlightedCount = downstreamHighlightCheck(d, highlightedCount);
      // If there are no downstream items and d is highlighted, un-highlight it.
      if (d.isHighlighted) {
        if (d.downstream && (highlightedCount !== d.downstream.length)) {
          highlightNodes(d);
        } else {
          unHighlightNodes(d);
        }
      } else {
        highlightNodes(d);
      }
      clickedOnce = false;  // This is for resetting the click flag
    }

    /**
     * This function will un-highlight d and the array of downstream nodes for d. This will NOT
     * un-highlight a node if all of it's children are highlighted (cycle checking)
     * @param {object} d
     */

    // TODO : Keep nodes with two highlighted upstream nodes highlighted on un-highlight with a count
    function unHighlightNodes (d) {
      d.isHighlighted = false;
      node.style('opacity', function (curNode) {
        let count = -1;
        if (d.downstream) {
          for (let i = 0; i < d.downstream.length; i++) {
            if (d.downstream[i].id === curNode.id) {
              downstreamHighlightCheck(curNode, count); // check downstream items for highlighting
            }
            if (count !== d.downstream.length && d.downstream[i].id === curNode.id) {
              curNode.isHighlighted = false;
            }
          }
        }
        return curNode.isHighlighted ? 1 : reducedOpacity;
      });

      path.style('opacity', function (curPath) {
        return (curPath.source.isHighlighted && curPath.target.isHighlighted) ? 1 : reducedOpacity;
      });
    }

    /**
     * This function will highlight the selected node "d" then highlight the nodes in it's downstream array
     * @param {object} d
     */
    function highlightNodes (d) {
      d.isHighlighted = true;
      node.style('opacity', function (curNode) {
        if (!d.noRelations) {
          for (let i = 0; i < d.downstream.length; i++) {
            if (d.downstream[i].id === curNode.id) {
              curNode.isHighlighted = true;
            }
          }
        }
        return curNode.isHighlighted ? 1 : reducedOpacity;
      });

      path.style('opacity', function (curPath) {
        return (curPath.source.isHighlighted && curPath.target.isHighlighted) ? 1 : reducedOpacity;
      });
    }

    /**
     * This function checks all the downstream items of your array to see if they are highlighted. This prevents
     * issues when we have a cycle and are un-highlighting nodes.
     * @param {object} d
     * @param {int} count
     */
    function downstreamHighlightCheck (d, count) {
      // This checks whether we should be highlighting or un-highlighting nodes
      d3.selectAll('g.node')  // Loops through all nodes and checks if they have downstream relations
        .each(function (curNode) {
          if (!d.noRelations) {
            for (let i = 0; i < d.downstream.length; i++) {
              // If the index matches and the node is already highlighted, increase our count.
              if (d.downstream[i].id === curNode.id) {
                if (curNode.isHighlighted) {
                  if (count === -1) {
                    count = 1;
                  } else {
                    count++;
                  }
                }
              }
            }
          }
        });
      return count;
    }

    // ============ Toggle collapsing nodes on Double click ===========
    /*
     * Node double click event hides all of the children nodes for double clicked node.
     *
     * @param {Object} clickedNode is the node that was clicked on
     */
    function nodeDoubleClick (clickedNode) {
      console.log('===== Double Click Fired =====');
      clickedOnce = false;  // For resetting the clickedOnce flag
      clearTimeout(timer);  // Reset the timer for click event
      collapse(clickedNode);
    }

    /*
     * Adds a downstream item and downstream edge to a given Node
     *
     * @param {Object} nodeItem is a node item
     * @param {Object} edge is an edge object that is going to be added to the nodeItem
     */
    function addDownstreamItemToNode (nodeItem, edge) {
      // Check if downstream items array exists
      if (typeof nodeItem.downstream === 'undefined') {
        nodeItem.downstream = [];
      }
      nodeItem.downstream.push(edge.target);  // Add the target ID to list of downstream items

      // Check if downstream Edges array exists
      if (typeof nodeItem.downstreamEdges === 'undefined') {
        nodeItem.downstreamEdges = [];
      }
      nodeItem.downstreamEdges.push(edge);  // Add the target ID to list of downstream items
      nodeItem.noRelations = false;
    }

    /*
     * Collapses all of the graph nodes downstream from the selected node
     *
     * param {Object} root is the object that is selected and whose downstream items will be toggled
     */
    function collapse (root) {
      console.log('Collapse Initiated');
      // Hide the node
      if (root.downstream && root.downstreamEdges) {
        root.downstream.forEach(function (item) {
          let selItem = d3.select("[id='" + item.id + "']");
          selItem.style('opacity', (selItem.style('opacity') == 0) ? 1 : 0);
        });

        root.downstreamEdges.forEach(function (item) {
          let selItem = d3.select("[id='" + item.id + "']");
          selItem.style('opacity', (selItem.style('opacity') == 0) ? 1 : 0);
        });
      }
    }
  }

  /*
   * Hides all of the graph nodes except the root id
   */
  /*
   * Hides all of the graph nodes except the root id
   */
  function collapseAll () {
    svg.selectAll('.node').style('opacity', function (item) {
      return item.id !== -1 ? 0 : 1;
    });
    d3.select('projectRoot').style('opacity', 1);  // Show the project node
    projectNode.downstream.forEach(function (item) {
      d3.select("[id='" + item.id + "']").style('opacity', 1);
    });

    let paths = svg.selectAll('path');
    paths.style('opacity', 0);
    projectNode.downstreamEdges.forEach(function (item) {
      d3.select("[id='" + item.id + "']").style('opacity', 1);
    });
  }
});
<|endoftext|>


<commit_before>/**
 * @file Triggers host specific boot
 * @since 0.2.1
 */
/*#ifndef(UMD)*/
"use strict";
/*global _gpfBootImplByHost*/ // Boot host specific implementation per host
/*global _gpfHost*/ // Host type
/*#endif*/

_gpfBootImplByHost[_gpfHost]();
<commit_msg>Host declaration<commit_after>/**
 * @file Triggers host specific boot
 * @since 0.2.1
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GPF_HOST*/ // Host types
/*global _gpfBootImplByHost*/ // Boot host specific implementation per host
/*global _gpfHost*/ // Host type
/*#endif*/

_gpfBootImplByHost[_gpfHost]();

/**
 * Host type enumeration
 *
 * @enum {String}
 * @readonly
 * @since 0.1.5
 */
gpf.hosts = {
    /**
     * Any browser (phantomjs is recognized separately)
     * @since 0.1.5
     */
    browser: _GPF_HOST.BROWSER,
    /**
     * [Nashorn](https://en.wikipedia.org/wiki/Nashorn_%28JavaScript_engine%29)
     * @since 0.2.4
     */
    nashorn: _GPF_HOST.NASHORN,
    /**
     * [NodeJs](http://nodejs.org/)
     * @since 0.1.5
     */
    nodejs: _GPF_HOST.NODEJS,
    /**
     * [PhantomJS](http://phantomjs.org/)
     * @since 0.1.5
     */
    phantomjs: _GPF_HOST.PHANTOMJS,
    /**
     * [Rhino](http://developer.mozilla.org/en/docs/Rhino)
     * @since 0.1.5
     */
    rhino: _GPF_HOST.RHINO,
    /**
     * Unknown (detection failed or the host is unknown)
     * @since 0.1.5
     */
    unknown: _GPF_HOST.UNKNOWN,
    /**
     * [cscript/wscript](http://technet.microsoft.com/en-us/library/bb490887.aspx)
     * @since 0.1.5
     */
    wscript: _GPF_HOST.WSCRIPT
};

/**
 * Returns the detected host type
 *
 * @return {gpf.hosts} Host type
 * @since 0.1.5
 */
gpf.host = function () {
    return _gpfHost;
};
<|endoftext|>


<commit_before>'use strict';
var rc_util = require('./lib/utility.js');
var _ = require('lodash');

function getAvgIn(degrees) {
  var sum = 0;
  _.each(degrees, function(rippled) {
    sum += parseInt(rippled.in, 10);
  });

  return sum / Object.keys(degrees).length;
}

function getAvgOut(degrees) {
  var sum = 0;
  _.each(degrees, function(rippled) {
    sum += parseInt(rippled.out, 10);
  });
  return sum / Object.keys(degrees).length;
}

module.exports = function(dbUrl, id, commander) {
  return new Promise(function(resolve, reject) {
    id = parseInt(id, 10);
    rc_util.getRowById(dbUrl, id, commander.logsql).then(function(row) {
      var body = JSON.parse(row.data);
      var results = {entry: row.entry_ipp,
                     general: {},
                     rippleds: {},
                     links: {},
                     degrees: {},
                     versions: {},
                     locations: {}};

      results.rippleds = rc_util.getRippledsC(body);

      results.versions = rc_util.getVersions(body);

      results.locations = rc_util.getLocations(body);

      results.links = rc_util.getLinks(body);

      results.degrees = rc_util.getDegrees(body);

      results.general.nodes = Object.keys(results.rippleds).length;
      results.general.links = Object.keys(results.links).length;
      results.general.versions = Object.keys(results.versions).length;
      results.general.locations = Object.keys(results.locations).length;
      results.general.avgIn = getAvgIn(results.degrees);
      results.general.avgOut = getAvgOut(results.degrees);

      console.log(results);
    }).catch(function(error) {
      reject(error);
    });
  });
};
<commit_msg>minor cleanup<commit_after>'use strict';
var rc_util = require('./lib/utility.js');
var _ = require('lodash');

function getAvgIn(degrees) {
  var sum = 0;
  _.each(degrees, function(rippled) {
    sum += parseInt(rippled.in, 10);
  });

  return sum / Object.keys(degrees).length;
}

function getAvgOut(degrees) {
  var sum = 0;
  _.each(degrees, function(rippled) {
    sum += parseInt(rippled.out, 10);
  });
  return sum / Object.keys(degrees).length;
}

module.exports = function(dbUrl, id, commander) {
  return new Promise(function(resolve, reject) {
    id = parseInt(id, 10);
    rc_util.getRowById(dbUrl, id, commander.logsql).then(function(row) {
      var body = JSON.parse(row.data);
      var results = {entry: row.entry_ipp,
                     general: {},
                     rippleds: {},
                     links: {},
                     degrees: {},
                     versions: {},
                     locations: {}};

      results.rippleds = rc_util.getRippledsC(body);

      results.versions = rc_util.getVersions(body);

      results.locations = rc_util.getLocations(body);

      results.links = rc_util.getLinks(body);

      results.degrees = rc_util.getDegrees(body);

      results.general.nodes = Object.keys(results.rippleds).length;
      results.general.links = Object.keys(results.links).length;
      results.general.versions = Object.keys(results.versions).length;
      results.general.locations = Object.keys(results.locations).length;
      results.general.avgIn = getAvgIn(results.degrees);
      results.general.avgOut = getAvgOut(results.degrees);

      console.log(results);
    }).catch(reject);
  });
};
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2012, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint anon:true, sloppy:true, nomen:true, node: true*/
/*global YUI*/

/**
 * @module ActionContextAddon
 */
YUI.add('mojito-deploy-addon', function(Y, NAME) {

    'use strict';

    var fs = require('fs'),
        REGEX_LANG_TOKEN = /\{langToken\}/g;

    /**
     * Access point: ac.deploy.*
     * Provides ability to create client runtime deployment HTML
     * @class Deploy.server
     */
    function Addon(command, adapter, ac) {
        this.instance = command.instance;
        this.scripts = {};
        this.ac = ac;
        this.rs = null;
    }

    Addon.prototype = {

        namespace: 'deploy',

        /**
         * Declaration of store requirement.
         * @method setStore
         * @private
         * @param {ResourceStore} rs The resource store instance.
         */
        setStore: function(rs) {
            this.rs = rs;
        },

        /**
         * Builds up the browser Mojito runtime.
         * @method constructMojitoClientRuntime
         * @param {AssetHandler} assetHandler asset handler used to add scripts
         *     to the DOM under construction.
         * @param {object} binderMap information about the binders that will be
         *     deployed to the client.
         */
        constructMojitoClientRuntime: function(assetHandler, binderMap) {

            //Y.log('Constructing Mojito client runtime', 'debug', NAME);

            var store = this.rs,
                contextServer = this.ac.context,
                appConfigServer = store.getAppConfig(contextServer),
                appGroupConfig = store.yui.getAppGroupConfig(),
                seed = appGroupConfig.seed || [],
                contextClient,
                appConfigClient,
                yuiConfig = {},
                yuiConfigEscaped,
                yuiConfigStr,
                closestLang = store.yui.getClosestLang(contextServer.lang),
                viewId,
                i,
                clientConfig = {},
                clientConfigEscaped,
                clientConfigStr,
                initialModuleList = {},
                initializer, // script for YUI initialization
                pathToRoot;

            contextClient = Y.mojito.util.copy(contextServer);
            contextClient.runtime = 'client';
            appConfigClient = store.getAppConfig(contextClient);
            clientConfig.context = contextClient;

            // The seed files collection is lang aware, hence we should adjust
            // is on runtime.
            for (i = 0; i < seed.length; i += 1) {
                // adjusting the seed based on {langToken} to facilitate
                // the customization of the seed file url per lang.
                seed[i] = seed[i].replace(REGEX_LANG_TOKEN, (closestLang ? '_' + closestLang : ''));
            }

            yuiConfig = Y.merge({

                fetchCSS: true,
                combine: true,
                // the base path for non-combo paths
                base: 'http://yui.yahooapis.com/' + Y.version + '/build/',
                // the path to the combo service
                comboBase: 'http://yui.yahooapis.com/combo?',
                // a fragment to prepend to the path attribute when
                // when building combo urls
                root: Y.version + '/build/',
                groups: {
                    app: appGroupConfig
                }
            }, ((appConfigClient.yui && appConfigClient.yui.config) || {}), {
                lang: contextServer.lang // same as contextClient.lang
            });
            // yui.config goes through a different channel (yuiConfig),
            // so we should remove it from the appConfigClient.
            if (appConfigClient.yui.config) {
                delete appConfigClient.yui.config;
            }

            // Set the YUI seed file to use on the client. This has to be done
            // before any other scripts are added and can be controlled through
            // application.json->yui->config->groups->app->seed in a form of
            // a array with the list of relative paths for all seed files.
            if (appGroupConfig.combine === false) {

                // if the combo is disabled, then we need to insert one by one
                // this is useful for offline and hybrid apps where the combo
                // does not work.
                for (i = 0; i < seed.length; i += 1) {
                    assetHandler.addAsset('js', 'top', appGroupConfig.base +
                        appGroupConfig.root + seed[i]);
                }

            } else {

                // using combo for the seed files
                assetHandler.addAsset('js', 'top', appGroupConfig.comboBase +
                    appGroupConfig.root + seed.join('&' + appGroupConfig.root));

            }

            // adding the default module for the Y.use statement in the client
            initialModuleList['mojito-client'] = true;

            // add binders' dependencies
            for (viewId in binderMap) {
                if (binderMap.hasOwnProperty(viewId)) {
                    if (binderMap[viewId].name) {
                        initialModuleList[binderMap[viewId].name] = true;
                    }
                }
            }

            clientConfig.binderMap = binderMap;

            // we need the app config on the client for log levels (at least)
            clientConfig.appConfig = appConfigClient;

            // this is mainly used by html5app
            pathToRoot = this.ac.http.getHeader('x-mojito-build-path-to-root');
            if (pathToRoot) {
                clientConfig.pathToRoot = pathToRoot;
            }

            clientConfig.routes = this.ac.url.getRouteMaker().getComputedRoutes();

            // Unicode escape the various strings in the config data to help
            // fight against possible script injection attacks.
            yuiConfigEscaped = Y.mojito.util.cleanse(yuiConfig);
            yuiConfigStr = JSON.stringify(yuiConfigEscaped);
            clientConfigEscaped = Y.mojito.util.cleanse(clientConfig);
            clientConfigStr = JSON.stringify(clientConfigEscaped);

            initialModuleList = "'" + Y.Object.keys(initialModuleList).join("','") + "'";

            initializer = '\n';

            // Add the boot script
            assetHandler.addAsset('blob', 'bottom', initializer);
        }

    };

    Y.namespace('mojito.addons.ac').deploy = Addon;

}, '0.1.0', {requires: [
    'mojito-util',
    'mojito-http-addon',
    'mojito-url-addon'
]});
<commit_msg>adding support for seed in a form of string in case shaker need it<commit_after>/*
 * Copyright (c) 2011-2012, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint anon:true, sloppy:true, nomen:true, node: true*/
/*global YUI*/

/**
 * @module ActionContextAddon
 */
YUI.add('mojito-deploy-addon', function(Y, NAME) {

    'use strict';

    var fs = require('fs'),
        REGEX_LANG_TOKEN = /\{langToken\}/g;

    /**
     * Access point: ac.deploy.*
     * Provides ability to create client runtime deployment HTML
     * @class Deploy.server
     */
    function Addon(command, adapter, ac) {
        this.instance = command.instance;
        this.scripts = {};
        this.ac = ac;
        this.rs = null;
    }

    Addon.prototype = {

        namespace: 'deploy',

        /**
         * Declaration of store requirement.
         * @method setStore
         * @private
         * @param {ResourceStore} rs The resource store instance.
         */
        setStore: function(rs) {
            this.rs = rs;
        },

        /**
         * Builds up the browser Mojito runtime.
         * @method constructMojitoClientRuntime
         * @param {AssetHandler} assetHandler asset handler used to add scripts
         *     to the DOM under construction.
         * @param {object} binderMap information about the binders that will be
         *     deployed to the client.
         */
        constructMojitoClientRuntime: function(assetHandler, binderMap) {

            //Y.log('Constructing Mojito client runtime', 'debug', NAME);

            var store = this.rs,
                contextServer = this.ac.context,
                appConfigServer = store.getAppConfig(contextServer),
                appGroupConfig = store.yui.getAppGroupConfig(),
                seed = Y.Array(appGroupConfig.seed),
                contextClient,
                appConfigClient,
                yuiConfig = {},
                yuiConfigEscaped,
                yuiConfigStr,
                closestLang = store.yui.getClosestLang(contextServer.lang),
                viewId,
                i,
                clientConfig = {},
                clientConfigEscaped,
                clientConfigStr,
                initialModuleList = {},
                initializer, // script for YUI initialization
                pathToRoot;

            contextClient = Y.mojito.util.copy(contextServer);
            contextClient.runtime = 'client';
            appConfigClient = store.getAppConfig(contextClient);
            clientConfig.context = contextClient;

            // The seed files collection is lang aware, hence we should adjust
            // is on runtime.
            for (i = 0; i < seed.length; i += 1) {
                // adjusting the seed based on {langToken} to facilitate
                // the customization of the seed file url per lang.
                seed[i] = seed[i].replace(REGEX_LANG_TOKEN, (closestLang ? '_' + closestLang : ''));
            }

            yuiConfig = Y.merge({

                fetchCSS: true,
                combine: true,
                // the base path for non-combo paths
                base: 'http://yui.yahooapis.com/' + Y.version + '/build/',
                // the path to the combo service
                comboBase: 'http://yui.yahooapis.com/combo?',
                // a fragment to prepend to the path attribute when
                // when building combo urls
                root: Y.version + '/build/',
                groups: {
                    app: appGroupConfig
                }
            }, ((appConfigClient.yui && appConfigClient.yui.config) || {}), {
                lang: contextServer.lang // same as contextClient.lang
            });
            // yui.config goes through a different channel (yuiConfig),
            // so we should remove it from the appConfigClient.
            if (appConfigClient.yui.config) {
                delete appConfigClient.yui.config;
            }

            // Set the YUI seed file to use on the client. This has to be done
            // before any other scripts are added and can be controlled through
            // application.json->yui->config->groups->app->seed in a form of
            // a array with the list of relative paths for all seed files.
            if (appGroupConfig.combine === false) {

                // if the combo is disabled, then we need to insert one by one
                // this is useful for offline and hybrid apps where the combo
                // does not work.
                for (i = 0; i < seed.length; i += 1) {
                    assetHandler.addAsset('js', 'top', appGroupConfig.base +
                        appGroupConfig.root + seed[i]);
                }

            } else {

                // using combo for the seed files
                assetHandler.addAsset('js', 'top', appGroupConfig.comboBase +
                    appGroupConfig.root + seed.join('&' + appGroupConfig.root));

            }

            // adding the default module for the Y.use statement in the client
            initialModuleList['mojito-client'] = true;

            // add binders' dependencies
            for (viewId in binderMap) {
                if (binderMap.hasOwnProperty(viewId)) {
                    if (binderMap[viewId].name) {
                        initialModuleList[binderMap[viewId].name] = true;
                    }
                }
            }

            clientConfig.binderMap = binderMap;

            // we need the app config on the client for log levels (at least)
            clientConfig.appConfig = appConfigClient;

            // this is mainly used by html5app
            pathToRoot = this.ac.http.getHeader('x-mojito-build-path-to-root');
            if (pathToRoot) {
                clientConfig.pathToRoot = pathToRoot;
            }

            clientConfig.routes = this.ac.url.getRouteMaker().getComputedRoutes();

            // Unicode escape the various strings in the config data to help
            // fight against possible script injection attacks.
            yuiConfigEscaped = Y.mojito.util.cleanse(yuiConfig);
            yuiConfigStr = JSON.stringify(yuiConfigEscaped);
            clientConfigEscaped = Y.mojito.util.cleanse(clientConfig);
            clientConfigStr = JSON.stringify(clientConfigEscaped);

            initialModuleList = "'" + Y.Object.keys(initialModuleList).join("','") + "'";

            initializer = '\n';

            // Add the boot script
            assetHandler.addAsset('blob', 'bottom', initializer);
        }

    };

    Y.namespace('mojito.addons.ac').deploy = Addon;

}, '0.1.0', {requires: [
    'mojito-util',
    'mojito-http-addon',
    'mojito-url-addon'
]});
<|endoftext|>


<commit_before>/** @license
 * RequireJS plugin for loading JSON files
 * - depends on Text plugin and it was HEAVILY "inspired" by it as well.
 * Author: Miller Medeiros
 * Version: 0.4.0 (2014/04/10)
 * Released under the MIT license
 */
define(['text'], function(text){

    var CACHE_BUST_QUERY_PARAM = 'bust',
        CACHE_BUST_FLAG = '!bust',
        jsonParse = (typeof JSON !== 'undefined' && typeof JSON.parse === 'function')? JSON.parse : function(val){
            return eval('('+ val +')'); //quick and dirty
        },
        buildMap = {};

    function cacheBust(url){
        url = url.replace(CACHE_BUST_FLAG, '');
        url += (url.indexOf('?') < 0)? '?' : '&';
        return url + CACHE_BUST_QUERY_PARAM +'='+ Math.round(2147483647 * Math.random());
    }

    //API
    return {

        load : function(name, req, onLoad, config) {
            if (( config.isBuild && (config.inlineJSON === false || name.indexOf(CACHE_BUST_QUERY_PARAM +'=') !== -1)) || (req.toUrl(name).indexOf('empty:') === 0)) {
                //avoid inlining cache busted JSON or if inlineJSON:false
                //and don't inline files marked as empty!
                onLoad(null);
            } else {
                text.get(req.toUrl(name), function(data){
                    if (config.isBuild) {
                        buildMap[name] = data;
                        onLoad(data);
                    } else {
                        onLoad(jsonParse(data));
                    }
                },
                    onLoad.error, {
                        accept: 'application/json'
                    }
                );
            }
        },

        normalize : function (name, normalize) {
            // used normalize to avoid caching references to a "cache busted" request
            if (name.indexOf(CACHE_BUST_FLAG) !== -1) {
                name = cacheBust(name);
            }
            // resolve any relative paths
            return normalize(name);
        },

        //write method based on RequireJS official text plugin by James Burke
        //https://github.com/jrburke/requirejs/blob/master/text.js
        write : function(pluginName, moduleName, write){
            if(moduleName in buildMap){
                var content = buildMap[moduleName];
                write('define("'+ pluginName +'!'+ moduleName +'", function(){ return '+ content +';});\n');
            }
        }

    };
});
<commit_msg>Call onload.error if JSON parsing fails.<commit_after>/** @license
 * RequireJS plugin for loading JSON files
 * - depends on Text plugin and it was HEAVILY "inspired" by it as well.
 * Author: Miller Medeiros
 * Version: 0.4.0 (2014/04/10)
 * Released under the MIT license
 */
define(['text'], function(text){

    var CACHE_BUST_QUERY_PARAM = 'bust',
        CACHE_BUST_FLAG = '!bust',
        jsonParse = (typeof JSON !== 'undefined' && typeof JSON.parse === 'function')? JSON.parse : function(val){
            return eval('('+ val +')'); //quick and dirty
        },
        buildMap = {};

    function cacheBust(url){
        url = url.replace(CACHE_BUST_FLAG, '');
        url += (url.indexOf('?') < 0)? '?' : '&';
        return url + CACHE_BUST_QUERY_PARAM +'='+ Math.round(2147483647 * Math.random());
    }

    //API
    return {

        load : function(name, req, onLoad, config) {
            if (( config.isBuild && (config.inlineJSON === false || name.indexOf(CACHE_BUST_QUERY_PARAM +'=') !== -1)) || (req.toUrl(name).indexOf('empty:') === 0)) {
                //avoid inlining cache busted JSON or if inlineJSON:false
                //and don't inline files marked as empty!
                onLoad(null);
            } else {
                text.get(req.toUrl(name), function(data){
                    var parsed;
                    if (config.isBuild) {
                        buildMap[name] = data;
                        onLoad(data);
                    } else {
                        try {
                            parsed = jsonParse(data);
                        } catch (e) {
                            onLoad.error(e);
                        }
                        onLoad(parsed);
                    }
                },
                    onLoad.error, {
                        accept: 'application/json'
                    }
                );
            }
        },

        normalize : function (name, normalize) {
            // used normalize to avoid caching references to a "cache busted" request
            if (name.indexOf(CACHE_BUST_FLAG) !== -1) {
                name = cacheBust(name);
            }
            // resolve any relative paths
            return normalize(name);
        },

        //write method based on RequireJS official text plugin by James Burke
        //https://github.com/jrburke/requirejs/blob/master/text.js
        write : function(pluginName, moduleName, write){
            if(moduleName in buildMap){
                var content = buildMap[moduleName];
                write('define("'+ pluginName +'!'+ moduleName +'", function(){ return '+ content +';});\n');
            }
        }

    };
});
<|endoftext|>


<commit_before>import fragment from 'Html-Fragment';
import kiteHtml from './kite.html';
import css from './kite.css';
import {getAnchor} from './utils';
import {positioner} from "./positioner";

let allKiteInstances = [];

function addOrRemoveWindowEvents() {
	let kitesShowing = allKiteInstances.filter(kite => kite.showing);
	if (kitesShowing.length) {
		window.addEventListener('click', windowClick);
	}
	else {
		window.removeEventListener('click', windowClick);
	}
}

function windowClick(e) {
	let anchorOrKiteElement = allKiteInstances.find(kite => {
		return (kite.anchor.contains(e.target) || kite.kite.contains(e.target))
	});

	Kite.each(kite => {
		if (kite !== anchorOrKiteElement) {
			kite.hide();
		}
	});
}

class Kite {
	constructor(anchorElementOrSelector, options) {
		allKiteInstances.push(this);
		this.anchor = getAnchor(anchorElementOrSelector);
		this.options = Object.assign({
			position: 'top',
			closeX: true,
			html: ''
		}, options);

		this.attached = false;
		this.kite = fragment(kiteHtml).firstChild;
		this.distance = 10;
		this.showing = false;

		this.kite.querySelector('.js-kite-content').innerHTML = this.options.html;
		this.anchor.addEventListener('click', this.show.bind(this));
	}

	show() {
		css.use();
		document.body.appendChild(this.kite);

		this.showing = true;
		this.attached = true;

		this.kite.classList.add('Kite--show');
		this.position();
		addOrRemoveWindowEvents();
	}

	hide() {
		this.showing = false;
		this.kite.classList.remove('Kite--show');
		this.kite.style.zIndex = 'auto';
		addOrRemoveWindowEvents();
	}

	position() {
		positioner.call(this);
	}

	destroy() {

	}

	static get fn() {
		return this.prototype;
	}

	static create(...args) {
		return new Kite(...args);
	}

	static each(cb) {
		allKiteInstances.forEach(cb);
	}
}

export default Kite;
<commit_msg>Always close when click occurs in element with "data-kite-close" attribute<commit_after>import fragment from 'Html-Fragment';
import kiteHtml from './kite.html';
import css from './kite.css';
import {getAnchor} from './utils';
import {positioner} from "./positioner";

let allKiteInstances = [];

function addOrRemoveWindowEvents() {
	let kitesShowing = allKiteInstances.filter(kite => kite.showing);
	if (kitesShowing.length) {
		window.addEventListener('click', windowClick);
	}
	else {
		window.removeEventListener('click', windowClick);
	}
}

function windowClick(e) {
	let shoudClose = !!e.srcElement.closest('[data-kite-close]');
	let anchorOrKiteElement;

	if (!shoudClose) {
		anchorOrKiteElement = allKiteInstances.find(kite => {
			return (kite.anchor.contains(e.srcElement) || kite.kite.contains(e.srcElement));
		});
	}

	Kite.each(kite => {
		if (kite !== anchorOrKiteElement) {
			kite.hide();
		}
	});
}

class Kite {
	constructor(anchorElementOrSelector, options) {
		allKiteInstances.push(this);
		this.anchor = getAnchor(anchorElementOrSelector);
		this.options = Object.assign({
			position: 'top',
			closeX: true,
			html: ''
		}, options);

		this.attached = false;
		this.kite = fragment(kiteHtml).firstChild;
		this.distance = 10;
		this.showing = false;

		this.kite.querySelector('.js-kite-content').innerHTML = this.options.html;
		this.anchor.addEventListener('click', this.show.bind(this));
	}

	show() {
		css.use();
		document.body.appendChild(this.kite);

		this.showing = true;
		this.attached = true;

		this.kite.classList.add('Kite--show');
		this.position();
		addOrRemoveWindowEvents();
	}

	hide() {
		this.showing = false;
		this.kite.classList.remove('Kite--show');
		this.kite.style.zIndex = 'auto';
		addOrRemoveWindowEvents();
	}

	position() {
		positioner.call(this);
	}

	destroy() {

	}

	static get fn() {
		return this.prototype;
	}

	static create(...args) {
		return new Kite(...args);
	}

	static each(cb) {
		allKiteInstances.forEach(cb);
	}
}

export default Kite;
<|endoftext|>


<commit_before>import {connectAdvanced} from "react-redux";
import getOr from "lodash/fp/getOr";
import updateIn from "lodash/fp/update";
import mapValues from "lodash/fp/mapValues";
import pick from "lodash/fp/pick";
import flattenDeep from "lodash/fp/flattenDeep";
import updateObject from "updeep/dist/update";
const mapValuesWithKey = mapValues.convert({cap: false});

export function composeReducers(...reducers) {
    return (state=null, action) => {
        return reducers.filter(r => typeof r === "function").reduce(
            ((state, subReducer) => subReducer(state, action)),
            state
        );
    };
}

function disableLodashPath(path) {
    if (typeof path === "string") {
        return [path];
    }

    return path;
}

export function update(...args) {
    let scope, update;

    if (args.length === 2) {
        [scope, update] = args;
    } else {
        update = args[0];
    }

    return {
        type: "LEAN_UPDATE",
        scope,
        update,
    };
}

const plain = {};
const withSlash = s => s ? ("/" + s) : "";

export function thunk(cb) {
    return {_thunk: cb};
}
export function connectLean(options=plain) {
    return connectAdvanced(dispatch => {
        const initialState = typeof options.getInitialState === "function"
            ? options.getInitialState()
            : plain;

        var boundHandlersCache = null;
        var propsCache = null;
        var prevScope = {}; // Just some object with unique identity
        const getProps = () => propsCache;

        var mapState = typeof options.mapState === "function"
            ? options.mapState
            : pick(Object.keys(initialState));

        const handlers = typeof options.handlers === "function"
            ? options.handlers(getProps)
            : options.handlers;

        return (fullState, ownProps) => {
            var scope = ownProps.scope || options.scope;
            if (Array.isArray(scope)) {
                scope = flattenDeep(scope);
            }

            var scopedState = fullState || plain;

            if (scope) {
                scopedState = {...getOr(plain, disableLodashPath(scope), fullState), scope};
            }

            scopedState = {...initialState, ...scopedState};

            // Implement React Redux style advanced performance pattern where
            // the mapState can create the mapState function itself
            let _state =  mapState(scopedState, ownProps);
            if (typeof _state === "function") {
                // map state generated a new mapState function. Save it
                mapState = _state;
                // and use it to map the state
                _state =  mapState(scopedState, ownProps);
            }
            scopedState = _state;

            // Regenerate handlers only when the scope changes
            if (prevScope !== scope) {
                prevScope = scope;
                const dispatchUpdate = (updateName, update) => {
                    if (!update) {
                        return;
                    }

                    if (update && typeof update._thunk === "function") {
                        return update._thunk(dispatchUpdate.bind(null, updateName), getProps);
                    }
                    var actionSuffix = scope;
                    if (Array.isArray(actionSuffix)) {
                        actionSuffix = actionSuffix.join(".");
                    }

                    dispatch({
                        type: "LEAN_UPDATE" + withSlash(actionSuffix) + withSlash(updateName),
                        update,
                        initialState,
                        scope,
                    });
                };

                const bindDispatch = (updateFn, updateName) => (...args) => dispatchUpdate(updateName, updateFn(...args.concat(propsCache)));

                boundHandlersCache = mapValuesWithKey(bindDispatch, handlers);
            }

            return propsCache = {...ownProps, ...scopedState, ...boundHandlersCache, scope};
        };

    }, {
        getDisplayName: name => "ConnectLean(" + name + ")",
    });
}

const actionPattern = /^LEAN_UPDATE/;

export function leanReducer(state, action) {
    if (!actionPattern.test(action.type)) {
        return state;
    }
    let {scope, update, initialState} = action;

    if (scope) {
        return updateIn(
            disableLodashPath(scope),
            s => updateObject(update, {...initialState, ...s}),
            state
        );
    }

    return updateObject(action.update, {...initialState, ...state});
}

export default leanReducer;
<commit_msg>Support old defaultProps too<commit_after>import {connectAdvanced} from "react-redux";
import getOr from "lodash/fp/getOr";
import updateIn from "lodash/fp/update";
import mapValues from "lodash/fp/mapValues";
import pick from "lodash/fp/pick";
import flattenDeep from "lodash/fp/flattenDeep";
import updateObject from "updeep/dist/update";
const mapValuesWithKey = mapValues.convert({cap: false});

export function composeReducers(...reducers) {
    return (state=null, action) => {
        return reducers.filter(r => typeof r === "function").reduce(
            ((state, subReducer) => subReducer(state, action)),
            state
        );
    };
}

function disableLodashPath(path) {
    if (typeof path === "string") {
        return [path];
    }

    return path;
}

export function update(...args) {
    let scope, update;

    if (args.length === 2) {
        [scope, update] = args;
    } else {
        update = args[0];
    }

    return {
        type: "LEAN_UPDATE",
        scope,
        update,
    };
}

const plain = {};
const withSlash = s => s ? ("/" + s) : "";

export function thunk(cb) {
    return {_thunk: cb};
}
export function connectLean(options=plain) {
    return connectAdvanced(dispatch => {
        let initialState = plain;

        if (options.getInitialState === "function") {
            initialState = options.getInitialState();
        } else if (options.defaultProps) {
            initialState = options.defaultProps;
        }

        var boundHandlersCache = null;
        var propsCache = null;
        var prevScope = {}; // Just some object with unique identity
        const getProps = () => propsCache;

        var mapState = typeof options.mapState === "function"
            ? options.mapState
            : pick(Object.keys(initialState));

        const handlers = typeof options.handlers === "function"
            ? options.handlers(getProps)
            : options.handlers;

        return (fullState, ownProps) => {
            var scope = ownProps.scope || options.scope;
            if (Array.isArray(scope)) {
                scope = flattenDeep(scope);
            }

            var scopedState = fullState || plain;

            if (scope) {
                scopedState = {...getOr(plain, disableLodashPath(scope), fullState), scope};
            }

            scopedState = {...initialState, ...scopedState};

            // Implement React Redux style advanced performance pattern where
            // the mapState can create the mapState function itself
            let _state =  mapState(scopedState, ownProps);
            if (typeof _state === "function") {
                // map state generated a new mapState function. Save it
                mapState = _state;
                // and use it to map the state
                _state =  mapState(scopedState, ownProps);
            }
            scopedState = _state;

            // Regenerate handlers only when the scope changes
            if (prevScope !== scope) {
                prevScope = scope;
                const dispatchUpdate = (updateName, update) => {
                    if (!update) {
                        return;
                    }

                    if (update && typeof update._thunk === "function") {
                        return update._thunk(dispatchUpdate.bind(null, updateName), getProps);
                    }
                    var actionSuffix = scope;
                    if (Array.isArray(actionSuffix)) {
                        actionSuffix = actionSuffix.join(".");
                    }

                    dispatch({
                        type: "LEAN_UPDATE" + withSlash(actionSuffix) + withSlash(updateName),
                        update,
                        initialState,
                        scope,
                    });
                };

                const bindDispatch = (updateFn, updateName) => (...args) => dispatchUpdate(updateName, updateFn(...args.concat(propsCache)));

                boundHandlersCache = mapValuesWithKey(bindDispatch, handlers);
            }

            return propsCache = {...ownProps, ...scopedState, ...boundHandlersCache, scope};
        };

    }, {
        getDisplayName: name => "ConnectLean(" + name + ")",
    });
}

const actionPattern = /^LEAN_UPDATE/;

export function leanReducer(state, action) {
    if (!actionPattern.test(action.type)) {
        return state;
    }
    let {scope, update, initialState} = action;

    if (scope) {
        return updateIn(
            disableLodashPath(scope),
            s => updateObject(update, {...initialState, ...s}),
            state
        );
    }

    return updateObject(action.update, {...initialState, ...state});
}

export default leanReducer;
<|endoftext|>


<commit_before>/*jshint node: true, -W106 */
'use strict';

/*
* Name : mapChart.js
* Module : Lib::BusinessTier::MapChart
* Location : /lib/businessTier/mapChart
*
* History :
*
* Version   Date         Programmer         Description
* =========================================================
* 0.0.1     2015-05-20   Filippo Rampado    Initial code
* =========================================================
*/

var Socket=require('../../presentationTier/socket.js');
var Graph=require('./graph.js');
var Page=require('../page/page.js');
var MapChartFlow=require('../flow/mapChartFlow.js');
var MapChartModel=require('../../dataTier/graph/mapChartModel.js');
var Helper = require('../../helpers/functionHelper.js');

function MapChart(params, page, graphSocket) {
	if (params===undefined){
		console.log('Error: 381');
		return;
	}
	if (!(graphSocket instanceof Socket)){
		console.log('Error: 382');
		return;
	}
	if (!(page instanceof Page)){
		console.log('Error: 383');
		return;
	}
	var mc=new MapChartModel(params);
	if (!mc.hasOwnProperty('ID')){
		return;
	}
	this.parent.constructor.call(this, page, graphSocket);
	this._dataMapChart=mc;
	this._flows=[];
}

MapChart.prototype = Object.create(Graph.prototype);
MapChart.prototype.constructor = Graph;
MapChart.prototype.parent = Graph.prototype;

MapChart.prototype.getFlowByID = function(ID){
	if (typeof ID==='string') {
		var flows=this._flows.length;
		var i=0;
		var found=false;
		while (i<flows && (!found)){
			if (this._flows[i].ID===ID){
				found=true;
			}
			else{
				i++;
			}
		}//while
		if (found){//in flows[i] there is the ID
			return this._flows[i];
		}
		//no ID in flows
	}
	return 282;
};

MapChart.prototype.createMapChartFlow = function(params){
	var mcf=new MapChartFlow(params, this._graphSocket);
	if (!mcf.hasOwnProperty('dataMapChartFlow')){
		return 232;
	}
	this._flows.push(mcf);

	var prop={ID: params.ID};
	if(params.name!==undefined && typeof params.name === 'string'){
		prop.name=params.name;
	}
	if(params.marker!==undefined && Helper.isValidMapMarker(params.marker)){
		prop.marker=params.marker;
	}
	if(params.trace!==undefined && Helper.isValidTrace(params.trace)){
		prop.trace=params.trace;
	}
	if(params.trailLength!==undefined && typeof params.trailLength==='number' && params.trailLength>=1){
		prop.trailLength=params.trailLength;
	}
	this._graphSocket.sendMessage('insertFlow', prop);

	return mcf;
};

MapChart.prototype.deleteFlow = function(ID){
	if (typeof ID==='string') {
		var flows=this._flows.length;
		var i=0;
		var found=false;
		while (i<flows && (!found)){
			if (this._flows[i].ID===ID){
				found=true;
			}
			else{
				i++;
			}
		}//while
		if (found){//in flows[i] there is the ID
			this._graphSocket.sendMessage('deleteFlow', ID);
			this._flows.splice(i, 1);
			return true;
		}
		//no ID in flows
	}
	return 283;
};

MapChart.prototype.deleteAllFloww = function(){
	while (this._flows.length>0){
		this._graphSocket.sendMessage('deleteFlow', this._flows[0].ID);
		this._flows.splice(0, 1);
	}
};

MapChart.prototype.addRecord = function(flowID, record){
	return this.getFlowByID(flowID).addRecord(record);
};

MapChart.prototype.deleteRecord = function(flowID, ID){
	return this.getFlowByID(flowID).deleteRecord(ID);
};

MapChart.prototype.updateRecord = function(flowID, ID, record){
	return this.getFlowByID(flowID).updateRecord(ID, record);
};

MapChart.prototype.updateProperties = function(params){
	if (params!==undefined){
		var prop=this._dataMapChart.updateProperties(params);
		prop.ID=this._dataMapChart.ID;
		this._graphSocket.sendMessage('updateGraphProp', prop);
	}
};

/*MapChart.prototype.getConfigJSON = function(){
	return JSON;
};*/

module.exports = MapChart;
<commit_msg>add getConfigJSON<commit_after>/*jshint node: true, -W106 */
'use strict';

/*
* Name : mapChart.js
* Module : Lib::BusinessTier::MapChart
* Location : /lib/businessTier/mapChart
*
* History :
*
* Version   Date         Programmer         Description
* =========================================================
* 0.0.1     2015-05-20   Filippo Rampado    Initial code
* =========================================================
*/

var Socket=require('../../presentationTier/socket.js');
var Graph=require('./graph.js');
var Page=require('../page/page.js');
var MapChartFlow=require('../flow/mapChartFlow.js');
var MapChartModel=require('../../dataTier/graph/mapChartModel.js');
var Helper = require('../../helpers/functionHelper.js');

function MapChart(params, page, graphSocket) {
	if (params===undefined){
		console.log('Error: 381');
		return;
	}
	if (!(graphSocket instanceof Socket)){
		console.log('Error: 382');
		return;
	}
	if (!(page instanceof Page)){
		console.log('Error: 383');
		return;
	}
	var mc=new MapChartModel(params);
	if (!mc.hasOwnProperty('ID')){
		return;
	}
	this.parent.constructor.call(this, page, graphSocket);
	this._dataMapChart=mc;
	this._flows=[];
}

MapChart.prototype = Object.create(Graph.prototype);
MapChart.prototype.constructor = Graph;
MapChart.prototype.parent = Graph.prototype;

MapChart.prototype.getFlowByID = function(ID){
	if (typeof ID==='string') {
		var flows=this._flows.length;
		var i=0;
		var found=false;
		while (i<flows && (!found)){
			if (this._flows[i].ID===ID){
				found=true;
			}
			else{
				i++;
			}
		}//while
		if (found){//in flows[i] there is the ID
			return this._flows[i];
		}
		//no ID in flows
	}
	return 282;
};

MapChart.prototype.createMapChartFlow = function(params){
	var mcf=new MapChartFlow(params, this._graphSocket);
	if (!mcf.hasOwnProperty('dataMapChartFlow')){
		return 232;
	}
	this._flows.push(mcf);

	var prop={ID: params.ID};
	if(params.name!==undefined && typeof params.name === 'string'){
		prop.name=params.name;
	}
	if(params.marker!==undefined && Helper.isValidMapMarker(params.marker)){
		prop.marker=params.marker;
	}
	if(params.trace!==undefined && Helper.isValidTrace(params.trace)){
		prop.trace=params.trace;
	}
	if(params.trailLength!==undefined && typeof params.trailLength==='number' && params.trailLength>=1){
		prop.trailLength=params.trailLength;
	}
	this._graphSocket.sendMessage('insertFlow', prop);

	return mcf;
};

MapChart.prototype.deleteFlow = function(ID){
	if (typeof ID==='string') {
		var flows=this._flows.length;
		var i=0;
		var found=false;
		while (i<flows && (!found)){
			if (this._flows[i].ID===ID){
				found=true;
			}
			else{
				i++;
			}
		}//while
		if (found){//in flows[i] there is the ID
			this._graphSocket.sendMessage('deleteFlow', ID);
			this._flows.splice(i, 1);
			return true;
		}
		//no ID in flows
	}
	return 283;
};

MapChart.prototype.deleteAllFloww = function(){
	while (this._flows.length>0){
		this._graphSocket.sendMessage('deleteFlow', this._flows[0].ID);
		this._flows.splice(0, 1);
	}
};

MapChart.prototype.addRecord = function(flowID, record){
	return this.getFlowByID(flowID).addRecord(record);
};

MapChart.prototype.deleteRecord = function(flowID, ID){
	return this.getFlowByID(flowID).deleteRecord(ID);
};

MapChart.prototype.updateRecord = function(flowID, ID, record){
	return this.getFlowByID(flowID).updateRecord(ID, record);
};

MapChart.prototype.updateProperties = function(params){
	if (params!==undefined){
		var prop=this._dataMapChart.updateProperties(params);
		prop.ID=this._dataMapChart.ID;
		this._graphSocket.sendMessage('updateGraphProp', prop);
	}
};

MapChart.prototype.getConfigJSON = function(){
	var configJSON={};
	configJSON.properties=this._dataMapChart.getProperties();
	var flowProp=[];
	var flowData=[];
	var flows=this._flows.length;
	for (var i=0; i<flows; i++){
		flowProp.push(this._flows[i]._dataMapChartFlow.getProperties());
		var records=this._flows[i]._dataMapChartFlow.getData();
		flowData.push({
			ID: flowProp.ID,
			records: records
		});
	}
	configJSON.properties.flows=flowProp;
	configJSON.data=flowData;
	return configJSON;
};

module.exports = MapChart;
<|endoftext|>


<commit_before>'use strict';

/* Controllers */
function WanderCtrl(scope, rootScope, cookies, FB) {
	// FB.init({
	// 		appId      : js_appId,                    // App ID from the app dashboard
	// 		status     : true,                                 // Check Facebook Login status
	// 		xfbml      : true                                  // Look for social plugins on the page
	// 	});
}

function LoginCtrl(scope) {
}

function SketchCtrl(scope, cookies, FB) {
	FB.me(function(response) {
		scope.user = response;
	});

	FB.api(function(response) {

	});

	scope.sketch = function(processing) {
		processing.setup = function() {
			processing.size(window.innerWidth, window.innerHeight);
		};

		processing.draw = function() {
			processing.background(255);
			processing.fill(0);
			processing.ellipse(0, 250, 10, 10);
			processing.textSize(32);
			if(scope.user) processing.text('Hello ' + scope.user.name, 500, 500);
		};
	}
}

WanderCtrl.$inject = ['$scope', '$rootScope', '$cookies', 'Facebook'];
LoginCtrl.$inject = ['$scope'];
SketchCtrl.$inject = ['$scope', '$cookies', 'Facebook'];<commit_msg>[Primitive foundation]<commit_after>'use strict';

/* Controllers */
function WanderCtrl(scope, rootScope, cookies, FB) {
	// FB.init({
	// 		appId      : js_appId,                    // App ID from the app dashboard
	// 		status     : true,                                 // Check Facebook Login status
	// 		xfbml      : true                                  // Look for social plugins on the page
	// 	});
}

function LoginCtrl(scope) {
}

function SketchCtrl(scope, cookies, FB) {
	FB.api('/me?fields=name,hometown,picture,birthday,photos.limit(1)', function(response) {
		scope.user = response;
	});

	scope.sketch = function(processing) {
		var profile_pic;
		var online;

		processing.setup = function() {
			processing.size(window.innerWidth, window.innerHeight);
		};

		processing.draw = function() {
			processing.background(255);
			processing.fill(0);
			processing.textSize(32);
			if(scope.user) {
				processing.text('Hello ' + scope.user.name, 500, 100);
				processing.text('Your hometown is ' + scope.user.hometown.name, 500, 150);
				processing.text('Your birthday is ' + scope.user.birthday, 500, 200);
				processing.text('Heres a photo of you', 500, 250);
				var photo_url = scope.user.photos.data[0].source;
				var profile_pic_url = scope.user.picture.data.url;
				if(online) {
					processing.image(online, 600, 300);
				} else {
					online = processing.loadImage(photo_url, "jpg");
				}

				if(profile_pic) {
					processing.image(profile_pic, 400, 75);
				} else {
					profile_pic = processing.loadImage(profile_pic_url, "jpg");
				}
			}
		};
	}
}

WanderCtrl.$inject = ['$scope', '$rootScope', '$cookies', 'Facebook'];
LoginCtrl.$inject = ['$scope'];
SketchCtrl.$inject = ['$scope', '$cookies', 'Facebook'];<|endoftext|>


<commit_before>const spawn = require('child_process').spawn;
const path = require('path');
const log = require('npmlog');
const uniq = require('lodash.uniq');
const makeHook = require('rnpm-hooks');
const async = require('async');

const isEmpty = require('./isEmpty');
const registerDependencyAndroid = require('./android/registerNativeModule');
const registerDependencyIOS = require('./ios/registerNativeModule');
const copyAssetsAndroid = require('./android/copyAssets');
const copyAssetsIOS = require('./ios/copyAssets');

log.heading = 'rnpm-link';

/**
 * Returns an array of dependencies that should be linked/checked.
 */
const getProjectDependencies = () => {
  const pjson = require(path.join(process.cwd(), './package.json'));
  return Object.keys(pjson.dependencies).filter(name => name !== 'react-native');
};

/**
 * Updates project and linkes all dependencies to it
 *
 * If optional argument [packageName] is provided, it's the only one that's checked
 */
module.exports = function link(config, args, callback) {

  try {
    const project = config.getProjectConfig();
  } catch (err) {
    log.error('ERRPACKAGEJSON', `No package found. Are you sure it's a React Native project?`);
    return;
  }

  const packageName = args[0];

  const dependencies =
    (packageName ? [packageName] : getProjectDependencies())
    .map(name => {
      try {
        return {
          config: config.getDependencyConfig(name),
          name,
        };
      } catch (err) {
        log.warn(
          'ERRINVALIDPROJ',
          `Project ${name} is not a react-native library`
        );
      }
    })
    .filter(dependency => dependency);

  const assets = uniq(
    dependencies.reduce(
      (assets, dependency) => assets.concat(dependency.config.assets),
      project.assets
    ),
    asset => path.basename(asset)
  );

  const makeLink = (dependency) => (cb) => {
    if (project.android && dependency.config.android) {
      log.info(`Linking ${dependency.name} android dependency`);
      registerDependencyAndroid(
        dependency.name,
        dependency.config.android,
        project.android
      );
    }

    if (project.ios && dependency.config.ios) {
      log.info(`Linking ${dependency.name} ios dependency`);
      registerDependencyIOS(dependency.config.ios, project.ios);
    }

    if (isEmpty(assets)) {
      return cb();
    }

    if (project.ios) {
      log.info('Linking assets to ios project');
      copyAssetsIOS(assets, project.ios);
    }

    if (project.android) {
      log.info('Linking assets to android project');
      copyAssetsAndroid(assets, project.android.assetsPath);
    }

    cb();
  };

  const tasks = dependencies.map((dependency) => (next) => {
    const queue = [];

    var prelink;
    var postlink;

    if (dependency.config.hooks) {
      prelink = dependency.config.hooks.prelink;
      postlink = dependency.config.hooks.postlink;
    }

    if (prelink) {
      queue.push(makeHook(prelink));
    }

    queue.push(makeLink(dependency));

    if (postlink) {
      queue.push(makeHook(postlink));
    }

    queue.push(next);

    async.waterfall(queue);
  });

  async.series(tasks, callback || () => {});
};
<commit_msg>Use next function as a callback on waterfall<commit_after>const spawn = require('child_process').spawn;
const path = require('path');
const log = require('npmlog');
const uniq = require('lodash.uniq');
const makeHook = require('rnpm-hooks');
const async = require('async');

const isEmpty = require('./isEmpty');
const registerDependencyAndroid = require('./android/registerNativeModule');
const registerDependencyIOS = require('./ios/registerNativeModule');
const copyAssetsAndroid = require('./android/copyAssets');
const copyAssetsIOS = require('./ios/copyAssets');

log.heading = 'rnpm-link';

/**
 * Returns an array of dependencies that should be linked/checked.
 */
const getProjectDependencies = () => {
  const pjson = require(path.join(process.cwd(), './package.json'));
  return Object.keys(pjson.dependencies).filter(name => name !== 'react-native');
};

/**
 * Updates project and linkes all dependencies to it
 *
 * If optional argument [packageName] is provided, it's the only one that's checked
 */
module.exports = function link(config, args, callback) {

  try {
    const project = config.getProjectConfig();
  } catch (err) {
    log.error('ERRPACKAGEJSON', `No package found. Are you sure it's a React Native project?`);
    return;
  }

  const packageName = args[0];

  const dependencies =
    (packageName ? [packageName] : getProjectDependencies())
    .map(name => {
      try {
        return {
          config: config.getDependencyConfig(name),
          name,
        };
      } catch (err) {
        log.warn(
          'ERRINVALIDPROJ',
          `Project ${name} is not a react-native library`
        );
      }
    })
    .filter(dependency => dependency);

  const assets = uniq(
    dependencies.reduce(
      (assets, dependency) => assets.concat(dependency.config.assets),
      project.assets
    ),
    asset => path.basename(asset)
  );

  const makeLink = (dependency) => (cb) => {
    if (project.android && dependency.config.android) {
      log.info(`Linking ${dependency.name} android dependency`);
      registerDependencyAndroid(
        dependency.name,
        dependency.config.android,
        project.android
      );
    }

    if (project.ios && dependency.config.ios) {
      log.info(`Linking ${dependency.name} ios dependency`);
      registerDependencyIOS(dependency.config.ios, project.ios);
    }

    if (isEmpty(assets)) {
      return cb();
    }

    if (project.ios) {
      log.info('Linking assets to ios project');
      copyAssetsIOS(assets, project.ios);
    }

    if (project.android) {
      log.info('Linking assets to android project');
      copyAssetsAndroid(assets, project.android.assetsPath);
    }

    cb();
  };

  const tasks = dependencies.map((dependency) => (next) => {
    const queue = [];

    var prelink;
    var postlink;

    if (dependency.config.hooks) {
      prelink = dependency.config.hooks.prelink;
      postlink = dependency.config.hooks.postlink;
    }

    if (prelink) {
      queue.push(makeHook(prelink));
    }

    queue.push(makeLink(dependency));

    if (postlink) {
      queue.push(makeHook(postlink));
    }

    async.waterfall(queue, next);
  });

  async.series(tasks, callback || () => {});
};
<|endoftext|>


<commit_before>'use strict';

import { getChildDebugElement } from 'tests/helpers';
import {Component, View, provide} from 'angular2/core';

import {
  TestComponentBuilder,
  injectAsync,
  beforeEach,
  beforeEachProviders,
  it
} from 'angular2/testing';

import Redoc from 'lib/components/Redoc/redoc';
import SchemaManager from 'lib/utils/SchemaManager';

describe('Redoc components', () => {
  describe('Redoc Component', () => {
    let builder;
    beforeEachProviders(() => [
        provide(SchemaManager, {useValue: new SchemaManager()})
    ]);
    beforeEach(injectAsync([TestComponentBuilder, SchemaManager], (tcb, schemaMgr) => {
      builder = tcb;
      return schemaMgr.load('/tests/schemas/extended-petstore.json').then(() => null, (err) => { throw err; });
    }));

    it('should init component', (done) => {
      builder.createAsync(TestApp).then(fixture => {
        let component = getChildDebugElement(fixture.debugElement, 'redoc').componentInstance;
        expect(component).not.toBeNull();
        done();
      }, err => done.fail(err));
    });

    it('should init components tree without errors', (done) => {
      builder.createAsync(TestApp).then(fixture => {
        (() => fixture.detectChanges()).should.not.throw();
        done();
      }, err => done.fail(err));
    });
  });
});

/** Test component that contains a Redoc. */
@Component({selector: 'test-app'})
@View({
  directives: [Redoc],
  template:
      `<redoc></redoc>`
})
class TestApp {
}
<commit_msg>Destroy redoc to unbind side-menu handlers<commit_after>'use strict';

import { getChildDebugElement } from 'tests/helpers';
import {Component, View, provide} from 'angular2/core';

import {
  TestComponentBuilder,
  injectAsync,
  beforeEach,
  beforeEachProviders,
  it
} from 'angular2/testing';

import Redoc from 'lib/components/Redoc/redoc';
import SchemaManager from 'lib/utils/SchemaManager';

describe('Redoc components', () => {
  describe('Redoc Component', () => {
    let builder;
    beforeEachProviders(() => [
        provide(SchemaManager, {useValue: new SchemaManager()})
    ]);
    beforeEach(injectAsync([TestComponentBuilder, SchemaManager], (tcb, schemaMgr) => {
      builder = tcb;
      return schemaMgr.load('/tests/schemas/extended-petstore.json').then(() => null, (err) => { throw err; });
    }));

    it('should init component', (done) => {
      builder.createAsync(TestApp).then(fixture => {
        let component = getChildDebugElement(fixture.debugElement, 'redoc').componentInstance;
        expect(component).not.toBeNull();
        fixture.destroy();
        done();
      }, err => done.fail(err));
    });

    it('should init components tree without errors', (done) => {
      builder.createAsync(TestApp).then(fixture => {
        (() => fixture.detectChanges()).should.not.throw();
        fixture.destroy();
        done();
      }, err => done.fail(err));
    });
  });
});

/** Test component that contains a Redoc. */
@Component({selector: 'test-app'})
@View({
  directives: [Redoc],
  template:
      `<redoc></redoc>`
})
class TestApp {
}
<|endoftext|>


<commit_before>/*globals d3:true */

var apisEyeSim = function (target) {
    var self = {};

    var _element = typeof target == 'string' ? d3.select(target) : target;
    var _frameDuration = 500;
    var _fadeDuration = 250;
    var _iteration = 0;
    var _frameTimer = null;
    var _renderer = self.emptyMatrix;

    self.renderer = function (r) {
        if (!arguments.length) return _renderer;
        _renderer = r;
        return self;
    };

    self.rows = function () {
        return 13;
    };

    self.cols = function () {
        return 9;
    };

    self.iteration = function () {
        return _iteration;
    };

    self.isInBounds = function (x, y) {
        var yMin = 0;
        var yMax = 12;

        if (x === 0 || x === 8) {
            yMin = 3;
            yMax = 9;
        }
        else if (x === 1 || x === 7) {
            yMin = 1;
            yMax = 11;
        }

        return y >= yMin && y <= yMax && x >= 0 && x <= 8;
    };

    self.emptyMatrix = function () {
        var matrix = [];

        for (var y = 0; y < self.rows(); ++y) {
            matrix[y] = [];

            for (var x = 0; x < self.cols(); ++x) {
                matrix[y][x] = { r: 0, g: 0, b: 0 };
            }
        }

        return matrix;
    };

    self.frameDuration = function (duration) {
        if (!arguments.length) return _frameDuration;
        _frameDuration = duration;
        self.stop().start();
        return self;
    };

    self.fadeDuration = function (duration) {
        if (!arguments.length) return _fadeDuration;
        _fadeDuration = duration;
        return self;
    };

    self.start = function () {
        var rows = d3.select(_element).selectAll('g').data(self.renderer);

        rows.enter().append('g');

        var dots = rows.selectAll('circle').data(function (r) { return r; });

        dots.enter().append('circle').attr('r', function (d, col, row) {
            return self.isInBounds(row, col) ? 10 : 2;
        })
        .attr('cx', function (c, i) { return (i + 1) * 30; })
        .attr('cy', function (c, i, j) { return (j + 1) * 30; });

        dots.transition().duration(_fadeDuration).attr('fill', function (c) {
            return 'rgb(' + c.r + ',' + c.g + ',' + c.b + ')';
        });

        if (!_frameTimer) {
            _frameTimer = setInterval(self.start, _frameDuration);
        }
        _iteration += 1;
        return self;
    };

    self.stop = function () {
        _frameTimer = clearInterval(_frameTimer);
        _iteration = 0;
        return self;
    };

    return self;
};
<commit_msg>Don't double-select element<commit_after>/*globals d3:true */

var apisEyeSim = function (target) {
    var self = {};

    var _element = typeof target == 'string' ? d3.select(target) : target;
    var _frameDuration = 500;
    var _fadeDuration = 250;
    var _iteration = 0;
    var _frameTimer = null;
    var _renderer = self.emptyMatrix;

    self.renderer = function (r) {
        if (!arguments.length) return _renderer;
        _renderer = r;
        return self;
    };

    self.rows = function () {
        return 13;
    };

    self.cols = function () {
        return 9;
    };

    self.iteration = function () {
        return _iteration;
    };

    self.isInBounds = function (x, y) {
        var yMin = 0;
        var yMax = 12;

        if (x === 0 || x === 8) {
            yMin = 3;
            yMax = 9;
        }
        else if (x === 1 || x === 7) {
            yMin = 1;
            yMax = 11;
        }

        return y >= yMin && y <= yMax && x >= 0 && x <= 8;
    };

    self.emptyMatrix = function () {
        var matrix = [];

        for (var y = 0; y < self.rows(); ++y) {
            matrix[y] = [];

            for (var x = 0; x < self.cols(); ++x) {
                matrix[y][x] = { r: 0, g: 0, b: 0 };
            }
        }

        return matrix;
    };

    self.frameDuration = function (duration) {
        if (!arguments.length) return _frameDuration;
        _frameDuration = duration;
        self.stop().start();
        return self;
    };

    self.fadeDuration = function (duration) {
        if (!arguments.length) return _fadeDuration;
        _fadeDuration = duration;
        return self;
    };

    self.start = function () {
        var rows = _element.selectAll('g').data(self.renderer);

        rows.enter().append('g');

        var dots = rows.selectAll('circle').data(function (r) { return r; });

        dots.enter().append('circle').attr('r', function (d, col, row) {
            return self.isInBounds(row, col) ? 10 : 2;
        })
        .attr('cx', function (c, i) { return (i + 1) * 30; })
        .attr('cy', function (c, i, j) { return (j + 1) * 30; });

        dots.transition().duration(_fadeDuration).attr('fill', function (c) {
            return 'rgb(' + c.r + ',' + c.g + ',' + c.b + ')';
        });

        if (!_frameTimer) {
            _frameTimer = setInterval(self.start, _frameDuration);
        }
        _iteration += 1;
        return self;
    };

    self.stop = function () {
        _frameTimer = clearInterval(_frameTimer);
        _iteration = 0;
        return self;
    };

    return self;
};
<|endoftext|>