<commit_before>import {colors} from "../color.js";
import {polyline} from "./primitives/polyline.js";
import {isArray, isObject} from "../util.js";
import {isContinuousScale, isDiscreteScale} from "../scales/index.js";
import {getExpressionSources} from "../runtime/expression.js";
import {getValueSources} from "../runtime/value.js";
import {createHashMap} from "../hashmap.js";
import {ticks as generateTicks} from "../math.js";

import {getPanelsElements} from "./panels.js";

//Available orientation values
let orientationValues = ["top", "bottom", "left", "right"];

//Axis default props
let defaultProps = {
    "line": true,
    "lineColor": "black",
    "lineWidth": "1px",
    "lineOpacity": 1,
    //Labels default attributes
    "label": true,
    "labelColor": "black",
    "labelSize": "11px",
    "labelOpacity": 0.8,
    "labelPadding": 5,
    "labelRotation": 0,
    "labelBaseline": "middle", //hanging|middle|baseline
    "labelAnchor": "middle",   //start|middle|center
    //Default ticks attributes
    "ticks": false,
    "tickCount": 0,
    "tickValues": [],
    "tickColor": "black",
    "tickSize": "11px",
    "tickOpacity": 0.8,
    "tickPadding": 5,
    "tickRotation": 0,
    "tickFormat": null,
    "tickBaseline": "middle",   //hanging|middle|baseline
    "tickAnchor": "middle",     //start|middle|end
    "slot": true,    //Display a line indication the tick position
    "slotColor": "black",
    "slotOpacity": 1,
    "slotWidth": "1px",
    //Default grid attributes
    "grid": false,
    "gridColor": "black",
    "gridOpacity": 1,
    "gridWidth": "1px"
};

//Interpolate scale values
let generateValues = function (scale, count) {
    //Check for continuous scale
    if (isContinuousScale(scale) === true) {
        //Get the range values
        let start = Math.min.apply(null, scale.domain); //Get start value
        let end = Math.max.apply(null, scale.domain); //Get end value
        //Return ticks values
        return generateTicks(start, end, count);
    }
    //Check for discrete scale
    else if (isDiscreteScale(scale) === true) {
        return scale.domain;
    }
    //Other scale type: error and return an empty values array
    //TODO
    return [];
};

//Get the display value
//let getDisplayValue = function (context, props, value) {
//    if (typeof props.tickFormat === "string") {
//        return context.expression(props.tickFormat.expr, {
//            "value": value
//        });
//    }
//    //Return the default value
//    return value;
//};

//Get orientation
let getOrientation = function (value) {
    return value.toLowerCase();
};

//Create an axis node
export function createAxisNode (context, index, props) {
    let node = context.addNode({
        "id": `axis:${index}`,
        "props": props, //Object.assign({}, defaultProps, props),
        "type": "axis",
        "targets": null, //createNodeList(),
        "parent": []
    });
    //Add sources fo this axis
    context.panels.targets.add(node.id, node); //Always ad the panels node
    if (typeof node.props.scale === "string") {
        context.scales[node.props.scale].targets.add(node.id, node);
    }
    //Axis position can be extracted from sources
    getValueSources(context, node.props.position).forEach(function (source) {
        source.targets.add(node.id, node);
    });
    //Check if tickformat is a string --> evaluate as an expression
    if (typeof node.props.tickFormat === "strong") {
        getExpressionSources(context, node.props.tickFormat).forEach(function (source) {
            source.targets.add(node.id, node);
        });
    }
    //Render this axis
    //return updateAxis(context, node);
}

//Export axis drawing
export function updateAxisNode (context, node) {
    //let target = node.parent; //parent.append("g");
    let props = node.props; //Object.assign({}, defaultProps, node.props);
    let draw = context.panels.value; //context.draw.computed;
    let scale = context.scales[props.scale].value;
    //Axis positions and size
    let axisSize = Math.abs(scale.range[1] - scale.range[0]); //Axis size
    //let axisStart = scale.range[0];
    //let axisEnd = scale.range[1];
    //Axis position
    let position = context.value(props.position, 0, 0); //defaultProps.position);
    //Get the axis type
    let orientation = getOrientation(props.orientation);
    let hasAxisLine = context.value(props.line, null, defaultProps.line); //Display axis line
    let isXAxis = orientation === "top" || orientation === "bottom";
    let hasAxisTicks = context.value(props.ticks, null, defaultProps.ticks); //Display ticks
    let hasAxisGrid = context.value(props.grid, null, defaultProps.grid); //Display axis grid
    let ticksValues = []; //Values to display
    if (hasAxisTicks === true) {
        if (isArray(props.tickValues) === true) {
            ticksValues = context.value(props.tickValues, [], []); //Get values from context
        }
        else {
            //Generate values from counts
            ticksValues = generateValues(scale, context.value(props.tickCount, 0, defaultProps.tickCount));
        }
    }
    //Get panels where this axis will be rendered
    getPanelsElements(context, props.panel).forEach(function (element, index) {
        //Check if there is a group for this axis
        let target = element.selectAll(`g[data-axis='${node.id}']`);
        if (target.length === 0) {
            target = element.append("g").attr("data-axis", node.id); //Create a new axis
        }
        //Remove old children
        target.empty();
        //Calculate the axis positions
        let axisPosition = {};
        //Check for top|bottom axis
        if (isXAxis === true) {
            axisPosition = {
                "x1": position + Math.min(scale.range[0], scale.range[1]),
                "x2": position + Math.max(scale.range[0], scale.range[1]),
                "y1": (orientation === "top") ? 0 : draw.height,
                "y2": (orientation === "top") ? 0 : draw.height
            };
        }
        else {
            axisPosition = {
                "x1": (orientation === "left") ? 0 : draw.width,
                "x2": (orientation === "left") ? 0 : draw.width,
                "y1": position + Math.min(scale.range[0], scale.range[1]),
                "y2": position + Math.max(scale.range[0], scale.range[1])
            };
        }
        //console.log(axisPosition);
        //Display ticks
        //if (props.ticks === true) { // && (typeof props.tickCount === "number" || viz.isArray(props.tickValues))) {
        if (context.value(props.ticks, null, defaultProps.ticks) === true) {
            let angle = context.value(props.tickRotation, null, defaultProps.tickRotation); //Get rotation angle
            let tickPadding = context.value(props.tickPadding, 0, defaultProps.tickPadding); //Get ticks padding
            let tickSlot = context.value(props.slot, null, defaultProps.slot); //Display tick slot
            //Display each label value
            ticksValues.forEach(function (value, index) {
                //Calculate the label positions
                let valuePosition = scale(value, index);
                //console.log(value + " --> " + valuePosition);
                //Check for null value --> not valid label
                if (valuePosition === null || typeof valuePosition === "undefined") {
                    return false;
                }
                //Check for interval scale
                if (scale.type === "interval") {//if (typeof props.scale.step === "number") {
                    valuePosition = valuePosition + scale.step / 2;
                }
                //let labelX = (isXAxis) ? position : props.x - props.labelMargin;
                //let labelY = (props.type === "y") ? position : props.y + props.labelMargin;
                let tickX = 0, tickY = 0; //, tickAnchor = "middle", tickBaseline = "middle";
                let slotLine = null;
                let gridLine = null;
                //let labelAnchor = (props.orientation === "left") ? "end" : "start";
                //Calculate the label positions
                if (orientation === "left" || orientation === "right") {
                    tickX = axisPosition.x1 + (((orientation === "left") ? -1 : +1) * tickPadding);
                    tickY = valuePosition + position; //props.y + props.height - position;
                    //Check for displaying the tick slot
                    if (tickSlot === true && hasAxisLine === true) {
                        let px2 = axisPosition.x1 + (((orientation === "left") ? -1 : +1) * tickPadding / 3);
                        slotLine = target.append("path");
                        slotLine.attr("d", polyline({
                            "points": [
                                [axisPosition.x1, tickY],
                                [px2, tickY]
                            ],
                            "closed": false
                        }));
                    }
                    //Check for displaying the grid line
                    if (hasAxisGrid === true) {
                        gridLine = target.append("path");
                        gridLine.attr("d", polyline({
                            "points": [[0, tickY], [draw.width, tickY]],
                            "closed": false
                        }));
                    }
                }
                else {
                    tickX = valuePosition + position;
                    tickY = axisPosition.y1 + (((orientation === "top") ? -1 : +1) * tickPadding);
                    //Check for displaying the tick slot
                    //if (props.tickSlot === true && props.line === true) {
                    if (tickSlot === true && hasAxisLine === true) {
                        let py2 = axisPosition.y1 + (((orientation === "top") ? -1 : +1) * tickPadding / 3);
                        slotLine = target.append("path");
                        slotLine.attr("d", polyline({
                            "points": [
                                [tickX, axisPosition.y1],
                                [tickX, py2]
                            ],
                            "closed": false
                        }));
                    }
                    //Check for displaying the grid line
                    if (hasAxisGrid === true) {
                        gridLine = target.append("path");
                        gridLine.attr("d", polyline({
                            "points": [[tickX, 0], [tickX, draw.height]],
                            "closed": false
                        }));
                    }
                }
                //Check for slot line --> set slot style
                if (slotLine !== null) {
                    slotLine.attr("fill", "none");
                    slotLine.attr("stroke-width", context.value(props.slotWidth, null, defaultProps.slotWidth)); //Default slot width
                    slotLine.attr("stroke", context.value(props.slotColor, null, context.theme.axesSlotColor));
                    slotLine.style("opacity", context.value(props.slotOpacity, 0, defaultProps.slotOpacity));
                }
                //Check for grid line --> set grid line
                if (gridLine !== null) {
                    gridLine.attr("fill", "none");
                    gridLine.attr("stroke-width", context.value(props.gridWidth, null, defaultProps.gridWidth));
                    gridLine.attr("stroke", context.value(props.gridColor, null, context.theme.axesGridColor));
                    gridLine.style("opacity", context.value(props.gridOpacity, 0, defaultProps.gridOpacity));
                }
                //Display the text element
                let text = target.append("text");
                text.text(context.value(props.tickFormat, value, value));
                text.attr("x", tickX);
                text.attr("y", tickY);
                text.attr("text-anchor", context.value(props.tickAnchor, null, defaultProps.tickAnchor));
                text.attr("alignment-baseline", context.value(props.tickBaseline, null, defaultProps.tickBaseline));
                text.attr("transform", `rotate(${angle}, ${tickX}, ${tickY})`);
                //Tick text style
                text.attr("fill", context.value(props.tickColor, null, context.theme.axesTickColor));
                text.style("font-weight", "bold"); //Default font-weight
                text.style("font-size", context.value(props.tickSize, null, defaultProps.tickSize));
                text.style("opacity", context.value(props.tickOpacity, null, defaultProps.tickOpacity));
            });
        }
        //Display the axis edge
        //if (context.value(props.line, null, defaultProps.line) === true) {
        if (hasAxisLine === true) {
            let line = target.append("path");
            line.attr("fill", "none"); //Prevent errors
            line.attr("stroke", context.value(props.lineColor, null, context.theme.axesLineColor));
            line.attr("stroke-width", context.value(props.lineWidth, null, defaultProps.lineWidth));
            line.style("opacity", context.value(props.lineOpacity, null, defaultProps.lineOpacity));
            line.attr("d", polyline({
                "points": [
                    [axisPosition.x1, axisPosition.y1],
                    [axisPosition.x2, axisPosition.y2]
                ],
                "closed": false
            }));
        }
    });
    //Done drawing the axis
    //return target;
}

<commit_msg>render: renamed tickPadding property as tickOffset<commit_after>import {colors} from "../color.js";
import {polyline} from "./primitives/polyline.js";
import {isArray, isObject} from "../util.js";
import {isContinuousScale, isDiscreteScale} from "../scales/index.js";
import {getExpressionSources} from "../runtime/expression.js";
import {getValueSources} from "../runtime/value.js";
import {createHashMap} from "../hashmap.js";
import {ticks as generateTicks} from "../math.js";

import {getPanelsElements} from "./panels.js";

//Available orientation values
let orientationValues = ["top", "bottom", "left", "right"];

//Axis default props
let defaultProps = {
    "line": true,
    "lineColor": "black",
    "lineWidth": "1px",
    "lineOpacity": 1,
    //Labels default attributes
    "label": true,
    "labelColor": "black",
    "labelSize": "11px",
    "labelOpacity": 0.8,
    "labelPadding": 5,
    "labelRotation": 0,
    "labelBaseline": "middle", //hanging|middle|baseline
    "labelAnchor": "middle",   //start|middle|center
    //Default ticks attributes
    "ticks": false,
    "tickCount": 0,
    "tickValues": [],
    "tickColor": "black",
    "tickSize": "11px",
    "tickOpacity": 0.8,
    "tickOffset": 5,
    "tickRotation": 0,
    "tickFormat": null,
    "tickBaseline": "middle",   //hanging|middle|baseline
    "tickAnchor": "middle",     //start|middle|end
    "slot": true,    //Display a line indication the tick position
    "slotColor": "black",
    "slotOpacity": 1,
    "slotWidth": "1px",
    //Default grid attributes
    "grid": false,
    "gridColor": "black",
    "gridOpacity": 1,
    "gridWidth": "1px"
};

//Interpolate scale values
let generateValues = function (scale, count) {
    //Check for continuous scale
    if (isContinuousScale(scale) === true) {
        //Get the range values
        let start = Math.min.apply(null, scale.domain); //Get start value
        let end = Math.max.apply(null, scale.domain); //Get end value
        //Return ticks values
        return generateTicks(start, end, count);
    }
    //Check for discrete scale
    else if (isDiscreteScale(scale) === true) {
        return scale.domain;
    }
    //Other scale type: error and return an empty values array
    //TODO
    return [];
};

//Get the display value
//let getDisplayValue = function (context, props, value) {
//    if (typeof props.tickFormat === "string") {
//        return context.expression(props.tickFormat.expr, {
//            "value": value
//        });
//    }
//    //Return the default value
//    return value;
//};

//Get orientation
let getOrientation = function (value) {
    return value.toLowerCase();
};

//Create an axis node
export function createAxisNode (context, index, props) {
    let node = context.addNode({
        "id": `axis:${index}`,
        "props": props, //Object.assign({}, defaultProps, props),
        "type": "axis",
        "targets": null, //createNodeList(),
        "parent": []
    });
    //Add sources fo this axis
    context.panels.targets.add(node.id, node); //Always ad the panels node
    if (typeof node.props.scale === "string") {
        context.scales[node.props.scale].targets.add(node.id, node);
    }
    //Axis position can be extracted from sources
    getValueSources(context, node.props.position).forEach(function (source) {
        source.targets.add(node.id, node);
    });
    //Check if tickformat is a string --> evaluate as an expression
    if (typeof node.props.tickFormat === "strong") {
        getExpressionSources(context, node.props.tickFormat).forEach(function (source) {
            source.targets.add(node.id, node);
        });
    }
    //Render this axis
    //return updateAxis(context, node);
}

//Export axis drawing
export function updateAxisNode (context, node) {
    //let target = node.parent; //parent.append("g");
    let props = node.props; //Object.assign({}, defaultProps, node.props);
    let draw = context.panels.value; //context.draw.computed;
    let scale = context.scales[props.scale].value;
    //Axis positions and size
    let axisSize = Math.abs(scale.range[1] - scale.range[0]); //Axis size
    //let axisStart = scale.range[0];
    //let axisEnd = scale.range[1];
    //Axis position
    let position = context.value(props.position, 0, 0); //defaultProps.position);
    //Get the axis type
    let orientation = getOrientation(props.orientation);
    let hasAxisLine = context.value(props.line, null, defaultProps.line); //Display axis line
    let isXAxis = orientation === "top" || orientation === "bottom";
    let hasAxisTicks = context.value(props.ticks, null, defaultProps.ticks); //Display ticks
    let hasAxisGrid = context.value(props.grid, null, defaultProps.grid); //Display axis grid
    let ticksValues = []; //Values to display
    if (hasAxisTicks === true) {
        if (isArray(props.tickValues) === true) {
            ticksValues = context.value(props.tickValues, [], []); //Get values from context
        }
        else {
            //Generate values from counts
            ticksValues = generateValues(scale, context.value(props.tickCount, 0, defaultProps.tickCount));
        }
    }
    //Get panels where this axis will be rendered
    getPanelsElements(context, props.panel).forEach(function (element, index) {
        //Check if there is a group for this axis
        let target = element.selectAll(`g[data-axis='${node.id}']`);
        if (target.length === 0) {
            target = element.append("g").attr("data-axis", node.id); //Create a new axis
        }
        //Remove old children
        target.empty();
        //Calculate the axis positions
        let axisPosition = {};
        //Check for top|bottom axis
        if (isXAxis === true) {
            axisPosition = {
                "x1": position + Math.min(scale.range[0], scale.range[1]),
                "x2": position + Math.max(scale.range[0], scale.range[1]),
                "y1": (orientation === "top") ? 0 : draw.height,
                "y2": (orientation === "top") ? 0 : draw.height
            };
        }
        else {
            axisPosition = {
                "x1": (orientation === "left") ? 0 : draw.width,
                "x2": (orientation === "left") ? 0 : draw.width,
                "y1": position + Math.min(scale.range[0], scale.range[1]),
                "y2": position + Math.max(scale.range[0], scale.range[1])
            };
        }
        //console.log(axisPosition);
        //Display ticks
        //if (props.ticks === true) { // && (typeof props.tickCount === "number" || viz.isArray(props.tickValues))) {
        if (context.value(props.ticks, null, defaultProps.ticks) === true) {
            let angle = context.value(props.tickRotation, null, defaultProps.tickRotation); //Get rotation angle
            let tickOffset = context.value(props.tickOffset, 0, defaultProps.tickOffset); //Get ticks offset
            let tickSlot = context.value(props.slot, null, defaultProps.slot); //Display tick slot
            //Display each label value
            ticksValues.forEach(function (value, index) {
                //Calculate the label positions
                let valuePosition = scale(value, index);
                //console.log(value + " --> " + valuePosition);
                //Check for null value --> not valid label
                if (valuePosition === null || typeof valuePosition === "undefined") {
                    return false;
                }
                //Check for interval scale
                if (scale.type === "interval") {//if (typeof props.scale.step === "number") {
                    valuePosition = valuePosition + scale.step / 2;
                }
                //let labelX = (isXAxis) ? position : props.x - props.labelMargin;
                //let labelY = (props.type === "y") ? position : props.y + props.labelMargin;
                let tickX = 0, tickY = 0; //, tickAnchor = "middle", tickBaseline = "middle";
                let slotLine = null;
                let gridLine = null;
                //let labelAnchor = (props.orientation === "left") ? "end" : "start";
                //Calculate the label positions
                if (orientation === "left" || orientation === "right") {
                    tickX = axisPosition.x1 + (((orientation === "left") ? -1 : +1) * tickOffset);
                    tickY = valuePosition + position; //props.y + props.height - position;
                    //Check for displaying the tick slot
                    if (tickSlot === true && hasAxisLine === true) {
                        let px2 = axisPosition.x1 + (((orientation === "left") ? -1 : +1) * tickOffset / 3);
                        slotLine = target.append("path");
                        slotLine.attr("d", polyline({
                            "points": [
                                [axisPosition.x1, tickY],
                                [px2, tickY]
                            ],
                            "closed": false
                        }));
                    }
                    //Check for displaying the grid line
                    if (hasAxisGrid === true) {
                        gridLine = target.append("path");
                        gridLine.attr("d", polyline({
                            "points": [[0, tickY], [draw.width, tickY]],
                            "closed": false
                        }));
                    }
                }
                else {
                    tickX = valuePosition + position;
                    tickY = axisPosition.y1 + (((orientation === "top") ? -1 : +1) * tickOffset);
                    //Check for displaying the tick slot
                    //if (props.tickSlot === true && props.line === true) {
                    if (tickSlot === true && hasAxisLine === true) {
                        let py2 = axisPosition.y1 + (((orientation === "top") ? -1 : +1) * tickOffset / 3);
                        slotLine = target.append("path");
                        slotLine.attr("d", polyline({
                            "points": [
                                [tickX, axisPosition.y1],
                                [tickX, py2]
                            ],
                            "closed": false
                        }));
                    }
                    //Check for displaying the grid line
                    if (hasAxisGrid === true) {
                        gridLine = target.append("path");
                        gridLine.attr("d", polyline({
                            "points": [[tickX, 0], [tickX, draw.height]],
                            "closed": false
                        }));
                    }
                }
                //Check for slot line --> set slot style
                if (slotLine !== null) {
                    slotLine.attr("fill", "none");
                    slotLine.attr("stroke-width", context.value(props.slotWidth, null, defaultProps.slotWidth)); //Default slot width
                    slotLine.attr("stroke", context.value(props.slotColor, null, context.theme.axesSlotColor));
                    slotLine.style("opacity", context.value(props.slotOpacity, 0, defaultProps.slotOpacity));
                }
                //Check for grid line --> set grid line
                if (gridLine !== null) {
                    gridLine.attr("fill", "none");
                    gridLine.attr("stroke-width", context.value(props.gridWidth, null, defaultProps.gridWidth));
                    gridLine.attr("stroke", context.value(props.gridColor, null, context.theme.axesGridColor));
                    gridLine.style("opacity", context.value(props.gridOpacity, 0, defaultProps.gridOpacity));
                }
                //Display the text element
                let text = target.append("text");
                text.text(context.value(props.tickFormat, value, value));
                text.attr("x", tickX);
                text.attr("y", tickY);
                text.attr("text-anchor", context.value(props.tickAnchor, null, defaultProps.tickAnchor));
                text.attr("alignment-baseline", context.value(props.tickBaseline, null, defaultProps.tickBaseline));
                text.attr("transform", `rotate(${angle}, ${tickX}, ${tickY})`);
                //Tick text style
                text.attr("fill", context.value(props.tickColor, null, context.theme.axesTickColor));
                text.style("font-weight", "bold"); //Default font-weight
                text.style("font-size", context.value(props.tickSize, null, defaultProps.tickSize));
                text.style("opacity", context.value(props.tickOpacity, null, defaultProps.tickOpacity));
            });
        }
        //Display the axis edge
        //if (context.value(props.line, null, defaultProps.line) === true) {
        if (hasAxisLine === true) {
            let line = target.append("path");
            line.attr("fill", "none"); //Prevent errors
            line.attr("stroke", context.value(props.lineColor, null, context.theme.axesLineColor));
            line.attr("stroke-width", context.value(props.lineWidth, null, defaultProps.lineWidth));
            line.style("opacity", context.value(props.lineOpacity, null, defaultProps.lineOpacity));
            line.attr("d", polyline({
                "points": [
                    [axisPosition.x1, axisPosition.y1],
                    [axisPosition.x2, axisPosition.y2]
                ],
                "closed": false
            }));
        }
    });
    //Done drawing the axis
    //return target;
}

<|endoftext|>


<commit_before>import React, {Component, memo} from 'react';
import PropTypes from 'prop-types';
import Registry from './registry';
import {propTypeErrorHandler} from './exceptions';
import {
    addIndex,
    assoc,
    assocPath,
    concat,
    dissoc,
    equals,
    isEmpty,
    isNil,
    has,
    keys,
    map,
    mergeRight,
    pick,
    pickBy,
    pipe,
    propOr,
    path as rpath,
    type
} from 'ramda';
import {notifyObservers, updateProps} from './actions';
import isSimpleComponent from './isSimpleComponent';
import {recordUiEdit} from './persistence';
import ComponentErrorBoundary from './components/error/ComponentErrorBoundary.react';
import checkPropTypes from './checkPropTypes';
import {getWatchedKeys, stringifyId} from './actions/dependencies';
import {
    getLoadingHash,
    getLoadingState,
    validateComponent
} from './utils/TreeContainer';
import {DashContext} from './APIController.react';

const NOT_LOADING = {
    is_loading: false
};

function CheckedComponent(p) {
    const {element, extraProps, props, children, type} = p;

    const errorMessage = checkPropTypes(
        element.propTypes,
        props,
        'component prop',
        element
    );
    if (errorMessage) {
        propTypeErrorHandler(errorMessage, props, type);
    }

    return createElement(element, props, extraProps, children);
}

CheckedComponent.propTypes = {
    children: PropTypes.any,
    element: PropTypes.any,
    layout: PropTypes.any,
    props: PropTypes.any,
    extraProps: PropTypes.any,
    id: PropTypes.string
};

function createElement(element, props, extraProps, children) {
    const allProps = mergeRight(props, extraProps);
    if (Array.isArray(children)) {
        return React.createElement(element, allProps, ...children);
    }
    return React.createElement(element, allProps, children);
}

function isDryComponent(obj) {
    return (
        type(obj) === 'Object' &&
        has('type', obj) &&
        has('namespace', obj) &&
        has('props', obj)
    );
}

const TreeContainer = memo(props => (
    <DashContext.Consumer>
        {context => (
            <BaseTreeContainer
                {...context.fn()}
                {...props}
                _dashprivate_path={JSON.parse(props._dashprivate_path)}
            />
        )}
    </DashContext.Consumer>
));

class BaseTreeContainer extends Component {
    constructor(props) {
        super(props);

        this.setProps = this.setProps.bind(this);
    }

    createContainer(props, component, path) {
        return isSimpleComponent(component) ? (
            component
        ) : (
            <TreeContainer
                key={
                    component &&
                    component.props &&
                    stringifyId(component.props.id)
                }
                _dashprivate_error={props._dashprivate_error}
                _dashprivate_layout={component}
                _dashprivate_loadingState={getLoadingState(
                    component,
                    path,
                    props._dashprivate_loadingMap
                )}
                _dashprivate_loadingStateHash={getLoadingHash(
                    path,
                    props._dashprivate_loadingMap
                )}
                _dashprivate_path={JSON.stringify(path)}
            />
        );
    }

    setProps(newProps) {
        const {
            _dashprivate_graphs,
            _dashprivate_dispatch,
            _dashprivate_path,
            _dashprivate_layout
        } = this.props;

        const oldProps = this.getLayoutProps();
        const {id} = oldProps;
        const changedProps = pickBy(
            (val, key) => !equals(val, oldProps[key]),
            newProps
        );
        if (!isEmpty(changedProps)) {
            // Identify the modified props that are required for callbacks
            const watchedKeys = getWatchedKeys(
                id,
                keys(changedProps),
                _dashprivate_graphs
            );

            // setProps here is triggered by the UI - record these changes
            // for persistence
            recordUiEdit(_dashprivate_layout, newProps, _dashprivate_dispatch);

            // Only dispatch changes to Dash if a watched prop changed
            if (watchedKeys.length) {
                _dashprivate_dispatch(
                    notifyObservers({
                        id,
                        props: pick(watchedKeys, changedProps)
                    })
                );
            }

            // Always update this component's props
            _dashprivate_dispatch(
                updateProps({
                    props: changedProps,
                    itempath: _dashprivate_path
                })
            );
        }
    }

    getChildren(components, path) {
        if (isNil(components)) {
            return null;
        }

        return Array.isArray(components)
            ? addIndex(map)(
                  (component, i) =>
                      this.createContainer(
                          this.props,
                          component,
                          concat(path, ['props', 'children', i])
                      ),
                  components
              )
            : this.createContainer(
                  this.props,
                  components,
                  concat(path, ['props', 'children'])
              );
    }

    getComponent(_dashprivate_layout, children, loading_state, setProps) {
        const {_dashprivate_config, _dashprivate_dispatch, _dashprivate_error} =
            this.props;

        if (isEmpty(_dashprivate_layout)) {
            return null;
        }

        if (isSimpleComponent(_dashprivate_layout)) {
            return _dashprivate_layout;
        }
        validateComponent(_dashprivate_layout);

        const element = Registry.resolve(_dashprivate_layout);

        // Hydrate components props
        const childrenProps = propOr([], 'childrenProps', _dashprivate_layout);
        const props = pipe(
            dissoc('children'),
            ...childrenProps
                .map(childrenProp => {
                    if (childrenProp.includes('.')) {
                        let path = childrenProp.split('.');
                        let node;
                        let nodeValue;
                        if (childrenProp.startsWith('[]')) {
                            const frontPath = path[0].slice(2);
                            node = _dashprivate_layout.props[frontPath];
                            if (node === undefined) {
                                return;
                            }
                            nodeValue = node.map((n, i) => ({
                                ...n,
                                [path[1]]: isDryComponent(n[path[1]])
                                    ? this.createContainer(
                                          this.props,
                                          n[path[1]],
                                          concat(this.props._dashprivate_path, [
                                              'props',
                                              frontPath,
                                              i,
                                              path[1]
                                          ])
                                      )
                                    : n
                            }));
                            path = [frontPath];
                        } else {
                            node = rpath(path, _dashprivate_layout.props);
                            if (node === undefined) {
                                return;
                            }
                            if (!isDryComponent(node)) {
                                return node;
                            }
                            nodeValue = this.createContainer(
                                this.props,
                                node,
                                concat(this.props._dashprivate_path, [
                                    'props',
                                    path[0],
                                    path[1]
                                ])
                            );
                        }
                        return assocPath(path, nodeValue);
                    }
                    const node = _dashprivate_layout.props[childrenProp];
                    if (node !== undefined) {
                        if (Array.isArray(node)) {
                            return assoc(
                                childrenProp,
                                node.map((n, i) =>
                                    isDryComponent(n)
                                        ? this.createContainer(
                                              this.props,
                                              n,
                                              concat(
                                                  this.props._dashprivate_path,
                                                  ['props', childrenProp, i]
                                              )
                                          )
                                        : n
                                )
                            );
                        }
                        if (!isDryComponent(node)) {
                            return node;
                        }
                        return assoc(
                            childrenProp,
                            this.createContainer(
                                this.props,
                                node,
                                concat(this.props._dashprivate_path, [
                                    'props',
                                    childrenProp
                                ])
                            )
                        );
                    }
                })
                .filter(e => e !== undefined)
        )(_dashprivate_layout.props);

        if (type(props.id) === 'Object') {
            // Turn object ids (for wildcards) into unique strings.
            // Because of the `dissoc` above we're not mutating the layout,
            // just the id we pass on to the rendered component
            props.id = stringifyId(props.id);
        }
        const extraProps = {
            loading_state: loading_state || NOT_LOADING,
            setProps
        };

        return (
            <ComponentErrorBoundary
                componentType={_dashprivate_layout.type}
                componentId={props.id}
                key={props.id}
                dispatch={_dashprivate_dispatch}
                error={_dashprivate_error}
            >
                {_dashprivate_config.props_check ? (
                    <CheckedComponent
                        children={children}
                        element={element}
                        props={props}
                        extraProps={extraProps}
                        type={_dashprivate_layout.type}
                    />
                ) : (
                    createElement(element, props, extraProps, children)
                )}
            </ComponentErrorBoundary>
        );
    }

    getLayoutProps() {
        return propOr({}, 'props', this.props._dashprivate_layout);
    }

    render() {
        const {
            _dashprivate_layout,
            _dashprivate_loadingState,
            _dashprivate_path
        } = this.props;

        const layoutProps = this.getLayoutProps();

        const children = this.getChildren(
            layoutProps.children,
            _dashprivate_path
        );

        return this.getComponent(
            _dashprivate_layout,
            children,
            _dashprivate_loadingState,
            this.setProps
        );
    }
}

TreeContainer.propTypes = {
    _dashprivate_error: PropTypes.any,
    _dashprivate_layout: PropTypes.object,
    _dashprivate_loadingState: PropTypes.oneOfType([
        PropTypes.object,
        PropTypes.bool
    ]),
    _dashprivate_loadingStateHash: PropTypes.string,
    _dashprivate_path: PropTypes.string
};

BaseTreeContainer.propTypes = {
    ...TreeContainer.propTypes,
    _dashprivate_config: PropTypes.object,
    _dashprivate_dispatch: PropTypes.func,
    _dashprivate_graphs: PropTypes.any,
    _dashprivate_loadingMap: PropTypes.any,
    _dashprivate_path: PropTypes.array
};

export default TreeContainer;
<commit_msg>Fix union rendering.<commit_after>import React, {Component, memo} from 'react';
import PropTypes from 'prop-types';
import Registry from './registry';
import {propTypeErrorHandler} from './exceptions';
import {
    addIndex,
    assoc,
    assocPath,
    concat,
    dissoc,
    equals,
    isEmpty,
    isNil,
    has,
    keys,
    map,
    mergeRight,
    pick,
    pickBy,
    pipe,
    propOr,
    path as rpath,
    type
} from 'ramda';
import {notifyObservers, updateProps} from './actions';
import isSimpleComponent from './isSimpleComponent';
import {recordUiEdit} from './persistence';
import ComponentErrorBoundary from './components/error/ComponentErrorBoundary.react';
import checkPropTypes from './checkPropTypes';
import {getWatchedKeys, stringifyId} from './actions/dependencies';
import {
    getLoadingHash,
    getLoadingState,
    validateComponent
} from './utils/TreeContainer';
import {DashContext} from './APIController.react';

const NOT_LOADING = {
    is_loading: false
};

function CheckedComponent(p) {
    const {element, extraProps, props, children, type} = p;

    const errorMessage = checkPropTypes(
        element.propTypes,
        props,
        'component prop',
        element
    );
    if (errorMessage) {
        propTypeErrorHandler(errorMessage, props, type);
    }

    return createElement(element, props, extraProps, children);
}

CheckedComponent.propTypes = {
    children: PropTypes.any,
    element: PropTypes.any,
    layout: PropTypes.any,
    props: PropTypes.any,
    extraProps: PropTypes.any,
    id: PropTypes.string
};

function createElement(element, props, extraProps, children) {
    const allProps = mergeRight(props, extraProps);
    if (Array.isArray(children)) {
        return React.createElement(element, allProps, ...children);
    }
    return React.createElement(element, allProps, children);
}

function isDryComponent(obj) {
    return (
        type(obj) === 'Object' &&
        has('type', obj) &&
        has('namespace', obj) &&
        has('props', obj)
    );
}

const TreeContainer = memo(props => (
    <DashContext.Consumer>
        {context => (
            <BaseTreeContainer
                {...context.fn()}
                {...props}
                _dashprivate_path={JSON.parse(props._dashprivate_path)}
            />
        )}
    </DashContext.Consumer>
));

class BaseTreeContainer extends Component {
    constructor(props) {
        super(props);

        this.setProps = this.setProps.bind(this);
    }

    createContainer(props, component, path) {
        return isSimpleComponent(component) ? (
            component
        ) : (
            <TreeContainer
                key={
                    component &&
                    component.props &&
                    stringifyId(component.props.id)
                }
                _dashprivate_error={props._dashprivate_error}
                _dashprivate_layout={component}
                _dashprivate_loadingState={getLoadingState(
                    component,
                    path,
                    props._dashprivate_loadingMap
                )}
                _dashprivate_loadingStateHash={getLoadingHash(
                    path,
                    props._dashprivate_loadingMap
                )}
                _dashprivate_path={JSON.stringify(path)}
            />
        );
    }

    setProps(newProps) {
        const {
            _dashprivate_graphs,
            _dashprivate_dispatch,
            _dashprivate_path,
            _dashprivate_layout
        } = this.props;

        const oldProps = this.getLayoutProps();
        const {id} = oldProps;
        const changedProps = pickBy(
            (val, key) => !equals(val, oldProps[key]),
            newProps
        );
        if (!isEmpty(changedProps)) {
            // Identify the modified props that are required for callbacks
            const watchedKeys = getWatchedKeys(
                id,
                keys(changedProps),
                _dashprivate_graphs
            );

            // setProps here is triggered by the UI - record these changes
            // for persistence
            recordUiEdit(_dashprivate_layout, newProps, _dashprivate_dispatch);

            // Only dispatch changes to Dash if a watched prop changed
            if (watchedKeys.length) {
                _dashprivate_dispatch(
                    notifyObservers({
                        id,
                        props: pick(watchedKeys, changedProps)
                    })
                );
            }

            // Always update this component's props
            _dashprivate_dispatch(
                updateProps({
                    props: changedProps,
                    itempath: _dashprivate_path
                })
            );
        }
    }

    getChildren(components, path) {
        if (isNil(components)) {
            return null;
        }

        return Array.isArray(components)
            ? addIndex(map)(
                  (component, i) =>
                      this.createContainer(
                          this.props,
                          component,
                          concat(path, ['props', 'children', i])
                      ),
                  components
              )
            : this.createContainer(
                  this.props,
                  components,
                  concat(path, ['props', 'children'])
              );
    }

    getComponent(_dashprivate_layout, children, loading_state, setProps) {
        const {_dashprivate_config, _dashprivate_dispatch, _dashprivate_error} =
            this.props;

        if (isEmpty(_dashprivate_layout)) {
            return null;
        }

        if (isSimpleComponent(_dashprivate_layout)) {
            return _dashprivate_layout;
        }
        validateComponent(_dashprivate_layout);

        const element = Registry.resolve(_dashprivate_layout);

        // Hydrate components props
        const childrenProps = propOr([], 'childrenProps', _dashprivate_layout);
        const props = pipe(
            dissoc('children'),
            ...childrenProps
                .map(childrenProp => {
                    if (childrenProp.includes('.')) {
                        let path = childrenProp.split('.');
                        let node;
                        let nodeValue;
                        if (childrenProp.startsWith('[]')) {
                            const frontPath = path[0].slice(2);
                            node = _dashprivate_layout.props[frontPath];
                            if (node === undefined) {
                                return;
                            }
                            nodeValue = node.map((n, i) => ({
                                ...n,
                                [path[1]]: isDryComponent(n[path[1]])
                                    ? this.createContainer(
                                          this.props,
                                          n[path[1]],
                                          concat(this.props._dashprivate_path, [
                                              'props',
                                              frontPath,
                                              i,
                                              path[1]
                                          ])
                                      )
                                    : n
                            }));
                            path = [frontPath];
                        } else {
                            node = rpath(path, _dashprivate_layout.props);
                            if (node === undefined) {
                                return;
                            }
                            if (!isDryComponent(node)) {
                                return assocPath(path, node);
                            }
                            nodeValue = this.createContainer(
                                this.props,
                                node,
                                concat(this.props._dashprivate_path, [
                                    'props',
                                    path[0],
                                    path[1]
                                ])
                            );
                        }
                        return assocPath(path, nodeValue);
                    }
                    const node = _dashprivate_layout.props[childrenProp];
                    if (node !== undefined) {
                        if (Array.isArray(node)) {
                            return assoc(
                                childrenProp,
                                node.map((n, i) =>
                                    isDryComponent(n)
                                        ? this.createContainer(
                                              this.props,
                                              n,
                                              concat(
                                                  this.props._dashprivate_path,
                                                  ['props', childrenProp, i]
                                              )
                                          )
                                        : n
                                )
                            );
                        }
                        if (!isDryComponent(node)) {
                            return assoc(childrenProp, node);
                        }
                        return assoc(
                            childrenProp,
                            this.createContainer(
                                this.props,
                                node,
                                concat(this.props._dashprivate_path, [
                                    'props',
                                    childrenProp
                                ])
                            )
                        );
                    }
                })
                .filter(e => e !== undefined)
        )(_dashprivate_layout.props);

        if (type(props.id) === 'Object') {
            // Turn object ids (for wildcards) into unique strings.
            // Because of the `dissoc` above we're not mutating the layout,
            // just the id we pass on to the rendered component
            props.id = stringifyId(props.id);
        }
        const extraProps = {
            loading_state: loading_state || NOT_LOADING,
            setProps
        };

        return (
            <ComponentErrorBoundary
                componentType={_dashprivate_layout.type}
                componentId={props.id}
                key={props.id}
                dispatch={_dashprivate_dispatch}
                error={_dashprivate_error}
            >
                {_dashprivate_config.props_check ? (
                    <CheckedComponent
                        children={children}
                        element={element}
                        props={props}
                        extraProps={extraProps}
                        type={_dashprivate_layout.type}
                    />
                ) : (
                    createElement(element, props, extraProps, children)
                )}
            </ComponentErrorBoundary>
        );
    }

    getLayoutProps() {
        return propOr({}, 'props', this.props._dashprivate_layout);
    }

    render() {
        const {
            _dashprivate_layout,
            _dashprivate_loadingState,
            _dashprivate_path
        } = this.props;

        const layoutProps = this.getLayoutProps();

        const children = this.getChildren(
            layoutProps.children,
            _dashprivate_path
        );

        return this.getComponent(
            _dashprivate_layout,
            children,
            _dashprivate_loadingState,
            this.setProps
        );
    }
}

TreeContainer.propTypes = {
    _dashprivate_error: PropTypes.any,
    _dashprivate_layout: PropTypes.object,
    _dashprivate_loadingState: PropTypes.oneOfType([
        PropTypes.object,
        PropTypes.bool
    ]),
    _dashprivate_loadingStateHash: PropTypes.string,
    _dashprivate_path: PropTypes.string
};

BaseTreeContainer.propTypes = {
    ...TreeContainer.propTypes,
    _dashprivate_config: PropTypes.object,
    _dashprivate_dispatch: PropTypes.func,
    _dashprivate_graphs: PropTypes.any,
    _dashprivate_loadingMap: PropTypes.any,
    _dashprivate_path: PropTypes.array
};

export default TreeContainer;
<|endoftext|>


<commit_before>/* global django */
django.jQuery(function($) {
  function updatePlaceholderHeight(ui) {
    // set placeholder height equal to item height
    ui.placeholder.height(ui.item.outerHeight());
  }

  function hideHorizontalOverflow() {
    // hide body horizontal overflow while dragging row
    $("body").css("overflow-x", "hidden");
  }

  function autoHorizontalOverflow() {
    // reset body horizontal overflow
    $("body").css("overflow-x", "auto");
  }

  function enforceSortableRowsCellsSize(node) {
    // enforce row cells size while sorting rows
    node.find(">tr").each(function() {
      $(this)
        .mousedown(function() {
          $(this)
            .find("td, th")
            .each(function() {
              $(this).css("width", $(this).width());
            });
        })
        .mouseup(function() {
          $(this)
            .find("td, th")
            .each(function() {
              $(this).css("width", "auto");
            });
        });
    });
  }

  $(".admin-ordering-context:not(.activated)")
    .addClass("activated")
    .each(function() {
      var $sortable,
        $sortableHandle,
        $sortableInputWrapper =
          '';

      var data = JSON.parse(this.getAttribute("data-context"));
      var inputFieldSelector = 'input[name$="-' + data.field + '"]';

      function updateOrdering(nodes) {
        var incOrdering = 10;
        var maxOrdering = nodes.length * incOrdering;
        nodes.each(function(index) {
          var row = $(this);
          var rowOrdering = data.fieldDesc
            ? maxOrdering - incOrdering * index
            : incOrdering * (index + 1);
          row.find(inputFieldSelector).val(rowOrdering);
          row.removeClass("row1 row2").addClass(index % 2 ? "row2" : "row1");
        });
      }

      if (data.field.startsWith("-")) {
        data.field = data.field.substring(1);
        data.fieldDesc = true;
      } else {
        data.fieldDesc = false;
      }

      if (data.tabular) {
        $sortable = $("#" + data.prefix + "-group tbody");
        $sortableHandle = $sortable.find(".field-" + data.field);
        $sortableHandle.addClass("admin-ordering-field");
        if (data.fieldHideInput) {
          $sortableHandle.addClass("admin-ordering-field-hide-input");
        }
        $sortableHandle
          .find(inputFieldSelector + ':not([type="hidden"])')
          .wrap($sortableInputWrapper);
        $sortable.sortable({
          items: ">.has_original",
          handle: $sortableHandle,
          start: function(_event, ui) {
            hideHorizontalOverflow();
            updatePlaceholderHeight(ui);
            // fix ui item height
            ui.item.css("height", ui.item.outerHeight());
          },
          update: function(_event, _ui) {
            updateOrdering($(".dynamic-" + data.prefix));
          },
          stop: function(_event, ui) {
            autoHorizontalOverflow();
            // reset ui item height
            ui.item.css("height", "auto");
          }
        });

        enforceSortableRowsCellsSize($sortable);
      } else if (data.stacked) {
        $sortable = $("#" + data.prefix + "-group");
        $sortableHandle = $sortable.find(".field-" + data.field);
        $sortableHandle.addClass("admin-ordering-field");
        if (data.fieldHideInput) {
          $sortableHandle.addClass("admin-ordering-field-hide-input");
        }
        $sortableHandle
          .find(inputFieldSelector + ':not([type="hidden"])')
          .wrap($sortableInputWrapper);
        $sortable.sortable({
          items: ">.has_original,>>.has_original",
          handle: $sortableHandle,
          start: function(_event, ui) {
            hideHorizontalOverflow();
            updatePlaceholderHeight(ui);
          },
          update: function(_event, _ui) {
            updateOrdering($(".dynamic-" + data.prefix));
          },
          stop: function(_event, _ui) {
            autoHorizontalOverflow();
          }
        });
      } else {
        $sortable = $("#result_list tbody");
        $sortableHandle = $sortable.find(".field-" + data.field);
        $sortableHandle.addClass("admin-ordering-field");
        if (data.fieldHideInput) {
          $sortableHandle.addClass("admin-ordering-field-hide-input");
        }
        if (!$sortableHandle.find("input").length) {
          return;
        }
        $sortableHandle
          .find(inputFieldSelector + ':not([type="hidden"])')
          .wrap($sortableInputWrapper);
        $sortable.sortable({
          handle: $sortableHandle,
          start: function(_event, ui) {
            hideHorizontalOverflow();
            updatePlaceholderHeight(ui);
          },
          update: function(_event, _ui) {
            updateOrdering($sortable.find("tr"));
          },
          stop: function(_event, _ui) {
            autoHorizontalOverflow();
          }
        });

        enforceSortableRowsCellsSize($sortable);
      }

      if (data.tabular || data.stacked) {
        // Yay, Django 1.9 or better!
        $(document).on("formset:added", function newForm(event, row) {
          if (row.hasClass("dynamic-" + data.prefix)) {
            updateOrdering($(".dynamic-" + data.prefix));
          }
        });
      }
    });
});
<commit_msg>Replace startsWith with indexOf == 0 to support IE<commit_after>/* global django */
django.jQuery(function($) {
  function updatePlaceholderHeight(ui) {
    // set placeholder height equal to item height
    ui.placeholder.height(ui.item.outerHeight());
  }

  function hideHorizontalOverflow() {
    // hide body horizontal overflow while dragging row
    $("body").css("overflow-x", "hidden");
  }

  function autoHorizontalOverflow() {
    // reset body horizontal overflow
    $("body").css("overflow-x", "auto");
  }

  function enforceSortableRowsCellsSize(node) {
    // enforce row cells size while sorting rows
    node.find(">tr").each(function() {
      $(this)
        .mousedown(function() {
          $(this)
            .find("td, th")
            .each(function() {
              $(this).css("width", $(this).width());
            });
        })
        .mouseup(function() {
          $(this)
            .find("td, th")
            .each(function() {
              $(this).css("width", "auto");
            });
        });
    });
  }

  $(".admin-ordering-context:not(.activated)")
    .addClass("activated")
    .each(function() {
      var $sortable,
        $sortableHandle,
        $sortableInputWrapper =
          '';

      var data = JSON.parse(this.getAttribute("data-context"));
      var inputFieldSelector = 'input[name$="-' + data.field + '"]';

      function updateOrdering(nodes) {
        var incOrdering = 10;
        var maxOrdering = nodes.length * incOrdering;
        nodes.each(function(index) {
          var row = $(this);
          var rowOrdering = data.fieldDesc
            ? maxOrdering - incOrdering * index
            : incOrdering * (index + 1);
          row.find(inputFieldSelector).val(rowOrdering);
          row.removeClass("row1 row2").addClass(index % 2 ? "row2" : "row1");
        });
      }

      if (data.field.indexOf("-") == 0) {
        data.field = data.field.substring(1);
        data.fieldDesc = true;
      } else {
        data.fieldDesc = false;
      }

      if (data.tabular) {
        $sortable = $("#" + data.prefix + "-group tbody");
        $sortableHandle = $sortable.find(".field-" + data.field);
        $sortableHandle.addClass("admin-ordering-field");
        if (data.fieldHideInput) {
          $sortableHandle.addClass("admin-ordering-field-hide-input");
        }
        $sortableHandle
          .find(inputFieldSelector + ':not([type="hidden"])')
          .wrap($sortableInputWrapper);
        $sortable.sortable({
          items: ">.has_original",
          handle: $sortableHandle,
          start: function(_event, ui) {
            hideHorizontalOverflow();
            updatePlaceholderHeight(ui);
            // fix ui item height
            ui.item.css("height", ui.item.outerHeight());
          },
          update: function(_event, _ui) {
            updateOrdering($(".dynamic-" + data.prefix));
          },
          stop: function(_event, ui) {
            autoHorizontalOverflow();
            // reset ui item height
            ui.item.css("height", "auto");
          }
        });

        enforceSortableRowsCellsSize($sortable);
      } else if (data.stacked) {
        $sortable = $("#" + data.prefix + "-group");
        $sortableHandle = $sortable.find(".field-" + data.field);
        $sortableHandle.addClass("admin-ordering-field");
        if (data.fieldHideInput) {
          $sortableHandle.addClass("admin-ordering-field-hide-input");
        }
        $sortableHandle
          .find(inputFieldSelector + ':not([type="hidden"])')
          .wrap($sortableInputWrapper);
        $sortable.sortable({
          items: ">.has_original,>>.has_original",
          handle: $sortableHandle,
          start: function(_event, ui) {
            hideHorizontalOverflow();
            updatePlaceholderHeight(ui);
          },
          update: function(_event, _ui) {
            updateOrdering($(".dynamic-" + data.prefix));
          },
          stop: function(_event, _ui) {
            autoHorizontalOverflow();
          }
        });
      } else {
        $sortable = $("#result_list tbody");
        $sortableHandle = $sortable.find(".field-" + data.field);
        $sortableHandle.addClass("admin-ordering-field");
        if (data.fieldHideInput) {
          $sortableHandle.addClass("admin-ordering-field-hide-input");
        }
        if (!$sortableHandle.find("input").length) {
          return;
        }
        $sortableHandle
          .find(inputFieldSelector + ':not([type="hidden"])')
          .wrap($sortableInputWrapper);
        $sortable.sortable({
          handle: $sortableHandle,
          start: function(_event, ui) {
            hideHorizontalOverflow();
            updatePlaceholderHeight(ui);
          },
          update: function(_event, _ui) {
            updateOrdering($sortable.find("tr"));
          },
          stop: function(_event, _ui) {
            autoHorizontalOverflow();
          }
        });

        enforceSortableRowsCellsSize($sortable);
      }

      if (data.tabular || data.stacked) {
        // Yay, Django 1.9 or better!
        $(document).on("formset:added", function newForm(event, row) {
          if (row.hasClass("dynamic-" + data.prefix)) {
            updateOrdering($(".dynamic-" + data.prefix));
          }
        });
      }
    });
});
<|endoftext|>


<commit_before>var lizAtlas = function() {

    lizMap.events.on({
        'uicreated':function(evt){

        if( !('atlasEnabled' in lizMap.config.options) )
            return;
        if( lizMap.config.options['atlasEnabled'] != 'True')
            return;

        var getLayerConfig = lizMap.getLayerConfigById( lizMap.config.options['atlasLayer'] );
        if ( !getLayerConfig )
            return;
        var layerConfig = getLayerConfig[1];
        var featureType = getLayerConfig[0];
        var primaryKey = lizMap.config.options['atlasPrimaryKey'] != '' ? lizMap.config.options['atlasPrimaryKey'] : null;
        if(!primaryKey)
            return;
        var titleField = lizMap.config.options['atlasFeatureLabel'] != '' ? lizMap.config.options['atlasFeatureLabel'] : null;
        if(!titleField)
            return;
        var sortField = lizMap.config.options['atlasSortField'] != '' ? lizMap.config.options['atlasSortField'] : titleField;

        var lizAtlasConfig = {
            'layername': featureType,
            'showAtStartup': lizMap.config.options['atlasShowAtStartup'] == 'True' ? true : false,
            'displayLayerDescription': lizMap.config.options['atlasDisplayLayerDescription'] == 'True' ? true : false,
            'primaryKey': primaryKey,
            'titleField': titleField,
            'sortField': sortField,
            'duration': lizMap.config.options['atlasDuration'],
            'autoPlay': lizMap.config.options['atlasAutoPlay'] == 'True' ? true : false,
            'maxWidth': lizMap.config.options['atlasMaxWidth'] +'%',
            'drawFeatureGeom': lizMap.config.options['atlasHighlightGeometry'] == 'True' ? true : false,
            'atlasDisplayPopup': lizMap.config.options['atlasDisplayPopup'] == 'True' ? true : false,
            'triggerFilter': lizMap.config.options['atlasTriggerFilter'] == 'True' ? true : false,
            'zoom': lizMap.config.options['atlasZoom'] == '' ? false : lizMap.config.options['atlasZoom']
        };
        var lizAtlasTimer;

        function getAtlasData(featureType) {

            // Get data
            lizMap.getAttributeFeatureData(featureType, null, null, 'geom', function(aName, aFilter, aFeatures, aAliases){
                if( aFeatures.length != 0 ) {
                    lizAtlasConfig['features'] = aFeatures;
                    lizAtlasConfig['featureType'] = featureType;
                    prepareFeatures();
                    launchAtlas();
                }
                $('body').css('cursor', 'auto');
                return false;
            });
        }

        function prepareFeatures(){

            // Get and order features
            lizAtlasConfig['features_with_pkey'] = {};
            var items = [];
            var pkey_field = lizAtlasConfig['primaryKey'];
            var s_field = lizAtlasConfig['sortField'];
            for(var i in lizAtlasConfig.features){

                // Get feature
                var feat = lizAtlasConfig.features[i];
                var fid = feat.id.split('.').pop();
                var pk_val = feat.properties[pkey_field];

                // Add feature in dictionary for further ref
                lizAtlasConfig['features_with_pkey'][pk_val] = feat;

                // Add feature to sorted oject
                items.push(feat.properties);
            }

            items.sort(function(a, b) {
                var nameA = a[s_field];
                var nameB = b[s_field];
                if( typeof(a[s_field]) == 'string' || typeof(b[s_field]) == 'string' ){
                    nameA = a[s_field].toUpperCase(); // ignore upper and lowercase
                    nameB = b[s_field].toUpperCase(); // ignore upper and lowercase
                }
                if (nameA < nameB) {
                    return -1;
                }
                if (nameA > nameB) {
                    return 1;
                }

                // names must be equal
                return 0;
            });

            lizAtlasConfig['features_sorted'] = items;
            //console.log(lizAtlasConfig['features_with_pkey']);
        }

        function getAtlasHome(){

            var home = '';
            // Add description

            if( lizAtlasConfig['displayLayerDescription'] ){
                var labstract = lizMap.config.layers[lizAtlasConfig.layername]['abstract'];
                if(labstract != ''){
                    home+= '
' + lizMap.config.layers[lizAtlasConfig.layername]['abstract'] + '
';
                }
            }

            // Add combobox with all data
            home+= '
';
            home+= '<select id="liz-atlas-select">';
            home+= '<option value="-1"> --- </option>';
            var pkey_field = lizAtlasConfig['primaryKey'];
            for(var i in lizAtlasConfig['features_sorted']){
                var item = lizAtlasConfig['features_sorted'][i];

                // Add option
                home+= '<option value="'+i+'">';
                home+= item[lizAtlasConfig['titleField']];
                home+= '</option>';
            }
            home+= '</select>';
            home+= '
';
            home+= '<button class="btn btn-mini btn-primary liz-atlas-item" value="-1">'+lizDict['atlas.toolbar.prev']+'</button>';
            home+= ' ';
            home+= '<button class="btn btn-mini btn-primary liz-atlas-item" value="1">'+lizDict['atlas.toolbar.next']+'</button>';
            home+= ' ';
            home+= '<button class="btn btn-mini btn-wanrning liz-atlas-run" value="1">'+lizDict['atlas.toolbar.play']+'</button>';
            home+= ' ';
            home+= '';
            home+= '';
            home+= '
';
            home+= '
';
            home+= '
';
            home+= '
';

            lizAtlasConfig.home = home;
            return home;
        }

        function launchAtlas(){
            lizMap.events.triggerEvent("uiatlascreationlaunched", lizAtlasConfig);
            // Get Atlas home
            var home = getAtlasHome(lizAtlasConfig.featureType, lizAtlasConfig.features);

            // Add dock
            lizMap.addDock(
                'atlas',
                lizDict['atlas.toolbar.title'],
                'right-dock',
                home,
                'icon-globe'
            );
            var title = '
';
            title+= '';
            title+= lizMap.config.layers[lizAtlasConfig.layername]['title'];
            title+= '
';
            $('#atlas').prepend(title);

            // Add events
            activateAtlasTrigger();

            // Limit dock size
            adaptAtlasSize();

            // Show dock
            if( lizAtlasConfig['showAtStartup'] && !lizMap.checkMobile() ){
                $('#mapmenu li.atlas:not(.active) a').click();
                // Hide legend
                $('#mapmenu li.switcher.active a').click();
            }

            // Start animation
            if( lizAtlasConfig['autoPlay'] && !lizMap.checkMobile() ){
                $('button.liz-atlas-run').click();
            }

            lizMap.events.triggerEvent("uiatlascreated", lizAtlasConfig);

        }

        function adaptAtlasSize(){
            lizMap.events.on({
            // Adapt dock size to display metadata
            rightdockopened: function(e) {
                if ( e.id == 'atlas') {
                    // Size : add class to content to enabled specific css to be applied
                    $('#content').addClass('atlas-visible');
                    lizMap.updateContentSize();

                }
            },
            rightdockclosed: function(e) {
                if ( e.id == 'atlas' ) {

                    // Set right-dock default size by removing #content class
                    $('#content').removeClass('atlas-visible');
                    lizMap.updateContentSize();

                    // Deactivate atlas and stop animation
                    deactivateAtlas();

                }
            }
            });

        }

        function activateAtlasTrigger(){
            $('#liz-atlas-select')
            .change( function(){
                var i = $(this).val();
                var len = lizAtlasConfig['features_sorted'].length;

                if( i == -1 ){
                    deactivateAtlas();
                    return false;
                }
                if( i && i>= 0 && i < len ){
                    var item = lizAtlasConfig['features_sorted'][i];

                    var pkey_field = lizAtlasConfig['primaryKey'];

                    if(item[pkey_field] in lizAtlasConfig['features_with_pkey'] ){
                        var feature = lizAtlasConfig['features_with_pkey'][item[pkey_field]];
                        runAtlasItem( feature );

                    }else{
                        console.log("no feature found");
                    }

                }
                return false;

            });

            $('#atlas div.menu-content')
            .on('click', 'button.liz-atlas-item', function(){
                var a = parseInt($(this).val());
                var curval = parseInt($('#liz-atlas-select').val());
                var nextval = a + curval;
                var len = lizAtlasConfig['features_sorted'].length;
                if(nextval >= len)
                    nextval = 0;
                if( nextval >= 0 && nextval < len){
                    $('#liz-atlas-select').val(nextval).change();
                }
                return false;
            });

            // Timer
            $('#atlas div.menu-content button.liz-atlas-run').click(function(){
                // Get button value
                var a = $(this).val();

                // Get animation duration
                var duration = lizAtlasConfig.duration;
                if( !(parseInt(duration) > 0) )
                    duration = 5;
                var step = parseInt(duration) * 1000;
                if(step < 2 || step > 60000){
                    step = 5000;
                }

                // Run or stop animation
                if( a == '1' ){
                    // Click on the next button
                    $('button.liz-atlas-item[value="1"]').click();

                    // Change the run button value into 0
                    $(this).val(0);

                    // Change button look
                    $(this).text(lizDict['atlas.toolbar.stop']).addClass('btn-danger');

                    // Run timer
                    lizAtlasTimer = setInterval(function(){
                        // Click on then next button for each step
                        $('button.liz-atlas-item[value="1"]').click();
                    }, step);
                }else{
                    deactivateAtlas();
                }
            });
        }

        function runAtlasItem(feature){

            // Use OL tools to reproject feature geometry
            var format = new OpenLayers.Format.GeoJSON();
            var feat = format.read(feature)[0];
            var f = feat.clone();
            var proj = lizMap.config.layers[lizAtlasConfig.layername]['featureCrs'];
            f.geometry.transform(proj, lizMap.map.getProjection());

            // Zoom to feature
            if( lizAtlasConfig['zoom']){
                if( lizAtlasConfig['zoom'].toLowerCase() == 'center' ){
                    // center
                    var lonlat = f.geometry.getBounds().getCenterLonLat();
                    lizMap.map.setCenter(lonlat);
                }
                else{
                    // zoom
                    lizMap.map.zoomToExtent(f.geometry.getBounds());
                }
            }

            // Draw feature geometry
            var getLayer = lizMap.map.getLayersByName('locatelayer');
            if ( lizAtlasConfig.drawFeatureGeom && getLayer.length > 0 ){
                alayer = getLayer[0];
                alayer.destroyFeatures();
                alayer.addFeatures([f]);
            }

            // Display popup
            if( lizAtlasConfig['atlasDisplayPopup'] ){
                lizMap.getFeaturePopupContent(lizAtlasConfig.featureType, feature, function(data){
                    // Add class to table
                    var popupReg = new RegExp('lizmapPopupTable', 'g');
                    text = data.replace( popupReg, 'table table-condensed lizmapPopupTable');
                    var text = '
'+text+'
';
                    // Remove
 with layer title
                    var titleReg = new RegExp('
.+
');
                    text = text.replace(titleReg, '');
                    $('#liz-atlas-item-detail').html(text).show();

                    // Trigger event ? a bit buggy
                    lizMap.events.triggerEvent("lizmappopupdisplayed", {'popup': null} );

                    // Add children
                    lizMap.addChildrenFeatureInfo(data);

                });
            }

            // Trigger Filter
            if( lizAtlasConfig['triggerFilter'] ){

                var fid = feature.id.split('.').pop();

                // Select feature
                lizMap.events.triggerEvent('layerfeatureselected',
                    {'featureType': lizAtlasConfig.featureType, 'fid': fid, 'updateDrawing': false}
                );
                // Filter selected feature
                lizMap.events.triggerEvent('layerfeaturefilterselected',
                    {'featureType': lizAtlasConfig.featureType}
                );
            }

        }

        function deactivateAtlas(){
            // Stop animation
            if( lizAtlasTimer ){
                var btrun = $('#atlas div.menu-content button.liz-atlas-run');
                // Change button value
                btrun.val(1);

                // Change button look
                btrun.text(lizDict['atlas.toolbar.play']).removeClass('btn-danger');

                // Reset interval and time
                clearInterval(lizAtlasTimer);
                lizAtlasTimer = null;
            }

            // Deactivate highlight
            var layer = lizMap.map.getLayersByName('locatelayer');
            if ( lizAtlasConfig.drawFeatureGeom && layer.length > 0 ){
                layer = layer[0];
                layer.destroyFeatures();
            }

            // Deactivate filter
            if ( lizAtlasConfig.triggerFilter && lizMap.lizmapLayerFilterActive ){
                lizMap.events.triggerEvent( "layerfeatureremovefilter",
                    { 'featureType': lizAtlasConfig.featureType}
                );
            }

            // Hide some containers
            $('#liz-atlas-item-detail').hide();
        }

        // Launch Atlas feature
        getAtlasData(lizAtlasConfig.layername);

        } // uicreated
    });

}();
<commit_msg>Atlas: Add hideFeaturesAtStratup in config<commit_after>var lizAtlas = function() {

    lizMap.events.on({
        'uicreated':function(evt){

        if( !('atlasEnabled' in lizMap.config.options) )
            return;
        if( lizMap.config.options['atlasEnabled'] != 'True')
            return;

        var getLayerConfig = lizMap.getLayerConfigById( lizMap.config.options['atlasLayer'] );
        if ( !getLayerConfig )
            return;
        var layerConfig = getLayerConfig[1];
        var featureType = getLayerConfig[0];
        var primaryKey = lizMap.config.options['atlasPrimaryKey'] != '' ? lizMap.config.options['atlasPrimaryKey'] : null;
        if(!primaryKey)
            return;
        var titleField = lizMap.config.options['atlasFeatureLabel'] != '' ? lizMap.config.options['atlasFeatureLabel'] : null;
        if(!titleField)
            return;
        var sortField = lizMap.config.options['atlasSortField'] != '' ? lizMap.config.options['atlasSortField'] : titleField;

        var lizAtlasConfig = {
            'layername': featureType,
            'showAtStartup': lizMap.config.options['atlasShowAtStartup'] == 'True' ? true : false,
            'displayLayerDescription': lizMap.config.options['atlasDisplayLayerDescription'] == 'True' ? true : false,
            'primaryKey': primaryKey,
            'titleField': titleField,
            'sortField': sortField,
            'duration': lizMap.config.options['atlasDuration'],
            'autoPlay': lizMap.config.options['atlasAutoPlay'] == 'True' ? true : false,
            'maxWidth': lizMap.config.options['atlasMaxWidth'] +'%',
            'drawFeatureGeom': lizMap.config.options['atlasHighlightGeometry'] == 'True' ? true : false,
            'atlasDisplayPopup': lizMap.config.options['atlasDisplayPopup'] == 'True' ? true : false,
            'triggerFilter': lizMap.config.options['atlasTriggerFilter'] == 'True' ? true : false,
            'hideFeaturesAtStratup': lizMap.config.options['hideFeaturesAtStratup'] == 'True' ? true : false,
            'zoom': lizMap.config.options['atlasZoom'] == '' ? false : lizMap.config.options['atlasZoom']
        };
        var lizAtlasTimer;

        function getAtlasData(featureType) {

            // Get data
            lizMap.getAttributeFeatureData(featureType, null, null, 'geom', function(aName, aFilter, aFeatures, aAliases){
                if( aFeatures.length != 0 ) {
                    lizAtlasConfig['features'] = aFeatures;
                    lizAtlasConfig['featureType'] = featureType;
                    prepareFeatures();
                    launchAtlas();
                }
                $('body').css('cursor', 'auto');
                return false;
            });
        }

        function prepareFeatures(){

            // Get and order features
            lizAtlasConfig['features_with_pkey'] = {};
            var items = [];
            var pkey_field = lizAtlasConfig['primaryKey'];
            var s_field = lizAtlasConfig['sortField'];
            for(var i in lizAtlasConfig.features){

                // Get feature
                var feat = lizAtlasConfig.features[i];
                var fid = feat.id.split('.').pop();
                var pk_val = feat.properties[pkey_field];

                // Add feature in dictionary for further ref
                lizAtlasConfig['features_with_pkey'][pk_val] = feat;

                // Add feature to sorted oject
                items.push(feat.properties);
            }

            items.sort(function(a, b) {
                var nameA = a[s_field];
                var nameB = b[s_field];
                if( typeof(a[s_field]) == 'string' || typeof(b[s_field]) == 'string' ){
                    nameA = a[s_field].toUpperCase(); // ignore upper and lowercase
                    nameB = b[s_field].toUpperCase(); // ignore upper and lowercase
                }
                if (nameA < nameB) {
                    return -1;
                }
                if (nameA > nameB) {
                    return 1;
                }

                // names must be equal
                return 0;
            });

            lizAtlasConfig['features_sorted'] = items;
            //console.log(lizAtlasConfig['features_with_pkey']);
        }

        function getAtlasHome(){

            var home = '';
            // Add description

            if( lizAtlasConfig['displayLayerDescription'] ){
                var labstract = lizMap.config.layers[lizAtlasConfig.layername]['abstract'];
                if(labstract != ''){
                    home+= '
' + lizMap.config.layers[lizAtlasConfig.layername]['abstract'] + '
';
                }
            }

            // Add combobox with all data
            home+= '
';
            home+= '<select id="liz-atlas-select">';
            home+= '<option value="-1"> --- </option>';
            var pkey_field = lizAtlasConfig['primaryKey'];
            for(var i in lizAtlasConfig['features_sorted']){
                var item = lizAtlasConfig['features_sorted'][i];

                // Add option
                home+= '<option value="'+i+'">';
                home+= item[lizAtlasConfig['titleField']];
                home+= '</option>';
            }
            home+= '</select>';
            home+= '
';
            home+= '<button class="btn btn-mini btn-primary liz-atlas-item" value="-1">'+lizDict['atlas.toolbar.prev']+'</button>';
            home+= ' ';
            home+= '<button class="btn btn-mini btn-primary liz-atlas-item" value="1">'+lizDict['atlas.toolbar.next']+'</button>';
            home+= ' ';
            home+= '<button class="btn btn-mini btn-wanrning liz-atlas-run" value="1">'+lizDict['atlas.toolbar.play']+'</button>';
            home+= ' ';
            home+= '';
            home+= '';
            home+= '
';
            home+= '
';
            home+= '
';
            home+= '
';

            lizAtlasConfig.home = home;
            return home;
        }

        function launchAtlas(){
            lizMap.events.triggerEvent("uiatlascreationlaunched", lizAtlasConfig);
            // Get Atlas home
            var home = getAtlasHome(lizAtlasConfig.featureType, lizAtlasConfig.features);

            // Add dock
            lizMap.addDock(
                'atlas',
                lizDict['atlas.toolbar.title'],
                'right-dock',
                home,
                'icon-globe'
            );
            var title = '
';
            title+= '';
            title+= lizMap.config.layers[lizAtlasConfig.layername]['title'];
            title+= '
';
            $('#atlas').prepend(title);

            // Add events
            activateAtlasTrigger();

            // Limit dock size
            adaptAtlasSize();

            // Show dock
            if( lizAtlasConfig['showAtStartup'] && !lizMap.checkMobile() ){
                $('#mapmenu li.atlas:not(.active) a').click();
                // Hide legend
                $('#mapmenu li.switcher.active a').click();
            }

            // Start animation
            if( lizAtlasConfig['autoPlay'] && !lizMap.checkMobile() ){
                $('button.liz-atlas-run').click();
            }

            lizMap.events.triggerEvent("uiatlascreated", lizAtlasConfig);

        }

        function adaptAtlasSize(){
            lizMap.events.on({
            // Adapt dock size to display metadata
            rightdockopened: function(e) {
                if ( e.id == 'atlas') {
                    // Size : add class to content to enabled specific css to be applied
                    $('#content').addClass('atlas-visible');
                    lizMap.updateContentSize();

                }
            },
            rightdockclosed: function(e) {
                if ( e.id == 'atlas' ) {

                    // Set right-dock default size by removing #content class
                    $('#content').removeClass('atlas-visible');
                    lizMap.updateContentSize();

                    // Deactivate atlas and stop animation
                    deactivateAtlas();

                }
            }
            });

        }

        function activateAtlasTrigger(){
            $('#liz-atlas-select')
            .change( function(){
                var i = $(this).val();
                var len = lizAtlasConfig['features_sorted'].length;

                if( i == -1 ){
                    deactivateAtlas();
                    return false;
                }
                if( i && i>= 0 && i < len ){
                    var item = lizAtlasConfig['features_sorted'][i];

                    var pkey_field = lizAtlasConfig['primaryKey'];

                    if(item[pkey_field] in lizAtlasConfig['features_with_pkey'] ){
                        var feature = lizAtlasConfig['features_with_pkey'][item[pkey_field]];
                        runAtlasItem( feature );

                    }else{
                        console.log("no feature found");
                    }

                }
                return false;

            });

            $('#atlas div.menu-content')
            .on('click', 'button.liz-atlas-item', function(){
                var a = parseInt($(this).val());
                var curval = parseInt($('#liz-atlas-select').val());
                var nextval = a + curval;
                var len = lizAtlasConfig['features_sorted'].length;
                if(nextval >= len)
                    nextval = 0;
                if( nextval >= 0 && nextval < len){
                    $('#liz-atlas-select').val(nextval).change();
                }
                return false;
            });

            // Timer
            $('#atlas div.menu-content button.liz-atlas-run').click(function(){
                // Get button value
                var a = $(this).val();

                // Get animation duration
                var duration = lizAtlasConfig.duration;
                if( !(parseInt(duration) > 0) )
                    duration = 5;
                var step = parseInt(duration) * 1000;
                if(step < 2 || step > 60000){
                    step = 5000;
                }

                // Run or stop animation
                if( a == '1' ){
                    // Click on the next button
                    $('button.liz-atlas-item[value="1"]').click();

                    // Change the run button value into 0
                    $(this).val(0);

                    // Change button look
                    $(this).text(lizDict['atlas.toolbar.stop']).addClass('btn-danger');

                    // Run timer
                    lizAtlasTimer = setInterval(function(){
                        // Click on then next button for each step
                        $('button.liz-atlas-item[value="1"]').click();
                    }, step);
                }else{
                    deactivateAtlas();
                }
            });
        }

        function runAtlasItem(feature){

            // Use OL tools to reproject feature geometry
            var format = new OpenLayers.Format.GeoJSON();
            var feat = format.read(feature)[0];
            var f = feat.clone();
            var proj = lizMap.config.layers[lizAtlasConfig.layername]['featureCrs'];
            f.geometry.transform(proj, lizMap.map.getProjection());

            // Zoom to feature
            if( lizAtlasConfig['zoom']){
                if( lizAtlasConfig['zoom'].toLowerCase() == 'center' ){
                    // center
                    var lonlat = f.geometry.getBounds().getCenterLonLat();
                    lizMap.map.setCenter(lonlat);
                }
                else{
                    // zoom
                    lizMap.map.zoomToExtent(f.geometry.getBounds());
                }
            }

            // Draw feature geometry
            var getLayer = lizMap.map.getLayersByName('locatelayer');
            if ( lizAtlasConfig.drawFeatureGeom && getLayer.length > 0 ){
                alayer = getLayer[0];
                alayer.destroyFeatures();
                alayer.addFeatures([f]);
            }

            // Display popup
            if( lizAtlasConfig['atlasDisplayPopup'] ){
                lizMap.getFeaturePopupContent(lizAtlasConfig.featureType, feature, function(data){
                    // Add class to table
                    var popupReg = new RegExp('lizmapPopupTable', 'g');
                    text = data.replace( popupReg, 'table table-condensed lizmapPopupTable');
                    var text = '
'+text+'
';
                    // Remove
 with layer title
                    var titleReg = new RegExp('
.+
');
                    text = text.replace(titleReg, '');
                    $('#liz-atlas-item-detail').html(text).show();

                    // Trigger event ? a bit buggy
                    lizMap.events.triggerEvent("lizmappopupdisplayed", {'popup': null} );

                    // Add children
                    lizMap.addChildrenFeatureInfo(data);

                });
            }

            // Trigger Filter
            if( lizAtlasConfig['triggerFilter'] ){

                var fid = feature.id.split('.').pop();

                // Select feature
                lizMap.events.triggerEvent('layerfeatureselected',
                    {'featureType': lizAtlasConfig.featureType, 'fid': fid, 'updateDrawing': false}
                );
                // Filter selected feature
                lizMap.events.triggerEvent('layerfeaturefilterselected',
                    {'featureType': lizAtlasConfig.featureType}
                );
            }

        }

        function deactivateAtlas(){
            // Stop animation
            if( lizAtlasTimer ){
                var btrun = $('#atlas div.menu-content button.liz-atlas-run');
                // Change button value
                btrun.val(1);

                // Change button look
                btrun.text(lizDict['atlas.toolbar.play']).removeClass('btn-danger');

                // Reset interval and time
                clearInterval(lizAtlasTimer);
                lizAtlasTimer = null;
            }

            // Deactivate highlight
            var layer = lizMap.map.getLayersByName('locatelayer');
            if ( lizAtlasConfig.drawFeatureGeom && layer.length > 0 ){
                layer = layer[0];
                layer.destroyFeatures();
            }

            // Deactivate filter
            if ( lizAtlasConfig.triggerFilter && lizMap.lizmapLayerFilterActive ){
                if ( lizAtlasConfig.hideFeaturesAtStratup ) {
                    // Select feature
                    lizMap.events.triggerEvent('layerfeatureselected',
                        {'featureType': lizAtlasConfig.featureType, 'fid': deactivatedValue, 'updateDrawing': false}
                    );
                    // Filter selected feature
                    lizMap.events.triggerEvent('layerfeaturefilterselected',
                        {'featureType': lizAtlasConfig.featureType}
                    );
                } else
                    lizMap.events.triggerEvent( "layerfeatureremovefilter",
                        { 'featureType': lizAtlasConfig.featureType}
                    );
            }

            // Hide some containers
            $('#liz-atlas-item-detail').hide();
        }

        // Launch Atlas feature
        getAtlasData(lizAtlasConfig.layername);

        } // uicreated
    });

}();
<|endoftext|>