<commit_before>/*
 *     Copyright 2012-2015 (c) CoNWeT Lab., Universidad Politécnica de Madrid
 *
 *     This file is part of Wirecloud Platform.
 *
 *     Wirecloud Platform is free software: you can redistribute it and/or
 *     modify it under the terms of the GNU Affero General Public License as
 *     published by the Free Software Foundation, either version 3 of the
 *     License, or (at your option) any later version.
 *
 *     Wirecloud is distributed in the hope that it will be useful, but WITHOUT
 *     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
 *     License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with Wirecloud Platform.  If not, see
 *     <http://www.gnu.org/licenses/>.
 *
 */

/*global gettext, LayoutManagerFactory, StyledElements, Wirecloud*/

(function () {

    "use strict";

    var UploadWindowMenu, upload_wgt_files, acceptListener, updateEmptyStatus, onUploadSuccess;

    /*************************************************************************
     *                            Private methods                            *
     *************************************************************************/

    onUploadSuccess = function onUploadSuccess() {
        this.mainview.viewsByName.search.mark_outdated();
    };

    upload_wgt_files = function upload_wgt_files() {
        var monitor, entries, count, failures, onComplete, onUploadFailure;

        monitor = LayoutManagerFactory.getInstance()._startComplexTask(gettext("Uploading packaged components"), 1);
        entries = this.fileTable.source.elements;
        count = entries.length;
        failures = [];

        onComplete = function () {
            if (--count === 0) {
                var layoutManager = LayoutManagerFactory.getInstance();
                layoutManager._notifyPlatformReady();
                if (failures.length > 0) {
                    var msg = document.createElement('p');
                    msg.textContent = gettext('Error uploading the following components:');
                    var details = document.createElement('ul');
                    for (var i = 0; i < failures.length; i++) {
                        var item = document.createElement('li');
                        var file_name = document.createElement('b');
                        file_name.textContent = failures[i].file;
                        item.appendChild(file_name);

                        var error_description = document.createTextNode(": " + failures[i].msg);
                        item.appendChild(error_description);

                        details.appendChild(item);
                    }
                    msg = new StyledElements.Fragment([msg, details]);
                    (new Wirecloud.ui.MessageWindowMenu(msg, Wirecloud.constants.LOGGING.ERROR_MSG)).show();
                }
            }
        };

        onUploadFailure = function onUploadFailure(file_entry, msg) {
            failures.push({'file': file_entry.name, 'msg': msg});
        };

        for (var i = 0; i < entries.length; i++) {
            this.catalogue.addPackagedResource(entries[i].file, {
                force_create: true,
                monitor: monitor,
                onSuccess: onUploadSuccess.bind(this),
                onFailure: onUploadFailure.bind(this, entries[i]),
                onComplete: onComplete
            });
        }
        this.fileTable.source.changeElements([]);
        updateEmptyStatus.call(this);
    };

    acceptListener = function acceptListener() {
        upload_wgt_files.call(this);
        this.hide();
    };

    updateEmptyStatus = function updateEmptyStatus() {
        var empty = this.fileTable.source.elements.length === 0;
        this.acceptButton.setDisabled(empty);
        if (empty) {
            this.htmlElement.classList.add('wc-upload-mac-dialog-empty');
        } else {
            this.htmlElement.classList.remove('wc-upload-mac-dialog-empty');
        }
    };

    /*************************************************************************
     *                           UploadWindowMenu                            *
     *************************************************************************/

    UploadWindowMenu = function UploadWindowMenu(options) {
        this.catalogue = options.catalogue;
        this.mainview = options.mainview;
        Wirecloud.ui.WindowMenu.call(this, gettext("Upload mashable application components"), 'wc-upload-mac-dialog');

        var builder = new StyledElements.GUIBuilder();
        var contents = builder.parse(Wirecloud.currentTheme.templates.wirecloud_catalogue_publish_interface, {
            'upload_wgt_button': function () {
                var button = new StyledElements.FileButton({text: gettext('Select files from your computer')});
                button.addEventListener('fileselect', function (button, files) {
                    for (var i = 0; i < files.length; i++) {
                        this.addFile(files[i]);
                    }
                }.bind(this));
                this.fileButton = button;
                return button;
            }.bind(this)
        });
        contents.insertInto(this.windowContent);

        this.fileTable = new StyledElements.ModelTable([
            {
                "field": "name",
                "label": "Name"
            },
            {
                "field": "size",
                "type": "number",
                "label": "Size",
                "width": "css",
                "class": "wc-upload-mac-size-column",
                "contentBuilder": function (file) {return Wirecloud.Utils.formatSize(file.size);}
            },
            {
                "label": "",
                "width": "css",
                "class": "wc-upload-mac-button-column",
                "sortable": false,
                "contentBuilder": function (entry) {
                    var button = new StyledElements.StyledButton({"iconClass": "icon-remove", plain: true});
                    button.addEventListener("click", this.removeFile.bind(this, entry.file));
                    return button;
                }.bind(this)
            }
        ], {
            pageSize: 0
        });
        var addMoreButton = new StyledElements.FileButton({text: gettext('Add more files')});
        addMoreButton.addEventListener('fileselect', function (button, files) {
            for (var i = 0; i < files.length; i++) {
                this.addFile(files[i]);
            }
        }.bind(this));
        this.fileTable.statusBar.appendChild(addMoreButton);
        this.fileTable.insertInto(this.windowContent);

        this.acceptButton = new StyledElements.StyledButton({
            text: gettext("Upload"),
            'class': 'btn-primary'
        });
        this.acceptButton.addEventListener("click", acceptListener.bind(this));
        this.acceptButton.insertInto(this.windowBottom);
        this.acceptButton.disable();

        // File Drag & drop borders
        var border = document.createElement("div");
        border.className = "wc-upload-mac-border";
        this.windowContent.appendChild(border);

        // Cancel button
        this.cancelButton = new StyledElements.StyledButton({
            text: gettext("Cancel"),
            'class': 'btn-default'
        });
        this.cancelButton.addEventListener("click", this._closeListener);
        this.cancelButton.insertInto(this.windowBottom);

        // Drag & drop support
        var drop_listener = function drop_listener(e) {
            e.preventDefault();
            deactivate();
        };
        var dragleave_listener = function dragleave_listener(e) {
            e.stopPropagation();
            deactivate();
        };
        var deactivate = function deactivate(e) {
            this.htmlElement.classList.remove('drag-hover');
            document.removeEventListener('drop', drop_listener, true);
            document.removeEventListener('dragleave', dragleave_listener, false);
            document.removeEventListener('dragover', Wirecloud.Utils.preventDefaultListener, true);
            this.htmlElement.addEventListener('dragover', activate_listener, true);
        }.bind(this);

        var activate_listener = function activate_listener(e) {
            var has_files;

            e.preventDefault();

            if (e.dataTransfer.types.contains) {
                has_files = e.dataTransfer.types.contains('Files');
            } else {
                has_files = e.dataTransfer.types.indexOf('Files') != -1;
            }
            if (has_files) {
                this.htmlElement.classList.add('drag-hover');
                this.htmlElement.removeEventListener('dragover', activate_listener, true);
                document.addEventListener('dragover', Wirecloud.Utils.preventDefaultListener, true);
                document.addEventListener('dragleave', dragleave_listener, false);
                document.addEventListener('drop', drop_listener, true);
            }
        }.bind(this);
        this.htmlElement.addEventListener('dragover', activate_listener, true);

        this.windowContent.addEventListener('drop', function (e) {
            var i;

            e.stopPropagation();
            e.preventDefault();
            this.windowContent.classList.remove('on');

            for (i = 0; i < e.dataTransfer.files.length; i++) {
                this.addFile(e.dataTransfer.files[i]);
            }
        }.bind(this), true);
    };
    UploadWindowMenu.prototype = new Wirecloud.ui.WindowMenu();

    UploadWindowMenu.prototype.addFile = function addFile(file) {
        var entry = {
            name: file.name,
            size: file.size,
            file: file
        };
        this.fileTable.source.addElement(entry);
        this.htmlElement.classList.remove('wc-upload-mac-dialog-empty');
        this.acceptButton.enable();
    };

    UploadWindowMenu.prototype.removeFile = function removeFile(file) {
        for (var i = 0; i < this.fileTable.source.elements.length; i++) {
            var entry = this.fileTable.source.elements[i];
            if (entry.file === file) {
                this.fileTable.source.elements.splice(i, 1);
                updateEmptyStatus.call(this);
                this.fileTable.source.refresh();
                break;
            }
        }
    };

    UploadWindowMenu.prototype.setFocus = function setFocus() {
        this.fileButton.focus();
    };

    UploadWindowMenu.prototype.show = function show() {
        Wirecloud.ui.WindowMenu.prototype.show.apply(this, arguments);
        this.fileButton.clear();
        this.fileTable.repaint();
        updateEmptyStatus.call(this);
    };

    UploadWindowMenu.prototype._closeListener = function _closeListener() {
        this.fileTable.source.changeElements([]);
        updateEmptyStatus.call(this);

        Wirecloud.ui.WindowMenu.prototype._closeListener.call(this);
    };

    Wirecloud.ui.WirecloudCatalogue = {};
    Wirecloud.ui.WirecloudCatalogue.UploadWindowMenu = UploadWindowMenu;
})();
<commit_msg>Refresh local catalogue view after uploading resources<commit_after>/*
 *     Copyright 2012-2015 (c) CoNWeT Lab., Universidad Politécnica de Madrid
 *
 *     This file is part of Wirecloud Platform.
 *
 *     Wirecloud Platform is free software: you can redistribute it and/or
 *     modify it under the terms of the GNU Affero General Public License as
 *     published by the Free Software Foundation, either version 3 of the
 *     License, or (at your option) any later version.
 *
 *     Wirecloud is distributed in the hope that it will be useful, but WITHOUT
 *     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
 *     License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with Wirecloud Platform.  If not, see
 *     <http://www.gnu.org/licenses/>.
 *
 */

/*global gettext, LayoutManagerFactory, StyledElements, Wirecloud*/

(function () {

    "use strict";

    var UploadWindowMenu, upload_wgt_files, acceptListener, updateEmptyStatus, onUploadSuccess;

    /*************************************************************************
     *                            Private methods                            *
     *************************************************************************/

    onUploadSuccess = function onUploadSuccess() {
        this.mainview.viewsByName.search.mark_outdated();
    };

    upload_wgt_files = function upload_wgt_files() {
        var monitor, entries, count, failures, onComplete, onUploadFailure;

        monitor = LayoutManagerFactory.getInstance()._startComplexTask(gettext("Uploading packaged components"), 1);
        entries = this.fileTable.source.elements;
        count = entries.length;
        failures = [];

        onComplete = function () {
            if (--count === 0) {
                var layoutManager = LayoutManagerFactory.getInstance();
                layoutManager._notifyPlatformReady();
                if (failures.length > 0) {
                    var msg = document.createElement('p');
                    msg.textContent = gettext('Error uploading the following components:');
                    var details = document.createElement('ul');
                    for (var i = 0; i < failures.length; i++) {
                        var item = document.createElement('li');
                        var file_name = document.createElement('b');
                        file_name.textContent = failures[i].file;
                        item.appendChild(file_name);

                        var error_description = document.createTextNode(": " + failures[i].msg);
                        item.appendChild(error_description);

                        details.appendChild(item);
                    }
                    msg = new StyledElements.Fragment([msg, details]);
                    (new Wirecloud.ui.MessageWindowMenu(msg, Wirecloud.constants.LOGGING.ERROR_MSG)).show();
                }
                this.mainview.viewsByName.search.refresh_if_needed();
            }
        };

        onUploadFailure = function onUploadFailure(file_entry, msg) {
            failures.push({'file': file_entry.name, 'msg': msg});
        };

        for (var i = 0; i < entries.length; i++) {
            this.catalogue.addPackagedResource(entries[i].file, {
                force_create: true,
                monitor: monitor,
                onSuccess: onUploadSuccess.bind(this),
                onFailure: onUploadFailure.bind(this, entries[i]),
                onComplete: onComplete.bind(this)
            });
        }
        this.fileTable.source.changeElements([]);
        updateEmptyStatus.call(this);
    };

    acceptListener = function acceptListener() {
        upload_wgt_files.call(this);
        this.hide();
    };

    updateEmptyStatus = function updateEmptyStatus() {
        var empty = this.fileTable.source.elements.length === 0;
        this.acceptButton.setDisabled(empty);
        if (empty) {
            this.htmlElement.classList.add('wc-upload-mac-dialog-empty');
        } else {
            this.htmlElement.classList.remove('wc-upload-mac-dialog-empty');
        }
    };

    /*************************************************************************
     *                           UploadWindowMenu                            *
     *************************************************************************/

    UploadWindowMenu = function UploadWindowMenu(options) {
        this.catalogue = options.catalogue;
        this.mainview = options.mainview;
        Wirecloud.ui.WindowMenu.call(this, gettext("Upload mashable application components"), 'wc-upload-mac-dialog');

        var builder = new StyledElements.GUIBuilder();
        var contents = builder.parse(Wirecloud.currentTheme.templates.wirecloud_catalogue_publish_interface, {
            'upload_wgt_button': function () {
                var button = new StyledElements.FileButton({text: gettext('Select files from your computer')});
                button.addEventListener('fileselect', function (button, files) {
                    for (var i = 0; i < files.length; i++) {
                        this.addFile(files[i]);
                    }
                }.bind(this));
                this.fileButton = button;
                return button;
            }.bind(this)
        });
        contents.insertInto(this.windowContent);

        this.fileTable = new StyledElements.ModelTable([
            {
                "field": "name",
                "label": "Name"
            },
            {
                "field": "size",
                "type": "number",
                "label": "Size",
                "width": "css",
                "class": "wc-upload-mac-size-column",
                "contentBuilder": function (file) {return Wirecloud.Utils.formatSize(file.size);}
            },
            {
                "label": "",
                "width": "css",
                "class": "wc-upload-mac-button-column",
                "sortable": false,
                "contentBuilder": function (entry) {
                    var button = new StyledElements.StyledButton({"iconClass": "icon-remove", plain: true});
                    button.addEventListener("click", this.removeFile.bind(this, entry.file));
                    return button;
                }.bind(this)
            }
        ], {
            pageSize: 0
        });
        var addMoreButton = new StyledElements.FileButton({text: gettext('Add more files')});
        addMoreButton.addEventListener('fileselect', function (button, files) {
            for (var i = 0; i < files.length; i++) {
                this.addFile(files[i]);
            }
        }.bind(this));
        this.fileTable.statusBar.appendChild(addMoreButton);
        this.fileTable.insertInto(this.windowContent);

        this.acceptButton = new StyledElements.StyledButton({
            text: gettext("Upload"),
            'class': 'btn-primary'
        });
        this.acceptButton.addEventListener("click", acceptListener.bind(this));
        this.acceptButton.insertInto(this.windowBottom);
        this.acceptButton.disable();

        // File Drag & drop borders
        var border = document.createElement("div");
        border.className = "wc-upload-mac-border";
        this.windowContent.appendChild(border);

        // Cancel button
        this.cancelButton = new StyledElements.StyledButton({
            text: gettext("Cancel"),
            'class': 'btn-default'
        });
        this.cancelButton.addEventListener("click", this._closeListener);
        this.cancelButton.insertInto(this.windowBottom);

        // Drag & drop support
        var drop_listener = function drop_listener(e) {
            e.preventDefault();
            deactivate();
        };
        var dragleave_listener = function dragleave_listener(e) {
            e.stopPropagation();
            deactivate();
        };
        var deactivate = function deactivate(e) {
            this.htmlElement.classList.remove('drag-hover');
            document.removeEventListener('drop', drop_listener, true);
            document.removeEventListener('dragleave', dragleave_listener, false);
            document.removeEventListener('dragover', Wirecloud.Utils.preventDefaultListener, true);
            this.htmlElement.addEventListener('dragover', activate_listener, true);
        }.bind(this);

        var activate_listener = function activate_listener(e) {
            var has_files;

            e.preventDefault();

            if (e.dataTransfer.types.contains) {
                has_files = e.dataTransfer.types.contains('Files');
            } else {
                has_files = e.dataTransfer.types.indexOf('Files') != -1;
            }
            if (has_files) {
                this.htmlElement.classList.add('drag-hover');
                this.htmlElement.removeEventListener('dragover', activate_listener, true);
                document.addEventListener('dragover', Wirecloud.Utils.preventDefaultListener, true);
                document.addEventListener('dragleave', dragleave_listener, false);
                document.addEventListener('drop', drop_listener, true);
            }
        }.bind(this);
        this.htmlElement.addEventListener('dragover', activate_listener, true);

        this.windowContent.addEventListener('drop', function (e) {
            var i;

            e.stopPropagation();
            e.preventDefault();
            this.windowContent.classList.remove('on');

            for (i = 0; i < e.dataTransfer.files.length; i++) {
                this.addFile(e.dataTransfer.files[i]);
            }
        }.bind(this), true);
    };
    UploadWindowMenu.prototype = new Wirecloud.ui.WindowMenu();

    UploadWindowMenu.prototype.addFile = function addFile(file) {
        var entry = {
            name: file.name,
            size: file.size,
            file: file
        };
        this.fileTable.source.addElement(entry);
        this.htmlElement.classList.remove('wc-upload-mac-dialog-empty');
        this.acceptButton.enable();
    };

    UploadWindowMenu.prototype.removeFile = function removeFile(file) {
        for (var i = 0; i < this.fileTable.source.elements.length; i++) {
            var entry = this.fileTable.source.elements[i];
            if (entry.file === file) {
                this.fileTable.source.elements.splice(i, 1);
                updateEmptyStatus.call(this);
                this.fileTable.source.refresh();
                break;
            }
        }
    };

    UploadWindowMenu.prototype.setFocus = function setFocus() {
        this.fileButton.focus();
    };

    UploadWindowMenu.prototype.show = function show() {
        Wirecloud.ui.WindowMenu.prototype.show.apply(this, arguments);
        this.fileButton.clear();
        this.fileTable.repaint();
        updateEmptyStatus.call(this);
    };

    UploadWindowMenu.prototype._closeListener = function _closeListener() {
        this.fileTable.source.changeElements([]);
        updateEmptyStatus.call(this);

        Wirecloud.ui.WindowMenu.prototype._closeListener.call(this);
    };

    Wirecloud.ui.WirecloudCatalogue = {};
    Wirecloud.ui.WirecloudCatalogue.UploadWindowMenu = UploadWindowMenu;
})();
<|endoftext|>


<commit_before><commit_msg>fixing things<commit_after><|endoftext|>


<commit_before>(function(Gear, Global, Constants, Util) {

	/**
	 * Shapes are primitive form, such as: rectangles, circles, lines, etc...
	 * @param {Object} config
	 */
	var Shape = function(config) {
		Gear.Node.call(this, config);

		this.nodeType = Constants.NODE_TYPE.SHAPE;
		this._colorKey = Gear.Color.getUnique();
		Global.shapes[this._colorKey] = this;
	};

	Shape.extend = Util.extend;

	Util.construct(Shape.prototype, Gear.Node.prototype, {

		/**
		 * Get the unique color id for this shape
		 * @return {String} color
		 */
		getColorId: function() {
			return this._colorKey;
		},

		drawScene: function(canvas) {
			// Get the draw. Use getDraw to allow an attr
			// to take precedence, otherwise, use the draw
			// as defined by this
			var draw = this.getDraw() || this.draw;
			if (!draw || !this.isVisible()) { return this; }

			canvas = canvas || this.getLayer().getCanvas();

			var context = canvas.getContext();

			canvas.save();
			canvas.applyOpacity(this);
			canvas.applyLineJoin(this);
			canvas.applyAncestorTransforms(this);
			canvas.applyRotation(this);

			if (this._cache) {
				canvas.getContext().drawImage(this._cache.getCanvas(), 0, 0);
			} else {
				draw.call(this, canvas);
			}

			canvas.restore();

			return this;
		},

		drawHit: function() {
			var draw = this.getHit() || this.hit || this.getDraw() || this.draw;
			if (!draw || !this.shouldDrawHit()) { return this; }

			var canvas = this.getLayer().getHitCanvas(),
				context = canvas.getContext();

			canvas.save();
			canvas.applyLineJoin(this);
			canvas.applyAncestorTransforms(this);
			canvas.applyRotation(this);
			draw.call(this, canvas);
			canvas.restore();

			return this;
		},

		getLineJoin: function() {
			return this.attr.lineJoin;
		},
		setLineJoin: function(joint) {
			this.attr.lineJoin = joint;
			return this;
		},

		/**
		 * Whether a stroke is set
		 * @return {Boolean}
		 */
		hasStroke: function() {
			var stroke = this.getStroke();
			return (stroke && stroke.isEnabled() && stroke.getWidth() > 0);
		},
		getStroke: function() {
			return this.attr.stroke;
		},
		setStroke: function(config) {
			if (config instanceof Gear.Stroke) {
				this.attr.stroke = config;
				return this;
			}

			this.attr.stroke = new Gear.Stroke(config);
			return this;
		},

		/**
		 * Whether a fill is set
		 * @return {Boolean}
		 */
		hasFill: function() {
			var fill = this.getFill();
			return (fill && fill.isEnabled());
		},
		getFill: function() {
			return this.attr.fill;
		},
		setFill: function(fill) {
			if (Gear.Fill.isFill(fill)) {
				this.att.fill = fill;
			}

			this.attr.fill = Gear.Fill.parse(fill);
			return this;
		},

		/**
		 * Whether a shadow is set
		 * @return {Boolean}
		 */
		hasShadow: function() {
			var shadow = this.getShadow();
			return (shadow && shadow.isEnabled() && shadow.getOpacity() !== 0);
		},
		getShadow: function() {
			return this.attr.shadow;
		},
		setShadow: function(config) {
			if (config instanceof Gear.Shadow) {
				this.attr.shadow = config;
				return this;
			}

			this.attr.shadow = new Gear.Shadow(config);
			return this;
		},

		/**
		 * Cache | Uncahe
		 */
		_getCacheScene: function() {
			return this._cacheScene || (this._cacheScene = new Gear.SceneCanvas());
		},
		cache: function() {
			var scene = this._getCacheScene(),
				draw = this.getDraw() || this.draw;
			scene.setSize(this.getSize());
			draw.call(this, scene);
			this._cache = scene;
		},
		uncache: function() {
			this._cache = null;
		},

		/**
		 * Destroy
		 * @return {[type]} [description]
		 */
		destroy: function() {
			Gear.Node.prototype.destroy.call(this);
			delete Global.shapes[this.getColorId()];
			return this;
		},

		toString: function() {
			return '[Shape]';
		}
	});

	Gear.Shape = Shape;

}(Gear, Gear.Global, Gear.Const, Gear.Util));<commit_msg>Make Shape easier to chain<commit_after>(function(Gear, Global, Constants, Util) {

	/**
	 * Shapes are primitive form, such as: rectangles, circles, lines, etc...
	 * @param {Object} config
	 */
	var Shape = function(config) {
		Gear.Node.call(this, config);

		this.nodeType = Constants.NODE_TYPE.SHAPE;
		this._colorKey = Gear.Color.getUnique();
		Global.shapes[this._colorKey] = this;
	};

	Shape.extend = Util.extend;

	Util.construct(Shape.prototype, Gear.Node.prototype, {

		/**
		 * Get the unique color id for this shape
		 * @return {String} color
		 */
		getColorId: function() {
			return this._colorKey;
		},

		drawScene: function(canvas) {
			// Get the draw. Use getDraw to allow an attr
			// to take precedence, otherwise, use the draw
			// as defined by this
			var draw = this.getDraw() || this.draw;
			if (!draw || !this.isVisible()) { return this; }

			canvas = canvas || this.getLayer().getCanvas();

			var context = canvas.getContext();

			canvas.save();
			canvas.applyOpacity(this);
			canvas.applyLineJoin(this);
			canvas.applyAncestorTransforms(this);
			canvas.applyRotation(this);

			if (this._cache) {
				canvas.getContext().drawImage(this._cache.getCanvas(), 0, 0);
			} else {
				draw.call(this, canvas);
			}

			canvas.restore();

			return this;
		},

		drawHit: function() {
			var draw = this.getHit() || this.hit || this.getDraw() || this.draw;
			if (!draw || !this.shouldDrawHit()) { return this; }

			var canvas = this.getLayer().getHitCanvas(),
				context = canvas.getContext();

			canvas.save();
			canvas.applyLineJoin(this);
			canvas.applyAncestorTransforms(this);
			canvas.applyRotation(this);
			draw.call(this, canvas);
			canvas.restore();

			return this;
		},

		getLineJoin: function() {
			return this.attr.lineJoin;
		},
		setLineJoin: function(joint) {
			this.attr.lineJoin = joint;
			return this;
		},

		/**
		 * Whether a stroke is set
		 * @return {Boolean}
		 */
		hasStroke: function() {
			var stroke = this.getStroke();
			return (stroke && stroke.isEnabled() && stroke.getWidth() > 0);
		},
		getStroke: function() {
			return this.attr.stroke;
		},
		setStroke: function(config) {
			if (config instanceof Gear.Stroke) {
				this.attr.stroke = config;
				return this;
			}

			this.attr.stroke = new Gear.Stroke(config);
			return this;
		},

		/**
		 * Whether a fill is set
		 * @return {Boolean}
		 */
		hasFill: function() {
			var fill = this.getFill();
			return (fill && fill.isEnabled());
		},
		getFill: function() {
			return this.attr.fill;
		},
		setFill: function(fill) {
			if (Gear.Fill.isFill(fill)) {
				this.att.fill = fill;
			}

			this.attr.fill = Gear.Fill.parse(fill);
			return this;
		},

		/**
		 * Whether a shadow is set
		 * @return {Boolean}
		 */
		hasShadow: function() {
			var shadow = this.getShadow();
			return (shadow && shadow.isEnabled() && shadow.getOpacity() !== 0);
		},
		getShadow: function() {
			return this.attr.shadow;
		},
		setShadow: function(config) {
			if (config instanceof Gear.Shadow) {
				this.attr.shadow = config;
				return this;
			}

			this.attr.shadow = new Gear.Shadow(config);
			return this;
		},

		/**
		 * Cache | Uncahe
		 */
		_getCacheScene: function() {
			return this._cacheScene || (this._cacheScene = new Gear.SceneCanvas());
		},
		cache: function() {
			var scene = this._getCacheScene(),
				draw = this.getDraw() || this.draw;
			scene.setSize(this.getSize());
			draw.call(this, scene);
			this._cache = scene;
			return this;
		},
		uncache: function() {
			this._cache = null;
			return this;
		},

		/**
		 * Destroy
		 * @return {[type]} [description]
		 */
		destroy: function() {
			Gear.Node.prototype.destroy.call(this);
			delete Global.shapes[this.getColorId()];
			return this;
		},

		toString: function() {
			return '[Shape]';
		}
	});

	Gear.Shape = Shape;

}(Gear, Gear.Global, Gear.Const, Gear.Util));<|endoftext|>


<commit_before>import thunkMiddleware from 'redux-thunk'
import {compose, createStore, applyMiddleware} from 'redux'
import imdiReducers from '../../reducers'
import analyticsMiddleware from './analyticsMiddleware'
import {logCustomPageView, logCustomEvent} from '../googleTagManager'

import {
  NAVIGATE,
  GOOGLE_TAG_MANAGER_EVENT
} from '../../actions/ActionTypes'

const middlewares = [
  applyMiddleware(thunkMiddleware),

  applyMiddleware(analyticsMiddleware((action, state) => {
    if (action.type == NAVIGATE) {
      logCustomPageView(action, state)
    }
    if (action.type == GOOGLE_TAG_MANAGER_EVENT) {
      logCustomEvent(action, state)
    }
  })),

].filter(Boolean)

const createStoreWithMiddlewares = compose(...middlewares)(createStore)

export default function createImdiAppStore(initialState = {}) {
  return createStoreWithMiddlewares(imdiReducers, initialState)
}
<commit_msg>Middleware wiring<commit_after>import thunkMiddleware from 'redux-thunk'
import {compose, createStore, applyMiddleware} from 'redux'
import imdiReducers from '../../reducers'
import analyticsMiddleware from './analyticsMiddleware'
import {logCustomPageView, logCustomEvent} from '../googleTagManager'

import {
  NAVIGATE,
  TRACK_EVENT,
  OPEN_CARD
} from '../../actions/ActionTypes'

const middlewares = [
  applyMiddleware(thunkMiddleware),

  applyMiddleware(analyticsMiddleware((action, state) => {
    if (action.type == NAVIGATE) {
      logCustomPageView(action, state)
    }
    if (action.type == OPEN_CARD || action.type.startsWith(TRACK_EVENT)) {
      logCustomEvent(action, state)
    }
  }))
].filter(Boolean)

const createStoreWithMiddlewares = compose(...middlewares)(createStore)

export default function createImdiAppStore(initialState = {}) {
  return createStoreWithMiddlewares(imdiReducers, initialState)
}
<|endoftext|>


<commit_before>'use strict';

var expect = require('chai').expect;
var fs = require('fs-extra');
var path = require('path');
var packageServerScript = require('../../../src/cli/domain/package-server-script/index.js');
var hashBuilder = require('../../../src/utils/hash-builder');

var serverName = 'server.js';
var componentName = 'component';
var componentPath = path.resolve(__dirname, componentName);
var publishPath = path.resolve(componentPath, '_package');
var webpackOptions = {
  stats: 'none'
};

describe('cli : domain : package-server-script', function(){
  beforeEach(function(done){
    if(!fs.existsSync(componentPath)) {
      fs.mkdirSync(componentPath);
      fs.mkdirSync(path.resolve(componentPath, '_package'));
    }
    done();
  });

  afterEach(function(done){
    if(fs.existsSync(componentPath)) {
      fs.removeSync(componentPath);
    }
    done();
  });

  describe('when packaging component\'s server.js', function(){
    this.timeout(15000);

    describe('when component implements not-valid javascript', function(){
      var serverContent = '\nmodule.exports.data=function(context,cb){\nreturn cb(null,data; };';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should throw an error with error details', function(done){
<<<<<<< 139682f91d4265cf5a425a2e232c0e52a16f09f9
        try {
          packageServerScript(
            {
              componentPath: componentPath,
              ocOptions: {
                files: {
                  data: serverName
                }
              },
              publishPath: publishPath,
              webpack: webpackOptions
            },
            function(err, res){
              try {
                expect(err.toString()).to.contain.contain('Unexpected token, expected , (3:19)');
                return done();
              } catch(e) {
                return done(e);
              }
              return done('error');
            }
          );
        } catch (e) {
          expect(e).to.contain.contain('Unexpected token, expected , (3:19)');
          return done();
        }
      });
    });

    describe('when component does not require any module', function(){
      var serverContent = 'module.exports.data=function(context,cb){\nreturn cb(null, {name:\'John\'});\n};';
=======
        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions
          },
          function(err, res){
            try {
              expect(err.toString()).to.contain.contain('Unexpected token, expected , (3:19)');
              return done();
            } catch(e) {
              return done(e);
            }
            return done('error');
          }
        );
      });
    });

    describe('when component does not require any json', function(){
      var serverContent = '\nmodule.exports.data=function(context,cb){\nreturn cb(null, {name:\'John\'});\n};';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should save compiled data provider and return a hash for the script', function(done){
        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              expect(res.type).to.equal('node.js');
              expect(res.src).to.equal('server.js');

              var compiledContent = fs.readFileSync(path.resolve(publishPath, res.src), {encoding: 'utf8'});
              expect(res.hashKey).to.equal(hashBuilder.fromString(compiledContent));
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });
    });

    describe('when component require a json file', function(){
      var user = {first: 'John',last:'Doe'};
      var jsonContent = JSON.stringify(user);
      var serverContent = 'var user = require(\'./user\');\nmodule.exports.data=function(){return user.first;};';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, 'user.json'), jsonContent);
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should save compiled and minified data provider encapsulating json content', function(done){
        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              var name = user.first;
              var bundle = require(path.resolve(publishPath, res.src));
              expect(bundle.data()).to.be.equal(name);

              var compiledContent = fs.readFileSync(path.resolve(publishPath, res.src), {encoding: 'utf8'});
              expect(compiledContent).to.not.contain('user');
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });
    });

    describe('when component does require an npm module', function(){
      var serverContent = 'var _ =require(\'underscore\');'
        + '\nvar user = {name:\'John\'};\nmodule.exports.data=function(context,cb){'
        + '\nreturn cb(null, _.has(user, \'name\'));\n};';
>>>>>>> integration tests

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should save compiled data provider', function(done){
        var dependencies = {underscore: '1.8.3'};

        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions,
            dependencies: dependencies
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              expect(res.type).to.equal('node.js');
              expect(res.src).to.equal('server.js');

              var compiledContent = fs.readFileSync(path.resolve(publishPath, res.src), {encoding: 'utf8'});
              expect(res.hashKey).to.equal(hashBuilder.fromString(compiledContent));
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });

      describe('end required depenencies is not present in the package.json', function(){
        it('should throw an error with details', function(done){
          var dependencies = {lodash: '1.0.0'};

          packageServerScript(
            {
              componentPath: componentPath,
              ocOptions: {
                files: {
                  data: serverName
                }
              },
              publishPath: publishPath,
              webpack: webpackOptions,
              dependencies: dependencies
            },
            function(err, res){
              try {
                expect(/Missing depenencies drom package.json => \"underscore\"/ig.test(err));
                return done();
              } catch(e) {
                return done(e);
              }
            }
          );
        });
      });
    });

    describe('when component does require a relative path from an npm module', function(){
      var serverContent = 'var data=require(\'react-dom/server\');module.exports.data=function(context,cb){return cb(null,data); };';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should throw an error when the dependency is not present in the package.json', function(done){
        var dependencies = {'react': '15.4.2'};

        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions,
            dependencies: dependencies
          },
          function(err, res){
            try {
              expect(err.toString()).to.contain('Missing dependencies from package.json => \"react-dom\"');
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });
    });

    describe('when component require a local js module', function(){
      var jsContent = 'var user = {first: \'John\',last:\'Doe\'};\nmodule.exports = user';
      var serverContent = 'var user = require(\'./user\');\nmodule.exports.data=function(){return user.first;};';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, 'user.js'), jsContent);
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should save compiled data provider encapsulating js module content', function(done){
        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              var name = 'John';
              var bundle = require(path.resolve(publishPath, res.src));
              expect(bundle.data()).to.be.equal(name);
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });
    });

    describe('when component uses es2015 javascript syntax', function(){
      var serverContent = 'const {first, last} = {first: "John", last: "Doe"};\nconst data = (context,cb) => cb(null, first, last)\nexport {data}';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should transpile it to es2015 through Babel', function(done){
        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              var compiledContent = fs.readFileSync(path.resolve(publishPath, res.src), {encoding: 'utf8'});
              expect(compiledContent).to.not.contain('=>');
              expect(compiledContent).to.not.contain('const');
              expect(compiledContent).to.contain('var');
              expect(compiledContent).to.contain('function');
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });
    });

    describe('when component code includes a loop', function(){
      var serverContent = 'module.exports.data=function(context,cb){ var x,y,z;'
        + 'while(true){ x = 234; }'
        + 'for(var i=1e12;;){ y = 546; }'
        + 'do { z = 342; } while(true);'
        + '}';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should wrap while/do/for;; loops with an iterator limit', function(done){
        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              var compiledContent = fs.readFileSync(path.resolve(publishPath, res.src), {encoding: 'utf8'});
              expect(compiledContent).to.contain('for(var r,a,t,i=1e9;;){if(i<=0)throw new Error(\"loop exceeded maximum allowed iterations\");r=234,i--}');
              expect(compiledContent).to.contain('for(var i=1e9;;){if(i<=0)throw new Error(\"loop exceeded maximum allowed iterations\");a=546,i--}');
              expect(compiledContent).to.contain('for(var i=1e9;;){if(i<=0)throw new Error(\"loop exceeded maximum allowed iterations\");t=342,i--}');
              done();
            } catch(e) {
              return done();
            }
          }
        );
      });
    });
  });
});
<commit_msg>unit tests<commit_after>'use strict';

var expect = require('chai').expect;
var fs = require('fs-extra');
var path = require('path');
var packageServerScript = require('../../../src/cli/domain/package-server-script/index.js');
var hashBuilder = require('../../../src/utils/hash-builder');

var serverName = 'server.js';
var componentName = 'component';
var componentPath = path.resolve(__dirname, componentName);
var publishPath = path.resolve(componentPath, '_package');
var webpackOptions = {
  stats: 'none'
};

describe('cli : domain : package-server-script', function(){
  beforeEach(function(done){
    if(!fs.existsSync(componentPath)) {
      fs.mkdirSync(componentPath);
      fs.mkdirSync(path.resolve(componentPath, '_package'));
    }
    done();
  });

  afterEach(function(done){
    if(fs.existsSync(componentPath)) {
      fs.removeSync(componentPath);
    }
    done();
  });

  describe('when packaging component\'s server.js', function(){
    this.timeout(15000);

    describe('when component implements not-valid javascript', function(){
      var serverContent = '\nmodule.exports.data=function(context,cb){\nreturn cb(null,data; };';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should throw an error with error details', function(done){
        try {
          packageServerScript(
            {
              componentPath: componentPath,
              ocOptions: {
                files: {
                  data: serverName
                }
              },
              publishPath: publishPath,
              webpack: webpackOptions
            },
            function(err, res){
              try {
                expect(err.toString()).to.contain.contain('Unexpected token, expected , (3:19)');
                return done();
              } catch(e) {
                return done(e);
              }
              return done('error');
            }
          );
        } catch (e) {
          expect(e).to.contain.contain('Unexpected token, expected , (3:19)');
          done();
        }
      });
    });

    describe('when component does not require any json', function(){
      var serverContent = '\nmodule.exports.data=function(context,cb){\nreturn cb(null, {name:\'John\'});\n};';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should save compiled data provider and return a hash for the script', function(done){
        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              expect(res.type).to.equal('node.js');
              expect(res.src).to.equal('server.js');

              var compiledContent = fs.readFileSync(path.resolve(publishPath, res.src), {encoding: 'utf8'});
              expect(res.hashKey).to.equal(hashBuilder.fromString(compiledContent));
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });
    });

    describe('when component require a json file', function(){
      var user = {first: 'John',last:'Doe'};
      var jsonContent = JSON.stringify(user);
      var serverContent = 'var user = require(\'./user\');\nmodule.exports.data=function(){return user.first;};';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, 'user.json'), jsonContent);
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should save compiled and minified data provider encapsulating json content', function(done){
        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              var name = user.first;
              var bundle = require(path.resolve(publishPath, res.src));
              expect(bundle.data()).to.be.equal(name);

              var compiledContent = fs.readFileSync(path.resolve(publishPath, res.src), {encoding: 'utf8'});
              expect(compiledContent).to.not.contain('user');
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });
    });

    describe('when component does require an npm module', function(){
      var serverContent = 'var _ =require(\'underscore\');'
        + '\nvar user = {name:\'John\'};\nmodule.exports.data=function(context,cb){'
        + '\nreturn cb(null, _.has(user, \'name\'));\n};';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should save compiled data provider', function(done){
        var dependencies = {underscore: '1.8.3'};

        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions,
            dependencies: dependencies
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              expect(res.type).to.equal('node.js');
              expect(res.src).to.equal('server.js');

              var compiledContent = fs.readFileSync(path.resolve(publishPath, res.src), {encoding: 'utf8'});
              expect(res.hashKey).to.equal(hashBuilder.fromString(compiledContent));
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });

      describe('end required depenencies is not present in the package.json', function(){
        it('should throw an error with details', function(done){
          var dependencies = {lodash: '1.0.0'};

          packageServerScript(
            {
              componentPath: componentPath,
              ocOptions: {
                files: {
                  data: serverName
                }
              },
              publishPath: publishPath,
              webpack: webpackOptions,
              dependencies: dependencies
            },
            function(err, res){
              try {
                expect(/Missing depenencies drom package.json => \"underscore\"/ig.test(err));
                return done();
              } catch(e) {
                return done(e);
              }
            }
          );
        });
      });
    });

    describe('when component does require a relative path from an npm module', function(){
      var serverContent = 'var data=require(\'react-dom/server\');module.exports.data=function(context,cb){return cb(null,data); };';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should throw an error when the dependency is not present in the package.json', function(done){
        var dependencies = {'react': '15.4.2'};

        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions,
            dependencies: dependencies
          },
          function(err, res){
            try {
              expect(err.toString()).to.contain('Missing dependencies from package.json => \"react-dom\"');
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });
    });

    describe('when component require a local js module', function(){
      var jsContent = 'var user = {first: \'John\',last:\'Doe\'};\nmodule.exports = user';
      var serverContent = 'var user = require(\'./user\');\nmodule.exports.data=function(){return user.first;};';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, 'user.js'), jsContent);
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should save compiled data provider encapsulating js module content', function(done){
        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              var name = 'John';
              var bundle = require(path.resolve(publishPath, res.src));
              expect(bundle.data()).to.be.equal(name);
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });
    });

    describe('when component uses es2015 javascript syntax', function(){
      var serverContent = 'const {first, last} = {first: "John", last: "Doe"};\nconst data = (context,cb) => cb(null, first, last)\nexport {data}';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should transpile it to es2015 through Babel', function(done){
        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              var compiledContent = fs.readFileSync(path.resolve(publishPath, res.src), {encoding: 'utf8'});
              expect(compiledContent).to.not.contain('=>');
              expect(compiledContent).to.not.contain('const');
              expect(compiledContent).to.contain('var');
              expect(compiledContent).to.contain('function');
              return done();
            } catch(e) {
              return done(e);
            }
          }
        );
      });
    });

    describe('when component code includes a loop', function(){
      var serverContent = 'module.exports.data=function(context,cb){ var x,y,z;'
        + 'while(true){ x = 234; }'
        + 'for(var i=1e12;;){ y = 546; }'
        + 'do { z = 342; } while(true);'
        + '}';

      beforeEach(function(done){
        fs.writeFileSync(path.resolve(componentPath, serverName), serverContent);
        done();
      });

      it('should wrap while/do/for;; loops with an iterator limit', function(done){
        packageServerScript(
          {
            componentPath: componentPath,
            ocOptions: {
              files: {
                data: serverName
              }
            },
            publishPath: publishPath,
            webpack: webpackOptions
          },
          function(err, res){
            if (err) {
              return done(err);
            }
            try {
              var compiledContent = fs.readFileSync(path.resolve(publishPath, res.src), {encoding: 'utf8'});
              expect(compiledContent).to.contain('for(var r,a,t,i=1e9;;){if(i<=0)throw new Error(\"loop exceeded maximum allowed iterations\");r=234,i--}');
              expect(compiledContent).to.contain('for(var i=1e9;;){if(i<=0)throw new Error(\"loop exceeded maximum allowed iterations\");a=546,i--}');
              expect(compiledContent).to.contain('for(var i=1e9;;){if(i<=0)throw new Error(\"loop exceeded maximum allowed iterations\");t=342,i--}');
              done();
            } catch(e) {
              return done();
            }
          }
        );
      });
    });
  });
});
<|endoftext|>


<commit_before>/**
 * Utilities for mouse or touch events.
 */

import Eventful from '../mixin/Eventful';
import env from './env';
import {buildTransformer} from './fourPointsTransform';

var isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;

var MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;
var EVENT_SAVED_PROP = '___zrEVENTSAVED';
var _calcOut = [];

/**
 * Get the `zrX` and `zrY`, which are relative to the top-left of
 * the input `el`.
 * CSS transform (2D & 3D) is supported.
 *
 * The strategy to fetch the coords:
 * + If `calculate` is not set as `true`, users of this method should
 * ensure that `el` is the same or the same size & location as `e.target`.
 * Otherwise the result coords are probably not expected. Because we
 * firstly try to get coords from e.offsetX/e.offsetY.
 * + If `calculate` is set as `true`, the input `el` can be any element
 * and we force to calculate the coords based on `el`.
 * + The input `el` should be positionable (not position:static).
 *
 * The force `calculate` can be used in case like:
 * When mousemove event triggered on ec tooltip, `e.target` is not `el`(zr painter.dom).
 *
 * @param {HTMLElement} el DOM element.
 * @param {Event} e Mouse event or touch event.
 * @param {Object} out Get `out.zrX` and `out.zrY` as the result.
 * @param {boolean} [calculate=false] Whether to force calculate
 *        the coordinates but not use ones provided by browser.
 */
export function clientToLocal(el, e, out, calculate) {
    out = out || {};

    // According to the W3C Working Draft, offsetX and offsetY should be relative
    // to the padding edge of the target element. The only browser using this convention
    // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does
    // not support the properties.
    // (see http://www.jacklmoore.com/notes/mouse-position/)
    // In zr painter.dom, padding edge equals to border edge.

    if (calculate || !env.canvasSupported) {
        calculateZrXY(el, e, out);
    }
    // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned
    // ancestor element, so we should make sure el is positioned (e.g., not position:static).
    // BTW1, Webkit don't return the same results as FF in non-simple cases (like add
    // zoom-factor, overflow / opacity layers, transforms ...)
    // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.
    // <https://bugs.jquery.com/ticket/8523#comment:14>
    // BTW3, In ff, offsetX/offsetY is always 0.
    else if (env.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {
        out.zrX = e.layerX;
        out.zrY = e.layerY;
    }
    // For IE6+, chrome, safari, opera. (When will ff support offsetX?)
    else if (e.offsetX != null) {
        out.zrX = e.offsetX;
        out.zrY = e.offsetY;
    }
    // For some other device, e.g., IOS safari.
    else {
        calculateZrXY(el, e, out);
    }

    return out;
}

function calculateZrXY(el, e, out) {
    // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect.
    if (el.getBoundingClientRect && env.domSupported) {
        var ex = e.clientX;
        var ey = e.clientY;

        if (el.nodeName.toUpperCase() === 'CANVAS') {
            // Original approach, which do not support CSS transform.
            // marker can not be locationed in a canvas container
            // (getBoundingClientRect is always 0). We do not support
            // that input a pre-created canvas to zr while using css
            // transform in iOS.
            var box = el.getBoundingClientRect();
            out.zrX = ex - box.left;
            out.zrY = ey - box.top;
            return;
        }
        else {
            var saved = el[EVENT_SAVED_PROP] || (el[EVENT_SAVED_PROP] = {});
            var transformer = preparePointerTransformer(prepareCoordMarkers(el, saved), saved);
            if (transformer) {
                transformer(_calcOut, ex, ey);
                out.zrX = _calcOut[0];
                out.zrY = _calcOut[1];
                return;
            }
        }
    }
    out.zrX = out.zrY = 0;
}

function prepareCoordMarkers(el, saved) {
    var markers = saved.markers;
    if (markers) {
        return markers;
    }

    markers = saved.markers = [];
    var propLR = ['left', 'right'];
    var propTB = ['top', 'bottom'];

    for (var i = 0; i < 4; i++) {
        var marker = document.createElement('div');
        var stl = marker.style;
        var idxLR = i % 2;
        var idxTB = (i >> 1) % 2;
        stl.cssText = [
            'position:absolute',
            'visibility: hidden',
            'padding: 0',
            'margin: 0',
            'border-width: 0',
            'width:0',
            'height:0',
            // 'width: 5px',
            // 'height: 5px',
            propLR[idxLR] + ':0',
            propTB[idxTB] + ':0',
            propLR[1 - idxLR] + ':auto',
            propTB[1 - idxTB] + ':auto',
            ''
        ].join('!important;');
        el.appendChild(marker);
        markers.push(marker);
    }

    return markers;
}

function preparePointerTransformer(markers, saved) {
    var transformer = saved.transformer;
    var oldSrcCoords = saved.srcCoords;
    var useOld = true;
    var srcCoords = [];
    var destCoords = [];

    for (var i = 0; i < 4; i++) {
        var rect = markers[i].getBoundingClientRect();
        var ii = 2 * i;
        var x = rect.left;
        var y = rect.top;
        srcCoords.push(x, y);
        useOld &= oldSrcCoords && x === oldSrcCoords[ii] && y === oldSrcCoords[ii + 1];
        destCoords.push(markers[i].offsetLeft, markers[i].offsetTop);
    }

    // Cache to avoid time consuming of `buildTransformer`.
    return useOld
        ? transformer
        : (
            saved.srcCoords = srcCoords,
            saved.transformer = buildTransformer(srcCoords, destCoords)
        );
}

/**
 * Normalize the coordinates of the input event.
 *
 * Get the `e.zrX` and `e.zrY`, which are relative to the top-left of
 * the input `el`.
 * Get `e.zrDelta` if using mouse wheel.
 * Get `e.which`, see the comment inside this function.
 *
 * Do not calculate repeatly if `zrX` and `zrY` already exist.
 *
 * Notice: see comments in `clientToLocal`. check the relationship
 * between the result coords and the parameters `el` and `calculate`.
 *
 * @param {HTMLElement} el DOM element.
 * @param {Event} [e] Mouse event or touch event. For lagency IE,
 *        do not need to input it and `window.event` is used.
 * @param {boolean} [calculate=false] Whether to force calculate
 *        the coordinates but not use ones provided by browser.
 */
export function normalizeEvent(el, e, calculate) {

    e = e || window.event;

    if (e.zrX != null) {
        return e;
    }

    var eventType = e.type;
    var isTouch = eventType && eventType.indexOf('touch') >= 0;

    if (!isTouch) {
        clientToLocal(el, e, e, calculate);
        e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;
    }
    else {
        var touch = eventType !== 'touchend'
            ? e.targetTouches[0]
            : e.changedTouches[0];
        touch && clientToLocal(el, touch, e, calculate);
    }

    // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0;
    // See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js
    // If e.which has been defined, it may be readonly,
    // see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which
    var button = e.button;
    if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {
        e.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));
    }
    // [Caution]: `e.which` from browser is not always reliable. For example,
    // when press left button and `mousemove (pointermove)` in Edge, the `e.which`
    // is 65536 and the `e.button` is -1. But the `mouseup (pointerup)` and
    // `mousedown (pointerdown)` is the same as Chrome does.

    return e;
}

/**
 * @param {HTMLElement} el
 * @param {string} name
 * @param {Function} handler
 */
export function addEventListener(el, name, handler) {
    if (isDomLevel2) {
        // Reproduct the console warning:
        // [Violation] Added non-passive event listener to a scroll-blocking <some> event.
        // Consider marking event handler as 'passive' to make the page more responsive.
        // Just set console log level: verbose in chrome dev tool.
        // then the warning log will be printed when addEventListener called.
        // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
        // We have not yet found a neat way to using passive. Because in zrender the dom event
        // listener delegate all of the upper events of element. Some of those events need
        // to prevent default. For example, the feature `preventDefaultMouseMove` of echarts.
        // Before passive can be adopted, these issues should be considered:
        // (1) Whether and how a zrender user specifies an event listener passive. And by default,
        // passive or not.
        // (2) How to tread that some zrender event listener is passive, and some is not. If
        // we use other way but not preventDefault of mousewheel and touchmove, browser
        // compatibility should be handled.

        // var opts = (env.passiveSupported && name === 'mousewheel')
        //     ? {passive: true}
        //     // By default, the third param of el.addEventListener is `capture: false`.
        //     : void 0;
        // el.addEventListener(name, handler /* , opts */);
        el.addEventListener(name, handler);
    }
    else {
        el.attachEvent('on' + name, handler);
    }
}

export function removeEventListener(el, name, handler) {
    if (isDomLevel2) {
        el.removeEventListener(name, handler);
    }
    else {
        el.detachEvent('on' + name, handler);
    }
}

/**
 * preventDefault and stopPropagation.
 * Notice: do not use this method in zrender. It can only be
 * used by upper applications if necessary.
 *
 * @param {Event} e A mouse or touch event.
 */
export var stop = isDomLevel2
    ? function (e) {
        e.preventDefault();
        e.stopPropagation();
        e.cancelBubble = true;
    }
    : function (e) {
        e.returnValue = false;
        e.cancelBubble = true;
    };

/**
 * This method only works for mouseup and mousedown. The functionality is restricted
 * for fault tolerance, See the `e.which` compatibility above.
 *
 * @param {MouseEvent} e
 * @return {boolean}
 */
export function isMiddleOrRightButtonOnMouseUpDown(e) {
    return e.which === 2 || e.which === 3;
}

/**
 * To be removed.
 * @deprecated
 */
export function notLeftMouse(e) {
    // If e.which is undefined, considered as left mouse event.
    return e.which > 1;
}

// For backwork compatibility
export {Eventful as Dispatcher};
<commit_msg>typo<commit_after>/**
 * Utilities for mouse or touch events.
 */

import Eventful from '../mixin/Eventful';
import env from './env';
import {buildTransformer} from './fourPointsTransform';

var isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;

var MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;
var EVENT_SAVED_PROP = '___zrEVENTSAVED';
var _calcOut = [];

/**
 * Get the `zrX` and `zrY`, which are relative to the top-left of
 * the input `el`.
 * CSS transform (2D & 3D) is supported.
 *
 * The strategy to fetch the coords:
 * + If `calculate` is not set as `true`, users of this method should
 * ensure that `el` is the same or the same size & location as `e.target`.
 * Otherwise the result coords are probably not expected. Because we
 * firstly try to get coords from e.offsetX/e.offsetY.
 * + If `calculate` is set as `true`, the input `el` can be any element
 * and we force to calculate the coords based on `el`.
 * + The input `el` should be positionable (not position:static).
 *
 * The force `calculate` can be used in case like:
 * When mousemove event triggered on ec tooltip, `e.target` is not `el`(zr painter.dom).
 *
 * @param {HTMLElement} el DOM element.
 * @param {Event} e Mouse event or touch event.
 * @param {Object} out Get `out.zrX` and `out.zrY` as the result.
 * @param {boolean} [calculate=false] Whether to force calculate
 *        the coordinates but not use ones provided by browser.
 */
export function clientToLocal(el, e, out, calculate) {
    out = out || {};

    // According to the W3C Working Draft, offsetX and offsetY should be relative
    // to the padding edge of the target element. The only browser using this convention
    // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does
    // not support the properties.
    // (see http://www.jacklmoore.com/notes/mouse-position/)
    // In zr painter.dom, padding edge equals to border edge.

    if (calculate || !env.canvasSupported) {
        calculateZrXY(el, e, out);
    }
    // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned
    // ancestor element, so we should make sure el is positioned (e.g., not position:static).
    // BTW1, Webkit don't return the same results as FF in non-simple cases (like add
    // zoom-factor, overflow / opacity layers, transforms ...)
    // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.
    // <https://bugs.jquery.com/ticket/8523#comment:14>
    // BTW3, In ff, offsetX/offsetY is always 0.
    else if (env.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {
        out.zrX = e.layerX;
        out.zrY = e.layerY;
    }
    // For IE6+, chrome, safari, opera. (When will ff support offsetX?)
    else if (e.offsetX != null) {
        out.zrX = e.offsetX;
        out.zrY = e.offsetY;
    }
    // For some other device, e.g., IOS safari.
    else {
        calculateZrXY(el, e, out);
    }

    return out;
}

function calculateZrXY(el, e, out) {
    // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect.
    if (el.getBoundingClientRect && env.domSupported) {
        var ex = e.clientX;
        var ey = e.clientY;

        if (el.nodeName.toUpperCase() === 'CANVAS') {
            // Original approach, which do not support CSS transform.
            // marker can not be locationed in a canvas container
            // (getBoundingClientRect is always 0). We do not support
            // that input a pre-created canvas to zr while using css
            // transform in iOS.
            var box = el.getBoundingClientRect();
            out.zrX = ex - box.left;
            out.zrY = ey - box.top;
            return;
        }
        else {
            var saved = el[EVENT_SAVED_PROP] || (el[EVENT_SAVED_PROP] = {});
            var transformer = preparePointerTransformer(prepareCoordMarkers(el, saved), saved);
            if (transformer) {
                transformer(_calcOut, ex, ey);
                out.zrX = _calcOut[0];
                out.zrY = _calcOut[1];
                return;
            }
        }
    }
    out.zrX = out.zrY = 0;
}

function prepareCoordMarkers(el, saved) {
    var markers = saved.markers;
    if (markers) {
        return markers;
    }

    markers = saved.markers = [];
    var propLR = ['left', 'right'];
    var propTB = ['top', 'bottom'];

    for (var i = 0; i < 4; i++) {
        var marker = document.createElement('div');
        var stl = marker.style;
        var idxLR = i % 2;
        var idxTB = (i >> 1) % 2;
        stl.cssText = [
            'position:absolute',
            'visibility: hidden',
            'padding: 0',
            'margin: 0',
            'border-width: 0',
            'width:0',
            'height:0',
            // 'width: 5px',
            // 'height: 5px',
            propLR[idxLR] + ':0',
            propTB[idxTB] + ':0',
            propLR[1 - idxLR] + ':auto',
            propTB[1 - idxTB] + ':auto',
            ''
        ].join('!important;');
        el.appendChild(marker);
        markers.push(marker);
    }

    return markers;
}

function preparePointerTransformer(markers, saved) {
    var transformer = saved.transformer;
    var oldSrcCoords = saved.srcCoords;
    var useOld = true;
    var srcCoords = [];
    var destCoords = [];

    for (var i = 0; i < 4; i++) {
        var rect = markers[i].getBoundingClientRect();
        var ii = 2 * i;
        var x = rect.left;
        var y = rect.top;
        srcCoords.push(x, y);
        useOld &= oldSrcCoords && x === oldSrcCoords[ii] && y === oldSrcCoords[ii + 1];
        destCoords.push(markers[i].offsetLeft, markers[i].offsetTop);
    }

    // Cache to avoid time consuming of `buildTransformer`.
    return useOld
        ? transformer
        : (
            saved.srcCoords = srcCoords,
            saved.transformer = buildTransformer(srcCoords, destCoords)
        );
}

/**
 * Normalize the coordinates of the input event.
 *
 * Get the `e.zrX` and `e.zrY`, which are relative to the top-left of
 * the input `el`.
 * Get `e.zrDelta` if using mouse wheel.
 * Get `e.which`, see the comment inside this function.
 *
 * Do not calculate repeatly if `zrX` and `zrY` already exist.
 *
 * Notice: see comments in `clientToLocal`. check the relationship
 * between the result coords and the parameters `el` and `calculate`.
 *
 * @param {HTMLElement} el DOM element.
 * @param {Event} [e] Mouse event or touch event. For lagency IE,
 *        do not need to input it and `window.event` is used.
 * @param {boolean} [calculate=false] Whether to force calculate
 *        the coordinates but not use ones provided by browser.
 */
export function normalizeEvent(el, e, calculate) {

    e = e || window.event;

    if (e.zrX != null) {
        return e;
    }

    var eventType = e.type;
    var isTouch = eventType && eventType.indexOf('touch') >= 0;

    if (!isTouch) {
        clientToLocal(el, e, e, calculate);
        e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;
    }
    else {
        var touch = eventType !== 'touchend'
            ? e.targetTouches[0]
            : e.changedTouches[0];
        touch && clientToLocal(el, touch, e, calculate);
    }

    // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0;
    // See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js
    // If e.which has been defined, it may be readonly,
    // see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which
    var button = e.button;
    if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {
        e.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));
    }
    // [Caution]: `e.which` from browser is not always reliable. For example,
    // when press left button and `mousemove (pointermove)` in Edge, the `e.which`
    // is 65536 and the `e.button` is -1. But the `mouseup (pointerup)` and
    // `mousedown (pointerdown)` is the same as Chrome does.

    return e;
}

/**
 * @param {HTMLElement} el
 * @param {string} name
 * @param {Function} handler
 */
export function addEventListener(el, name, handler) {
    if (isDomLevel2) {
        // Reproduct the console warning:
        // [Violation] Added non-passive event listener to a scroll-blocking <some> event.
        // Consider marking event handler as 'passive' to make the page more responsive.
        // Just set console log level: verbose in chrome dev tool.
        // then the warning log will be printed when addEventListener called.
        // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
        // We have not yet found a neat way to using passive. Because in zrender the dom event
        // listener delegate all of the upper events of element. Some of those events need
        // to prevent default. For example, the feature `preventDefaultMouseMove` of echarts.
        // Before passive can be adopted, these issues should be considered:
        // (1) Whether and how a zrender user specifies an event listener passive. And by default,
        // passive or not.
        // (2) How to tread that some zrender event listener is passive, and some is not. If
        // we use other way but not preventDefault of mousewheel and touchmove, browser
        // compatibility should be handled.

        // var opts = (env.passiveSupported && name === 'mousewheel')
        //     ? {passive: true}
        //     // By default, the third param of el.addEventListener is `capture: false`.
        //     : void 0;
        // el.addEventListener(name, handler /* , opts */);
        el.addEventListener(name, handler);
    }
    else {
        el.attachEvent('on' + name, handler);
    }
}

export function removeEventListener(el, name, handler) {
    if (isDomLevel2) {
        el.removeEventListener(name, handler);
    }
    else {
        el.detachEvent('on' + name, handler);
    }
}

/**
 * preventDefault and stopPropagation.
 * Notice: do not use this method in zrender. It can only be
 * used by upper applications if necessary.
 *
 * @param {Event} e A mouse or touch event.
 */
export var stop = isDomLevel2
    ? function (e) {
        e.preventDefault();
        e.stopPropagation();
        e.cancelBubble = true;
    }
    : function (e) {
        e.returnValue = false;
        e.cancelBubble = true;
    };

/**
 * This method only works for mouseup and mousedown. The functionality is restricted
 * for fault tolerance, See the `e.which` compatibility above.
 *
 * @param {MouseEvent} e
 * @return {boolean}
 */
export function isMiddleOrRightButtonOnMouseUpDown(e) {
    return e.which === 2 || e.which === 3;
}

/**
 * To be removed.
 * @deprecated
 */
export function notLeftMouse(e) {
    // If e.which is undefined, considered as left mouse event.
    return e.which > 1;
}

// For backwark compatibility
export {Eventful as Dispatcher};
<|endoftext|>