<commit_before>(function () {
    "use strict";

    /**
     * @param {*} owner jQueryUI widget instance
     * @param {ol.PluggableMap} olMap
     * @param {Object} schema
     * @constructor
     */
    Mapbender.Digitizer.FeatureRenderer = function FeatureRenderer(owner, olMap, schema) {
        this.owner = owner;
        this.olMap = olMap;

        this.styles = this.initializeStyles_(schema.styles);

        this.layer = this.createSchemaFeatureLayer_(schema);
        this.olMap.addLayer(this.layer);
        this.excludedFromHighlighting_ = [];

        this.addSelectControl_();

        var renderer = this;
        this.layer.getSource().on(ol.source.VectorEventType.ADDFEATURE, function (event) {
            var feature = event.feature;
            renderer.initializeFeature(schema, feature);
            renderer.registerFeatureEvents(schema, feature);
        });
        $(olMap).on('Digitizer.FeatureUpdatedOnServer', function (event) {
            renderer.onFeatureUpdatedOnServer(schema);
        });
    }
    Object.assign(Mapbender.Digitizer.FeatureRenderer.prototype, {
        initializeFeature: function(schema, feature) {
            feature.set("mbOrigin", "digitizer");
            this.setStyle_(feature, this.styles.default);
            if (schema.allowCustomStyle) {
                this.customStyleFeature_(schema, feature);
            }

            feature.set("oldGeometry", feature.getGeometry().clone());
        },
        registerFeatureEvents: function(schema, feature) {
            var renderer = this;
            var watchedProperties = ['hover', 'dirty', 'editing', 'hidden'];
            feature.on(ol.ObjectEventType.PROPERTYCHANGE, function (event) {
                if (-1 !== watchedProperties.indexOf(event.key)) {
                    renderer.updateFeatureStyle(schema, feature);
                }
            });
        },
        setRenderIntent: function(feature, intent) {
            var style = this.getStyleForIntent_(feature, intent);
            this.setStyle_(feature, style);
        },
        setStyle_: function(feature, style) {
            // adopted code from mapbender/ol4-extensions package, plus fixes
            // @todo: turn this into a style function on the layer
            var labelPattern = /\${([^}]+)}/g;
            var styleFunction = function (feature) {
                var baseStyles;
                if (typeof style === 'function') {
                    baseStyles = style.apply(this, arguments);
                    if (!Array.isArray(baseStyles)) {
                        baseStyles = [baseStyles];
                    }
                } else {
                    baseStyles = [style];
                }
                var labelValue = baseStyles[0].getText() && baseStyles[0].getText().getText();
                if (!labelPattern.test(labelValue || '')) {
                    return baseStyles;
                }
                var labelStyle = new ol.style.Style({
                    text: baseStyles[0].getText().clone()
                });
                baseStyles[0] = baseStyles[0].clone();
                baseStyles[0].setText(null);

                var attributes = feature.get("data") || {};
                var label = labelValue.replace(labelPattern, function(match, attributeName) {
                    return attributes[attributeName] || '';
                });
                labelStyle.getText().setText(label);
                return baseStyles.concat([labelStyle]);
            };
            feature.setStyle(styleFunction);
        },
        getStyleForIntent_: function(feature, intent) {
            // @todo: turn this into a style function on the layer, so it will work without events
            var intent_ = intent;
            if (!this.styles[intent]) {
                console.warn("Unknown render intent " + intent + ", using default");
                intent_ = 'default';
            }
            var style;
            if (intent_ === 'default') {
                // NOTE: "style" value only set by feature style editor (disabled?; see customStyleFeature_)
                style = feature.get('style');
            }
            return style || this.styles[intent_];
        },
        updateFeatureStyle: function(schema, feature) {
            if (feature.get('editing')) {
                this.setRenderIntent(feature, 'editing');
            } else if (feature.get("hidden")) {
                this.setRenderIntent(feature, 'invisible');
            } else if (feature.get('hover')) {
                this.setRenderIntent(feature, 'select');
            } else if (feature.get('dirty')) {
                this.setRenderIntent(feature, 'unsaved');
            } else {
                this.setRenderIntent(feature, 'default');
            }
        },
        setExcludedFromHighlighting: function(features) {
            var features_ = features || [];
            this.excludedFromHighlighting_.splice(0, this.excludedFromHighlighting_.length);
            for (var i = 0; i < features_.length; ++i) {
                this.excludedFromHighlighting_.push(features_[i]);
            }
        }
    });

    Object.assign(Mapbender.Digitizer.FeatureRenderer.prototype, {
        onFeatureUpdatedOnServer: function(schema) {
            if (schema.refreshLayersAfterFeatureSave) {
                $.each(schema.refreshLayersAfterFeatureSave, function (k1, instanceId) {
                    var source = Mapbender.Model.getSourceById(instanceId);
                    var layers = source.getNativeLayers();
                    $.each(layers, function (k2, layer) {
                        Mapbender.layerManager.refreshLayer(layer);
                    });
                });
            }

            if (schema.refreshFeaturesAfterSave) {
                for (var i = 0; i < schema.refreshFeaturesAfterSave.length; ++i) {
                    var schemaName = schema.refreshFeaturesAfterSave[i];
                    this.refreshConnectedDigitizerFeatures(schemaName);
                }
            }
        }
    });
    // @todo: salvage this
    //        Modifying Digitizer A should NOT call into other Digitizer code
    //        Other Digitizer should REACT to a change event
    //        For this to work, the event must be listenable (=triggered on DOM, not on completely internal objects)
    Mapbender.Digitizer.FeatureRenderer.prototype.refreshConnectedDigitizerFeatures = function(schemaName){
        $(".mb-element-digitizer").not(".mb-element-data-manager").each(function(index,element){
            var foreignDigitizer = $(element).data("mapbenderMbDigitizer");

            try {
                foreignDigitizer.schemes[schemaName].layer.getSource().refresh();
            } catch(e) {
                console.error("No active Digitizer Scheme '"+schemaName+"'",e); // ???
            }
        });
    };

    Mapbender.Digitizer.FeatureRenderer.prototype.getLayer = function() {
        return this.layer;
    };

    Mapbender.Digitizer.FeatureRenderer.prototype.initializeStyles_ = function (styleConfigs) {
        var styles = {};
        var keys = Object.keys(styleConfigs);
        for (var i = 0; i < keys.length; ++ i) {
            var key = keys[i];
            var styleConfig = styleConfigs[key];
            styles[key] = ol.style.StyleConverter.convertToOL4Style(styleConfig);
        }
        Object.freeze(styles.default.getFill().getColor()); // Freeze Color to prevent unpredictable behaviour
        styles.invisible = new ol.style.Style();
        styles.editing = this.createEditingStyle_();
        return styles;
    };

    Mapbender.Digitizer.FeatureRenderer.prototype.createSchemaFeatureLayer_ = function (schema) {
        var layer = new ol.layer.Vector({
            source: new ol.source.Vector(),
            visible: true,
            minResolution: Mapbender.Model.scaleToResolution(schema.maxScale || 0),
            maxResolution: Mapbender.Model.scaleToResolution(schema.minScale || Infinity)
        });
        return layer;
    };

    Mapbender.Digitizer.FeatureRenderer.prototype.customStyleFeature_ = function (schema, feature) {
        var styleField = schema.featureType.styleField;
        var itemData = feature.get("data");
        var jsonStyle = styleField && itemData && itemData[styleField];

        if (jsonStyle) {
            var basicStyle = JSON.parse(jsonStyle);
            var style = ol.style.StyleConverter.convertToOL4Style(basicStyle);
            feature.set("basicStyle", basicStyle);
            feature.set("style", style);
            this.setStyle_(feature, style);
        }
    };

    Mapbender.Digitizer.FeatureRenderer.prototype.addSelectControl_ = function () {
        this.highlightControl = this.initializeHighlightControl_();
        this.selectControl = this.initializeSelectControl_();
        this.olMap.addInteraction(this.selectControl);
        this.olMap.addInteraction(this.highlightControl);
    };
    Mapbender.Digitizer.FeatureRenderer.prototype.initializeHighlightControl_ = function () {
        var renderer = this;
        var highlightControl = new ol.interaction.Select({
            condition: ol.events.condition.pointerMove,
            layers: [this.layer],
            filter: function(feature) {
                return -1 === renderer.excludedFromHighlighting_.indexOf(feature);
            }
        });
        highlightControl.on('select', function (e) {
            e.deselected.forEach(function(feature) {
                feature.set('hover', false);
            });
            e.selected.forEach(function(feature) {
                feature.set('hover', true);
            });
        });

        highlightControl.setActive(false);
        return highlightControl;
    };
    Mapbender.Digitizer.FeatureRenderer.prototype.initializeSelectControl_ = function () {
        var selectControl = new ol.interaction.Select({
            condition: ol.events.condition.singleClick,
            layers: [this.layer]
        });

        var widget = this.owner;
        selectControl.on('select', function (event) {
            selectControl.getFeatures().clear();
            widget.onFeatureClick(event.selected[0]);
        });
        selectControl.setActive(false);
        return selectControl;
    };

    /**
     * @return function
     * @private
     */
    Mapbender.Digitizer.FeatureRenderer.prototype.createEditingStyle_ = function() {
        // Adopted from "ol4-extensions" repository
        // @see https://github.com/mapbender/ol4-extensions/blob/0.0.4/selectableModify.js#L3
        var baseStyle = ol.style.Style.defaultFunction()[0].clone();
        var verticesStyle = new ol.style.Style({
            geometry: function(feature) {
                // Concatenate all vertices of all rings
                var coordinates = Array.prototype.concat.apply([], feature.getGeometry().getCoordinates());
                return new ol.geom.MultiPoint(coordinates);
            },
            image: new ol.style.Circle({
                radius: 3,
                fill: new ol.style.Fill({
                    color: "#ffcc33"
                })
            })
        });
        var midpointStyle = new ol.style.Style({
            geometry: function(feature) {
                var lineStrings = feature.getGeometry().getCoordinates().map(function(ringCoordinates) {
                    return new ol.geom.LineString(ringCoordinates);
                });
                var coordinates = Array.prototype.concat.apply([], lineStrings.map(function(lineString) {
                    var midpoints = [];
                    lineString.forEachSegment(function(start, end) {
                        midpoints.push([(start[0] + end[0]) / 2, (start[1] + end[1]) / 2]);
                    });
                    return midpoints;
                }));
                return new ol.geom.MultiPoint(coordinates);
            },
            image: new ol.style.Circle({
                radius: 3,
                stroke: new ol.style.Stroke({
                    color: "#ffcc33",
                    width: 4
                })
            })
        });

        return function (feature) {
            var geometry = feature.getGeometry();
            var styles = [baseStyle];

            if (geometry.getType() === "Polygon") {
                styles.push(verticesStyle);
                styles.push(midpointStyle);
            }
            return styles;
        }
    };
})();
<commit_msg>Fix editing style on lines and (implicit) multi-geometry types<commit_after>(function () {
    "use strict";

    /**
     * @param {*} owner jQueryUI widget instance
     * @param {ol.PluggableMap} olMap
     * @param {Object} schema
     * @constructor
     */
    Mapbender.Digitizer.FeatureRenderer = function FeatureRenderer(owner, olMap, schema) {
        this.owner = owner;
        this.olMap = olMap;

        this.styles = this.initializeStyles_(schema.styles);

        this.layer = this.createSchemaFeatureLayer_(schema);
        this.olMap.addLayer(this.layer);
        this.excludedFromHighlighting_ = [];

        this.addSelectControl_();

        var renderer = this;
        this.layer.getSource().on(ol.source.VectorEventType.ADDFEATURE, function (event) {
            var feature = event.feature;
            renderer.initializeFeature(schema, feature);
            renderer.registerFeatureEvents(schema, feature);
        });
        $(olMap).on('Digitizer.FeatureUpdatedOnServer', function (event) {
            renderer.onFeatureUpdatedOnServer(schema);
        });
    }
    Object.assign(Mapbender.Digitizer.FeatureRenderer.prototype, {
        initializeFeature: function(schema, feature) {
            feature.set("mbOrigin", "digitizer");
            this.setStyle_(feature, this.styles.default);
            if (schema.allowCustomStyle) {
                this.customStyleFeature_(schema, feature);
            }

            feature.set("oldGeometry", feature.getGeometry().clone());
        },
        registerFeatureEvents: function(schema, feature) {
            var renderer = this;
            var watchedProperties = ['hover', 'dirty', 'editing', 'hidden'];
            feature.on(ol.ObjectEventType.PROPERTYCHANGE, function (event) {
                if (-1 !== watchedProperties.indexOf(event.key)) {
                    renderer.updateFeatureStyle(schema, feature);
                }
            });
        },
        setRenderIntent: function(feature, intent) {
            var style = this.getStyleForIntent_(feature, intent);
            this.setStyle_(feature, style);
        },
        setStyle_: function(feature, style) {
            // adopted code from mapbender/ol4-extensions package, plus fixes
            // @todo: turn this into a style function on the layer
            var labelPattern = /\${([^}]+)}/g;
            var styleFunction = function (feature) {
                var baseStyles;
                if (typeof style === 'function') {
                    baseStyles = style.apply(this, arguments);
                    if (!Array.isArray(baseStyles)) {
                        baseStyles = [baseStyles];
                    }
                } else {
                    baseStyles = [style];
                }
                var labelValue = baseStyles[0].getText() && baseStyles[0].getText().getText();
                if (!labelPattern.test(labelValue || '')) {
                    return baseStyles;
                }
                var labelStyle = new ol.style.Style({
                    text: baseStyles[0].getText().clone()
                });
                baseStyles[0] = baseStyles[0].clone();
                baseStyles[0].setText(null);

                var attributes = feature.get("data") || {};
                var label = labelValue.replace(labelPattern, function(match, attributeName) {
                    return attributes[attributeName] || '';
                });
                labelStyle.getText().setText(label);
                return baseStyles.concat([labelStyle]);
            };
            feature.setStyle(styleFunction);
        },
        getStyleForIntent_: function(feature, intent) {
            // @todo: turn this into a style function on the layer, so it will work without events
            var intent_ = intent;
            if (!this.styles[intent]) {
                console.warn("Unknown render intent " + intent + ", using default");
                intent_ = 'default';
            }
            var style;
            if (intent_ === 'default') {
                // NOTE: "style" value only set by feature style editor (disabled?; see customStyleFeature_)
                style = feature.get('style');
            }
            return style || this.styles[intent_];
        },
        updateFeatureStyle: function(schema, feature) {
            if (feature.get('editing')) {
                this.setRenderIntent(feature, 'editing');
            } else if (feature.get("hidden")) {
                this.setRenderIntent(feature, 'invisible');
            } else if (feature.get('hover')) {
                this.setRenderIntent(feature, 'select');
            } else if (feature.get('dirty')) {
                this.setRenderIntent(feature, 'unsaved');
            } else {
                this.setRenderIntent(feature, 'default');
            }
        },
        setExcludedFromHighlighting: function(features) {
            var features_ = features || [];
            this.excludedFromHighlighting_.splice(0, this.excludedFromHighlighting_.length);
            for (var i = 0; i < features_.length; ++i) {
                this.excludedFromHighlighting_.push(features_[i]);
            }
        }
    });

    Object.assign(Mapbender.Digitizer.FeatureRenderer.prototype, {
        onFeatureUpdatedOnServer: function(schema) {
            if (schema.refreshLayersAfterFeatureSave) {
                $.each(schema.refreshLayersAfterFeatureSave, function (k1, instanceId) {
                    var source = Mapbender.Model.getSourceById(instanceId);
                    var layers = source.getNativeLayers();
                    $.each(layers, function (k2, layer) {
                        Mapbender.layerManager.refreshLayer(layer);
                    });
                });
            }

            if (schema.refreshFeaturesAfterSave) {
                for (var i = 0; i < schema.refreshFeaturesAfterSave.length; ++i) {
                    var schemaName = schema.refreshFeaturesAfterSave[i];
                    this.refreshConnectedDigitizerFeatures(schemaName);
                }
            }
        }
    });
    // @todo: salvage this
    //        Modifying Digitizer A should NOT call into other Digitizer code
    //        Other Digitizer should REACT to a change event
    //        For this to work, the event must be listenable (=triggered on DOM, not on completely internal objects)
    Mapbender.Digitizer.FeatureRenderer.prototype.refreshConnectedDigitizerFeatures = function(schemaName){
        $(".mb-element-digitizer").not(".mb-element-data-manager").each(function(index,element){
            var foreignDigitizer = $(element).data("mapbenderMbDigitizer");

            try {
                foreignDigitizer.schemes[schemaName].layer.getSource().refresh();
            } catch(e) {
                console.error("No active Digitizer Scheme '"+schemaName+"'",e); // ???
            }
        });
    };

    Mapbender.Digitizer.FeatureRenderer.prototype.getLayer = function() {
        return this.layer;
    };

    Mapbender.Digitizer.FeatureRenderer.prototype.initializeStyles_ = function (styleConfigs) {
        var styles = {};
        var keys = Object.keys(styleConfigs);
        for (var i = 0; i < keys.length; ++ i) {
            var key = keys[i];
            var styleConfig = styleConfigs[key];
            styles[key] = ol.style.StyleConverter.convertToOL4Style(styleConfig);
        }
        Object.freeze(styles.default.getFill().getColor()); // Freeze Color to prevent unpredictable behaviour
        styles.invisible = new ol.style.Style();
        styles.editing = this.createEditingStyle_();
        return styles;
    };

    Mapbender.Digitizer.FeatureRenderer.prototype.createSchemaFeatureLayer_ = function (schema) {
        var layer = new ol.layer.Vector({
            source: new ol.source.Vector(),
            visible: true,
            minResolution: Mapbender.Model.scaleToResolution(schema.maxScale || 0),
            maxResolution: Mapbender.Model.scaleToResolution(schema.minScale || Infinity)
        });
        return layer;
    };

    Mapbender.Digitizer.FeatureRenderer.prototype.customStyleFeature_ = function (schema, feature) {
        var styleField = schema.featureType.styleField;
        var itemData = feature.get("data");
        var jsonStyle = styleField && itemData && itemData[styleField];

        if (jsonStyle) {
            var basicStyle = JSON.parse(jsonStyle);
            var style = ol.style.StyleConverter.convertToOL4Style(basicStyle);
            feature.set("basicStyle", basicStyle);
            feature.set("style", style);
            this.setStyle_(feature, style);
        }
    };

    Mapbender.Digitizer.FeatureRenderer.prototype.addSelectControl_ = function () {
        this.highlightControl = this.initializeHighlightControl_();
        this.selectControl = this.initializeSelectControl_();
        this.olMap.addInteraction(this.selectControl);
        this.olMap.addInteraction(this.highlightControl);
    };
    Mapbender.Digitizer.FeatureRenderer.prototype.initializeHighlightControl_ = function () {
        var renderer = this;
        var highlightControl = new ol.interaction.Select({
            condition: ol.events.condition.pointerMove,
            layers: [this.layer],
            filter: function(feature) {
                return -1 === renderer.excludedFromHighlighting_.indexOf(feature);
            }
        });
        highlightControl.on('select', function (e) {
            e.deselected.forEach(function(feature) {
                feature.set('hover', false);
            });
            e.selected.forEach(function(feature) {
                feature.set('hover', true);
            });
        });

        highlightControl.setActive(false);
        return highlightControl;
    };
    Mapbender.Digitizer.FeatureRenderer.prototype.initializeSelectControl_ = function () {
        var selectControl = new ol.interaction.Select({
            condition: ol.events.condition.singleClick,
            layers: [this.layer]
        });

        var widget = this.owner;
        selectControl.on('select', function (event) {
            selectControl.getFeatures().clear();
            widget.onFeatureClick(event.selected[0]);
        });
        selectControl.setActive(false);
        return selectControl;
    };

    /**
     * @return function
     * @private
     */
    Mapbender.Digitizer.FeatureRenderer.prototype.createEditingStyle_ = function() {
        // Adopted from "ol4-extensions" repository
        // @see https://github.com/mapbender/ol4-extensions/blob/0.0.4/selectableModify.js#L3
        var baseStyle = ol.style.Style.defaultFunction()[0].clone();
        var extractEdges = function(geometry) {
            var polygons, lines;
            switch (geometry.getType()) {
                case 'MultiPolygon':
                    polygons = geometry.getPolygons();
                    break;
                case 'Polygon':
                    polygons = [geometry];
                    break;
                case 'LineString':
                    lines = [geometry];
                    break;
                case 'MultiLineString':
                    lines = geometry.getLineStrings();
                    break;
                default:
                    break;
            }
            if (polygons) {
                lines = [];
                for (var p = 0; p < polygons.length; ++p) {
                    var polygon = polygons[p];
                    var rings = polygon.getCoordinates();
                    for (var r = 0; r < rings.length; ++r) {
                        var ring = rings[r];
                        lines.push(new ol.geom.LineString(ring));
                    }
                }
            }
            return lines || [];
        };
        var verticesStyle = new ol.style.Style({
            geometry: function(feature) {
                // Concatenate all vertices
                var coordinates = Array.prototype.concat.apply([], extractEdges(feature.getGeometry()).map(function(lineString) {
                    return lineString.getCoordinates();
                }));
                return new ol.geom.MultiPoint(coordinates);
            },
            image: new ol.style.Circle({
                radius: 3,
                fill: new ol.style.Fill({
                    color: "#ffcc33"
                })
            })
        });
        var midpointStyle = new ol.style.Style({
            geometry: function(feature) {
                var lineStrings = extractEdges(feature.getGeometry());
                var coordinates = Array.prototype.concat.apply([], lineStrings.map(function(lineString) {
                    var midpoints = [];
                    lineString.forEachSegment(function(start, end) {
                        midpoints.push([(start[0] + end[0]) / 2, (start[1] + end[1]) / 2]);
                    });
                    return midpoints;
                }));
                return new ol.geom.MultiPoint(coordinates);
            },
            image: new ol.style.Circle({
                radius: 3,
                stroke: new ol.style.Stroke({
                    color: "#ffcc33",
                    width: 4
                })
            })
        });

        return function (feature) {
            return [baseStyle, verticesStyle, midpointStyle];
        }
    };
})();
<|endoftext|>


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

import SubtreeContainer from '../_SubtreeContainer';
import PopupBody from '../_PopupBody';

export default class Popup extends Component {

    static Position = PopupBody.Position;
    static TriggerMode = PopupBody.TriggerMode;

    constructor(props) {
        super(props);
    }

    render() {

        const {visible} = this.props;

        return (
            <SubtreeContainer visible={visible}>
                <PopupBody {...this.props}/>
            </SubtreeContainer>
        );

    }

};

Popup.propTypes = PopupBody.propTypes;
Popup.defaultProps = PopupBody.defaultProps;<commit_msg>optimize Popup<commit_after>import React, {Component} from 'react';

import SubtreeContainer from '../_SubtreeContainer';
import PopupBody from '../_PopupBody';

export default class Popup extends Component {

    static Position = PopupBody.Position;
    static TriggerMode = PopupBody.TriggerMode;

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    render() {

        const {visible} = this.props;

        return (
            <SubtreeContainer visible={visible}>
                <PopupBody {...this.props}/>
            </SubtreeContainer>
        );

    }

};

Popup.propTypes = PopupBody.propTypes;
Popup.defaultProps = PopupBody.defaultProps;<|endoftext|>


<commit_before>var gitGraph = new GitGraph({
  template: "blackarrow" // "blackarrow" or "metro" or Template Object
});

var master = gitGraph.branch("master"); // Create branch named "master"
gitGraph.commit("Initial commit") // Commit on HEAD Branch (here this is master)
.commit("My second commit")
.commit("Add awesome feature");

var dev = gitGraph.branch("dev"); // Create branch named "dev" (a HEAD fork)
dev.commit("Youhou \\o/"); // Commit on dev
master.commit("I'm the master !"); // Commit on master

// Advanced commit method with style and specific author (HEAD)
gitGraph.commit({
  dotColor: "white",
  dotSize: 10,
  dotStrokeWidth: 10,
  message: "Alors c'est qui le papa ?",
  author: "Me <me@planee.fr>"
});

//master.checkout(); // Checkout on master branch for create "test" since master
var test = gitGraph.branch("test");
gitGraph.commit({
  message: "test"
});
gitGraph.commit();
dev.commit().commit(); // 2 default Commit on "dev"

gitGraph.author = "Fabien0102 <fabien0102@planee.fr>"; // Change default author
master.commit(); // Default commit on master (you can see the new author)

master.checkout(); // Checkout on master branch
dev.merge(); // Merge dev into HEAD (master) (automatic merge commit)
test.commit("Final commit");
test.merge(master, "My special merge commit message"); // Merge into HEAD with special merge commit message

test.commit("error"); // Error: You can't commit on merged branch

gitGraph.render(); // Render gitGraph
<commit_msg>Update example<commit_after>var gitGraph = new GitGraph({
  template: "blackarrow" // "blackarrow" or "metro" or Template Object
});

var master = gitGraph.branch("master"); // Create branch named "master"
gitGraph.commit("Initial commit") // Commit on HEAD Branch (here this is master)
.commit("My second commit")
.commit("Add awesome feature");

var dev = gitGraph.branch("dev"); // Create branch named "dev" (a HEAD fork)
dev.commit("Youhou \\o/"); // Commit on dev
master.commit("I'm the master !"); // Commit on master

// Advanced commit method with style and specific author (HEAD)
gitGraph.commit({
  dotColor: "white",
  dotSize: 10,
  dotStrokeWidth: 10,
  message: "Alors c'est qui le papa ?",
  author: "Me <me@planee.fr>"
});

//master.checkout(); // Checkout on master branch for create "test" since master
var test = gitGraph.branch("test");
gitGraph.commit({
  message: "test"
});
gitGraph.commit();
dev.commit().commit(); // 2 default Commit on "dev"

gitGraph.author = "Fabien0102 <fabien0102@planee.fr>"; // Change default author
master.commit(); // Default commit on master (you can see the new author)

master.checkout(); // Checkout on master branch
dev.merge(); // Merge dev into HEAD (master) (automatic merge commit)
test.commit("Final commit");
test.merge(master, "My special merge commit message"); // Merge into HEAD with special merge commit message

test.commit("It's works !");

gitGraph.render(); // Render gitGraph
<|endoftext|>


<commit_before>angular.module('horizontalBarChart', []).directive('horizontalBarChart', function ($filter) {
	try {
		return {
			scope: {
				'width': '=',
				'height': '=',
				'data': '=',
				'description': '=',
				'onClick': '&',
				'accessor': '=',
				'colors': '=',
				'colors2': '='
			},
			restrict: 'E',
			link: buildLink
		};

		function buildLink (scope, element, attr) {
			scope.colors = scope.colors || ['#5b8def', '#dae8fe'];
			scope.colors2 = scope.colors2 || ['#5b8def', '#dae8fe'];
			const MARGIN = {
				TOP: 30,
				LEFT: 100,
				BOTTOM: 30,
				RIGHT: 10
			};
			const DURATION = 500;
			const WIDTH = (scope.width || 500) - (MARGIN.LEFT + MARGIN.RIGHT);
			const HEIGHT = (scope.height || 200) - (MARGIN.TOP + MARGIN.BOTTOM);
			var el = element[0];
			var svg = d3.select(el).append('svg')
						.attr('width', WIDTH + (MARGIN.LEFT + MARGIN.RIGHT))
						.attr('height', HEIGHT + (MARGIN.TOP + MARGIN.BOTTOM))
						.append('g')
						.attr('transform', 'translate(' + MARGIN.LEFT + ',' + MARGIN.TOP + ')');

	        scope.$watch('data', function () {
				removeChart();
				var minMax = calcMinMax(scope.data);
				var x = d3.scaleLinear().domain([minMax.y.min, minMax.y.max]).range([0, WIDTH]);
				var y = d3.scaleBand().rangeRound([0, HEIGHT]).padding(0.1);
				var xAxis = d3.axisBottom(x).ticks(5).tickSize([0]).tickPadding([20]);
				var yAxis = d3.axisLeft(y).tickSize([0]).tickPadding([10]);
				x.domain([0, d3.max(scope.data.data1, function(d) { return parseInt(d.value); })]);
				y.domain(scope.data.data1.map(function(d) { return d.name; }));

				svg.append('g')
					.attr('class', 'x axis')
					.attr('transform', 'translate(0,' + HEIGHT + ')')
					.call(xAxis);

				svg.append('g')
					.attr('class', 'y axis')
					.attr("transform", "translate(" + x(0) + ",0)")
					.call(yAxis);

				drawBar(scope.data.data1, scope.colors[1], scope.colors2[1]);
				drawBar(scope.data.data2, scope.colors[0], scope.colors2[0]);

				svg.selectAll('path').style('stroke', '#C2C2C2');
				svg.selectAll('text').attr('fill', '#444444');
				svg.selectAll('.x.axis line').attr('y2', -HEIGHT).style('stroke', '#C2C2C2').style('opacity', '0.5');

				function drawBar (data, color, color2) {
					var bars = svg.selectAll('.bar').data(data).enter();
					bars.append('rect')
						.attr('class', 'bar2')
						.attr('x', 0)
						.attr('y', function (d) {
							return y(d.name) + y.bandwidth() / 4;
						})
						.attr('width', 0)
						.attr('height', y.bandwidth() / 2)
						.style('stroke', 'white')
						.attr('fill', function (d, i) {
							var size = data.length || 0;
							return ((size / 2) <= i && i <=  size) ? color2 : color;
						})
						.transition()
						.duration(DURATION)
						.delay(function (d, i) {
							return i * 50;
						})
						.attr('width', function (d, i, j) {
							return Math.abs(x(d.value) - x(1));
						});
				}
			});

			function removeChart () {
				svg.selectAll('rect')
					.transition()
					.duration(DURATION)
					.attr('width', 0);
				svg.selectAll('*').remove();
			}

			function calcMinMax (param) {
				var result = {
					y: {
						min: 0,
						max: parseInt(param.data1[0].value || 0)
					},
					y1: {
						min: 0,
						max: parseInt(param.data2[0].value || 0)
					}
				};
				for (var i = 1; i < param.data1.length; i++) {
					if (result.y.max < parseInt(param.data1[i].value)) {
						result.y.max = parseInt(param.data1[i].value);
					}
					if (result.y1.max < parseInt(param.data2[i].value)) {
						result.y1.max = parseInt(param.data2[i].value);
					}
				}
				return result;
			}
		}
	} catch (e) {
        var xcb = 'http://stackoverflow.com/search?q=[js]+' + e.message;
        window.open(xcb, '_blank');
    }
});
<commit_msg>Update horizontal.bar.chart.directive.js<commit_after>angular.module('horizontalBarChart', []).directive('horizontalBarChart', function ($filter) {
	try {
		return {
			scope: {
				'width': '=',
				'height': '=',
				'data': '=',
				'description': '=',
				'onClick': '&',
				'accessor': '=',
				'colors': '=',
				'colors2': '='
			},
			restrict: 'E',
			link: buildLink
		};

		function buildLink (scope, element, attr) {
			scope.colors = scope.colors || ['#5b8def', '#dae8fe'];
			scope.colors2 = scope.colors2 || ['#5b8def', '#dae8fe'];
			const MARGIN = {
				TOP: 30,
				LEFT: 100,
				BOTTOM: 30,
				RIGHT: 10
			};
			const DURATION = 500;
			const WIDTH = (scope.width || 500) - (MARGIN.LEFT + MARGIN.RIGHT);
			const HEIGHT = (scope.height || 200) - (MARGIN.TOP + MARGIN.BOTTOM);
			var el = element[0];
			var svg = d3.select(el).append('svg')
						.attr('width', WIDTH + (MARGIN.LEFT + MARGIN.RIGHT))
						.attr('height', HEIGHT + (MARGIN.TOP + MARGIN.BOTTOM))
						.append('g')
						.attr('transform', 'translate(' + MARGIN.LEFT + ',' + MARGIN.TOP + ')');

	        scope.$watch('data', function () {
				removeChart();
				var minMax = calcMinMax(scope.data);
				var x = d3.scaleLinear().domain([minMax.y.min, minMax.y.max]).range([0, WIDTH]);
				var y = d3.scaleBand().rangeRound([0, HEIGHT]).padding(0.1);
				var xAxis = d3.axisBottom(x).ticks(5).tickSize([0]).tickPadding([20]);
				var yAxis = d3.axisLeft(y).tickSize([0]).tickPadding([10]);
				x.domain([0, d3.max(scope.data.data1, function(d) { return parseInt(d.value); })]);
				y.domain(scope.data.data1.map(function(d) { return d.name; }));

				svg.append('g')
					.attr('class', 'x axis')
					.attr('transform', 'translate(0,' + HEIGHT + ')')
					.call(xAxis);

				svg.append('g')
					.attr('class', 'y axis')
					.attr("transform", "translate(" + x(0) + ",0)")
					.call(yAxis);

				drawBar(scope.data.data1, scope.colors[1], scope.colors2[1]);
				drawBar(scope.data.data2, scope.colors[0], scope.colors2[0]);

				svg.selectAll('path').style('stroke', '#C2C2C2');
				svg.selectAll('text').attr('fill', '#444444');
				svg.selectAll('.x.axis line').attr('y2', -HEIGHT).style('stroke', '#C2C2C2').style('opacity', '0.5');

				function drawBar (data, color, color2) {
					var bars = svg.selectAll('.bar').data(data).enter();
					bars.append('rect')
						.attr('class', 'bar2')
						.attr('y', function (d) {
							return y(d.name) + y.bandwidth() / 4;
						})
						.attr('width', 0)
						.attr('height', y.bandwidth() / 2)
						.style('stroke', 'white')
						.attr('fill', function (d, i) {
							var size = data.length || 0;
							return ((size / 2) <= i && i <=  size) ? color2 : color;
						})
						.transition()
						.duration(DURATION)
						.delay(function (d, i) {
							return i * 50;
						})
						.attr('width', function (d, i, j) {
							return Math.abs(x(d.value) - x(1));
						})
						.attr('x', 0);
				}
			});

			function removeChart () {
				svg.selectAll('rect')
					.transition()
					.duration(DURATION)
					.attr('width', 0);
				svg.selectAll('*').remove();
			}

			function calcMinMax (param) {
				var result = {
					y: {
						min: 0,
						max: parseInt(param.data1[0].value || 0)
					},
					y1: {
						min: 0,
						max: parseInt(param.data2[0].value || 0)
					}
				};
				for (var i = 1; i < param.data1.length; i++) {
					if (result.y.max < parseInt(param.data1[i].value)) {
						result.y.max = parseInt(param.data1[i].value);
					}
					if (result.y1.max < parseInt(param.data2[i].value)) {
						result.y1.max = parseInt(param.data2[i].value);
					}
				}
				return result;
			}
		}
	} catch (e) {
        var xcb = 'http://stackoverflow.com/search?q=[js]+' + e.message;
        window.open(xcb, '_blank');
    }
});
<|endoftext|>


<commit_before>var ITDoorsAjax = (function() {

    var defaults = {
        ajaxFilterFormClass: 'ajax-filter-form',
        shortFormClass: 'itdoors-short-form',
        canBeResetedClass: 'can-be-reseted',
        select2Class: 'itdoors-select2',
        daterangeClass: 'itdoors-daterange',
        daterangeCustomClass: 'itdoors-daterange-custom',
        daterangeTextClass: 'itdoors-daterange-text',
        daterangeStartClass: 'itdoors-daterange-start',
        daterangeEndClass: 'itdoors-daterange-end',
        assetsDir: '',
        loadingImgPath: ''
    };

    function ITDoorsAjax(){
        this.params = {};
    };

    ITDoorsAjax.prototype.init = function(options)
    {
        this.params = $.extend(defaults, options);

        this.params.loadingImgPath = this.params.assetsDir + 'templates/metronic/img/ajax-loading.gif';

        this.initAjaxFilterForm();

        this.initSelect2();

        this.initDateRange();

        this.initDateRangeCustom();
    }

    ITDoorsAjax.prototype.initSelect2 = function()
    {
        if (!jQuery().select2) {
            return;
        }

        var selfClass = this;

        $('.' + selfClass.params.select2Class).each(function(index) {
            selfClass.select2($(this));
        });
    }

    ITDoorsAjax.prototype.initDateRange = function()
    {
        var selfClass = this;

        if (!jQuery().daterangepicker) {
            return;
        }

        $('.' + selfClass.params.daterangeClass).each(function(index) {
            var self = $(this);

            var $form = self.closest('form');

            var btn =
                '' +
                    '<button class="btn default date-range-toggle" type="button">' +
                    '   ' +
                    '</button>'
            '';

            self.append($(btn));

            $(this).daterangepicker({
                    opens: (App.isRTL() ? 'left' : 'right'),
                    format: 'DD.MM.YYYY',
                    separator: ' to ',
                    startDate: moment().subtract('days', 29),
                    endDate: moment()
                },
                function (start, end) {
                    var daterangeStart = self.parent().find('.' + selfClass.params.daterangeStartClass);
                    var daterangeEnd = self.parent().find('.' + selfClass.params.daterangeEndClass);

                    daterangeStart.val(start.format('DD.MM.YYYY'));
                    daterangeEnd.val(end.format('DD.MM.YYYY'));

                    self.find('input').val(start.format('DD.MM.YYYY') + ' - ' + end.format('DD.MM.YYYY'));

                    if ($form.hasClass(selfClass.params.shortFormClass))
                    {
                        $form.trigger('change');
                    }
                }
            );
        });
    }

    ITDoorsAjax.prototype.initDateRangeCustom = function()
    {
        var selfClass = this;

        if (!jQuery().daterangepicker) {
            return;
        }

        $('.' + selfClass.params.daterangeCustomClass).each(function(index) {
            var self = $(this);

            var $form = self.closest('form');

            var btn =
                '' +
                    '<button class="btn default date-range-toggle" type="button">' +
                    '   ' +
                    '</button>'
                '';

            self.append($(btn));

            $(this).daterangepicker({
                    opens:  'right',
                    startDate: moment().subtract('days', 29),
                    endDate: moment(),
                    dateLimit: {
                        days: 60
                    },
                    showDropdowns: false,
                    showWeekNumbers: true,
                    timePicker: false,
                    timePickerIncrement: 1,
                    timePicker12Hour: true,
                    ranges: {
                        'Сегодня': [moment(), moment()],
                        'Вчера': [moment().subtract('days', 1), moment().subtract('days', 1)],
                        'Последняя неделя': [moment().subtract('days', 6), moment()],
                        'Последние 30 дней': [moment().subtract('days', 29), moment()],
                        'Текущий месяц': [moment().startOf('month'), moment().endOf('month')],
                        'Предыдущий месяц': [moment().subtract('month', 1).startOf('month'), moment().subtract('month', 1).endOf('month')]
                    },
                    buttonClasses: ['btn'],
                    applyClass: 'blue',
                    cancelClass: 'default',
                    format: 'MM/DD/YYYY',
                    separator: ' до ',
                    language: 'ru',
                    locale: {
                        applyLabel: 'Принять',
                        fromLabel: 'До',
                        toLabel: 'С',
                        customRangeLabel: 'Выберите интервал',
                        daysOfWeek: ["Вс","Пн","Вт","Ср","Чт","Пт","Сб"],
                        monthNames: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],
                        firstDay: 1
                    }
                },
                function (start, end) {
                    var daterangeStart = self.parent().find('.' + selfClass.params.daterangeStartClass);
                    var daterangeEnd = self.parent().find('.' + selfClass.params.daterangeEndClass);

                    daterangeStart.val(start.format('DD.MM.YYYY'));
                    daterangeEnd.val(end.format('DD.MM.YYYY'));

                    self.find('input').val(start.format('DD.MM.YYYY') + ' - ' + end.format('DD.MM.YYYY'));

                    if ($form.hasClass(selfClass.params.shortFormClass))
                    {
                        $form.trigger('change');
                    }
                }
            );

            self.find('input').html(moment().subtract('days', 29).format('MMMM D, YYYY') + ' - ' + moment().format('MMMM D, YYYY'));
            $(this).show();
        });
    }

    ITDoorsAjax.prototype.updateList = function(targetId)
    {
        var selfClass = this;

        var target = $('#' + targetId);

        var url = target.data('url');
        var params = target.data('params');

        $.ajax({
            type: 'POST',
            url: url,
            data: params,
            beforeSend: function () {
                selfClass.blockUI(target);
            },
            success: function (response) {
                target.html(response);
                selfClass.unblockUI(target);
            }
        });
    }

    ITDoorsAjax.prototype.blockUI = function (el, centerY) {
        var selfClass = this;

        if (el.height() <= 400) {
            centerY = true;
        }
        el.block({
            message: '',
            centerY: centerY != undefined ? centerY : true,
            css: {
                top: '10%',
                border: 'none',
                padding: '2px',
                backgroundColor: 'none'
            },
            overlayCSS: {
                backgroundColor: '#FFF',
                opacity: 0.5,
                cursor: 'wait'
            }
        });
    };

    // wrapper function to  un-block element(finish loading)
    ITDoorsAjax.prototype.unblockUI = function (el, clean) {
        el.css('position', '');
        el.css('zoom', '');
        el.unblock();
    };

    ITDoorsAjax.prototype.select2 = function (selector, defaultParams){

        var $selector = $(selector);

        if (!defaultParams)
        {
            defaultParams = {};
        }

        if (!$selector.length)
        {
            return false;
        }

        if (!$.isFunction($.fn.select2))
        {
            return false;
        }

        var url = $selector.data('url');
        var urlById = $selector.data('url-by-id');

        var selectorParams = $selector.data('params');

        var params = $.extend({
            minimumInputLength: 2,
            allowClear: true
        }, selectorParams);

        params = $.extend(params, defaultParams);

        if (url)
        {
            params.ajax = {
                url: url,
                dataType: 'json',
                data: function (term, page) {
                    return {
                        query: term,
                        q: term
                    };
                },
                results: function (data, page) {
                    return {
                        results: data
                    };
                }
            }
        }

        if (urlById)
        {
            params.initSelection = function (element, callback) {
                var id = $(element).val();
                if (id !== "") {
                    $.ajax(urlById, {
                        data: {
                            id: id
                        },
                        dataType: "json"
                    }).done(function (data) {
                        callback(data)
                    });
                }
            }
        }

        $selector.select2(params);
    }

    ITDoorsAjax.prototype.resetForm = function(form)
    {
        var selfClass = this;

        form.find('.' + selfClass.params.canBeResetedClass).each(function(index){
            if ($(this).hasClass(selfClass.params.select2Class))
            {
                $(this).select2('data', null);
            }

            if ($(this).hasClass(selfClass.params.daterangeStartClass) ||
                $(this).hasClass(selfClass.params.daterangeEndClass) ||
                $(this).hasClass(selfClass.params.daterangeTextClass))
            {
                $(this).val('');
            }

            if ($(this).attr('type') == 'checkbox')
            {
                if ($(this).is(':checked'))
                {
                    $(this).trigger('click');
                }
            }
        });
    }

    ITDoorsAjax.prototype.initAjaxFilterForm = function()
    {
        var selfClass = this;

        var $form = $('.' + selfClass.params.ajaxFilterFormClass)

        $('.' + selfClass.params.ajaxFilterFormClass + ' .itdoors-filter-cancel-btn').live('click', function(e){
            e.preventDefault();

            var resetField = $form.find('.ajax-form-reset-field');

            selfClass.resetForm($form);

            resetField.val(1);

            $form.submit();

            resetField.val(0);
        });

        $form.live('submit', function(e){

            e.preventDefault();

            var self = $(this);

            $(this).ajaxSubmit({
                dataType: 'json',
                beforeSend: function () {

                    selfClass.blockUI(self);
                },
                success: function(response) {

                    selfClass.unblockUI(self);

                    if (response.error)
                    {
                        return;
                    }

                    if (response.success)
                    {
                        if (response.successFunctions){
                            var successFunctions = JSON.parse(response.successFunctions);

                            for (key in successFunctions) {
                                var successFunction = successFunctions[key].split('.');

                                if (successFunction[0] && successFunction[1]) {
                                    if (window[successFunction[0]] && typeof window[successFunction[0]][successFunction[1]] === 'function'){
                                        formok = window[successFunction[0]][successFunction[1]](key);
                                    }
                                }
                                else {
                                    if (typeof window[successFunctions[key]] === 'function'){
                                        formok = window[successFunctions[key]](key);
                                    }
                                }
                            }
                        }
                    }
                }
            });
        });

        var $formShort = $('.' + selfClass.params.ajaxFilterFormClass + '.' + selfClass.params.shortFormClass).live('change', function(){
            $(this).submit();
        });
    };

    return new ITDoorsAjax();
})();<commit_msg>add choices to select 2<commit_after>var ITDoorsAjax = (function() {

    var defaults = {
        ajaxFilterFormClass: 'ajax-filter-form',
        shortFormClass: 'itdoors-short-form',
        canBeResetedClass: 'can-be-reseted',
        select2Class: 'itdoors-select2',
        daterangeClass: 'itdoors-daterange',
        daterangeCustomClass: 'itdoors-daterange-custom',
        daterangeTextClass: 'itdoors-daterange-text',
        daterangeStartClass: 'itdoors-daterange-start',
        daterangeEndClass: 'itdoors-daterange-end',
        assetsDir: '',
        loadingImgPath: ''
    };

    function ITDoorsAjax(){
        this.params = {};
    };

    ITDoorsAjax.prototype.init = function(options)
    {
        this.params = $.extend(defaults, options);

        this.params.loadingImgPath = this.params.assetsDir + 'templates/metronic/img/ajax-loading.gif';

        this.initAjaxFilterForm();

        this.initSelect2();

        this.initDateRange();

        this.initDateRangeCustom();
    }

    ITDoorsAjax.prototype.initSelect2 = function()
    {
        if (!jQuery().select2) {
            return;
        }

        var selfClass = this;

        $('.' + selfClass.params.select2Class).each(function(index) {
            selfClass.select2($(this));
        });
    }

    ITDoorsAjax.prototype.initDateRange = function()
    {
        var selfClass = this;

        if (!jQuery().daterangepicker) {
            return;
        }

        $('.' + selfClass.params.daterangeClass).each(function(index) {
            var self = $(this);

            var $form = self.closest('form');

            var btn =
                '' +
                    '<button class="btn default date-range-toggle" type="button">' +
                    '   ' +
                    '</button>'
            '';

            self.append($(btn));

            $(this).daterangepicker({
                    opens: (App.isRTL() ? 'left' : 'right'),
                    format: 'DD.MM.YYYY',
                    separator: ' to ',
                    startDate: moment().subtract('days', 29),
                    endDate: moment()
                },
                function (start, end) {
                    var daterangeStart = self.parent().find('.' + selfClass.params.daterangeStartClass);
                    var daterangeEnd = self.parent().find('.' + selfClass.params.daterangeEndClass);

                    daterangeStart.val(start.format('DD.MM.YYYY'));
                    daterangeEnd.val(end.format('DD.MM.YYYY'));

                    self.find('input').val(start.format('DD.MM.YYYY') + ' - ' + end.format('DD.MM.YYYY'));

                    if ($form.hasClass(selfClass.params.shortFormClass))
                    {
                        $form.trigger('change');
                    }
                }
            );
        });
    }

    ITDoorsAjax.prototype.initDateRangeCustom = function()
    {
        var selfClass = this;

        if (!jQuery().daterangepicker) {
            return;
        }

        $('.' + selfClass.params.daterangeCustomClass).each(function(index) {
            var self = $(this);

            var $form = self.closest('form');

            var btn =
                '' +
                    '<button class="btn default date-range-toggle" type="button">' +
                    '   ' +
                    '</button>'
                '';

            self.append($(btn));

            $(this).daterangepicker({
                    opens:  'right',
                    startDate: moment().subtract('days', 29),
                    endDate: moment(),
                    dateLimit: {
                        days: 60
                    },
                    showDropdowns: false,
                    showWeekNumbers: true,
                    timePicker: false,
                    timePickerIncrement: 1,
                    timePicker12Hour: true,
                    ranges: {
                        'Сегодня': [moment(), moment()],
                        'Вчера': [moment().subtract('days', 1), moment().subtract('days', 1)],
                        'Последняя неделя': [moment().subtract('days', 6), moment()],
                        'Последние 30 дней': [moment().subtract('days', 29), moment()],
                        'Текущий месяц': [moment().startOf('month'), moment().endOf('month')],
                        'Предыдущий месяц': [moment().subtract('month', 1).startOf('month'), moment().subtract('month', 1).endOf('month')]
                    },
                    buttonClasses: ['btn'],
                    applyClass: 'blue',
                    cancelClass: 'default',
                    format: 'MM/DD/YYYY',
                    separator: ' до ',
                    language: 'ru',
                    locale: {
                        applyLabel: 'Принять',
                        fromLabel: 'До',
                        toLabel: 'С',
                        customRangeLabel: 'Выберите интервал',
                        daysOfWeek: ["Вс","Пн","Вт","Ср","Чт","Пт","Сб"],
                        monthNames: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],
                        firstDay: 1
                    }
                },
                function (start, end) {
                    var daterangeStart = self.parent().find('.' + selfClass.params.daterangeStartClass);
                    var daterangeEnd = self.parent().find('.' + selfClass.params.daterangeEndClass);

                    daterangeStart.val(start.format('DD.MM.YYYY'));
                    daterangeEnd.val(end.format('DD.MM.YYYY'));

                    self.find('input').val(start.format('DD.MM.YYYY') + ' - ' + end.format('DD.MM.YYYY'));

                    if ($form.hasClass(selfClass.params.shortFormClass))
                    {
                        $form.trigger('change');
                    }
                }
            );

            self.find('input').html(moment().subtract('days', 29).format('MMMM D, YYYY') + ' - ' + moment().format('MMMM D, YYYY'));
            $(this).show();
        });
    }

    ITDoorsAjax.prototype.updateList = function(targetId)
    {
        var selfClass = this;

        var target = $('#' + targetId);

        var url = target.data('url');
        var params = target.data('params');

        $.ajax({
            type: 'POST',
            url: url,
            data: params,
            beforeSend: function () {
                selfClass.blockUI(target);
            },
            success: function (response) {
                target.html(response);
                selfClass.unblockUI(target);
            }
        });
    }

    ITDoorsAjax.prototype.blockUI = function (el, centerY) {
        var selfClass = this;

        if (el.height() <= 400) {
            centerY = true;
        }
        el.block({
            message: '',
            centerY: centerY != undefined ? centerY : true,
            css: {
                top: '10%',
                border: 'none',
                padding: '2px',
                backgroundColor: 'none'
            },
            overlayCSS: {
                backgroundColor: '#FFF',
                opacity: 0.5,
                cursor: 'wait'
            }
        });
    };

    // wrapper function to  un-block element(finish loading)
    ITDoorsAjax.prototype.unblockUI = function (el, clean) {
        el.css('position', '');
        el.css('zoom', '');
        el.unblock();
    };

    ITDoorsAjax.prototype.select2 = function (selector, defaultParams){

        var $selector = $(selector);

        if (!defaultParams)
        {
            defaultParams = {};
        }

        if (!$selector.length)
        {
            return false;
        }

        if (!$.isFunction($.fn.select2))
        {
            return false;
        }

        var url = $selector.data('url');
        var urlById = $selector.data('url-by-id');

        var selectorParams = $selector.data('params');

        var params = $.extend({
            minimumInputLength: 2,
            allowClear: true
        }, selectorParams);

        params = $.extend(params, defaultParams);

        var choices = $selector.data('choices');

        if (choices) {
            params.data = choices;
        }

        if (url)
        {
            params.ajax = {
                url: url,
                dataType: 'json',
                data: function (term, page) {
                    return {
                        query: term,
                        q: term
                    };
                },
                results: function (data, page) {
                    return {
                        results: data
                    };
                }
            }
        }

        if (urlById)
        {
            params.initSelection = function (element, callback) {
                var id = $(element).val();
                if (id !== "") {
                    $.ajax(urlById, {
                        data: {
                            id: id
                        },
                        dataType: "json"
                    }).done(function (data) {
                        callback(data)
                    });
                }
            }
        }

        $selector.select2(params);
    }

    ITDoorsAjax.prototype.resetForm = function(form)
    {
        var selfClass = this;

        form.find('.' + selfClass.params.canBeResetedClass).each(function(index){
            if ($(this).hasClass(selfClass.params.select2Class))
            {
                $(this).select2('data', null);
            }

            if ($(this).hasClass(selfClass.params.daterangeStartClass) ||
                $(this).hasClass(selfClass.params.daterangeEndClass) ||
                $(this).hasClass(selfClass.params.daterangeTextClass))
            {
                $(this).val('');
            }

            if ($(this).attr('type') == 'checkbox')
            {
                if ($(this).is(':checked'))
                {
                    $(this).trigger('click');
                }
            }
        });
    }

    ITDoorsAjax.prototype.initAjaxFilterForm = function()
    {
        var selfClass = this;

        var $form = $('.' + selfClass.params.ajaxFilterFormClass)

        $('.' + selfClass.params.ajaxFilterFormClass + ' .itdoors-filter-cancel-btn').live('click', function(e){
            e.preventDefault();

            var resetField = $form.find('.ajax-form-reset-field');

            selfClass.resetForm($form);

            resetField.val(1);

            $form.submit();

            resetField.val(0);
        });

        $form.live('submit', function(e){

            e.preventDefault();

            var self = $(this);

            $(this).ajaxSubmit({
                dataType: 'json',
                beforeSend: function () {

                    selfClass.blockUI(self);
                },
                success: function(response) {

                    selfClass.unblockUI(self);

                    if (response.error)
                    {
                        return;
                    }

                    if (response.success)
                    {
                        if (response.successFunctions){
                            var successFunctions = JSON.parse(response.successFunctions);

                            for (key in successFunctions) {
                                var successFunction = successFunctions[key].split('.');

                                if (successFunction[0] && successFunction[1]) {
                                    if (window[successFunction[0]] && typeof window[successFunction[0]][successFunction[1]] === 'function'){
                                        formok = window[successFunction[0]][successFunction[1]](key);
                                    }
                                }
                                else {
                                    if (typeof window[successFunctions[key]] === 'function'){
                                        formok = window[successFunctions[key]](key);
                                    }
                                }
                            }
                        }
                    }
                }
            });
        });

        var $formShort = $('.' + selfClass.params.ajaxFilterFormClass + '.' + selfClass.params.shortFormClass).live('change', function(){
            $(this).submit();
        });
    };

    return new ITDoorsAjax();
})();<|endoftext|>


<commit_before>/**
@class
@name chunkFeature
@extends $.ui.chunk
@memberOf $.ui
*/
$.widget('ui.chunkFeature', $.ui.chunk,
	/**
	@lends $.ui.chunkFeature
	*/
	{

	_bind : function() {
		if (this.options.id > 0) {
			this.dialog.contents.find('input[name=parent_id]').val(this.options.id);

			var button = $('<button />')
				.addClass('b-button ui-helper-left')
				.text('Remove')
				.button({
					icons: {primary : 'b-button-icon b-button-icon-delete'}
				})
				.click(function() {
					this.remove();
					this.dialog.close();
				});

			this.dialog.contents.dialog('widget')
				.find('.ui-dialog-buttonpane')
				.prepend(button);
		}
	},

	edit : function() {
		var featureEditor = this;

		this.confirmation = new boomDialog({
			title : 'Edit feature?',
			msg : '
You clicked on a feature box.

Do you want to visit the featured page or edit the feature?
',
			closeButton : false,
			buttons : [
				{
					text : 'Visit page',
					class : 'b-button b-button-textonly',
					click : function() {
						featureEditor.viewTarget();
					}
				},
				{
					text : 'Edit feature',
					class : 'b-button b-button-textonly',
					click : function() {
						featureEditor.editTarget();
					}
				}
			]
		})
		.fail(function() {
			featureEditor.bind();
		});
	},

	editTarget : function() {
		var featureEditor = this;

		$.boom.log('Feature chunk slot edit');

		this.dialog = new boomDialog({
			url: '/cms/chunk/feature/edit/' + this.options.currentPage.id,
			width: 400,
			closeButton : false,
			position : {my: "bottom", at: "center", of: window},
			title: 'Page feature',
			onLoad : function() {
				featureEditor.confirmation && featureEditor.confirmation.close();

				featureEditor.dialog.contents.find('.boom-tree').pageTree({
					onPageSelect : function(page) {
						featureEditor.insert(page.page_id);
						featureEditor.dialog.close();
					}
				});
			},
			open: function() {
				featureEditor._bind();
			}
		})
		.fail(function() {
			featureEditor.bind();
		});
	},

	/**
	Get the RID for this feature box.
	@returns {Int} Page RID
	*/
	getData: function(){
		return {target_page_id : this.options.id};
	},

	getTargetUrl : function() {
		return this.element.is('a')? this.element.attr('href') : this.element.find('a').attr('href');
	},

	/**
	Insert the selected page into the DOM as a feature box.
	@param {Int} rid Page RID
	*/
	insert : function(rid){
		this.options.id = rid;

		return this._save();
	},

	viewTarget : function() {
		top.window.location = this.getTargetUrl();
	}
});<commit_msg>If feature box doesn't have a target then don't ask if user wants to view target<commit_after>/**
@class
@name chunkFeature
@extends $.ui.chunk
@memberOf $.ui
*/
$.widget('ui.chunkFeature', $.ui.chunk,
	/**
	@lends $.ui.chunkFeature
	*/
	{

	_bind : function() {
		if (this.options.id > 0) {
			this.dialog.contents.find('input[name=parent_id]').val(this.options.id);

			var button = $('<button />')
				.addClass('b-button ui-helper-left')
				.text('Remove')
				.button({
					icons: {primary : 'b-button-icon b-button-icon-delete'}
				})
				.click(function() {
					this.remove();
					this.dialog.close();
				});

			this.dialog.contents.dialog('widget')
				.find('.ui-dialog-buttonpane')
				.prepend(button);
		}
	},

	edit : function() {
		var featureEditor = this;

		if (this.getTargetUrl()) {
			this.confirmation = new boomDialog({
				title : 'Edit feature?',
				msg : '
You clicked on a feature box.

Do you want to visit the featured page or edit the feature?
',
				closeButton : false,
				buttons : [
					{
						text : 'Visit page',
						class : 'b-button b-button-textonly',
						click : function() {
							featureEditor.viewTarget();
						}
					},
					{
						text : 'Edit feature',
						class : 'b-button b-button-textonly',
						click : function() {
							featureEditor.editTarget();
						}
					}
				]
			})
			.fail(function() {
				featureEditor.bind();
			});
		} else {
			this.editTarget();
		}
	},

	editTarget : function() {
		var featureEditor = this;

		$.boom.log('Feature chunk slot edit');

		this.dialog = new boomDialog({
			url: '/cms/chunk/feature/edit/' + this.options.currentPage.id,
			width: 400,
			closeButton : false,
			position : {my: "bottom", at: "center", of: window},
			title: 'Page feature',
			onLoad : function() {
				featureEditor.confirmation && featureEditor.confirmation.close();

				featureEditor.dialog.contents.find('.boom-tree').pageTree({
					onPageSelect : function(page) {
						featureEditor.insert(page.page_id);
						featureEditor.dialog.close();
					}
				});
			},
			open: function() {
				featureEditor._bind();
			}
		})
		.fail(function() {
			featureEditor.bind();
		});
	},

	/**
	Get the RID for this feature box.
	@returns {Int} Page RID
	*/
	getData: function(){
		return {target_page_id : this.options.id};
	},

	getTargetUrl : function() {
		return this.element.is('a')? this.element.attr('href') : this.element.find('a').attr('href');
	},

	/**
	Insert the selected page into the DOM as a feature box.
	@param {Int} rid Page RID
	*/
	insert : function(rid){
		this.options.id = rid;

		return this._save();
	},

	viewTarget : function() {
		top.window.location = this.getTargetUrl();
	}
});<|endoftext|>


<commit_before>var analyzer
examples.music = function (selection) {
  var numLines = 2000
  var s = d3.select(selection)
          .attr(size)
          .call(pathgl)

  var scale = Math.PI * 2 / numLines

  var midX = size.width / 2
  var midY = size.height / 2

  var audio = d3.select('.right').append('audio').attr('src', 'overture.mp3')

  var node = audio.on('play', initAudio).node()
  node.play()
  s.on('click', function () {
    node.currentTime = 65
  })

  var lines = s.selectAll('line').data(d3.range(numLines).map(function () { return {a: 0}}))
              .enter()
              .append('line')
              .attr({
                x1: size.width >> 1
              , y1: size.height >> 1
  , stroke: function () { return "hsl(" + Math.random() * 360 + ",100%, 50%)" }
  , x2: function (d, i) { return Math.cos(i * 2) * innerWidth }
  , y2: function (d, i) { return Math.sin(i * 2) * innerHeight }
  })
  //"hsl(" + Math.random() * 360 + ",100%, 50%)"
  window.x  = 0

  d3.timer(function () {
    if (! analyzer) return
    var byteFreq = new Uint8Array(analyzer.frequencyBinCount)

    analyzer.getByteFrequencyData(byteFreq)
    lines.each(function (d, i) {
      var freq  = byteFreq[i % 1024]
      d.diff = d.a - freq
      d.a = freq
    })
    .attr('stroke', function (d) { return "hsl(" + Math.abs(d.diff * 10 + 200) + ",100%, 50%)" })
    .attr('x2', function (d, i) { return midX + (Math.cos(i) * d.a) })
    .attr('y2', function (d, i) { return midY + (Math.sin(i) * d.a)})

    //s.node().style.background = "hsl(" + d3.sum(byteFreq) * 5 + ",100%, 50%)"
  })
  dropAndLoad(document.querySelector('.right'), initDnD, "ArrayBuffer")
}

function initAudio() {
  window.audio = this
  var audioContext = new webkitAudioContext();
  window.analyzer = audioContext.createAnalyser();
  var source = audioContext.createMediaElementSource(audio);
  source.connect(analyzer);
  analyzer.connect(audioContext.destination);
  audio.play();
}

function initDnD (arrayBuffer) {
  window.audioCtx = new webkitAudioContext()
  window.analyser = audioCtx.createAnalyser()

  if (window.source)
    source.noteOff(0)

  if (window.source)
    audio.stop()
  audioCtx.decodeAudioData(arrayBuffer, function(buffer) {

    window.source = audioCtx.createBufferSource()
    source.buffer = buffer

    source.connect(analyser)

    analyser.connect(audioCtx.destination)

    source.start(0)
    analyzer = analyser
  })
}

function dropAndLoad(dropElement, callback, readFormat) {
  var readFormat = readFormat || "DataUrl"

  dropElement.addEventListener('dragover', function(e) {
    e.stopPropagation()
    e.preventDefault()
    e.dataTransfer.dropEffect = 'copy'
  }, false)

  dropElement.addEventListener('drop', function(e) {
    e.stopPropagation()
    e.preventDefault()
    loadFile(e.dataTransfer.files[0])
  }, false)

  function loadFile(files) {
    var file = files
    var reader = new FileReader()
    reader.onload = function(e) {
      callback(e.target.result)
    }
    reader['readAs'+readFormat](file)
  }
}
<commit_msg>use both time and freq data in music vis<commit_after>var analyzer
examples.music = function (selection) {
  var numLines = 2048
  var s = d3.select(selection)
          .attr(size)
          .call(pathgl)

  var scale = Math.PI * 2 / numLines

  var midX = size.width / 2
  var midY = size.height / 2

  var audio = d3.select('.right').append('audio').attr('src', 'overture.mp3')

  var node = audio.on('play', initAudio).node()
  node.play()
  s.on('click', function () {
    node.currentTime = 65
  })

  var lines = s.selectAll('line').data(d3.range(numLines).map(function () { return {a: 0}}))
              .enter()
              .append('line')
              .attr({
                x1: size.width >> 1
              , y1: size.height >> 1
  , stroke: function () { return "hsl(" + Math.random() * 360 + ",100%, 50%)" }
  , x2: function (d, i) { return Math.cos(i * 2) * innerWidth }
  , y2: function (d, i) { return Math.sin(i * 2) * innerHeight }
  })
  //"hsl(" + Math.random() * 360 + ",100%, 50%)"

  d3.timer(function () {
    if (! analyzer) return
    var freqData = new Uint8Array(analyzer.frequencyBinCount)
    var timeData = new Uint8Array(analyzer.frequencyBinCount)

    analyzer.getByteTimeDomainData(timeData)
    analyzer.getByteFrequencyData(freqData)
    lines.each(function (d, i) {
      var freq  = (i > 1024 ? freqData : timeData)[i % 1024]
      d.diff = d.a - freq
      d.a = freq
    })
    .attr('stroke', function (d) { return "hsl(" + Math.abs(d.diff * 10 + 200) + ",100%, 50%)" })
    .attr('x2', function (d, i) { return midX + (Math.cos(i) * d.a) })
    .attr('y2', function (d, i) { return midY + (Math.sin(i) * d.a)})

    //s.node().style.background = "hsl(" + d3.sum(byteFreq) * 5 + ",100%, 50%)"
  })
  dropAndLoad(document.querySelector('.right'), initDnD, "ArrayBuffer")
}

function initAudio() {
  window.audio = this
  var audioContext = new webkitAudioContext();
  window.analyzer = audioContext.createAnalyser();
  var source = audioContext.createMediaElementSource(audio);
  source.connect(analyzer);
  analyzer.connect(audioContext.destination);
  audio.play();
}

function initDnD (arrayBuffer) {
  window.audioCtx = new webkitAudioContext()
  window.analyser = audioCtx.createAnalyser()

  if (window.source)
    source.noteOff(0)

  if (window.source)
    audio.stop()
  audioCtx.decodeAudioData(arrayBuffer, function(buffer) {

    window.source = audioCtx.createBufferSource()
    source.buffer = buffer

    source.connect(analyser)

    analyser.connect(audioCtx.destination)

    source.start(0)
    analyzer = analyser
  })
}

function dropAndLoad(dropElement, callback, readFormat) {
  var readFormat = readFormat || "DataUrl"

  dropElement.addEventListener('dragover', function(e) {
    e.stopPropagation()
    e.preventDefault()
    e.dataTransfer.dropEffect = 'copy'
  }, false)

  dropElement.addEventListener('drop', function(e) {
    e.stopPropagation()
    e.preventDefault()
    loadFile(e.dataTransfer.files[0])
  }, false)

  function loadFile(files) {
    var file = files
    var reader = new FileReader()
    reader.onload = function(e) {
      callback(e.target.result)
    }
    reader['readAs'+readFormat](file)
  }
}
<|endoftext|>


<commit_before>import Renderer from './Renderer';
import marks from './marks/index';
import {domChild, domClear, domCreate, cssClass} from './util/dom';
import {openTag, closeTag} from './util/tags';
import {font, textValue} from './util/text';
import {visit} from './util/visit';
import clip from './util/svg/clip';
import metadata from './util/svg/metadata';
import {styles, styleProperties} from './util/svg/styles';
import {inherits} from 'vega-util';

var ns = metadata.xmlns;

export default function SVGRenderer(loader) {
  Renderer.call(this, loader);
  this._dirtyID = 1;
  this._dirty = [];
  this._svg = null;
  this._root = null;
  this._defs = null;
}

var prototype = inherits(SVGRenderer, Renderer);
var base = Renderer.prototype;

prototype.initialize = function(el, width, height, padding) {
  if (el) {
    this._svg = domChild(el, 0, 'svg', ns);
    this._svg.setAttribute('class', 'marks');
    domClear(el, 1);
    // set the svg root group
    this._root = domChild(this._svg, 0, 'g', ns);
    domClear(this._svg, 1);
  }

  // create the svg definitions cache
  this._defs = {
    gradient: {},
    clipping: {}
  };

  // set background color if defined
  this.background(this._bgcolor);

  return base.initialize.call(this, el, width, height, padding);
};

prototype.background = function(bgcolor) {
  if (arguments.length && this._svg) {
    this._svg.style.setProperty('background-color', bgcolor);
  }
  return base.background.apply(this, arguments);
};

prototype.resize = function(width, height, origin) {
  base.resize.call(this, width, height, origin);

  if (this._svg) {
    this._svg.setAttribute('width', this._width);
    this._svg.setAttribute('height', this._height);
    this._svg.setAttribute('viewBox', '0 0 ' + this._width + ' ' + this._height);
    this._root.setAttribute('transform', 'translate(' + this._origin + ')');
  }

  this._dirty = [];

  return this;
};

prototype.svg = function() {
  if (!this._svg) return null;

  var attr = {
    'class':  'marks',
    'width':  this._width,
    'height': this._height,
    'viewBox': '0 0 ' + this._width + ' ' + this._height
  };
  for (var key in metadata) {
    attr[key] = metadata[key];
  }

  return openTag('svg', attr) + this._svg.innerHTML + closeTag('svg');
};

// -- Render entry point --

prototype._render = function(scene) {
  // perform spot updates and re-render markup
  if (this._dirtyCheck()) {
    if (this._dirtyAll) this._resetDefs();
    this.draw(this._root, scene);
    domClear(this._root, 1);
  }

  this.updateDefs();

  this._dirty = [];
  ++this._dirtyID;

  return this;
};

// -- Manage SVG definitions ('defs') block --

prototype.updateDefs = function() {
  var svg = this._svg,
      defs = this._defs,
      el = defs.el,
      index = 0, id;

  for (id in defs.gradient) {
    if (!el) defs.el = (el = domChild(svg, 0, 'defs', ns));
    updateGradient(el, defs.gradient[id], index++);
  }

  for (id in defs.clipping) {
    if (!el) defs.el = (el = domChild(svg, 0, 'defs', ns));
    updateClipping(el, defs.clipping[id], index++);
  }

  // clean-up
  if (el) {
    if (index === 0) {
      svg.removeChild(el);
      defs.el = null;
    } else {
      domClear(el, index);
    }
  }
};

function updateGradient(el, grad, index) {
  var i, n, stop;

  el = domChild(el, index, 'linearGradient', ns);
  el.setAttribute('id', grad.id);
  el.setAttribute('x1', grad.x1);
  el.setAttribute('x2', grad.x2);
  el.setAttribute('y1', grad.y1);
  el.setAttribute('y2', grad.y2);

  for (i=0, n=grad.stops.length; i<n; ++i) {
    stop = domChild(el, i, 'stop', ns);
    stop.setAttribute('offset', grad.stops[i].offset);
    stop.setAttribute('stop-color', grad.stops[i].color);
  }
  domClear(el, i);
}

function updateClipping(el, clip, index) {
  var rect;

  el = domChild(el, index, 'clipPath', ns);
  el.setAttribute('id', clip.id);
  rect = domChild(el, 0, 'rect', ns);
  rect.setAttribute('x', 0);
  rect.setAttribute('y', 0);
  rect.setAttribute('width', clip.width);
  rect.setAttribute('height', clip.height);
}

prototype._resetDefs = function() {
  var def = this._defs;
  def.gradient = {};
  def.clipping = {};
};

// -- Manage rendering of items marked as dirty --

prototype.dirty = function(item) {
  if (item.dirty !== this._dirtyID) {
    item.dirty = this._dirtyID;
    this._dirty.push(item);
  }
};

prototype.isDirty = function(item) {
  return this._dirtyAll
    || !item._svg
    || item.dirty === this._dirtyID;
};

prototype._dirtyCheck = function() {
  this._dirtyAll = true;
  var items = this._dirty;
  if (!items.length) return true;

  var id = ++this._dirtyID,
      item, mark, type, mdef, i, n, o;

  for (i=0, n=items.length; i<n; ++i) {
    item = items[i];
    mark = item.mark;

    if (mark.marktype !== type) {
      // memoize mark instance lookup
      type = mark.marktype;
      mdef = marks[type];
    }

    if (mark.zdirty && mark.dirty !== id) {
      this._dirtyAll = false;
      mark.dirty = id;
      dirtyParents(mark.group, id);
    }

    if (item.exit) { // EXIT
      if (mdef.nested && mark.items.length) {
        // if nested mark with remaining points, update instead
        o = mark.items[0];
        if (o._svg) this._update(mdef, o._svg, o);
      } else if (item._svg) {
        // otherwise remove from DOM
        item._svg.parentNode.removeChild(item._svg);
      }
      item._svg = null;
      continue;
    }

    item = (mdef.nested ? mark.items[0] : item);
    if (item._update === id) continue; // already visited

    if (!item._svg || !item._svg.ownerSVGElement) {
      // ENTER
      this._dirtyAll = false;
      dirtyParents(item, id);
    } else {
      // IN-PLACE UPDATE
      this._update(mdef, item._svg, item);
    }
    item._update = id;
  }
  return !this._dirtyAll;
};

function dirtyParents(item, id) {
  for (; item && item.dirty !== id; item=item.mark.group) {
    item.dirty = id;
    if (item.mark && item.mark.dirty !== id) {
      item.mark.dirty = id;
    } else return;
  }
}

// -- Construct & maintain scenegraph to SVG mapping ---

// Draw a mark container.
prototype.draw = function(el, scene, prev) {
  if (!this.isDirty(scene)) return scene._svg;

  var renderer = this,
      mdef = marks[scene.marktype],
      events = scene.interactive === false ? 'none' : null,
      isGroup = mdef.tag === 'g',
      sibling = null,
      i = 0,
      parent;

  parent = bind(scene, el, prev, 'g');
  parent.setAttribute('class', cssClass(scene));
  if (!isGroup && events) {
    parent.style.setProperty('pointer-events', events);
  }
  if (scene.clip) {
    parent.setAttribute('clip-path', clip(renderer, scene, scene.group));
  }

  function process(item) {
    var dirty = renderer.isDirty(item),
        node = bind(item, parent, sibling, mdef.tag);

    if (dirty) {
      renderer._update(mdef, node, item);
      if (isGroup) recurse(renderer, node, item);
    }

    sibling = node;
    ++i;
  }

  if (mdef.nested) {
    if (scene.items.length) process(scene.items[0]);
  } else {
    visit(scene, process);
  }

  domClear(parent, i);
  return parent;
};

// Recursively process group contents.
function recurse(renderer, el, group) {
  el = el.lastChild;
  var prev, idx = 0;

  visit(group, function(item) {
    prev = renderer.draw(el, item, prev);
    ++idx;
  });

  // remove any extraneous DOM elements
  domClear(el, 1 + idx);
}

// Bind a scenegraph item to an SVG DOM element.
// Create new SVG elements as needed.
function bind(item, el, sibling, tag) {
  var node = item._svg, doc;

  // create a new dom node if needed
  if (!node) {
    doc = el.ownerDocument;
    node = domCreate(doc, tag, ns);
    item._svg = node;

    if (item.mark) {
      node.__data__ = item;
      node.__values__ = {fill: 'default'};

      // if group, create background and foreground elements
      if (tag === 'g') {
        var bg = domCreate(doc, 'path', ns);
        bg.setAttribute('class', 'background');
        node.appendChild(bg);
        bg.__data__ = item;

        var fg = domCreate(doc, 'g', ns);
        node.appendChild(fg);
        fg.__data__ = item;
      }
    }
  }

  if (doc || node.previousSibling !== sibling) {
    el.insertBefore(node, sibling ? sibling.nextSibling : el.firstChild);
  }

  return node;
}

// -- Set attributes & styles on SVG elements ---

var element = null, // temp var for current SVG element
    values = null;  // temp var for current values hash

// Extra configuration for certain mark types
var mark_extras = {
  group: function(mdef, el, item) {
    values = el.__values__; // use parent's values hash

    element = el.childNodes[1];
    mdef.foreground(emit, item, this);

    element = el.childNodes[0];
    mdef.background(emit, item, this);

    var value = item.mark.interactive === false ? 'none' : null;
    if (value !== values.events) {
      element.style.setProperty('pointer-events', value);
      values.events = value;
    }
  },
  text: function(mdef, el, item) {
    var str = textValue(item);
    if (str !== values.text) {
      el.textContent = str;
      values.text = str;
    }
    str = font(item);
    if (str !== values.font) {
      el.style.setProperty('font', str);
      values.font = str;
    }
  }
};

prototype._update = function(mdef, el, item) {
  // set dom element and values cache
  // provides access to emit method
  element = el;
  values = el.__values__;

  // apply svg attributes
  mdef.attr(emit, item, this);

  // some marks need special treatment
  var extra = mark_extras[mdef.type];
  if (extra) extra.call(this, mdef, el, item);

  // apply svg css styles
  // note: element may be modified by 'extra' method
  this.style(element, item);
};

function emit(name, value, ns) {
  // early exit if value is unchanged
  if (value === values[name]) return;

  if (value != null) {
    // if value is provided, update DOM attribute
    if (ns) {
      element.setAttributeNS(ns, name, value);
    } else {
      element.setAttribute(name, value);
    }
  } else {
    // else remove DOM attribute
    if (ns) {
      element.removeAttributeNS(ns, name);
    } else {
      element.removeAttribute(name);
    }
  }

  // note current value for future comparison
  values[name] = value;
}

prototype.style = function(el, o) {
  if (o == null) return;
  var i, n, prop, name, value;

  for (i=0, n=styleProperties.length; i<n; ++i) {
    prop = styleProperties[i];
    value = o[prop];
    if (value === values[prop]) continue;

    name = styles[prop];
    if (value == null) {
      if (name === 'fill') {
        el.style.setProperty(name, 'none');
      } else {
        el.style.removeProperty(name);
      }
    } else {
      if (value.id) {
        // ensure definition is included
        this._defs.gradient[value.id] = value;
        value = 'url(' + href() + '#' + value.id + ')';
      }
      el.style.setProperty(name, value+'');
    }

    values[prop] = value;
  }
};

function href() {
  return typeof window !== 'undefined' ? window.location.href : '';
}
<commit_msg>Fix issue in svg node binding<commit_after>import Renderer from './Renderer';
import marks from './marks/index';
import {domChild, domClear, domCreate, cssClass} from './util/dom';
import {openTag, closeTag} from './util/tags';
import {font, textValue} from './util/text';
import {visit} from './util/visit';
import clip from './util/svg/clip';
import metadata from './util/svg/metadata';
import {styles, styleProperties} from './util/svg/styles';
import {inherits} from 'vega-util';

var ns = metadata.xmlns;

export default function SVGRenderer(loader) {
  Renderer.call(this, loader);
  this._dirtyID = 1;
  this._dirty = [];
  this._svg = null;
  this._root = null;
  this._defs = null;
}

var prototype = inherits(SVGRenderer, Renderer);
var base = Renderer.prototype;

prototype.initialize = function(el, width, height, padding) {
  if (el) {
    this._svg = domChild(el, 0, 'svg', ns);
    this._svg.setAttribute('class', 'marks');
    domClear(el, 1);
    // set the svg root group
    this._root = domChild(this._svg, 0, 'g', ns);
    domClear(this._svg, 1);
  }

  // create the svg definitions cache
  this._defs = {
    gradient: {},
    clipping: {}
  };

  // set background color if defined
  this.background(this._bgcolor);

  return base.initialize.call(this, el, width, height, padding);
};

prototype.background = function(bgcolor) {
  if (arguments.length && this._svg) {
    this._svg.style.setProperty('background-color', bgcolor);
  }
  return base.background.apply(this, arguments);
};

prototype.resize = function(width, height, origin) {
  base.resize.call(this, width, height, origin);

  if (this._svg) {
    this._svg.setAttribute('width', this._width);
    this._svg.setAttribute('height', this._height);
    this._svg.setAttribute('viewBox', '0 0 ' + this._width + ' ' + this._height);
    this._root.setAttribute('transform', 'translate(' + this._origin + ')');
  }

  this._dirty = [];

  return this;
};

prototype.svg = function() {
  if (!this._svg) return null;

  var attr = {
    'class':  'marks',
    'width':  this._width,
    'height': this._height,
    'viewBox': '0 0 ' + this._width + ' ' + this._height
  };
  for (var key in metadata) {
    attr[key] = metadata[key];
  }

  return openTag('svg', attr) + this._svg.innerHTML + closeTag('svg');
};

// -- Render entry point --

prototype._render = function(scene) {
  // perform spot updates and re-render markup
  if (this._dirtyCheck()) {
    if (this._dirtyAll) this._resetDefs();
    this.draw(this._root, scene);
    domClear(this._root, 1);
  }

  this.updateDefs();

  this._dirty = [];
  ++this._dirtyID;

  return this;
};

// -- Manage SVG definitions ('defs') block --

prototype.updateDefs = function() {
  var svg = this._svg,
      defs = this._defs,
      el = defs.el,
      index = 0, id;

  for (id in defs.gradient) {
    if (!el) defs.el = (el = domChild(svg, 0, 'defs', ns));
    updateGradient(el, defs.gradient[id], index++);
  }

  for (id in defs.clipping) {
    if (!el) defs.el = (el = domChild(svg, 0, 'defs', ns));
    updateClipping(el, defs.clipping[id], index++);
  }

  // clean-up
  if (el) {
    if (index === 0) {
      svg.removeChild(el);
      defs.el = null;
    } else {
      domClear(el, index);
    }
  }
};

function updateGradient(el, grad, index) {
  var i, n, stop;

  el = domChild(el, index, 'linearGradient', ns);
  el.setAttribute('id', grad.id);
  el.setAttribute('x1', grad.x1);
  el.setAttribute('x2', grad.x2);
  el.setAttribute('y1', grad.y1);
  el.setAttribute('y2', grad.y2);

  for (i=0, n=grad.stops.length; i<n; ++i) {
    stop = domChild(el, i, 'stop', ns);
    stop.setAttribute('offset', grad.stops[i].offset);
    stop.setAttribute('stop-color', grad.stops[i].color);
  }
  domClear(el, i);
}

function updateClipping(el, clip, index) {
  var rect;

  el = domChild(el, index, 'clipPath', ns);
  el.setAttribute('id', clip.id);
  rect = domChild(el, 0, 'rect', ns);
  rect.setAttribute('x', 0);
  rect.setAttribute('y', 0);
  rect.setAttribute('width', clip.width);
  rect.setAttribute('height', clip.height);
}

prototype._resetDefs = function() {
  var def = this._defs;
  def.gradient = {};
  def.clipping = {};
};

// -- Manage rendering of items marked as dirty --

prototype.dirty = function(item) {
  if (item.dirty !== this._dirtyID) {
    item.dirty = this._dirtyID;
    this._dirty.push(item);
  }
};

prototype.isDirty = function(item) {
  return this._dirtyAll
    || !item._svg
    || item.dirty === this._dirtyID;
};

prototype._dirtyCheck = function() {
  this._dirtyAll = true;
  var items = this._dirty;
  if (!items.length) return true;

  var id = ++this._dirtyID,
      item, mark, type, mdef, i, n, o;

  for (i=0, n=items.length; i<n; ++i) {
    item = items[i];
    mark = item.mark;

    if (mark.marktype !== type) {
      // memoize mark instance lookup
      type = mark.marktype;
      mdef = marks[type];
    }

    if (mark.zdirty && mark.dirty !== id) {
      this._dirtyAll = false;
      mark.dirty = id;
      dirtyParents(mark.group, id);
    }

    if (item.exit) { // EXIT
      if (mdef.nested && mark.items.length) {
        // if nested mark with remaining points, update instead
        o = mark.items[0];
        if (o._svg) this._update(mdef, o._svg, o);
      } else if (item._svg) {
        // otherwise remove from DOM
        item._svg.parentNode.removeChild(item._svg);
      }
      item._svg = null;
      continue;
    }

    item = (mdef.nested ? mark.items[0] : item);
    if (item._update === id) continue; // already visited

    if (!item._svg || !item._svg.ownerSVGElement) {
      // ENTER
      this._dirtyAll = false;
      dirtyParents(item, id);
    } else {
      // IN-PLACE UPDATE
      this._update(mdef, item._svg, item);
    }
    item._update = id;
  }
  return !this._dirtyAll;
};

function dirtyParents(item, id) {
  for (; item && item.dirty !== id; item=item.mark.group) {
    item.dirty = id;
    if (item.mark && item.mark.dirty !== id) {
      item.mark.dirty = id;
    } else return;
  }
}

// -- Construct & maintain scenegraph to SVG mapping ---

// Draw a mark container.
prototype.draw = function(el, scene, prev) {
  if (!this.isDirty(scene)) return scene._svg;

  var renderer = this,
      mdef = marks[scene.marktype],
      events = scene.interactive === false ? 'none' : null,
      isGroup = mdef.tag === 'g',
      sibling = null,
      i = 0,
      parent;

  parent = bind(scene, el, prev, 'g');
  parent.setAttribute('class', cssClass(scene));
  if (!isGroup && events) {
    parent.style.setProperty('pointer-events', events);
  }
  if (scene.clip) {
    parent.setAttribute('clip-path', clip(renderer, scene, scene.group));
  }

  function process(item) {
    var dirty = renderer.isDirty(item),
        node = bind(item, parent, sibling, mdef.tag);

    if (dirty) {
      renderer._update(mdef, node, item);
      if (isGroup) recurse(renderer, node, item);
    }

    sibling = node;
    ++i;
  }

  if (mdef.nested) {
    if (scene.items.length) process(scene.items[0]);
  } else {
    visit(scene, process);
  }

  domClear(parent, i);
  return parent;
};

// Recursively process group contents.
function recurse(renderer, el, group) {
  el = el.lastChild;
  var prev, idx = 0;

  visit(group, function(item) {
    prev = renderer.draw(el, item, prev);
    ++idx;
  });

  // remove any extraneous DOM elements
  domClear(el, 1 + idx);
}

// Bind a scenegraph item to an SVG DOM element.
// Create new SVG elements as needed.
function bind(item, el, sibling, tag) {
  var node = item._svg, doc;

  // create a new dom node if needed
  if (!node) {
    doc = el.ownerDocument;
    node = domCreate(doc, tag, ns);
    item._svg = node;

    if (item.mark) {
      node.__data__ = item;
      node.__values__ = {fill: 'default'};

      // if group, create background and foreground elements
      if (tag === 'g') {
        var bg = domCreate(doc, 'path', ns);
        bg.setAttribute('class', 'background');
        node.appendChild(bg);
        bg.__data__ = item;

        var fg = domCreate(doc, 'g', ns);
        node.appendChild(fg);
        fg.__data__ = item;
      }
    }
  }

  if (doc || node.previousSibling !== sibling || !sibling) {
    el.insertBefore(node, sibling ? sibling.nextSibling : el.firstChild);
  }

  return node;
}

// -- Set attributes & styles on SVG elements ---

var element = null, // temp var for current SVG element
    values = null;  // temp var for current values hash

// Extra configuration for certain mark types
var mark_extras = {
  group: function(mdef, el, item) {
    values = el.__values__; // use parent's values hash

    element = el.childNodes[1];
    mdef.foreground(emit, item, this);

    element = el.childNodes[0];
    mdef.background(emit, item, this);

    var value = item.mark.interactive === false ? 'none' : null;
    if (value !== values.events) {
      element.style.setProperty('pointer-events', value);
      values.events = value;
    }
  },
  text: function(mdef, el, item) {
    var str = textValue(item);
    if (str !== values.text) {
      el.textContent = str;
      values.text = str;
    }
    str = font(item);
    if (str !== values.font) {
      el.style.setProperty('font', str);
      values.font = str;
    }
  }
};

prototype._update = function(mdef, el, item) {
  // set dom element and values cache
  // provides access to emit method
  element = el;
  values = el.__values__;

  // apply svg attributes
  mdef.attr(emit, item, this);

  // some marks need special treatment
  var extra = mark_extras[mdef.type];
  if (extra) extra.call(this, mdef, el, item);

  // apply svg css styles
  // note: element may be modified by 'extra' method
  this.style(element, item);
};

function emit(name, value, ns) {
  // early exit if value is unchanged
  if (value === values[name]) return;

  if (value != null) {
    // if value is provided, update DOM attribute
    if (ns) {
      element.setAttributeNS(ns, name, value);
    } else {
      element.setAttribute(name, value);
    }
  } else {
    // else remove DOM attribute
    if (ns) {
      element.removeAttributeNS(ns, name);
    } else {
      element.removeAttribute(name);
    }
  }

  // note current value for future comparison
  values[name] = value;
}

prototype.style = function(el, o) {
  if (o == null) return;
  var i, n, prop, name, value;

  for (i=0, n=styleProperties.length; i<n; ++i) {
    prop = styleProperties[i];
    value = o[prop];
    if (value === values[prop]) continue;

    name = styles[prop];
    if (value == null) {
      if (name === 'fill') {
        el.style.setProperty(name, 'none');
      } else {
        el.style.removeProperty(name);
      }
    } else {
      if (value.id) {
        // ensure definition is included
        this._defs.gradient[value.id] = value;
        value = 'url(' + href() + '#' + value.id + ')';
      }
      el.style.setProperty(name, value+'');
    }

    values[prop] = value;
  }
};

function href() {
  return typeof window !== 'undefined' ? window.location.href : '';
}
<|endoftext|>