<commit_before>angular.module('anol.draw')
/**
 * @ngdoc directive
 * @name anol.draw.anolDraw
 *
 * @requires $compile
 * @requires $rootScope
 * @requires $translate
 * @requires anol.map.MapService
 * @requires anol.map.ControlsSerivce
 * @requries anol.map.DrawService
 *
 * @param {boolean} continueDrawing Don't deactivate drawing after feature is added
 * @param {function} postDrawAction Action to call after feature is drawn. Draw control will be deactivated when postDrawAction defined.
 * @param {boolean} freeDrawing Deactivate snapped drawing
 * @param {string} pointTooltipPlacement Position of point tooltip
 * @param {string} lineTooltipPlacement Position of line tooltip
 * @param {string} polygonTooltipPlacement Position of polygon tooltip
 * @param {number} tooltipDelay Time in milisecounds to wait before display tooltip
 * @param {boolean} tooltipEnable Enable tooltips. Default true for non-touch screens, default false for touchscreens
 * @param {string} templateUrl Url to template to use instead of default one
 *
 * @description
 * Provides controls to draw points, lines and polygons, modify and remove them
 */
.directive('anolDraw', ['$compile', '$rootScope', '$translate', '$timeout', 'ControlsService', 'MapService', 'DrawService',
    function($compile, $rootScope, $translate, $timeout, ControlsService, MapService, DrawService) {
    return {
        restrict: 'A',
        require: '?^anolMap',
        scope: {
            continueDrawing: '@',
            postDrawAction: '&',
            freeDrawing: '@',
            tooltipDelay: '@',
            tooltipEnable: '@',
            pointTooltipPlacement: '@',
            lineTooltipPlacement: '@',
            polygonTooltipPlacement: '@'
        },
        templateUrl: function(tElement, tAttrs) {
            var defaultUrl = 'src/modules/draw/templates/draw.html';
            return tAttrs.templateUrl || defaultUrl;
        },
        link: function(scope, element, attrs, AnolMapController) {
            // attribute defaults
            scope.continueDrawing = angular.isDefined(scope.continueDrawing) ?
                scope.continueDrawing : false;
            scope.freeDrawing = angular.isDefined(scope.freeDrawing) ?
                scope.freeDrawing : false;
            scope.tooltipEnable = angular.isDefined(scope.tooltipEnable) ?
                scope.tooltipEnable : !ol.has.TOUCH;
            scope.tooltipDelay = angular.isDefined(scope.tooltipDelay) ?
                scope.tooltipDelay : 500;
            scope.pointTooltipPlacement = angular.isDefined(scope.pointTooltipPlacement) ?
                scope.pointTooltipPlacement : 'right';
            scope.lineTooltipPlacement = angular.isDefined(scope.lineTooltipPlacement) ?
                scope.lineTooltipPlacement : 'right';
            scope.polygonTooltipPlacement = angular.isDefined(scope.polygonTooltipPlacement) ?
                scope.polygonTooltipPlacement : 'right';

            scope.activeLayer = undefined;
            var changeCursorEventKey;
            var selectedFeature;
            var controls = [];
            var drawPointControl, drawLineControl, drawPolygonControl, modifyControl;

            // disabled by default. Will be enabled, when feature selected
            var removeButtonElement = element.find('.draw-remove');
            removeButtonElement.addClass('disabled');

            var bindCursorChange = function() {
                changeCursorEventKey = scope.map.on('pointermove', changeCursor);
            };
            var unbindCursorChange = function() {
                if(changeCursorEventKey !== undefined) {
                    scope.map.unByKey(changeCursorEventKey);
                    changeCursorEventKey = undefined;
                }
            };
            var executePostDrawCallback = function(evt) {
                scope.postDrawAction()(scope.activeLayer, evt.feature);
            };

            var createDrawInteractions = function(drawType, source, control, layer) {
                // create draw interaction
                var draw = new ol.interaction.Draw({
                    source: source,
                    type: drawType
                });

                if(angular.isFunction(scope.postDrawAction) && angular.isFunction(scope.postDrawAction())) {
                    draw.on('drawend', executePostDrawCallback);
                }

                if(scope.continueDrawing === false && control !== undefined) {
                    draw.on('drawend', function() {
                        // TODO remove when https://github.com/openlayers/ol3/issues/3610/ resolved
                        $timeout(function() { control.deactivate(); }, 275);
                    });
                }
                draw.on('drawstart', unbindCursorChange);
                draw.on('drawend', bindCursorChange);

                var interactions = [draw];
                if(scope.freeDrawing !== false) {
                    var snapInteraction = new ol.interaction.Snap({
                        source: layer.getSource()
                    });
                    interactions.push(snapInteraction);
                }
                return interactions;
            };

            var createModifyInteractions = function(layer) {
                var selectInteraction = new ol.interaction.Select({
                    toggleCondition: ol.events.condition.never,
                    layers: [layer]
                });
                selectInteraction.on('select', function(evt) {
                    if(evt.selected.length === 0) {
                        selectedFeature = undefined;
                        removeButtonElement.addClass('disabled');
                    } else {
                        selectedFeature = evt.selected[0];
                        removeButtonElement.removeClass('disabled');
                    }
                });
                var modifyInteraction = new ol.interaction.Modify({
                    features: selectInteraction.getFeatures()
                });
                modifyInteraction.on('modifystart', function() {
                    if(changeCursorEventKey !== undefined) {
                        scope.map.unByKey(changeCursorEventKey);
                    }
                });
                modifyInteraction.on('modifyend', function() {
                    changeCursorEventKey = scope.map.on('pointermove', changeCursor);
                });
                var snapInteraction = new ol.interaction.Snap({
                    source: layer.getSource()
                });
                return [selectInteraction, modifyInteraction, snapInteraction];
            };

            var createDrawControl = function(controlElement, controlTarget) {
                var controlOptions = {
                    element: controlElement,
                    target: controlTarget,
                    exclusive: true,
                    disabled: true
                };
                if(AnolMapController === null) {
                    controlOptions.olControl = null;
                }
                var drawControl = new anol.control.Control(controlOptions);
                drawControl.onDeactivate(deactivate, scope);
                drawControl.onActivate(activate, scope);
                return drawControl;
            };

            var createModifyControl = function(controlElement, controlTarget) {
                var controlOptions = {
                    element: controlElement,
                    target: controlTarget,
                    exclusive: true,
                    disabled: true
                };
                if(AnolMapController === null) {
                    controlOptions.olControl = null;
                }
                var _modifyControl = new anol.control.Control(controlOptions);
                _modifyControl.onDeactivate(deactivate);
                _modifyControl.onActivate(activate);
                _modifyControl.onDeactivate(function() {
                    selectedFeature = undefined;
                });
                return _modifyControl;
            };

            var deactivate = function(targetControl) {
                angular.forEach(targetControl.interactions, function(interaction) {
                    interaction.setActive(false);
                });
            };

            var activate = function(targetControl) {
                angular.forEach(targetControl.interactions, function(interaction) {
                    interaction.setActive(true);
                });
            };

            var changeCursor = function(evt) {
                var pixel = scope.map.getEventPixel(evt.originalEvent);

                var hit = scope.map.hasFeatureAtPixel(pixel, function(layer) {
                    return layer === scope.activeLayer.olLayer;
                });

                scope.map.getTarget().style.cursor = hit ? 'pointer' : '';
            };

            // Button binds
            scope.drawPoint = function() {
                if(drawPointControl.disabled === true) {
                    return;
                }
                if(drawPointControl.active) {
                    drawPointControl.deactivate();
                } else {
                    drawPointControl.activate();
                }
            };

            scope.drawLine = function() {
                if(drawLineControl.disabled === true) {
                    return;
                }
                if(drawLineControl.active) {
                    drawLineControl.deactivate();
                } else {
                    drawLineControl.activate();
                }
            };

            scope.drawPolygon = function() {
                if(drawPolygonControl.disabled === true) {
                    return;
                }
                if(drawPolygonControl.active) {
                    drawPolygonControl.deactivate();
                } else {
                    drawPolygonControl.activate();
                }
            };

            scope.modify = function() {
                if(modifyControl.disabled === true) {
                    return;
                }
                if(modifyControl.active) {
                    modifyControl.deactivate();
                } else {
                    modifyControl.activate();
                }
            };

            scope.remove = function() {
                if(selectedFeature !== undefined) {
                    scope.activeLayer.olLayer.getSource().removeFeature(selectedFeature);
                    modifyControl.interactions[0].getFeatures().clear();
                    selectedFeature = undefined;
                }
            };

            // extra action for a realy custumised draw experience
            scope.drawCustom = function(drawType, postDrawCallback) {
                // skip when no active layer present
                if(scope.activeLayer === undefined) {
                    return;
                }
                // deactivate other controls
                angular.forEach(controls, function(control) {
                    control.deactivate();
                });

                var olLayer = scope.activeLayer.olLayer;
                var source = olLayer.getSource();
                // third param is control we don't need for this action
                var customInteractions = createDrawInteractions(drawType, source, undefined, olLayer);

                // stores control activate event handler unregistering informations
                var unregisters = [];
                var deregisterActiveLayerChange;
                var removeCustomDraw = function() {
                    // remove interactions after drawing is done
                    angular.forEach(customInteractions, function(interaction) {
                        interaction.setActive(false);
                        scope.map.removeInteraction(interaction);
                    });
                    deregisterActiveLayerChange();
                    angular.forEach(unregisters, function(unregister) {
                        unregister[0].unActivate(unregister[1]);
                    });
                };

                // first one is always the drawInteraction
                var customDrawInteraction = customInteractions[0];
                // remove custom draw after draw finish and call the callback
                customDrawInteraction.on('drawend', function(evt) {
                    removeCustomDraw();
                    postDrawCallback(scope.activeLayer, evt.feature);
                });

                // remove custom draw when active layer changes
                deregisterActiveLayerChange = scope.$watch(function() {
                    return DrawService.activeLayer;
                }, function(newActiveLayer) {
                    if(newActiveLayer === scope.activeLayer) {
                        return;
                    }
                    removeCustomDraw();
                });

                // remove custom draw when one of the other controls get active
                angular.forEach(controls, function(control) {
                    unregisters.push([control, control.oneActivate(function() {
                        removeCustomDraw();
                    })]);
                });

                // activate and add customInteractions
                angular.forEach(customInteractions, function(interaction) {
                    interaction.setActive(true);
                    scope.map.addInteraction(interaction);
                });
            };

            scope.map = MapService.getMap();

            element.addClass('anol-draw');

            if(AnolMapController !== null) {
                element.addClass('ol-control');
                var drawControl = new anol.control.Control({
                    element: element
                });
                controls.push(drawControl);
            }

            drawPointControl = createDrawControl(
                element.find('.draw-point'),
                element
            );
            controls.push(drawPointControl);

            drawLineControl = createDrawControl(
                element.find('.draw-line'),
                element
            );
            controls.push(drawLineControl);

            drawPolygonControl = createDrawControl(
                element.find('.draw-polygon'),
                element
            );
            controls.push(drawPolygonControl);

            modifyControl = createModifyControl(
                element.find('.draw-modify'),
                element
            );
            modifyControl.onActivate(function() {
                changeCursorEventKey = scope.map.on('pointermove', changeCursor);
            });
            modifyControl.onDeactivate(function(control) {
                control.interactions[0].getFeatures().clear();
                removeButtonElement.addClass('disabled');
                if(changeCursorEventKey !== undefined) {
                    scope.map.unByKey(changeCursorEventKey);
                }
            });
            controls.push(modifyControl);

            ControlsService.addControls(controls);

            var allInteractions = function() {
                return drawPointControl.interactions
                    .concat(drawLineControl.interactions)
                    .concat(drawPolygonControl.interactions)
                    .concat(modifyControl.interactions);
            };

            var visibleDewatcher;

            var bindActiveLayer = function(layer) {
                drawPointControl.interactions = createDrawInteractions(
                    'Point', layer.olLayer.getSource(), drawPointControl, layer.olLayer);
                drawPointControl.enable();
                drawLineControl.interactions = createDrawInteractions(
                    'LineString', layer.olLayer.getSource(), drawLineControl, layer.olLayer);
                drawLineControl.enable();
                drawPolygonControl.interactions = createDrawInteractions(
                    'Polygon', layer.olLayer.getSource(), drawPolygonControl, layer.olLayer);
                drawPolygonControl.enable();
                modifyControl.interactions = createModifyInteractions(layer.olLayer);
                modifyControl.enable();

                angular.forEach(allInteractions(), function(interaction) {
                    interaction.setActive(false);
                    scope.map.addInteraction(interaction);
                });

                scope.activeLayer = layer;

                visibleDewatcher = scope.$watch(function() {
                    return scope.activeLayer.getVisible();
                }, function(n) {
                    if(n === false) {
                        DrawService.changeLayer(undefined);
                    }
                });
            };

            var unbindActiveLayer = function() {
                angular.forEach(allInteractions(), function(interaction) {
                    interaction.setActive(false);
                    scope.map.removeInteraction(interaction);
                });

                drawPointControl.disable();
                drawPointControl.interactions = [];
                drawLineControl.disable();
                drawLineControl.interactions = [];
                drawPolygonControl.disable();
                drawPolygonControl.interactions = [];
                modifyControl.disable();
                modifyControl.interactions = [];

                if(visibleDewatcher !== undefined) {
                    visibleDewatcher();
                }

                scope.activeLayer = undefined;
            };

            scope.$watch(function() {
                return DrawService.activeLayer;
            }, function(newActiveLayer, oldActiveLayer) {
                if(newActiveLayer === scope.activeLayer) {
                    return;
                }
                if(oldActiveLayer !== undefined) {
                    unbindActiveLayer();
                }
                if(newActiveLayer !== undefined) {
                    bindActiveLayer(newActiveLayer);
                }
            });
        }
    };
}]);
<commit_msg>Removed unneeded event handler<commit_after>angular.module('anol.draw')
/**
 * @ngdoc directive
 * @name anol.draw.anolDraw
 *
 * @requires $compile
 * @requires $rootScope
 * @requires $translate
 * @requires anol.map.MapService
 * @requires anol.map.ControlsSerivce
 * @requries anol.map.DrawService
 *
 * @param {boolean} continueDrawing Don't deactivate drawing after feature is added
 * @param {function} postDrawAction Action to call after feature is drawn. Draw control will be deactivated when postDrawAction defined.
 * @param {boolean} freeDrawing Deactivate snapped drawing
 * @param {string} pointTooltipPlacement Position of point tooltip
 * @param {string} lineTooltipPlacement Position of line tooltip
 * @param {string} polygonTooltipPlacement Position of polygon tooltip
 * @param {number} tooltipDelay Time in milisecounds to wait before display tooltip
 * @param {boolean} tooltipEnable Enable tooltips. Default true for non-touch screens, default false for touchscreens
 * @param {string} templateUrl Url to template to use instead of default one
 *
 * @description
 * Provides controls to draw points, lines and polygons, modify and remove them
 */
.directive('anolDraw', ['$compile', '$rootScope', '$translate', '$timeout', 'ControlsService', 'MapService', 'DrawService',
    function($compile, $rootScope, $translate, $timeout, ControlsService, MapService, DrawService) {
    return {
        restrict: 'A',
        require: '?^anolMap',
        scope: {
            continueDrawing: '@',
            postDrawAction: '&',
            freeDrawing: '@',
            tooltipDelay: '@',
            tooltipEnable: '@',
            pointTooltipPlacement: '@',
            lineTooltipPlacement: '@',
            polygonTooltipPlacement: '@'
        },
        templateUrl: function(tElement, tAttrs) {
            var defaultUrl = 'src/modules/draw/templates/draw.html';
            return tAttrs.templateUrl || defaultUrl;
        },
        link: function(scope, element, attrs, AnolMapController) {
            // attribute defaults
            scope.continueDrawing = angular.isDefined(scope.continueDrawing) ?
                scope.continueDrawing : false;
            scope.freeDrawing = angular.isDefined(scope.freeDrawing) ?
                scope.freeDrawing : false;
            scope.tooltipEnable = angular.isDefined(scope.tooltipEnable) ?
                scope.tooltipEnable : !ol.has.TOUCH;
            scope.tooltipDelay = angular.isDefined(scope.tooltipDelay) ?
                scope.tooltipDelay : 500;
            scope.pointTooltipPlacement = angular.isDefined(scope.pointTooltipPlacement) ?
                scope.pointTooltipPlacement : 'right';
            scope.lineTooltipPlacement = angular.isDefined(scope.lineTooltipPlacement) ?
                scope.lineTooltipPlacement : 'right';
            scope.polygonTooltipPlacement = angular.isDefined(scope.polygonTooltipPlacement) ?
                scope.polygonTooltipPlacement : 'right';

            scope.activeLayer = undefined;
            var changeCursorEventKey;
            var selectedFeature;
            var controls = [];
            var drawPointControl, drawLineControl, drawPolygonControl, modifyControl;

            // disabled by default. Will be enabled, when feature selected
            var removeButtonElement = element.find('.draw-remove');
            removeButtonElement.addClass('disabled');

            var bindCursorChange = function() {
                changeCursorEventKey = scope.map.on('pointermove', changeCursor);
            };
            var unbindCursorChange = function() {
                if(changeCursorEventKey !== undefined) {
                    scope.map.unByKey(changeCursorEventKey);
                    changeCursorEventKey = undefined;
                }
            };
            var executePostDrawCallback = function(evt) {
                scope.postDrawAction()(scope.activeLayer, evt.feature);
            };

            var createDrawInteractions = function(drawType, source, control, layer) {
                // create draw interaction
                var draw = new ol.interaction.Draw({
                    source: source,
                    type: drawType
                });

                if(angular.isFunction(scope.postDrawAction) && angular.isFunction(scope.postDrawAction())) {
                    draw.on('drawend', executePostDrawCallback);
                }

                if(scope.continueDrawing === false && control !== undefined) {
                    draw.on('drawend', function() {
                        // TODO remove when https://github.com/openlayers/ol3/issues/3610/ resolved
                        $timeout(function() { control.deactivate(); }, 275);
                    });
                }

                var interactions = [draw];
                if(scope.freeDrawing !== false) {
                    var snapInteraction = new ol.interaction.Snap({
                        source: layer.getSource()
                    });
                    interactions.push(snapInteraction);
                }
                return interactions;
            };

            var createModifyInteractions = function(layer) {
                var selectInteraction = new ol.interaction.Select({
                    toggleCondition: ol.events.condition.never,
                    layers: [layer]
                });
                selectInteraction.on('select', function(evt) {
                    if(evt.selected.length === 0) {
                        selectedFeature = undefined;
                        removeButtonElement.addClass('disabled');
                    } else {
                        selectedFeature = evt.selected[0];
                        removeButtonElement.removeClass('disabled');
                    }
                });
                var modifyInteraction = new ol.interaction.Modify({
                    features: selectInteraction.getFeatures()
                });
                modifyInteraction.on('modifystart', function() {
                    if(changeCursorEventKey !== undefined) {
                        scope.map.unByKey(changeCursorEventKey);
                    }
                });
                modifyInteraction.on('modifyend', function() {
                    changeCursorEventKey = scope.map.on('pointermove', changeCursor);
                });
                var snapInteraction = new ol.interaction.Snap({
                    source: layer.getSource()
                });
                return [selectInteraction, modifyInteraction, snapInteraction];
            };

            var createDrawControl = function(controlElement, controlTarget) {
                var controlOptions = {
                    element: controlElement,
                    target: controlTarget,
                    exclusive: true,
                    disabled: true
                };
                if(AnolMapController === null) {
                    controlOptions.olControl = null;
                }
                var drawControl = new anol.control.Control(controlOptions);
                drawControl.onDeactivate(deactivate, scope);
                drawControl.onActivate(activate, scope);
                return drawControl;
            };

            var createModifyControl = function(controlElement, controlTarget) {
                var controlOptions = {
                    element: controlElement,
                    target: controlTarget,
                    exclusive: true,
                    disabled: true
                };
                if(AnolMapController === null) {
                    controlOptions.olControl = null;
                }
                var _modifyControl = new anol.control.Control(controlOptions);
                _modifyControl.onDeactivate(deactivate);
                _modifyControl.onActivate(activate);
                _modifyControl.onDeactivate(function() {
                    selectedFeature = undefined;
                });
                return _modifyControl;
            };

            var deactivate = function(targetControl) {
                angular.forEach(targetControl.interactions, function(interaction) {
                    interaction.setActive(false);
                });
            };

            var activate = function(targetControl) {
                angular.forEach(targetControl.interactions, function(interaction) {
                    interaction.setActive(true);
                });
            };

            var changeCursor = function(evt) {
                var pixel = scope.map.getEventPixel(evt.originalEvent);

                var hit = scope.map.hasFeatureAtPixel(pixel, function(layer) {
                    return layer === scope.activeLayer.olLayer;
                });

                scope.map.getTarget().style.cursor = hit ? 'pointer' : '';
            };

            // Button binds
            scope.drawPoint = function() {
                if(drawPointControl.disabled === true) {
                    return;
                }
                if(drawPointControl.active) {
                    drawPointControl.deactivate();
                } else {
                    drawPointControl.activate();
                }
            };

            scope.drawLine = function() {
                if(drawLineControl.disabled === true) {
                    return;
                }
                if(drawLineControl.active) {
                    drawLineControl.deactivate();
                } else {
                    drawLineControl.activate();
                }
            };

            scope.drawPolygon = function() {
                if(drawPolygonControl.disabled === true) {
                    return;
                }
                if(drawPolygonControl.active) {
                    drawPolygonControl.deactivate();
                } else {
                    drawPolygonControl.activate();
                }
            };

            scope.modify = function() {
                if(modifyControl.disabled === true) {
                    return;
                }
                if(modifyControl.active) {
                    modifyControl.deactivate();
                } else {
                    modifyControl.activate();
                }
            };

            scope.remove = function() {
                if(selectedFeature !== undefined) {
                    scope.activeLayer.olLayer.getSource().removeFeature(selectedFeature);
                    modifyControl.interactions[0].getFeatures().clear();
                    selectedFeature = undefined;
                }
            };

            // extra action for a realy custumised draw experience
            scope.drawCustom = function(drawType, postDrawCallback) {
                // skip when no active layer present
                if(scope.activeLayer === undefined) {
                    return;
                }
                // deactivate other controls
                angular.forEach(controls, function(control) {
                    control.deactivate();
                });

                var olLayer = scope.activeLayer.olLayer;
                var source = olLayer.getSource();
                // third param is control we don't need for this action
                var customInteractions = createDrawInteractions(drawType, source, undefined, olLayer);

                // stores control activate event handler unregistering informations
                var unregisters = [];
                var deregisterActiveLayerChange;
                var removeCustomDraw = function() {
                    // remove interactions after drawing is done
                    angular.forEach(customInteractions, function(interaction) {
                        interaction.setActive(false);
                        scope.map.removeInteraction(interaction);
                    });
                    deregisterActiveLayerChange();
                    angular.forEach(unregisters, function(unregister) {
                        unregister[0].unActivate(unregister[1]);
                    });
                };

                // first one is always the drawInteraction
                var customDrawInteraction = customInteractions[0];
                // remove custom draw after draw finish and call the callback
                customDrawInteraction.on('drawend', function(evt) {
                    removeCustomDraw();
                    postDrawCallback(scope.activeLayer, evt.feature);
                });

                // remove custom draw when active layer changes
                deregisterActiveLayerChange = scope.$watch(function() {
                    return DrawService.activeLayer;
                }, function(newActiveLayer) {
                    if(newActiveLayer === scope.activeLayer) {
                        return;
                    }
                    removeCustomDraw();
                });

                // remove custom draw when one of the other controls get active
                angular.forEach(controls, function(control) {
                    unregisters.push([control, control.oneActivate(function() {
                        removeCustomDraw();
                    })]);
                });

                // activate and add customInteractions
                angular.forEach(customInteractions, function(interaction) {
                    interaction.setActive(true);
                    scope.map.addInteraction(interaction);
                });
            };

            scope.map = MapService.getMap();

            element.addClass('anol-draw');

            if(AnolMapController !== null) {
                element.addClass('ol-control');
                var drawControl = new anol.control.Control({
                    element: element
                });
                controls.push(drawControl);
            }

            drawPointControl = createDrawControl(
                element.find('.draw-point'),
                element
            );
            controls.push(drawPointControl);

            drawLineControl = createDrawControl(
                element.find('.draw-line'),
                element
            );
            controls.push(drawLineControl);

            drawPolygonControl = createDrawControl(
                element.find('.draw-polygon'),
                element
            );
            controls.push(drawPolygonControl);

            modifyControl = createModifyControl(
                element.find('.draw-modify'),
                element
            );
            modifyControl.onActivate(function() {
                changeCursorEventKey = scope.map.on('pointermove', changeCursor);
            });
            modifyControl.onDeactivate(function(control) {
                control.interactions[0].getFeatures().clear();
                removeButtonElement.addClass('disabled');
                if(changeCursorEventKey !== undefined) {
                    scope.map.unByKey(changeCursorEventKey);
                }
            });
            controls.push(modifyControl);

            ControlsService.addControls(controls);

            var allInteractions = function() {
                return drawPointControl.interactions
                    .concat(drawLineControl.interactions)
                    .concat(drawPolygonControl.interactions)
                    .concat(modifyControl.interactions);
            };

            var visibleDewatcher;

            var bindActiveLayer = function(layer) {
                drawPointControl.interactions = createDrawInteractions(
                    'Point', layer.olLayer.getSource(), drawPointControl, layer.olLayer);
                drawPointControl.enable();
                drawLineControl.interactions = createDrawInteractions(
                    'LineString', layer.olLayer.getSource(), drawLineControl, layer.olLayer);
                drawLineControl.enable();
                drawPolygonControl.interactions = createDrawInteractions(
                    'Polygon', layer.olLayer.getSource(), drawPolygonControl, layer.olLayer);
                drawPolygonControl.enable();
                modifyControl.interactions = createModifyInteractions(layer.olLayer);
                modifyControl.enable();

                angular.forEach(allInteractions(), function(interaction) {
                    interaction.setActive(false);
                    scope.map.addInteraction(interaction);
                });

                scope.activeLayer = layer;

                visibleDewatcher = scope.$watch(function() {
                    return scope.activeLayer.getVisible();
                }, function(n) {
                    if(n === false) {
                        DrawService.changeLayer(undefined);
                    }
                });
            };

            var unbindActiveLayer = function() {
                angular.forEach(allInteractions(), function(interaction) {
                    interaction.setActive(false);
                    scope.map.removeInteraction(interaction);
                });

                drawPointControl.disable();
                drawPointControl.interactions = [];
                drawLineControl.disable();
                drawLineControl.interactions = [];
                drawPolygonControl.disable();
                drawPolygonControl.interactions = [];
                modifyControl.disable();
                modifyControl.interactions = [];

                if(visibleDewatcher !== undefined) {
                    visibleDewatcher();
                }

                scope.activeLayer = undefined;
            };

            scope.$watch(function() {
                return DrawService.activeLayer;
            }, function(newActiveLayer, oldActiveLayer) {
                if(newActiveLayer === scope.activeLayer) {
                    return;
                }
                if(oldActiveLayer !== undefined) {
                    unbindActiveLayer();
                }
                if(newActiveLayer !== undefined) {
                    bindActiveLayer(newActiveLayer);
                }
            });
        }
    };
}]);
<|endoftext|>


<commit_before>var debug = require('debug');
var error = debug('line-bot:error');
var log = debug('line-bot:log');
var request = require('superagent-promise')(require('superagent'), Promise);
var merge = require('lodash.merge');

var ReceiveFactory = require('./receive/ReceiveFactory');
var SignatureValidator = require('./SignatureValidator');

var BotAPIChannel = require('./constants/BotAPIChannel');
var Endpoint = require('./constants/Endpoint');
var EventType = require('./constants/EventType');
var MessageBuilder = require('./message/builder');
var RecipientType = require('./constants/RecipientType');

module.exports.init = function(config) {
  var api = {};
  var defaultHeaders = { 'Content-Type': 'application/json; charset=UTF-8' };
  if (config.channelToken) {
    // For Business Connect
    defaultHeaders['X-LINE-ChannelToken'] = config.channelToken;
  } else {
    // For Trial
    defaultHeaders['X-Line-ChannelID'] = config.channelID;
    defaultHeaders['X-Line-ChannelSecret'] = config.channelSecret;
    defaultHeaders['X-Line-Trusted-User-With-ACL'] = config.channelMID;
  }

  api.sendText = function(mid, text, toType) {
    return this.sendMessage(mid, MessageBuilder.buildText(text), toType || RecipientType.USER);
  };

  api.sendImage = function(mid, imageUrl, previewUrl, toType) {
    return this.sendMessage(mid, MessageBuilder.buildImage(imageUrl, previewUrl), toType || RecipientType.USER);
  };

  api.sendVideo = function(mid, videoUrl, previewImageURL, toType) {
    return this.sendMessage(mid, MessageBuilder.buildVideo(videoUrl, previewImageUrl), toType || RecipientType.USER);
  };

  api.sendAudio = function(mid, audioUrl, durationMillis, toType) {
    return this.sendMessage(mid, MessageBuilder.buildAudio(audioUrl, durationMillis), toType || RecipientType.USER);
  };

  api.sendLocation = function(mid, text, latitude, longitude, toType) {
    return this.sendMessage(mid, MessageBuilder.buildLocation(text, latitude, longitude), toType || RecipientType.USER);
  };

  api.sendSticker = function(mid, stkid, stkpkgid, stkver, toType) {
    return this.sendMessage(mid, MessageBuilder.buildSticker(stkid, stkpkgid, stkver || null), toType || RecipientType.USER);
  };

  api.sendRichMessage = function(mid, imageUrl, altText, markup, toType) {
    return this.sendMessage(mid, MessageBuilder.buildRichMessage(imageUrl, altText, markup), toType || RecipientType.USER);
  };

  // Not supported for groups and rooms.
  api.sendMultipleMessages = function(mid, multipleMessages, messageNotified) {
    return this.sendMessage(mid, MessageBuilder.buildMultipleMessages(multipleMessages, messageNotified || 0), null, EventType.SENDING_MULTIPLE_MESSAGES);
  };

  api.getMessageContent = function(messageId, fileHandler) {

  };

  api.getMessageContentPreview = function(messageId, fileHandler) {

  };

  api.getUserProfile = function(mid) {
    return request.get(Endpoint.PROFILE)
    .set(defaultHeaders)
    .query({ mids: mid instanceof Array ? mid.join() : mid })
    .end();
  };

  api.validateSignature = function(json, signature) {
    return SignatureValidator.validateSignature(JSON.stringify(json), this.channelSecret, signature);
  };

  api.createReceivesFromJSON = function(json) {
    return ReceiveFactory.createFromJSON(config, json);
  };

  api.sendMessage = function(mid, data, toType, eventType) {
    return this.postMessage({
      to: mid instanceof Array ? mid: [mid],
      content: merge(data, { toType: toType || RecipientType.USER })
    }, eventType || EventType.SENDING_MESSAGE);
  };

  api.postMessage = function(data, eventType) {
    data.toChannel = BotAPIChannel.SENDING_CHANNEL_ID;
    data.eventType = eventType;

    // debugging
    log('POST ' + Endpoint.EVENT);
    log('headers:');
    log(defaultHeaders);
    log('body:');
    log(data);

    return request.post(Endpoint.EVENT)
    .set(defaultHeaders)
    .send(data)
    .then(function(res) {
      return res;
    }, function(err) {
      var response = err.response;

      // debugging
      error('statusCode: ' + response.statusCode);
      error('body: ');
      error(response.body);

      throw err;
    });
  };

  // For Business Connect
  api.sendLinkMessage = function() {

  };

  // For Business Connect
  api.leaveGroup = function(groupId) {
    if (!config.channelToken) throw new Error('Leave a group is only appear in Business Connect API');
    return request.delete(Endpoint.LEAVE_GROUP + groupId)
    .set(defaultHeaders)
    .then(function(res) {
      return res;
    }, function(err) {
      var response = err.response;

      // debugging
      error('statusCode: ' + response.statusCode);
      error('body: ');
      error(response.body);

      throw err;
    });
  };

  // For Business Connect
  api.leaveRoom = function(roomId) {
    if (!config.channelToken) throw new Error('Leave a group is only appear in Business Connect API');
    return request.delete(Endpoint.LEAVE_ROOM + groupId)
    .set(defaultHeaders)
    .then(function(res) {
      return res;
    }, function(err) {
      var response = err.response;

      // debugging
      error('statusCode: ' + response.statusCode);
      error('body: ');
      error(response.body);

      throw err;
    });
  };

  // For Business Connect
  api.addOfficialAccount = function(accessToken) {
    if (!config.channelToken) throw new Error('Add an official account to a user\'s friend list is only appear in Business Connect API');
    return request.post(Endpoint.OFFICAL_ACCOUNT_CONTACTS)
    .set('X-Line-ChannelToken', accessToken)
    .then(function(res) {
      return res;
    }, function(err) {
      var response = err.response;

      // debugging
      error('statusCode: ' + response.statusCode);
      error('body: ');
      error(response.body);

      throw err;
    });
  };

  return api;
};
<commit_msg>fixed channel secret is undefined<commit_after>var debug = require('debug');
var error = debug('line-bot:error');
var log = debug('line-bot:log');
var request = require('superagent-promise')(require('superagent'), Promise);
var merge = require('lodash.merge');

var ReceiveFactory = require('./receive/ReceiveFactory');
var SignatureValidator = require('./SignatureValidator');

var BotAPIChannel = require('./constants/BotAPIChannel');
var Endpoint = require('./constants/Endpoint');
var EventType = require('./constants/EventType');
var MessageBuilder = require('./message/builder');
var RecipientType = require('./constants/RecipientType');

module.exports.init = function(config) {
  var api = {
    channelSecret: config.channelSecret,
    channelMID: config.channelMID,
    channelID: config.channelID,
    channelToken: config.channelToken
  };
  var defaultHeaders = { 'Content-Type': 'application/json; charset=UTF-8' };
  if (config.channelToken) {
    // For Business Connect
    defaultHeaders['X-LINE-ChannelToken'] = config.channelToken;
  } else {
    // For Trial
    defaultHeaders['X-Line-ChannelID'] = config.channelID;
    defaultHeaders['X-Line-ChannelSecret'] = config.channelSecret;
    defaultHeaders['X-Line-Trusted-User-With-ACL'] = config.channelMID;
  }

  api.sendText = function(mid, text, toType) {
    return this.sendMessage(mid, MessageBuilder.buildText(text), toType || RecipientType.USER);
  };

  api.sendImage = function(mid, imageUrl, previewUrl, toType) {
    return this.sendMessage(mid, MessageBuilder.buildImage(imageUrl, previewUrl), toType || RecipientType.USER);
  };

  api.sendVideo = function(mid, videoUrl, previewImageURL, toType) {
    return this.sendMessage(mid, MessageBuilder.buildVideo(videoUrl, previewImageUrl), toType || RecipientType.USER);
  };

  api.sendAudio = function(mid, audioUrl, durationMillis, toType) {
    return this.sendMessage(mid, MessageBuilder.buildAudio(audioUrl, durationMillis), toType || RecipientType.USER);
  };

  api.sendLocation = function(mid, text, latitude, longitude, toType) {
    return this.sendMessage(mid, MessageBuilder.buildLocation(text, latitude, longitude), toType || RecipientType.USER);
  };

  api.sendSticker = function(mid, stkid, stkpkgid, stkver, toType) {
    return this.sendMessage(mid, MessageBuilder.buildSticker(stkid, stkpkgid, stkver || null), toType || RecipientType.USER);
  };

  api.sendRichMessage = function(mid, imageUrl, altText, markup, toType) {
    return this.sendMessage(mid, MessageBuilder.buildRichMessage(imageUrl, altText, markup), toType || RecipientType.USER);
  };

  // Not supported for groups and rooms.
  api.sendMultipleMessages = function(mid, multipleMessages, messageNotified) {
    return this.sendMessage(mid, MessageBuilder.buildMultipleMessages(multipleMessages, messageNotified || 0), null, EventType.SENDING_MULTIPLE_MESSAGES);
  };

  api.getMessageContent = function(messageId, fileHandler) {

  };

  api.getMessageContentPreview = function(messageId, fileHandler) {

  };

  api.getUserProfile = function(mid) {
    return request.get(Endpoint.PROFILE)
    .set(defaultHeaders)
    .query({ mids: mid instanceof Array ? mid.join() : mid })
    .end();
  };

  api.validateSignature = function(json, signature) {
    return SignatureValidator.validateSignature(JSON.stringify(json), this.channelSecret, signature);
  };

  api.createReceivesFromJSON = function(json) {
    return ReceiveFactory.createFromJSON(config, json);
  };

  api.sendMessage = function(mid, data, toType, eventType) {
    return this.postMessage({
      to: mid instanceof Array ? mid: [mid],
      content: merge(data, { toType: toType || RecipientType.USER })
    }, eventType || EventType.SENDING_MESSAGE);
  };

  api.postMessage = function(data, eventType) {
    data.toChannel = BotAPIChannel.SENDING_CHANNEL_ID;
    data.eventType = eventType;

    // debugging
    log('POST ' + Endpoint.EVENT);
    log('headers:');
    log(defaultHeaders);
    log('body:');
    log(data);

    return request.post(Endpoint.EVENT)
    .set(defaultHeaders)
    .send(data)
    .then(function(res) {
      return res;
    }, function(err) {
      var response = err.response;

      // debugging
      error('statusCode: ' + response.statusCode);
      error('body: ');
      error(response.body);

      throw err;
    });
  };

  // For Business Connect
  api.sendLinkMessage = function() {

  };

  // For Business Connect
  api.leaveGroup = function(groupId) {
    if (!config.channelToken) throw new Error('Leave a group is only appear in Business Connect API');
    return request.delete(Endpoint.LEAVE_GROUP + groupId)
    .set(defaultHeaders)
    .then(function(res) {
      return res;
    }, function(err) {
      var response = err.response;

      // debugging
      error('statusCode: ' + response.statusCode);
      error('body: ');
      error(response.body);

      throw err;
    });
  };

  // For Business Connect
  api.leaveRoom = function(roomId) {
    if (!config.channelToken) throw new Error('Leave a group is only appear in Business Connect API');
    return request.delete(Endpoint.LEAVE_ROOM + groupId)
    .set(defaultHeaders)
    .then(function(res) {
      return res;
    }, function(err) {
      var response = err.response;

      // debugging
      error('statusCode: ' + response.statusCode);
      error('body: ');
      error(response.body);

      throw err;
    });
  };

  // For Business Connect
  api.addOfficialAccount = function(accessToken) {
    if (!config.channelToken) throw new Error('Add an official account to a user\'s friend list is only appear in Business Connect API');
    return request.post(Endpoint.OFFICAL_ACCOUNT_CONTACTS)
    .set('X-Line-ChannelToken', accessToken)
    .then(function(res) {
      return res;
    }, function(err) {
      var response = err.response;

      // debugging
      error('statusCode: ' + response.statusCode);
      error('body: ');
      error(response.body);

      throw err;
    });
  };

  return api;
};
<|endoftext|>


<commit_before>import Firebase from 'firebase/app'
import 'firebase/database'
import _ from 'lodash'

import {SPECIAL_VALUES} from './actions'
import {selectors} from './reducer'

const get_root_ref = () => Firebase.database().ref()

const handlers = {}

function ref_maker(path, sort = {}) {
  let this_ref = get_root_ref().child(path)

  if (sort.orderBy) {
    const value = _.get(sort, 'orderBy.value')
    if (value == null) {
      this_ref = this_ref[`orderBy${sort.orderBy.type}`]()
    } else {
      this_ref = this_ref[`orderBy${sort.orderBy.type}`](value)
    }
  }
  if (sort.startAt) {
    this_ref = this_ref.startAt(sort.startAt)
  }
  if (sort.equalTo) {
    this_ref = this_ref.equalTo(sort.equalTo)
  }
  if (sort.endAt) {
    this_ref = this_ref.endAt(sort.endAt)
  }
  if (sort.limitToFirst) {
    this_ref = this_ref.limitToFirst(sort.limitToFirst)
  }
  if (sort.limitToLast) {
    this_ref = this_ref.limitToLast(sort.limitToLast)
  }
  return this_ref
}

const dispatch_response = ({dispatch, update_action: type, payload, path, key}) => {
  if (type == undefined) return

  dispatch({
    type,
    payload,
    meta: {
      path,
      key,
    },
  })
}

handlers.once = ({meta: {path, update_action, init_value, batch, sort}}) => (dispatch, getState) => {
  if (batch) return batch_get({is_on: false, path, update_action, init_value, batch, sort, dispatch, getState})

  const this_ref = ref_maker(path, sort)
  return this_ref.once('value').then((snap) => {
    let payload = snap.val()
    if (!snap.exists() && init_value) {
      this_ref.set(init_value)
      payload = init_value
    }

    dispatch_response({dispatch, update_action, payload, path, key: snap.key })
    return payload
  })
}
const batch_check = ({is_on, path, update_action, batch, sort, dispatch}) => (snap) => {
  let keys = []
  snap.forEach((child_snap) => {
    keys.push(child_snap.key)
  })
  if (keys.length > 1) {
    dispatch_response({dispatch, update_action, path, payload: snap.val(), key: snap.key})
  }
  if (keys.length < batch) {
    // end
    if (is_on) {
      // continue listening
      sort.limitToFirst = undefined
      sort.startAt = keys[keys.length - 1]
      const ref = ref_maker(path, sort)
      ref.on('child_added', (snap) => {
        const key = snap.key
        dispatch_response({dispatch, update_action, path, payload: {[key]: snap.val()}, key})
      })
    }
    return Promise.resolve()
  }
  // need more
  sort.limitToFirst = batch
  sort.startAt = keys[keys.length - 1]
  const ref = ref_maker(path, sort)

  return ref.once('value').then(batch_check({is_on, path, update_action, batch, sort, dispatch}))
}
const batch_get = ({is_on, path, update_action, batch, sort = {}, dispatch}) => {
  sort.limitToFirst = batch
  sort.orderBy = sort.orderBy || {type: 'Key'}
  let ref = ref_maker(path, sort)
  return ref.once('value')
    .then(batch_check({is_on, path, update_action, batch, sort, dispatch}))
}

handlers.on = ({meta: {path, update_action, init_value, batch, sort}}) => (dispatch, getState) => {
  const state = selectors.listeners(getState())[path]
  if (state && state.count > 1) return Promise.resolve()

  if (batch) return batch_get({is_on: true, path, update_action, init_value, batch, sort, dispatch, getState})

  const this_ref = ref_maker(path, sort)
  let first_time = true
  const response = new Promise((resolve) => {
    this_ref.on('value', (snap) => {
      if (!snap.exists() && init_value) {
        this_ref.set(init_value)
      } else {
        const payload = snap.val()
        dispatch_response({dispatch, update_action, path, payload, key: snap.key})

        if (response.callback) dispatch(response.callback(payload))

        if (first_time) {
          first_time = false
          resolve(snap)
        }
      }
    })
  })
  response.on = (callback) => response.callback = callback
  return response
}
handlers.set = ({payload, meta: {path}}) => (dispatch, getState) => {
  const this_ref = get_root_ref().child(path)
  return this_ref.set(payload)
}
handlers.update = ({payload, meta: {path}}) => (dispatch, getState) => {
  const this_ref = get_root_ref().child(path)
  return this_ref.update(payload)
}
handlers.push = ({payload, meta: {path}}) => (dispatch, getState) => {
  const this_ref = get_root_ref().child(path).push()
  this_ref.then(() => {
    if (_.isEmpty(payload)) {
      return {}
    }
    const real_payload = _.mapValues(payload, (v) => (v === SPECIAL_VALUES.KEY) ? this_ref.key : v)
    return this_ref.set(real_payload)
  })
  return this_ref
}
handlers.off = ({meta: {path}}) => (dispatch, getState) => {
  const this_ref = get_root_ref().child(path)
  this_ref.off()
  return Promise.resolve()
}
handlers.remove = ({meta: {path}}) => (dispatch, getState) => {
  const this_ref = get_root_ref().child(path)
  this_ref.remove()
  return Promise.resolve()
}
handlers.switch = (action) => (dispatch, getState) => {
  if (!action.meta.old_path) return handlers.on(action)(dispatch, getState)

  return handlers.off({meta: {path: action.meta.old_path}})(dispatch, getState)
    .then(() => handlers.on(action)(dispatch, getState))
}

export default _.mapKeys(handlers, (value, key) => `firebase/${key}`)
<commit_msg>fix: force on to be async<commit_after>import Firebase from 'firebase/app'
import 'firebase/database'
import _ from 'lodash'

import {SPECIAL_VALUES} from './actions'
import {selectors} from './reducer'

const get_root_ref = () => Firebase.database().ref()

const handlers = {}

function ref_maker(path, sort = {}) {
  let this_ref = get_root_ref().child(path)

  if (sort.orderBy) {
    const value = _.get(sort, 'orderBy.value')
    if (value == null) {
      this_ref = this_ref[`orderBy${sort.orderBy.type}`]()
    } else {
      this_ref = this_ref[`orderBy${sort.orderBy.type}`](value)
    }
  }
  if (sort.startAt) {
    this_ref = this_ref.startAt(sort.startAt)
  }
  if (sort.equalTo) {
    this_ref = this_ref.equalTo(sort.equalTo)
  }
  if (sort.endAt) {
    this_ref = this_ref.endAt(sort.endAt)
  }
  if (sort.limitToFirst) {
    this_ref = this_ref.limitToFirst(sort.limitToFirst)
  }
  if (sort.limitToLast) {
    this_ref = this_ref.limitToLast(sort.limitToLast)
  }
  return this_ref
}

const dispatch_response = ({dispatch, update_action: type, payload, path, key}) => {
  if (type == undefined) return

  dispatch({
    type,
    payload,
    meta: {
      path,
      key,
    },
  })
}

handlers.once = ({meta: {path, update_action, init_value, batch, sort}}) => (dispatch, getState) => {
  if (batch) return batch_get({is_on: false, path, update_action, init_value, batch, sort, dispatch, getState})

  const this_ref = ref_maker(path, sort)
  return this_ref.once('value').then((snap) => {
    let payload = snap.val()
    if (!snap.exists() && init_value) {
      this_ref.set(init_value)
      payload = init_value
    }

    dispatch_response({dispatch, update_action, payload, path, key: snap.key })
    return payload
  })
}
const batch_check = ({is_on, path, update_action, batch, sort, dispatch}) => (snap) => {
  let keys = []
  snap.forEach((child_snap) => {
    keys.push(child_snap.key)
  })
  if (keys.length > 1) {
    dispatch_response({dispatch, update_action, path, payload: snap.val(), key: snap.key})
  }
  if (keys.length < batch) {
    // end
    if (is_on) {
      // continue listening
      sort.limitToFirst = undefined
      sort.startAt = keys[keys.length - 1]
      const ref = ref_maker(path, sort)
      ref.on('child_added', (snap) => {
        const key = snap.key
        dispatch_response({dispatch, update_action, path, payload: {[key]: snap.val()}, key})
      })
    }
    return Promise.resolve()
  }
  // need more
  sort.limitToFirst = batch
  sort.startAt = keys[keys.length - 1]
  const ref = ref_maker(path, sort)

  return ref.once('value').then(batch_check({is_on, path, update_action, batch, sort, dispatch}))
}
const batch_get = ({is_on, path, update_action, batch, sort = {}, dispatch}) => {
  sort.limitToFirst = batch
  sort.orderBy = sort.orderBy || {type: 'Key'}
  let ref = ref_maker(path, sort)
  return ref.once('value')
    .then(batch_check({is_on, path, update_action, batch, sort, dispatch}))
}

handlers.on = ({meta: {path, update_action, init_value, batch, sort}}) => (dispatch, getState) => {
  const state = selectors.listeners(getState())[path]
  if (state && state.count > 1) return Promise.resolve()

  if (batch) return batch_get({is_on: true, path, update_action, init_value, batch, sort, dispatch, getState})

  const this_ref = ref_maker(path, sort)
  let first_time = true
  const response = new Promise((resolve) => {
    setTimeout( // on is not always async this force it to be
      () => {
        this_ref.on('value', (snap) => {
          if (!snap.exists() && init_value) {
            this_ref.set(init_value)
          } else {
            const payload = snap.val()
            dispatch_response({dispatch, update_action, path, payload, key: snap.key})

            if (response.callback) dispatch(response.callback(payload))

            if (first_time) {
              first_time = false
              resolve(snap)
            }
          }
        })
      },
      0
    )
  })
  response.on = (callback) => response.callback = callback
  return response
}
handlers.set = ({payload, meta: {path}}) => (dispatch, getState) => {
  const this_ref = get_root_ref().child(path)
  return this_ref.set(payload)
}
handlers.update = ({payload, meta: {path}}) => (dispatch, getState) => {
  const this_ref = get_root_ref().child(path)
  return this_ref.update(payload)
}
handlers.push = ({payload, meta: {path}}) => (dispatch, getState) => {
  const this_ref = get_root_ref().child(path).push()
  this_ref.then(() => {
    if (_.isEmpty(payload)) {
      return {}
    }
    const real_payload = _.mapValues(payload, (v) => (v === SPECIAL_VALUES.KEY) ? this_ref.key : v)
    return this_ref.set(real_payload)
  })
  return this_ref
}
handlers.off = ({meta: {path}}) => (dispatch, getState) => {
  const this_ref = get_root_ref().child(path)
  this_ref.off()
  return Promise.resolve()
}
handlers.remove = ({meta: {path}}) => (dispatch, getState) => {
  const this_ref = get_root_ref().child(path)
  this_ref.remove()
  return Promise.resolve()
}
handlers.switch = (action) => (dispatch, getState) => {
  if (!action.meta.old_path) return handlers.on(action)(dispatch, getState)

  return handlers.off({meta: {path: action.meta.old_path}})(dispatch, getState)
    .then(() => handlers.on(action)(dispatch, getState))
}

export default _.mapKeys(handlers, (value, key) => `firebase/${key}`)
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * Author: Robert Kereskenyi
 */

"use strict";

define(['jquery',
        'underscore',
        'js/Constants',
        'js/NodePropertyNames',
        'logManager',
        'js/Panels/MetaEditor/MetaEditorConstants',
        'eventDispatcher',
        'text!./METATemplate.js'], function (_jquery,
                                    _underscore,
                                    CONSTANTS,
                                    nodePropertyNames,
                                    logManager,
                                    MetaEditorConstants,
                                    EventDispatcher,
                                    METATemplateJS) {

    var META_RULES_CONTAINER_NODE_ID = MetaEditorConstants.META_ASPECT_CONTAINER_ID,
        _client,
        _territoryId,
        _territoryUI,
        TerritoryUI,
        _metaMembers,
        _patterns = {},
        _logger = logManager.create("METAAspectHelper"),
        _events = {'META_ASPECT_CHANGED': 'META_ASPECT_CHANGED'},
        _metaTypes;

    TerritoryUI = function () {
        $.extend(this, new EventDispatcher());
    };

    TerritoryUI.prototype.onOneEvent = function (/*events*/) {
        _processMetaContainer();

        this.dispatchEvent(_events.META_ASPECT_CHANGED);
    };

    var _reset = function () {
        _metaTypes = {};

        if (_territoryId) {
            _client.removeUI(_territoryId);
        }

        //there is an open project
        if (_client.getActiveProject()) {
            _territoryId = _client.addUI(_territoryUI, true);

            _patterns = {};
            _metaMembers = [];
            _patterns[META_RULES_CONTAINER_NODE_ID] = { "children": 0 };

            setTimeout(function (){
                _client.updateTerritory(_territoryId, _patterns);
            }, 100);

        }
    };

    var _metaFriendlyName = function (name) {
        var ret = name,
            re,
            i;

        // Not allowed characters to replace.
        var input = "áéíóöőúüűÁÉÍÓÖŐÚÜŰ ";

        // Safe characters to replace to.
        var output = "aeiooouuuAEIOOOUUU_";

        // allowed characters
        var allowed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_';

        i = input.length;
        while (i--) {
            re = new RegExp(input[i], "g");
            ret = ret.replace(re, output[i]);
        }

        i = ret.length;
        while (i--) {
            if (allowed.indexOf(ret[i]) === -1) {
                ret.splice(i, 1);
            }
        }

        return ret;
    };

    var _processMetaContainer = function () {
        var metaContainer = _client.getNode(META_RULES_CONTAINER_NODE_ID);

        //reset META info container
        _metaTypes = {};

        if (metaContainer) {
            //read the META rules out of the META container and generate
            var metaAspectSetMembers = metaContainer.getMemberIds(MetaEditorConstants.META_ASPECT_SET_NAME),
                diff,
                territoryChanged = false,
                len,
                nodeID,
                nodeName;

            if (metaAspectSetMembers && metaAspectSetMembers.length > 0) {
                //check deleted nodes
                diff = _.difference(_metaMembers, metaAspectSetMembers);
                len = diff.length;
                while (len--) {
                    if (diff[len] !== META_RULES_CONTAINER_NODE_ID) {
                        delete _patterns[diff[len]];
                        territoryChanged = true;
                    }
                }

                //check added nodes
                diff = _.difference(metaAspectSetMembers, _metaMembers);
                len = diff.length;
                while (len--) {
                    if (diff[len] !== META_RULES_CONTAINER_NODE_ID) {
                        _patterns[diff[len]] = { "children": 0 };
                        territoryChanged = true;
                    }
                }

                //save the new contained nodes
                _metaMembers = metaAspectSetMembers.slice(0);

                _metaTypes = {};

                //generate the ID - TYPE mapping
                len = _metaMembers.length;
                while (len--) {
                    nodeID = _metaMembers[len];
                    var metaMemberNode = _client.getNode(nodeID);

                    if (metaMemberNode) {
                        nodeName = _metaFriendlyName(metaMemberNode.getAttribute(nodePropertyNames.Attributes.name));

                        if (nodeName === undefined || nodeName === null || nodeName === "") {
                            _logger.error('META item "' + nodeID + '" has an invalid name of: ' + nodeName);
                        } else {
                            if (_metaTypes.hasOwnProperty(nodeName)) {
                                _logger.error('Duplicate name on META level: "' + nodeName + '"');
                                delete _metaTypes[nodeName];
                            } else {
                                _metaTypes[nodeName] = nodeID;
                            }
                        }
                    }
                }

                _logger.debug('_metaTypes: \n' + JSON.stringify(_metaTypes));

                //there was change in the territory
                if (territoryChanged === true) {
                    setTimeout(function (){
                        _client.updateTerritory(_territoryId, _patterns);
                    }, 10);
                }
            }
        }
    };

    var _initialize = function (c) {
        //if already initialized, just return
        if (_client) {
            return;
        }
        _client = c;

        _client.addEventListener(_client.events.PROJECT_OPENED, function (/*__project, projectName*/) {
            _reset();
        });

        _client.addEventListener(_client.events.PROJECT_CLOSED, function (/*__project*/) {
            _reset();
        });

        _client.addEventListener(_client.events.BRANCH_CHANGED, function (/*__project, branch*/) {
            _reset();
        });

        _territoryUI = new TerritoryUI();
        _initialize = undefined;
    };

    var _isMETAType = function (objID, metaTypeID) {
        var result = false;

        if (objID && metaTypeID) {
            result = _client.isTypeOf(objID, metaTypeID);
        }

        return result;
    };

    var _getMetaAspectMembers = function () {
        var members = [];

        for (var m in _metaTypes) {
            if (_metaTypes.hasOwnProperty(m)) {
                members.push(_metaTypes[m]);
            }
        }

        return members;
    };

    var _addEventListener = function (event, callback) {
        if (_territoryUI) {
            _territoryUI.addEventListener(event, callback);
        }
    };

    var _removeEventListener = function (event, callback) {
        if (_territoryUI) {
            _territoryUI.removeEventListener(event, callback);
        }
    };

    var _getMETAAspectTypes = function () {
        var result = {};
        _.extend(result, _metaTypes);

        return result;
    };

    var _getMETAAspectTypesSorted = function () {
        var result = {},
            typeNames = [],
            m;

        for (m in _metaTypes) {
            if (_metaTypes.hasOwnProperty(m)) {
                typeNames.push(m);
            }
        }

        typeNames.sort();

        for (m = 0; m < typeNames.length; m += 1) {
            result[typeNames[m]] = _metaTypes[typeNames[m]];
        }

        return result;
    };

    /*
    Returns the parent meta types of the given object ID in the order of inheritance.
     */
    var _getMETATypesOf = function (objID) {
        var result = [];

        for (var m in _metaTypes) {
            if (_metaTypes.hasOwnProperty(m)) {
                if (_isMETAType(objID, _metaTypes[m])) {
                    result.push(m);
                }
            }
        }

        // sort based on metatypes inheritance
        result.sort(function(a, b) {
            return  _isMETAType(_metaTypes[a], _metaTypes[b]) ? -1 : 1;
        });

        return result;
    };

    var _generateMETAAspectJavaScript = function () {
        var result = {};

        if (!_.isEmpty(_metaTypes)) {
            var projName = _client.getActiveProject();
            var content = METATemplateJS;
            var sortedMetaTypes = _getMETAAspectTypesSorted();
            var typeCheckMethodTemplate = 'var _is__METATYPE__ = function (objID) { return METAAspectHelper.isMETAType(objID, _metaTypes.__METATYPE__); };'
            var typeCheckMethods = '';
            var typeCheckMethodsMap = [];
            var typeCheckMethodNamePrefix = 'is';
            var typeCheckMethodsMapIndent = '\t\t\t';
            var metaAspectTypesMap = [];

            //generate each type checker method
            /*
             var _isXXX = function (objID) {
                return METAAspectHelper.isMETAType(objID, _metaTypes.XXX);
             };
             */
            for (var t in sortedMetaTypes) {
                if (sortedMetaTypes.hasOwnProperty(t)) {
                    typeCheckMethods += typeCheckMethodTemplate.replace(/__METATYPE__/g, t) + '\n\t';
                    typeCheckMethodsMap.push(typeCheckMethodNamePrefix + t + ": _" + typeCheckMethodNamePrefix + t);
                    metaAspectTypesMap.push('\'' + t + '\'' + ': ' + '\'' + sortedMetaTypes[t] + '\'');
                }
            }

            content = content.replace( /__PROJECT__/g, projName);
            content = content.replace(/__META_ASPECT_TYPES__/g, '{\n\t\t' + metaAspectTypesMap.join(',\n\t\t') + '\n\t}');
            content = content.replace(/__META_ASPECT_TYPE_CHECKING__/g, typeCheckMethods);
            content = content.replace(/__TYPE_CHECK_METHOD_MAP__/g, '{\n' + typeCheckMethodsMapIndent + typeCheckMethodsMap.join(',\n' + typeCheckMethodsMapIndent) + '\n\t\t}');

            result.fileName = projName + ".META.js";
            result.content = content;
        }

        return result;
    };

    //return utility functions
    return { initialize: _initialize,
            isMETAType: _isMETAType,
            getMetaAspectMembers: _getMetaAspectMembers,
            events: _events,
            addEventListener: _addEventListener,
            removeEventListener: _removeEventListener,
            getMETAAspectTypes: _getMETAAspectTypes,
            getMETAAspectTypesSorted: _getMETAAspectTypesSorted,
            getMETATypesOf: _getMETATypesOf,
            generateMETAAspectJavaScript: _generateMETAAspectJavaScript
        };
});<commit_msg>bugfix in eliminating invalid chatracters<commit_after>/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * Author: Robert Kereskenyi
 */

"use strict";

define(['jquery',
        'underscore',
        'js/Constants',
        'js/NodePropertyNames',
        'logManager',
        'js/Panels/MetaEditor/MetaEditorConstants',
        'eventDispatcher',
        'text!./METATemplate.js'], function (_jquery,
                                    _underscore,
                                    CONSTANTS,
                                    nodePropertyNames,
                                    logManager,
                                    MetaEditorConstants,
                                    EventDispatcher,
                                    METATemplateJS) {

    var META_RULES_CONTAINER_NODE_ID = MetaEditorConstants.META_ASPECT_CONTAINER_ID,
        _client,
        _territoryId,
        _territoryUI,
        TerritoryUI,
        _metaMembers,
        _patterns = {},
        _logger = logManager.create("METAAspectHelper"),
        _events = {'META_ASPECT_CHANGED': 'META_ASPECT_CHANGED'},
        _metaTypes;

    TerritoryUI = function () {
        $.extend(this, new EventDispatcher());
    };

    TerritoryUI.prototype.onOneEvent = function (/*events*/) {
        _processMetaContainer();

        this.dispatchEvent(_events.META_ASPECT_CHANGED);
    };

    var _reset = function () {
        _metaTypes = {};

        if (_territoryId) {
            _client.removeUI(_territoryId);
        }

        //there is an open project
        if (_client.getActiveProject()) {
            _territoryId = _client.addUI(_territoryUI, true);

            _patterns = {};
            _metaMembers = [];
            _patterns[META_RULES_CONTAINER_NODE_ID] = { "children": 0 };

            setTimeout(function (){
                _client.updateTerritory(_territoryId, _patterns);
            }, 100);

        }
    };

    var _metaFriendlyName = function (name) {
        var ret = name,
            re,
            i;

        // Not allowed characters to replace.
        var input = "áéíóöőúüűÁÉÍÓÖŐÚÜŰ ";

        // Safe characters to replace to.
        var output = "aeiooouuuAEIOOOUUU_";

        // allowed characters
        var allowed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_';

        i = input.length;
        while (i--) {
            re = new RegExp(input[i], "g");
            ret = ret.replace(re, output[i]);
        }

        i = ret.length;
        while (i--) {
            if (allowed.indexOf(ret[i]) === -1) {
                ret = ret.substr(0, i) + ret.substr(i + 1);
            }
        }

        return ret;
    };

    var _processMetaContainer = function () {
        var metaContainer = _client.getNode(META_RULES_CONTAINER_NODE_ID);

        //reset META info container
        _metaTypes = {};

        if (metaContainer) {
            //read the META rules out of the META container and generate
            var metaAspectSetMembers = metaContainer.getMemberIds(MetaEditorConstants.META_ASPECT_SET_NAME),
                diff,
                territoryChanged = false,
                len,
                nodeID,
                nodeName;

            if (metaAspectSetMembers && metaAspectSetMembers.length > 0) {
                //check deleted nodes
                diff = _.difference(_metaMembers, metaAspectSetMembers);
                len = diff.length;
                while (len--) {
                    if (diff[len] !== META_RULES_CONTAINER_NODE_ID) {
                        delete _patterns[diff[len]];
                        territoryChanged = true;
                    }
                }

                //check added nodes
                diff = _.difference(metaAspectSetMembers, _metaMembers);
                len = diff.length;
                while (len--) {
                    if (diff[len] !== META_RULES_CONTAINER_NODE_ID) {
                        _patterns[diff[len]] = { "children": 0 };
                        territoryChanged = true;
                    }
                }

                //save the new contained nodes
                _metaMembers = metaAspectSetMembers.slice(0);

                _metaTypes = {};

                //generate the ID - TYPE mapping
                len = _metaMembers.length;
                while (len--) {
                    nodeID = _metaMembers[len];
                    var metaMemberNode = _client.getNode(nodeID);

                    if (metaMemberNode) {
                        nodeName = _metaFriendlyName(metaMemberNode.getAttribute(nodePropertyNames.Attributes.name));

                        if (nodeName === undefined || nodeName === null || nodeName === "") {
                            _logger.error('META item "' + nodeID + '" has an invalid name of: ' + nodeName);
                        } else {
                            if (_metaTypes.hasOwnProperty(nodeName)) {
                                _logger.error('Duplicate name on META level: "' + nodeName + '"');
                                delete _metaTypes[nodeName];
                            } else {
                                _metaTypes[nodeName] = nodeID;
                            }
                        }
                    }
                }

                _logger.debug('_metaTypes: \n' + JSON.stringify(_metaTypes));

                //there was change in the territory
                if (territoryChanged === true) {
                    setTimeout(function (){
                        _client.updateTerritory(_territoryId, _patterns);
                    }, 10);
                }
            }
        }
    };

    var _initialize = function (c) {
        //if already initialized, just return
        if (_client) {
            return;
        }
        _client = c;

        _client.addEventListener(_client.events.PROJECT_OPENED, function (/*__project, projectName*/) {
            _reset();
        });

        _client.addEventListener(_client.events.PROJECT_CLOSED, function (/*__project*/) {
            _reset();
        });

        _client.addEventListener(_client.events.BRANCH_CHANGED, function (/*__project, branch*/) {
            _reset();
        });

        _territoryUI = new TerritoryUI();
        _initialize = undefined;
    };

    var _isMETAType = function (objID, metaTypeID) {
        var result = false;

        if (objID && metaTypeID) {
            result = _client.isTypeOf(objID, metaTypeID);
        }

        return result;
    };

    var _getMetaAspectMembers = function () {
        var members = [];

        for (var m in _metaTypes) {
            if (_metaTypes.hasOwnProperty(m)) {
                members.push(_metaTypes[m]);
            }
        }

        return members;
    };

    var _addEventListener = function (event, callback) {
        if (_territoryUI) {
            _territoryUI.addEventListener(event, callback);
        }
    };

    var _removeEventListener = function (event, callback) {
        if (_territoryUI) {
            _territoryUI.removeEventListener(event, callback);
        }
    };

    var _getMETAAspectTypes = function () {
        var result = {};
        _.extend(result, _metaTypes);

        return result;
    };

    var _getMETAAspectTypesSorted = function () {
        var result = {},
            typeNames = [],
            m;

        for (m in _metaTypes) {
            if (_metaTypes.hasOwnProperty(m)) {
                typeNames.push(m);
            }
        }

        typeNames.sort();

        for (m = 0; m < typeNames.length; m += 1) {
            result[typeNames[m]] = _metaTypes[typeNames[m]];
        }

        return result;
    };

    /*
    Returns the parent meta types of the given object ID in the order of inheritance.
     */
    var _getMETATypesOf = function (objID) {
        var result = [];

        for (var m in _metaTypes) {
            if (_metaTypes.hasOwnProperty(m)) {
                if (_isMETAType(objID, _metaTypes[m])) {
                    result.push(m);
                }
            }
        }

        // sort based on metatypes inheritance
        result.sort(function(a, b) {
            return  _isMETAType(_metaTypes[a], _metaTypes[b]) ? -1 : 1;
        });

        return result;
    };

    var _generateMETAAspectJavaScript = function () {
        var result = {};

        if (!_.isEmpty(_metaTypes)) {
            var projName = _client.getActiveProject();
            var content = METATemplateJS;
            var sortedMetaTypes = _getMETAAspectTypesSorted();
            var typeCheckMethodTemplate = 'var _is__METATYPE__ = function (objID) { return METAAspectHelper.isMETAType(objID, _metaTypes.__METATYPE__); };'
            var typeCheckMethods = '';
            var typeCheckMethodsMap = [];
            var typeCheckMethodNamePrefix = 'is';
            var typeCheckMethodsMapIndent = '\t\t\t';
            var metaAspectTypesMap = [];

            //generate each type checker method
            /*
             var _isXXX = function (objID) {
                return METAAspectHelper.isMETAType(objID, _metaTypes.XXX);
             };
             */
            for (var t in sortedMetaTypes) {
                if (sortedMetaTypes.hasOwnProperty(t)) {
                    typeCheckMethods += typeCheckMethodTemplate.replace(/__METATYPE__/g, t) + '\n\t';
                    typeCheckMethodsMap.push(typeCheckMethodNamePrefix + t + ": _" + typeCheckMethodNamePrefix + t);
                    metaAspectTypesMap.push('\'' + t + '\'' + ': ' + '\'' + sortedMetaTypes[t] + '\'');
                }
            }

            content = content.replace( /__PROJECT__/g, projName);
            content = content.replace(/__META_ASPECT_TYPES__/g, '{\n\t\t' + metaAspectTypesMap.join(',\n\t\t') + '\n\t}');
            content = content.replace(/__META_ASPECT_TYPE_CHECKING__/g, typeCheckMethods);
            content = content.replace(/__TYPE_CHECK_METHOD_MAP__/g, '{\n' + typeCheckMethodsMapIndent + typeCheckMethodsMap.join(',\n' + typeCheckMethodsMapIndent) + '\n\t\t}');

            result.fileName = projName + ".META.js";
            result.content = content;
        }

        return result;
    };

    //return utility functions
    return { initialize: _initialize,
            isMETAType: _isMETAType,
            getMetaAspectMembers: _getMetaAspectMembers,
            events: _events,
            addEventListener: _addEventListener,
            removeEventListener: _removeEventListener,
            getMETAAspectTypes: _getMETAAspectTypes,
            getMETAAspectTypesSorted: _getMETAAspectTypesSorted,
            getMETATypesOf: _getMETATypesOf,
            generateMETAAspectJavaScript: _generateMETAAspectJavaScript
        };
});<|endoftext|>