<commit_before>import { updaters } from "./graph";
import { updateApp } from "./update-app";
import { saveSvgAsPng } from "save-svg-as-png";

import {
    FORCE_GRAPH,
    GRID_LAYOUT,
    SET_NORMALIZATION_SIDEBAR,
    SET_NORMALIZATION_SIDEBAR_VALUE,
    SET_NORMALIZATION_MENU,
    RESET_NORMALIZATION_SIDEBAR,
    RESET_NORMALIZATION_MENU,
    GREY_EDGES_DASHED_MENU,
    GREY_EDGES_DASHED_SIDEBAR,
    GREY_EDGE_THRESHOLD_MENU,
    GREY_EDGE_THRESHOLD_SLIDER_SIDEBAR,
    WEIGHTS_SHOW_MOUSE_OVER_CLASS,
    WEIGHTS_SHOW_ALWAYS_CLASS,
    WEIGHTS_HIDE_CLASS,
    SHOW_WEIGHTS_MOUSEOVER,
    SHOW_ALL_WEIGHTS,
    HIDE_ALL_WEIGHTS,
    COLOR_EDGES,
    BLACK_EDGES,
    LINK_DIST_SLIDER_SIDEBAR,
    LINK_DIST_MENU,
    CHARGE_SLIDER_SIDEBAR,
    CHARGE_MENU,
    CHARGE_DEFAULT_VALUE,
    LINK_DIST_DEFAULT_VALUE,
    LOCK_SLIDERS_CLASS,
    RESET_SLIDERS_CLASS,
    UNDO_SLIDERS_RESET_CLASS,
    FORCE_GRAPH_BUTTON,
    GRID_LAYOUT_BUTTON,
    GRID_LAYOUT_CLASS,
    FORCE_GRAPH_CLASS,
    NODE_COLORING_TOGGLE_CLASS,
    AVG_REPLICATE_VALS_TOP_MENU,
    AVG_REPLICATE_VALS_TOP_SIDEBAR,
    AVG_REPLICATE_VALS_BOTTOM_MENU,
    AVG_REPLICATE_VALS_BOTTOM_SIDEBAR,
    LOG_FOLD_CHANGE_MAX_VALUE_SIDEBAR_BUTTON,
    LOG_FOLD_CHANGE_MAX_VALUE_MENU,
    LOG_FOLD_CHANGE_MAX_VALUE_SIDEBAR_INPUT,
    TOP_DATASET_SELECTION_SIDEBAR,
    BOTTOM_DATASET_SELECTION_SIDEBAR,
    TOP_DATASET_SELECTION_MENU,
    BOTTOM_DATASET_SELECTION_MENU,
    ZOOM_DISPLAY_MAXIMUM_SELECTOR,
    ZOOM_DISPLAY_MAXIMUM_VALUE,
    ZOOM_DISPLAY_MINIMUM_SELECTOR,
    ZOOM_DISPLAY_MINIMUM_VALUE,
    EXPORT_TO_PNG,
    EXPORT_TO_SVG
} from "./constants";

import { setupLoadAndImportHandlers } from "./setup-load-and-import-handlers";

export const setupHandlers = grnState => {
    setupLoadAndImportHandlers(grnState);

    var valueValidator = (min, max, value) => {
        return Math.min(max, Math.max(min, value));
    };

    const determineFileType = filename => {
        if (filename.includes(".xlsx")) {
            return ".xlsx";
        } else if (filename.includes(".sif")) {
            return ".sif";
        } else if (filename.includes(".graphml")) {
            return ".graphml";
        }
    };

    const exportSVG = (svgElement, name) => {
        var editedName = name.replace(determineFileType(name), "");
        var serializer = new XMLSerializer();
        var source = serializer.serializeToString(svgElement);

        if (!source.match(/^<svg[^>]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/)) {
            source = source.replace(/^<svg/, "<svg xmlns=\"http://www.w3.org/2000/svg\"");
        }
        if (!source.match(/^<svg[^>]+"http\:\/\/www\.w3\.org\/1999\/xlink"/)) {
            source = source.replace(/^<svg/, "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
        }

        source = "<?xml version=\"1.0\" standalone=\"no\"?>\r\n" + source;
        var svgUrl = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(source);

        $("#exportAsSvg").attr("href", svgUrl);
        $("#exportAsSvg").attr("download", editedName);
    };

    // Grid and Force Graph Layout
    $(FORCE_GRAPH_BUTTON).click(() => {
        updaters.setNodesToForceGraph();
        grnState.graphLayout = FORCE_GRAPH;
        updateApp(grnState);
    });

    $(FORCE_GRAPH_CLASS).click(() => {
        updaters.setNodesToForceGraph();
        grnState.graphLayout = FORCE_GRAPH;
        updateApp(grnState);
    });

    $(GRID_LAYOUT_BUTTON).click(() => {
        updaters.setNodesToGrid();
        grnState.graphLayout = GRID_LAYOUT;
        updateApp(grnState);
    });

    $(GRID_LAYOUT_CLASS).click(() =>  {
        updaters.setNodesToGrid();
        grnState.graphLayout = GRID_LAYOUT;
        updateApp(grnState);
    });

// Image Export
    $(EXPORT_TO_PNG).click(() => {
        var svgContainer = document.getElementById("exportContainer");
        var editedName = grnState.name.replace(determineFileType(name), "");
        saveSvgAsPng(svgContainer, editedName + ".png");
    });

    $(EXPORT_TO_SVG).click(() => {
        var svgContainer = document.getElementById("exportContainer");
        exportSVG(svgContainer, grnState.name + ".svg");
    });

// Node Coloring
    $(NODE_COLORING_TOGGLE_CLASS).click(() => {
        grnState.nodeColoring.nodeColoringEnabled = !grnState.nodeColoring.nodeColoringEnabled;
        updateApp(grnState);
    });

    $(TOP_DATASET_SELECTION_SIDEBAR).change(() => {
        var selection = $(TOP_DATASET_SELECTION_SIDEBAR).find(":selected").attr("value");
        grnState.nodeColoring.topDataset = selection;
        if (grnState.nodeColoring.bottomDataSameAsTop) {
            grnState.nodeColoring.bottomDataset = selection;
        }
        updateApp(grnState);
    });

    $(TOP_DATASET_SELECTION_MENU).click(() => {
        var selection = $(this).attr("value");
        grnState.nodeColoring.topDataset = selection;
        if (grnState.nodeColoring.bottomDataSameAsTop) {
            grnState.nodeColoring.bottomDataset = selection;
        }
        updateApp(grnState);
    });

    $(AVG_REPLICATE_VALS_TOP_SIDEBAR).change(() => {
        grnState.nodeColoring.averageTopDataset = !grnState.nodeColoring.averageTopDataset;
        updateApp(grnState);
    });

    $(AVG_REPLICATE_VALS_TOP_MENU).click(() => {
        grnState.nodeColoring.averageTopDataset = !grnState.nodeColoring.averageTopDataset;
        updateApp(grnState);
    });

    $(BOTTOM_DATASET_SELECTION_SIDEBAR).change(() => {
        var selection = $(BOTTOM_DATASET_SELECTION_SIDEBAR).find(":selected").attr("value");
        grnState.nodeColoring.bottomDataset = selection;
        if (grnState.nodeColoring.bottomDataset === "Same as Top Dataset") {
            grnState.nodeColoring.bottomDataset = grnState.nodeColoring.topDataset;
            grnState.nodeColoring.bottomDataSameAsTop = true;
        } else {
            grnState.nodeColoring.bottomDataSameAsTop = false;
        }
        updateApp(grnState);
    });

    $(BOTTOM_DATASET_SELECTION_MENU).click(() => {
        var selection = $(this).attr("value");
        grnState.nodeColoring.bottomDataset = selection;
        if (selection === "Same as Top Dataset") {
            grnState.nodeColoring.bottomDataset = grnState.nodeColoring.topDataset;
            grnState.nodeColoring.bottomDataSameAsTop = true;
        } else {
            grnState.nodeColoring.bottomDataSameAsTop = false;
            grnState.nodeColoring.bottomDataset = selection;
        }
        updateApp(grnState);
    });

    $(AVG_REPLICATE_VALS_BOTTOM_SIDEBAR).change(() => {
        grnState.nodeColoring.averageBottomDataset = !grnState.nodeColoring.averageBottomDataset;
        updateApp(grnState);
    });

    $(AVG_REPLICATE_VALS_BOTTOM_MENU).click(() => {
        grnState.nodeColoring.averageBottomDataset = !grnState.nodeColoring.averageBottomDataset;
        updateApp(grnState);
    });

    var logFoldChangeMaxValueValidator = value => {
        return valueValidator(0.01, 100, value);
    };

    $(LOG_FOLD_CHANGE_MAX_VALUE_SIDEBAR_BUTTON).click(() => {
        var value = logFoldChangeMaxValueValidator($(LOG_FOLD_CHANGE_MAX_VALUE_SIDEBAR_INPUT).val());
        grnState.nodeColoring.logFoldChangeMaxValue = value;
        updateApp(grnState);
    });

    $(LOG_FOLD_CHANGE_MAX_VALUE_MENU).change(() => {
        var value = logFoldChangeMaxValueValidator($(LOG_FOLD_CHANGE_MAX_VALUE_MENU).val());
        grnState.nodeColoring.logFoldChangeMaxValue = value;
        updateApp(grnState);
    });

// Sliders Code
    var linkDistValidator = value => {
        return valueValidator(1, 1000, value);
    };

    var chargeValidator = value => {
        return valueValidator(-2000, 0, value);
    };

    $(LINK_DIST_SLIDER_SIDEBAR).change(() => {
        var value = linkDistValidator($(LINK_DIST_SLIDER_SIDEBAR).val());
        grnState.linkDistanceSlider.currentVal = value;
        updateApp(grnState);
    });

    $(LINK_DIST_MENU).change(() => {
        var value = linkDistValidator($(LINK_DIST_MENU).val());
        grnState.linkDistanceSlider.currentVal = value;
        updateApp(grnState);
    });

    $(CHARGE_SLIDER_SIDEBAR).change(() => {
        var value = chargeValidator($(CHARGE_SLIDER_SIDEBAR).val());
        grnState.chargeSlider.currentVal = value;
        updateApp(grnState);
    });

    $(CHARGE_MENU).change(() => {
        var value = chargeValidator($(CHARGE_MENU).val());
        grnState.chargeSlider.currentVal = value;
        updateApp(grnState);
    });

    $(LOCK_SLIDERS_CLASS).click(() => {
        grnState.slidersLocked = !grnState.slidersLocked;
        updateApp(grnState);
    });

    $(RESET_SLIDERS_CLASS).click(() => {
        grnState.chargeSlider.backup = grnState.chargeSlider.currentVal;
        grnState.linkDistanceSlider.backup = grnState.linkDistanceSlider.currentVal;
        grnState.chargeSlider.currentVal = CHARGE_DEFAULT_VALUE;
        grnState.linkDistanceSlider.currentVal = LINK_DIST_DEFAULT_VALUE;
        grnState.showUndoReset = true;
        updateApp(grnState);
    });

    $(UNDO_SLIDERS_RESET_CLASS).click(() => {
        grnState.chargeSlider.currentVal = grnState.chargeSlider.backup;
        grnState.linkDistanceSlider.currentVal = grnState.linkDistanceSlider.backup;
        grnState.showUndoReset = false;
        updateApp(grnState);
    });

// Weights Visualization
    $(WEIGHTS_SHOW_ALWAYS_CLASS).click(() => {
        grnState.edgeWeightDisplayOption = SHOW_ALL_WEIGHTS;
        updateApp(grnState);
    });

    $(WEIGHTS_HIDE_CLASS).click(() => {
        grnState.edgeWeightDisplayOption = HIDE_ALL_WEIGHTS;
        updateApp(grnState);
    });

    // Normalization Options
    $(SET_NORMALIZATION_SIDEBAR).click(() => {
        grnState.normalizationMax = $(SET_NORMALIZATION_SIDEBAR_VALUE).val();
        updateApp(grnState);
    });

    $(SET_NORMALIZATION_MENU).change(() => {
        grnState.normalizationMax = $(SET_NORMALIZATION_MENU).val();
        updateApp(grnState);
    });

    $(RESET_NORMALIZATION_SIDEBAR).click(() => {
        grnState.normalizationMax = grnState.resetNormalizationMax;
        updateApp(grnState);
    });

    $(RESET_NORMALIZATION_MENU).click(() => {
        grnState.normalizationMax = grnState.resetNormalizationMax;
        updateApp(grnState);
    });

// Grey Edges
    $(GREY_EDGES_DASHED_SIDEBAR).change(() => {
        grnState.dashedLine = $(GREY_EDGES_DASHED_SIDEBAR).prop("checked");
        updateApp(grnState);
    });

    $(GREY_EDGES_DASHED_MENU).click(() => {
        grnState.dashedLine = !$(GREY_EDGES_DASHED_MENU).prop("checked");
        updateApp(grnState);
    });

    $(GREY_EDGE_THRESHOLD_MENU).change(() => {
        grnState.grayEdgeThreshold = Math.round($(GREY_EDGE_THRESHOLD_MENU).val());
        updateApp(grnState);
    });

    $(GREY_EDGE_THRESHOLD_SLIDER_SIDEBAR).change(() => {
        grnState.grayEdgeThreshold = Math.round($(GREY_EDGE_THRESHOLD_SLIDER_SIDEBAR).val() * 100);
        updateApp(grnState);
    });

    $(WEIGHTS_SHOW_MOUSE_OVER_CLASS).click(() => {
        grnState.edgeWeightDisplayOption = SHOW_WEIGHTS_MOUSEOVER;
        updateApp(grnState);
    });

    $(COLOR_EDGES).click(() => {
        grnState.colorOptimal = true;
        updateApp(grnState);
    });

    $(BLACK_EDGES).click(() => {
        grnState.colorOptimal = false;
        updateApp(grnState);
    });

    // Allow text-selection for input elements embedded within menu items.
    //
    // Partial thank you:
    //   https://stackoverflow.com/questions/6848140/how-do-i-prevent-drag-on-a-child-but-allow-drag-on-the-parent
    //
    // We use function syntax so that internal `this` can be used.
    $(".dropdown input.keepopen").parent().attr({
        draggable: false
    });

    // Prevent Bootstrap dropdown from closing on clicks in menu input boxes
    // https://stackoverflow.com/a/27759926
    $(".dropdown").on({
        "click": function (event) {
            if ($(event.target).hasClass("keepopen")) {
                $(this).data("closable", $(event.target).closest(".dropdown-toggle").length !== 0);
            }
        },

        "mouseup": function (event) {
            if ($(event.target).find(".keepopen").length > 0) {
                $(this).data("closable", $(event.target).closest(".dropdown-toggle").length !== 0);
            }
        },

        "hide.bs.dropdown": function () {
            var hide = $(this).data("closable");
            $(this).data("closable", true);
            return hide;
        }
    });

    $(ZOOM_DISPLAY_MAXIMUM_SELECTOR).text(ZOOM_DISPLAY_MAXIMUM_VALUE);
    $(ZOOM_DISPLAY_MINIMUM_SELECTOR).text(ZOOM_DISPLAY_MINIMUM_VALUE);
};
<commit_msg>make changes for PR #802<commit_after>import { updaters } from "./graph";
import { updateApp } from "./update-app";
import { saveSvgAsPng } from "save-svg-as-png";

import {
    FORCE_GRAPH,
    GRID_LAYOUT,
    SET_NORMALIZATION_SIDEBAR,
    SET_NORMALIZATION_SIDEBAR_VALUE,
    SET_NORMALIZATION_MENU,
    RESET_NORMALIZATION_SIDEBAR,
    RESET_NORMALIZATION_MENU,
    GREY_EDGES_DASHED_MENU,
    GREY_EDGES_DASHED_SIDEBAR,
    GREY_EDGE_THRESHOLD_MENU,
    GREY_EDGE_THRESHOLD_SLIDER_SIDEBAR,
    WEIGHTS_SHOW_MOUSE_OVER_CLASS,
    WEIGHTS_SHOW_ALWAYS_CLASS,
    WEIGHTS_HIDE_CLASS,
    SHOW_WEIGHTS_MOUSEOVER,
    SHOW_ALL_WEIGHTS,
    HIDE_ALL_WEIGHTS,
    COLOR_EDGES,
    BLACK_EDGES,
    LINK_DIST_SLIDER_SIDEBAR,
    LINK_DIST_MENU,
    CHARGE_SLIDER_SIDEBAR,
    CHARGE_MENU,
    CHARGE_DEFAULT_VALUE,
    LINK_DIST_DEFAULT_VALUE,
    LOCK_SLIDERS_CLASS,
    RESET_SLIDERS_CLASS,
    UNDO_SLIDERS_RESET_CLASS,
    GRID_LAYOUT_BUTTON,
    GRID_LAYOUT_CLASS,
    NODE_COLORING_TOGGLE_CLASS,
    AVG_REPLICATE_VALS_TOP_MENU,
    AVG_REPLICATE_VALS_TOP_SIDEBAR,
    AVG_REPLICATE_VALS_BOTTOM_MENU,
    AVG_REPLICATE_VALS_BOTTOM_SIDEBAR,
    LOG_FOLD_CHANGE_MAX_VALUE_SIDEBAR_BUTTON,
    LOG_FOLD_CHANGE_MAX_VALUE_MENU,
    LOG_FOLD_CHANGE_MAX_VALUE_SIDEBAR_INPUT,
    TOP_DATASET_SELECTION_SIDEBAR,
    BOTTOM_DATASET_SELECTION_SIDEBAR,
    TOP_DATASET_SELECTION_MENU,
    BOTTOM_DATASET_SELECTION_MENU,
    ZOOM_DISPLAY_MAXIMUM_SELECTOR,
    ZOOM_DISPLAY_MAXIMUM_VALUE,
    ZOOM_DISPLAY_MINIMUM_SELECTOR,
    ZOOM_DISPLAY_MINIMUM_VALUE,
    EXPORT_TO_PNG,
    EXPORT_TO_SVG
} from "./constants";

import { setupLoadAndImportHandlers } from "./setup-load-and-import-handlers";

export const setupHandlers = grnState => {
    setupLoadAndImportHandlers(grnState);

    var valueValidator = (min, max, value) => {
        return Math.min(max, Math.max(min, value));
    };

    const determineFileType = filename => {
        if (filename.includes(".xlsx")) {
            return ".xlsx";
        } else if (filename.includes(".sif")) {
            return ".sif";
        } else if (filename.includes(".graphml")) {
            return ".graphml";
        }
    };

    const exportSVG = (svgElement, name) => {
        var editedName = name.replace(determineFileType(name), "");
        var serializer = new XMLSerializer();
        var source = serializer.serializeToString(svgElement);

        if (!source.match(/^<svg[^>]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/)) {
            source = source.replace(/^<svg/, "<svg xmlns=\"http://www.w3.org/2000/svg\"");
        }
        if (!source.match(/^<svg[^>]+"http\:\/\/www\.w3\.org\/1999\/xlink"/)) {
            source = source.replace(/^<svg/, "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
        }

        source = "<?xml version=\"1.0\" standalone=\"no\"?>\r\n" + source;
        var svgUrl = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(source);

        $("#exportAsSvg").attr("href", svgUrl);
        $("#exportAsSvg").attr("download", editedName);
    };

    // Grid and Force Graph Layout
    $("#forceGraph, #forceGraphButton").click(() => {
        updaters.setNodesToForceGraph();
        grnState.graphLayout = FORCE_GRAPH;
        updateApp(grnState);
    });

    $(GRID_LAYOUT_BUTTON).click(() => {
        updaters.setNodesToGrid();
        grnState.graphLayout = GRID_LAYOUT;
        updateApp(grnState);
    });

    $(GRID_LAYOUT_CLASS).click(() =>  {
        updaters.setNodesToGrid();
        grnState.graphLayout = GRID_LAYOUT;
        updateApp(grnState);
    });

// Image Export
    $(EXPORT_TO_PNG).click(() => {
        var svgContainer = document.getElementById("exportContainer");
        var editedName = grnState.name.replace(determineFileType(name), "");
        saveSvgAsPng(svgContainer, editedName + ".png");
    });

    $(EXPORT_TO_SVG).click(() => {
        var svgContainer = document.getElementById("exportContainer");
        exportSVG(svgContainer, grnState.name + ".svg");
    });

// Node Coloring
    $(NODE_COLORING_TOGGLE_CLASS).click(() => {
        grnState.nodeColoring.nodeColoringEnabled = !grnState.nodeColoring.nodeColoringEnabled;
        updateApp(grnState);
    });

    $(TOP_DATASET_SELECTION_SIDEBAR).change(() => {
        var selection = $(TOP_DATASET_SELECTION_SIDEBAR).find(":selected").attr("value");
        grnState.nodeColoring.topDataset = selection;
        if (grnState.nodeColoring.bottomDataSameAsTop) {
            grnState.nodeColoring.bottomDataset = selection;
        }
        updateApp(grnState);
    });

    $(TOP_DATASET_SELECTION_MENU).click(() => {
        var selection = $(this).attr("value");
        grnState.nodeColoring.topDataset = selection;
        if (grnState.nodeColoring.bottomDataSameAsTop) {
            grnState.nodeColoring.bottomDataset = selection;
        }
        updateApp(grnState);
    });

    $(AVG_REPLICATE_VALS_TOP_SIDEBAR).change(() => {
        grnState.nodeColoring.averageTopDataset = !grnState.nodeColoring.averageTopDataset;
        updateApp(grnState);
    });

    $(AVG_REPLICATE_VALS_TOP_MENU).click(() => {
        grnState.nodeColoring.averageTopDataset = !grnState.nodeColoring.averageTopDataset;
        updateApp(grnState);
    });

    $(BOTTOM_DATASET_SELECTION_SIDEBAR).change(() => {
        var selection = $(BOTTOM_DATASET_SELECTION_SIDEBAR).find(":selected").attr("value");
        grnState.nodeColoring.bottomDataset = selection;
        if (grnState.nodeColoring.bottomDataset === "Same as Top Dataset") {
            grnState.nodeColoring.bottomDataset = grnState.nodeColoring.topDataset;
            grnState.nodeColoring.bottomDataSameAsTop = true;
        } else {
            grnState.nodeColoring.bottomDataSameAsTop = false;
        }
        updateApp(grnState);
    });

    $(BOTTOM_DATASET_SELECTION_MENU).click(() => {
        var selection = $(this).attr("value");
        grnState.nodeColoring.bottomDataset = selection;
        if (selection === "Same as Top Dataset") {
            grnState.nodeColoring.bottomDataset = grnState.nodeColoring.topDataset;
            grnState.nodeColoring.bottomDataSameAsTop = true;
        } else {
            grnState.nodeColoring.bottomDataSameAsTop = false;
            grnState.nodeColoring.bottomDataset = selection;
        }
        updateApp(grnState);
    });

    $(AVG_REPLICATE_VALS_BOTTOM_SIDEBAR).change(() => {
        grnState.nodeColoring.averageBottomDataset = !grnState.nodeColoring.averageBottomDataset;
        updateApp(grnState);
    });

    $(AVG_REPLICATE_VALS_BOTTOM_MENU).click(() => {
        grnState.nodeColoring.averageBottomDataset = !grnState.nodeColoring.averageBottomDataset;
        updateApp(grnState);
    });

    var logFoldChangeMaxValueValidator = value => {
        return valueValidator(0.01, 100, value);
    };

    $(LOG_FOLD_CHANGE_MAX_VALUE_SIDEBAR_BUTTON).click(() => {
        var value = logFoldChangeMaxValueValidator($(LOG_FOLD_CHANGE_MAX_VALUE_SIDEBAR_INPUT).val());
        grnState.nodeColoring.logFoldChangeMaxValue = value;
        updateApp(grnState);
    });

    $(LOG_FOLD_CHANGE_MAX_VALUE_MENU).change(() => {
        var value = logFoldChangeMaxValueValidator($(LOG_FOLD_CHANGE_MAX_VALUE_MENU).val());
        grnState.nodeColoring.logFoldChangeMaxValue = value;
        updateApp(grnState);
    });

// Sliders Code
    var linkDistValidator = value => {
        return valueValidator(1, 1000, value);
    };

    var chargeValidator = value => {
        return valueValidator(-2000, 0, value);
    };

    $(LINK_DIST_SLIDER_SIDEBAR).change(() => {
        var value = linkDistValidator($(LINK_DIST_SLIDER_SIDEBAR).val());
        grnState.linkDistanceSlider.currentVal = value;
        updateApp(grnState);
    });

    $(LINK_DIST_MENU).change(() => {
        var value = linkDistValidator($(LINK_DIST_MENU).val());
        grnState.linkDistanceSlider.currentVal = value;
        updateApp(grnState);
    });

    $(CHARGE_SLIDER_SIDEBAR).change(() => {
        var value = chargeValidator($(CHARGE_SLIDER_SIDEBAR).val());
        grnState.chargeSlider.currentVal = value;
        updateApp(grnState);
    });

    $(CHARGE_MENU).change(() => {
        var value = chargeValidator($(CHARGE_MENU).val());
        grnState.chargeSlider.currentVal = value;
        updateApp(grnState);
    });

    $(LOCK_SLIDERS_CLASS).click(() => {
        grnState.slidersLocked = !grnState.slidersLocked;
        updateApp(grnState);
    });

    $(RESET_SLIDERS_CLASS).click(() => {
        grnState.chargeSlider.backup = grnState.chargeSlider.currentVal;
        grnState.linkDistanceSlider.backup = grnState.linkDistanceSlider.currentVal;
        grnState.chargeSlider.currentVal = CHARGE_DEFAULT_VALUE;
        grnState.linkDistanceSlider.currentVal = LINK_DIST_DEFAULT_VALUE;
        grnState.showUndoReset = true;
        updateApp(grnState);
    });

    $(UNDO_SLIDERS_RESET_CLASS).click(() => {
        grnState.chargeSlider.currentVal = grnState.chargeSlider.backup;
        grnState.linkDistanceSlider.currentVal = grnState.linkDistanceSlider.backup;
        grnState.showUndoReset = false;
        updateApp(grnState);
    });

// Weights Visualization
    $(WEIGHTS_SHOW_ALWAYS_CLASS).click(() => {
        grnState.edgeWeightDisplayOption = SHOW_ALL_WEIGHTS;
        updateApp(grnState);
    });

    $(WEIGHTS_HIDE_CLASS).click(() => {
        grnState.edgeWeightDisplayOption = HIDE_ALL_WEIGHTS;
        updateApp(grnState);
    });

    // Normalization Options
    $(SET_NORMALIZATION_SIDEBAR).click(() => {
        grnState.normalizationMax = $(SET_NORMALIZATION_SIDEBAR_VALUE).val();
        updateApp(grnState);
    });

    $(SET_NORMALIZATION_MENU).change(() => {
        grnState.normalizationMax = $(SET_NORMALIZATION_MENU).val();
        updateApp(grnState);
    });

    $(RESET_NORMALIZATION_SIDEBAR).click(() => {
        grnState.normalizationMax = grnState.resetNormalizationMax;
        updateApp(grnState);
    });

    $(RESET_NORMALIZATION_MENU).click(() => {
        grnState.normalizationMax = grnState.resetNormalizationMax;
        updateApp(grnState);
    });

// Grey Edges
    $(GREY_EDGES_DASHED_SIDEBAR).change(() => {
        grnState.dashedLine = $(GREY_EDGES_DASHED_SIDEBAR).prop("checked");
        updateApp(grnState);
    });

    $(GREY_EDGES_DASHED_MENU).click(() => {
        grnState.dashedLine = !$(GREY_EDGES_DASHED_MENU).prop("checked");
        updateApp(grnState);
    });

    $(GREY_EDGE_THRESHOLD_MENU).change(() => {
        grnState.grayEdgeThreshold = Math.round($(GREY_EDGE_THRESHOLD_MENU).val());
        updateApp(grnState);
    });

    $(GREY_EDGE_THRESHOLD_SLIDER_SIDEBAR).change(() => {
        grnState.grayEdgeThreshold = Math.round($(GREY_EDGE_THRESHOLD_SLIDER_SIDEBAR).val() * 100);
        updateApp(grnState);
    });

    $(WEIGHTS_SHOW_MOUSE_OVER_CLASS).click(() => {
        grnState.edgeWeightDisplayOption = SHOW_WEIGHTS_MOUSEOVER;
        updateApp(grnState);
    });

    $(COLOR_EDGES).click(() => {
        grnState.colorOptimal = true;
        updateApp(grnState);
    });

    $(BLACK_EDGES).click(() => {
        grnState.colorOptimal = false;
        updateApp(grnState);
    });

    // Allow text-selection for input elements embedded within menu items.
    //
    // Partial thank you:
    //   https://stackoverflow.com/questions/6848140/how-do-i-prevent-drag-on-a-child-but-allow-drag-on-the-parent
    //
    // We use function syntax so that internal `this` can be used.
    $(".dropdown input.keepopen").parent().attr({
        draggable: false
    });

    // Prevent Bootstrap dropdown from closing on clicks in menu input boxes
    // https://stackoverflow.com/a/27759926
    $(".dropdown").on({
        "click": function (event) {
            if ($(event.target).hasClass("keepopen")) {
                $(this).data("closable", $(event.target).closest(".dropdown-toggle").length !== 0);
            }
        },

        "mouseup": function (event) {
            if ($(event.target).find(".keepopen").length > 0) {
                $(this).data("closable", $(event.target).closest(".dropdown-toggle").length !== 0);
            }
        },

        "hide.bs.dropdown": function () {
            var hide = $(this).data("closable");
            $(this).data("closable", true);
            return hide;
        }
    });

    $(ZOOM_DISPLAY_MAXIMUM_SELECTOR).text(ZOOM_DISPLAY_MAXIMUM_VALUE);
    $(ZOOM_DISPLAY_MINIMUM_SELECTOR).text(ZOOM_DISPLAY_MINIMUM_VALUE);
};
<|endoftext|>


<commit_before>/* @flow */
/* eslint-disable no-console */

// This grants us source map support, which combined with our webpack source
// maps will give us nice stack traces.
import 'source-map-support/register';

import path from 'path';
import uuid from 'node-uuid';
import appRoot from 'app-root-path';
import express from 'express';
import type { $Request, $Response, NextFunction } from 'express';
import compression from 'compression';
import hpp from 'hpp';
import helmet from 'helmet';
import universalMiddleware from './middleware/universalMiddleware';
import { notEmpty } from '../shared/universal/utils/guards';
import fs from 'fs';
import https from 'https';

const appRootPath = appRoot.toString();

// Create our express based server.
const app = express();

// Attach a unique "nonce" to every response.  This allows use to declare
// inline scripts as being safe for execution against our content security policy.
// @see https://helmetjs.github.io/docs/csp/
app.use((req: $Request, res: $Response, next: NextFunction) => {
  res.locals.nonce = uuid.v4(); // eslint-disable-line no-param-reassign
  next();
});

// Don't expose any software information to potential hackers.
app.disable('x-powered-by');

// Prevent HTTP Parameter pollution.
// @see http://bit.ly/2f8q7Td
app.use(hpp());

// Content Security Policy (CSP)
//
// If you are unfamiliar with CSPs then I highly recommend that you do some
// reading on the subject:
//  - https://content-security-policy.com/
//  - https://developers.google.com/web/fundamentals/security/csp/
//  - https://developer.mozilla.org/en/docs/Web/Security/CSP
//  - https://helmetjs.github.io/docs/csp/
//
// If you are relying on scripts/styles/assets from other servers (internal or
// external to your company) then you will need to explicitly configure the
// CSP below to allow for this.  For example you can see I have had to add
// the polyfill.io CDN in order to allow us to use the polyfill script.
// It can be a pain to manage these, but it's a really great habit to get in
// to.
//
// You may find CSPs annoying at first, but it is a great habit to build.
// The CSP configuration is an optional item for helmet, however you should
// not remove it without making a serious consideration that you do not require
// the added security.
const cspConfig = {
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: [
      // Allow scripts hosted from our application.
      "'self'",
      // Allow scripts from cdn.polyfill.io so that we can import the polyfill.
      'cdn.polyfill.io',
      'maps.googleapis.com',
      // Note: We will execution of any inline scripts that have the following
      // nonce identifier attached to them.
      // This is useful for guarding your application whilst allowing an inline
      // script to do data store rehydration (redux/mobx/apollo) for example.
      // @see https://helmetjs.github.io/docs/csp/
      // $FlowFixMe
      (req, res) => `'nonce-${res.locals.nonce}'`,
    ],
    styleSrc: ["'self'", "'unsafe-inline'", 'blob:', 'fonts.googleapis.com'],
    imgSrc: ["'self'", 'data:', 'csi.gstatic.com', 'maps.gstatic.com', 'maps.googleapis.com'],
    // Note: Setting this to stricter than * breaks the service worker. :(
    // I can't figure out how to get around this, so if you know of a safer
    // implementation that is kinder to service workers please let me know.
    connectSrc: ['*'], // ["'self'", 'ws:'],
    fontSrc: ["'self'", 'fonts.gstatic.com'],
    objectSrc: ["'none'"],
    mediaSrc: ["'none'"],
    childSrc: ["'self'"],
  },
};
if (process.env.NODE_ENV === 'development') {
  // When in development mode we need to add our secondary express server that
  // is used to host our client bundle to our csp config.
  Object.keys(cspConfig.directives).forEach(directive =>
    cspConfig.directives[directive].push(
      `localhost:${notEmpty(process.env.CLIENT_DEVSERVER_PORT)}`
    )
  );
}
app.use(helmet.contentSecurityPolicy(cspConfig));

// The xssFilter middleware sets the X-XSS-Protection header to prevent
// reflected XSS attacks.
// @see https://helmetjs.github.io/docs/xss-filter/
app.use(helmet.xssFilter());

// Frameguard mitigates clickjacking attacks by setting the X-Frame-Options header.
// @see https://helmetjs.github.io/docs/frameguard/
app.use(helmet.frameguard('deny'));

// Sets the X-Download-Options to prevent Internet Explorer from executing
// downloads in your site’s context.
// @see https://helmetjs.github.io/docs/ienoopen/
app.use(helmet.ieNoOpen());

// Don’t Sniff Mimetype middleware, noSniff, helps prevent browsers from trying
// to guess (“sniff”) the MIME type, which can have security implications. It
// does this by setting the X-Content-Type-Options header to nosniff.
// @see https://helmetjs.github.io/docs/dont-sniff-mimetype/
app.use(helmet.noSniff());

// Gzip compress the responses.
app.use(compression());

// Configure static serving of our webpack bundled client files.
app.use(
  notEmpty(process.env.CLIENT_BUNDLE_HTTP_PATH),
  express.static(
    path.resolve(appRootPath, notEmpty(process.env.BUNDLE_OUTPUT_PATH), './client'),
    { maxAge: notEmpty(process.env.CLIENT_BUNDLE_CACHE_MAXAGE) }
  )
);

// Configure static serving of our "public" root http path static files.
app.use(express.static(path.resolve(appRootPath, './public')));

// When in production mode, bind our service worker folder so that it can
// be served.
// Note: the service worker needs to be available at the http root of your
// application for the offline support to work.
if (process.env.NODE_ENV === 'production') {
  app.use(
    express.static(
      path.resolve(appRootPath, notEmpty(process.env.BUNDLE_OUTPUT_PATH), './serviceWorker')
    )
  );
}

// The universal middleware for our React application.
app.get('*', universalMiddleware);

// Handle 404 errors.
// Note: the react application middleware hands 404 paths, but it is good to
// have this backup for paths not handled by the universal middleware. For
// example you may bind a /api path to express.
app.use((req: $Request, res: $Response, next: NextFunction) => { // eslint-disable-line no-unused-vars,max-len
  res.status(404).send('Sorry, that resource was not found.');
});

// Handle all other errors (i.e. 500).
// Note: You must provide specify all 4 parameters on this callback function
// even if they aren't used, otherwise it won't be used.
app.use((err: ?Error, req: $Request, res: $Response, next: NextFunction) => { // eslint-disable-line no-unused-vars,max-len
  if (err) {
    console.log(err);
    console.log(err.stack);
  }
  res.status(500).send('Sorry, an unexpected error occurred.');
});

// Create an http listener for our express app.
const port = parseInt(notEmpty(process.env.SERVER_PORT), 10);
const listener = app.listen(port, () =>
  console.log(`Server listening on port ${port}`)
);

// HTTPS
if (process.env.HTTPS_SSL_KEY_FILE) {
  const options = {
    key: fs.readFileSync(process.env.HTTPS_SSL_KEY_FILE),
    cert: fs.readFileSync(process.env.HTTPS_SSL_CERT_FILE),
  };
  const port = parseInt(notEmpty(process.env.SERVER_SSL_PORT), 10);
  const server = https.createServer(options, app).listen(port, () => {
    console.log("HTTPS server listening on port " + port);
  });
}

// We export the listener as it will be handy for our development hot reloader.
export default listener;
<commit_msg>Wrap HTTPS listen attempt in try-catch<commit_after>/* @flow */
/* eslint-disable no-console */

// This grants us source map support, which combined with our webpack source
// maps will give us nice stack traces.
import 'source-map-support/register';

import path from 'path';
import uuid from 'node-uuid';
import appRoot from 'app-root-path';
import express from 'express';
import type { $Request, $Response, NextFunction } from 'express';
import compression from 'compression';
import hpp from 'hpp';
import helmet from 'helmet';
import universalMiddleware from './middleware/universalMiddleware';
import { notEmpty } from '../shared/universal/utils/guards';
import fs from 'fs';
import https from 'https';

const appRootPath = appRoot.toString();

// Create our express based server.
const app = express();

// Attach a unique "nonce" to every response.  This allows use to declare
// inline scripts as being safe for execution against our content security policy.
// @see https://helmetjs.github.io/docs/csp/
app.use((req: $Request, res: $Response, next: NextFunction) => {
  res.locals.nonce = uuid.v4(); // eslint-disable-line no-param-reassign
  next();
});

// Don't expose any software information to potential hackers.
app.disable('x-powered-by');

// Prevent HTTP Parameter pollution.
// @see http://bit.ly/2f8q7Td
app.use(hpp());

// Content Security Policy (CSP)
//
// If you are unfamiliar with CSPs then I highly recommend that you do some
// reading on the subject:
//  - https://content-security-policy.com/
//  - https://developers.google.com/web/fundamentals/security/csp/
//  - https://developer.mozilla.org/en/docs/Web/Security/CSP
//  - https://helmetjs.github.io/docs/csp/
//
// If you are relying on scripts/styles/assets from other servers (internal or
// external to your company) then you will need to explicitly configure the
// CSP below to allow for this.  For example you can see I have had to add
// the polyfill.io CDN in order to allow us to use the polyfill script.
// It can be a pain to manage these, but it's a really great habit to get in
// to.
//
// You may find CSPs annoying at first, but it is a great habit to build.
// The CSP configuration is an optional item for helmet, however you should
// not remove it without making a serious consideration that you do not require
// the added security.
const cspConfig = {
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: [
      // Allow scripts hosted from our application.
      "'self'",
      // Allow scripts from cdn.polyfill.io so that we can import the polyfill.
      'cdn.polyfill.io',
      'maps.googleapis.com',
      // Note: We will execution of any inline scripts that have the following
      // nonce identifier attached to them.
      // This is useful for guarding your application whilst allowing an inline
      // script to do data store rehydration (redux/mobx/apollo) for example.
      // @see https://helmetjs.github.io/docs/csp/
      // $FlowFixMe
      (req, res) => `'nonce-${res.locals.nonce}'`,
    ],
    styleSrc: ["'self'", "'unsafe-inline'", 'blob:', 'fonts.googleapis.com'],
    imgSrc: ["'self'", 'data:', 'csi.gstatic.com', 'maps.gstatic.com', 'maps.googleapis.com'],
    // Note: Setting this to stricter than * breaks the service worker. :(
    // I can't figure out how to get around this, so if you know of a safer
    // implementation that is kinder to service workers please let me know.
    connectSrc: ['*'], // ["'self'", 'ws:'],
    fontSrc: ["'self'", 'fonts.gstatic.com'],
    objectSrc: ["'none'"],
    mediaSrc: ["'none'"],
    childSrc: ["'self'"],
  },
};
if (process.env.NODE_ENV === 'development') {
  // When in development mode we need to add our secondary express server that
  // is used to host our client bundle to our csp config.
  Object.keys(cspConfig.directives).forEach(directive =>
    cspConfig.directives[directive].push(
      `localhost:${notEmpty(process.env.CLIENT_DEVSERVER_PORT)}`
    )
  );
}
app.use(helmet.contentSecurityPolicy(cspConfig));

// The xssFilter middleware sets the X-XSS-Protection header to prevent
// reflected XSS attacks.
// @see https://helmetjs.github.io/docs/xss-filter/
app.use(helmet.xssFilter());

// Frameguard mitigates clickjacking attacks by setting the X-Frame-Options header.
// @see https://helmetjs.github.io/docs/frameguard/
app.use(helmet.frameguard('deny'));

// Sets the X-Download-Options to prevent Internet Explorer from executing
// downloads in your site’s context.
// @see https://helmetjs.github.io/docs/ienoopen/
app.use(helmet.ieNoOpen());

// Don’t Sniff Mimetype middleware, noSniff, helps prevent browsers from trying
// to guess (“sniff”) the MIME type, which can have security implications. It
// does this by setting the X-Content-Type-Options header to nosniff.
// @see https://helmetjs.github.io/docs/dont-sniff-mimetype/
app.use(helmet.noSniff());

// Gzip compress the responses.
app.use(compression());

// Configure static serving of our webpack bundled client files.
app.use(
  notEmpty(process.env.CLIENT_BUNDLE_HTTP_PATH),
  express.static(
    path.resolve(appRootPath, notEmpty(process.env.BUNDLE_OUTPUT_PATH), './client'),
    { maxAge: notEmpty(process.env.CLIENT_BUNDLE_CACHE_MAXAGE) }
  )
);

// Configure static serving of our "public" root http path static files.
app.use(express.static(path.resolve(appRootPath, './public')));

// When in production mode, bind our service worker folder so that it can
// be served.
// Note: the service worker needs to be available at the http root of your
// application for the offline support to work.
if (process.env.NODE_ENV === 'production') {
  app.use(
    express.static(
      path.resolve(appRootPath, notEmpty(process.env.BUNDLE_OUTPUT_PATH), './serviceWorker')
    )
  );
}

// The universal middleware for our React application.
app.get('*', universalMiddleware);

// Handle 404 errors.
// Note: the react application middleware hands 404 paths, but it is good to
// have this backup for paths not handled by the universal middleware. For
// example you may bind a /api path to express.
app.use((req: $Request, res: $Response, next: NextFunction) => { // eslint-disable-line no-unused-vars,max-len
  res.status(404).send('Sorry, that resource was not found.');
});

// Handle all other errors (i.e. 500).
// Note: You must provide specify all 4 parameters on this callback function
// even if they aren't used, otherwise it won't be used.
app.use((err: ?Error, req: $Request, res: $Response, next: NextFunction) => { // eslint-disable-line no-unused-vars,max-len
  if (err) {
    console.log(err);
    console.log(err.stack);
  }
  res.status(500).send('Sorry, an unexpected error occurred.');
});

// Create an http listener for our express app.
const port = parseInt(notEmpty(process.env.SERVER_PORT), 10);
const listener = app.listen(port, () =>
  console.log(`Server listening on port ${port}`)
);

// HTTPS
if (process.env.HTTPS_SSL_KEY_FILE) {
  try {
    const options = {
      key: fs.readFileSync(process.env.HTTPS_SSL_KEY_FILE),
      cert: fs.readFileSync(process.env.HTTPS_SSL_CERT_FILE),
    };
    const httpsPort = parseInt(notEmpty(process.env.SERVER_SSL_PORT), 10);
    https.createServer(options, app).listen(httpsPort, () => {
      console.log(`HTTPS server listening on port ${httpsPort}`);
    });
  } catch (e) {
    console.error(`Couldn't start HTTPS server: ${e}`);
  }
}

// We export the listener as it will be handy for our development hot reloader.
export default listener;
<|endoftext|>


<commit_before>import { some } from 'lodash'
const LRU = require('lru-cache')
const mime = require('mime')
const request = require('request')
const streamifier = require('streamifier')
const url = require('url')
const cache = LRU(50)

const staticPages = [
  '/',
  '/help',
  '/help/markdown',
  '/about',
  '/about/careers',
  '/about/contact',
  '/about/team',
  '/subscribe',
  '/styleguide',
  '/terms',
  '/terms/privacy'
]

const transformPathname = pathname => {
  // remove trailing slash
  pathname = pathname.replace(/\/$/, '')

  // a path without an extension should be served by index.html in
  // the folder of the same name.
  if (!pathname.match(/\.\w{2,4}$/)) {
    if (pathname.startsWith('/admin')) {
      // serve the admin Angular app
      pathname = '/admin'
    } else if (!some(staticPages, x => x === pathname)) {
      // for any paths not explicitly listed, serve the Angular app.
      pathname = '/app'
    }

    pathname += '/index.html'
  }

  // add the deploy-specific (cache-busting) path prefix
  if (!pathname.startsWith('/assets')) {
    pathname = `/assets/${process.env.BUNDLE_VERSION}${pathname}`
  }

  return pathname
}

const handlePage = page => (req, res) => {
  if (process.env.DISABLE_PROXY) {
    return res.status(503).send('Service Unavailable')
  }

  var u = url.parse(req.url)
  u.pathname = transformPathname(u.pathname)
  var newUrl = process.env.ASSET_HOST.replace(/\/$/, '') + url.format(u)

  // use path without query params as cache key
  const cacheKey = u.pathname
  const cachedValue = (cacheKey ? cache.get(cacheKey) : null)

  if (cachedValue) {
    console.log(` ☺ ${newUrl}`)
    var mimeType = mime.lookup(u.pathname)

    res.set('Content-Type', mimeType)
    streamifier.createReadStream(cachedValue).pipe(res)
  } else {
    console.log(` ↑ ${newUrl}`)
    var chunks = []

    request.get(newUrl)
    .on('response', upstreamRes => {
      upstreamRes.on('data', d => chunks.push(d))
      upstreamRes.on('end', () => cacheKey && cache.set(cacheKey, Buffer.concat(chunks)))
    })
    .on('error', err => res.serverError(err.message))
    .pipe(res)
  }
}

export const handleStaticPages = server => {
  staticPages.forEach(page => server.get(page, handlePage(page)))
}
<commit_msg>fix behavior of homepage<commit_after>import { some } from 'lodash'
const LRU = require('lru-cache')
const mime = require('mime')
const request = require('request')
const streamifier = require('streamifier')
const url = require('url')
const cache = LRU(50)

const staticPages = [
  '',
  '/help',
  '/help/markdown',
  '/about',
  '/about/careers',
  '/about/contact',
  '/about/team',
  '/subscribe',
  '/styleguide',
  '/terms',
  '/terms/privacy'
]

const transformPathname = pathname => {
  // remove trailing slash
  pathname = pathname.replace(/\/$/, '')

  // a path without an extension should be served by index.html in
  // the folder of the same name.
  if (!pathname.match(/\.\w{2,4}$/)) {
    if (pathname.startsWith('/admin')) {
      // serve the admin Angular app
      pathname = '/admin'
    } else if (!some(staticPages, x => x === pathname)) {
      // for any paths not explicitly listed, serve the Angular app.
      pathname = '/app'
    }

    pathname += '/index.html'
  }

  // add the deploy-specific (cache-busting) path prefix
  if (!pathname.startsWith('/assets')) {
    pathname = `/assets/${process.env.BUNDLE_VERSION}${pathname}`
  }

  return pathname
}

const handlePage = page => (req, res) => {
  if (process.env.DISABLE_PROXY) {
    return res.status(503).send('Service Unavailable')
  }

  var u = url.parse(req.url)
  u.pathname = transformPathname(u.pathname)
  var newUrl = process.env.ASSET_HOST.replace(/\/$/, '') + url.format(u)

  // use path without query params as cache key
  const cacheKey = u.pathname
  const cachedValue = (cacheKey ? cache.get(cacheKey) : null)

  if (cachedValue) {
    console.log(` ☺ ${newUrl}`)
    var mimeType = mime.lookup(u.pathname)

    res.set('Content-Type', mimeType)
    streamifier.createReadStream(cachedValue).pipe(res)
  } else {
    console.log(` ↑ ${newUrl}`)
    var chunks = []

    request.get(newUrl)
    .on('response', upstreamRes => {
      upstreamRes.on('data', d => chunks.push(d))
      upstreamRes.on('end', () => cacheKey && cache.set(cacheKey, Buffer.concat(chunks)))
    })
    .on('error', err => res.serverError(err.message))
    .pipe(res)
  }
}

export const handleStaticPages = server => {
  staticPages.forEach(page => {
    if (page === '') page = '/'
    server.get(page, handlePage(page))
  })
}
<|endoftext|>


<commit_before>import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import reducers from '../reducers';

const logger = createLogger();

export default createStore(
  reducers,
  applyMiddleware(logger),
  applyMiddleware(thunk)
);
<commit_msg>Logs start collapsed<commit_after>import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import reducers from '../reducers';

const logger = createLogger({collapsed: true});

export default createStore(
  reducers,
  applyMiddleware(logger),
  applyMiddleware(thunk)
);
<|endoftext|>


<commit_before>minerva.views.MapPanel = minerva.View.extend({

    events: {
        'click .m-save-current-baselayer': function () {
            this.session.sessionJsonContents.center = this.map.center();
            this.session.sessionJsonContents.zoom = this.map.zoom();
            this.session.saveSession();
        }
    },

    _specifyWmsDatasetLayer: function (dataset, layer) {
        var minervaMetadata = dataset.getMinervaMetadata();
        var baseUrl = minervaMetadata.base_url;
        var layerName = minervaMetadata.type_name;
        // TODO: inclued projection in params ??
        var projection = 'EPSG:3857';
        layer.gcs(projection);
        layer.tileUrl(
            function (zoom, x, y) {
                var xLowerLeft = geo.mercator.tilex2long(x, zoom);
                var yLowerLeft = geo.mercator.tiley2lat(y + 1, zoom);
                var xUpperRight = geo.mercator.tilex2long(x + 1, zoom);
                var yUpperRight = geo.mercator.tiley2lat(y, zoom);

                var sw = geo.mercator.ll2m(xLowerLeft, yLowerLeft, true);
                var ne = geo.mercator.ll2m(xUpperRight, yUpperRight, true);
                var bbox_mercator = sw.x + ',' + sw.y + ',' + ne.x + ',' + ne.y;
                var params = {
                    SERVICE: 'WMS',
                    VERSION: '1.3.0',
                    REQUEST: 'GetMap',
                    LAYERS: layerName,
                    STYLES: '',
                    BBOX: bbox_mercator,
                    WIDTH: 256,
                    HEIGHT: 256,
                    FORMAT: 'image/png',
                    TRANSPARENT: true,
                    SRS: projection,
                    TILED: true
                };
                return baseUrl + '?' + $.param(params);
            }
        );
    },

    addDataset: function (dataset) {
        // TODO HACK
        // deleting and re-adding ui layer to keep it on top
        //this.map.deleteLayer(this.uiLayer);
        // this causes a problem when there are at least two feature layers,
        // so for now it is commented out
        // this means we keep re-adding the ui layer each time a dataset is
        // added as a feature layer, which is even more of a HACK
        if (!_.contains(this.datasetLayers, dataset.id)) {
            if (dataset.getDatasetType() === 'wms') {
                var datasetId = dataset.id;
                var layer = this.map.createLayer('osm');
                this.datasetLayers[datasetId] = layer;
                this._specifyWmsDatasetLayer(dataset, layer);

                this.legendWidget[datasetId] = new minerva.views.LegendWidget({
                    el: $('.m-map-legend-container'),
                    parentView: this,
                    id: datasetId,
                    legend: 'data:image/png;base64,' + dataset.getMinervaMetadata().legend
                });
                this.legendWidget[datasetId].render();
                this.legendWidget[datasetId].show();

                // Add the UI slider back
                this.uiLayer = this.map.createLayer('ui');
                this.uiLayer.createWidget('slider');
                this.map.draw();
            } else {
                // Assume the dataset provides a reader, so load the data
                // and adapt the dataset to the map with the reader.
                dataset.once('m:dataLoaded', function (datasetId) {
                    // TODO: allow these datasets to specify a legend.
                    var dataset = this.collection.get(datasetId);
                    var layer = this.map.createLayer('feature');

                    var reader = geo.createFileReader(dataset.geoFileReader, {layer: layer});
                    this.datasetLayers[datasetId] = layer;

                    layer.clear();

                    reader.read(dataset.fileData, _.bind(function () {
                        // Add the UI slider back
                        this.uiLayer = this.map.createLayer('ui');
                        this.uiLayer.createWidget('slider');
                        this.map.draw();
                    }, this));
                }, this);

                dataset.loadData();
            }
        }
    },

    removeDataset: function (dataset) {
        var datasetId = dataset.id;
        var layer = this.datasetLayers[datasetId];
        if (_.has(this.legendWidget, datasetId)) {
            this.legendWidget[datasetId].remove(datasetId);
            delete this.legendWidget[datasetId];
        }
        if (dataset.getDatasetType() === 'wms') {
            this.map.deleteLayer(layer);
        } else if (layer) {
            layer.clear();
            layer.draw();
        }
        delete this.datasetLayers[datasetId];
    },

    initialize: function (settings) {
        girder.events.on('m:layerDatasetLoaded', this.addDataset, this);
        girder.events.on('m:layerDatasetRemoved', this.removeDataset, this);
        this.session = settings.session;
        this.listenTo(this.session, 'm:mapUpdated', function () {
            // TODO for now only dealing with center
            if (this.map) {
                // TODO could better separate geojs needs from session storage
                this.map.center(this.session.sessionJsonContents.center);
            }
        });
        this.datasetLayers = {};
        this.legendWidget = {};
    },

    renderMap: function () {
        if (!this.map) {
            this.map = geo.map({
                node: '.mapPanelMap',
                center: this.session.sessionJsonContents.center,
                zoom: this.session.sessionJsonContents.zoom
            });
            this.map.createLayer(this.session.sessionJsonContents.basemap);
            this.uiLayer = this.map.createLayer('ui');
            this.uiLayer.createWidget('slider');
        }
        this.map.draw();
    },

    render: function () {
        this.$el.html(minerva.templates.mapPanel({}));
        this.renderMap();
        var tooltipProperties = {
            placement: 'left',
            delay: 400,
            container: this.$el,
            trigger: 'hover'
        };
        this.$('.m-save-current-baselayer').tooltip(tooltipProperties);
        return this;
    }
});
<commit_msg>Don't use the OSM attribution when using a WMS source<commit_after>minerva.views.MapPanel = minerva.View.extend({

    events: {
        'click .m-save-current-baselayer': function () {
            this.session.sessionJsonContents.center = this.map.center();
            this.session.sessionJsonContents.zoom = this.map.zoom();
            this.session.saveSession();
        }
    },

    _specifyWmsDatasetLayer: function (dataset, layer) {
        var minervaMetadata = dataset.getMinervaMetadata();
        var baseUrl = minervaMetadata.base_url;
        var layerName = minervaMetadata.type_name;
        // TODO: inclued projection in params ??
        var projection = 'EPSG:3857';
        layer.gcs(projection);
        layer.tileUrl(
            function (zoom, x, y) {
                var xLowerLeft = geo.mercator.tilex2long(x, zoom);
                var yLowerLeft = geo.mercator.tiley2lat(y + 1, zoom);
                var xUpperRight = geo.mercator.tilex2long(x + 1, zoom);
                var yUpperRight = geo.mercator.tiley2lat(y, zoom);

                var sw = geo.mercator.ll2m(xLowerLeft, yLowerLeft, true);
                var ne = geo.mercator.ll2m(xUpperRight, yUpperRight, true);
                var bbox_mercator = sw.x + ',' + sw.y + ',' + ne.x + ',' + ne.y;
                var params = {
                    SERVICE: 'WMS',
                    VERSION: '1.3.0',
                    REQUEST: 'GetMap',
                    LAYERS: layerName,
                    STYLES: '',
                    BBOX: bbox_mercator,
                    WIDTH: 256,
                    HEIGHT: 256,
                    FORMAT: 'image/png',
                    TRANSPARENT: true,
                    SRS: projection,
                    TILED: true
                };
                return baseUrl + '?' + $.param(params);
            }
        );
    },

    addDataset: function (dataset) {
        // TODO HACK
        // deleting and re-adding ui layer to keep it on top
        //this.map.deleteLayer(this.uiLayer);
        // this causes a problem when there are at least two feature layers,
        // so for now it is commented out
        // this means we keep re-adding the ui layer each time a dataset is
        // added as a feature layer, which is even more of a HACK
        if (!_.contains(this.datasetLayers, dataset.id)) {
            if (dataset.getDatasetType() === 'wms') {
                var datasetId = dataset.id;
                var layer = this.map.createLayer('osm', {attribution: null});
                this.datasetLayers[datasetId] = layer;
                this._specifyWmsDatasetLayer(dataset, layer);

                this.legendWidget[datasetId] = new minerva.views.LegendWidget({
                    el: $('.m-map-legend-container'),
                    parentView: this,
                    id: datasetId,
                    legend: 'data:image/png;base64,' + dataset.getMinervaMetadata().legend
                });
                this.legendWidget[datasetId].render();
                this.legendWidget[datasetId].show();

                // Add the UI slider back
                this.uiLayer = this.map.createLayer('ui');
                this.uiLayer.createWidget('slider');
                this.map.draw();
            } else {
                // Assume the dataset provides a reader, so load the data
                // and adapt the dataset to the map with the reader.
                dataset.once('m:dataLoaded', function (datasetId) {
                    // TODO: allow these datasets to specify a legend.
                    var dataset = this.collection.get(datasetId);
                    var layer = this.map.createLayer('feature');

                    var reader = geo.createFileReader(dataset.geoFileReader, {layer: layer});
                    this.datasetLayers[datasetId] = layer;

                    layer.clear();

                    reader.read(dataset.fileData, _.bind(function () {
                        // Add the UI slider back
                        this.uiLayer = this.map.createLayer('ui');
                        this.uiLayer.createWidget('slider');
                        this.map.draw();
                    }, this));
                }, this);

                dataset.loadData();
            }
        }
    },

    removeDataset: function (dataset) {
        var datasetId = dataset.id;
        var layer = this.datasetLayers[datasetId];
        if (_.has(this.legendWidget, datasetId)) {
            this.legendWidget[datasetId].remove(datasetId);
            delete this.legendWidget[datasetId];
        }
        if (dataset.getDatasetType() === 'wms') {
            this.map.deleteLayer(layer);
        } else if (layer) {
            layer.clear();
            layer.draw();
        }
        delete this.datasetLayers[datasetId];
    },

    initialize: function (settings) {
        girder.events.on('m:layerDatasetLoaded', this.addDataset, this);
        girder.events.on('m:layerDatasetRemoved', this.removeDataset, this);
        this.session = settings.session;
        this.listenTo(this.session, 'm:mapUpdated', function () {
            // TODO for now only dealing with center
            if (this.map) {
                // TODO could better separate geojs needs from session storage
                this.map.center(this.session.sessionJsonContents.center);
            }
        });
        this.datasetLayers = {};
        this.legendWidget = {};
    },

    renderMap: function () {
        if (!this.map) {
            this.map = geo.map({
                node: '.mapPanelMap',
                center: this.session.sessionJsonContents.center,
                zoom: this.session.sessionJsonContents.zoom
            });
            this.map.createLayer(this.session.sessionJsonContents.basemap);
            this.uiLayer = this.map.createLayer('ui');
            this.uiLayer.createWidget('slider');
        }
        this.map.draw();
    },

    render: function () {
        this.$el.html(minerva.templates.mapPanel({}));
        this.renderMap();
        var tooltipProperties = {
            placement: 'left',
            delay: 400,
            container: this.$el,
            trigger: 'hover'
        };
        this.$('.m-save-current-baselayer').tooltip(tooltipProperties);
        return this;
    }
});
<|endoftext|>


<commit_before>/*
    Angular State Handler
    2015-10-12
    Public Domain.
    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.
*/

! function(window, angular, undefined) {
  "use strict";
  var app = angular.module("stateHandler", ["ngRoute"]),
    randomTemplateUrl = "###" + (Math.random() * 10 / 10) + "###",
    routeHash = {},
    routeTemplateUrlCollection = [],
    dummyElem = document.createElement("a"),
    newRoute = null;

  function getRelativePath(url) {
    dummyElem.href = url;
    return {
      path: dummyElem.pathname,
      fullPath: dummyElem.pathname + dummyElem.search
    };
  }

  // function generateSearchStringFromObject(obj) {
  //   var str = undefined;
  //   for (var a in obj) {
  //     if (str === undefined) {
  //       str = "?";
  //     } else {
  //       str += "&";
  //     }
  //     str += a + "=" + obj[a];
  //   }

  //   return str || "";
  // }

  // Factories required to configure this module
  app.provider('$factoriesForStateHandle', ["$provide",
    function($provide) {
      var obj = {
        $get: function() {}
      };

      getFactoryReferenceFn("$route");
      getFactoryReferenceFn("$timeout");
      getFactoryReferenceFn("$location");

      function getFactoryReferenceFn(factoryName) {
        $provide.decorator(factoryName, ['$delegate', factoryDecoratorFn]);

        function factoryDecoratorFn($delegate) {
          return obj[factoryName] = $delegate;
        };
      }

      return obj;
    }
  ]);

  // Provider to handle view and path state based on routing
  app.provider('$stateHandle', ["$provide", "$factoriesForStateHandleProvider",
    function($provide, $factoriesForStateHandleProvider) {
      var $browser = undefined,
        identityHash = {},
        authParams = {
          path: undefined,
          route: null
        },
        _constructor = function(subscriber, pathExpr) {
          this.subscriber = subscriber;
          this.pathExpr = pathExpr;
          this.callBacks = [];
        },
        obj = {
          subscribe: subscribeFn,
          getSubscribers: getSubscribersFn,
          setAuthParams: setAuthParamsFn,
          getAuthParams: getAuthParamsFn
        };

      function subscribeFn(subscriber, pathExpr) {
        if (!(pathExpr in identityHash)) {
          identityHash[pathExpr] = {};
        } else if (subscriber in identityHash[pathExpr]) {
          identityHash[pathExpr][subscriber].callBacks.length = 0;
        }

        return identityHash[pathExpr][subscriber] || (identityHash[pathExpr][subscriber] = new _constructor(subscriber, pathExpr));
      }

      function getSubscribersFn(pathExpr) {
        return identityHash[pathExpr];
      }

      function setAuthParamsFn(path, route) {
        authParams.path = path;
        authParams.route = route;
        return this;
      }

      function getAuthParamsFn() {
        return authParams;
      }

      function subscriberResponseFn(callback) {
        var that = this;
        that.callBacks.push(callback);
        $factoriesForStateHandleProvider.$timeout(function() {
          if (that.pathExpr == newRoute.originalPath) {
            callback(newRoute.params);
          }
        },100);
      };

      _constructor.prototype = {
        response: subscriberResponseFn
      }

      return {
        $get: function() {
          return obj;
        }
      };
    }
  ]);

  app.run(['$route', '$location', '$rootScope', '$timeout', '$stateHandle', '$window', '$q', function($route, $location, $rootScope, $timeout, $stateHandle, $window, $q) {
    var previousUrl = undefined,
      searchUrl = undefined,
      callbackTimeoutId = null,
      isNewLoaded = true,
      userAuthenticated = undefined,
      deferred = $q.defer(),
      notInitCall=false;

    $stateHandle.route = {};

    // function getPropertyValueFromHistoryStateFn(prop) {
    //   var historyState = $location.$$state;
    //   if (historyState && ('path' in historyState)) {
    //     if (routeHash[historyState.path] && (prop in routeHash[historyState.path])) {
    //       return routeHash[historyState.path][prop];
    //     }
    //   }
    //   var fallBackValue = undefined;
    //   for (var _a3 in routeHash) {
    //     var regexp = new RegExp(routeHash[_a3].regexp),
    //       currentRoute = routeHash[_a3];
    //     if (prop in currentRoute) {
    //       if (historyState && 'path' in historyState && regexp.test(historyState.path)) {
    //         if (prop in routeHash[_a3]) {
    //           return routeHash[_a3][prop];
    //         }
    //       }
    //       if (fallBackValue === undefined) {
    //         fallBackValue = routeHash[_a3][prop];
    //       }
    //     }
    //   }

    //   return fallBackValue;
    // }

    function getPrevUrlIfReloadWhenViewIsSetFn() {
      var historyState = $location.state();
      if (historyState && ('path' in historyState)) {
        return historyState.path;
      } else {
        for (var a in routeHash) {
          if (/\/$/.test(a) === true) {
            return a;
          }
        }
      }
    }

    $rootScope.$on('$routeChangeStart', function(event, newUrl, prevUrl) {
      var newUrl = newUrl;
      $stateHandle.route.prevUrl = prevUrl;
      newRoute = $stateHandle.route.newUrl = newUrl;
      if (newUrl.templateUrl == randomTemplateUrl) {
        if (prevUrl === undefined) {
          var location = $location.path(),
            pathToSet = getPrevUrlIfReloadWhenViewIsSetFn();
          $stateHandle.path(pathToSet);
          $timeout(function() {
            $stateHandle.path(location, false);
          });
        } else {
          $stateHandle.path($location.path(), false);
          if (previousUrl !== undefined) {
            $location.state({
              path: previousUrl,
              searchString: searchUrl
            });
          }
        }
      } else {
        previousUrl = $location.path();
        searchUrl = $location.search();
      }
    });

    $rootScope.$on('$locationChangeStart', function(event, newUrl, prevUrl) {
      var callSubscribers = function(route) {
        var subscribers = $stateHandle.getSubscribers(route.originalPath);
        if(notInitCall){
          for (var a in subscribers) {
            var subscriberCallbacks = subscribers[a].callBacks;
            for (var i = 0, len = subscriberCallbacks.length; i < len; i++) {
              subscriberCallbacks[i](route.params);
            }
          }
        }

	notInitCall = true;
        if (isNewLoaded && $stateHandle.route.prevUrl !== undefined && route.originalPath !== $stateHandle.route.prevUrl.originalPath) {
          callSubscribers($stateHandle.route.prevUrl);
        }
        isNewLoaded = false;
      };

      $timeout.cancel(callbackTimeoutId);
      callbackTimeoutId = $timeout(function() {
        if ($stateHandle.route && $stateHandle.route.newUrl.title !== undefined) {
          document.title = $stateHandle.route.newUrl.title;
        }

        callSubscribers($stateHandle.route.newUrl);
      }, 100);
    });

    function resetRouteFn(callback) {
      var stateObj = $location.state();
      $stateHandle.path(previousUrl || (stateObj && stateObj.path ||
        function() {
          for (var _a in routeHash) {
            if (/\/$/.test(a) === true) {
              return a;
            }
          }
        }()
      ), false);

      $location.search(searchUrl || (stateObj && stateObj.searchString) || {});
    }

    function editLocationRouteFunctions(prop) {
      var original = $location[prop];
      return function(value, reload) {
        var ArrayPassedToApply = [];
        if (reload === false) {
          var lastRoute = $route.current,
            un = $rootScope.$on('$locationChangeSuccess', function() {
              $route.current = lastRoute;
              un();
            });
        }
        if (value !== undefined) {
          ArrayPassedToApply.push(value);
        }
        return original.apply($location, ArrayPassedToApply);
      }
    }

    function setUserAuthFn(bool) {
      userAuthenticated = bool;
      deferred.resolve(userAuthenticated);
      return this;
    }

    function ifUserAuthenticatedFn(callback) {
      if (userAuthenticated === undefined) {
        deferred.resolve(false);
      }
      deferred.promise.then(function(userAuthenticated) {
        callback(userAuthenticated);
        callback = function() {};
      });
    }

    $stateHandle.ifUserAuthenticated = ifUserAuthenticatedFn;
    $stateHandle.setUserAuth = setUserAuthFn;
    $stateHandle.resetRoute = resetRouteFn;
    $stateHandle.path = editLocationRouteFunctions("path");
    $stateHandle.search = editLocationRouteFunctions("search");

    routeHash = $route.routes;
    // routeHash.getPropertyValue = getPropertyValueFromHistoryStateFn;
  }]);

  app.config(["$provide", "$routeProvider", "$httpProvider", "$locationProvider", "$stateHandleProvider", "$factoriesForStateHandleProvider",
    function($provide, $routeProvider, $httpProvider, $locationProvider, $stateHandleProvider, $factoriesForStateHandleProvider) {
      var $stateHandle = $stateHandleProvider.$get(),
        whenFn = cloneRouteProviderFn.call($stateHandleProvider, 'when'),
        otherwiseFn = cloneRouteProviderFn.call($stateHandleProvider, 'otherwise'),
        urlBeforeViewSet = undefined;

      function cloneRouteProviderFn(prop) {
        var that = this,
          functionRef = $routeProvider[prop];
        return function(path, route) {
          if (route !== undefined) {
            if (!('templateUrl' in route || 'template' in route)) {
              route.templateUrl = randomTemplateUrl;
            } else if ('templateUrl' in route) {
              if (routeTemplateUrlCollection.indexOf(route.templateUrl) === -1) {
                routeTemplateUrlCollection.push(route.templateUrl);
              }
            }
          }

          functionRef.apply($routeProvider, arguments);
          return (that);
        };
      }

      function removeFn(path) {
        var $routeRef = $routeProvider.$get();
        path = path.replace(/\/$/i, "");
        delete($routeRef.routes[path]);
        delete($routeRef.routes[path + "/"]);
        return (this);
      }

      function removeCurrentFn() {
        var $routeRef = $routeProvider.$get();
        return (this.remove($routeRef.current.originalPath));
      }

      function reloadRouteFn() {
        $factoriesForStateHandleProvider.$route.reload();
      }

      function noAuthFn(path, route) {
        var that = this,
          authParamsPathRef = $stateHandle.getAuthParams().path;

        if (authParamsPathRef !== undefined) {
          $stateHandleProvider.remove(authParamsPathRef);
        }

        $stateHandle.setAuthParams(path, route);

        if (route !== undefined && 'authentication' in route) {
          delete route['authentication'];
        }

        $stateHandleProvider.when(path, route || {});
        return that;
      }

      $stateHandle.remove = $stateHandleProvider.remove = removeFn;
      $stateHandle.removeCurrent = $stateHandleProvider.removeCurrent = removeCurrentFn;
      $stateHandle.when = $stateHandleProvider.when = whenFn;
      $stateHandle.otherwise = $stateHandleProvider.otherwise = otherwiseFn;
      $stateHandle.reloadRoute = $stateHandleProvider.reloadRoute = reloadRouteFn;
      $stateHandle.noAuth = $stateHandleProvider.noAuth = noAuthFn;

      $locationProvider.html5Mode(true);
    }
  ]);
}(window, window.angular);
<commit_msg>Update stateHandler.js<commit_after>/*
    Angular State Handler
    2015-10-12
    Public Domain.
    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.
*/

! function(window, angular, undefined) {
  "use strict";
  var app = angular.module("stateHandler", ["ngRoute"]),
    randomTemplateUrl = "###" + (Math.random() * 10 / 10) + "###",
    routeHash = {},
    routeTemplateUrlCollection = [],
    dummyElem = document.createElement("a");

  function getRelativePath(url) {
    dummyElem.href = url;
    return {
      path: dummyElem.pathname,
      fullPath: dummyElem.pathname + dummyElem.search
    };
  }

  // function generateSearchStringFromObject(obj) {
  //   var str = undefined;
  //   for (var a in obj) {
  //     if (str === undefined) {
  //       str = "?";
  //     } else {
  //       str += "&";
  //     }
  //     str += a + "=" + obj[a];
  //   }

  //   return str || "";
  // }

  // Factories required to configure this module
  app.provider('$factoriesForStateHandle', ["$provide",
    function($provide) {
      var obj = {
        $get: function() {}
      };

      getFactoryReferenceFn("$route");
      getFactoryReferenceFn("$timeout");
      getFactoryReferenceFn("$location");

      function getFactoryReferenceFn(factoryName) {
        $provide.decorator(factoryName, ['$delegate', factoryDecoratorFn]);

        function factoryDecoratorFn($delegate) {
          return obj[factoryName] = $delegate;
        };
      }

      return obj;
    }
  ]);

  // Provider to handle view and path state based on routing
  app.provider('$stateHandle', ["$provide", "$factoriesForStateHandleProvider",
    function($provide, $factoriesForStateHandleProvider) {
      var $browser = undefined,
        identityHash = {},
        authParams = {
          path: undefined,
          route: null
        },
        _constructor = function(subscriber, pathExpr) {
          this.subscriber = subscriber;
          this.pathExpr = pathExpr;
          this.callBacks = [];
        },
        obj = {
          subscribe: subscribeFn,
          getSubscribers: getSubscribersFn,
          setAuthParams: setAuthParamsFn,
          getAuthParams: getAuthParamsFn
        };

      function subscribeFn(subscriber, pathExpr) {
        if (!(pathExpr in identityHash)) {
          identityHash[pathExpr] = {};
        } else if (subscriber in identityHash[pathExpr]) {
          identityHash[pathExpr][subscriber].callBacks.length = 0;
        }

        return identityHash[pathExpr][subscriber] || (identityHash[pathExpr][subscriber] = new _constructor(subscriber, pathExpr));
      }

      function getSubscribersFn(pathExpr) {
        return identityHash[pathExpr];
      }

      function setAuthParamsFn(path, route) {
        authParams.path = path;
        authParams.route = route;
        return this;
      }

      function getAuthParamsFn() {
        return authParams;
      }

      function subscriberResponseFn(callback) {
        var that = this;
        that.callBacks.push(callback);
        $factoriesForStateHandleProvider.$timeout(function() {
          if (that.pathExpr == $factoriesForStateHandleProvider.$route.current.originalPath) {
            callback($factoriesForStateHandleProvider.$route.current.params);
          }
        });
      };

      _constructor.prototype = {
        response: subscriberResponseFn
      }

      return {
        $get: function() {
          return obj;
        }
      };
    }
  ]);

  app.run(['$route', '$location', '$rootScope', '$timeout', '$stateHandle', '$window', '$q', function($route, $location, $rootScope, $timeout, $stateHandle, $window, $q) {
    var previousUrl = undefined,
      searchUrl = undefined,
      callbackTimeoutId = null,
      isNewLoaded = true,
      userAuthenticated = undefined,
      deferred = $q.defer();

    $stateHandle.route = {};

    // function getPropertyValueFromHistoryStateFn(prop) {
    //   var historyState = $location.$$state;
    //   if (historyState && ('path' in historyState)) {
    //     if (routeHash[historyState.path] && (prop in routeHash[historyState.path])) {
    //       return routeHash[historyState.path][prop];
    //     }
    //   }
    //   var fallBackValue = undefined;
    //   for (var _a3 in routeHash) {
    //     var regexp = new RegExp(routeHash[_a3].regexp),
    //       currentRoute = routeHash[_a3];
    //     if (prop in currentRoute) {
    //       if (historyState && 'path' in historyState && regexp.test(historyState.path)) {
    //         if (prop in routeHash[_a3]) {
    //           return routeHash[_a3][prop];
    //         }
    //       }
    //       if (fallBackValue === undefined) {
    //         fallBackValue = routeHash[_a3][prop];
    //       }
    //     }
    //   }

    //   return fallBackValue;
    // }

    function getPrevUrlIfReloadWhenViewIsSetFn() {
      var historyState = $location.state();
      if (historyState && ('path' in historyState)) {
        return historyState.path;
      } else {
        for (var a in routeHash) {
          if (/\/$/.test(a) === true) {
            return a;
          }
        }
      }
    }

    $rootScope.$on('$routeChangeStart', function(event, newUrl, prevUrl) {
      var newUrl = newUrl;
      $stateHandle.route.prevUrl = prevUrl;
      $stateHandle.route.newUrl = newUrl;
      if (newUrl.templateUrl == randomTemplateUrl) {
        if (prevUrl === undefined) {
          var location = $location.path(),
            pathToSet = getPrevUrlIfReloadWhenViewIsSetFn();
          $stateHandle.path(pathToSet);
          $timeout(function() {
            $stateHandle.path(location, false);
          });
        } else {
          $stateHandle.path($location.path(), false);
          if (previousUrl !== undefined) {
            $location.state({
              path: previousUrl,
              searchString: searchUrl
            });
          }
        }
      } else {
        previousUrl = $location.path();
        searchUrl = $location.search();
      }
    });

    $rootScope.$on('$locationChangeStart', function(event, newUrl, prevUrl) {
      var callSubscribers = function(route) {
        var subscribers = $stateHandle.getSubscribers(route.originalPath);
        for (var a in subscribers) {
          var subscriberCallbacks = subscribers[a].callBacks;
          for (var i = 0, len = subscriberCallbacks.length; i < len; i++) {
            subscriberCallbacks[i](route.params);
          }
        }

        if (isNewLoaded && $stateHandle.route.prevUrl !== undefined && route.originalPath !== $stateHandle.route.prevUrl.originalPath) {
          callSubscribers($stateHandle.route.prevUrl);
        }
        isNewLoaded = false;
      };

      $timeout.cancel(callbackTimeoutId);
      callbackTimeoutId = $timeout(function() {
        if ($stateHandle.route && $stateHandle.route.newUrl.title !== undefined) {
          document.title = $stateHandle.route.newUrl.title;
        }
        callSubscribers($stateHandle.route.newUrl);
      }, 100);
    });

    function resetRouteFn(callback) {
      var stateObj = $location.state();
      $stateHandle.path(previousUrl || (stateObj && stateObj.path ||
        function() {
          for (var _a in routeHash) {
            if (/\/$/.test(a) === true) {
              return a;
            }
          }
        }()
      ), false);

      $location.search(searchUrl || (stateObj && stateObj.searchString) || {});
    }

    function editLocationRouteFunctions(prop) {
      var original = $location[prop];
      return function(value, reload) {
        var ArrayPassedToApply = [];
        if (reload === false) {
          var lastRoute = $route.current,
            un = $rootScope.$on('$locationChangeSuccess', function() {
              $route.current = lastRoute;
              un();
            });
        }
        if (value !== undefined) {
          ArrayPassedToApply.push(value);
        }
        return original.apply($location, ArrayPassedToApply);
      }
    }

    function setUserAuthFn(bool) {
      userAuthenticated = bool;
      deferred.resolve(userAuthenticated);
      return this;
    }

    function ifUserAuthenticatedFn(callback) {
      if (userAuthenticated === undefined) {
        deferred.resolve(false);
      }
      deferred.promise.then(function(userAuthenticated) {
        callback(userAuthenticated);
        callback = function() {};
      });
    }

    $stateHandle.ifUserAuthenticated = ifUserAuthenticatedFn;
    $stateHandle.setUserAuth = setUserAuthFn;
    $stateHandle.resetRoute = resetRouteFn;
    $stateHandle.path = editLocationRouteFunctions("path");
    $stateHandle.search = editLocationRouteFunctions("search");

    routeHash = $route.routes;
    // routeHash.getPropertyValue = getPropertyValueFromHistoryStateFn;
  }]);

  app.config(["$provide", "$routeProvider", "$httpProvider", "$locationProvider", "$stateHandleProvider", "$factoriesForStateHandleProvider",
    function($provide, $routeProvider, $httpProvider, $locationProvider, $stateHandleProvider, $factoriesForStateHandleProvider) {
      var $stateHandle = $stateHandleProvider.$get(),
        whenFn = cloneRouteProviderFn.call($stateHandleProvider, 'when'),
        otherwiseFn = cloneRouteProviderFn.call($stateHandleProvider, 'otherwise'),
        urlBeforeViewSet = undefined;

      function cloneRouteProviderFn(prop) {
        var that = this,
          functionRef = $routeProvider[prop];
        return function(path, route) {
          if (route !== undefined) {
            if (!('templateUrl' in route || 'template' in route)) {
              route.templateUrl = randomTemplateUrl;
            } else if ('templateUrl' in route) {
              if (routeTemplateUrlCollection.indexOf(route.templateUrl) === -1) {
                routeTemplateUrlCollection.push(route.templateUrl);
              }
            }
          }

          functionRef.apply($routeProvider, arguments);
          return (that);
        };
      }

      function removeFn(path) {
        var $routeRef = $routeProvider.$get();
        path = path.replace(/\/$/i, "");
        delete($routeRef.routes[path]);
        delete($routeRef.routes[path + "/"]);
        return (this);
      }

      function removeCurrentFn() {
        var $routeRef = $routeProvider.$get();
        return (this.remove($routeRef.current.originalPath));
      }

      function reloadRouteFn() {
        $factoriesForStateHandleProvider.$route.reload();
      }

      function noAuthFn(path, route) {
        var that = this,
          authParamsPathRef = $stateHandle.getAuthParams().path;

        if (authParamsPathRef !== undefined) {
          $stateHandleProvider.remove(authParamsPathRef);
        }

        $stateHandle.setAuthParams(path, route);

        if (route !== undefined && 'authentication' in route) {
          delete route['authentication'];
        }

        $stateHandleProvider.when(path, route || {});
        return that;
      }

      $stateHandle.remove = $stateHandleProvider.remove = removeFn;
      $stateHandle.removeCurrent = $stateHandleProvider.removeCurrent = removeCurrentFn;
      $stateHandle.when = $stateHandleProvider.when = whenFn;
      $stateHandle.otherwise = $stateHandleProvider.otherwise = otherwiseFn;
      $stateHandle.reloadRoute = $stateHandleProvider.reloadRoute = reloadRouteFn;
      $stateHandle.noAuth = $stateHandleProvider.noAuth = noAuthFn;

      $locationProvider.html5Mode(true);
    }
  ]);
}(window, window.angular);
<|endoftext|>