<commit_before>"use strict";

define(['js/Constants',
    'js/NodePropertyNames',
    'js/Widgets/DiagramDesigner/DiagramDesignerWidget.DecoratorBase',
    'js/Widgets/DiagramDesigner/DiagramDesignerWidget.Constants',
    'text!../Core/ModelDecorator.html',
    '../Core/ModelDecorator.Core',
    '../Core/ModelDecorator.Constants',
    'js/DragDrop/DragConstants',
    'js/DragDrop/DragHelper',
    'css!./ModelDecorator.DiagramDesignerWidget'], function (CONSTANTS,
                                                          nodePropertyNames,
                                                          DiagramDesignerWidgetDecoratorBase,
                                                          DiagramDesignerWidgetConstants,
                                                          modelDecoratorTemplate,
                                                          ModelDecoratorCore,
                                                          ModelDecoratorConstants,
                                                          DragConstants,
                                                          DragHelper) {

    var ModelDecoratorDiagramDesignerWidget,
        DECORATOR_ID = "ModelDecoratorDiagramDesignerWidget",
        PORT_CONTAINER_OFFSET_Y = 15,
        ACCEPT_DROPPABLE_CLASS = 'accept-droppable',
        DRAGGABLE_MOUSE = 'DRAGGABLE';

    ModelDecoratorDiagramDesignerWidget = function (options) {
        var opts = _.extend( {}, options);

        DiagramDesignerWidgetDecoratorBase.apply(this, [opts]);

        this._initializeVariables({"connectors": true});

        this._selfPatterns = {};

        this.logger.debug("ModelDecoratorDiagramDesignerWidget ctor");
    };

    /************************ INHERITANCE *********************/
    _.extend(ModelDecoratorDiagramDesignerWidget.prototype, DiagramDesignerWidgetDecoratorBase.prototype);
    _.extend(ModelDecoratorDiagramDesignerWidget.prototype, ModelDecoratorCore.prototype);

    /**************** OVERRIDE INHERITED / EXTEND ****************/

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.DECORATORID = DECORATOR_ID;

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.$DOMBase = $(modelDecoratorTemplate);

    //callback method for territory update
    ModelDecoratorDiagramDesignerWidget.prototype.onOneEvent = function (events) {
        //don't really care here, just want to make sure that the reference object is loaded in the client
        this.logger.debug('onOneEvent: ' + JSON.stringify(events));
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.on_addTo = function () {
        var self = this;

        this._renderContent();

        // set title editable on double-click
        this.skinParts.$name.on("dblclick.editOnDblClick", null, function (event) {
            if (self.hostDesignerItem.canvas.getIsReadOnlyMode() !== true) {
                $(this).editInPlace({"class": "",
                    "onChange": function (oldValue, newValue) {
                        self.__onNodeTitleChanged(oldValue, newValue);
                    }});
            }
            event.stopPropagation();
            event.preventDefault();
        });

        // reference icon on double-click
        this.$el.on("dblclick.refDblClick", '.' + ModelDecoratorConstants.REFERENCE_POINTER_CLASS, function (event) {
            if (!($(this).hasClass(ModelDecoratorConstants.REFERENCE_POINTER_CLASS_NONSET))) {
                self.__navigateToReference();
            }
            event.stopPropagation();
            event.preventDefault();
        });
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.update = function () {
        this._update();
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.calculateDimension = function () {
        if (this.hostDesignerItem) {
            this.hostDesignerItem.setSize(this.$el.outerWidth(true), this.$el.outerHeight(true));

            this._paddingTop = parseInt(this.$el.css('padding-top'), 10);
            this._borderTop = parseInt(this.$el.css('border-top-width'), 10);
        }
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.destroy = function () {
        //drop territory
        if (this._territoryId) {
            this._control._client.removeUI(this._territoryId);
        }

        //call base destroy
        ModelDecoratorCore.prototype.destroy.call(this);
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.getConnectionAreas = function (id/*, isEnd, connectionMetaInfo*/) {
        var result = [],
            edge = 10,
            LEN = 20;

        //by default return the bounding box edges midpoints

        if (id === undefined || id === this.hostDesignerItem.id) {
            //top left
            result.push( {"id": "0",
                "x1": edge,
                "y1": 0,
                "x2": this.hostDesignerItem.getWidth() - edge,
                "y2": 0,
                "angle1": 270,
                "angle2": 270,
                "len": LEN} );

            result.push( {"id": "1",
                "x1": edge,
                "y1": this.hostDesignerItem.getHeight(),
                "x2": this.hostDesignerItem.getWidth() - edge,
                "y2": this.hostDesignerItem.getHeight(),
                "angle1": 90,
                "angle2": 90,
                "len": LEN} );
        } else {
            //subcomponent
            var portConnArea = this._ports[id].getConnectorArea(),
                idx = this._portIDs.indexOf(id);

            result.push( {"id": idx,
                "x1": portConnArea.x1,
                "y1": portConnArea.y1 + PORT_CONTAINER_OFFSET_Y + this._paddingTop + this._borderTop,
                "x2": portConnArea.x2,
                "y2": portConnArea.y2 + PORT_CONTAINER_OFFSET_Y + this._paddingTop + this._borderTop,
                "angle1": portConnArea.angle1,
                "angle2": portConnArea.angle2,
                "len": portConnArea.len} );
        }

        return result;
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    //called when the designer item's subcomponent should be updated
    ModelDecoratorDiagramDesignerWidget.prototype.updateSubcomponent = function (portId) {
        this._updatePort(portId);
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    //Shows the 'connectors' - appends them to the DOM
    ModelDecoratorDiagramDesignerWidget.prototype.showSourceConnectors = function (params) {
        var connectors,
            i;

        if (!params) {
            this.$sourceConnectors.show();
            if (this._portIDs) {
                i = this._portIDs.length;
                while (i--) {
                    this._ports[this._portIDs[i]].showConnectors();
                }
            }
        } else {
            connectors = params.connectors;
            i = connectors.length;
            while (i--) {
                if (connectors[i] === undefined) {
                    //show connector for the represented item itself
                    this.$sourceConnectors.show();
                } else {
                    //one of the ports' connector should be displayed
                    if (this._ports[connectors[i]]) {
                        this._ports[connectors[i]].showConnectors();
                    }
                }
            }
        }
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    //Hides the 'connectors' - detaches them from the DOM
    ModelDecoratorDiagramDesignerWidget.prototype.hideSourceConnectors = function () {
        var i;

        this.$sourceConnectors.hide();

        if (this._portIDs) {
            i = this._portIDs.length;
            while (i--) {
                this._ports[this._portIDs[i]].hideConnectors();
            }
        }
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    //should highlight the connectors for the given elements
    ModelDecoratorDiagramDesignerWidget.prototype.showEndConnectors = function (params) {
       this.showSourceConnectors(params);
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    //Hides the 'connectors' - detaches them from the DOM
    ModelDecoratorDiagramDesignerWidget.prototype.hideEndConnectors = function () {
        this.hideSourceConnectors();
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.notifyComponentEvent = function (componentList) {
        var len = componentList.length;
        while (len--) {
            this._updatePort(componentList[len].id);
        }
        this._checkTerritoryReady();
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._portPositionChanged = function (portId) {
        this.calculateDimension();
        this.hostDesignerItem.canvas.dispatchEvent(this.hostDesignerItem.canvas.events.ITEM_SUBCOMPONENT_POSITION_CHANGED, {"ItemID": this.hostDesignerItem.id,
            "SubComponentID": portId});
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._registerForNotification = function(portId) {
        var partId = this._metaInfo[CONSTANTS.GME_ID];

        this._control.registerComponentIDForPartID(portId, partId);
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._unregisterForNotification = function(portId) {
        var partId = this._metaInfo[CONSTANTS.GME_ID];

        this._control.unregisterComponentIDFromPartID(portId, partId);
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._renderPort = function (portId) {
        var isPort;

        isPort = ModelDecoratorCore.prototype._renderPort.call(this, portId);

        if (isPort) {
            this.__registerAsSubcomponent(portId);
        }
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._removePort = function (portId) {
        var idx = this._portIDs.indexOf(portId);

        if (idx !== -1) {
            this.__unregisterAsSubcomponent(portId);
        }

        ModelDecoratorCore.prototype._removePort.call(this, portId);
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._updateReference = function () {
        var inverseClass = 'inverse-on-hover',
            self = this;

        ModelDecoratorCore.prototype._updateReference.call(this);

        if (this.skinParts.$ref) {
            if (this.skinParts.$ref.hasClass(ModelDecoratorConstants.REFERENCE_POINTER_CLASS_NONSET)) {
                this.skinParts.$ref.removeClass(inverseClass);
            } else {
                this.skinParts.$ref.addClass(inverseClass);
            }

            //edit droppable mode
            this.$el.on('mouseenter.' + DRAGGABLE_MOUSE, null, function (event) {
                self.__onMouseEnter(event);
            })
            .on('mouseleave.' + DRAGGABLE_MOUSE, null, function (event) {
                self.__onMouseLeave(event);
            })
            .on('mouseup.' + DRAGGABLE_MOUSE, null, function (event) {
                self.__onMouseUp(event);
            });
        } else {
            this.$el.off('mouseenter.' + DRAGGABLE_MOUSE)
                .off('mouseleave.' + DRAGGABLE_MOUSE)
                .off('mouseup.' + DRAGGABLE_MOUSE);
        }
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._refToChanged = function (oldValue, newValue) {
        this.logger.debug('refToChanged from ' + oldValue + ' to ' + newValue);

        if (oldValue) {
            delete this._selfPatterns[oldValue];
        }

        if (newValue) {
            this._territoryId = this._territoryId || this._control._client.addUI(this, true);
            this._selfPatterns[newValue] = { "children": 0 };
        }

        if (this._selfPatterns && !_.isEmpty(this._selfPatterns)) {
            this._control._client.updateTerritory(this._territoryId, this._selfPatterns);
        } else {
            if (this._territoryId) {
                this._control._client.removeUI(this._territoryId);
            }
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onBackgroundDroppableOver = function (helper) {
        if (this.__onBackgroundDroppableAccept(helper) === true) {
            this.__doAcceptDroppable(true);
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onBackgroundDroppableOut = function () {
        this.__doAcceptDroppable(false);
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onBackgroundDrop = function (helper) {
        var dragInfo = helper.data(DragConstants.DRAG_INFO),
            dragItems = DragHelper.getDragItems(dragInfo),
            dragEffects = DragHelper.getDragEffects(dragInfo);

        if (this.__acceptDroppable === true) {
            if (dragItems.length === 1 && dragEffects.indexOf(DragHelper.DRAG_EFFECTS.DRAG_CREATE_REFERENCE) !== -1) {
                this._setReferenceValue(dragItems[0]);
            }
        }

        this.__doAcceptDroppable(false);
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onBackgroundDroppableAccept = function (helper) {
        var dragInfo = helper.data(DragConstants.DRAG_INFO),
            dragItems = DragHelper.getDragItems(dragInfo),
            dragEffects = DragHelper.getDragEffects(dragInfo);

        return dragItems.length === 1 &&
            dragItems[0] !== this._metaInfo[CONSTANTS.GME_ID] &&
            dragEffects.indexOf(DragHelper.DRAG_EFFECTS.DRAG_CREATE_REFERENCE) !== -1 &&
            this._control._client.isValidTarget(this._metaInfo[CONSTANTS.GME_ID],"ref",dragItems[0]);
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__doAcceptDroppable = function (accept) {
        if (accept === true) {
            this.__acceptDroppable = true;
            this.$el.addClass(ACCEPT_DROPPABLE_CLASS);
        } else {
            this.__acceptDroppable = false;
            this.$el.removeClass(ACCEPT_DROPPABLE_CLASS);
        }

        this.hostDesignerItem.canvas._enableDroppable(!accept);
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onMouseEnter = function (event) {
        if (this.hostDesignerItem.canvas.getIsReadOnlyMode() !== true) {
            //check if it's dragging anything with jQueryUI
            if ($.ui.ddmanager.current && $.ui.ddmanager.current.helper) {
                this.__onDragOver = true;
                this.__onBackgroundDroppableOver($.ui.ddmanager.current.helper);
                event.stopPropagation();
                event.preventDefault();
            }
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onMouseLeave = function (event) {
        if (this.__onDragOver) {
            this.__onBackgroundDroppableOut();
            this.__onDragOver = false;
            event.stopPropagation();
            event.preventDefault();
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onMouseUp = function (/*event*/) {
        if (this.__onDragOver) {
            //TODO: this is still questionable if we should hack the jQeuryUI 's draggable&droppable and use half of it only
            this.__onBackgroundDrop($.ui.ddmanager.current.helper);
            this.__onDragOver = false;
            this.hostDesignerItem.canvas._enableDroppable(false);
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__registerAsSubcomponent = function(portId) {
        if (this.hostDesignerItem) {
            this.hostDesignerItem.registerSubcomponent(portId, {"GME_ID": portId});
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__unregisterAsSubcomponent = function(portId) {
        if (this.hostDesignerItem) {
            this.hostDesignerItem.unregisterSubcomponent(portId);
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onNodeTitleChanged = function (oldValue, newValue) {
        var client = this._control._client;

        client.setAttributes(this._metaInfo[CONSTANTS.GME_ID], nodePropertyNames.Attributes.name, newValue);
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__navigateToReference = function () {
        var client = this._control._client,
            nodeObj;

        if (this._refTo) {
            nodeObj = client.getNode(this._refTo);
            if (nodeObj) {
                if (nodeObj.getParentId()) {
                    this._control._client.setSelectedObjectId(nodeObj.getParentId(), this._refTo);
                } else {
                    this._control._client.setSelectedObjectId('root', this._refTo);
                }
            } else {
                this.logger.warning('_navigateToReference client.getNode(' + this._refTo + ') returned null... :(');
            }
        }
    };

    return ModelDecoratorDiagramDesignerWidget;
});<commit_msg>using CONSTANTS.POINTER_REF insted of "ref" hardcoded string<commit_after>"use strict";

define(['js/Constants',
    'js/NodePropertyNames',
    'js/Widgets/DiagramDesigner/DiagramDesignerWidget.DecoratorBase',
    'js/Widgets/DiagramDesigner/DiagramDesignerWidget.Constants',
    'text!../Core/ModelDecorator.html',
    '../Core/ModelDecorator.Core',
    '../Core/ModelDecorator.Constants',
    'js/DragDrop/DragConstants',
    'js/DragDrop/DragHelper',
    'css!./ModelDecorator.DiagramDesignerWidget'], function (CONSTANTS,
                                                          nodePropertyNames,
                                                          DiagramDesignerWidgetDecoratorBase,
                                                          DiagramDesignerWidgetConstants,
                                                          modelDecoratorTemplate,
                                                          ModelDecoratorCore,
                                                          ModelDecoratorConstants,
                                                          DragConstants,
                                                          DragHelper) {

    var ModelDecoratorDiagramDesignerWidget,
        DECORATOR_ID = "ModelDecoratorDiagramDesignerWidget",
        PORT_CONTAINER_OFFSET_Y = 15,
        ACCEPT_DROPPABLE_CLASS = 'accept-droppable',
        DRAGGABLE_MOUSE = 'DRAGGABLE';

    ModelDecoratorDiagramDesignerWidget = function (options) {
        var opts = _.extend( {}, options);

        DiagramDesignerWidgetDecoratorBase.apply(this, [opts]);

        this._initializeVariables({"connectors": true});

        this._selfPatterns = {};

        this.logger.debug("ModelDecoratorDiagramDesignerWidget ctor");
    };

    /************************ INHERITANCE *********************/
    _.extend(ModelDecoratorDiagramDesignerWidget.prototype, DiagramDesignerWidgetDecoratorBase.prototype);
    _.extend(ModelDecoratorDiagramDesignerWidget.prototype, ModelDecoratorCore.prototype);

    /**************** OVERRIDE INHERITED / EXTEND ****************/

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.DECORATORID = DECORATOR_ID;

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.$DOMBase = $(modelDecoratorTemplate);

    //callback method for territory update
    ModelDecoratorDiagramDesignerWidget.prototype.onOneEvent = function (events) {
        //don't really care here, just want to make sure that the reference object is loaded in the client
        this.logger.debug('onOneEvent: ' + JSON.stringify(events));
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.on_addTo = function () {
        var self = this;

        this._renderContent();

        // set title editable on double-click
        this.skinParts.$name.on("dblclick.editOnDblClick", null, function (event) {
            if (self.hostDesignerItem.canvas.getIsReadOnlyMode() !== true) {
                $(this).editInPlace({"class": "",
                    "onChange": function (oldValue, newValue) {
                        self.__onNodeTitleChanged(oldValue, newValue);
                    }});
            }
            event.stopPropagation();
            event.preventDefault();
        });

        // reference icon on double-click
        this.$el.on("dblclick.refDblClick", '.' + ModelDecoratorConstants.REFERENCE_POINTER_CLASS, function (event) {
            if (!($(this).hasClass(ModelDecoratorConstants.REFERENCE_POINTER_CLASS_NONSET))) {
                self.__navigateToReference();
            }
            event.stopPropagation();
            event.preventDefault();
        });
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.update = function () {
        this._update();
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.calculateDimension = function () {
        if (this.hostDesignerItem) {
            this.hostDesignerItem.setSize(this.$el.outerWidth(true), this.$el.outerHeight(true));

            this._paddingTop = parseInt(this.$el.css('padding-top'), 10);
            this._borderTop = parseInt(this.$el.css('border-top-width'), 10);
        }
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.destroy = function () {
        //drop territory
        if (this._territoryId) {
            this._control._client.removeUI(this._territoryId);
        }

        //call base destroy
        ModelDecoratorCore.prototype.destroy.call(this);
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.getConnectionAreas = function (id/*, isEnd, connectionMetaInfo*/) {
        var result = [],
            edge = 10,
            LEN = 20;

        //by default return the bounding box edges midpoints

        if (id === undefined || id === this.hostDesignerItem.id) {
            //top left
            result.push( {"id": "0",
                "x1": edge,
                "y1": 0,
                "x2": this.hostDesignerItem.getWidth() - edge,
                "y2": 0,
                "angle1": 270,
                "angle2": 270,
                "len": LEN} );

            result.push( {"id": "1",
                "x1": edge,
                "y1": this.hostDesignerItem.getHeight(),
                "x2": this.hostDesignerItem.getWidth() - edge,
                "y2": this.hostDesignerItem.getHeight(),
                "angle1": 90,
                "angle2": 90,
                "len": LEN} );
        } else {
            //subcomponent
            var portConnArea = this._ports[id].getConnectorArea(),
                idx = this._portIDs.indexOf(id);

            result.push( {"id": idx,
                "x1": portConnArea.x1,
                "y1": portConnArea.y1 + PORT_CONTAINER_OFFSET_Y + this._paddingTop + this._borderTop,
                "x2": portConnArea.x2,
                "y2": portConnArea.y2 + PORT_CONTAINER_OFFSET_Y + this._paddingTop + this._borderTop,
                "angle1": portConnArea.angle1,
                "angle2": portConnArea.angle2,
                "len": portConnArea.len} );
        }

        return result;
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    //called when the designer item's subcomponent should be updated
    ModelDecoratorDiagramDesignerWidget.prototype.updateSubcomponent = function (portId) {
        this._updatePort(portId);
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    //Shows the 'connectors' - appends them to the DOM
    ModelDecoratorDiagramDesignerWidget.prototype.showSourceConnectors = function (params) {
        var connectors,
            i;

        if (!params) {
            this.$sourceConnectors.show();
            if (this._portIDs) {
                i = this._portIDs.length;
                while (i--) {
                    this._ports[this._portIDs[i]].showConnectors();
                }
            }
        } else {
            connectors = params.connectors;
            i = connectors.length;
            while (i--) {
                if (connectors[i] === undefined) {
                    //show connector for the represented item itself
                    this.$sourceConnectors.show();
                } else {
                    //one of the ports' connector should be displayed
                    if (this._ports[connectors[i]]) {
                        this._ports[connectors[i]].showConnectors();
                    }
                }
            }
        }
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    //Hides the 'connectors' - detaches them from the DOM
    ModelDecoratorDiagramDesignerWidget.prototype.hideSourceConnectors = function () {
        var i;

        this.$sourceConnectors.hide();

        if (this._portIDs) {
            i = this._portIDs.length;
            while (i--) {
                this._ports[this._portIDs[i]].hideConnectors();
            }
        }
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    //should highlight the connectors for the given elements
    ModelDecoratorDiagramDesignerWidget.prototype.showEndConnectors = function (params) {
       this.showSourceConnectors(params);
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    //Hides the 'connectors' - detaches them from the DOM
    ModelDecoratorDiagramDesignerWidget.prototype.hideEndConnectors = function () {
        this.hideSourceConnectors();
    };

    /**** Override from DiagramDesignerWidgetDecoratorBase ****/
    ModelDecoratorDiagramDesignerWidget.prototype.notifyComponentEvent = function (componentList) {
        var len = componentList.length;
        while (len--) {
            this._updatePort(componentList[len].id);
        }
        this._checkTerritoryReady();
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._portPositionChanged = function (portId) {
        this.calculateDimension();
        this.hostDesignerItem.canvas.dispatchEvent(this.hostDesignerItem.canvas.events.ITEM_SUBCOMPONENT_POSITION_CHANGED, {"ItemID": this.hostDesignerItem.id,
            "SubComponentID": portId});
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._registerForNotification = function(portId) {
        var partId = this._metaInfo[CONSTANTS.GME_ID];

        this._control.registerComponentIDForPartID(portId, partId);
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._unregisterForNotification = function(portId) {
        var partId = this._metaInfo[CONSTANTS.GME_ID];

        this._control.unregisterComponentIDFromPartID(portId, partId);
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._renderPort = function (portId) {
        var isPort;

        isPort = ModelDecoratorCore.prototype._renderPort.call(this, portId);

        if (isPort) {
            this.__registerAsSubcomponent(portId);
        }
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._removePort = function (portId) {
        var idx = this._portIDs.indexOf(portId);

        if (idx !== -1) {
            this.__unregisterAsSubcomponent(portId);
        }

        ModelDecoratorCore.prototype._removePort.call(this, portId);
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._updateReference = function () {
        var inverseClass = 'inverse-on-hover',
            self = this;

        ModelDecoratorCore.prototype._updateReference.call(this);

        if (this.skinParts.$ref) {
            if (this.skinParts.$ref.hasClass(ModelDecoratorConstants.REFERENCE_POINTER_CLASS_NONSET)) {
                this.skinParts.$ref.removeClass(inverseClass);
            } else {
                this.skinParts.$ref.addClass(inverseClass);
            }

            //edit droppable mode
            this.$el.on('mouseenter.' + DRAGGABLE_MOUSE, null, function (event) {
                self.__onMouseEnter(event);
            })
            .on('mouseleave.' + DRAGGABLE_MOUSE, null, function (event) {
                self.__onMouseLeave(event);
            })
            .on('mouseup.' + DRAGGABLE_MOUSE, null, function (event) {
                self.__onMouseUp(event);
            });
        } else {
            this.$el.off('mouseenter.' + DRAGGABLE_MOUSE)
                .off('mouseleave.' + DRAGGABLE_MOUSE)
                .off('mouseup.' + DRAGGABLE_MOUSE);
        }
    };

    /**** Override from ModelDecoratorCore ****/
    ModelDecoratorDiagramDesignerWidget.prototype._refToChanged = function (oldValue, newValue) {
        this.logger.debug('refToChanged from ' + oldValue + ' to ' + newValue);

        if (oldValue) {
            delete this._selfPatterns[oldValue];
        }

        if (newValue) {
            this._territoryId = this._territoryId || this._control._client.addUI(this, true);
            this._selfPatterns[newValue] = { "children": 0 };
        }

        if (this._selfPatterns && !_.isEmpty(this._selfPatterns)) {
            this._control._client.updateTerritory(this._territoryId, this._selfPatterns);
        } else {
            if (this._territoryId) {
                this._control._client.removeUI(this._territoryId);
            }
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onBackgroundDroppableOver = function (helper) {
        if (this.__onBackgroundDroppableAccept(helper) === true) {
            this.__doAcceptDroppable(true);
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onBackgroundDroppableOut = function () {
        this.__doAcceptDroppable(false);
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onBackgroundDrop = function (helper) {
        var dragInfo = helper.data(DragConstants.DRAG_INFO),
            dragItems = DragHelper.getDragItems(dragInfo),
            dragEffects = DragHelper.getDragEffects(dragInfo);

        if (this.__acceptDroppable === true) {
            if (dragItems.length === 1 && dragEffects.indexOf(DragHelper.DRAG_EFFECTS.DRAG_CREATE_REFERENCE) !== -1) {
                this._setReferenceValue(dragItems[0]);
            }
        }

        this.__doAcceptDroppable(false);
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onBackgroundDroppableAccept = function (helper) {
        var dragInfo = helper.data(DragConstants.DRAG_INFO),
            dragItems = DragHelper.getDragItems(dragInfo),
            dragEffects = DragHelper.getDragEffects(dragInfo);

        return dragItems.length === 1 &&
            dragItems[0] !== this._metaInfo[CONSTANTS.GME_ID] &&
            dragEffects.indexOf(DragHelper.DRAG_EFFECTS.DRAG_CREATE_REFERENCE) !== -1 &&
            this._control._client.isValidTarget(this._metaInfo[CONSTANTS.GME_ID],CONSTANTS.POINTER_REF,dragItems[0]);
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__doAcceptDroppable = function (accept) {
        if (accept === true) {
            this.__acceptDroppable = true;
            this.$el.addClass(ACCEPT_DROPPABLE_CLASS);
        } else {
            this.__acceptDroppable = false;
            this.$el.removeClass(ACCEPT_DROPPABLE_CLASS);
        }

        this.hostDesignerItem.canvas._enableDroppable(!accept);
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onMouseEnter = function (event) {
        if (this.hostDesignerItem.canvas.getIsReadOnlyMode() !== true) {
            //check if it's dragging anything with jQueryUI
            if ($.ui.ddmanager.current && $.ui.ddmanager.current.helper) {
                this.__onDragOver = true;
                this.__onBackgroundDroppableOver($.ui.ddmanager.current.helper);
                event.stopPropagation();
                event.preventDefault();
            }
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onMouseLeave = function (event) {
        if (this.__onDragOver) {
            this.__onBackgroundDroppableOut();
            this.__onDragOver = false;
            event.stopPropagation();
            event.preventDefault();
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onMouseUp = function (/*event*/) {
        if (this.__onDragOver) {
            //TODO: this is still questionable if we should hack the jQeuryUI 's draggable&droppable and use half of it only
            this.__onBackgroundDrop($.ui.ddmanager.current.helper);
            this.__onDragOver = false;
            this.hostDesignerItem.canvas._enableDroppable(false);
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__registerAsSubcomponent = function(portId) {
        if (this.hostDesignerItem) {
            this.hostDesignerItem.registerSubcomponent(portId, {"GME_ID": portId});
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__unregisterAsSubcomponent = function(portId) {
        if (this.hostDesignerItem) {
            this.hostDesignerItem.unregisterSubcomponent(portId);
        }
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__onNodeTitleChanged = function (oldValue, newValue) {
        var client = this._control._client;

        client.setAttributes(this._metaInfo[CONSTANTS.GME_ID], nodePropertyNames.Attributes.name, newValue);
    };

    ModelDecoratorDiagramDesignerWidget.prototype.__navigateToReference = function () {
        var client = this._control._client,
            nodeObj;

        if (this._refTo) {
            nodeObj = client.getNode(this._refTo);
            if (nodeObj) {
                if (nodeObj.getParentId()) {
                    this._control._client.setSelectedObjectId(nodeObj.getParentId(), this._refTo);
                } else {
                    this._control._client.setSelectedObjectId('root', this._refTo);
                }
            } else {
                this.logger.warning('_navigateToReference client.getNode(' + this._refTo + ') returned null... :(');
            }
        }
    };

    return ModelDecoratorDiagramDesignerWidget;
});<|endoftext|>


<commit_before>//// [thisInClassBodyStaticESNext.ts]
// all are allowed with es-compliant class field emit
class Foo {
    x = this
    static t = this
    static at = () => this
    static ft = function () { return this }
    static mt() { return this }
}

//// [thisInClassBodyStaticESNext.js]
// all are allowed with es-compliant class field emit
class Foo {
    x = this;
    static t = this;
    static at = () => this;
    static ft = function () { return this; };
    static mt() { return this; }
}
<commit_msg>Update baseline (#37049)<commit_after>//// [thisInClassBodyStaticESNext.ts]
// all are allowed with es-compliant class field emit
class Foo {
    x = this
    static t = this
    static at = () => this
    static ft = function () { return this }
    static mt() { return this }
}

//// [thisInClassBodyStaticESNext.js]
// all are allowed with es-compliant class field emit
const Foo = /** @class */ (() => {
    class Foo {
        x = this;
        static t = this;
        static at = () => this;
        static ft = function () { return this; };
        static mt() { return this; }
    }
    return Foo;
})();
<|endoftext|>


<commit_before>import React from 'react'
import ReactGA from 'react-ga'
import getConfig from 'next/config'
// MOBILIZATION and external dependencies
import { Mobilization } from 'bonde-webpage'
import { PluggableWidget, FinishMessageCustom } from 'bonde-webpage/lib/ux'
// DRAFT PLUGIN and external dependencies
import { DraftPlugin } from 'bonde-webpage/lib/plugins/draft'
// FORM PLUGIN and external dependencies
import FormPlugin from './plugin-form.connected'
import { FormAnalytics, FormTellAFriend } from 'bonde-webpage/lib/plugins/form'
// CONTENT PLUGIN and external dependencies
import { ContentPlugin } from 'bonde-webpage/lib/plugins/content'
// PRESSURE PLUGIN and external dependencies
import PressurePlugin from './plugin-pressure.connected'
import { PressureAnalytics, PressureTellAFriend } from 'bonde-webpage/lib/plugins/pressure'
import graphqlClient from '../apolloClient'
// PRESSURE PLUGIN and external dependencies
import DonationPlugin from './plugin-donation.connected'
import { DonationAnalytics, DonationTellAFriend } from 'bonde-webpage/lib/plugins/donation'
// TODO: Icons should be inside plugin reference.
/*import { PressureEmailIcon, PressurePhoneIcon } from '@/pages/playground-mobs/icons'*/

import { connect } from 'react-redux'
import { selectors as MobilizationSelectors } from 'bonde-webpage/lib/redux'
import { FinishPostDonation } from 'bonde-webpage/lib/plugins/donation/components'

const { publicRuntimeConfig } = getConfig()

export const getSharedPath = (mobilization) => {
  const domain = publicRuntimeConfig.domainPublic

  if (domain && domain.indexOf('staging') !== -1) {
    return `http://${mobilization.slug}.${domain}`
  }

  return mobilization.custom_domain
    ? `http://${mobilization.custom_domain}`
    : `http://${mobilization.slug}.${domain}`
}

const mapStateToProps = (state, props) => {
  const query = MobilizationSelectors(state, props)
  return {
    mobilization: query.getMobilization() || query.getMobilizations()[0],
    blocks: query.getBlocks(),
    blocksIsLoaded: query.blocksIsLoaded(),
    widgets: query.getWidgets()
  }
}

const mobilizationConnect = connect(mapStateToProps)

const imageUrl = '/static/images/check-mark-image.png'

const MyCustomPressurePlugin = (props) => (
  <PressurePlugin
    {...props}
    analyticsEvents={PressureAnalytics}
    graphqlClient={graphqlClient}
    overrides={{
      FinishCustomMessage: { component: FinishMessageCustom },
      FinishDefaultMessage: {
        component: PressureTellAFriend,
        props: { imageUrl, href: getSharedPath(props.mobilization) }
      },
    }}
  />
)

const plugins = [
  {
    kind: 'draft',
    component: DraftPlugin,
    options: { noOverlay: true }
  },
  {
    kind: 'form',
    component: (props) => (
      <FormPlugin
        {...props}
        analyticsEvents={FormAnalytics}
        overrides={{
          FinishCustomMessage: { component: FinishMessageCustom },
          FinishDefaultMessage: {
            component: FormTellAFriend,
            props: { imageUrl, href: getSharedPath(props.mobilization) }
          },
          FinishDonationMessage: {
            component: FinishPostDonation
          }
        }}
      />
    )
  },
  {
    kind: 'donation',
    component: (props) => (
      <DonationPlugin
        {...props}
        pagarmeKey={publicRuntimeConfig.pagarmeKey}
        analyticsEvents={DonationAnalytics}
        overrides={{
          FinishCustomMessage: { component: FinishMessageCustom },
          FinishDefaultMessage: {
            component: DonationTellAFriend,
            props: { imageUrl, href: getSharedPath(props.mobilization) }
          },
        }}
      />
    )
  },
  {
    kind: 'pressure',
    component: MyCustomPressurePlugin
  },
  {
    kind: 'pressure-phone',
    component: MyCustomPressurePlugin
  },
  {
    kind: 'content',
    component: ContentPlugin
  }
]

class MobilizationPreview extends React.Component {

  componentDidMount () {
    const isTest = false
    if (!isTest && this.props.mobilization) {
      const { mobilization } = this.props

      ReactGA.initialize('UA-26278513-30')
      ReactGA.pageview('/' + mobilization.slug)

      if (mobilization.google_analytics_code) {
        ReactGA.initialize(
          mobilization.google_analytics_code,
          { gaOptions: { name: 'MobilizationTracker' } }
        )
        ReactGA.ga('MobilizationTracker.send', 'pageview', '/')
      }
    }
  }

  render () {
    // Properties received by HOC
    const { blocks, widgets } = this.props
    const {
      color_scheme: colorScheme,
      header_font: headerFont,
      body_font: bodyFont
    } = this.props.mobilization

    return (
      <Mobilization
        linkTo={b => `block-${b.id}`}
        blocks={blocks}
        widgets={widgets}
        widgetComponent={PluggableWidget}
        colorScheme={colorScheme}
        headerFont={headerFont}
        bodyFont={bodyFont}
        extraWidgetProps={{
          mobilization: this.props.mobilization,
          editable: this.props.editable,
          plugins
        }}
      />
    )
  }
}

export default mobilizationConnect(MobilizationPreview)<commit_msg>fix(public): resolve bug FinishDonationMessage<commit_after>import React from 'react'
import ReactGA from 'react-ga'
import getConfig from 'next/config'
// MOBILIZATION and external dependencies
import { Mobilization } from 'bonde-webpage'
import { PluggableWidget, FinishMessageCustom } from 'bonde-webpage/lib/ux'
// DRAFT PLUGIN and external dependencies
import { DraftPlugin } from 'bonde-webpage/lib/plugins/draft'
// FORM PLUGIN and external dependencies
import FormPlugin from './plugin-form.connected'
import { FormAnalytics, FormTellAFriend } from 'bonde-webpage/lib/plugins/form'
// CONTENT PLUGIN and external dependencies
import { ContentPlugin } from 'bonde-webpage/lib/plugins/content'
// PRESSURE PLUGIN and external dependencies
import PressurePlugin from './plugin-pressure.connected'
import { PressureAnalytics, PressureTellAFriend } from 'bonde-webpage/lib/plugins/pressure'
import graphqlClient from '../apolloClient'
// PRESSURE PLUGIN and external dependencies
import DonationPlugin from './plugin-donation.connected'
import { DonationAnalytics, DonationTellAFriend } from 'bonde-webpage/lib/plugins/donation'
// TODO: Icons should be inside plugin reference.
/*import { PressureEmailIcon, PressurePhoneIcon } from '@/pages/playground-mobs/icons'*/

import { connect } from 'react-redux'
import { selectors as MobilizationSelectors } from 'bonde-webpage/lib/redux'
import { FinishPostDonation } from 'bonde-webpage/lib/plugins/donation/components'

const { publicRuntimeConfig } = getConfig()

export const getSharedPath = (mobilization) => {
  const domain = publicRuntimeConfig.domainPublic

  if (domain && domain.indexOf('staging') !== -1) {
    return `http://${mobilization.slug}.${domain}`
  }

  return mobilization.custom_domain
    ? `http://${mobilization.custom_domain}`
    : `http://${mobilization.slug}.${domain}`
}

const mapStateToProps = (state, props) => {
  const query = MobilizationSelectors(state, props)
  return {
    mobilization: query.getMobilization() || query.getMobilizations()[0],
    blocks: query.getBlocks(),
    blocksIsLoaded: query.blocksIsLoaded(),
    widgets: query.getWidgets()
  }
}

const mobilizationConnect = connect(mapStateToProps)

const imageUrl = '/static/images/check-mark-image.png'

const MyCustomPressurePlugin = (props) => (
  <PressurePlugin
    {...props}
    analyticsEvents={PressureAnalytics}
    graphqlClient={graphqlClient}
    overrides={{
      FinishCustomMessage: { component: FinishMessageCustom },
      FinishDefaultMessage: {
        component: PressureTellAFriend,
        props: { imageUrl, href: getSharedPath(props.mobilization) }
      },
    }}
  />
)

const plugins = [
  {
    kind: 'draft',
    component: DraftPlugin,
    options: { noOverlay: true }
  },
  {
    kind: 'form',
    component: (props) => (
      <FormPlugin
        {...props}
        analyticsEvents={FormAnalytics}
        overrides={{
          FinishCustomMessage: { component: FinishMessageCustom },
          FinishDefaultMessage: {
            component: FormTellAFriend,
            props: { imageUrl, href: getSharedPath(props.mobilization) }
          }
        }}
      />
    )
  },
  {
    kind: 'donation',
    component: (props) => (
      <DonationPlugin
        {...props}
        pagarmeKey={publicRuntimeConfig.pagarmeKey}
        analyticsEvents={DonationAnalytics}
        overrides={{
          FinishCustomMessage: { component: FinishMessageCustom },
          FinishDefaultMessage: {
            component: DonationTellAFriend,
            props: { imageUrl, href: getSharedPath(props.mobilization) }
          },
          FinishDonationMessage: {
            component: FinishPostDonation
          }
        }}
      />
    )
  },
  {
    kind: 'pressure',
    component: MyCustomPressurePlugin
  },
  {
    kind: 'pressure-phone',
    component: MyCustomPressurePlugin
  },
  {
    kind: 'content',
    component: ContentPlugin
  }
]

class MobilizationPreview extends React.Component {

  componentDidMount () {
    const isTest = false
    if (!isTest && this.props.mobilization) {
      const { mobilization } = this.props

      ReactGA.initialize('UA-26278513-30')
      ReactGA.pageview('/' + mobilization.slug)

      if (mobilization.google_analytics_code) {
        ReactGA.initialize(
          mobilization.google_analytics_code,
          { gaOptions: { name: 'MobilizationTracker' } }
        )
        ReactGA.ga('MobilizationTracker.send', 'pageview', '/')
      }
    }
  }

  render () {
    // Properties received by HOC
    const { blocks, widgets } = this.props
    const {
      color_scheme: colorScheme,
      header_font: headerFont,
      body_font: bodyFont
    } = this.props.mobilization

    return (
      <Mobilization
        linkTo={b => `block-${b.id}`}
        blocks={blocks}
        widgets={widgets}
        widgetComponent={PluggableWidget}
        colorScheme={colorScheme}
        headerFont={headerFont}
        bodyFont={bodyFont}
        extraWidgetProps={{
          mobilization: this.props.mobilization,
          editable: this.props.editable,
          plugins
        }}
      />
    )
  }
}

export default mobilizationConnect(MobilizationPreview)<|endoftext|>


<commit_before>var boot = require('../');
var exportBrowserifyToFile = require('./helpers/browserify').exportToSandbox;
var fs = require('fs');
var path = require('path');
var expect = require('chai').expect;
var browserify = require('browserify');
var sandbox = require('./helpers/sandbox');
var vm = require('vm');
var createBrowserLikeContext = require('./helpers/browser').createContext;
var printContextLogs = require('./helpers/browser').printContextLogs;

describe('browser support for multiple apps', function() {
  this.timeout(60000); // 60s to give browserify enough time to finish

  beforeEach(sandbox.reset);

  it('has API for bundling and booting multiple apps', function(done) {
    var app1Dir = path.resolve(__dirname, './fixtures/browser-app');
    var app2Dir = path.resolve(__dirname, './fixtures/browser-app-2');

    var apps = [
      {
        appDir: app1Dir,
        appFile: './app.js',
        moduleName: 'browser-app'
      },
      {
        appDir: app2Dir,
        appFile: './app.js',
        moduleName: 'browser-app2',
        appId: 'browserApp2'
      }
    ];

    browserifyTestApps(apps, function(err, bundlePath) {
      if (err) return done(err);

      var bundledApps = executeBundledApps(bundlePath, apps);
      var app1 = bundledApps.defaultApp;
      var app2 = bundledApps.browserApp2;

      expect(app1.settings).to.have.property('custom-key', 'custom-value');
      expect(Object.keys(app1.models)).to.include('Customer');
      expect(Object.keys(app1.models)).to.not.include('Robot');
      expect(app1.models.Customer.settings).to.have.property('_customized',
        'Customer');

      expect(Object.keys(app2.models)).to.include('Robot');
      expect(Object.keys(app2.models)).to.not.include('Customer');

      done();
    });
  });
});

function browserifyTestApps(apps, next) {
  var b = browserify({
    basedir: appDir,
    debug: true
  });

  for (var i in apps) {
    var appDir = apps[i].appDir;
    var appFile = apps[i].appFile;
    var moduleName = apps[i].moduleName;
    var appId = apps[i].appId;

    appFile = path.join(appDir, appFile);
    b.require(appFile, {expose: moduleName});

    var opts = appDir;
    if (appId) {
      opts = {
        appId: appId,
        appRootDir: appDir
      };
    }
    boot.compileToBrowserify(opts, b);
  }

  exportBrowserifyToFile(b, 'browser-app-bundle.js', next);
}

function executeBundledApps(bundlePath, apps) {
  var code = fs.readFileSync(bundlePath);
  var context = createBrowserLikeContext();
  vm.runInContext(code, context, bundlePath);

  var script = 'var apps = {};\n';
  for (var i in apps) {
    var moduleName = apps[i].moduleName;
    var id = apps[i].appId || 'defaultApp';
    script += 'apps.' + id + ' = require("' + moduleName + '");\n';
  }
  script += 'apps;\n';

  var appsInContext = vm.runInContext(script, context);

  printContextLogs(context);

  return appsInContext;
}
<commit_msg>test: fix strict mode failure<commit_after>var boot = require('../');
var exportBrowserifyToFile = require('./helpers/browserify').exportToSandbox;
var fs = require('fs');
var path = require('path');
var expect = require('chai').expect;
var browserify = require('browserify');
var sandbox = require('./helpers/sandbox');
var vm = require('vm');
var createBrowserLikeContext = require('./helpers/browser').createContext;
var printContextLogs = require('./helpers/browser').printContextLogs;

describe('browser support for multiple apps', function() {
  this.timeout(60000); // 60s to give browserify enough time to finish

  beforeEach(sandbox.reset);

  it('has API for bundling and booting multiple apps', function(done) {
    var app1Dir = path.resolve(__dirname, './fixtures/browser-app');
    var app2Dir = path.resolve(__dirname, './fixtures/browser-app-2');

    var apps = [
      {
        appDir: app1Dir,
        appFile: './app.js',
        moduleName: 'browser-app'
      },
      {
        appDir: app2Dir,
        appFile: './app.js',
        moduleName: 'browser-app2',
        appId: 'browserApp2'
      }
    ];

    browserifyTestApps(apps, function(err, bundlePath) {
      if (err) return done(err);

      var bundledApps = executeBundledApps(bundlePath, apps);
      var app1 = bundledApps.defaultApp;
      var app2 = bundledApps.browserApp2;

      expect(app1.settings).to.have.property('custom-key', 'custom-value');
      expect(Object.keys(app1.models)).to.include('Customer');
      expect(Object.keys(app1.models)).to.not.include('Robot');
      expect(app1.models.Customer.settings).to.have.property('_customized',
        'Customer');

      expect(Object.keys(app2.models)).to.include('Robot');
      expect(Object.keys(app2.models)).to.not.include('Customer');

      done();
    });
  });
});

function browserifyTestApps(apps, next) {
  var b = browserify({
    debug: true
  });

  for (var i in apps) {
    var appDir = apps[i].appDir;
    var appFile = apps[i].appFile;
    var moduleName = apps[i].moduleName;
    var appId = apps[i].appId;

    appFile = path.join(appDir, appFile);
    b.require(appFile, {expose: moduleName});

    var opts = appDir;
    if (appId) {
      opts = {
        appId: appId,
        appRootDir: appDir
      };
    }
    boot.compileToBrowserify(opts, b);
  }

  exportBrowserifyToFile(b, 'browser-app-bundle.js', next);
}

function executeBundledApps(bundlePath, apps) {
  var code = fs.readFileSync(bundlePath);
  var context = createBrowserLikeContext();
  vm.runInContext(code, context, bundlePath);

  var script = 'var apps = {};\n';
  for (var i in apps) {
    var moduleName = apps[i].moduleName;
    var id = apps[i].appId || 'defaultApp';
    script += 'apps.' + id + ' = require("' + moduleName + '");\n';
  }
  script += 'apps;\n';

  var appsInContext = vm.runInContext(script, context);

  printContextLogs(context);

  return appsInContext;
}
<|endoftext|>


<commit_before>const webpack = require('webpack');
const { resolve } = require('path');
const { existsSync } = require('fs');
const merge = require('webpack-merge');
const { filter } = require('minimatch');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const CrittersPlugin = require('critters-webpack-plugin');
const RenderHTMLPlugin = require('./render-html-plugin');
const PushManifestPlugin = require('./push-manifest');
const baseConfig = require('./webpack-base-config');
const BabelEsmPlugin = require('babel-esm-plugin');
const { normalizePath } = require('../../util');

const cleanFilename = name =>
	name.replace(
		/(^\/(routes|components\/(routes|async))\/|(\/index)?\.js$)/g,
		''
	);

function clientConfig(env) {
	const { isProd, source, src /*, port? */ } = env;

	let entry = {
		bundle: resolve(__dirname, './../entry'),
		polyfills: resolve(__dirname, './polyfills'),
	};

	if (!isProd) {
		entry.bundle = [
			entry.bundle,
			'webpack-dev-server/client',
			'webpack/hot/dev-server',
		];
	}

	return {
		entry: entry,
		output: {
			path: env.dest,
			publicPath: '/',
			filename: isProd ? '[name].[chunkhash:5].js' : '[name].js',
			chunkFilename: '[name].chunk.[chunkhash:5].js',
		},

		resolveLoader: {
			alias: {
				async: require.resolve('@preact/async-loader'),
			},
		},

		// automatic async components :)
		module: {
			rules: [
				{
					test: /\.[jt]sx?$/,
					include: [
						filter(source('routes') + '/{*,*/index}.{js,jsx,ts,tsx}'),
						filter(
							source('components') +
								'/{routes,async}/{*,*/index}.{js,jsx,ts,tsx}'
						),
					],
					loader: require.resolve('@preact/async-loader'),
					options: {
						name(filename) {
							filename = normalizePath(filename);
							let relative = filename.replace(normalizePath(src), '');
							if (!relative.includes('/routes/')) return false;
							return 'route-' + cleanFilename(relative);
						},
						formatName(filename) {
							filename = normalizePath(filename);
							let relative = filename.replace(normalizePath(source('.')), '');
							return cleanFilename(relative);
						},
					},
				},
			],
		},

		plugins: [
			new PushManifestPlugin(env),
			...RenderHTMLPlugin(env),
			...getBabelEsmPlugin(env),
			new CopyWebpackPlugin(
				[
					...(existsSync(source('manifest.json'))
						? [{ from: 'manifest.json' }]
						: [
								{
									from: resolve(__dirname, '../../resources/manifest.json'),
									to: 'manifest.json',
								},
								{
									from: resolve(__dirname, '../../resources/icon.png'),
									to: 'assets/icon.png',
								},
						  ]),
					// copy any static files
					existsSync(source('assets')) && { from: 'assets', to: 'assets' },
					// copy sw-debug
					{
						from: resolve(__dirname, '../../resources/sw-debug.js'),
						to: 'sw-debug.js',
					},
				].filter(Boolean)
			),
		],
	};
}

function getBabelEsmPlugin(config) {
	const esmPlugins = [];
	if (config.esm) {
		esmPlugins.push(
			new BabelEsmPlugin({
				filename: config.isProd
					? '[name].[chunkhash:5].esm.js'
					: '[name].esm.js',
				chunkFilename: '[name].chunk.[chunkhash:5].esm.js',
				excludedPlugins: ['BabelEsmPlugin', 'SWBuilderPlugin'],
				beforeStartExecution: (plugins, newConfig) => {
					const babelPlugins = newConfig.plugins;
					newConfig.plugins = babelPlugins.filter(plugin => {
						if (
							Array.isArray(plugin) &&
							plugin[0].indexOf('fast-async') !== -1
						) {
							return false;
						}
						return true;
					});
					plugins.forEach(plugin => {
						if (
							plugin.constructor.name === 'DefinePlugin' &&
							plugin.definitions
						) {
							for (const definition in plugin.definitions) {
								if (definition === 'process.env.ES_BUILD') {
									plugin.definitions[definition] = true;
								}
							}
						} else if (
							plugin.constructor.name === 'DefinePlugin' &&
							!plugin.definitions
						) {
							throw new Error(
								'WebpackDefinePlugin found but not `process.env.ES_BUILD`.'
							);
						}
					});
				},
			})
		);
	}
	return esmPlugins;
}

function isProd(config) {
	let limit = 200 * 1000; // 200kb

	const prodConfig = {
		performance: Object.assign(
			{
				hints: 'warning',
				maxAssetSize: limit,
				maxEntrypointSize: limit,
			},
			config.pkg.performance
		),

		plugins: [
			new webpack.DefinePlugin({
				'process.env.ADD_SW': config.sw,
				'process.env.ES_BUILD': false,
				'process.env.ESM': config.esm,
			}),
		],

		optimization: {
			minimizer: [
				new TerserPlugin({
					cache: true,
					parallel: true,
					terserOptions: {
						output: { comments: false },
						mangle: true,
						compress: {
							keep_fargs: false,
							pure_getters: true,
							hoist_funs: true,
							pure_funcs: [
								'classCallCheck',
								'_classCallCheck',
								'_possibleConstructorReturn',
								'Object.freeze',
								'invariant',
								'warning',
							],
						},
					},
					sourceMap: true,
				}),
				new OptimizeCssAssetsPlugin({}),
			],
		},
	};

	if (config.sw) {
		prodConfig.plugins.push(
			new SWPrecacheWebpackPlugin({
				filename: 'sw.js',
				navigateFallback: 'index.html',
				navigateFallbackWhitelist: [/^(?!\/__).*/],
				minify: true,
				stripPrefix: config.cwd,
				staticFileGlobsIgnorePatterns: [
					/\.esm\.js$/,
					/polyfills(\..*)?\.js$/,
					/\.map$/,
					/push-manifest\.json$/,
					/.DS_Store/,
					/\.git/,
				],
			})
		);
	}

	if (config.esm && config.sw) {
		prodConfig.plugins.push(
			new SWPrecacheWebpackPlugin({
				filename: 'sw-esm.js',
				navigateFallback: 'index.html',
				navigateFallbackWhitelist: [/^(?!\/__).*/],
				minify: true,
				stripPrefix: config.cwd,
				staticFileGlobsIgnorePatterns: [
					/(\.[\w]{5}\.js)/,
					/polyfills(\..*)?\.js$/,
					/\.map$/,
					/push-manifest\.json$/,
					/.DS_Store/,
					/\.git/,
				],
			})
		);
	}

	if (config['inline-css']) {
		prodConfig.plugins.push(new CrittersPlugin());
	}

	if (config.analyze) {
		prodConfig.plugins.push(new BundleAnalyzerPlugin());
	}

	return prodConfig;
}

function isDev(config) {
	const { cwd, src } = config;

	return {
		plugins: [
			new webpack.NamedModulesPlugin(),
			new webpack.HotModuleReplacementPlugin(),
			new webpack.DefinePlugin({
				'process.env.ADD_SW': config.sw,
				'process.env.RHL': config.rhl,
			}),
		],

		devServer: {
			inline: true,
			hot: true,
			compress: true,
			publicPath: '/',
			contentBase: src,
			https: config.https,
			port: process.env.PORT || config.port || 8080,
			host: process.env.HOST || config.host || '0.0.0.0',
			// setup(app) {
			// 	app.use(middleware);
			// },
			disableHostCheck: true,
			historyApiFallback: true,
			quiet: true,
			clientLogLevel: 'none',
			overlay: false,
			stats: 'minimal',
			watchOptions: {
				ignored: [resolve(cwd, 'build'), resolve(cwd, 'node_modules')],
			},
		},
	};
}

module.exports = function(env) {
	return merge(
		baseConfig(env),
		clientConfig(env),
		(env.isProd ? isProd : isDev)(env)
	);
};
<commit_msg>[next] fix keyframe name collisisions (#744)<commit_after>const webpack = require('webpack');
const { resolve } = require('path');
const { existsSync } = require('fs');
const merge = require('webpack-merge');
const { filter } = require('minimatch');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const CrittersPlugin = require('critters-webpack-plugin');
const RenderHTMLPlugin = require('./render-html-plugin');
const PushManifestPlugin = require('./push-manifest');
const baseConfig = require('./webpack-base-config');
const BabelEsmPlugin = require('babel-esm-plugin');
const { normalizePath } = require('../../util');

const cleanFilename = name =>
	name.replace(
		/(^\/(routes|components\/(routes|async))\/|(\/index)?\.js$)/g,
		''
	);

function clientConfig(env) {
	const { isProd, source, src /*, port? */ } = env;

	let entry = {
		bundle: resolve(__dirname, './../entry'),
		polyfills: resolve(__dirname, './polyfills'),
	};

	if (!isProd) {
		entry.bundle = [
			entry.bundle,
			'webpack-dev-server/client',
			'webpack/hot/dev-server',
		];
	}

	return {
		entry: entry,
		output: {
			path: env.dest,
			publicPath: '/',
			filename: isProd ? '[name].[chunkhash:5].js' : '[name].js',
			chunkFilename: '[name].chunk.[chunkhash:5].js',
		},

		resolveLoader: {
			alias: {
				async: require.resolve('@preact/async-loader'),
			},
		},

		// automatic async components :)
		module: {
			rules: [
				{
					test: /\.[jt]sx?$/,
					include: [
						filter(source('routes') + '/{*,*/index}.{js,jsx,ts,tsx}'),
						filter(
							source('components') +
								'/{routes,async}/{*,*/index}.{js,jsx,ts,tsx}'
						),
					],
					loader: require.resolve('@preact/async-loader'),
					options: {
						name(filename) {
							filename = normalizePath(filename);
							let relative = filename.replace(normalizePath(src), '');
							if (!relative.includes('/routes/')) return false;
							return 'route-' + cleanFilename(relative);
						},
						formatName(filename) {
							filename = normalizePath(filename);
							let relative = filename.replace(normalizePath(source('.')), '');
							return cleanFilename(relative);
						},
					},
				},
			],
		},

		plugins: [
			new PushManifestPlugin(env),
			...RenderHTMLPlugin(env),
			...getBabelEsmPlugin(env),
			new CopyWebpackPlugin(
				[
					...(existsSync(source('manifest.json'))
						? [{ from: 'manifest.json' }]
						: [
								{
									from: resolve(__dirname, '../../resources/manifest.json'),
									to: 'manifest.json',
								},
								{
									from: resolve(__dirname, '../../resources/icon.png'),
									to: 'assets/icon.png',
								},
						  ]),
					// copy any static files
					existsSync(source('assets')) && { from: 'assets', to: 'assets' },
					// copy sw-debug
					{
						from: resolve(__dirname, '../../resources/sw-debug.js'),
						to: 'sw-debug.js',
					},
				].filter(Boolean)
			),
		],
	};
}

function getBabelEsmPlugin(config) {
	const esmPlugins = [];
	if (config.esm) {
		esmPlugins.push(
			new BabelEsmPlugin({
				filename: config.isProd
					? '[name].[chunkhash:5].esm.js'
					: '[name].esm.js',
				chunkFilename: '[name].chunk.[chunkhash:5].esm.js',
				excludedPlugins: ['BabelEsmPlugin', 'SWBuilderPlugin'],
				beforeStartExecution: (plugins, newConfig) => {
					const babelPlugins = newConfig.plugins;
					newConfig.plugins = babelPlugins.filter(plugin => {
						if (
							Array.isArray(plugin) &&
							plugin[0].indexOf('fast-async') !== -1
						) {
							return false;
						}
						return true;
					});
					plugins.forEach(plugin => {
						if (
							plugin.constructor.name === 'DefinePlugin' &&
							plugin.definitions
						) {
							for (const definition in plugin.definitions) {
								if (definition === 'process.env.ES_BUILD') {
									plugin.definitions[definition] = true;
								}
							}
						} else if (
							plugin.constructor.name === 'DefinePlugin' &&
							!plugin.definitions
						) {
							throw new Error(
								'WebpackDefinePlugin found but not `process.env.ES_BUILD`.'
							);
						}
					});
				},
			})
		);
	}
	return esmPlugins;
}

function isProd(config) {
	let limit = 200 * 1000; // 200kb

	const prodConfig = {
		performance: Object.assign(
			{
				hints: 'warning',
				maxAssetSize: limit,
				maxEntrypointSize: limit,
			},
			config.pkg.performance
		),

		plugins: [
			new webpack.DefinePlugin({
				'process.env.ADD_SW': config.sw,
				'process.env.ES_BUILD': false,
				'process.env.ESM': config.esm,
			}),
		],

		optimization: {
			minimizer: [
				new TerserPlugin({
					cache: true,
					parallel: true,
					terserOptions: {
						output: { comments: false },
						mangle: true,
						compress: {
							keep_fargs: false,
							pure_getters: true,
							hoist_funs: true,
							pure_funcs: [
								'classCallCheck',
								'_classCallCheck',
								'_possibleConstructorReturn',
								'Object.freeze',
								'invariant',
								'warning',
							],
						},
					},
					sourceMap: true,
				}),
				new OptimizeCssAssetsPlugin({
					cssProcessorOptions: {
						// Fix keyframes in different CSS chunks minifying to colliding names:
						reduceIdents: false
					}
				}),
			],
		},
	};

	if (config.sw) {
		prodConfig.plugins.push(
			new SWPrecacheWebpackPlugin({
				filename: 'sw.js',
				navigateFallback: 'index.html',
				navigateFallbackWhitelist: [/^(?!\/__).*/],
				minify: true,
				stripPrefix: config.cwd,
				staticFileGlobsIgnorePatterns: [
					/\.esm\.js$/,
					/polyfills(\..*)?\.js$/,
					/\.map$/,
					/push-manifest\.json$/,
					/.DS_Store/,
					/\.git/,
				],
			})
		);
	}

	if (config.esm && config.sw) {
		prodConfig.plugins.push(
			new SWPrecacheWebpackPlugin({
				filename: 'sw-esm.js',
				navigateFallback: 'index.html',
				navigateFallbackWhitelist: [/^(?!\/__).*/],
				minify: true,
				stripPrefix: config.cwd,
				staticFileGlobsIgnorePatterns: [
					/(\.[\w]{5}\.js)/,
					/polyfills(\..*)?\.js$/,
					/\.map$/,
					/push-manifest\.json$/,
					/.DS_Store/,
					/\.git/,
				],
			})
		);
	}

	if (config['inline-css']) {
		prodConfig.plugins.push(new CrittersPlugin());
	}

	if (config.analyze) {
		prodConfig.plugins.push(new BundleAnalyzerPlugin());
	}

	return prodConfig;
}

function isDev(config) {
	const { cwd, src } = config;

	return {
		plugins: [
			new webpack.NamedModulesPlugin(),
			new webpack.HotModuleReplacementPlugin(),
			new webpack.DefinePlugin({
				'process.env.ADD_SW': config.sw,
				'process.env.RHL': config.rhl,
			}),
		],

		devServer: {
			inline: true,
			hot: true,
			compress: true,
			publicPath: '/',
			contentBase: src,
			https: config.https,
			port: process.env.PORT || config.port || 8080,
			host: process.env.HOST || config.host || '0.0.0.0',
			// setup(app) {
			// 	app.use(middleware);
			// },
			disableHostCheck: true,
			historyApiFallback: true,
			quiet: true,
			clientLogLevel: 'none',
			overlay: false,
			stats: 'minimal',
			watchOptions: {
				ignored: [resolve(cwd, 'build'), resolve(cwd, 'node_modules')],
			},
		},
	};
}

module.exports = function(env) {
	return merge(
		baseConfig(env),
		clientConfig(env),
		(env.isProd ? isProd : isDev)(env)
	);
};
<|endoftext|>