<commit_before>/*
 * Copyright (c) 2008-2012 The Open Source Geospatial Foundation
 *
 * Published under the BSD license.
 * See https://github.com/geoext/geoext2/blob/master/license.txt for the full text
 * of the license.
 */

/**
 * @class GeoExt.panel.PrintMap
 *
 * A map panel that controls scale and center of a print page. Based on the
 *  current view (i.e. layers and extent) of a source map, this panel will be
 *  sized according to the aspect ratio of the print page. As the user zooms
 *  and pans in the :class:`GeoExt.PrintMapPanel`, the print page will update
 *  its scale and center accordingly. If the scale on the print page changes
 *  (e.g. by setting it using a combo box with a
 *  {@link GeoExt.plugins.PrintPageField}), the extent of the
 *  {@link GeoExt.PrintMapPanel} will be updated to match the page bounds.
 *
 *      The #zoom, #center and #extent config options will have
 *      no affect, as they will be determined by the #sourceMap.
 *
 *
 *  A map with a "Print..." button. If clicked, a dialog containing a
 *  PrintMapPanel will open, with a "Create PDF" button.
 *
 * Example:

var mapPanel = new GeoExt.MapPanel({
    renderTo: "map",
    layers: [new OpenLayers.Layer.WMS("Tasmania State Boundaries",
        "http://demo.opengeo.org/geoserver/wms",
        {layers: "topp:tasmania_state_boundaries"}, {singleTile: true})],
    center: [146.56, -41.56],
    zoom: 6,
    bbar: [{
        text: "Print...",
        handler: function() {
            var printDialog = new Ext.Window({
                autoHeight: true,
                width: 350,
                items: [new GeoExt.PrintMapPanel({
                    sourceMap: mapPanel,
                    printProvider: {
                        capabilities: printCapabilities
                    }
                })],
                bbar: [{
                    text: "Create PDF",
                    handler: function() {
                        printDialog.items.get(0).print();
                    }
                }]
            });
            printDialog.show();
        }
    }]
});

 */
Ext.define('GeoExt.panel.PrintMap', {
    extend : 'GeoExt.panel.Map',
    requires: ['GeoExt.data.PrintPage'],
    alias : 'widget.gx_printmappanel',
    alternateClassName : 'GeoExt.PrintMapPanel',

    /**
     * @cfg {Object} map
     * Optional configuration for the `OpenLayers.Map` object
     *  that this PrintMapPanel creates. Useful e.g. to configure a map with a
     *  custom set of controls, or to add a `preaddlayer` listener for
     *  filtering out layer types that cannot be printed.
     */

    /**
     * @cfg {GeoExt.MapPanel/OpenLayers.Map} sourceMap
     * The map that is to be printed.
     */

    /**
     * @private
     * @property {OpenLayers.Map} sourceMap
     */
    sourceMap: null,

    /**
     * @cfg {GeoExt.data.PrintProvider/Object} printProvider
     * PrintProvider to use for printing. If an `Object` is provided, a new PrintProvider will
     *  be created and configured with the object.
     *
     *    The PrintMapPanel requires the printProvider's capabilities
     *    to be available upon initialization. This means that a PrintMapPanel
     *    configured with an `Object` as `printProvider` will only work
     *    when `capabilities` is provided in the printProvider's
     *    configuration object. If `printProvider` is provided as an instance
     *    of :class:`GeoExt.data.PrintProvider`, the capabilities must be
     *    loaded before PrintMapPanel initialization.
     */

    /**
     * @property {GeoExt.data.PrintProvider} printProvider
     * PrintProvider for this PrintMapPanel.
     */
    printProvider: null,

    /**
     * @property {GeoExt.data.PrintPage} printPage
     * PrintPage for this PrintMapPanel.
     *  Read-only.
     */
    printPage: null,

    /**
     * @cfg {Boolean} limitScales
     * If set to true, the printPage cannot be set to scales that
     *  would generate a preview in this {@link GeoExt.PrintMapPanel} with a
     *  completely different extent than the one that would appear on the
     *  printed map. Default is false.
     */

    /**
     * @property {Ext.data.Store} previewScales
     * A data store with a subset of the printProvider's
     *  scales. By default, this contains all the scales of the printProvider.
     *  If `limitScales` is set to true, it will only contain print scales
     *  that can properly be previewed with this :class:`GeoExt.PrintMapPanel`.
     */
    previewScales: null,

    /**
     * @cfg {OpenLayers.LonLat/Number[]} center
     * A location for the map center.
     * Do not set, as this will be overridden with the `sourceMap`
     *  center.
     */
    center: null,

    /**
     * @cfg {Number} zoom
     * An initial zoom level for the map. Do not set, because the
     *  initial extent will be determined by the `sourceMap`.
     */
    zoom: null,

    /**
     * @cfg {OpenLayers.Bounds/Number[]} extent
     * An initial extent for the map.
     *  Do not set, because the initial extent will be determined by the
     *  `sourceMap`.
     */
    extent: null,

    /**
     * @private
     * @property {Number} currentZoom
     */
    currentZoom: null,

    /**
     * @private
     */
    initComponent: function() {
        if(this.sourceMap instanceof GeoExt.MapPanel) {
            this.sourceMap = this.sourceMap.map;
        }

        if (!this.map) {
            this.map = {};
        }

        Ext.applyIf(this.map, {
            projection: this.sourceMap.getProjection(),
            maxExtent: this.sourceMap.getMaxExtent(),
            maxResolution: this.sourceMap.getMaxResolution(),
            units: this.sourceMap.getUnits()
        });

        if(!(this.printProvider instanceof GeoExt.data.PrintProvider)) {
            this.printProvider = Ext.create('GeoExt.data.PrintProvider',
                this.printProvider);
        }
        this.printPage = Ext.create('GeoExt.data.PrintPage', {
            printProvider: this.printProvider
        });

        this.previewScales = Ext.create('Ext.data.Store', {
            fields: [
                 {name: 'name', type: 'string'},
                 {name: 'value', type: 'int'}
            ],
            data: this.printProvider.scales.getRange()
        });

        this.layers = [];
        var layer;
        Ext.each(this.sourceMap.layers, function(layer) {
            if (layer.getVisibility() === true) {
                if (layer instanceof OpenLayers.Layer.Vector) {
                    var features = layer.features,
                        clonedFeatures = new Array(features.length),
                        vector = new OpenLayers.Layer.Vector(layer.name);
                    for (var i=0, ii=features.length; i<ii; ++i) {
                        clonedFeatures[i] = features[i].clone();
                    }
                    vector.addFeatures(clonedFeatures, {silent: true});
                    this.layers.push(vector);
                } else {
                    this.layers.push(layer.clone());
                }
            }
        }, this);

        this.extent = this.sourceMap.getExtent();
<<<<<<>>>>>> 44a39a261fbb87800f0707e10692d4300a4cce81
        this.callParent(arguments);
    },

    /**
     * Calls the internal adjustSize-function and resizes
     * this {@link GeoExt.panel.PrintMap PrintMapPanel} due
     * to the needed size, defined by the current layout of the #printProvider.
     *
     * The Function was removed from Ext.Panel in ExtJS 4 and is
     * now implemented here.
     *
     * @private
     *
     */
    syncSize: function() {
        var s = this.adjustSize(this.map.size.w, this.map.size.h);
        this.setSize(s.width, s.height);
    },

    /**
     * @private
     */
    bind: function() {

        // we have to call syncSize here because of changed
        // rendering order in ExtJS4
        this.syncSize();

        this.printPage.on("change", this.fitZoom, this);
        this.printProvider.on("layoutchange", this.syncSize, this);
        this.map.events.register("moveend", this, this.updatePage);

        this.printPage.fit(this.sourceMap);

        if (this.initialConfig.limitScales === true) {
            this.on("resize", this.calculatePreviewScales, this);
            this.calculatePreviewScales();
        }
    },

    /**
     * Private method called after the panel has been rendered.
     *
     * @private
     */
    afterRender: function() {

        this.callParent(arguments);
        this.doComponentLayout();
        if (!this.ownerCt) {
            this.bind();
        } else {
            this.ownerCt.on({
                "afterlayout": {
                    fn: this.bind,
                    scope: this,
                    single: true
                }
            });
        }
    },

    /**
     * Private override - sizing this component always takes the aspect ratio
     *  of the print page into account.
     *
     * @private
     * @param {Number} width If not provided or 0, initialConfig.width will
     *  be used.
     * @param {Number} height If not provided or 0, initialConfig.height
     *  will be used.
     */
    adjustSize: function(width, height) {
        var printSize = this.printProvider.layout.get("size");
        var ratio = printSize.width / printSize.height;
        // respect width & height when sizing according to the print page's
        // aspect ratio - do not exceed either, but don't take values for
        // granted if container is configured with autoWidth or autoHeight.
        var ownerCt = this.ownerCt;
        var targetWidth = (ownerCt && ownerCt.autoWidth) ? 0 :
            (width || this.initialConfig.width);
        var targetHeight = (ownerCt && ownerCt.autoHeight) ? 0 :
            (height || this.initialConfig.height);
        if (targetWidth) {
            height = targetWidth / ratio;
            if (targetHeight && height > targetHeight) {
                height = targetHeight;
                width = height * ratio;
            } else {
                width = targetWidth;
            }
        } else if (targetHeight) {
            width = targetHeight * ratio;
            height = targetHeight;
        }

        return {width: width, height: height};
    },

    /**
     *  Fits this PrintMapPanel's zoom to the print scale.
     *
     *  @private
     */
    fitZoom: function() {
        if (!this._updating && this.printPage.scale) {
            this._updating = true;
            var printBounds = this.printPage.getPrintExtent(this.map);
            this.currentZoom = this.map.getZoomForExtent(printBounds);
            this.map.zoomToExtent(printBounds, false);

            delete this._updating;
        }
    },

    /**
     * Updates the print page to match this PrintMapPanel's center and scale.
     *
     * @private
     */
    updatePage: function() {
        if (!this._updating) {
            var zoom = this.map.getZoom();
            this._updating = true;
            if (zoom === this.currentZoom) {
                this.printPage.setCenter(this.map.getCenter());
            } else {
                this.printPage.fit(this.map);
            }
            delete this._updating;
            this.currentZoom = zoom;
        }
    },

    /**
     * @private
     */
    calculatePreviewScales: function() {
        this.previewScales.removeAll();

        this.printPage.suspendEvents();
        var scale = this.printPage.scale;

        // group print scales by the zoom level they would be previewed at
        var viewSize = this.map.getSize();
        var scalesByZoom = {};
        var zooms = [];
        this.printProvider.scales.each(function(rec) {
            this.printPage.setScale(rec);
            var extent = this.printPage.getPrintExtent(this.map);
            var zoom = this.map.getZoomForExtent(extent);

            var idealResolution = Math.max(
                extent.getWidth() / viewSize.w,
                extent.getHeight() / viewSize.h
            );
            var resolution = this.map.getResolutionForZoom(zoom);
            // the closer to the ideal resolution, the better the fit
            var diff = Math.abs(idealResolution - resolution);
            if (!(zoom in scalesByZoom) || scalesByZoom[zoom].diff > diff) {
                scalesByZoom[zoom] = {
                    rec: rec,
                    diff: diff
                };
                zooms.indexOf(zoom) == -1 && zooms.push(zoom);
            }
        }, this);

        // add only the preview scales that closely fit print extents
        for (var i=0, ii=zooms.length; i<ii; ++i) {
            this.previewScales.add(scalesByZoom[zooms[i]].rec);
        }

        scale && this.printPage.setScale(scale);
        this.printPage.resumeEvents();

        if (scale && this.previewScales.getCount() > 0) {
            var maxScale = this.previewScales.getAt(0);
            var minScale = this.previewScales.getAt(this.previewScales.getCount()-1);
            if (scale.get("value") < minScale.get("value")) {
                this.printPage.setScale(minScale);
            } else if (scale.get("value") > maxScale.get("value")) {
                this.printPage.setScale(maxScale);
            }
        }

        this.fitZoom();
    },

    /**
     * Convenience method for printing the map, without the need to
     *  interact with the printProvider and printPage.
     *
     * @param {Object} options options for
     *  the {@link GeoExt.data.PrintProvider#method-print print method}.
     *
     */
    print: function(options) {
        this.printProvider.print(this.map, [this.printPage], options);
    },

    /**
     * @private
     */
    beforeDestroy: function() {
        this.map.events.unregister("moveend", this, this.updatePage);
        this.printPage.un("change", this.fitZoom, this);
        this.printProvider.un("layoutchange", this.syncSize, this);

        this.callParent(arguments);
    }
});
<commit_msg>Fixup merge conflict markers<commit_after>/*
 * Copyright (c) 2008-2012 The Open Source Geospatial Foundation
 *
 * Published under the BSD license.
 * See https://github.com/geoext/geoext2/blob/master/license.txt for the full text
 * of the license.
 */

/**
 * @class GeoExt.panel.PrintMap
 *
 * A map panel that controls scale and center of a print page. Based on the
 *  current view (i.e. layers and extent) of a source map, this panel will be
 *  sized according to the aspect ratio of the print page. As the user zooms
 *  and pans in the :class:`GeoExt.PrintMapPanel`, the print page will update
 *  its scale and center accordingly. If the scale on the print page changes
 *  (e.g. by setting it using a combo box with a
 *  {@link GeoExt.plugins.PrintPageField}), the extent of the
 *  {@link GeoExt.PrintMapPanel} will be updated to match the page bounds.
 *
 *      The #zoom, #center and #extent config options will have
 *      no affect, as they will be determined by the #sourceMap.
 *
 *
 *  A map with a "Print..." button. If clicked, a dialog containing a
 *  PrintMapPanel will open, with a "Create PDF" button.
 *
 * Example:

var mapPanel = new GeoExt.MapPanel({
    renderTo: "map",
    layers: [new OpenLayers.Layer.WMS("Tasmania State Boundaries",
        "http://demo.opengeo.org/geoserver/wms",
        {layers: "topp:tasmania_state_boundaries"}, {singleTile: true})],
    center: [146.56, -41.56],
    zoom: 6,
    bbar: [{
        text: "Print...",
        handler: function() {
            var printDialog = new Ext.Window({
                autoHeight: true,
                width: 350,
                items: [new GeoExt.PrintMapPanel({
                    sourceMap: mapPanel,
                    printProvider: {
                        capabilities: printCapabilities
                    }
                })],
                bbar: [{
                    text: "Create PDF",
                    handler: function() {
                        printDialog.items.get(0).print();
                    }
                }]
            });
            printDialog.show();
        }
    }]
});

 */
Ext.define('GeoExt.panel.PrintMap', {
    extend : 'GeoExt.panel.Map',
    requires: ['GeoExt.data.PrintPage'],
    alias : 'widget.gx_printmappanel',
    alternateClassName : 'GeoExt.PrintMapPanel',

    /**
     * @cfg {Object} map
     * Optional configuration for the `OpenLayers.Map` object
     *  that this PrintMapPanel creates. Useful e.g. to configure a map with a
     *  custom set of controls, or to add a `preaddlayer` listener for
     *  filtering out layer types that cannot be printed.
     */

    /**
     * @cfg {GeoExt.MapPanel/OpenLayers.Map} sourceMap
     * The map that is to be printed.
     */

    /**
     * @private
     * @property {OpenLayers.Map} sourceMap
     */
    sourceMap: null,

    /**
     * @cfg {GeoExt.data.PrintProvider/Object} printProvider
     * PrintProvider to use for printing. If an `Object` is provided, a new PrintProvider will
     *  be created and configured with the object.
     *
     *    The PrintMapPanel requires the printProvider's capabilities
     *    to be available upon initialization. This means that a PrintMapPanel
     *    configured with an `Object` as `printProvider` will only work
     *    when `capabilities` is provided in the printProvider's
     *    configuration object. If `printProvider` is provided as an instance
     *    of :class:`GeoExt.data.PrintProvider`, the capabilities must be
     *    loaded before PrintMapPanel initialization.
     */

    /**
     * @property {GeoExt.data.PrintProvider} printProvider
     * PrintProvider for this PrintMapPanel.
     */
    printProvider: null,

    /**
     * @property {GeoExt.data.PrintPage} printPage
     * PrintPage for this PrintMapPanel.
     *  Read-only.
     */
    printPage: null,

    /**
     * @cfg {Boolean} limitScales
     * If set to true, the printPage cannot be set to scales that
     *  would generate a preview in this {@link GeoExt.PrintMapPanel} with a
     *  completely different extent than the one that would appear on the
     *  printed map. Default is false.
     */

    /**
     * @property {Ext.data.Store} previewScales
     * A data store with a subset of the printProvider's
     *  scales. By default, this contains all the scales of the printProvider.
     *  If `limitScales` is set to true, it will only contain print scales
     *  that can properly be previewed with this :class:`GeoExt.PrintMapPanel`.
     */
    previewScales: null,

    /**
     * @cfg {OpenLayers.LonLat/Number[]} center
     * A location for the map center.
     * Do not set, as this will be overridden with the `sourceMap`
     *  center.
     */
    center: null,

    /**
     * @cfg {Number} zoom
     * An initial zoom level for the map. Do not set, because the
     *  initial extent will be determined by the `sourceMap`.
     */
    zoom: null,

    /**
     * @cfg {OpenLayers.Bounds/Number[]} extent
     * An initial extent for the map.
     *  Do not set, because the initial extent will be determined by the
     *  `sourceMap`.
     */
    extent: null,

    /**
     * @private
     * @property {Number} currentZoom
     */
    currentZoom: null,

    /**
     * @private
     */
    initComponent: function() {
        if(this.sourceMap instanceof GeoExt.MapPanel) {
            this.sourceMap = this.sourceMap.map;
        }

        if (!this.map) {
            this.map = {};
        }

        Ext.applyIf(this.map, {
            projection: this.sourceMap.getProjection(),
            maxExtent: this.sourceMap.getMaxExtent(),
            maxResolution: this.sourceMap.getMaxResolution(),
            units: this.sourceMap.getUnits()
        });

        if(!(this.printProvider instanceof GeoExt.data.PrintProvider)) {
            this.printProvider = Ext.create('GeoExt.data.PrintProvider',
                this.printProvider);
        }
        this.printPage = Ext.create('GeoExt.data.PrintPage', {
            printProvider: this.printProvider
        });

        this.previewScales = Ext.create('Ext.data.Store', {
            fields: [
                 {name: 'name', type: 'string'},
                 {name: 'value', type: 'int'}
            ],
            data: this.printProvider.scales.getRange()
        });

        this.layers = [];
        var layer;
        Ext.each(this.sourceMap.layers, function(layer) {
            if (layer.getVisibility() === true) {
                if (layer instanceof OpenLayers.Layer.Vector) {
                    var features = layer.features,
                        clonedFeatures = new Array(features.length),
                        vector = new OpenLayers.Layer.Vector(layer.name);
                    for (var i=0, ii=features.length; i<ii; ++i) {
                        clonedFeatures[i] = features[i].clone();
                    }
                    vector.addFeatures(clonedFeatures, {silent: true});
                    this.layers.push(vector);
                } else {
                    this.layers.push(layer.clone());
                }
            }
        }, this);

        this.extent = this.sourceMap.getExtent();

        this.callParent(arguments);
    },

    /**
     * Calls the internal adjustSize-function and resizes
     * this {@link GeoExt.panel.PrintMap PrintMapPanel} due
     * to the needed size, defined by the current layout of the #printProvider.
     *
     * The Function was removed from Ext.Panel in ExtJS 4 and is
     * now implemented here.
     *
     * @private
     *
     */
    syncSize: function() {
        var s = this.adjustSize(this.map.size.w, this.map.size.h);
        this.setSize(s.width, s.height);
    },

    /**
     * @private
     */
    bind: function() {

        // we have to call syncSize here because of changed
        // rendering order in ExtJS4
        this.syncSize();

        this.printPage.on("change", this.fitZoom, this);
        this.printProvider.on("layoutchange", this.syncSize, this);
        this.map.events.register("moveend", this, this.updatePage);

        this.printPage.fit(this.sourceMap);

        if (this.initialConfig.limitScales === true) {
            this.on("resize", this.calculatePreviewScales, this);
            this.calculatePreviewScales();
        }
    },

    /**
     * Private method called after the panel has been rendered.
     *
     * @private
     */
    afterRender: function() {

        this.callParent(arguments);
        this.doComponentLayout();
        if (!this.ownerCt) {
            this.bind();
        } else {
            this.ownerCt.on({
                "afterlayout": {
                    fn: this.bind,
                    scope: this,
                    single: true
                }
            });
        }
    },

    /**
     * Private override - sizing this component always takes the aspect ratio
     *  of the print page into account.
     *
     * @private
     * @param {Number} width If not provided or 0, initialConfig.width will
     *  be used.
     * @param {Number} height If not provided or 0, initialConfig.height
     *  will be used.
     */
    adjustSize: function(width, height) {
        var printSize = this.printProvider.layout.get("size");
        var ratio = printSize.width / printSize.height;
        // respect width & height when sizing according to the print page's
        // aspect ratio - do not exceed either, but don't take values for
        // granted if container is configured with autoWidth or autoHeight.
        var ownerCt = this.ownerCt;
        var targetWidth = (ownerCt && ownerCt.autoWidth) ? 0 :
            (width || this.initialConfig.width);
        var targetHeight = (ownerCt && ownerCt.autoHeight) ? 0 :
            (height || this.initialConfig.height);
        if (targetWidth) {
            height = targetWidth / ratio;
            if (targetHeight && height > targetHeight) {
                height = targetHeight;
                width = height * ratio;
            } else {
                width = targetWidth;
            }
        } else if (targetHeight) {
            width = targetHeight * ratio;
            height = targetHeight;
        }

        return {width: width, height: height};
    },

    /**
     *  Fits this PrintMapPanel's zoom to the print scale.
     *
     *  @private
     */
    fitZoom: function() {
        if (!this._updating && this.printPage.scale) {
            this._updating = true;
            var printBounds = this.printPage.getPrintExtent(this.map);
            this.currentZoom = this.map.getZoomForExtent(printBounds);
            this.map.zoomToExtent(printBounds, false);

            delete this._updating;
        }
    },

    /**
     * Updates the print page to match this PrintMapPanel's center and scale.
     *
     * @private
     */
    updatePage: function() {
        if (!this._updating) {
            var zoom = this.map.getZoom();
            this._updating = true;
            if (zoom === this.currentZoom) {
                this.printPage.setCenter(this.map.getCenter());
            } else {
                this.printPage.fit(this.map);
            }
            delete this._updating;
            this.currentZoom = zoom;
        }
    },

    /**
     * @private
     */
    calculatePreviewScales: function() {
        this.previewScales.removeAll();

        this.printPage.suspendEvents();
        var scale = this.printPage.scale;

        // group print scales by the zoom level they would be previewed at
        var viewSize = this.map.getSize();
        var scalesByZoom = {};
        var zooms = [];
        this.printProvider.scales.each(function(rec) {
            this.printPage.setScale(rec);
            var extent = this.printPage.getPrintExtent(this.map);
            var zoom = this.map.getZoomForExtent(extent);

            var idealResolution = Math.max(
                extent.getWidth() / viewSize.w,
                extent.getHeight() / viewSize.h
            );
            var resolution = this.map.getResolutionForZoom(zoom);
            // the closer to the ideal resolution, the better the fit
            var diff = Math.abs(idealResolution - resolution);
            if (!(zoom in scalesByZoom) || scalesByZoom[zoom].diff > diff) {
                scalesByZoom[zoom] = {
                    rec: rec,
                    diff: diff
                };
                zooms.indexOf(zoom) == -1 && zooms.push(zoom);
            }
        }, this);

        // add only the preview scales that closely fit print extents
        for (var i=0, ii=zooms.length; i<ii; ++i) {
            this.previewScales.add(scalesByZoom[zooms[i]].rec);
        }

        scale && this.printPage.setScale(scale);
        this.printPage.resumeEvents();

        if (scale && this.previewScales.getCount() > 0) {
            var maxScale = this.previewScales.getAt(0);
            var minScale = this.previewScales.getAt(this.previewScales.getCount()-1);
            if (scale.get("value") < minScale.get("value")) {
                this.printPage.setScale(minScale);
            } else if (scale.get("value") > maxScale.get("value")) {
                this.printPage.setScale(maxScale);
            }
        }

        this.fitZoom();
    },

    /**
     * Convenience method for printing the map, without the need to
     *  interact with the printProvider and printPage.
     *
     * @param {Object} options options for
     *  the {@link GeoExt.data.PrintProvider#method-print print method}.
     *
     */
    print: function(options) {
        this.printProvider.print(this.map, [this.printPage], options);
    },

    /**
     * @private
     */
    beforeDestroy: function() {
        this.map.events.unregister("moveend", this, this.updatePage);
        this.printPage.un("change", this.fitZoom, this);
        this.printProvider.un("layoutchange", this.syncSize, this);

        this.callParent(arguments);
    }
});
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008-2013 The Open Source Geospatial Foundation
 *
 * Published under the BSD license.
 * See https://github.com/geoext/geoext2/blob/master/license.txt for the full
 * text of the license.
 */

/**
 * The LayerNode plugin. This is used to create a node that is connected to
 * a layer, so the checkbox and the layer's visibility are in sync. A basic
 * layer node would be configured like this:
 *     {plugins: ['gx_layernode'], layer: myLayer}
 *
 * See GeoExt.data.LayerTreeModel for more details on GeoExt extensions to the
 * node configuration.
 */
Ext.define('GeoExt.tree.LayerNode', {
    extend: 'Ext.AbstractPlugin',
    alias: 'plugin.gx_layer',

    /**
     * @private
     * The init method is invoked after initComponent method has been run for
     * the client Component.
     *
     * It perform plugin initialization.
     * @param {Ext.Component} target The client Component which owns this plugin.
     */
    init: function(target) {

        this.target = target;
        var layer = target.get('layer');

        target.set('checked', layer.getVisibility());
        if (!target.get('checkedGroup') && layer.isBaseLayer) {
            target.set('checkedGroup', 'gx_baselayer');
        }
        target.set('fixedText', !!target.text);

        target.set('leaf', true);

        if(!target.get('iconCls')) {
            target.set('iconCls', "gx-tree-layer-icon");
        }

        target.on('afteredit', this.onAfterEdit, this);
        layer.events.on({
            "visibilitychanged": this.onLayerVisibilityChanged,
            scope: this
        });
    },

    /**
     * @private
     * Handler for the node's afteredit event.
     *
     * @param {GeoExt.data.LayerTreeModel} node
     * @param {String[]} modifiedFields
     */
    onAfterEdit: function(node, modifiedFields) {
        var me = this;

        if(~Ext.Array.indexOf(modifiedFields, 'checked')) {
            me.onCheckChange();
        }
    },

    /**
     * @private
     * Handler for visibilitychanged events on the layer
     */
    onLayerVisibilityChanged: function() {
        if(!this._visibilityChanging) {
            this.target.set('checked', this.target.get('layer').getVisibility());
        }
    },

    /**
     * @private
     * Updates the visibility of the layer that is connected to the target
     * node.
     */
    onCheckChange: function() {
        var node = this.target,
            checked = this.target.get('checked');

        if(checked != node.get('layer').getVisibility()) {
            node._visibilityChanging = true;
            var layer = node.get('layer');
            if(checked && layer.isBaseLayer && layer.map) {
                layer.map.setBaseLayer(layer);
            } else if(!checked && layer.isBaseLayer && layer.map &&
                      layer.map.baseLayer && layer.id == layer.map.baseLayer.id) {
                // Must prevent the unchecking of radio buttons
                this.target.set('checked', this.target.get('layer').getVisibility());
            } else {
                layer.setVisibility(checked);
            }
            delete node._visibilityChanging;
        }
    }

});
<commit_msg>replace this.target by node and layer in onCheckChange<commit_after>/*
 * Copyright (c) 2008-2013 The Open Source Geospatial Foundation
 *
 * Published under the BSD license.
 * See https://github.com/geoext/geoext2/blob/master/license.txt for the full
 * text of the license.
 */

/**
 * The LayerNode plugin. This is used to create a node that is connected to
 * a layer, so the checkbox and the layer's visibility are in sync. A basic
 * layer node would be configured like this:
 *     {plugins: ['gx_layernode'], layer: myLayer}
 *
 * See GeoExt.data.LayerTreeModel for more details on GeoExt extensions to the
 * node configuration.
 */
Ext.define('GeoExt.tree.LayerNode', {
    extend: 'Ext.AbstractPlugin',
    alias: 'plugin.gx_layer',

    /**
     * @private
     * The init method is invoked after initComponent method has been run for
     * the client Component.
     *
     * It perform plugin initialization.
     * @param {Ext.Component} target The client Component which owns this plugin.
     */
    init: function(target) {

        this.target = target;
        var layer = target.get('layer');

        target.set('checked', layer.getVisibility());
        if (!target.get('checkedGroup') && layer.isBaseLayer) {
            target.set('checkedGroup', 'gx_baselayer');
        }
        target.set('fixedText', !!target.text);

        target.set('leaf', true);

        if(!target.get('iconCls')) {
            target.set('iconCls', "gx-tree-layer-icon");
        }

        target.on('afteredit', this.onAfterEdit, this);
        layer.events.on({
            "visibilitychanged": this.onLayerVisibilityChanged,
            scope: this
        });
    },

    /**
     * @private
     * Handler for the node's afteredit event.
     *
     * @param {GeoExt.data.LayerTreeModel} node
     * @param {String[]} modifiedFields
     */
    onAfterEdit: function(node, modifiedFields) {
        var me = this;

        if(~Ext.Array.indexOf(modifiedFields, 'checked')) {
            me.onCheckChange();
        }
    },

    /**
     * @private
     * Handler for visibilitychanged events on the layer
     */
    onLayerVisibilityChanged: function() {
        if(!this._visibilityChanging) {
            this.target.set('checked', this.target.get('layer').getVisibility());
        }
    },

    /**
     * @private
     * Updates the visibility of the layer that is connected to the target
     * node.
     */
    onCheckChange: function() {
        var node = this.target,
            checked = this.target.get('checked');

        if(checked != node.get('layer').getVisibility()) {
            node._visibilityChanging = true;
            var layer = node.get('layer');
            if(checked && layer.isBaseLayer && layer.map) {
                layer.map.setBaseLayer(layer);
            } else if(!checked && layer.isBaseLayer && layer.map &&
                      layer.map.baseLayer && layer.id == layer.map.baseLayer.id) {
                // Must prevent the unchecking of radio buttons
                node.set('checked', layer.getVisibility());
            } else {
                layer.setVisibility(checked);
            }
            delete node._visibilityChanging;
        }
    }

});
<|endoftext|>


<commit_before>import {moduloActividad, actividadTest} from '../../../helpers/actividadTest';

let nombre = "4.1.6";

// No tiene sentido testear, no hay objetivo claro.
/*
moduloActividad(nombre);

actividadTest(nombre, {
	solucion: `<xml xmlns="http://www.w3.org/1999/xhtml">
  <block type="al_empezar_a_ejecutar" id="1" deletable="false" movable="false" editable="false" x="15" y="15">
    <statement name="program">
      <block type="repetir" id="|KneHL[}QuG.8DM_bHtq">
        <value name="count">
          <block type="math_number" id="K/^RF-kMoU2vQeYQdh7-">
            <field name="NUM">5</field>
          </block>
        </value>
        <statement name="block">
          <block type="MoverACasillaDerecha" id="5X41a:-!K0TyfUB~F=H]">
            <next>
              <block type="MoverACasillaAbajo" id="5:_E9$oi#WB(Yxo:MmG7"></block>
            </next>
          </block>
        </statement>
        <next>
          <block type="ComerChurrasco" id="d4y{D[O3OmG$%MA/{qk9"></block>
        </next>
      </block>
    </statement>
  </block>
</xml>`,
});*/
<commit_msg>el fix anterior hice cagada<commit_after>/*
import {moduloActividad, actividadTest} from '../../../helpers/actividadTest';

let nombre = "4.1.6";

// Habría que testear simplemente que carga.

moduloActividad(nombre);

actividadTest(nombre, {
	solucion: `<xml xmlns="http://www.w3.org/1999/xhtml">
  <block type="al_empezar_a_ejecutar" id="1" deletable="false" movable="false" editable="false" x="15" y="15">
    <statement name="program">
      <block type="repetir" id="|KneHL[}QuG.8DM_bHtq">
        <value name="count">
          <block type="math_number" id="K/^RF-kMoU2vQeYQdh7-">
            <field name="NUM">5</field>
          </block>
        </value>
        <statement name="block">
          <block type="MoverACasillaDerecha" id="5X41a:-!K0TyfUB~F=H]">
            <next>
              <block type="MoverACasillaAbajo" id="5:_E9$oi#WB(Yxo:MmG7"></block>
            </next>
          </block>
        </statement>
        <next>
          <block type="ComerChurrasco" id="d4y{D[O3OmG$%MA/{qk9"></block>
        </next>
      </block>
    </statement>
  </block>
</xml>`,
});*/
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/* global capitalizeFirstLetters */

/**
 * Loads the page if the user is logged in. Otherwise, redirects to the
 * login page.
 */
function load() {
  /* global loadPage */
  loadPage(loadReceiptAnalysis);  // From js/common.js.
}

/** Fetches receipt properties from the server and adds them to the page. */
function loadReceiptAnalysis() {
  const receipt = getReceiptFromQueryString();

  // Set the value and max value of the date input field.
  const dateInput = document.getElementById('date-input');
  const today = formatDate(new Date());
  dateInput.value = receipt.date || today;
  dateInput.max = today;

  if (receipt.storeName) {
    document.getElementById('store-input').value = receipt.storeName;
  }
  if (receipt.price) {
    document.getElementById('price-input').value =
        Number(receipt.price).toLocaleString(undefined, {
          maximumFractionDigits: 2,
          currency: 'USD',
          style: 'currency',
          currencyDisplay: 'symbol',
        });
  }
  if (receipt.categories) {
    document.getElementById('categories-input').value = receipt.categories;
  }

  document.getElementById('receipt-image').src = receipt.imageUrl;
}

/**
 * Extracts the receipt properties from the query string.
 * @return {object} The extracted receipt.
 */
function getReceiptFromQueryString() {
  const parameters = new URLSearchParams(location.search);

  const date = formatReceiptProperty('timestamp', getDateFromTimestamp);
  const storeName = formatReceiptProperty('store', capitalizeFirstLetters);
  const price = parameters.get('price');
  const categories = formatReceiptProperty('categories', formatCategories);
  const imageUrl = parameters.get('image-url');

  return {date, storeName, price, categories, imageUrl};
}

/**
 * Extracts the given property from the query string and formats it.
 * @param {string} propertyName The name of the query string property.
 * @param {function(string): *} format A function to format the specified
 *     property.
 * @return {*} The formatted property, or null if the property is not in the
 *     query string.
 */
function formatReceiptProperty(propertyName, format) {
  const parameters = new URLSearchParams(location.search);
  return parameters.has(propertyName) ? format(parameters.get(propertyName)) :
                                        null;
}

/** Converts a timestamp string into the equivalent date string. */
function getDateFromTimestamp(timestamp) {
  const time = parseInt(timestamp);

  // Only return the year, month, and day
  return new Date(time).toISOString().substring(0, 10);
}

/**
 * Capitalizes and adds spaces between the categories.
 * @param {string} categories A comma-separated list of categories
 * @return {string} The formatted list of categories.
 */
function formatCategories(categories) {
  return capitalizeFirstLetters(categories.replace(/,/gi, ', '));
}

/**
 * Converts a date to 'YYYY-MM-DD' format, corresponding to the value attribute
 * of the date input.
 * @param {Date} date The date to convert.
 * @return {string} The formatted date.
 */
function formatDate(date) {
  const day = String(date.getDate()).padStart(2, '0');
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const year = date.getFullYear();
  return `${year}-${month}-${day}`;
}

/** Builds the div element for a category along with its children. */
function buildCategoryElement(category) {
  const categoryElement =
      document.querySelector('#category-template').content.cloneNode(true);
  categoryElement.querySelector('#category-name').innerText = category;

  return categoryElement;
}

/**
 * Sends a request to update the receipt.
 */
async function updateReceipt(event) {
  // Prevent the default action of reloading the page on form submission.
  event.preventDefault();

  document.body.style.cursor = 'wait';
  const saveButton = document.getElementById('submit-receipt');
  const homeButton = document.getElementById('return-home');
  saveButton.disabled = true;
  homeButton.disabled = true;

  const receipt = getReceiptFromForm();
  const editRequest = new URLSearchParams();

  editRequest.append('id', receipt.id);
  editRequest.append('date', receipt.date);
  editRequest.append('store', receipt.store);
  editRequest.append('price', receipt.price);

  createCategoryList(receipt.categories).forEach((category) => {
    editRequest.append('categories', category);
  });

  const response =
      await fetch(`/edit-receipt?${editRequest.toString()}`, {method: 'POST'});

  if (response.status !== 200) {
    const error = await response.text();
    document.body.style.cursor = 'default';
    alert(error);
    saveButton.disabled = false;
    homeButton.disabled = false;
    return;
  }

  const json = await response.json();
  const params = setUrlParameters(json);

  // Restore the cursor after the edit request has loaded.
  document.body.style.cursor = 'default';

  // Remove warning for unsaved changes.
  window.onbeforeunload = null;

  // Update query string with edited fields.
  window.location.replace(`/receipt-analysis.html?${params.toString()}`);
}

/**
 * Gets the receipt properties from the form data.
 * @return {object} The extracted receipt.
 */
function getReceiptFromForm() {
  const id = new URLSearchParams(location.search).get('id');
  const date = document.getElementById('date-input').valueAsNumber;
  const store = document.getElementById('store-input').value;
  const price =
      convertStringToNumber(document.getElementById('price-input').value);
  const categories = document.getElementById('categories-input').value;

  return {id, date, store, price, categories};
}

/** Converts the comma-separated categories string into a list of categories. */
function createCategoryList(categories) {
  return categories.split(',').map((category) => category.trim());
}

/**
 * Creates URL parameters using the properties of the receipt in the given JSON
 * response.
 * @param {object} json The JSON response from the edit servlet.
 * @return {URLSearchParams} The updated URL parameters containing the edited
 *     fields.
 */
function setUrlParameters(json) {
  const receipt = json.propertyMap;
  const params = new URLSearchParams();

  params.append('id', json.key.id);
  params.append('image-url', receipt.imageUrl.value);
  params.append('categories', receipt.categories);
  params.append('price', receipt.price);
  params.append('store', receipt.store);
  params.append('timestamp', receipt.timestamp);
  return params;
}

/**
 * Converts the formatted price back to a number when the user
 * selects the price input.
 */
function convertPricetoValue(event) {
  const value = event.target.value;
  event.target.value = value ? convertStringToNumber(value) : '';
}

/**
 * Converts a string value into a number, removing all non-numeric characters.
 */
function convertStringToNumber(string) {
  return Number(String(string).replace(/[^0-9.]+/g, ''));
}

/**
 * Converts the number inputted by the user to a formatted string when
 * the user unfocuses from the price input.
 */
function formatCurrency(event) {
  const value = event.target.value;

  if (value) {
    event.target.value =
        convertStringToNumber(value).toLocaleString(undefined, {
          maximumFractionDigits: 2,
          currency: 'USD',
          style: 'currency',
          currencyDisplay: 'symbol',
        });
  } else {
    event.target.value = '';
  }
}

/**
 * Redirects the user to the home page when the "Return to Home" button is
 * clicked.
 */
function redirectHome() {
  if (isFormSaved()) {
    // Remove warning for unsaved changes.
    window.onbeforeunload = null;
  } else {
    // Warn user of losing unsaved changes.
    window.onbeforeunload = () => true;
  }

  if (!isReceiptComplete()) {
    alert('Please ensure that all fields are set and have been saved.');
    return;
  }

  window.location.href = '/';
}

/**
 * Checks if there are any unsaved changes.
 * @return {boolean} Whether the form data matches the stored receipt.
 */
function isFormSaved() {
  const savedReceipt = getReceiptFromQueryString();
  const formReceipt = getReceiptFromForm();

  return savedReceipt.date === getDateFromTimestamp(formReceipt.date) &&
      savedReceipt.storeName === formReceipt.store &&
      convertStringToNumber(savedReceipt.price) === formReceipt.price &&
      savedReceipt.categories === formReceipt.categories;
}

/**
 * Checks all receipt fields are saved.
 * @return {boolean} Whether all fields have been set.
 */
function isReceiptComplete() {
  const savedReceipt = getReceiptFromQueryString();

  return savedReceipt.date && savedReceipt.storeName && savedReceipt.price &&
      savedReceipt.categories;
}
<commit_msg>Use toFixed() to format price input.<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/* global capitalizeFirstLetters */

/**
 * Loads the page if the user is logged in. Otherwise, redirects to the
 * login page.
 */
function load() {
  /* global loadPage */
  loadPage(loadReceiptAnalysis);  // From js/common.js.
}

/** Fetches receipt properties from the server and adds them to the page. */
function loadReceiptAnalysis() {
  const receipt = getReceiptFromQueryString();

  // Set the value and max value of the date input field.
  const dateInput = document.getElementById('date-input');
  const today = formatDate(new Date());
  dateInput.value = receipt.date || today;
  dateInput.max = today;

  if (receipt.storeName) {
    document.getElementById('store-input').value = receipt.storeName;
  }
  if (receipt.price) {
    document.getElementById('price-input').value =
        `$${Number(receipt.price).toFixed(2)}`;
  }
  if (receipt.categories) {
    document.getElementById('categories-input').value = receipt.categories;
  }

  document.getElementById('receipt-image').src = receipt.imageUrl;
}

/**
 * Extracts the receipt properties from the query string.
 * @return {object} The extracted receipt.
 */
function getReceiptFromQueryString() {
  const parameters = new URLSearchParams(location.search);

  const date = formatReceiptProperty('timestamp', getDateFromTimestamp);
  const storeName = formatReceiptProperty('store', capitalizeFirstLetters);
  const price = parameters.get('price');
  const categories = formatReceiptProperty('categories', formatCategories);
  const imageUrl = parameters.get('image-url');

  return {date, storeName, price, categories, imageUrl};
}

/**
 * Extracts the given property from the query string and formats it.
 * @param {string} propertyName The name of the query string property.
 * @param {function(string): *} format A function to format the specified
 *     property.
 * @return {*} The formatted property, or null if the property is not in the
 *     query string.
 */
function formatReceiptProperty(propertyName, format) {
  const parameters = new URLSearchParams(location.search);
  return parameters.has(propertyName) ? format(parameters.get(propertyName)) :
                                        null;
}

/** Converts a timestamp string into the equivalent date string. */
function getDateFromTimestamp(timestamp) {
  const time = parseInt(timestamp);

  // Only return the year, month, and day
  return new Date(time).toISOString().substring(0, 10);
}

/**
 * Capitalizes and adds spaces between the categories.
 * @param {string} categories A comma-separated list of categories
 * @return {string} The formatted list of categories.
 */
function formatCategories(categories) {
  return capitalizeFirstLetters(categories.replace(/,/gi, ', '));
}

/**
 * Converts a date to 'YYYY-MM-DD' format, corresponding to the value attribute
 * of the date input.
 * @param {Date} date The date to convert.
 * @return {string} The formatted date.
 */
function formatDate(date) {
  const day = String(date.getDate()).padStart(2, '0');
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const year = date.getFullYear();
  return `${year}-${month}-${day}`;
}

/** Builds the div element for a category along with its children. */
function buildCategoryElement(category) {
  const categoryElement =
      document.querySelector('#category-template').content.cloneNode(true);
  categoryElement.querySelector('#category-name').innerText = category;

  return categoryElement;
}

/**
 * Sends a request to update the receipt.
 */
async function updateReceipt(event) {
  // Prevent the default action of reloading the page on form submission.
  event.preventDefault();

  document.body.style.cursor = 'wait';
  const saveButton = document.getElementById('submit-receipt');
  const homeButton = document.getElementById('return-home');
  saveButton.disabled = true;
  homeButton.disabled = true;

  const receipt = getReceiptFromForm();
  const editRequest = new URLSearchParams();

  editRequest.append('id', receipt.id);
  editRequest.append('date', receipt.date);
  editRequest.append('store', receipt.store);
  editRequest.append('price', receipt.price);

  createCategoryList(receipt.categories).forEach((category) => {
    editRequest.append('categories', category);
  });

  const response =
      await fetch(`/edit-receipt?${editRequest.toString()}`, {method: 'POST'});

  if (response.status !== 200) {
    const error = await response.text();
    document.body.style.cursor = 'default';
    alert(error);
    saveButton.disabled = false;
    homeButton.disabled = false;
    return;
  }

  const json = await response.json();
  const params = setUrlParameters(json);

  // Restore the cursor after the edit request has loaded.
  document.body.style.cursor = 'default';

  // Remove warning for unsaved changes.
  window.onbeforeunload = null;

  // Update query string with edited fields.
  window.location.replace(`/receipt-analysis.html?${params.toString()}`);
}

/**
 * Gets the receipt properties from the form data.
 * @return {object} The extracted receipt.
 */
function getReceiptFromForm() {
  const id = new URLSearchParams(location.search).get('id');
  const date = document.getElementById('date-input').valueAsNumber;
  const store = document.getElementById('store-input').value;
  const price =
      convertStringToNumber(document.getElementById('price-input').value);
  const categories = document.getElementById('categories-input').value;

  return {id, date, store, price, categories};
}

/** Converts the comma-separated categories string into a list of categories. */
function createCategoryList(categories) {
  return categories.split(',').map((category) => category.trim());
}

/**
 * Creates URL parameters using the properties of the receipt in the given JSON
 * response.
 * @param {object} json The JSON response from the edit servlet.
 * @return {URLSearchParams} The updated URL parameters containing the edited
 *     fields.
 */
function setUrlParameters(json) {
  const receipt = json.propertyMap;
  const params = new URLSearchParams();

  params.append('id', json.key.id);
  params.append('image-url', receipt.imageUrl.value);
  params.append('categories', receipt.categories);
  params.append('price', receipt.price);
  params.append('store', receipt.store);
  params.append('timestamp', receipt.timestamp);
  return params;
}

/**
 * Converts the formatted price back to a number when the user
 * selects the price input.
 */
function convertPricetoValue(event) {
  const value = event.target.value;
  event.target.value = value ? convertStringToNumber(value) : '';
}

/**
 * Converts a string value into a number, removing all non-numeric characters.
 */
function convertStringToNumber(string) {
  return Number(String(string).replace(/[^0-9.]+/g, ''));
}

/**
 * Converts the number inputted by the user to a formatted string when
 * the user unfocuses from the price input.
 */
function formatCurrency(event) {
  const value = event.target.value;

  if (value) {
    event.target.value =
        convertStringToNumber(value).toLocaleString(undefined, {
          maximumFractionDigits: 2,
          currency: 'USD',
          style: 'currency',
          currencyDisplay: 'symbol',
        });
  } else {
    event.target.value = '';
  }
}

/**
 * Redirects the user to the home page when the "Return to Home" button is
 * clicked.
 */
function redirectHome() {
  if (isFormSaved()) {
    // Remove warning for unsaved changes.
    window.onbeforeunload = null;
  } else {
    // Warn user of losing unsaved changes.
    window.onbeforeunload = () => true;
  }

  if (!isReceiptComplete()) {
    alert('Please ensure that all fields are set and have been saved.');
    return;
  }

  window.location.href = '/';
}

/**
 * Checks if there are any unsaved changes.
 * @return {boolean} Whether the form data matches the stored receipt.
 */
function isFormSaved() {
  const savedReceipt = getReceiptFromQueryString();
  const formReceipt = getReceiptFromForm();

  return savedReceipt.date === getDateFromTimestamp(formReceipt.date) &&
      savedReceipt.storeName === formReceipt.store &&
      convertStringToNumber(savedReceipt.price) === formReceipt.price &&
      savedReceipt.categories === formReceipt.categories;
}

/**
 * Checks all receipt fields are saved.
 * @return {boolean} Whether all fields have been set.
 */
function isReceiptComplete() {
  const savedReceipt = getReceiptFromQueryString();

  return savedReceipt.date && savedReceipt.storeName && savedReceipt.price &&
      savedReceipt.categories;
}
<|endoftext|>


<commit_before>Ext.define('webglsprint.Main', {
    singleton: true
}, function() {
    /**
     * Main application launch function. To be called after page has finished loading.
     */
    webglsprint.Main.launch = function() {
        //Create a framerate tracker, throw it in the top right
        var stats = new Stats();
        stats.setMode(0); // 0: fps, 1: ms
        stats.domElement.style.position = 'absolute';
        stats.domElement.style.right = '0px';
        stats.domElement.style.top = '0px';
        document.body.appendChild( stats.domElement );

        //Make our request for a lot of boreholes...
        var maxBoreholes = 1000;
        var boreholeId = undefined; //'boreholes.5271';
        webglsprint.boreholes.Loader.getBoreholes(maxBoreholes, boreholeId, function(success, message, boreholes) {
            if (!success) {
                alert('ERROR: ' + message);
                return;
            }

            Ext.get('loading-text').remove();
            alert('Rendering ' + boreholes.length + ' boreholes now.\nTo look around, hold down the mouse and drag. To move the camera, use WASD');
            if (!boreholes.length) {
                return;
            }

            //Just pull a reference the <canvas> element, set it to "full size" in
            //the browser window
            var canvasEl = Ext.get('webgl-sprint-canvas').dom;
            canvasEl.width = window.innerWidth;
            canvasEl.height = window.innerHeight;

            //Create the basic ThreeJS elements
            //See also: http://threejs.org/docs/#Manual/Introduction/Creating_a_scene
            var scene = new THREE.Scene();
            var camera = new THREE.PerspectiveCamera(75, canvasEl.width / canvasEl.height, 0.1, 10000);
            var renderer = new THREE.WebGLRenderer({
                canvas : Ext.get('webgl-sprint-canvas').dom
            });

            //We need to figure out the mean x,y,z values in order to point our camera
            //at something interesting
            var mean = {
                xTotal : 0,
                yTotal : 0,
                zTotal : 0,
                n : 0
            };

            //Iterate over our JSON representation of N boreholes
            for (i = 0; i < boreholes.length; ++i) {
                var points = [];

                for (j = 0; j < boreholes[i].points.length; ++j) {
                    var point = boreholes[i].points[j];

                    mean.xTotal += point.x;
                    mean.yTotal += point.y;
                    mean.zTotal += point.z;
                    mean.n++;

                    points.push(new THREE.Vector3(point.x, point.y, point.z));
                }

                //The tube geometry will divide the points up into a set of n segments
                //with a specified number of points on the radius.
                var segments = Math.ceil(Math.log(points.length) / Math.LN2); //lets decimate according to an arbitrary scale
                var radius = 5;
                var thickness = 0.1; //This doesn't increase/decrease polygons. Just their scale

                var path = new THREE.SplineCurve3(points);
                var geometry = new THREE.TubeGeometry(path, segments, 10, radius, false);
                var material = new THREE.MeshBasicMaterial( { color: Math.floor(Math.random()*16777215), wireframe: true} );
                var tube = new THREE.Mesh(geometry, material);
                scene.add(tube);
            }

            mean.x = mean.xTotal / mean.n;
            mean.y = mean.yTotal / mean.n;
            mean.z = mean.zTotal / mean.n;

            //Just plonk our camera right in the middle of the geometries
            //hopefully it looks roughly in the right direction
            camera.position.x = mean.x;
            camera.position.y = mean.y;
            camera.position.z = mean.z;

            // This is a plugin that makes the camera interactive
            // The user can look with mouse and pan with WASD
            var controls = new THREE.FlyControls( camera );
            controls.movementSpeed = 10;
            controls.domElement = Ext.get('viewport').dom;
            controls.rollSpeed = 0.01;
            controls.autoForward = false;
            controls.dragToLook = true;

            // We need a function that repeatedly loops
            // Drawing updates to our scene based on the current
            // camera position
            var update = function() {
                requestAnimationFrame( update );

                stats.begin();

                controls.update(1);
                renderer.render(scene, camera);

                stats.end();
            };
            update();

            //This is in case the user resizes their browser window
            window.addEventListener('resize', onWindowResize, false );
            function onWindowResize( event ) {
                camera.aspect = window.innerWidth / window.innerHeight;
                renderer.setSize( window.innerWidth, window.innerHeight );
                renderer.render( scene, camera );
            };

            // mouse-right click
            Ext.get('webgl-sprint-canvas').dom.addEventListener('mousedown', onMouseDown, false);
            function onMouseDown(event) {
                console.log('mouse down',  event.button, event.clientX, event.clientY);
                if (event.button == 2) {
                    Ext.create('Ext.window.Window', {
                        title: 'Hello',
                        height: 200,
                        width: 400,
                        layout: 'fit',
                        items: {  // Let's put an empty grid in just to illustrate fit layout
                            xtype: 'grid',
                            border: false,
                            columns: [{header: 'World'}],                 // One header just for show. There's no data,
                            store: Ext.create('Ext.data.ArrayStore', {}) // A dummy empty data store
                        }
                    }).show();
                }
            };

        });
    }
});<commit_msg>Working right-click selection<commit_after>Ext.define('webglsprint.Main', {
    singleton: true
}, function() {
    /**
     * Main application launch function. To be called after page has finished loading.
     */
    webglsprint.Main.launch = function() {
        //Create a framerate tracker, throw it in the top right
        var stats = new Stats();
        stats.setMode(0); // 0: fps, 1: ms
        stats.domElement.style.position = 'absolute';
        stats.domElement.style.right = '0px';
        stats.domElement.style.top = '0px';
        document.body.appendChild( stats.domElement );

        var projector = new THREE.Projector();
        var raycaster = new THREE.Raycaster();

        //Make our request for a lot of boreholes...
        var maxBoreholes = 1000;
        var boreholeId = undefined; //'boreholes.5271';
        webglsprint.boreholes.Loader.getBoreholes(maxBoreholes, boreholeId, function(success, message, boreholes) {
            if (!success) {
                alert('ERROR: ' + message);
                return;
            }

            Ext.get('loading-text').remove();
            alert('Rendering ' + boreholes.length + ' boreholes now.\nTo look around, hold down the mouse and drag. To move the camera, use WASD');
            if (!boreholes.length) {
                return;
            }

            //Just pull a reference the <canvas> element, set it to "full size" in
            //the browser window
            var canvasEl = Ext.get('webgl-sprint-canvas').dom;
            canvasEl.width = window.innerWidth;
            canvasEl.height = window.innerHeight;

            //Create the basic ThreeJS elements
            //See also: http://threejs.org/docs/#Manual/Introduction/Creating_a_scene
            var scene = new THREE.Scene();
            var camera = new THREE.PerspectiveCamera(75, canvasEl.width / canvasEl.height, 0.1, 10000);
            var renderer = new THREE.WebGLRenderer({
                canvas : Ext.get('webgl-sprint-canvas').dom
            });

            //We need to figure out the mean x,y,z values in order to point our camera
            //at something interesting
            var mean = {
                xTotal : 0,
                yTotal : 0,
                zTotal : 0,
                n : 0
            };

            //Iterate over our JSON representation of N boreholes
            for (i = 0; i < boreholes.length; ++i) {
                var points = [];

                for (j = 0; j < boreholes[i].points.length; ++j) {
                    var point = boreholes[i].points[j];

                    mean.xTotal += point.x;
                    mean.yTotal += point.y;
                    mean.zTotal += point.z;
                    mean.n++;

                    points.push(new THREE.Vector3(point.x, point.y, point.z));
                }

                //The tube geometry will divide the points up into a set of n segments
                //with a specified number of points on the radius.
                var segments = Math.ceil(Math.log(points.length) / Math.LN2); //lets decimate according to an arbitrary scale
                var radius = 5;
                var thickness = 0.1; //This doesn't increase/decrease polygons. Just their scale

                var path = new THREE.SplineCurve3(points);
                var geometry = new THREE.TubeGeometry(path, segments, 10, radius, false);
                var material = new THREE.MeshBasicMaterial( { color: Math.floor(Math.random()*16777215), wireframe: true} );
                var tube = new THREE.Mesh(geometry, material);
                scene.add(tube);
            }

            mean.x = mean.xTotal / mean.n;
            mean.y = mean.yTotal / mean.n;
            mean.z = mean.zTotal / mean.n;

            //Just plonk our camera right in the middle of the geometries
            //hopefully it looks roughly in the right direction
            camera.position.x = mean.x;
            camera.position.y = mean.y;
            camera.position.z = mean.z;

            // This is a plugin that makes the camera interactive
            // The user can look with mouse and pan with WASD
            var controls = new THREE.FlyControls( camera );
            controls.movementSpeed = 10;
            controls.domElement = Ext.get('viewport').dom;
            controls.rollSpeed = 0.01;
            controls.autoForward = false;
            controls.dragToLook = true;

            // We need a function that repeatedly loops
            // Drawing updates to our scene based on the current
            // camera position
            var update = function() {
                requestAnimationFrame( update );

                stats.begin();

                controls.update(1);
                renderer.render(scene, camera);

                stats.end();
            };
            update();

            //This is in case the user resizes their browser window
            window.addEventListener('resize', onWindowResize, false );
            function onWindowResize( event ) {
                camera.aspect = window.innerWidth / window.innerHeight;
                renderer.setSize( window.innerWidth, window.innerHeight );
                renderer.render( scene, camera );
            };

            // mouse-right click
            Ext.get('webgl-sprint-canvas').dom.addEventListener('mousedown', onMouseDown, false);
            function onMouseDown(event) {
                console.log('mouse down',  event.button, event.clientX, event.clientY);
                if (event.button == 2) {
                    var x = ( event.clientX / window.innerWidth ) * 2 - 1;
                    var y = - ( event.clientY / window.innerHeight ) * 2 + 1;
                    var vector = new THREE.Vector3(x, y, 1);
                    projector.unprojectVector(vector, camera);
                    raycaster.set(camera.position, vector.sub(camera.position).normalize());
                    var intersects = raycaster.intersectObjects(scene.children);
                    if ( intersects.length > 0 ) {
                        // intersects[0].object
                        Ext.create('Ext.window.Window', {
                            title: 'Hello',
                            height: 200,
                            width: 400,
                            layout: 'fit',
                            items: {
                                xtype: 'textfield',
                                fieldLabel: '' + event.clientX + ' ' + event.clientY
                            }
                        }).show();
                    }
                }
            };

        });
    }
});<|endoftext|>


<commit_before>import React from 'react';
import {ReverseLink} from 'react-router-reverse';

export class AddonListing extends React.Component {
  static propTypes = {
    addons: React.PropTypes.array.isRequired,
    isReview: React.PropTypes.bool,
    publish: React.PropTypes.func,
    reject: React.PropTypes.func,
  };
  render() {
    return (

        {this.props.addons.map(addon =>

            <Addon {...this.props} {...addon}
                   isReviewListing={this.props.isReview}/>

        )}
        {this.props.addons.length === 0 &&
No add-ons.
}

    );
  }
}

export class Addon extends React.Component {
  static PropTypes = {
    name: React.PropTypes.string.isRequired,
    slug: React.PropTypes.string.isRequired,
    status: React.PropTypes.string.isRequired,
    version: React.PropTypes.string.isRequired,

    isReview: React.PropTypes.bool,
    isReviewListing: React.PropTypes.bool,

    isPublishing: React.PropTypes.bool,
    isRejecting: React.PropTypes.bool,

    publish: React.PropTypes.func,
    reject: React.PropTypes.func,
  };

  publish = () => {
    this.props.publish(this.props.slug);
  }

  reject = () => {
    this.props.reject(this.props.slug);
  }

  renderName() {
    if (this.props.isReviewListing) {
      return (
        <ReverseLink to="addon-review-detail"
                     params={{slug: this.props.slug}}>

{this.props.name}

        </ReverseLink>
      );
    }
    return
{this.props.name}

  }

  isButtonDisabled() {
    return this.props.isPublishing || this.props.isRejecting;
  }

  render() {
    return (

          {this.renderName()}

Slug

{this.props.slug}

Status

{this.props.status}

Version

{this.props.version}

        {this.props.isReview &&

            <button onClick={this.reject} disabled={this.isButtonDisabled()}>
              {this.props.isRejecting ? 'Rejecting...' : 'Reject'}
            </button>
            <button onClick={this.publish} disabled={this.isButtonDisabled()}>
              {this.props.isPublishing ? 'Publishing...' : 'Publish'}
            </button>

        }

    );
  }
}
<commit_msg>add download/manifest url links<commit_after>import React from 'react';
import {ReverseLink} from 'react-router-reverse';

export class AddonListing extends React.Component {
  static propTypes = {
    addons: React.PropTypes.array.isRequired,
    isReview: React.PropTypes.bool,
    publish: React.PropTypes.func,
    reject: React.PropTypes.func,
  };

  render() {
    return (

        {this.props.addons.map(addon =>

            <Addon {...this.props} {...addon}
                   isReviewListing={this.props.isReview}/>

        )}
        {this.props.addons.length === 0 &&
No add-ons.
}

    );
  }
}

export class Addon extends React.Component {
  static PropTypes = {
    download_url: React.PropTypes.string.isRequired,
    manifest_url: React.PropTypes.string.isRequired,
    name: React.PropTypes.string.isRequired,
    slug: React.PropTypes.string.isRequired,
    status: React.PropTypes.string.isRequired,
    version: React.PropTypes.string.isRequired,

    isReview: React.PropTypes.bool,
    isReviewListing: React.PropTypes.bool,
    isPublishing: React.PropTypes.bool,
    isRejecting: React.PropTypes.bool,
    publish: React.PropTypes.func,
    reject: React.PropTypes.func,
  };

  publish = () => {
    this.props.publish(this.props.slug);
  }

  reject = () => {
    this.props.reject(this.props.slug);
  }

  renderName() {
    if (this.props.isReviewListing) {
      return (
        <ReverseLink to="addon-review-detail"
                     params={{slug: this.props.slug}}>

{this.props.name}

        </ReverseLink>
      );
    }
    return
{this.props.name}

  }

  render() {
    const disabled = this.props.isPublishing || this.props.isRejecting;

    return (

          {this.renderName()}

Files

              Download {this.props.name} .zip

Manifest

              Download {this.props.name} manifest

Slug

{this.props.slug}

Status

{this.props.status}

Version

{this.props.version}

        {this.props.isReview &&

            <button onClick={this.reject} disabled={disabled}>
              {this.props.isRejecting ? 'Rejecting...' : 'Reject'}
            </button>
            <button onClick={this.publish} disabled={disabled}>
              {this.props.isPublishing ? 'Publishing...' : 'Publish'}
            </button>

        }

    );
  }
}
<|endoftext|>


<commit_before>import * as Response from './response';
import { QUESTION_TYPE_ENUM } from 'constants/pogues-constants';

export function stateToModel(
  state,
  collectedVariables,
  collectedVariablesStore,
  type,
) {
  let collectedVariablesFinal = collectedVariables;
  if(type == 'MULTIPLE_CHOICE' || type == 'TABLE') {
    collectedVariablesFinal.map(collected=> {
      const find = Object.values(collectedVariablesStore).find(variable=> variable.id == collected);
      if(find && find.type == 'TEXT' && !find.x) {
        collectedVariablesFinal = collectedVariablesFinal.filter(element => element != find.id)
      }
    })
  }
  const responsesModel = collectedVariablesFinal.map(cv =>
    Response.stateToRemote({ ...state, collectedVariable: cv }),
  );

  let attributeModel = [];

  const mappingModel = responsesModel.map(r => {
    const { x, y, isCollected } = collectedVariablesStore[r.CollectedVariableReference];
    // Table : Fix lines and look into columns
    const MappingTarget =
      type === QUESTION_TYPE_ENUM.MULTIPLE_CHOICE ? `${x}` : `${x} ${y}`;

      if (isCollected === false ) {
        attributeModel.push({
          "AttributeValue": "NoDataByDefinition",
          "AttributeTarget": MappingTarget
        },)
      }
    return { MappingSource: r.id, MappingTarget };
  });

  if (type == 'TABLE') {
    return {
      Response: responsesModel,
      Mapping: mappingModel,
      Attribute: attributeModel,
    }
  } else {
    return {
      Response: responsesModel,
      Mapping: mappingModel,
    }
  };
}<commit_msg>Use constants<commit_after>import * as Response from './response';
import { QUESTION_TYPE_ENUM } from 'constants/pogues-constants';

export function stateToModel(
  state,
  collectedVariables,
  collectedVariablesStore,
  type,
) {
  let collectedVariablesFinal = collectedVariables;
  if(type === QUESTION_TYPE_ENUM.MULTIPLE_CHOICE || type === QUESTION_TYPE_ENUM.TABLE) {
    collectedVariablesFinal.map(collected => {
      const find = Object.values(collectedVariablesStore).find(variable=> variable.id == collected);
      if(find && find.type == 'TEXT' && !find.x) {
        collectedVariablesFinal = collectedVariablesFinal.filter(element => element != find.id)
      }
    })
  }
  const responsesModel = collectedVariablesFinal.map(cv =>
    Response.stateToRemote({ ...state, collectedVariable: cv }),
  );

  let attributeModel = [];

  const mappingModel = responsesModel.map(r => {
    const { x, y, isCollected } = collectedVariablesStore[r.CollectedVariableReference];
    // Table : Fix lines and look into columns
    const MappingTarget =
      type === QUESTION_TYPE_ENUM.MULTIPLE_CHOICE ? `${x}` : `${x} ${y}`;

      if (!isCollected) {
        attributeModel.push({
          "AttributeValue": "NoDataByDefinition",
          "AttributeTarget": MappingTarget
        },)
      }
    return { MappingSource: r.id, MappingTarget };
  });

  if (type === QUESTION_TYPE_ENUM.TABLE) {
    return {
      Response: responsesModel,
      Mapping: mappingModel,
      Attribute: attributeModel,
    }
  } else {
    return {
      Response: responsesModel,
      Mapping: mappingModel,
    }
  };
}<|endoftext|>


<commit_before>angular.module('angular-meteor.settings', [])
  .constant('$angularMeteorSettings', {
    suppressWarnings: false
  });
<commit_msg>feat($angularMeteorSettings): suppress warnings<commit_after>angular.module('angular-meteor.settings', [])
  .constant('$angularMeteorSettings', {
    suppressWarnings: true
  });
<|endoftext|>


<commit_before>AugmentedSzczecin.controller('AddPoiController', ['$scope', '$filter', 'apiService', function($scope, $filter, apiService) {
    $scope.addPoi = function(poi) {
        $scope.newPoi = poi;
        /**
         * Saves checked days of the week as array with their names
         */
        daysMappings = { "monday": "MONDAY", "tuesday":"TUESDAY", "wednesday":"WEDNESDAY", "thursday": "THURSDAY", "friday":"FRIDAY", "saturday":"SATURDAY", "sunday":"SUNDAY"};
        daysList = [];
        for(day in $scope.newPoi['opening']['day']) {
            if ($scope.newPoi['opening']['day'][day]) {
                daysList.push(daysMappings[day]);
            }
        }
        $scope.newPoi.opening.day = daysList;

        /**
         * get time from input and save it as string
         */
        var openTime = Date.parse($scope.newPoi.opening.open);
        openTime = new Date(openTime);
        var openHours = openTime.getHours();
        var openMinutes = openTime.getMinutes();
        $scope.newPoi.opening.open = openHours +':' + openMinutes;

        var closeTime = Date.parse($scope.newPoi.opening.close);
        closeTime = new Date(closeTime);
        var closeHours = closeTime.getHours();
        var closeMinutes = closeTime.getMinutes();
        $scope.newPoi.opening.close = closeHours + ":" + closeMinutes;

        $scope.newPoi = angular.toJson(poi);
        /**
         * post new poi to server
         */
        apiService.addPlace($scope.newPoi);
    };
}]);<commit_msg>[AUGMENTEDSZN-320] save tags in array<commit_after>AugmentedSzczecin.controller('AddPoiController', ['$scope', '$filter', 'apiService', function($scope, $filter, apiService) {
    $scope.addPoi = function(poi) {
        $scope.newPoi = poi;
        /**
         * Saves checked days of the week as array with their names
         */
        daysMappings = { "monday": "MONDAY", "tuesday":"TUESDAY", "wednesday":"WEDNESDAY", "thursday": "THURSDAY", "friday":"FRIDAY", "saturday":"SATURDAY", "sunday":"SUNDAY"};
        daysList = [];
        for(day in $scope.newPoi['opening']['day']) {
            if ($scope.newPoi['opening']['day'][day]) {
                daysList.push(daysMappings[day]);
            }
        }
        $scope.newPoi.opening.day = daysList;

        /**
         * get time from input and save it as string
         */
        var openTime = Date.parse($scope.newPoi.opening.open);
        openTime = new Date(openTime);
        var openHours = openTime.getHours();
        var openMinutes = openTime.getMinutes();
        $scope.newPoi.opening.open = openHours +':' + openMinutes;

        var closeTime = Date.parse($scope.newPoi.opening.close);
        closeTime = new Date(closeTime);
        var closeHours = closeTime.getHours();
        var closeMinutes = closeTime.getMinutes();
        $scope.newPoi.opening.close = closeHours + ":" + closeMinutes;

        tagsList = $scope.newPoi.tags.split(', ');
        $scope.newPoi.tags = tagsList;

        $scope.newPoi = angular.toJson(poi);
        /**
         * post new poi to server
         */
        apiService.addPlace($scope.newPoi);
    };
}]);<|endoftext|>


<commit_before><commit_msg>Fixed FAB transition<commit_after><|endoftext|>


<commit_before>export const polyfill = (() => {
	let clock = Date.now()

	return callback => {
		const currentTime = Date.now()
		if (currentTime - clock > 16) {
			clock = currentTime
			callback(currentTime)
		} else {
			setTimeout(() => polyfill(callback), 0)
		}
	}
})()

// prettier-ignore
export const requestAnimationFrame =
		window.requestAnimationFrame
	|| window.webkitRequestAnimationFrame
	|| window.mozRequestAnimationFrame
	|| polyfill
<commit_msg>remove prettier ignore<commit_after>export const polyfill = (() => {
	let clock = Date.now()

	return callback => {
		const currentTime = Date.now()
		if (currentTime - clock > 16) {
			clock = currentTime
			callback(currentTime)
		} else {
			setTimeout(() => polyfill(callback), 0)
		}
	}
})()

export const requestAnimationFrame =
	window.requestAnimationFrame ||
	window.webkitRequestAnimationFrame ||
	window.mozRequestAnimationFrame ||
	polyfill
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngInject
 */
var UserRegisterController = function ($scope, $http, $location, $routeParams, npolarApiConfig, NpolarApiMessage, User, base64) {
  const registrationUri = "https://"+npolarApiConfig.base.split("//")[1]+"/user/register";
  const confirmationUri = "https://"+npolarApiConfig.base.split("//")[1]+"/user/confirm";
  const captchaUri = "https://api.npolar.no/_captcha";

  $scope.captcha = {
	uuid: null,
	src: "//:0",
	string: ""
  };

  $scope.resource = User;
  $scope.user = { link: `https://${window.location.host}/user/confirm` };

  $scope.compare = function(user) {
    if (user.password2 !== undefined) {
      if (user.password !== user.password2) {
        $scope.pwdStyle = { color: "rgb(215,10,83)", "border-color": "rgb(215,10,83)" };
      } else {
        $scope.pwdStyle = { color: "rgb(34,139,34)", "border-color": "rgb(34,139,34)" };
      }

      if (user.password2 === "") {
        $scope.pwdStyle={};
      }
    }
  };

  $scope.register = function(user) {
    if (user.password !== user.password2) {
      NpolarApiMessage.emit("npolar-api-error", "Password mismatch! Please enter the same password twice.");
    } else {
      $scope.user = user;
      $http({
        method: "POST",
        url: registrationUri,
        data: $scope.user,
        headers: {
          "Authorization": "Sicas " + base64.encode($scope.captcha.uuid + ":" + $scope.captcha.string)
        }
      }).then(function success() {
        NpolarApiMessage.emit("npolar-info", "You should receive a confirmation mail in a short while");
        $location.path(".");
      }, function error(res) {
        NpolarApiMessage.emit("npolar-api-error", (typeof res.data === "object" && res.data && res.data.error ? res.data.error : "Registration failed"));
      });
    }
  };

  $scope.confirm = function(id) {
      $http({
        method: "GET",
        url: confirmationUri+'/'+$routeParams.id
      }).then(function success() {
        NpolarApiMessage.emit("npolar-info", "Confirmation successful. You can now login with your new account");
        $location.path(".");
      }, function error() {
        NpolarApiMessage.emit("npolar-api-error", "Confirmation failed");
      });
  };

  if($scope.captcha) {
    ($scope.captcha.renew = function() {
      $http({
        method: "GET",
        url: captchaUri + "/?width=100&height=50&time=" + Date.now()
      }).then(function(response) {
        $scope.captcha.src = captchaUri + response.data.path;
        $scope.captcha.uuid = response.data.uuid;
        $scope.captcha.string = "";
      });
    }());
  }

  $scope.valid = function() {
    return (!$scope.captcha || $scope.captcha.string) && $scope.user.email && $scope.user.name && $scope.user.password && ($scope.user.password === $scope.user.password2);
  };
};

module.exports = UserRegisterController;
<commit_msg>Work on error handling<commit_after>'use strict';

/**
 * @ngInject
 */
var UserRegisterController = function ($scope, $http, $location, $routeParams, npolarApiConfig, NpolarApiMessage, User, base64) {
  const registrationUri = "https://"+npolarApiConfig.base.split("//")[1]+"/user/register";
  const confirmationUri = "https://"+npolarApiConfig.base.split("//")[1]+"/user/confirm";
  const captchaUri = "https://api.npolar.no/_captcha";

  $scope.captcha = {
	uuid: null,
	src: "//:0",
	string: ""
  };

  $scope.resource = User;
  $scope.user = { link: `https://${window.location.host}/user/confirm` };

  $scope.compare = function(user) {
    if (user.password2 !== undefined) {
      if (user.password !== user.password2) {
        $scope.pwdStyle = { color: "rgb(215,10,83)", "border-color": "rgb(215,10,83)" };
      } else {
        $scope.pwdStyle = { color: "rgb(34,139,34)", "border-color": "rgb(34,139,34)" };
      }

      if (user.password2 === "") {
        $scope.pwdStyle={};
      }
    }
  };

  $scope.register = function(user) {
    if (user.password !== user.password2) {
      NpolarApiMessage.emit("npolar-error", "Password mismatch! Please enter the same password twice.");
    } else {
      $scope.user = user;
      $http({
        method: "POST",
        url: registrationUri,
        data: $scope.user,
        headers: {
          "Authorization": "Sicas " + base64.encode($scope.captcha.uuid + ":" + $scope.captcha.string)
        }
      }).then(function success() {
        NpolarApiMessage.emit("npolar-info", "You should receive a confirmation mail in a short while");
        $location.path(".");
      });
    }
  };

  $scope.confirm = function(id) {
      $http({
        method: "GET",
        url: confirmationUri+'/'+$routeParams.id
      }).then(function success() {
        NpolarApiMessage.emit("npolar-info", "Confirmation successful. You can now login with your new account");
        $location.path(".");
      });
  };

  if($scope.captcha) {
    ($scope.captcha.renew = function() {
      $http({
        method: "GET",
        url: captchaUri + "/?width=100&height=50&time=" + Date.now()
      }).then(function(response) {
        $scope.captcha.src = captchaUri + response.data.path;
        $scope.captcha.uuid = response.data.uuid;
        $scope.captcha.string = "";
      });
    }());
  }

  $scope.valid = function() {
    return (!$scope.captcha || $scope.captcha.string) && $scope.user.email && $scope.user.name && $scope.user.password && ($scope.user.password === $scope.user.password2);
  };
};

module.exports = UserRegisterController;
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 */

import { BackSide, FrontSide } from '../../constants.js';
import { BoxBufferGeometry } from '../../geometries/BoxGeometry.js';
import { PlaneBufferGeometry } from '../../geometries/PlaneGeometry.js';
import { ShaderMaterial } from '../../materials/ShaderMaterial.js';
import { Color } from '../../math/Color.js';
import { Mesh } from '../../objects/Mesh.js';
import { ShaderLib } from '../shaders/ShaderLib.js';

function WebGLBackground( renderer, state, objects, premultipliedAlpha ) {

	var clearColor = new Color( 0x000000 );
	var clearAlpha = 0;

	var planeMesh;
	var boxMesh;

	function render( renderList, scene, camera, forceClear ) {

		var background = scene.background;

		if ( background === null ) {

			setClear( clearColor, clearAlpha );

		} else if ( background && background.isColor ) {

			setClear( background, 1 );
			forceClear = true;

		}

		if ( renderer.autoClear || forceClear ) {

			renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );

		}

		if ( background && background.isCubeTexture ) {

			if ( boxMesh === undefined ) {

				boxMesh = new Mesh(
					new BoxBufferGeometry( 1, 1, 1 ),
					new ShaderMaterial( {
						uniforms: ShaderLib.cube.uniforms,
						vertexShader: ShaderLib.cube.vertexShader,
						fragmentShader: ShaderLib.cube.fragmentShader,
						side: BackSide,
						depthTest: true,
						depthWrite: false,
						fog: false
					} )
				);

				boxMesh.geometry.removeAttribute( 'normal' );
				boxMesh.geometry.removeAttribute( 'uv' );

				boxMesh.onBeforeRender = function ( renderer, scene, camera ) {

					this.matrixWorld.copyPosition( camera.matrixWorld );

				};

				objects.update( boxMesh );

			}

			boxMesh.material.uniforms.tCube.value = background;

			renderList.push( boxMesh, boxMesh.geometry, boxMesh.material, 0, null );

		} else if ( background && background.isTexture ) {

			if ( planeMesh === undefined ) {

				planeMesh = new Mesh(
					new PlaneBufferGeometry( 2, 2 ),
					new ShaderMaterial( {
						uniforms: ShaderLib.background.uniforms,
						vertexShader: ShaderLib.background.vertexShader,
						fragmentShader: ShaderLib.background.fragmentShader,
						side: FrontSide,
						depthTest: true,
						depthWrite: false,
						fog: false
					} )
				);

				planeMesh.geometry.removeAttribute( 'normal' );

				objects.update( planeMesh );

			}

			planeMesh.material.uniforms.t2D.value = background;

			renderList.push( planeMesh, planeMesh.geometry, planeMesh.material, 0, null );

		}

	}

	function setClear( color, alpha ) {

		state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );

	}

	return {

		getClearColor: function () {

			return clearColor;

		},
		setClearColor: function ( color, alpha ) {

			clearColor.set( color );
			clearAlpha = alpha !== undefined ? alpha : 1;
			setClear( clearColor, clearAlpha );

		},
		getClearAlpha: function () {

			return clearAlpha;

		},
		setClearAlpha: function ( alpha ) {

			clearAlpha = alpha;
			setClear( clearColor, clearAlpha );

		},
		render: render

	};

}

export { WebGLBackground };
<commit_msg>Clone uniforms<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 */

import { BackSide, FrontSide } from '../../constants.js';
import { BoxBufferGeometry } from '../../geometries/BoxGeometry.js';
import { PlaneBufferGeometry } from '../../geometries/PlaneGeometry.js';
import { ShaderMaterial } from '../../materials/ShaderMaterial.js';
import { Color } from '../../math/Color.js';
import { Mesh } from '../../objects/Mesh.js';
import { ShaderLib } from '../shaders/ShaderLib.js';
import { UniformsUtils } from '../shaders/UniformsUtils.js';

function WebGLBackground( renderer, state, objects, premultipliedAlpha ) {

	var clearColor = new Color( 0x000000 );
	var clearAlpha = 0;

	var planeMesh;
	var boxMesh;

	function render( renderList, scene, camera, forceClear ) {

		var background = scene.background;

		if ( background === null ) {

			setClear( clearColor, clearAlpha );

		} else if ( background && background.isColor ) {

			setClear( background, 1 );
			forceClear = true;

		}

		if ( renderer.autoClear || forceClear ) {

			renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );

		}

		if ( background && background.isCubeTexture ) {

			if ( boxMesh === undefined ) {

				boxMesh = new Mesh(
					new BoxBufferGeometry( 1, 1, 1 ),
					new ShaderMaterial( {
						uniforms: UniformsUtils.clone( ShaderLib.cube.uniforms ),
						vertexShader: ShaderLib.cube.vertexShader,
						fragmentShader: ShaderLib.cube.fragmentShader,
						side: BackSide,
						depthTest: true,
						depthWrite: false,
						fog: false
					} )
				);

				boxMesh.geometry.removeAttribute( 'normal' );
				boxMesh.geometry.removeAttribute( 'uv' );

				boxMesh.onBeforeRender = function ( renderer, scene, camera ) {

					this.matrixWorld.copyPosition( camera.matrixWorld );

				};

				objects.update( boxMesh );

			}

			boxMesh.material.uniforms.tCube.value = background;

			renderList.push( boxMesh, boxMesh.geometry, boxMesh.material, 0, null );

		} else if ( background && background.isTexture ) {

			if ( planeMesh === undefined ) {

				planeMesh = new Mesh(
					new PlaneBufferGeometry( 2, 2 ),
					new ShaderMaterial( {
						uniforms: UniformsUtils.clone( ShaderLib.background.uniforms ),
						vertexShader: ShaderLib.background.vertexShader,
						fragmentShader: ShaderLib.background.fragmentShader,
						side: FrontSide,
						depthTest: true,
						depthWrite: false,
						fog: false
					} )
				);

				planeMesh.geometry.removeAttribute( 'normal' );

				objects.update( planeMesh );

			}

			planeMesh.material.uniforms.t2D.value = background;

			renderList.push( planeMesh, planeMesh.geometry, planeMesh.material, 0, null );

		}

	}

	function setClear( color, alpha ) {

		state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );

	}

	return {

		getClearColor: function () {

			return clearColor;

		},
		setClearColor: function ( color, alpha ) {

			clearColor.set( color );
			clearAlpha = alpha !== undefined ? alpha : 1;
			setClear( clearColor, clearAlpha );

		},
		getClearAlpha: function () {

			return clearAlpha;

		},
		setClearAlpha: function ( alpha ) {

			clearAlpha = alpha;
			setClear( clearColor, clearAlpha );

		},
		render: render

	};

}

export { WebGLBackground };
<|endoftext|>


<commit_before>var send = require('koa-send');
var Koa = require('koa');
var app = new Koa();

// $ GET /package.json
// $ GET /

app.use(function (ctx, next){
  if ('/' == ctx.path) ctx.path = 'index.html';
  return send(ctx, ctx.path, { root: __dirname + '/starter-template' });
})

app.listen(3000);
console.log('listening on port 3000');<commit_msg>add default / to index.html<commit_after>var send = require('koa-send');
var Koa = require('koa');
var app = new Koa();

app.use(function (ctx, next){
  if ('/' == ctx.path) ctx.path = 'index.html';
  return send(ctx, ctx.path, { root: __dirname + '/starter-template' });
})

app.listen(3000);
console.log('listening on port 3000');<|endoftext|>