<commit_before>import React, { Component } from 'react';

const Line = ({ i, current, next }) => {
  const mid = calculateMidPoint(current, next);

  const text = (
    <text
      style={{
        WebkitUserSelect: 'none',
      }}
      x={mid.x - 25}
      y={mid.y - 25}
      fontFamily="sans-serif"
      fontSize="12px"
      stroke="none"
      fill="black"
    >
      {calculateLength(current, next)}
    </text>
  );

  return (
    <g>
      <path
        key={i}
        d={`M${current.x} ${current.y} L${next.x} ${next.y}`}
        stroke="black"
        strokeWidth="3"
        fill="none"
      />
      { text }
    </g>
  );
};

export default Line;

function calculateLength(c, n) {
  const a = c.x - n.x;
  const b = c.y - n.y;

  return parseInt(Math.sqrt(a*a + b*b));
}

function calculateMidPoint(c, n) {
  const a = c.x + n.x;
  const b = c.y + n.y;

  return {
    x: parseInt(a/2),
    y: parseInt(b/2),
  };
}
<commit_msg>Make Line functional component into a regular component<commit_after>import React, { Component } from 'react';

class Line extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    const { i, current, next } = this.props;

    const mid = calculateMidPoint(current, next);

    const text = (
      <text
        style={{
          WebkitUserSelect: 'none',
        }}
        x={mid.x - 25}
        y={mid.y - 25}
        fontFamily="sans-serif"
        fontSize="12px"
        stroke="none"
        fill="black"
      >
        {calculateLength(current, next)}
      </text>
    );

    return (
      <g>
        <path
          key={i}
          d={`M${current.x} ${current.y} L${next.x} ${next.y}`}
          stroke="black"
          strokeWidth="3"
          fill="none"
        />
        { text }
      </g>
    );
  }
};

export default Line;

function calculateLength(c, n) {
  const a = c.x - n.x;
  const b = c.y - n.y;

  return parseInt(Math.sqrt(a*a + b*b));
}

function calculateMidPoint(c, n) {
  const a = c.x + n.x;
  const b = c.y + n.y;

  return {
    x: parseInt(a/2),
    y: parseInt(b/2),
  };
}
<|endoftext|>


<commit_before>(function(window){
    'use strict';
    function dragSelector(config) {
        return new DSInternal(config);
    }

    dragSelector.version = "0.0.1";

    function DSInternal(config) {
        if (typeof window.d3 === 'undefined') {
            throw Error("d3.js must exist in order to use the d3.js drag selector plugin. Ensure that it is placed above this file when referencing your scripts.")
        }
        this.d3 = window.d3;
        config = config || {};
        this.config = {};
        this.config.selectNode = config.selectNode;
        this.config.selectFilter = config.selectFilter;
        this.config.selectedClass = config.selectedClass || "";
        this.config.rectangleClass = config.rectangleClass || "";
        this.config.rectRelativeToNode = (config.rectRelativeToNode && config.rectRelativeToNode.select) ? config.rectRelativeToNode.node() : (config.rectRelativeToNode ? config.rectRelativeToNode : null); // make it a true node if it's a d3 selection
        this.config.onSelect = config.onSelect;
        this.config.onDragStart = config.onDragStart;
        this.config.onDragEnd = config.onDragEnd;
        this.config.multiSelectKey = config.multiSelectKey || "ctrl";
        this.config.preventDragBubbling = config.preventDragBubbling === false ? false : true; // default to prevent drag bubbling to stop text highlighting
    }

    var fn = DSInternal.prototype;

    fn.selectNode = function(nodeTag) {
        if (!arguments.length) return this.config.selectNode;
        this.config.selectNode = nodeTag;
        return this;
    };
    fn.selectFilter = function(filter) {
        if (!arguments.length) return this.config.selectFilter;
        this.config.selectFilter = filter;
        return this;
    };
    fn.selectedClass = function(className) {
        if (!arguments.length) return this.config.selectedClass;
        this.config.selectedClass = className;
        return this;
    };
    fn.rectangleClass = function(className) {
        if (!arguments.length) return this.config.rectangleClass;
        this.config.rectangleClass = className;
        return this;
    };
    fn.rectRelativeToNode = function(node) {
        if (!arguments.length) return this.config.rectRelativeToNode;
        this.config.rectRelativeToNode = node.select ? node.node() : node;
        return this;
    };
    fn.onSelect = function(cb) {
        if (!arguments.length) return this.config.onSelect;
        this.config.onSelect = cb;
        return this;
    };
    fn.onDragStart = function(cb) {
        if (!arguments.length) return this.config.onDragStart;
        this.config.onDragStart = cb;
        return this;
    };
    fn.onDragEnd = function(cb) {
        if (!arguments.length) return this.config.onDragEnd;
        this.config.onDragEnd = cb;
        return this;
    };
    fn.multiSelectKey = function(key) {
        if (!arguments.length) return this.config.multiSelectKey;
        this.config.multiSelectKey = key;
        return this;
    };
    fn.preventDragBubbling = function(bool) {
        if (!arguments.length) return this.config.preventDragBubbling;
        this.config.preventDragBubbling = bool;
        return this;
    };

    fn.selector = function() {
        var $$ = this;
        return function(node) {
            internalSelectInit.call($$, node);
        };
    };

    function internalSelectInit(node) {
        var $$ = this,
            rect,
            nodeSelector = $$.config.selectNode + ($$.config.selectFilter || ""),
            targets = node.selectAll(nodeSelector),
            currentlyFound = "",
            clickedNode;
        if (!(($$.config.selectNode === "path") || ($$.config.selectNode === "rect") || ($$.config.selectNode === "circle"))) {
            throw Error("The \"selectNode\" configuration option must be either \"path\", \"rect\" or \"circle\".");
        }
        if (!$$.config.selectedClass) {
            throw Error("The \"selectedClass\" configuration option must be specified and must not be falsy");
        }
        node.on("mousedown", function(d, i, a) {
            if (($$.config.multiSelectKey === "ctrl" && $$.d3.event.ctrlKey) ||
                ($$.config.multiSelectKey === "shift" && $$.d3.event.shiftKey) ||
                ($$.config.multiSelectKey === "alt" && $$.d3.event.altKey)) {
                targets = targets.filter(":not(." + $$.config.selectedClass + ")"); // set the targets (the things to be searched) to exclude those already selected
            } else {
                targets = node.selectAll(nodeSelector); // else reset - we search all
            }
            if (rect) rect.remove();
            var point = $$.d3.mouse($$.config.rectRelativeToNode || this);
            if ($$.config.onDragStart) $$.config.onDragStart(); // .call? if yes, what scope?
            rect = node
                    .append("rect")
                    .attr("x", point[0])
                    .attr("y", point[1])
                    .attr("width", 0)
                    .attr("height", 0)
                    .attr("transform", $$.d3.select($$.config.rectRelativeToNode).attr("transform"))
                    .style("pointer-events", "none")
                    .classed($$.config.rectangleClass, $$.config.rectangleClass ? true : false);
            if ($$.config.selectNode === "path") { // check whether, when clicking, we are clicking inside a path and hence should select it
                targets
                    .each(function(d, i, a) {
                        if ($$.d3.event.target === this) { // ought this be currentTarget?
                            clickedNode = $$.d3.select(this);
                        }
                    });
            }
        })
        .on("mousemove", function(d, i, a) {
            if (rect && ($$.d3.select(rect.node())) && !rect.empty()) {
                if ($$.config.preventDragBubbling) pauseEvent($$.d3.event);
                var update = getUpdatedRect($$.d3.mouse($$.config.rectRelativeToNode || this), rect);
                rect.attr(update);
                if ($$.config.selectNode === "circle") {
                    circleSearch.call($$, targets, update, rect.node());
                } else if ($$.config.selectNode === "rect") {
                    rectSearch.call($$, targets, update, rect.node());
                } else if ($$.config.selectNode === "path") {
                    pathSearch.call($$, targets, update, rect.node());
                }
                if (clickedNode) clickedNode.classed($$.config.selectedClass,true);
                if ($$.config.onSelect) {
                    var found = node.selectAll(nodeSelector).filter("." + $$.config.selectedClass); // do not filter "targets" here due to "targets" possibly not containing all elements (in case of multiselect)
                    var foundIdx = "";
                    found.each(function(d,i) { foundIdx += i; });
                    if (currentlyFound !== foundIdx) {
                        $$.config.onSelect.call(found, found);
                        currentlyFound = foundIdx;
                    }
                }
            }
        })
        .on("mouseup", function(d, i, a) {
            if (rect) rect.remove();
            rect = null; // setting to null helps us not enter mousemove event's main body after
            clickedNode = null;
            if ($$.config.onDragEnd) {
                var selected = node.selectAll(nodeSelector).filter("." + $$.config.selectedClass); // do not filter "targets" here due to "targets" possibly not containing all elements (in case of multiselect)
                $$.config.onDragEnd.call(selected, selected);
            }
        });
    }

    function getUpdatedRect(point, rect) {
        var update = {
            x:      parseInt(rect.attr("x"), 10),
            y:      parseInt(rect.attr("y"), 10),
            width:  parseInt(rect.attr("width"), 10),
            height: parseInt(rect.attr("height"), 10)
        },
        movement = {
            x: point[0] - update.x,
            y: point[1] - update.y
        };
        if (movement.x < 1 || movement.x * 2 < update.width) { // is it left of clickpoint
            update.x = point[0];
            update.width -= movement.x;
        } else { // no, it's right of clickpoint
            update.width = movement.x;
        }
        if (movement.y < 1 || movement.y * 2 < update.height) { // is it abnove clickpoint?
            update.y = point[1];
            update.height -= movement.y;
        } else { // no, it's below clickpoint'
            update.height = movement.y;
        }
        return update;
    }

    function applyCTMtoRect(CTMmatrix, rect) {
        var xt = CTMmatrix.e + rect.x*CTMmatrix.a,
            yt = CTMmatrix.f + rect.y*CTMmatrix.d;
        return { x: xt, y: yt, width: rect.width * CTMmatrix.a, height: rect.height * CTMmatrix.d };
    }

    function circleSearch(targetCircles, rect, rectNode) {
        var $$ = this;
        targetCircles
            .each(function(d, i, a) {
                var thisCircle = $$.d3.select(this);
                if (circleWithinArea({ x: thisCircle.attr("cx"), y: thisCircle.attr("cy"), r: thisCircle.attr("r") }, applyCTMtoRect(rectNode.getTransformToElement(this), rect))) {
                    thisCircle.classed($$.config.selectedClass, true);
                } else {
                   thisCircle.classed($$.config.selectedClass, false);
                }
        });
    }

    function rectSearch(targetRects, rect, rectNode) {
        var $$ = this;
        targetRects
            .each(function(d, i, a) {
                var thisRect = $$.d3.select(this);
                if (rectWithinArea(
                        { x: parseInt(thisRect.attr("x"), 10), y: parseInt(thisRect.attr("y"), 10), width: parseInt(thisRect.attr("width"), 10), height: parseInt(thisRect.attr("height"), 10) },
                        applyCTMtoRect(rectNode.getTransformToElement(this), rect)
                    )
                   ) {
                    thisRect.classed($$.config.selectedClass, true);
                } else {
                    thisRect.classed($$.config.selectedClass, false);
                }
        });
    }

    function pathSearch(targetPath, rect, rectNode) {
        var $$ = this;
        targetPath
            .each(function(d, i, a) {
                var xformRect = applyCTMtoRect(rectNode.getTransformToElement(this), rect);
                if (!rectWithinArea(this.getBBox(),xformRect)) { // if it isn't within the boundary box, don't bother scanning
                    $$.d3.select(this).classed($$.config.selectedClass, false);
                    return;
                }
                var lineSegments = this.pathSegList,
                    previousPoint = lineSegments.getItem(0),
                    curSubPath = lineSegments.getItem(0),
                    lineSelection = $$.d3.select(this),
                    originalPath = this.getAttribute("d");
                for (var j = 1, l = lineSegments.numberOfItems; j < l; j++){
                    var segment = lineSegments.getItem(j);
                    switch (segment.pathSegType) {
                        case SVGPathSeg.PATHSEG_MOVETO_ABS :
                            curSubPath = segment;
                            break;
                        case SVGPathSeg.PATHSEG_LINETO_ABS:
                            if (lineWithinArea({ start: previousPoint, end: segment }, xformRect)) {
                                lineSelection.classed($$.config.selectedClass, true);
                                this.setAttribute("d", originalPath);
                                return;
                            }
                            break;
                        case SVGPathSeg.PATHSEG_CLOSEPATH:
                            if (lineWithinArea({ start: previousPoint, end: curSubPath }, xformRect)) {
                                lineSelection.classed($$.config.selectedClass, true);
                                this.setAttribute("d", originalPath);
                                return;
                            }
                            break;
                        default:
                            var sampledLines = getResampledLine(this.cloneNode(), previousPoint, segment);
                            if (sampledLines.some(function(e) { return lineWithinArea(e, xformRect); })) {
                                lineSelection.classed($$.config.selectedClass, true);
                                this.setAttribute("d", originalPath);
                                return;
                            }
                    }
                    previousPoint = segment;
                }
                this.setAttribute("d", originalPath);
                lineSelection.classed($$.config.selectedClass, false);
            });
    }

    function circleWithinArea(circle, area) {
        var half = { x: area.width/2, y: area.height/2 },
            center = {
            x: circle.x - (area.x+half.x),
            y: circle.y - (area.y+half.y)
        },
            side = {
            x: Math.abs (center.x) - half.x,
            y: Math.abs (center.y) - half.y
        };
        if (side.x >  circle.r || side.y >  circle.r)
            return false;
        if (side.x < -circle.r && side.y < -circle.r)
            return true;
        if (side.x < 0 || side.y < 0)
            return true;

        return side.x*side.x + side.y*side.y  < circle.r*circle.r;
    }

    function rectWithinArea(rect, area) {
        return rect.x < (area.x + area.width) &&
               (rect.x + rect.width) > area.x &&
               rect.y < (area.y + area.height) &&
               (rect.y + rect.height) > area.y;
    }

    function lineWithinArea(line, area) {
        var tl = { x: area.x, y: area.y + area.height },
            tr = { x: area.x + area.width, y: area.y + area.height },
            br = { x: area.x + area.width, y: area.y },
            bl = { x: area.x, y: area.y };
        if (cornorsSameSide([tl,tr,br,bl],line.start,line.end) && endProject(line.start, line.end, tl, tr, br, bl)) return true;
        return false;
    }

    function cornorsSameSide(cornorsArr, lineStart, lineEnd) {
        var xC = lineStart.x - lineEnd.x,
            yC = lineEnd.y - lineStart.y,
            os = lineEnd.x * lineStart.y - lineStart.x * lineEnd.y,
            allLessThanZero = true,
            allMoreThanZero = true;
        cornorsArr.forEach(function(e) {
            var v = e.x * yC + e.y * xC + os;
            allLessThanZero = allLessThanZero && v < 0;
            allMoreThanZero = allMoreThanZero && v > 0;
        });
        return !(allLessThanZero || allMoreThanZero);
    }

    function endProject(lineStart, lineEnd, tl, tr, br, bl) {
        return !(
            (lineStart.x > tr.x && lineEnd.x > tr.x) ||
            (lineStart.x < bl.x && lineEnd.x < bl.x) ||
            (lineStart.y > tr.y && lineEnd.y > tr.y) ||
            (lineStart.y < bl.y && lineEnd.y < bl.y)
        );
    }

    function getResampledLine(clonedNode, start, segment) {
        var lines = [],
            points = [],
            i = 0,
            segmentLength = getSegmentLength(clonedNode, start, segment),
            precision = 5; // increasing this will degrade performance but will increase the accuracy of the resampling. ** hard coded for the present **
        points.push(clonedNode.getPointAtLength(0));
        while ((i+=(1/precision)) <= 1) {
            var curPoint = clonedNode.getPointAtLength(i * segmentLength),
                pi = points.length - 1;
            lines.push({ start: { x: points[pi].x, y: points[pi].y }, end: { x: curPoint.x, y: curPoint.y }});
            points.push(curPoint);
        }
        return lines;
    }

    function getSegmentLength(node, start, segment) {
        var startX = typeof start.x !== 'undefined' ? start.x : start.x1,
            startY = typeof start.y !== 'undefined' ? start.y : start.y1,
            startEl = node.createSVGPathSegMovetoAbs(startX, startY);
        node.pathSegList.clear();
        node.pathSegList.appendItem(startEl);
        node.pathSegList.appendItem(segment);
        return node.getTotalLength();
    }

    function pauseEvent(e){
        if(e.stopPropagation) e.stopPropagation();
        if(e.preventDefault) e.preventDefault();
        e.cancelBubble=true;
        e.returnValue=false;
        return false;
    }

    window.d3dragSelector = dragSelector;

})(window);<commit_msg>Renamed "rectRelativeToNode" to "rectTranslateNode".<commit_after>(function(window){
    'use strict';
    function dragSelector(config) {
        return new DSInternal(config);
    }

    dragSelector.version = "0.0.1";

    function DSInternal(config) {
        if (typeof window.d3 === 'undefined') {
            throw Error("d3.js must exist in order to use the d3.js drag selector plugin. Ensure that it is placed above this file when referencing your scripts.")
        }
        this.d3 = window.d3;
        config = config || {};
        this.config = {};
        this.config.selectNode = config.selectNode;
        this.config.selectFilter = config.selectFilter;
        this.config.selectedClass = config.selectedClass || "";
        this.config.rectangleClass = config.rectangleClass || "";
        this.config.rectTranslateNode = (config.rectTranslateNode && config.rectTranslateNode.select) ? config.rectTranslateNode.node() : config.rectTranslateNode;
        this.config.onSelect = config.onSelect;
        this.config.onDragStart = config.onDragStart;
        this.config.onDragEnd = config.onDragEnd;
        this.config.multiSelectKey = config.multiSelectKey || "ctrl";
        this.config.preventDragBubbling = config.preventDragBubbling === false ? false : true; // default to prevent drag bubbling to stop text highlighting
    }

    var fn = DSInternal.prototype;

    fn.selectNode = function(nodeTag) {
        if (!arguments.length) return this.config.selectNode;
        this.config.selectNode = nodeTag;
        return this;
    };
    fn.selectFilter = function(filter) {
        if (!arguments.length) return this.config.selectFilter;
        this.config.selectFilter = filter;
        return this;
    };
    fn.selectedClass = function(className) {
        if (!arguments.length) return this.config.selectedClass;
        this.config.selectedClass = className;
        return this;
    };
    fn.rectangleClass = function(className) {
        if (!arguments.length) return this.config.rectangleClass;
        this.config.rectangleClass = className;
        return this;
    };
    fn.rectTranslateNode = function(node) {
        if (!arguments.length) return this.config.rectTranslateNode;
        this.config.rectTranslateNode = (node && node.select) ? node.node() : node;
        return this;
    };
    fn.onSelect = function(cb) {
        if (!arguments.length) return this.config.onSelect;
        this.config.onSelect = cb;
        return this;
    };
    fn.onDragStart = function(cb) {
        if (!arguments.length) return this.config.onDragStart;
        this.config.onDragStart = cb;
        return this;
    };
    fn.onDragEnd = function(cb) {
        if (!arguments.length) return this.config.onDragEnd;
        this.config.onDragEnd = cb;
        return this;
    };
    fn.multiSelectKey = function(key) {
        if (!arguments.length) return this.config.multiSelectKey;
        this.config.multiSelectKey = key;
        return this;
    };
    fn.preventDragBubbling = function(bool) {
        if (!arguments.length) return this.config.preventDragBubbling;
        this.config.preventDragBubbling = bool;
        return this;
    };

    fn.selector = function() {
        var $$ = this;
        if (!(($$.config.selectNode === "path") || ($$.config.selectNode === "rect") || ($$.config.selectNode === "circle"))) {
            throw Error("The \"selectNode\" configuration option must be either \"path\", \"rect\" or \"circle\".");
        }
        if (!$$.config.selectedClass) {
            throw Error("The \"selectedClass\" configuration option must be specified and must not be falsy");
        }
        return function(node) {
            internalSelectInit.call($$, node);
        };
    };

    function internalSelectInit(node) {
        var $$ = this,
            rect,
            nodeSelector = $$.config.selectNode + ($$.config.selectFilter || ""),
            targets = node.selectAll(nodeSelector),
            currentlyFound = "",
            clickedNode;
        node.on("mousedown", function(d, i, a) {
            if (($$.config.multiSelectKey === "ctrl" && $$.d3.event.ctrlKey) ||
                ($$.config.multiSelectKey === "shift" && $$.d3.event.shiftKey) ||
                ($$.config.multiSelectKey === "alt" && $$.d3.event.altKey)) {
                targets = targets.filter(":not(." + $$.config.selectedClass + ")"); // set the targets (the things to be searched) to exclude those already selected
            } else {
                targets = node.selectAll(nodeSelector); // else reset - we search all
            }
            if (rect) rect.remove();
            var point = $$.d3.mouse($$.config.rectTranslateNode || this);
            if ($$.config.onDragStart) $$.config.onDragStart(); // .call? if yes, what scope?
            rect = node
                    .append("rect")
                    .attr("x", point[0])
                    .attr("y", point[1])
                    .attr("width", 0)
                    .attr("height", 0)
                    .attr("transform", $$.d3.select($$.config.rectTranslateNode).attr("transform"))
                    .style("pointer-events", "none")
                    .classed($$.config.rectangleClass, $$.config.rectangleClass ? true : false);
            if ($$.config.selectNode === "path") { // check whether, when clicking, we are clicking inside a path and hence should select it
                targets
                    .each(function(d, i, a) {
                        if ($$.d3.event.target === this) { // ought this be currentTarget?
                            clickedNode = $$.d3.select(this);
                        }
                    });
            }
        })
        .on("mousemove", function(d, i, a) {
            if (rect && ($$.d3.select(rect.node())) && !rect.empty()) {
                if ($$.config.preventDragBubbling) pauseEvent($$.d3.event);
                var update = getUpdatedRect($$.d3.mouse($$.config.rectTranslateNode || this), rect);
                rect.attr(update);
                if ($$.config.selectNode === "circle") {
                    circleSearch.call($$, targets, update, rect.node());
                } else if ($$.config.selectNode === "rect") {
                    rectSearch.call($$, targets, update, rect.node());
                } else if ($$.config.selectNode === "path") {
                    pathSearch.call($$, targets, update, rect.node());
                }
                if (clickedNode) clickedNode.classed($$.config.selectedClass,true);
                if ($$.config.onSelect) {
                    var found = node.selectAll(nodeSelector).filter("." + $$.config.selectedClass); // do not filter "targets" here due to "targets" possibly not containing all elements (in case of multiselect)
                    var foundIdx = "";
                    found.each(function(d,i) { foundIdx += i; });
                    if (currentlyFound !== foundIdx) {
                        $$.config.onSelect.call(found, found);
                        currentlyFound = foundIdx;
                    }
                }
            }
        })
        .on("mouseup", function(d, i, a) {
            if (rect) rect.remove();
            rect = null; // setting to null helps us not enter mousemove event's main body after
            clickedNode = null;
            if ($$.config.onDragEnd) {
                var selected = node.selectAll(nodeSelector).filter("." + $$.config.selectedClass); // do not filter "targets" here due to "targets" possibly not containing all elements (in case of multiselect)
                $$.config.onDragEnd.call(selected, selected);
            }
        });
    }

    function getUpdatedRect(point, rect) {
        var update = {
            x:      parseInt(rect.attr("x"), 10),
            y:      parseInt(rect.attr("y"), 10),
            width:  parseInt(rect.attr("width"), 10),
            height: parseInt(rect.attr("height"), 10)
        },
        movement = {
            x: point[0] - update.x,
            y: point[1] - update.y
        };
        if (movement.x < 1 || movement.x * 2 < update.width) { // is it left of clickpoint
            update.x = point[0];
            update.width -= movement.x;
        } else { // no, it's right of clickpoint
            update.width = movement.x;
        }
        if (movement.y < 1 || movement.y * 2 < update.height) { // is it abnove clickpoint?
            update.y = point[1];
            update.height -= movement.y;
        } else { // no, it's below clickpoint'
            update.height = movement.y;
        }
        return update;
    }

    function applyCTMtoRect(CTMmatrix, rect) {
        var xt = CTMmatrix.e + rect.x*CTMmatrix.a,
            yt = CTMmatrix.f + rect.y*CTMmatrix.d;
        return { x: xt, y: yt, width: rect.width * CTMmatrix.a, height: rect.height * CTMmatrix.d };
    }

    function circleSearch(targetCircles, rect, rectNode) {
        var $$ = this;
        targetCircles
            .each(function(d, i, a) {
                var thisCircle = $$.d3.select(this);
                if (circleWithinArea({ x: thisCircle.attr("cx"), y: thisCircle.attr("cy"), r: thisCircle.attr("r") }, applyCTMtoRect(rectNode.getTransformToElement(this), rect))) {
                    thisCircle.classed($$.config.selectedClass, true);
                } else {
                   thisCircle.classed($$.config.selectedClass, false);
                }
        });
    }

    function rectSearch(targetRects, rect, rectNode) {
        var $$ = this;
        targetRects
            .each(function(d, i, a) {
                var thisRect = $$.d3.select(this);
                if (rectWithinArea(
                        { x: parseInt(thisRect.attr("x"), 10), y: parseInt(thisRect.attr("y"), 10), width: parseInt(thisRect.attr("width"), 10), height: parseInt(thisRect.attr("height"), 10) },
                        applyCTMtoRect(rectNode.getTransformToElement(this), rect)
                    )
                   ) {
                    thisRect.classed($$.config.selectedClass, true);
                } else {
                    thisRect.classed($$.config.selectedClass, false);
                }
        });
    }

    function pathSearch(targetPath, rect, rectNode) {
        var $$ = this;
        targetPath
            .each(function(d, i, a) {
                var xformRect = applyCTMtoRect(rectNode.getTransformToElement(this), rect);
                if (!rectWithinArea(this.getBBox(),xformRect)) { // if it isn't within the boundary box, don't bother scanning
                    $$.d3.select(this).classed($$.config.selectedClass, false);
                    return;
                }
                var lineSegments = this.pathSegList,
                    previousPoint = lineSegments.getItem(0),
                    curSubPath = lineSegments.getItem(0),
                    lineSelection = $$.d3.select(this),
                    originalPath = this.getAttribute("d");
                for (var j = 1, l = lineSegments.numberOfItems; j < l; j++){
                    var segment = lineSegments.getItem(j);
                    switch (segment.pathSegType) {
                        case SVGPathSeg.PATHSEG_MOVETO_ABS :
                            curSubPath = segment;
                            break;
                        case SVGPathSeg.PATHSEG_LINETO_ABS:
                            if (lineWithinArea({ start: previousPoint, end: segment }, xformRect)) {
                                lineSelection.classed($$.config.selectedClass, true);
                                this.setAttribute("d", originalPath);
                                return;
                            }
                            break;
                        case SVGPathSeg.PATHSEG_CLOSEPATH:
                            if (lineWithinArea({ start: previousPoint, end: curSubPath }, xformRect)) {
                                lineSelection.classed($$.config.selectedClass, true);
                                this.setAttribute("d", originalPath);
                                return;
                            }
                            break;
                        default:
                            var sampledLines = getResampledLine(this.cloneNode(), previousPoint, segment);
                            if (sampledLines.some(function(e) { return lineWithinArea(e, xformRect); })) {
                                lineSelection.classed($$.config.selectedClass, true);
                                this.setAttribute("d", originalPath);
                                return;
                            }
                    }
                    previousPoint = segment;
                }
                this.setAttribute("d", originalPath);
                lineSelection.classed($$.config.selectedClass, false);
            });
    }

    function circleWithinArea(circle, area) {
        var half = { x: area.width/2, y: area.height/2 },
            center = {
            x: circle.x - (area.x+half.x),
            y: circle.y - (area.y+half.y)
        },
            side = {
            x: Math.abs (center.x) - half.x,
            y: Math.abs (center.y) - half.y
        };
        if (side.x >  circle.r || side.y >  circle.r)
            return false;
        if (side.x < -circle.r && side.y < -circle.r)
            return true;
        if (side.x < 0 || side.y < 0)
            return true;

        return side.x*side.x + side.y*side.y  < circle.r*circle.r;
    }

    function rectWithinArea(rect, area) {
        return rect.x < (area.x + area.width) &&
               (rect.x + rect.width) > area.x &&
               rect.y < (area.y + area.height) &&
               (rect.y + rect.height) > area.y;
    }

    function lineWithinArea(line, area) {
        var tl = { x: area.x, y: area.y + area.height },
            tr = { x: area.x + area.width, y: area.y + area.height },
            br = { x: area.x + area.width, y: area.y },
            bl = { x: area.x, y: area.y };
        if (cornorsSameSide([tl,tr,br,bl],line.start,line.end) && endProject(line.start, line.end, tl, tr, br, bl)) return true;
        return false;
    }

    function cornorsSameSide(cornorsArr, lineStart, lineEnd) {
        var xC = lineStart.x - lineEnd.x,
            yC = lineEnd.y - lineStart.y,
            os = lineEnd.x * lineStart.y - lineStart.x * lineEnd.y,
            allLessThanZero = true,
            allMoreThanZero = true;
        cornorsArr.forEach(function(e) {
            var v = e.x * yC + e.y * xC + os;
            allLessThanZero = allLessThanZero && v < 0;
            allMoreThanZero = allMoreThanZero && v > 0;
        });
        return !(allLessThanZero || allMoreThanZero);
    }

    function endProject(lineStart, lineEnd, tl, tr, br, bl) {
        return !(
            (lineStart.x > tr.x && lineEnd.x > tr.x) ||
            (lineStart.x < bl.x && lineEnd.x < bl.x) ||
            (lineStart.y > tr.y && lineEnd.y > tr.y) ||
            (lineStart.y < bl.y && lineEnd.y < bl.y)
        );
    }

    function getResampledLine(clonedNode, start, segment) {
        var lines = [],
            points = [],
            i = 0,
            segmentLength = getSegmentLength(clonedNode, start, segment),
            precision = 5; // increasing this will degrade performance but will increase the accuracy of the resampling. ** hard coded for the present **
        points.push(clonedNode.getPointAtLength(0));
        while ((i+=(1/precision)) <= 1) {
            var curPoint = clonedNode.getPointAtLength(i * segmentLength),
                pi = points.length - 1;
            lines.push({ start: { x: points[pi].x, y: points[pi].y }, end: { x: curPoint.x, y: curPoint.y }});
            points.push(curPoint);
        }
        return lines;
    }

    function getSegmentLength(node, start, segment) {
        var startX = typeof start.x !== 'undefined' ? start.x : start.x1,
            startY = typeof start.y !== 'undefined' ? start.y : start.y1,
            startEl = node.createSVGPathSegMovetoAbs(startX, startY);
        node.pathSegList.clear();
        node.pathSegList.appendItem(startEl);
        node.pathSegList.appendItem(segment);
        return node.getTotalLength();
    }

    function pauseEvent(e){
        if(e.stopPropagation) e.stopPropagation();
        if(e.preventDefault) e.preventDefault();
        e.cancelBubble=true;
        e.returnValue=false;
        return false;
    }

    window.d3dragSelector = dragSelector;

})(window);<|endoftext|>


<commit_before>CapoRSS.Router.Main = Backbone.Router.extend({
	routes: {
		"": "clear",
		"feed/:id": "viewFeed",
		"folder/:id": "viewFolder",
		"item": "viewAllItems"
	},

	initialize: function() {
		this.itemListRegion = new Backbone.Marionette.Region({
			el: '#item-list'
		});
		this.currentSelection = null;
		this.itemList = null;

		this.filters = {
			query: '',
			search_title: true,
			sort: '',
			show_read: SETTINGS.show_read
		};
	},

	/**
	 * Clear the itemList.
	 */
	clear: function() {
		$('#item-list').scrollTop(0);

		this.itemListRegion.close();

		if(this.currentSelection !== null) {
			this.currentSelection.set('active', false);
			this.currentSelection = null;
		}

		$('.mobile-item-button').addClass('invisible');
		$('#item-list').addClass('hidden-xs');
		$('.feed-list').removeClass('hidden-xs');
	},

	/**
	 * Update the itemList with the items of the model in parameter.
	 * @param {(CapoRSS.Model.Folder|CapoRSS.Model.Feed|CapoRSS.Model.AllItemsFolder)} model
	 */
	updateItemList: function(model) {
		var that = this;
		$('#item-list').scrollTop(0);
		this.itemListRegion.close();

		var options = {
			reset: true,
			reset_pagination: true,
			data: _.clone(this.filters),
			success: function() {
				that.itemListRegion.show(that.itemList);
			}
		};

		if(this.currentSelection !== null) {
			this.currentSelection.set('active', false);
			this.currentSelection.items.query = '';
			this.currentSelection.items.sort = '';
			this.currentSelection.items.search_title = false;
		}
		model.set('active', true);
		this.currentSelection = model;

		this.itemList = new CapoRSS.View.ItemList({collection: model.items});
		model.items.fetch(options);

		$('#item-list').removeClass('hidden-xs');
		$('.feed-list').addClass('hidden-xs');
		$('.mobile-item-button').removeClass('invisible');
		$('#item-list').focus();
	},

	refreshItemList: function(filters) {
		if(filters !== null) {
			this.filters = _.defaults(filters, this.filters);
		}

		if(this.currentSelection !== null) {
			this.itemList.cursor = null;
			return this.itemList.collection.fetch({
				reset: true,
				reset_pagination: true,
				data: _.clone(this.filters)
			});
		}
	},

	/**
	 * Update the item list using a feed id.
	 * @param {number} id The feed id
	 */
	viewFeed: function(id) {
		var model = CapoRSS.folders.getFeed(id);

		this.updateItemList(model);
	},

	/**
	 * Update the item list using a folder id.
	 * @param {number} id The folder id
	 */
	viewFolder: function(id) {
		var model = CapoRSS.folders.get(id);

		this.updateItemList(model);
	},

	/**
	 * Update the item list using the AllItemFolder.
	 */
	viewAllItems: function() {
		var model = CapoRSS.folderList.allItemsFolder;
		this.updateItemList(model);
	},

	/**
	 * Go to the router url for the model in parameter.
	 * @param {(CapoRSS.Model.Folder|CapoRSS.Model.Feed|CapoRSS.Model.AllItemFolder)} model
	 */
	goToModel: function(model) {
		if(model instanceof CapoRSS.Model.Folder) {
			this.navigate('folder/' + model.id, {trigger: true});
		}
		else if(model instanceof CapoRSS.Model.Feed) {
			this.navigate('feed/' + model.id, {trigger: true});
		}
		else {
			this.navigate('item', {trigger: true});
		}
    }
});
<commit_msg>Fix mobile itemlist scrolling.<commit_after>CapoRSS.Router.Main = Backbone.Router.extend({
	routes: {
		"": "clear",
		"feed/:id": "viewFeed",
		"folder/:id": "viewFolder",
		"item": "viewAllItems"
	},

	initialize: function() {
		this.itemListRegion = new Backbone.Marionette.Region({
			el: '#item-list'
		});
		this.currentSelection = null;
		this.itemList = null;

		this.filters = {
			query: '',
			search_title: true,
			sort: '',
			show_read: SETTINGS.show_read
		};
	},

	/**
	 * Clear the itemList.
	 */
	clear: function() {
		$('#item-list').scrollTop(0);

		this.itemListRegion.close();

		if(this.currentSelection !== null) {
			this.currentSelection.set('active', false);
			this.currentSelection = null;
		}

		$('.mobile-item-button').addClass('invisible');
		$('#item-list').addClass('hidden-xs');
		$('.feed-list').removeClass('hidden-xs');

		// FIXME: This line is needed to fix scrolling on mobile. A CSS fix would be better.
		$(window).resize();
	},

	/**
	 * Update the itemList with the items of the model in parameter.
	 * @param {(CapoRSS.Model.Folder|CapoRSS.Model.Feed|CapoRSS.Model.AllItemsFolder)} model
	 */
	updateItemList: function(model) {
		var that = this;
		$('#item-list').scrollTop(0);
		this.itemListRegion.close();

		var options = {
			reset: true,
			reset_pagination: true,
			data: _.clone(this.filters),
			success: function() {
				that.itemListRegion.show(that.itemList);
			}
		};

		if(this.currentSelection !== null) {
			this.currentSelection.set('active', false);
			this.currentSelection.items.query = '';
			this.currentSelection.items.sort = '';
			this.currentSelection.items.search_title = false;
		}
		model.set('active', true);
		this.currentSelection = model;

		this.itemList = new CapoRSS.View.ItemList({collection: model.items});
		model.items.fetch(options);

		$('#item-list').removeClass('hidden-xs');
		$('.feed-list').addClass('hidden-xs');
		$('.mobile-item-button').removeClass('invisible');
		$('#item-list').focus();

		// FIXME: This line is needed to fix scrolling on mobile. A CSS fix would be better.
		$(window).resize();
	},

	refreshItemList: function(filters) {
		if(filters !== null) {
			this.filters = _.defaults(filters, this.filters);
		}

		if(this.currentSelection !== null) {
			this.itemList.cursor = null;
			return this.itemList.collection.fetch({
				reset: true,
				reset_pagination: true,
				data: _.clone(this.filters)
			});
		}
	},

	/**
	 * Update the item list using a feed id.
	 * @param {number} id The feed id
	 */
	viewFeed: function(id) {
		var model = CapoRSS.folders.getFeed(id);

		this.updateItemList(model);
	},

	/**
	 * Update the item list using a folder id.
	 * @param {number} id The folder id
	 */
	viewFolder: function(id) {
		var model = CapoRSS.folders.get(id);

		this.updateItemList(model);
	},

	/**
	 * Update the item list using the AllItemFolder.
	 */
	viewAllItems: function() {
		var model = CapoRSS.folderList.allItemsFolder;
		this.updateItemList(model);
	},

	/**
	 * Go to the router url for the model in parameter.
	 * @param {(CapoRSS.Model.Folder|CapoRSS.Model.Feed|CapoRSS.Model.AllItemFolder)} model
	 */
	goToModel: function(model) {
		if(model instanceof CapoRSS.Model.Folder) {
			this.navigate('folder/' + model.id, {trigger: true});
		}
		else if(model instanceof CapoRSS.Model.Feed) {
			this.navigate('feed/' + model.id, {trigger: true});
		}
		else {
			this.navigate('item', {trigger: true});
		}
    }
});
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import cn from '../../utils/cn'
import prism from '../../utils/prism'
import getIndent from '../../utils/getIndent'
import normalizeCode from '../../utils/normalizeCode'
import normalizeHtml from '../../utils/normalizeHtml'
import htmlToPlain from '../../utils/htmlToPlain'
import selectionRange from '../../vendor/selection-range'

class Editor extends Component {
  static defaultProps = {
    contentEditable: true
  }

  undoStack = []
  undoOffset = 0
  undoTimestamp = 0

  state = {
    html: ''
  }

  onRef = node => {
    this.ref = node
  }

  getPlain = () => {
    if (this._innerHTML === this.ref.innerHTML) {
      return this._plain
    }

    const plain = htmlToPlain(normalizeHtml(this.ref.innerHTML))

    this._plain = plain
    this._innerHTML = this.ref.innerHTML

    return this._plain
  }

  recordChange = (plain, selection) => {
    if (plain === this.undoStack[this.undoStack.length - 1]) {
      return
    }

    if (this.undoOffset > 0) {
      this.undoStack = this.undoStack.slice(0, -this.undoOffset)
      this.undoOffset = 0
    }

    const timestamp = Date.now()
    const record = { plain, selection }

    // Overwrite last record if threshold is not crossed
    if (timestamp - this.undoTimestamp < 3000) {
      this.undoStack[this.undoStack.length - 1] = record
    } else {
      this.undoStack.push(record)

      if (this.undoStack.length > 50) {
        this.undoStack.shift()
      }
    }

    this.undoTimestamp = timestamp
  }

  updateContent = plain => {
    this.setState({ html: prism(plain) })

    if (this.props.onChange) {
      this.props.onChange(plain)
    }
  }

  restoreStackState = offset => {
    const { plain, selection } = this.undoStack[this.undoStack.length - 1 - offset]

    this.selection = selection
    this.undoOffset = offset
    this.updateContent(plain)
  }

  undo = () => {
    const offset = this.undoOffset + 1
    if (offset >= this.undoStack.length) {
      return
    }

    this.restoreStackState(offset)
  }

  redo = () => {
    const offset = this.undoOffset - 1
    if (offset < 0) {
      return
    }

    this.restoreStackState(offset)
  }

  onKeyDown = evt => {
    if (this.props.onKeyDown) {
      this.props.onKeyDown(evt)
    }
    if (evt.keyCode === 9 && !this.props.ignoreTabKey) { // Tab Key
      document.execCommand('insertHTML', false, '&#009')
      evt.preventDefault()
    } else if (evt.keyCode === 13) { // Enter Key
      const { start: cursorPos } = selectionRange(this.ref)
      const indentation = getIndent(this.getPlain(), cursorPos)

      document.execCommand('insertHTML', false, '\n' + indentation)
      evt.preventDefault()
    } else if (
      // Undo / Redo
      evt.keyCode === 90 &&
      evt.metaKey !== evt.ctrlKey &&
      !evt.altKey
    ) {
      if (evt.shiftKey) {
        this.redo()
      } else {
        this.undo()
      }

      evt.preventDefault()
    }
  }

  onKeyUp = evt => {
    if (this.props.onKeyUp) {
      this.props.onKeyUp(evt)
    }
    if (
      evt.keyCode === 91 || // left cmd
      evt.keyCode === 93 || // right cmd
      evt.ctrlKey ||
      evt.metaKey
    ) {
      return
    }

    // Enter key
    if (evt.keyCode === 13) {
      this.undoTimestamp = 0
    }

    this.selection = selectionRange(this.ref)

    if (
      evt.keyCode !== 37 && // left
      evt.keyCode !== 38 && // up
      evt.keyCode !== 39 && // right
      evt.keyCode !== 40 // down
    ) {
      const plain = this.getPlain()

      this.recordChange(plain, this.selection)
      this.updateContent(plain)
    } else {
      this.undoTimestamp = 0
    }
  }

  onClick = evt => {
    if (this.props.onClick) {
      this.props.onClick(evt)
    }
    this.undoTimestamp = 0 // Reset timestamp
    this.selection = selectionRange(this.ref)
  }

  componentWillMount() {
    const html = prism(normalizeCode(this.props.code))
    this.setState({ html })
  }

  componentDidMount() {
    this.recordChange(this.getPlain())
    this.undoTimestamp = 0 // Reset timestamp
  }

  componentWillReceiveProps({ code }) {
    if (code !== this.props.code) {
      const html = prism(normalizeCode(code))
      this.setState({ html })
    }
  }

  componentDidUpdate() {
    const { selection } = this
    if (selection) {
      selectionRange(this.ref, selection)
    }
  }

  render() {
    const { contentEditable, className, style, ...rest } = this.props
    const { html } = this.state
    delete rest.code

    return (
      <pre
        {...rest}
        ref={this.onRef}
        className={cn('prism-code', className)}
        style={style}
        contentEditable={contentEditable}
        onKeyDown={contentEditable && this.onKeyDown}
        onKeyUp={contentEditable && this.onKeyUp}
        onClick={contentEditable && this.onClick}
        dangerouslySetInnerHTML={{ __html: html }}
      />
    )
  }
}

export default Editor
<commit_msg>Disable spellcheck in editor<commit_after>import React, { Component } from 'react'
import cn from '../../utils/cn'
import prism from '../../utils/prism'
import getIndent from '../../utils/getIndent'
import normalizeCode from '../../utils/normalizeCode'
import normalizeHtml from '../../utils/normalizeHtml'
import htmlToPlain from '../../utils/htmlToPlain'
import selectionRange from '../../vendor/selection-range'

class Editor extends Component {
  static defaultProps = {
    contentEditable: true
  }

  undoStack = []
  undoOffset = 0
  undoTimestamp = 0

  state = {
    html: ''
  }

  onRef = node => {
    this.ref = node
  }

  getPlain = () => {
    if (this._innerHTML === this.ref.innerHTML) {
      return this._plain
    }

    const plain = htmlToPlain(normalizeHtml(this.ref.innerHTML))

    this._plain = plain
    this._innerHTML = this.ref.innerHTML

    return this._plain
  }

  recordChange = (plain, selection) => {
    if (plain === this.undoStack[this.undoStack.length - 1]) {
      return
    }

    if (this.undoOffset > 0) {
      this.undoStack = this.undoStack.slice(0, -this.undoOffset)
      this.undoOffset = 0
    }

    const timestamp = Date.now()
    const record = { plain, selection }

    // Overwrite last record if threshold is not crossed
    if (timestamp - this.undoTimestamp < 3000) {
      this.undoStack[this.undoStack.length - 1] = record
    } else {
      this.undoStack.push(record)

      if (this.undoStack.length > 50) {
        this.undoStack.shift()
      }
    }

    this.undoTimestamp = timestamp
  }

  updateContent = plain => {
    this.setState({ html: prism(plain) })

    if (this.props.onChange) {
      this.props.onChange(plain)
    }
  }

  restoreStackState = offset => {
    const { plain, selection } = this.undoStack[this.undoStack.length - 1 - offset]

    this.selection = selection
    this.undoOffset = offset
    this.updateContent(plain)
  }

  undo = () => {
    const offset = this.undoOffset + 1
    if (offset >= this.undoStack.length) {
      return
    }

    this.restoreStackState(offset)
  }

  redo = () => {
    const offset = this.undoOffset - 1
    if (offset < 0) {
      return
    }

    this.restoreStackState(offset)
  }

  onKeyDown = evt => {
    if (this.props.onKeyDown) {
      this.props.onKeyDown(evt)
    }
    if (evt.keyCode === 9 && !this.props.ignoreTabKey) { // Tab Key
      document.execCommand('insertHTML', false, '&#009')
      evt.preventDefault()
    } else if (evt.keyCode === 13) { // Enter Key
      const { start: cursorPos } = selectionRange(this.ref)
      const indentation = getIndent(this.getPlain(), cursorPos)

      document.execCommand('insertHTML', false, '\n' + indentation)
      evt.preventDefault()
    } else if (
      // Undo / Redo
      evt.keyCode === 90 &&
      evt.metaKey !== evt.ctrlKey &&
      !evt.altKey
    ) {
      if (evt.shiftKey) {
        this.redo()
      } else {
        this.undo()
      }

      evt.preventDefault()
    }
  }

  onKeyUp = evt => {
    if (this.props.onKeyUp) {
      this.props.onKeyUp(evt)
    }
    if (
      evt.keyCode === 91 || // left cmd
      evt.keyCode === 93 || // right cmd
      evt.ctrlKey ||
      evt.metaKey
    ) {
      return
    }

    // Enter key
    if (evt.keyCode === 13) {
      this.undoTimestamp = 0
    }

    this.selection = selectionRange(this.ref)

    if (
      evt.keyCode !== 37 && // left
      evt.keyCode !== 38 && // up
      evt.keyCode !== 39 && // right
      evt.keyCode !== 40 // down
    ) {
      const plain = this.getPlain()

      this.recordChange(plain, this.selection)
      this.updateContent(plain)
    } else {
      this.undoTimestamp = 0
    }
  }

  onClick = evt => {
    if (this.props.onClick) {
      this.props.onClick(evt)
    }
    this.undoTimestamp = 0 // Reset timestamp
    this.selection = selectionRange(this.ref)
  }

  componentWillMount() {
    const html = prism(normalizeCode(this.props.code))
    this.setState({ html })
  }

  componentDidMount() {
    this.recordChange(this.getPlain())
    this.undoTimestamp = 0 // Reset timestamp
  }

  componentWillReceiveProps({ code }) {
    if (code !== this.props.code) {
      const html = prism(normalizeCode(code))
      this.setState({ html })
    }
  }

  componentDidUpdate() {
    const { selection } = this
    if (selection) {
      selectionRange(this.ref, selection)
    }
  }

  render() {
    const { contentEditable, className, style, ...rest } = this.props
    const { html } = this.state
    delete rest.code

    return (
      <pre
        {...rest}
        ref={this.onRef}
        className={cn('prism-code', className)}
        style={style}
        spellCheck="false"
        contentEditable={contentEditable}
        onKeyDown={contentEditable && this.onKeyDown}
        onKeyUp={contentEditable && this.onKeyUp}
        onClick={contentEditable && this.onClick}
        dangerouslySetInnerHTML={{ __html: html }}
      />
    )
  }
}

export default Editor
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Jive Software
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

var jive = require("jive-sdk");
var q = require("q");
var store = jive.service.persistence();
var JiveApi = require("./JiveApiFacade");
var JiveOauth = require("./JiveOauth");

var STORE_NAME = "places";

function recursiveOverwrite(record,newObject){
    if (typeof(newObject) === "object" || typeof newObject === "array") {
        for(var m in newObject) {
            if(record[m]){
                recursiveOverwrite(record[m], newObject[m]);
            }else {
                record[m] = newObject[m];
            }
        }

    }else{
        record = newObject;
    }

}

/**
 * save will store the object with the given placeUrl as the key. If the object
 * already exists then it does a recursive overwrite of members. Meaning it only
 * overwrites members currently there at any level.
 * @param {string} placeUrl the key to identify the place
 * @param {object} set of members to place/overwrite on the record.
 * @param {boolean} dontStamp if this is true then the cache is not invalidated after save.
 * @return {promise} the new record is returned. External properties are not gathered to
 * allow client code to do validation.
 */
exports.save = function(placeUrl, newObject, dontStamp){
    if(!placeUrl || placeUrl === "" || typeof placeUrl !== "string"){
        throw Error("Invalid Place");
    }
    return store.findByID(STORE_NAME, placeUrl).then(function (found) {
        var record = found || {};
        recursiveOverwrite(record, newObject);
        var delimitter = "/";
        var tokens = placeUrl.split(delimitter);
        var domainTokens = tokens.slice(0, 3);

        record.jiveUrl =  domainTokens.join(delimitter);
        record.placeID =  tokens[tokens.length -1];
        record.placeUrl = placeUrl;
        record.invalidCache = !dontStamp;
        return store.save(STORE_NAME, placeUrl, record).then(function(){
            return record;
        });
    })
};

/**
 * refresh the cache for a given record. The cache is not left in an invalid state.
 * @param {string} placeUrl the key for the given place
 * @return {object} the record is returned with refreshed cache elements
 */
exports.invalidateCache = function(placeUrl){
    if(!placeUrl || placeUrl === "" || typeof placeUrl !== "string"){
        throw Error("Invalid Place");
    }
    var self = this;
    return self.save(placeUrl).then(function (record) {
        return pullExternalPropertiesIn(self, record);
    })
}

function pullExternalPropertiesIn(self,linked){
    if(linked &&
        linked.jive &&
        (linked.github && (!linked.github.repoOwner || !linked.github.repo)
            || linked.invalidCache)){
        //cache repo information
        return jive.community.findByJiveURL(linked.jiveUrl).then(function (community) {
            var jauth = new JiveOauth(linked.placeUrl,linked.jive.access_token, linked.jive.refresh_token);
            var japi = new JiveApi(community, jauth);
            return japi.getAllExtProps("places/" + linked.placeID).then(function (extprops) {
                linked.github.repo = extprops.github4jiveRepo;
                linked.github.repoOwner = extprops.github4jiveRepoOwner;
                var githubReplacement = {"github": linked.github};
                return self.save(linked.placeUrl, githubReplacement, true);
            })
        });

    }else{
        return linked;
    }
}

/**
 * Get all place records out of the store
 * @return {[object]} returns array of all place records.
 */
exports.getAllPlaces = function(){
    var self = this;
    return store.find(STORE_NAME).then(function (linkedPlaces) {
        return q.all(linkedPlaces.map(function (linked) {
            return pullExternalPropertiesIn(self, linked);
        }));
    });
};

/**
 * Retrieve a record by its place api url
 * @param {string} placeurl the full api url for the place
 * @return {object} the record with hydrated cache elements.
 */
exports.getPlaceByUrl = function(placeUrl){
    var self = this;
    return store.findByID(STORE_NAME, placeUrl).then(function (linked) {
        return pullExternalPropertiesIn(self,linked);
    });
};<commit_msg>fixed faulty recursive overwrite method<commit_after>/*
 * Copyright 2014 Jive Software
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

var jive = require("jive-sdk");
var q = require("q");
var store = jive.service.persistence();
var JiveApi = require("./JiveApiFacade");
var JiveOauth = require("./JiveOauth");

var STORE_NAME = "places";

function recursiveOverwrite(record,newObject){
    if (typeof(newObject) === "object" || typeof newObject === "array") {
        for(var m in newObject) {
            if(record[m]){
                recursiveOverwrite(record[m], newObject[m]);
            }else {
                record[m] = newObject[m];
            }
        }

    }else{
        record = newObject;
    }

}

function extend(origin, add) {
  // Don't do anything if add isn't an object
  if (!add || typeof add !== 'object') return origin;

  var keys = Object.keys(add);
  var i = keys.length;
  while (i--) {
    origin[keys[i]] = add[keys[i]];
  }
  return origin;
}

/**
 * save will store the object with the given placeUrl as the key. If the object
 * already exists then it does a recursive overwrite of members. Meaning it only
 * overwrites members currently there at any level.
 * @param {string} placeUrl the key to identify the place
 * @param {object} set of members to place/overwrite on the record.
 * @param {boolean} dontStamp if this is true then the cache is not invalidated after save.
 * @return {promise} the new record is returned. External properties are not gathered to
 * allow client code to do validation.
 */
exports.save = function(placeUrl, newObject, dontStamp){
    if(!placeUrl || placeUrl === "" || typeof placeUrl !== "string"){
        throw Error("Invalid Place");
    }
    return store.findByID(STORE_NAME, placeUrl).then(function (found) {
        var record = found || {};
        extend(record, newObject);
        var delimitter = "/";
        var tokens = placeUrl.split(delimitter);
        var domainTokens = tokens.slice(0, 3);

        record.jiveUrl =  domainTokens.join(delimitter);
        record.placeID =  tokens[tokens.length -1];
        record.placeUrl = placeUrl;
        record.invalidCache = !dontStamp;
        return store.save(STORE_NAME, placeUrl, record).then(function(){
            return record;
        });
    })
};

/**
 * refresh the cache for a given record. The cache is not left in an invalid state.
 * @param {string} placeUrl the key for the given place
 * @return {object} the record is returned with refreshed cache elements
 */
exports.invalidateCache = function(placeUrl){
    if(!placeUrl || placeUrl === "" || typeof placeUrl !== "string"){
        throw Error("Invalid Place");
    }
    var self = this;
    return self.save(placeUrl).then(function (record) {
        return pullExternalPropertiesIn(self, record);
    })
}

function pullExternalPropertiesIn(self,linked){
    if(linked &&
        linked.jive &&
        (linked.github && (!linked.github.repoOwner || !linked.github.repo)
            || linked.invalidCache)){
        //cache repo information
        return jive.community.findByJiveURL(linked.jiveUrl).then(function (community) {
            var jauth = new JiveOauth(linked.placeUrl,linked.jive.access_token, linked.jive.refresh_token);
            var japi = new JiveApi(community, jauth);
            return japi.getAllExtProps("places/" + linked.placeID).then(function (extprops) {
                linked.github.repo = extprops.github4jiveRepo;
                linked.github.repoOwner = extprops.github4jiveRepoOwner;
                var githubReplacement = {"github": linked.github};
                return self.save(linked.placeUrl, githubReplacement, true);
            })
        });

    }else{
        return linked;
    }
}

/**
 * Get all place records out of the store
 * @return {[object]} returns array of all place records.
 */
exports.getAllPlaces = function(){
    var self = this;
    return store.find(STORE_NAME).then(function (linkedPlaces) {
        return q.all(linkedPlaces.map(function (linked) {
            return pullExternalPropertiesIn(self, linked);
        }));
    });
};

/**
 * Retrieve a record by its place api url
 * @param {string} placeurl the full api url for the place
 * @return {object} the record with hydrated cache elements.
 */
exports.getPlaceByUrl = function(placeUrl){
    var self = this;
    return store.findByID(STORE_NAME, placeUrl).then(function (linked) {
        return pullExternalPropertiesIn(self,linked);
    });
};
<|endoftext|>


<commit_before>// Copyright 2011-2018, The Trustees of Indiana University and Northwestern
//   University.  Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
//   under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
//   CONDITIONS OF ANY KIND, either express or implied. See the License for the
//   specific language governing permissions and limitations under the License.

/**
 * Quality helper class to add functionality to stock MEJS quality plugin
 * @class MEJSQualityHelper
 */
class MEJSQualityHelper {
  constructor() {
    $(document).on('mejs4handleSuccess', this.addQualitySelectorListeners);
  }

  /**
   * Add event listeners to send quality selections to server
   * @function addQualitySelectorListeners
   * @return {void}
   */
  addQualitySelectorListeners() {
    const player = mejs4AvalonPlayer.player;
    const radios = player.qualitiesButton.querySelectorAll(
      'input[type="radio"]'
    );

    for (let i = 0, total = radios.length; i < total; i++) {
      const radio = radios[i];
      radio.addEventListener(
        'change',
        mejs4AvalonPlayer.mejsQualityHelper.sendQualitySelection
      );
    }
  }

  sendQualitySelection(e) {
    $.ajax({
      type: 'POST',
      url: '/media_objects/set_session_quality',
      data: { quality: e.target.quality },
      dataType: 'json'
    });
  }
}
<commit_msg>Update mejs4_helper_quality.es6 (#2818)<commit_after>// Copyright 2011-2018, The Trustees of Indiana University and Northwestern
//   University.  Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed
//   under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
//   CONDITIONS OF ANY KIND, either express or implied. See the License for the
//   specific language governing permissions and limitations under the License.

/**
 * Quality helper class to add functionality to stock MEJS quality plugin
 * @class MEJSQualityHelper
 */
class MEJSQualityHelper {
  constructor() {
    $(document).on('mejs4handleSuccess', this.addQualitySelectorListeners);
  }

  /**
   * Add event listeners to send quality selections to server
   * @function addQualitySelectorListeners
   * @return {void}
   */
  addQualitySelectorListeners() {
    const player = mejs4AvalonPlayer.player;
    const radios = player.qualitiesButton.querySelectorAll(
      'input[type="radio"]'
    );

    for (let i = 0, total = radios.length; i < total; i++) {
      const radio = radios[i];
      radio.addEventListener(
        'change',
        mejs4AvalonPlayer.mejsQualityHelper.sendQualitySelection
      );
    }
  }

  sendQualitySelection(e) {
    $.ajax({
      type: 'POST',
      url: '/media_objects/set_session_quality',
      data: { quality: e.target.value },
      dataType: 'json'
    });
  }
}
<|endoftext|>


<commit_before>/**
 * Create a Formed layout.
 */

import _assign from 'lodash/assign';

const layout = (() => {
  'use strict';

  const defaults = {
    parent: null
  };

  const cssInterface = {
    headerClass: 'Layout-header',
    drawerClass: 'Layout-drawer',
    drawerBtnClass: 'Layout-header-menu',
    mainClass: 'Layout-main',
    maskClass: 'Layout-mask',
    isDrawerActiveClass: 'is-active',
    breakpoint: '(min-width: 992px)'
  };

  const KEYCODES = {
    ENTER: 13,
    ESCAPE: 27,
    SPACE: 32
  };

  function hasActiveDrawer() {
    return this.drawer
      && this.drawer.classList.contains(cssInterface.isDrawerActiveClass);
  }

  function hasDrawerFixed() {
    return this.drawer
      && this.element.classList.contains('Layout--drawerFixed');
  }

  function toggleDrawer() {
    this.drawer.classList.toggle(cssInterface.isDrawerActiveClass);
    this.mask.classList.toggle(cssInterface.isDrawerActiveClass);

    // Set aria attributes
    if (this.hasActiveDrawer()) {
      this.drawer.setAttribute('aria-hidden', 'false');
      this.drawerBtn.setAttribute('aria-expanded', 'true');
    }
    else {
      this.drawer.setAttribute('aria-hidden', 'true');
      this.drawerBtn.setAttribute('aria-expanded', 'false');
    }
  }

  // Create a new layout, returning new object with the api attached to its
  // proto.

  function create(element, options = {}) {
    const layout = Object.create(api);

    layout.config = _assign({}, defaults, options);
    layout.element = element;

    wrapLayout.call(layout);
    cacheChildren.call(layout);

    if (layout.drawer) {
      drawerSetup.call(layout);
    }

    layout.breakpoint =
      window.matchMedia((cssInterface.breakpoint));

    screenSizeHandler.call(layout);
    bindings.call(layout);

    return layout;
  }

  // Private functions

  // Handlers

  function drawerToggleHandler(evt) {
    const { SPACE, ENTER } = KEYCODES;

    if (evt && (evt.type === 'keydown')) {
      if (evt.keyCode === SPACE || evt.keyCode === ENTER) {
        evt.preventDefault();
      }
      else {
        return;
      }
    }

    this.toggleDrawer();
  }

  function keyboardHandler(evt) {
    if (evt.keyCode === KEYCODES.ESCAPE
        && this.hasActiveDrawer()) {
      this.toggleDrawer();
    }
  }

  function screenSizeHandler() {
    if (this.breakpoint.matches && this.drawer) {
      this.drawer
        .setAttribute('aria-hidden', (!this.hasDrawerFixed()).toString());
      this.drawerBtn.setAttribute('aria-expanded', 'false');

      this.drawer.classList.remove(cssInterface.isDrawerActiveClass);
      this.mask.classList.remove(cssInterface.isDrawerActiveClass);
    }
    else if (this.hasDrawerFixed()) {
      this.drawer.setAttribute('aria-hidden', 'true');
    }
  }

  // Helpers

  function bindings() {
    if (this.drawer) {
      this.drawerBtn
        .addEventListener('click', drawerToggleHandler.bind(this));

      this.drawerBtn
        .addEventListener('keydown', drawerToggleHandler.bind(this));

      this.drawer
        .addEventListener('keydown', keyboardHandler.bind(this));

      this.mask.addEventListener('click',
          drawerToggleHandler.bind(this));
    }

    this.breakpoint.addListener(screenSizeHandler.bind(this));

    return this;
  }

  function wrapLayout() {
    const container = !this.config.parent
      ? document.createElement('div')
      : document.querySelector(this.config.parent);

    container.classList.add('layout-absoluteViewport');

    // Capter any focused element.
    const focusedElement = document.querySelector(':focus');

    if (!this.config.parent) {
      this.element.parentNode.insertBefore(container, this.element);
      this.element.parentNode.removeChild(this.element);
      container.appendChild(this.element);
    }

    if (focusedElement) {
      focusedElement.focus();
    }

    return this;
  }

  function cacheChildren() {
    const directChildren = this.element.childNodes;
    const numChildren = directChildren.length;

    for (let i = 0; i < numChildren; i++) {
      let child = directChildren[i];

      if (child.classList
          && child.classList.contains(cssInterface.headerClass)) {
        this.header = child;
      }

      if (child.classList
          && child.classList.contains(cssInterface.drawerClass)) {
        this.drawer = child;
      }

      if (child.classList
          && child.classList.contains(cssInterface.mainClass)) {
        this.main = child;
      }
    }

    return this;
  }

  function drawerSetup() {
    this.drawerBtn =
          this.element.querySelector(`.${cssInterface.drawerBtnClass}`);

    if (!this.drawerBtn) {
      throw Error(`No ${cssInterface.drawerBtnClass} detected.`);
    }

    // Ensure proper attributes are set.
    this.drawer.setAttribute('aria-hidden', 'true');
    this.drawerBtn.setAttribute('aria-expanded', 'false');
    this.drawerBtn.setAttribute('tabindex', '0');
    this.drawerBtn.setAttribute('type', 'button');

    // If not button add proper aria attr.
    if (this.drawerBtn.tagName.toLowerCase() !== 'button') {
      this.drawerBtn.setAttribute('role', 'button');
    }

    createLayoutMask.call(this);

    return this;
  }

  function createLayoutMask() {
    this.mask = document.createElement('div');
    this.mask.classList.add(cssInterface.maskClass);

    this.element.appendChild(this.mask);

    return this;
  }

  const api = {
    hasActiveDrawer,
    hasDrawerFixed,
    toggleDrawer
  };

  return create;
})();

export default layout;
<commit_msg>feat(component): layout<commit_after>/**
 * Create a Formed layout.
 */

import _assign from 'lodash/assign';

const layout = (() => {
  'use strict';

  const defaults = {
    parent: null
  };

  const cssInterface = {
    headerClass: 'Layout-header',
    drawerClass: 'Layout-drawer',
    drawerBtnClass: 'Layout-header-menu',
    mainClass: 'Layout-main',
    maskClass: 'Layout-mask',
    isDrawerActiveClass: 'is-active',
    breakpoint: '(min-width: 992px)'
  };

  const KEYCODES = {
    ENTER: 13,
    ESCAPE: 27,
    SPACE: 32
  };

  function hasActiveDrawer() {
    return this.drawer
      && this.drawer.classList.contains(cssInterface.isDrawerActiveClass);
  }

  function hasDrawerFixed() {
    return this.drawer
      && this.element.classList.contains('Layout--drawerFixed');
  }

  function destroy() {
    killEvents.call(this);
  }

  function refresh() {
    killEvents.call(this);
    cacheChildren.call(this);

    if (this.drawer) {
      drawerSetup.call(this);
    }

    this.screenSizeHandler();

    events.call(this);

    return this;
  }

  function toggleDrawer() {
    this.drawer.classList.toggle(cssInterface.isDrawerActiveClass);
    this.mask.classList.toggle(cssInterface.isDrawerActiveClass);

    // Set aria attributes
    if (this.hasActiveDrawer()) {
      this.drawer.setAttribute('aria-hidden', 'false');
      this.drawerBtn.setAttribute('aria-expanded', 'true');
    }
    else {
      this.drawer.setAttribute('aria-hidden', 'true');
      this.drawerBtn.setAttribute('aria-expanded', 'false');
    }

    return this;
  }

  // Create a new layout, returning new object with the api attached to its
  // proto.

  function create(element, options = {}) {
    const layout = Object.create(api);

    layout.config = _assign({}, defaults, options);
    layout.element = element;

    layout.drawerToggleHandler = drawerToggleHandler.bind(layout);
    layout.keyboardHandler = keyboardHandler.bind(layout);
    layout.screenSizeHandler = screenSizeHandler.bind(layout);

    wrapLayout.call(layout);
    cacheChildren.call(layout);

    if (layout.drawer) {
      drawerSetup.call(layout);
    }

    layout.breakpoint = window.matchMedia((cssInterface.breakpoint));

    layout.screenSizeHandler();
    events.call(layout);

    return layout;
  }

  // Private functions

  // Handlers

  function drawerToggleHandler(evt) {
    const { SPACE, ENTER } = KEYCODES;

    if (evt && (evt.type === 'keydown')) {
      if (evt.keyCode === SPACE || evt.keyCode === ENTER) {
        evt.preventDefault();
      }
      else {
        return;
      }
    }

    this.toggleDrawer();
  }

  function keyboardHandler(evt) {
    if (evt.keyCode === KEYCODES.ESCAPE
        && this.hasActiveDrawer()) {
      this.toggleDrawer();
    }
  }

  function screenSizeHandler() {
    if (this.breakpoint.matches && this.drawer) {
      this.drawer
        .setAttribute('aria-hidden', (!this.hasDrawerFixed()).toString());
      this.drawerBtn.setAttribute('aria-expanded', 'false');

      this.drawer.classList.remove(cssInterface.isDrawerActiveClass);
      this.mask.classList.remove(cssInterface.isDrawerActiveClass);
    }
    else if (this.hasDrawerFixed()) {
      this.drawer.setAttribute('aria-hidden', 'true');
    }
  }

  // Helpers

  function events() {
    if (this.drawer) {
      this.drawerBtn
        .addEventListener('click', this.drawerToggleHandler);

      this.drawerBtn
        .addEventListener('keydown', this.drawerToggleHandler);

      this.drawer
        .addEventListener('keydown', this.keyboardHandler);

      this.mask
        .addEventListener('click', this.drawerToggleHandler);
    }

    this.breakpoint.addListener(this.screenSizeHandler);

    return this;
  }

  function killEvents() {
    if (this.drawer) {
      this.drawerBtn
        .removeEventListener('click', this.drawerToggleHandler);

      this.drawerBtn
        .removeEventListener('keydown', this.drawerToggleHandler);

      this.drawer
        .removeEventListener('keydown', this.keyboardHandler);

      this.mask
        .removeEventListener('click', this.drawerToggleHandler);
    }

    this.breakpoint.removeListener(screenSizeHandler);
  }

  function wrapLayout() {
    const container = !this.config.parent
      ? document.createElement('div')
      : document.querySelector(this.config.parent);

    container.classList.add('layout-absoluteViewport');

    // Capter any focused element.
    const focusedElement = document.querySelector(':focus');

    if (!this.config.parent) {
      this.element.parentNode.insertBefore(container, this.element);
      this.element.parentNode.removeChild(this.element);
      container.appendChild(this.element);
    }

    if (focusedElement) {
      focusedElement.focus();
    }

    return this;
  }

  function cacheChildren() {
    const directChildren = this.element.childNodes;
    const numChildren = directChildren.length;

    for (let i = 0; i < numChildren; i++) {
      let child = directChildren[i];

      if (child.classList
          && child.classList.contains(cssInterface.headerClass)) {
        this.header = child;
      }

      if (child.classList
          && child.classList.contains(cssInterface.drawerClass)) {
        this.drawer = child;
      }

      if (child.classList
          && child.classList.contains(cssInterface.mainClass)) {
        this.main = child;
      }
    }

    return this;
  }

  function drawerSetup() {
    this.drawerBtn =
          this.element.querySelector(`.${cssInterface.drawerBtnClass}`);

    if (!this.drawerBtn) {
      throw Error(`No ${cssInterface.drawerBtnClass} detected.`);
    }

    // Ensure proper attributes are set.
    this.drawer.setAttribute('aria-hidden', 'true');
    this.drawerBtn.setAttribute('aria-expanded', 'false');
    this.drawerBtn.setAttribute('tabindex', '0');
    this.drawerBtn.setAttribute('type', 'button');

    // If not button add proper aria attr.
    if (this.drawerBtn.tagName.toLowerCase() !== 'button') {
      this.drawerBtn.setAttribute('role', 'button');
    }

    createLayoutMask.call(this);

    return this;
  }

  function createLayoutMask() {
    this.mask = document.createElement('div');
    this.mask.classList.add(cssInterface.maskClass);

    this.element.appendChild(this.mask);

    return this;
  }

  const api = {
    destroy,
    hasActiveDrawer,
    hasDrawerFixed,
    toggleDrawer,
    refresh
  };

  return create;
})();

export default layout;
<|endoftext|>


<commit_before>import React, {Component} from 'react';

let INTERVAL_ID;

class DetectHttpsServer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            successfulFetch: false
        };
    }

    // TODO - Maybe make this it's own stateful component
    componentWillMount() {

        // TODO - It seems like you need to restart the app in order for the
        // app to use the newly installed certs -
        // the fetch won't change from failure to success
        // with a single app session.
        // So, I don't think this needs to be a setInterval..
        // TODO - verify this.

        INTERVAL_ID = setInterval(() => {
            // TODO - Instead of "secure", use "status"
            fetch('https://connector.plot.ly:5001/secure')
            .then(request => {
                console.warn('successfulFetch: true');
                this.setState({successfulFetch: true});
            })
            .catch(err => {
                if (err.message === 'failed to fetch') {
                    console.warn('successfulFetch: false');
                    this.setState({successfulFetch: false});
                }
            });
        }, 1000);
    }

    componentWillUnmount() {
        clearInterval(INTERVAL_ID);
    }

    render() {
        console.warn(this.state);
        if (this.state.successfulFetch) {
            console.warn('renderSuccess');
            return this.props.renderSuccess;
        } else {
            console.warn('renderFailed');
            return this.props.renderFailed;
        }
    }

}

export default DetectHttpsServer;
<commit_msg>rm copy and pasted todo<commit_after>import React, {Component} from 'react';

let INTERVAL_ID;

class DetectHttpsServer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            successfulFetch: false
        };
    }

    componentWillMount() {

        // TODO - It seems like you need to restart the app in order for the
        // app to use the newly installed certs -
        // the fetch won't change from failure to success
        // with a single app session.
        // So, I don't think this needs to be a setInterval..
        // TODO - verify this.

        INTERVAL_ID = setInterval(() => {
            // TODO - Instead of "secure", use "status"
            fetch('https://connector.plot.ly:5001/secure')
            .then(request => {
                console.warn('successfulFetch: true');
                this.setState({successfulFetch: true});
            })
            .catch(err => {
                if (err.message === 'failed to fetch') {
                    console.warn('successfulFetch: false');
                    this.setState({successfulFetch: false});
                }
            });
        }, 1000);
    }

    componentWillUnmount() {
        clearInterval(INTERVAL_ID);
    }

    render() {
        console.warn(this.state);
        if (this.state.successfulFetch) {
            console.warn('renderSuccess');
            return this.props.renderSuccess;
        } else {
            console.warn('renderFailed');
            return this.props.renderFailed;
        }
    }

}

export default DetectHttpsServer;
<|endoftext|>


<commit_before>define(function (require, exports, module) {
    "use strict";

    var CommandManager      = brackets.getModule("command/CommandManager"),
        MainViewManager     = brackets.getModule("view/MainViewManager"),
        Commands            = brackets.getModule("command/Commands");
    // Orientation
    var VERTICAL_ORIENTATION    = 0,
        HORIZONTAL_ORIENTATION  = 1;
    // by default we use vertical orientation
    var _orientation = VERTICAL_ORIENTATION;

    /*
     * Publicly avaialble function used to create an empty iframe within the second-panel
     */
    function init() {
        //Get current GUI layout
        var result = MainViewManager.getLayoutScheme();

        // If iframe does not exist, then show it
        if(result.rows === 1 && result.columns === 1) {
            show(_orientation);
        }
        /*
         *Creating the empty iFrame we'll be using
         * Starting by Emptying all contents of #second-pane
         */
        var _panel = $("#second-pane").empty();

        // Create the iFrame for the blob to live in later
        var iframeConfig = {
            id: "bramble-iframe-browser",
            frameborder: 0
        };
        //Append iFrame to _panel
        $("<iframe>", iframeConfig).css({"width":"100%", "height":"100%"}).appendTo(_panel);
    }

    /*
     * Publicly available function used to change the _orientation value of iframe-browser
     * orientation: Takes one argument of either VERTICAL_ORIENTATION OR
     * HORIZONTAL_ORIENTATION and uses that to change the _orientation value accordingly
     */
    function setOrientation(orientation) {
        if(orientation === VERTICAL_ORIENTATION) {
            _orientation = VERTICAL_ORIENTATION;
        }
        else if (orientation === HORIZONTAL_ORIENTATION) {
            _orientation = HORIZONTAL_ORIENTATION;
        }
    }

    /*
     * Publicly available function used to change the layout of the iFrame
     * orientation: Takes one argument of either VERTICAL_ORIENTATION OR
     * HORIZONTAL_ORIENTATION and uses that to change the layout accordingly
     */
    function show() {
        if(_orientation === VERTICAL_ORIENTATION) {
            CommandManager.execute(Commands.CMD_SPLITVIEW_VERTICAL);
        }
        else if(_orientation === HORIZONTAL_ORIENTATION) {
            CommandManager.execute(Commands.CMD_SPLITVIEW_HORIZONTAL);
        }
    }

    /**
     * Function used to interact with the second-pane
     * In which our iFrame will exists and will be filled
     * with the url that has been passed to this function
     */
    function update(url) {
        // If url has been sent, make the iFrames' src that of the url
        if(url) {
            var $iframe = $("#bramble-iframe-browser");
            if ( $iframe.length ) {
                $iframe.attr('src',url);
            }
        }
    }

    // Return reference to iframe element or null if not available.
    function getBrowserIFrame() {
        return document.getElementById("bramble-iframe-browser");
    }

    // Define public API
    exports.init = init;
    exports.update = update;
    exports.show = show;
    exports.getBrowserIFrame = getBrowserIFrame;
    // Expose these constants on our module, so callers can use them with setOrientation()
    exports.HORIZONTAL_ORIENTATION = HORIZONTAL_ORIENTATION;
    exports.VERTICAL_ORIENTATION = VERTICAL_ORIENTATION;
    exports.setOrientation = setOrientation;

});
<commit_msg>Added method to check if init has been run, changed logic of update<commit_after>define(function (require, exports, module) {
    "use strict";

    var CommandManager      = brackets.getModule("command/CommandManager"),
        MainViewManager     = brackets.getModule("view/MainViewManager"),
        Commands            = brackets.getModule("command/Commands");
    // Orientation
    var VERTICAL_ORIENTATION    = 0,
        HORIZONTAL_ORIENTATION  = 1;
    // by default we use vertical orientation
    var _orientation = VERTICAL_ORIENTATION;

    /*
     * Publicly avaialble function used to create an empty iframe within the second-panel
     */
    function init() {
        //Check to see if we've created the iframe already, return if so
        if(getBrowserIFrame()) {
            return;
        }
        //Get current GUI layout
        var result = MainViewManager.getLayoutScheme();

        // If iframe does not exist, then show it
        if(result.rows === 1 && result.columns === 1) {
            show(_orientation);
        }
        /*
         *Creating the empty iFrame we'll be using
         * Starting by Emptying all contents of #second-pane
         */
        var _panel = $("#second-pane").empty();

        // Create the iFrame for the blob to live in later
        var iframeConfig = {
            id: "bramble-iframe-browser",
            frameborder: 0
        };
        //Append iFrame to _panel
        $("<iframe>", iframeConfig).css({"width":"100%", "height":"100%"}).appendTo(_panel);
    }

    /*
     * Publicly available function used to change the _orientation value of iframe-browser
     * orientation: Takes one argument of either VERTICAL_ORIENTATION OR
     * HORIZONTAL_ORIENTATION and uses that to change the _orientation value accordingly
     */
    function setOrientation(orientation) {
        if(orientation === VERTICAL_ORIENTATION) {
            _orientation = VERTICAL_ORIENTATION;
        }
        else if (orientation === HORIZONTAL_ORIENTATION) {
            _orientation = HORIZONTAL_ORIENTATION;
        }
    }

    /*
     * Publicly available function used to change the layout of the iFrame
     * orientation: Takes one argument of either VERTICAL_ORIENTATION OR
     * HORIZONTAL_ORIENTATION and uses that to change the layout accordingly
     */
    function show() {
        if(_orientation === VERTICAL_ORIENTATION) {
            CommandManager.execute(Commands.CMD_SPLITVIEW_VERTICAL);
        }
        else if(_orientation === HORIZONTAL_ORIENTATION) {
            CommandManager.execute(Commands.CMD_SPLITVIEW_HORIZONTAL);
        }
    }

    /**
     * Function used to interact with the second-pane
     * In which our iFrame will exists and will be filled
     * with the url that has been passed to this function
     */
    function update(url) {
        // If url has been sent, make the iFrames' src that of the url
        if(url) {
            //Get the iframe
            var iframe = getBrowserIFrame();
            //Check to make sure it exists
            if(iframe) {
                //Set its src as url
                iframe.src = url;
            }
        }
    }

    // Return reference to iframe element or null if not available.
    function getBrowserIFrame() {
        return document.getElementById("bramble-iframe-browser");
    }

    // Define public API
    exports.init = init;
    exports.update = update;
    exports.show = show;
    exports.getBrowserIFrame = getBrowserIFrame;
    // Expose these constants on our module, so callers can use them with setOrientation()
    exports.HORIZONTAL_ORIENTATION = HORIZONTAL_ORIENTATION;
    exports.VERTICAL_ORIENTATION = VERTICAL_ORIENTATION;
    exports.setOrientation = setOrientation;

});
<|endoftext|>


<commit_before>import MultiChart from '../stories/MultiChart'

const React = require('react')
const { Component, PropTypes } = React
const { curry, uniq } = require('ramda')
const { isNumberArray, isBooleanArray } = require('../model/classifier')
const { numericChart } = require('../viz/numeric-chart')
const { categoricalChart } = require('../viz/categorical-chart')
const { booleanChart } = require('../viz/boolean-chart')
const table = require('../model/table')

const chartFn = (column) => {
  if (isBooleanArray(column)) return booleanChart
  if (isNumberArray(column)) return numericChart
  return categoricalChart
}

const reduce = (c, dataTable, columnNames) => {
  var charts = []
  var datas = []
  var configs = []
  for (var i = 0; i < table.width(dataTable); i++) {
    const column = c(i)
    const name = columnNames[i]
    const cf = chartFn(column)
    const config = {name, className: name, top: 20, left: 50 * i}
    if (cf === categoricalChart) {
      config['keys'] = uniq(column).sort()
    }
    charts.push(cf)
    datas.push(column)
    configs.push(config)
  }
  return { charts, datas, configs }
}

class StripesChart extends Component {
  propTypes: {
    dataTable: PropTypes.array.isRequired,
    columnNames: PropTypes.array.isRequired,
    sortColumn: PropTypes.number
  }

  render() {
    const { dataTable, columnNames, sortColumn } = this.props
    const ordered = table.byColumn(dataTable, sortColumn)
    const c = curry(table.column)(dataTable, ordered)

    const { charts, datas, configs } = reduce(c, dataTable, columnNames)
    return (
      <div className="App">
        <MultiChart
          chartFn={charts}
          data={datas}
          config={configs}
        />
      </div>
    )
  }
}

export default StripesChart
<commit_msg>inlines MultiChart functionality into StripesChart<commit_after>const React = require('react')
const { Component, PropTypes } = React
const FauxDom = require('react-faux-dom')
const d3 = require('d3')
const { curry, uniq } = require('ramda')
const { isNumberArray, isBooleanArray } = require('../model/classifier')
const { numericChart } = require('../viz/numeric-chart')
const { categoricalChart } = require('../viz/categorical-chart')
const { booleanChart } = require('../viz/boolean-chart')
const table = require('../model/table')

const chartFn = (column) => {
  if (isBooleanArray(column)) return booleanChart
  if (isNumberArray(column)) return numericChart
  return categoricalChart
}

const reduce = (c, dataTable, columnNames) => {
  var charts = []
  var datas = []
  var configs = []
  for (var i = 0; i < table.width(dataTable); i++) {
    const column = c(i)
    const name = columnNames[i]
    const cf = chartFn(column)
    const config = {name, className: name, top: 20, left: 50 * i}
    if (cf === categoricalChart) {
      config['keys'] = uniq(column).sort()
    }
    charts.push(cf)
    datas.push(column)
    configs.push(config)
  }
  return { charts, datas, configs }
}

class StripesChart extends Component {
  propTypes: {
    dataTable: PropTypes.array.isRequired,
    columnNames: PropTypes.array.isRequired,
    sortColumn: PropTypes.number
  }

  render() {
    const { dataTable, columnNames, sortColumn } = this.props
    const ordered = table.byColumn(dataTable, sortColumn)
    const c = curry(table.column)(dataTable, ordered)

    const { charts, datas, configs } = reduce(c, dataTable, columnNames)
    const node = FauxDom.createElement('svg')
    const g = d3.select(node)
    .attr('width', datas.length * 50)
    .attr('height', 3000)
    .append('g')

    for (let i = 0; i < datas.length; i++) {
      charts[i](g, datas[i], configs[i])
    }

    return node.toReact()
  }
}

export default StripesChart
<|endoftext|>


<commit_before>const { Map } = require('immutable');
const chai = require('chai');
const { expect } = require('chai');
const chaiImmutable = require('chai-immutable');

chai.use(chaiImmutable);

import userReducer, { RECEIVE_USERS } from '../redux/reducers/user-reducer';

const user = Map({
  id: 'number1',
  color: 'blue',
  x: 0,
  y: 1.6,
  z: 5,
  xrot: 0,
  yrot: 0,
  zrot: 0
});

const user2 = Map({
  id: 'number2',
  color: 'red',
  x: 1,
  y: 1.6,
  z: 5,
  xrot: 0,
  yrot: 0,
  zrot: 0
});

const updatedUser1Data = Map({
  id: 'number1',
  color: 'blue',
  x: 1,
  y: 2.6,
  z: 6,
  xrot: 1,
  yrot: 1,
  zrot: 1
});

describe('Frontend userReducer', () => {
  const initialState = Map({
    'number1': user,
    'number2': user2
  });

  const newState = Map({
    'number1': updatedUser1Data,
    'number2': user2
  });

  it('updates the state to reflect a user\'s current position/rotation', () => {
    const action = {
      type: RECEIVE_USERS,
      users: newState
    };

    const nextState = userReducer(initialState, action);

    expect(nextState).to.equal(Map({
      'number1': Map({
        id: 'number1',
        color: 'blue',
        x: 1,
        y: 2.6,
        z: 6,
        xrot: 1,
        yrot: 1,
        zrot: 1
      }),
      'number2': Map({
        id: 'number2',
        color: 'red',
        x: 1,
        y: 1.6,
        z: 5,
        xrot: 0,
        yrot: 0,
        zrot: 0
      })
    }));
  });
});

xdescribe('The view', () => {
  it('is populated with existing users upon joining', () => {

  });

  it('adds a user when a new user joins if they don\'t already exist on the DOM', () => {

  });

  it('updates the position/rotation of a user if they already exist on the DOM', () => {

  });

  it('removes a user when the user disconnects', () => {

  });
});
<commit_msg>Delete FE tests temporarily<commit_after><|endoftext|>