<commit_before>/**
 * Copyright (c) 2009-2011 The Open Planning Project
 */

Ext.USE_NATIVE_JSON = true;

// http://www.sencha.com/forum/showthread.php?141254-Ext.Slider-not-working-properly-in-IE9
// TODO re-evaluate once we move to Ext 4
Ext.override(Ext.dd.DragTracker, {
    onMouseMove: function (e, target) {
        if (this.active && Ext.isIE && !Ext.isIE9 && !e.browserEvent.button) {
            e.preventDefault();
            this.onMouseUp(e);
            return;
        }
        e.preventDefault();
        var xy = e.getXY(), s = this.startXY;
        this.lastXY = xy;
        if (!this.active) {
            if (Math.abs(s[0] - xy[0]) > this.tolerance || Math.abs(s[1] - xy[1]) > this.tolerance) {
                this.triggerStart(e);
            } else {
                return;
            }
        }
        this.fireEvent('mousemove', this, e);
        this.onDrag(e);
        this.fireEvent('drag', this, e);
    }
});

(function() {
    // backwards compatibility for reading saved maps
    // these source plugins were renamed after 2.3.2
    Ext.preg("gx_wmssource", gxp.plugins.WMSSource);
    Ext.preg("gx_olsource", gxp.plugins.OLSource);
    Ext.preg("gx_googlesource", gxp.plugins.GoogleSource);
    Ext.preg("gx_bingsource", gxp.plugins.BingSource);
    Ext.preg("gx_osmsource", gxp.plugins.OSMSource);
})();

/**
 * api: (define)
 * module = GeoExplorer
 * extends = gxp.Viewer
 */

/** api: constructor
 *  .. class:: GeoExplorer(config)
 *     Create a new GeoExplorer application.
 *
 *     Parameters:
 *     config - {Object} Optional application configuration properties.
 *
 *     Valid config properties:
 *     map - {Object} Map configuration object.
 *     sources - {Object} An object with properties whose values are WMS endpoint URLs
 *
 *     Valid map config properties:
 *         projection - {String} EPSG:xxxx
 *         units - {String} map units according to the projection
 *         maxResolution - {Number}
 *         layers - {Array} A list of layer configuration objects.
 *         center - {Array} A two item array with center coordinates.
 *         zoom - {Number} An initial zoom level.
 *
 *     Valid layer config properties (WMS):
 *     name - {String} Required WMS layer name.
 *     title - {String} Optional title to display for layer.
 */
var GeoExplorer = Ext.extend(gxp.Viewer, {

    // Begin i18n.
    zoomSliderText: "
Zoom Level: {zoom}

Scale: 1:{scale}
",
    loadConfigErrorText: "Trouble reading saved configuration:
",
    loadConfigErrorDefaultText: "Server Error.",
    xhrTroubleText: "Communication Trouble: Status ",
    layersText: "Layers",
    titleText: "Title",
    bookmarkText: "Bookmark URL",
    permakinkText: 'Permalink',
    appInfoText: "GeoExplorer",
    aboutText: "About GeoExplorer",
    mapInfoText: "Map Info",
    descriptionText: "Description",
    contactText: "Contact",
    aboutThisMapText: "About this Map",
    // End i18n.

    /**
     * private: property[mapPanel]
     * the :class:`GeoExt.MapPanel` instance for the main viewport
     */
    mapPanel: null,

    toggleGroup: "toolGroup",

    constructor: function(config) {
        this.mapItems = [
            {
                xtype: "gxp_scaleoverlay"
            }, {
                xtype: "gx_zoomslider",
                vertical: true,
                height: 100,
                plugins: new GeoExt.ZoomSliderTip({
                    template: this.zoomSliderText
                })
            }
        ];

        // both the Composer and the Viewer need to know about the viewerTools
        // First row in each object is needed to correctly render a tool in the treeview
        // of the embed map dialog. TODO: make this more flexible so this is not needed.
        config.viewerTools = [
            {
                leaf: true,
                text: gxp.plugins.Print.prototype.tooltip,
                ptype: "gxp_print",
                iconCls: "gxp-icon-print",
                customParams: {outputFilename: 'GeoExplorer-print'},
                printService: config.printService,
                checked: true
            }, {
                leaf: true,
                text: gxp.plugins.Navigation.prototype.tooltip,
                checked: true,
                iconCls: "gxp-icon-pan",
                ptype: "gxp_navigation",
                toggleGroup: this.toggleGroup
            }, {
                leaf: true,
                text: gxp.plugins.WMSGetFeatureInfo.prototype.infoActionTip,
                checked: true,
                iconCls: "gxp-icon-getfeatureinfo",
                ptype: "gxp_wmsgetfeatureinfo",
                format: 'grid',
                toggleGroup: this.toggleGroup
            }, {
                leaf: true,
                text: gxp.plugins.Measure.prototype.measureTooltip,
                checked: true,
                iconCls: "gxp-icon-measure-length",
                ptype: "gxp_measure",
                controlOptions: {immediate: true},
                toggleGroup: this.toggleGroup
            }, {
                leaf: true,
                text: gxp.plugins.Zoom.prototype.zoomInTooltip + " / " + gxp.plugins.Zoom.prototype.zoomOutTooltip,
                checked: true,
                iconCls: "gxp-icon-zoom-in",
                numberOfButtons: 2,
                ptype: "gxp_zoom"
            }, {
                leaf: true,
                text: gxp.plugins.NavigationHistory.prototype.previousTooltip + " / " + gxp.plugins.NavigationHistory.prototype.nextTooltip,
                checked: true,
                iconCls: "gxp-icon-zoom-previous",
                numberOfButtons: 2,
                ptype: "gxp_navigationhistory"
            }, {
                leaf: true,
                text: gxp.plugins.ZoomToExtent.prototype.tooltip,
                checked: true,
                iconCls: gxp.plugins.ZoomToExtent.prototype.iconCls,
                ptype: "gxp_zoomtoextent"
            }, {
                leaf: true,
                text: gxp.plugins.Legend.prototype.tooltip,
                checked: true,
                iconCls: "gxp-icon-legend",
                ptype: "gxp_legend"
            }, {
                leaf: true,
                text: gxp.plugins.GoogleEarth.prototype.tooltip,
                checked: true,
                iconCls: "gxp-icon-googleearth",
                ptype: "gxp_googleearth"
        }];

        GeoExplorer.superclass.constructor.apply(this, arguments);
    },

    loadConfig: function(config) {

        var mapUrl = window.location.hash.substr(1);
        var match = mapUrl.match(/^maps\/(\d+)$/);
        if (match) {
            this.id = Number(match[1]);
            OpenLayers.Request.GET({
                url: "../" + mapUrl,
                success: function(request) {
                    var addConfig = Ext.util.JSON.decode(request.responseText);
                    this.applyConfig(Ext.applyIf(addConfig, config));
                },
                failure: function(request) {
                    var obj;
                    try {
                        obj = Ext.util.JSON.decode(request.responseText);
                    } catch (err) {
                        // pass
                    }
                    var msg = this.loadConfigErrorText;
                    if (obj && obj.error) {
                        msg += obj.error;
                    } else {
                        msg += this.loadConfigErrorDefaultText;
                    }
                    this.on({
                        ready: function() {
                            this.displayXHRTrouble(msg, request.status);
                        },
                        scope: this
                    });
                    delete this.id;
                    window.location.hash = "";
                    this.applyConfig(config);
                },
                scope: this
            });
        } else {
            var query = Ext.urlDecode(document.location.search.substr(1));
            if (query && query.q) {
                var queryConfig = Ext.util.JSON.decode(query.q);
                Ext.apply(config, queryConfig);
            }
            this.applyConfig(config);
        }

    },

    displayXHRTrouble: function(msg, status) {

        Ext.Msg.show({
            title: this.xhrTroubleText + status,
            msg: msg,
            icon: Ext.MessageBox.WARNING
        });

    },

    /** private: method[initPortal]
     * Create the various parts that compose the layout.
     */
    initPortal: function() {

        var westPanel = new Ext.Panel({
            id: "westpanel",
            border: false,
            region: "west",
            layout: "fit",
            width: 250,
            split: true,
            collapsible: true,
            collapseMode: "mini",
            header: false
        });

        this.toolbar = new Ext.Toolbar({
            disabled: true,
            id: 'paneltbar',
            items: this.createTools()
        });
        this.on("ready", function() {
            // enable only those items that were not specifically disabled
            var disabled = this.toolbar.items.filterBy(function(item) {
                return item.initialConfig && item.initialConfig.disabled;
            });
            this.toolbar.enable();
            disabled.each(function(item) {
                item.disable();
            });
        });

        var googleEarthPanel = new gxp.GoogleEarthPanel({
            mapPanel: this.mapPanel,
            listeners: {
                beforeadd: function(record) {
                    return record.get("group") !== "background";
                }
            }
        });

        // TODO: continue making this Google Earth Panel more independent
        // Currently, it's too tightly tied into the viewer.
        // In the meantime, we keep track of all items that the were already
        // disabled when the panel is shown.
        var preGoogleDisabled = [];

        googleEarthPanel.on("show", function() {
            preGoogleDisabled.length = 0;
            this.toolbar.items.each(function(item) {
                if (item.disabled) {
                    preGoogleDisabled.push(item);
                }
            });
            this.toolbar.disable();
            // loop over all the tools and remove their output
            for (var key in this.tools) {
                var tool = this.tools[key];
                if (tool.outputTarget === "map") {
                    tool.removeOutput();
                }
            }
            var layersContainer = Ext.getCmp("tree");
            var layersToolbar = layersContainer && layersContainer.getTopToolbar();
            if (layersToolbar) {
                layersToolbar.items.each(function(item) {
                    if (item.disabled) {
                        preGoogleDisabled.push(item);
                    }
                });
                layersToolbar.disable();
            }
        }, this);

        googleEarthPanel.on("hide", function() {
            // re-enable all tools
            this.toolbar.enable();

            var layersContainer = Ext.getCmp("tree");
            var layersToolbar = layersContainer && layersContainer.getTopToolbar();
            if (layersToolbar) {
                layersToolbar.enable();
            }
            // now go back and disable all things that were disabled previously
            for (var i=0, ii=preGoogleDisabled.length; i<ii; ++i) {
                preGoogleDisabled[i].disable();
            }

        }, this);

        this.mapPanelContainer = new Ext.Panel({
            layout: "card",
            region: "center",
            defaults: {
                border: false
            },
            items: [
                this.mapPanel,
                googleEarthPanel
            ],
            activeItem: 0
        });

        this.portalItems = [{
            region: "center",
            layout: "border",
            tbar: this.toolbar,
            items: [
                this.mapPanelContainer,
                westPanel
            ]
        }];

        GeoExplorer.superclass.initPortal.apply(this, arguments);
    },

    /** private: method[createTools]
     * Create the toolbar configuration for the main panel.  This method can be
     * overridden in derived explorer classes such as :class:`GeoExplorer.Composer`
     * or :class:`GeoExplorer.Viewer` to provide specialized controls.
     */
    createTools: function() {
        var tools = [
            "-"
        ];
        return tools;
    },

    /** private: method[showUrl]
     */
    showUrl: function() {
        var win = new Ext.Window({
            title: this.bookmarkText,
            layout: 'form',
            labelAlign: 'top',
            modal: true,
            bodyStyle: "padding: 5px",
            width: 300,
            items: [{
                xtype: 'textfield',
                fieldLabel: this.permakinkText,
                readOnly: true,
                anchor: "100%",
                selectOnFocus: true,
                value: window.location.href
            }]
        });
        win.show();
        win.items.first().selectText();
    },

    /** api: method[getBookmark]
     *  :return: ``String``
     *
     *  Generate a bookmark for an unsaved map.
     */
    getBookmark: function() {
        var params = Ext.apply(
            OpenLayers.Util.getParameters(),
            {q: Ext.util.JSON.encode(this.getState())}
        );

        // disregard any hash in the url, but maintain all other components
        var url =
            document.location.href.split("?").shift() +
            "?" + Ext.urlEncode(params);

        return url;
    },

    /** private: method[displayAppInfo]
     * Display an informational dialog about the application.
     */
    displayAppInfo: function() {
        var appInfo = new Ext.Panel({
            title: this.appInfoText,
            html: ""+this.aboutText+" "
        });

        var about = Ext.applyIf(this.about, {
            title: '',
            "abstract": '',
            contact: ''
        });

        var mapInfo = new Ext.Panel({
            title: this.mapInfoText,
            html: '
' +
                  '
'+this.titleText+'

' + about.title +
                  '

'+this.descriptionText+'

' + about['abstract'] +
                  '

'+this.contactText+'

' + about.contact +'

',
            height: 'auto',
            width: 'auto'
        });

        var tabs = new Ext.TabPanel({
            activeTab: 0,
            items: [mapInfo, appInfo]
        });

        var win = new Ext.Window({
            title: this.aboutThisMapText,
            modal: true,
            layout: "fit",
            width: 300,
            height: 300,
            items: [tabs]
        });
        win.show();
    }
});

<commit_msg>Fixing Bing resolution issue.<commit_after>/**
 * Copyright (c) 2009-2011 The Open Planning Project
 */

Ext.USE_NATIVE_JSON = true;

// Suite 2.4.5 release cycle hotfixes
// https://github.com/openlayers/openlayers/commit/284ec6a9573f8657d1a3979ead774044e721d7c7
OpenLayers.Layer.Bing.prototype.maxResolution = Number.POSITIVE_INFINITY;

// http://www.sencha.com/forum/showthread.php?141254-Ext.Slider-not-working-properly-in-IE9
// TODO re-evaluate once we move to Ext 4
Ext.override(Ext.dd.DragTracker, {
    onMouseMove: function (e, target) {
        if (this.active && Ext.isIE && !Ext.isIE9 && !e.browserEvent.button) {
            e.preventDefault();
            this.onMouseUp(e);
            return;
        }
        e.preventDefault();
        var xy = e.getXY(), s = this.startXY;
        this.lastXY = xy;
        if (!this.active) {
            if (Math.abs(s[0] - xy[0]) > this.tolerance || Math.abs(s[1] - xy[1]) > this.tolerance) {
                this.triggerStart(e);
            } else {
                return;
            }
        }
        this.fireEvent('mousemove', this, e);
        this.onDrag(e);
        this.fireEvent('drag', this, e);
    }
});

(function() {
    // backwards compatibility for reading saved maps
    // these source plugins were renamed after 2.3.2
    Ext.preg("gx_wmssource", gxp.plugins.WMSSource);
    Ext.preg("gx_olsource", gxp.plugins.OLSource);
    Ext.preg("gx_googlesource", gxp.plugins.GoogleSource);
    Ext.preg("gx_bingsource", gxp.plugins.BingSource);
    Ext.preg("gx_osmsource", gxp.plugins.OSMSource);
})();

/**
 * api: (define)
 * module = GeoExplorer
 * extends = gxp.Viewer
 */

/** api: constructor
 *  .. class:: GeoExplorer(config)
 *     Create a new GeoExplorer application.
 *
 *     Parameters:
 *     config - {Object} Optional application configuration properties.
 *
 *     Valid config properties:
 *     map - {Object} Map configuration object.
 *     sources - {Object} An object with properties whose values are WMS endpoint URLs
 *
 *     Valid map config properties:
 *         projection - {String} EPSG:xxxx
 *         units - {String} map units according to the projection
 *         maxResolution - {Number}
 *         layers - {Array} A list of layer configuration objects.
 *         center - {Array} A two item array with center coordinates.
 *         zoom - {Number} An initial zoom level.
 *
 *     Valid layer config properties (WMS):
 *     name - {String} Required WMS layer name.
 *     title - {String} Optional title to display for layer.
 */
var GeoExplorer = Ext.extend(gxp.Viewer, {

    // Begin i18n.
    zoomSliderText: "
Zoom Level: {zoom}

Scale: 1:{scale}
",
    loadConfigErrorText: "Trouble reading saved configuration:
",
    loadConfigErrorDefaultText: "Server Error.",
    xhrTroubleText: "Communication Trouble: Status ",
    layersText: "Layers",
    titleText: "Title",
    bookmarkText: "Bookmark URL",
    permakinkText: 'Permalink',
    appInfoText: "GeoExplorer",
    aboutText: "About GeoExplorer",
    mapInfoText: "Map Info",
    descriptionText: "Description",
    contactText: "Contact",
    aboutThisMapText: "About this Map",
    // End i18n.

    /**
     * private: property[mapPanel]
     * the :class:`GeoExt.MapPanel` instance for the main viewport
     */
    mapPanel: null,

    toggleGroup: "toolGroup",

    constructor: function(config) {
        this.mapItems = [
            {
                xtype: "gxp_scaleoverlay"
            }, {
                xtype: "gx_zoomslider",
                vertical: true,
                height: 100,
                plugins: new GeoExt.ZoomSliderTip({
                    template: this.zoomSliderText
                })
            }
        ];

        // both the Composer and the Viewer need to know about the viewerTools
        // First row in each object is needed to correctly render a tool in the treeview
        // of the embed map dialog. TODO: make this more flexible so this is not needed.
        config.viewerTools = [
            {
                leaf: true,
                text: gxp.plugins.Print.prototype.tooltip,
                ptype: "gxp_print",
                iconCls: "gxp-icon-print",
                customParams: {outputFilename: 'GeoExplorer-print'},
                printService: config.printService,
                checked: true
            }, {
                leaf: true,
                text: gxp.plugins.Navigation.prototype.tooltip,
                checked: true,
                iconCls: "gxp-icon-pan",
                ptype: "gxp_navigation",
                toggleGroup: this.toggleGroup
            }, {
                leaf: true,
                text: gxp.plugins.WMSGetFeatureInfo.prototype.infoActionTip,
                checked: true,
                iconCls: "gxp-icon-getfeatureinfo",
                ptype: "gxp_wmsgetfeatureinfo",
                format: 'grid',
                toggleGroup: this.toggleGroup
            }, {
                leaf: true,
                text: gxp.plugins.Measure.prototype.measureTooltip,
                checked: true,
                iconCls: "gxp-icon-measure-length",
                ptype: "gxp_measure",
                controlOptions: {immediate: true},
                toggleGroup: this.toggleGroup
            }, {
                leaf: true,
                text: gxp.plugins.Zoom.prototype.zoomInTooltip + " / " + gxp.plugins.Zoom.prototype.zoomOutTooltip,
                checked: true,
                iconCls: "gxp-icon-zoom-in",
                numberOfButtons: 2,
                ptype: "gxp_zoom"
            }, {
                leaf: true,
                text: gxp.plugins.NavigationHistory.prototype.previousTooltip + " / " + gxp.plugins.NavigationHistory.prototype.nextTooltip,
                checked: true,
                iconCls: "gxp-icon-zoom-previous",
                numberOfButtons: 2,
                ptype: "gxp_navigationhistory"
            }, {
                leaf: true,
                text: gxp.plugins.ZoomToExtent.prototype.tooltip,
                checked: true,
                iconCls: gxp.plugins.ZoomToExtent.prototype.iconCls,
                ptype: "gxp_zoomtoextent"
            }, {
                leaf: true,
                text: gxp.plugins.Legend.prototype.tooltip,
                checked: true,
                iconCls: "gxp-icon-legend",
                ptype: "gxp_legend"
            }, {
                leaf: true,
                text: gxp.plugins.GoogleEarth.prototype.tooltip,
                checked: true,
                iconCls: "gxp-icon-googleearth",
                ptype: "gxp_googleearth"
        }];

        GeoExplorer.superclass.constructor.apply(this, arguments);
    },

    loadConfig: function(config) {

        var mapUrl = window.location.hash.substr(1);
        var match = mapUrl.match(/^maps\/(\d+)$/);
        if (match) {
            this.id = Number(match[1]);
            OpenLayers.Request.GET({
                url: "../" + mapUrl,
                success: function(request) {
                    var addConfig = Ext.util.JSON.decode(request.responseText);
                    this.applyConfig(Ext.applyIf(addConfig, config));
                },
                failure: function(request) {
                    var obj;
                    try {
                        obj = Ext.util.JSON.decode(request.responseText);
                    } catch (err) {
                        // pass
                    }
                    var msg = this.loadConfigErrorText;
                    if (obj && obj.error) {
                        msg += obj.error;
                    } else {
                        msg += this.loadConfigErrorDefaultText;
                    }
                    this.on({
                        ready: function() {
                            this.displayXHRTrouble(msg, request.status);
                        },
                        scope: this
                    });
                    delete this.id;
                    window.location.hash = "";
                    this.applyConfig(config);
                },
                scope: this
            });
        } else {
            var query = Ext.urlDecode(document.location.search.substr(1));
            if (query && query.q) {
                var queryConfig = Ext.util.JSON.decode(query.q);
                Ext.apply(config, queryConfig);
            }
            this.applyConfig(config);
        }

    },

    displayXHRTrouble: function(msg, status) {

        Ext.Msg.show({
            title: this.xhrTroubleText + status,
            msg: msg,
            icon: Ext.MessageBox.WARNING
        });

    },

    /** private: method[initPortal]
     * Create the various parts that compose the layout.
     */
    initPortal: function() {

        var westPanel = new Ext.Panel({
            id: "westpanel",
            border: false,
            region: "west",
            layout: "fit",
            width: 250,
            split: true,
            collapsible: true,
            collapseMode: "mini",
            header: false
        });

        this.toolbar = new Ext.Toolbar({
            disabled: true,
            id: 'paneltbar',
            items: this.createTools()
        });
        this.on("ready", function() {
            // enable only those items that were not specifically disabled
            var disabled = this.toolbar.items.filterBy(function(item) {
                return item.initialConfig && item.initialConfig.disabled;
            });
            this.toolbar.enable();
            disabled.each(function(item) {
                item.disable();
            });
        });

        var googleEarthPanel = new gxp.GoogleEarthPanel({
            mapPanel: this.mapPanel,
            listeners: {
                beforeadd: function(record) {
                    return record.get("group") !== "background";
                }
            }
        });

        // TODO: continue making this Google Earth Panel more independent
        // Currently, it's too tightly tied into the viewer.
        // In the meantime, we keep track of all items that the were already
        // disabled when the panel is shown.
        var preGoogleDisabled = [];

        googleEarthPanel.on("show", function() {
            preGoogleDisabled.length = 0;
            this.toolbar.items.each(function(item) {
                if (item.disabled) {
                    preGoogleDisabled.push(item);
                }
            });
            this.toolbar.disable();
            // loop over all the tools and remove their output
            for (var key in this.tools) {
                var tool = this.tools[key];
                if (tool.outputTarget === "map") {
                    tool.removeOutput();
                }
            }
            var layersContainer = Ext.getCmp("tree");
            var layersToolbar = layersContainer && layersContainer.getTopToolbar();
            if (layersToolbar) {
                layersToolbar.items.each(function(item) {
                    if (item.disabled) {
                        preGoogleDisabled.push(item);
                    }
                });
                layersToolbar.disable();
            }
        }, this);

        googleEarthPanel.on("hide", function() {
            // re-enable all tools
            this.toolbar.enable();

            var layersContainer = Ext.getCmp("tree");
            var layersToolbar = layersContainer && layersContainer.getTopToolbar();
            if (layersToolbar) {
                layersToolbar.enable();
            }
            // now go back and disable all things that were disabled previously
            for (var i=0, ii=preGoogleDisabled.length; i<ii; ++i) {
                preGoogleDisabled[i].disable();
            }

        }, this);

        this.mapPanelContainer = new Ext.Panel({
            layout: "card",
            region: "center",
            defaults: {
                border: false
            },
            items: [
                this.mapPanel,
                googleEarthPanel
            ],
            activeItem: 0
        });

        this.portalItems = [{
            region: "center",
            layout: "border",
            tbar: this.toolbar,
            items: [
                this.mapPanelContainer,
                westPanel
            ]
        }];

        GeoExplorer.superclass.initPortal.apply(this, arguments);
    },

    /** private: method[createTools]
     * Create the toolbar configuration for the main panel.  This method can be
     * overridden in derived explorer classes such as :class:`GeoExplorer.Composer`
     * or :class:`GeoExplorer.Viewer` to provide specialized controls.
     */
    createTools: function() {
        var tools = [
            "-"
        ];
        return tools;
    },

    /** private: method[showUrl]
     */
    showUrl: function() {
        var win = new Ext.Window({
            title: this.bookmarkText,
            layout: 'form',
            labelAlign: 'top',
            modal: true,
            bodyStyle: "padding: 5px",
            width: 300,
            items: [{
                xtype: 'textfield',
                fieldLabel: this.permakinkText,
                readOnly: true,
                anchor: "100%",
                selectOnFocus: true,
                value: window.location.href
            }]
        });
        win.show();
        win.items.first().selectText();
    },

    /** api: method[getBookmark]
     *  :return: ``String``
     *
     *  Generate a bookmark for an unsaved map.
     */
    getBookmark: function() {
        var params = Ext.apply(
            OpenLayers.Util.getParameters(),
            {q: Ext.util.JSON.encode(this.getState())}
        );

        // disregard any hash in the url, but maintain all other components
        var url =
            document.location.href.split("?").shift() +
            "?" + Ext.urlEncode(params);

        return url;
    },

    /** private: method[displayAppInfo]
     * Display an informational dialog about the application.
     */
    displayAppInfo: function() {
        var appInfo = new Ext.Panel({
            title: this.appInfoText,
            html: ""+this.aboutText+" "
        });

        var about = Ext.applyIf(this.about, {
            title: '',
            "abstract": '',
            contact: ''
        });

        var mapInfo = new Ext.Panel({
            title: this.mapInfoText,
            html: '
' +
                  '
'+this.titleText+'

' + about.title +
                  '

'+this.descriptionText+'

' + about['abstract'] +
                  '

'+this.contactText+'

' + about.contact +'

',
            height: 'auto',
            width: 'auto'
        });

        var tabs = new Ext.TabPanel({
            activeTab: 0,
            items: [mapInfo, appInfo]
        });

        var win = new Ext.Window({
            title: this.aboutThisMapText,
            modal: true,
            layout: "fit",
            width: 300,
            height: 300,
            items: [tabs]
        });
        win.show();
    }
});

<|endoftext|>


<commit_before>'use strict';

/**
 * Browser SubApp Sidebar View handler.
 *
 * @module juju.browser
 * @submodule views
 *
 */
YUI.add('subapp-browser-sidebar', function(Y) {
  var ns = Y.namespace('juju.browser.views'),
      models = Y.namespace('juju.models'),
      views = Y.namespace('juju.views'),
      widgets = Y.namespace('juju.widgets');

  /**
   * Sidebar master view for the gui browser.
   *
   * @class Sidebar
   * @extends {juju.browser.views.MainView}
   *
   */
  ns.Sidebar = Y.Base.create('browser-view-sidebar', ns.MainView, [], {
    _fullscreenTarget: '/bws/fullscreen',

    template: views.Templates.sidebar,
    visible: true,

    events: {
      '.charm-token': {
        'click': '_handleTokenSelect'
      }
    },

    /**
     * Given a set of Charms generate a CharmSlider widget with that data.
     *
     * @method _generateSliderWidget
     * @param {Object} sliderCharms BrowserCharmList of Charms from the API.
     *
     */
    _generateSliderWidget: function(sliderCharms) {
      var sliderWidgets = [];

      sliderCharms.each(function(charm) {
        sliderWidgets.push(
            new Y.juju.widgets.browser.CharmToken(charm.getAttrs()));
      });

      if (sliderWidgets.length) {
        var slider = new Y.juju.widgets.browser.CharmSlider({
          items: Y.Array.map(sliderWidgets, function(widget) {
            var node = Y.Node.create('<div>');
            widget.render(node);
            return node.getHTML();
          })
        });
        return slider;
      } else {
        return false;
      }
    },

    /**
     * Event handler for selecting a charm from a list on the page. Forces a
     * render of the charm details view for the user.
     *
     * @method _handleTokenSelect
     * @param {Event} ev the click event from the charm token.
     *
     */
    _handleTokenSelect: function(ev) {
      var id = ev.currentTarget.getData('charmid');
      var model = this._cacheCharms.getById(id);

      // Show the details view for this model.
      this._renderCharmDetails(
          model,
          this.get('container')
      );
    },

    /**
     * Initially we load editorial content to populate the sidebar. Build this
     * content.
     *
     * @method _renderEditorialView
     * @param {Node} container A node to stick the rendered output into.
     *
     */
    _renderEditorialView: function(container) {
      var tpl = this.template(),
          tplNode = Y.Node.create(tpl),
          store = this.get('store');

      this._renderSearchWidget(tplNode);

      if (typeof container !== 'object') {
        container = this.get('container');
      } else {
        this.set('container', container);
      }

      container.setHTML(tplNode);

      // By default we grab the editorial content from the api to use for
      // display.
      this.get('store').sidebarEditorial({
        'success': function(data) {
          var sliderCharms = this.get('store').resultsToCharmlist(
              data.result.slider);
          var sliderContainer = container.one('.bws-left .slider');
          var sliderCharmContainer = new Y.juju.widgets.browser.CharmContainer({
            name: 'Featured Charms',
            cutoff: 1,
            children: sliderCharms.map(function(charm) {
              return charm.getAttrs(); })
          });
          sliderCharmContainer.render(sliderContainer);

          // Add in the charm tokens for the new as well.
          var newContainer = container.one('.bws-left .new');
          var newCharms = this.get('store').resultsToCharmlist(
              data.result['new']);
          var newCharmContainer = new Y.juju.widgets.browser.CharmContainer({
            name: 'New Charms',
            cutoff: 2,
            children: newCharms.map(function(charm) {
              return charm.getAttrs(); })
          });
          newCharmContainer.render(newContainer);

          // Add the charms to the cache for use in other views.
          // Start with a reset to empty any current cached models.
          this._cacheCharms.reset(newCharms);
          this._cacheCharms.add(sliderCharms);
          this.charmContainers = [newCharmContainer, sliderCharmContainer];
        },

        'failure': function(data, request) {
          var message;
          if (data && data.type) {
            message = 'Charm API error of type: ' + data.type;
          } else {
            message = 'Charm API server did not respond';
          }
          this.get('db').notifications.add(
              new models.Notification({
                title: 'Failed to load sidebar content.',
                message: message,
                level: 'error'
              })
          );
        }
      }, this);
    },

    /**
     * Destroy this view and clear from the dom world.
     *
     * @method destructor
     *
     */
    destructor: function() {
      if (this.slider) {
        this.slider.destroy();
      }
      if (this.charmContainers) {
        Y.Array.each(this.charmContainers, function(container) {
          container.destroy();
        });
      }
    },

    /**
     * Render out the view to the DOM.
     *
     * @method render
     *
     */
    render: function(container) {
      if (this.get('charmID')) {
        this._renderCharmView(container);
      } else {
        this._renderEditorialView(container);
      }
      // Bind our view to the events from the search widget used for controls.
      this._bindSearchWidgetEvents();
    }

  }, {
    ATTRS: {}
  });

}, '0.1.0', {
  requires: [
    'browser-charm-container',
    'browser-charm-slider',
    'browser-charm-token',
    'browser-search-widget',
    'juju-charm-store',
    'juju-models',
    'juju-templates',
    'subapp-browser-charmview',
    'subapp-browser-mainview',
    'view'
  ]
});
<commit_msg>Sidebar references to slider widget removed.<commit_after>'use strict';

/**
 * Browser SubApp Sidebar View handler.
 *
 * @module juju.browser
 * @submodule views
 *
 */
YUI.add('subapp-browser-sidebar', function(Y) {
  var ns = Y.namespace('juju.browser.views'),
      models = Y.namespace('juju.models'),
      views = Y.namespace('juju.views'),
      widgets = Y.namespace('juju.widgets');

  /**
   * Sidebar master view for the gui browser.
   *
   * @class Sidebar
   * @extends {juju.browser.views.MainView}
   *
   */
  ns.Sidebar = Y.Base.create('browser-view-sidebar', ns.MainView, [], {
    _fullscreenTarget: '/bws/fullscreen',

    template: views.Templates.sidebar,
    visible: true,

    events: {
      '.charm-token': {
        'click': '_handleTokenSelect'
      }
    },

    /**
     * Event handler for selecting a charm from a list on the page. Forces a
     * render of the charm details view for the user.
     *
     * @method _handleTokenSelect
     * @param {Event} ev the click event from the charm token.
     *
     */
    _handleTokenSelect: function(ev) {
      var id = ev.currentTarget.getData('charmid');
      var model = this._cacheCharms.getById(id);

      // Show the details view for this model.
      this._renderCharmDetails(
          model,
          this.get('container')
      );
    },

    /**
     * Initially we load editorial content to populate the sidebar. Build this
     * content.
     *
     * @method _renderEditorialView
     * @param {Node} container A node to stick the rendered output into.
     *
     */
    _renderEditorialView: function(container) {
      var tpl = this.template(),
          tplNode = Y.Node.create(tpl),
          store = this.get('store');

      this._renderSearchWidget(tplNode);

      if (typeof container !== 'object') {
        container = this.get('container');
      } else {
        this.set('container', container);
      }

      container.setHTML(tplNode);

      // By default we grab the editorial content from the api to use for
      // display.
      this.get('store').sidebarEditorial({
        'success': function(data) {
          // XXX: j.c.sackett Apr 9, 2013: Remove all references to "slider"
          // once Charmworld API is updated
          var sliderCharms = this.get('store').resultsToCharmlist(
              data.result.slider);
          var sliderContainer = container.one('.bws-left .slider');
          var sliderCharmContainer = new Y.juju.widgets.browser.CharmContainer({
            name: 'Featured Charms',
            cutoff: 1,
            children: sliderCharms.map(function(charm) {
              return charm.getAttrs(); })
          });
          sliderCharmContainer.render(sliderContainer);

          // Add in the charm tokens for the new as well.
          var newContainer = container.one('.bws-left .new');
          var newCharms = this.get('store').resultsToCharmlist(
              data.result['new']);
          var newCharmContainer = new Y.juju.widgets.browser.CharmContainer({
            name: 'New Charms',
            cutoff: 2,
            children: newCharms.map(function(charm) {
              return charm.getAttrs(); })
          });
          newCharmContainer.render(newContainer);

          // Add the charms to the cache for use in other views.
          // Start with a reset to empty any current cached models.
          this._cacheCharms.reset(newCharms);
          this._cacheCharms.add(sliderCharms);
          this.charmContainers = [newCharmContainer, sliderCharmContainer];
        },

        'failure': function(data, request) {
          var message;
          if (data && data.type) {
            message = 'Charm API error of type: ' + data.type;
          } else {
            message = 'Charm API server did not respond';
          }
          this.get('db').notifications.add(
              new models.Notification({
                title: 'Failed to load sidebar content.',
                message: message,
                level: 'error'
              })
          );
        }
      }, this);
    },

    /**
     * Destroy this view and clear from the dom world.
     *
     * @method destructor
     *
     */
    destructor: function() {
      if (this.charmContainers) {
        Y.Array.each(this.charmContainers, function(container) {
          container.destroy();
        });
      }
    },

    /**
     * Render out the view to the DOM.
     *
     * @method render
     *
     */
    render: function(container) {
      if (this.get('charmID')) {
        this._renderCharmView(container);
      } else {
        this._renderEditorialView(container);
      }
      // Bind our view to the events from the search widget used for controls.
      this._bindSearchWidgetEvents();
    }

  }, {
    ATTRS: {}
  });

}, '0.1.0', {
  requires: [
    'browser-charm-container',
    'browser-charm-token',
    'browser-search-widget',
    'juju-charm-store',
    'juju-models',
    'juju-templates',
    'subapp-browser-charmview',
    'subapp-browser-mainview',
    'view'
  ]
});
<|endoftext|>


<commit_before>'use strict';

module.exports = (bot, config) => {
    return {
        commands: {
            load: [
                {
                    pattern: /^([a-z_]+)$/,
                    requires: 'admin',
                    execute: (event, plugin) => {
                        bot.loadPlugin(plugin)
                            .then(() => {
                                bot.notify(event.nick, `Plugin ${plugin} has been successfully loaded.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Plugin ${plugin} could not be loaded: ${error}`);
                            });
                    }
                },
                'Usage: load PLUGIN_NAME'
            ],
            admins: [
                {
                    pattern: /^add (\S+)$/,
                    requires: 'admin',
                    execute: (event, user) => {
                        if (bot.permissions.isAdmin(user)) {
                            return bot.notify(event.nick, `User ${user} is already an administrator.`);
                        }
                        bot.permissions.setAdmin(user, true)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} is now an administrator.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not save permissions: ${error}`);
                            });
                    }
                },
                {
                    pattern: /^remove (\S+)$/,
                    requires: 'admin',
                    execute: (event, user) => {
                        if (!bot.permissions.isAdmin(user)) {
                            return bot.notify(event.nick, `User ${user} is not an administrator.`);
                        }
                        bot.permissions.setAdmin(user, false)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} is no longer an administrator.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not save permissions: ${error}`);
                            });
                    }
                },
                'Usage: admins <add|remove> USER_NAME'
            ],
            op: [
                {
                    pattern: /^(\S+)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        bot.giveOp(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was opped.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not op user: ${error}`);
                            });
                        }
                },
                'Usage: op USER_NAME'
            ],
            deop: [
                {
                    pattern: /^(\S+)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        bot.takeOp(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was deopped.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not deop user: ${error}`);
                            });
                        }
                },
                'Usage: deop USER_NAME'
            ],
            voice: [
                {
                    pattern: /^(\S+)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        bot.giveVoice(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was voiced.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not voice user: ${error}`);
                            });
                        }
                },
                'Usage: voice USER_NAME'
            ],
            devoice: [
                {
                    pattern: /^(\S+)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        bot.takeVoice(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was devoiced.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not devoice user: ${error}`);
                            });
                        }
                },
                'Usage: devoice USER_NAME'
            ]
        }
    };
};<commit_msg>Allow empty argument for self-targetting<commit_after>'use strict';

module.exports = (bot, config) => {
    return {
        commands: {
            load: [
                {
                    pattern: /^([a-z_]+)$/,
                    requires: 'admin',
                    execute: (event, plugin) => {
                        bot.loadPlugin(plugin)
                            .then(() => {
                                bot.notify(event.nick, `Plugin ${plugin} has been successfully loaded.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Plugin ${plugin} could not be loaded: ${error}`);
                            });
                    }
                },
                'Usage: load PLUGIN_NAME'
            ],
            admins: [
                {
                    pattern: /^add (\S+)$/,
                    requires: 'admin',
                    execute: (event, user) => {
                        if (bot.permissions.isAdmin(user)) {
                            return bot.notify(event.nick, `User ${user} is already an administrator.`);
                        }
                        bot.permissions.setAdmin(user, true)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} is now an administrator.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not save permissions: ${error}`);
                            });
                    }
                },
                {
                    pattern: /^remove (\S+)$/,
                    requires: 'admin',
                    execute: (event, user) => {
                        if (!bot.permissions.isAdmin(user)) {
                            return bot.notify(event.nick, `User ${user} is not an administrator.`);
                        }
                        bot.permissions.setAdmin(user, false)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} is no longer an administrator.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not save permissions: ${error}`);
                            });
                    }
                },
                'Usage: admins <add|remove> USER_NAME'
            ],
            op: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if(user.length === 0) user = event.nick;
                        bot.giveOp(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was opped.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not op user: ${error}`);
                            });
                        }
                },
                'Usage: op [USER_NAME]'
            ],
            deop: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if(user.length === 0) user = event.nick;
                        bot.takeOp(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was deopped.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not deop user: ${error}`);
                            });
                        }
                },
                'Usage: deop [USER_NAME]'
            ],
            voice: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if(user.length === 0) user = event.nick;
                        bot.giveVoice(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was voiced.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not voice user: ${error}`);
                            });
                        }
                },
                'Usage: voice [USER_NAME]'
            ],
            devoice: [
                {
                    pattern: /^(\S*)$/,
                    requires: 'operator',
                    execute: (event, user) => {
                        if(user.length === 0) user = event.nick;
                        bot.takeVoice(user, event.channel)
                            .then(() => {
                                bot.notify(event.nick, `User ${user} was devoiced.`);
                            })
                            .catch((error) => {
                                bot.notify(event.nick, `Could not devoice user: ${error}`);
                            });
                        }
                },
                'Usage: devoice [USER_NAME]'
            ]
        }
    };
};<|endoftext|>


<commit_before>// Webpack Config for {Production} (Server)
// · devTool: https://webpack.github.io/docs/build-performance.html#sourcemaps
// · Optimization: https://github.com/webpack/docs/wiki/optimization
// · DefinePlugin: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
// · ExternalsPlugin: https://github.com/Morhaus/webpack-externals-plugin

const path = require('path');
const webpack = require('webpack');
const ExternalsPlugin = require('webpack-externals-plugin');
const colors = require('colors');

if (process.env.NODE_ENV !== 'production') {
  console.log(colors.bold.red('You can run "webpack --config webpack.server.js" only in NODE_ENV="production"'))
  process.exit(1);
}

const plugins = [
  new webpack.IgnorePlugin(/\.css$/),
  new ExternalsPlugin({
    type: 'commonjs',
    include: path.join(__dirname, '/node_modules/'),
  }),
  // Avoid using the console in production mode.
  new webpack.DefinePlugin({ 'console': {
    log: () => void 0
  }})
];

module.exports = {
  devtool: 'source-map',
  entry: [ './src/server/index.jsx' ],
  output: {
    path: path.join(__dirname, 'build'),
    filename: 'server.bundle.js',
    publicPath: '/static/'
  },
  target: 'async-node',
  node: {
    __filename: true,
    __dirname: true
  },
  resolve: {
    extensions: [ '', '.js', '.jsx' ],
    modules: [ 'src/server', 'node_modules' ]
  },
  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        include: path.resolve(__dirname, 'src'),
        exclude: /node_modules/,
        loaders: [ 'babel-loader' ]
      }, {
        test: /\.json$/,
        loader: 'json-loader'
      }
    ]
  },
  plugins
};
<commit_msg>Ignore .css, .sass, .scss, .less when using require in server.<commit_after>// Webpack Config for {Production} (Server)
// · devTool: https://webpack.github.io/docs/build-performance.html#sourcemaps
// · Optimization: https://github.com/webpack/docs/wiki/optimization
// · DefinePlugin: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
// · ExternalsPlugin: https://github.com/Morhaus/webpack-externals-plugin

const path = require('path');
const webpack = require('webpack');
const ExternalsPlugin = require('webpack-externals-plugin');
const colors = require('colors');

if (process.env.NODE_ENV !== 'production') {
  console.log(colors.bold.red('You can run "webpack --config webpack.server.js" only in NODE_ENV="production"'))
  process.exit(1);
}

const plugins = [
  new webpack.IgnorePlugin(/\.(css|sass|scss|less)$/),
  new ExternalsPlugin({
    type: 'commonjs',
    include: path.join(__dirname, '/node_modules/'),
  }),
  // Avoid using the console in production mode.
  new webpack.DefinePlugin({ 'console': {
    log: () => void 0
  }})
];

module.exports = {
  devtool: 'source-map',
  entry: [ './src/server/index.jsx' ],
  output: {
    path: path.join(__dirname, 'build'),
    filename: 'server.bundle.js',
    publicPath: '/static/'
  },
  target: 'async-node',
  node: {
    __filename: true,
    __dirname: true
  },
  resolve: {
    extensions: [ '', '.js', '.jsx' ],
    modules: [ 'src/server', 'node_modules' ]
  },
  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        include: path.resolve(__dirname, 'src'),
        exclude: /node_modules/,
        loaders: [ 'babel-loader' ]
      }, {
        test: /\.json$/,
        loader: 'json-loader'
      }
    ]
  },
  plugins
};
<|endoftext|>


<commit_before>import Vue from "vue";
import Router from "vue-router";

Vue.use(Router);

export function createRouter (views) {
	let templatePages = {};

	let routes = [];
	let nested = {};

	for (let view of views) {
		if (view.info.nested) {
			if (!nested[view.info.nested]) nested[view.info.nested] = [];

			let sub = {
				path: view.info.route,
				component: view.vue
			};

			nested[view.info.nested].push(sub);

			view.$nested = sub;
		}
	}

	for (let view of views) {
		if (view.info.type == "page" && !view.info.nested) {
			if (view.info["template-page"])
				templatePages[view.info["template-page"]] = view;

			let route = {
				path: view.info.route,
				component: view.vue
			};

			let absoluteRoute = view.info.route;

			if (nested[absoluteRoute])
				route.children = nested[absoluteRoute];

			routes.push(route);
		}else if (view.info.type == "page" && view.info.nested) {
			let absoluteRoute = view.info.nested + "/" + view.info.route;

			if (nested[absoluteRoute]) {
				let myNested = view.$nested;

				myNested.children = nested[absoluteRoute];
			}
		}
	}

	return new Router({
		mode: "history",
		routes: [
			...routes,
			{
				path: "*",
				component: templatePages["404"].vue
			}
		]
	});
}<commit_msg>Added scroll resets.<commit_after>import Vue from "vue";
import Router from "vue-router";

Vue.use(Router);

export function createRouter (views) {
	let templatePages = {};

	let routes = [];
	let nested = {};

	for (let view of views) {
		if (view.info.nested) {
			if (!nested[view.info.nested]) nested[view.info.nested] = [];

			let sub = {
				path: view.info.route,
				component: view.vue
			};

			nested[view.info.nested].push(sub);

			view.$nested = sub;
		}
	}

	for (let view of views) {
		if (view.info.type == "page" && !view.info.nested) {
			if (view.info["template-page"])
				templatePages[view.info["template-page"]] = view;

			let route = {
				path: view.info.route,
				component: view.vue
			};

			let absoluteRoute = view.info.route;

			if (nested[absoluteRoute])
				route.children = nested[absoluteRoute];

			routes.push(route);
		}else if (view.info.type == "page" && view.info.nested) {
			let absoluteRoute = view.info.nested + "/" + view.info.route;

			if (nested[absoluteRoute]) {
				let myNested = view.$nested;

				myNested.children = nested[absoluteRoute];
			}
		}
	}

	return new Router({
		mode: "history",
		routes: [
			...routes,
			{
				path: "*",
				component: templatePages["404"].vue
			}
		],
		scrollBehavior(to, from, savedPosition) {
			if (document.querySelector(".websom-main-wrap"))
				document.querySelector(".websom-main-wrap").scrollTo(0, 0);
			return {
				x: 0,
				y: 0
			};
		}
	});
}<|endoftext|>


<commit_before>import React from 'react';
import {number} from 'prop-types';
import InternalLink from '../../../atoms/links/internal';

const listStyles = {
  listStyleType: 'none',
  padding: 0,
  display: 'flex',
  flexWrap: 'nowrap',
  justifyContent: 'space-evenly',
  li: {display: 'inline-block'}
};

function isActivePage(currentPage, pageNumber) {
  return currentPage === pageNumber;
}

function highlightWhenActive(currentPage, pageNumber) {
  return isActivePage(currentPage, pageNumber) ? '#ced' : undefined;
}

export default function Pagination({totalPages, currentPage}) {
  return (

      {
        Array
          .from({length: totalPages}, (_, index) => ({pageNumber: index + 1}))
          .map(({pageNumber}) => (
            <li key={`page-${pageNumber}`} css={{backgroundColor: highlightWhenActive(currentPage, pageNumber)}}>
              <InternalLink to={1 === pageNumber ? '/archive' : `/archive/page-${pageNumber}`}>
                {`${pageNumber}`}
              </InternalLink>

          ))
      }

  );
}

Pagination.propTypes = {
  totalPages: number.isRequired,
  currentPage: number.isRequired
};
<commit_msg>feat(archive-pagination): improved hover styles<commit_after>import React from 'react';
import {number} from 'prop-types';
import InternalLink from '../../../atoms/links/internal';

const listStyles = {
  listStyleType: 'none',
  padding: 0,
  display: 'flex',
  flexWrap: 'nowrap',
  justifyContent: 'space-evenly',
  li: {display: 'inline-block', ':hover': {backgroundColor: '#eee'}},
  a: {':hover': {textDecoration: 'none'}, padding: '6px 12px'}
};

function isActivePage(currentPage, pageNumber) {
  return currentPage === pageNumber;
}

function highlightWhenActive(currentPage, pageNumber) {
  return isActivePage(currentPage, pageNumber) ? '#ced' : undefined;
}

export default function Pagination({totalPages, currentPage}) {
  return (

      {
        Array
          .from({length: totalPages}, (_, index) => ({pageNumber: index + 1}))
          .map(({pageNumber}) => {
            const pageStyles = {backgroundColor: highlightWhenActive(currentPage, pageNumber)};

            return (
              <li key={`page-${pageNumber}`} css={pageStyles}>
                <InternalLink to={1 === pageNumber ? '/archive' : `/archive/page-${pageNumber}`}>
                  {`${pageNumber}`}
                </InternalLink>

            );
          })
      }

  );
}

Pagination.propTypes = {
  totalPages: number.isRequired,
  currentPage: number.isRequired
};
<|endoftext|>


<commit_before>var restify = require('restify');
var config = require('config');
var serverConfig = config.Server;
var models = require('./models/');
var ResultConverter = require('./result-converter.js');

var server = restify.createServer({ name: 'cm-updater-server' });

var extractRequestParameters = function(req) {
	var requestParameters = null;

	// Prior to CM11 the CMUpdater app did not send the correct content-type.
	// Thus auto-parsing the body did not work.
	if (req.is('json')) {
		requestParameters = req.body;
	} else if (!!req.body) {
		try {
			requestParameters = JSON.parse(req.body);
		} catch (err) {
			// Ignore, should be handled with a 404 by the caller
			// (the result is null in this case).
		}
	}

	return requestParameters;
}

models.sequelize.sync().success(function() {
	server.listen(serverConfig.listeningPort, serverConfig.listeningAddress, function () {
		console.log('%s listening at %s', server.name, server.url);
	});

	server.use(restify.bodyParser(serverConfig.bodyParserserverConfiguration || {}));

	// Conditionally enable the throttle module with the settings from the serverConfig.
	if (serverConfig.throttleserverConfiguration && serverConfig.throttleserverConfiguration.isEnabled) {
		server.use(restify.throttle(serverConfig.throttleserverConfiguration));
	}

	if (serverConfig.serveStaticConfiguration) {
		serverConfig.serveStaticConfiguration.forEach(function(staticSettings) {
			server.get(new RegExp(staticSettings.urlPattern), restify.serveStatic(staticSettings.options));
		});
	}

	server.get('/changelog/:romId', function (req, res, next) {
		models.Rom.find(req.params.romId).complete(function(err, rom) {
			if (err) {
				res.send(500);
				return next();
			}

			if (!rom) {
				res.send(404);
				return next();
			}

			if (!rom.isActive) {
				res.send(410);
				return next();
			}

			var findParentRomHandler = function(childRom, resultHandler) {
				childRom.getParentRom().complete(function(err, parentRom) {
					if (err) {
						resultHandler(null);
					} else {
						resultHandler(parentRom);
					}
				});
			}

			ResultConverter.getChangelogContent(rom, findParentRomHandler, function(body) {
				res.writeHead(200, {
					'Content-Length': Buffer.byteLength(body),
					'Content-Type': 'text/plain'
				});

				res.end(body);

				return next();
			});
		});
	});

	server.get('/download/rom/:romId', function (req, res, next) {
		models.Rom.find({
			include: [
				{
					model: models.RomVariant
				}
			],
			where: {
				id: req.params.romId
			}
		}).complete(function(err, rom) {
			if (err) {
				res.send(500);
			} else if (!rom) {
				res.send(404);
			} else if (!rom.isActive) {
				res.send(410);
			} else {
				var realDownloadUrl = ResultConverter.getRealRomDownloadUrl(rom);

				res.writeHead(301, { Location: realDownloadUrl });
				res.end();

				models.Download.build({
					RomId: rom.id,
					userAgent: req.headers['user-agent'],
				}).save().error(function (err) {
					// Ignoring errors here since those have no impact for the user.
				});
			}

			return next();
		});
	});

	server.get('/download/incremental/:incrementalId', function (req, res, next) {
		models.Incremental.find({
			include: [
				{
					model: models.RomVariant
				}
			],
			where: {
				id: req.params.incrementalId
			}
		}).complete(function(err, incremental) {
			if (err) {
				res.send(500);
			} else if (!incremental) {
				res.send(404);
			} else if (!incremental.isActive) {
				res.send(410);
			} else {
				var realDownloadUrl = ResultConverter.getRealIncrementalDownloadUrl(incremental);

				res.writeHead(301, { Location: realDownloadUrl });
				res.end();

				models.Download.build({
					IncrementalId: incremental.id,
					userAgent: req.headers['user-agent'],
				}).save().error(function (err) {
					// Ignoring errors here since those have no impact for the user.
				});
			}

			return next();
		});
	});

	server.post('/api/v1/build/get_delta', function(req, res, next) {
		var requestParameters = extractRequestParameters(req);

		if (!requestParameters || !requestParameters.source_incremental || !requestParameters.target_incremental) {
			res.send(400, ResultConverter.convertIncrementalErrors(
				"source_incremental and target_incremental are required parameters!"));
			return next();
		}

		models.Incremental.find({ include: [
			{ model: models.Rom, as: 'sourceRom', where: { incrementalId: requestParameters.source_incremental } },
			{ model: models.Rom, as: 'targetRom', where: { incrementalId: requestParameters.target_incremental } }
		]}).complete(function(err, incremental) {
			if (err) {
				res.send(500, ResultConverter.convertIncrementalErrors('Database error.'));
			} else if (!incremental || !incremental.isActive) {
				res.send(200, ResultConverter.convertIncrementalErrors("No matching incremental update found!"));
			} else {
				res.send(200, ResultConverter.convertIncremental(incremental));
			}

			return next();
		});
	});

	server.post('/api', function(req, res, next) {
		var requestParameters = extractRequestParameters(req);
		var responseId = null;

		if (!requestParameters || !requestParameters.params) {
			res.send(400, ResultConverter.convertRomListError(responseId, 'params is a required parameter!'));
			return next();
		} else if (requestParameters.method != 'get_all_builds') {
			res.send(400, ResultConverter.convertRomListError(responseId, requestParameters.method + ' is not a valid "method"!'));
			return next();
		}

		models.Rom.findAll({
			include: [
				{
					model: models.RomVariant,
					include: [
						{
							model: models.Device,
							where: {
								name: requestParameters.params.device,
							}
						}
					]
				}
			],
			where: {
				updateChannel: requestParameters.params.channels,
				isActive: true,
			},
		}).complete(function(err, roms) {
			if (err) {
				res.send(500, ResultConverter.convertRomListError(responseId, 'Database error.'));
			} else {
				res.send(200, ResultConverter.convertRomList(responseId, roms));
			}

			return next();
		});
	});
});
<commit_msg>Fixed getting incremental updates.<commit_after>var restify = require('restify');
var config = require('config');
var serverConfig = config.Server;
var models = require('./models/');
var ResultConverter = require('./result-converter.js');

var server = restify.createServer({ name: 'cm-updater-server' });

var extractRequestParameters = function(req) {
	var requestParameters = null;

	// Prior to CM11 the CMUpdater app did not send the correct content-type.
	// Thus auto-parsing the body did not work.
	if (req.is('json')) {
		requestParameters = req.body;
	} else if (!!req.body) {
		try {
			requestParameters = JSON.parse(req.body);
		} catch (err) {
			// Ignore, should be handled with a 404 by the caller
			// (the result is null in this case).
		}
	}

	return requestParameters;
}

models.sequelize.sync().success(function() {
	server.listen(serverConfig.listeningPort, serverConfig.listeningAddress, function () {
		console.log('%s listening at %s', server.name, server.url);
	});

	server.use(restify.bodyParser(serverConfig.bodyParserserverConfiguration || {}));

	// Conditionally enable the throttle module with the settings from the serverConfig.
	if (serverConfig.throttleserverConfiguration && serverConfig.throttleserverConfiguration.isEnabled) {
		server.use(restify.throttle(serverConfig.throttleserverConfiguration));
	}

	if (serverConfig.serveStaticConfiguration) {
		serverConfig.serveStaticConfiguration.forEach(function(staticSettings) {
			server.get(new RegExp(staticSettings.urlPattern), restify.serveStatic(staticSettings.options));
		});
	}

	server.get('/changelog/:romId', function (req, res, next) {
		models.Rom.find(req.params.romId).complete(function(err, rom) {
			if (err) {
				res.send(500);
				return next();
			}

			if (!rom) {
				res.send(404);
				return next();
			}

			if (!rom.isActive) {
				res.send(410);
				return next();
			}

			var findParentRomHandler = function(childRom, resultHandler) {
				childRom.getParentRom().complete(function(err, parentRom) {
					if (err) {
						resultHandler(null);
					} else {
						resultHandler(parentRom);
					}
				});
			}

			ResultConverter.getChangelogContent(rom, findParentRomHandler, function(body) {
				res.writeHead(200, {
					'Content-Length': Buffer.byteLength(body),
					'Content-Type': 'text/plain'
				});

				res.end(body);

				return next();
			});
		});
	});

	server.get('/download/rom/:romId', function (req, res, next) {
		models.Rom.find({
			include: [
				{
					model: models.RomVariant
				}
			],
			where: {
				id: req.params.romId
			}
		}).complete(function(err, rom) {
			if (err) {
				res.send(500);
			} else if (!rom) {
				res.send(404);
			} else if (!rom.isActive) {
				res.send(410);
			} else {
				var realDownloadUrl = ResultConverter.getRealRomDownloadUrl(rom);

				res.writeHead(301, { Location: realDownloadUrl });
				res.end();

				models.Download.build({
					RomId: rom.id,
					userAgent: req.headers['user-agent'],
				}).save().error(function (err) {
					// Ignoring errors here since those have no impact for the user.
				});
			}

			return next();
		});
	});

	server.get('/download/incremental/:incrementalId', function (req, res, next) {
		models.Incremental.find({
			include: [
				{
					model: models.RomVariant
				}
			],
			where: {
				id: req.params.incrementalId
			}
		}).complete(function(err, incremental) {
			if (err) {
				res.send(500);
			} else if (!incremental) {
				res.send(404);
			} else if (!incremental.isActive) {
				res.send(410);
			} else {
				var realDownloadUrl = ResultConverter.getRealIncrementalDownloadUrl(incremental);

				res.writeHead(301, { Location: realDownloadUrl });
				res.end();

				models.Download.build({
					IncrementalId: incremental.id,
					userAgent: req.headers['user-agent'],
				}).save().error(function (err) {
					// Ignoring errors here since those have no impact for the user.
				});
			}

			return next();
		});
	});

	server.post('/api/v1/build/get_delta', function(req, res, next) {
		var requestParameters = extractRequestParameters(req);

		if (!requestParameters || !requestParameters.source_incremental || !requestParameters.target_incremental) {
			res.send(400, ResultConverter.convertIncrementalErrors(
				"source_incremental and target_incremental are required parameters!"));
			return next();
		}

		models.Incremental.find({ include: [
			{
				model: models.Rom,
				as: 'sourceRom',
				where: {
					incrementalId: requestParameters.source_incremental
				}
			},
			{
				model: models.Rom,
				as: 'targetRom',
				where: {
					incrementalId: requestParameters.target_incremental
				}
			},
			{
				model: models.RomVariant,
			},
		]}).complete(function(err, incremental) {
			if (err) {
				res.send(500, ResultConverter.convertIncrementalErrors('Database error.'));
			} else if (!incremental || !incremental.isActive) {
				res.send(200, ResultConverter.convertIncrementalErrors("No matching incremental update found!"));
			} else {
				res.send(200, ResultConverter.convertIncremental(incremental));
			}

			return next();
		});
	});

	server.post('/api', function(req, res, next) {
		var requestParameters = extractRequestParameters(req);
		var responseId = null;

		if (!requestParameters || !requestParameters.params) {
			res.send(400, ResultConverter.convertRomListError(responseId, 'params is a required parameter!'));
			return next();
		} else if (requestParameters.method != 'get_all_builds') {
			res.send(400, ResultConverter.convertRomListError(responseId, requestParameters.method + ' is not a valid "method"!'));
			return next();
		}

		models.Rom.findAll({
			include: [
				{
					model: models.RomVariant,
					include: [
						{
							model: models.Device,
							where: {
								name: requestParameters.params.device,
							}
						}
					]
				}
			],
			where: {
				updateChannel: requestParameters.params.channels,
				isActive: true,
			},
		}).complete(function(err, roms) {
			if (err) {
				res.send(500, ResultConverter.convertRomListError(responseId, 'Database error.'));
			} else {
				res.send(200, ResultConverter.convertRomList(responseId, roms));
			}

			return next();
		});
	});
});
<|endoftext|>


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

  // Module systems magic dance.

  if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
    // NodeJS
    module.exports = plugin;
  } else if (typeof define === "function" && define.amd) {
    // AMD
    define(function () {
        return plugin;
    });
  } else {
    // Other environment (usually <script> tag): plug in to global chai instance directly.
    neume.use(plugin);
  }

})(function(neume, _) {
  "use strict";

  neume.register("debug", function(ugen, spec, inputs) {
    var context = ugen.$context;
    var outlet  = context.createScriptProcessor(2048, 1, 1);

    var interval = _.finite(_.defaults(spec.interval, 1)) * context.sampleRate;
    var label    = String(spec.label || "");
    var samples  = 0;

    if (label) {
      label = label + ": ";
    }

    interval = Math.max(1, interval|0);

    outlet.onaudioprocess = function(e) {
      var input = e.inputBuffer.getChannelData(0);
      var length = input.length;

      for (var i = 0; i < length; i++) {
        samples += 1;
        if (samples === interval) {
          console.log(label + input[i]);
          samples = 0;
        }
      }

      e.outputBuffer.getChannelData(0).set(input);
    };

    context.createSum(inputs).connect(outlet);

    return new neume.Unit({
      outlet: outlet
    });
  });

});
<commit_msg>rename debug -> debug~<commit_after>(function(plugin) {
  "use strict";

  // Module systems magic dance.

  if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
    // NodeJS
    module.exports = plugin;
  } else if (typeof define === "function" && define.amd) {
    // AMD
    define(function () {
        return plugin;
    });
  } else {
    // Other environment (usually <script> tag): plug in to global chai instance directly.
    neume.use(plugin);
  }

})(function(neume, _) {
  "use strict";

  neume.register("debug~", function(ugen, spec, inputs) {
    var context = ugen.$context;
    var outlet  = context.createScriptProcessor(2048, 1, 1);

    var interval = _.finite(_.defaults(spec.interval, 1)) * context.sampleRate;
    var label    = String(spec.label || "");
    var samples  = 0;

    if (label) {
      label = label + ": ";
    }

    interval = Math.max(1, interval|0);

    outlet.onaudioprocess = function(e) {
      var input = e.inputBuffer.getChannelData(0);
      var length = input.length;

      for (var i = 0; i < length; i++) {
        samples += 1;
        if (samples === interval) {
          console.log(label + input[i]);
          samples = 0;
        }
      }

      e.outputBuffer.getChannelData(0).set(input);
    };

    context.createSum(inputs).connect(outlet);

    return new neume.Unit({
      outlet: outlet
    });
  });

});
<|endoftext|>


<commit_before>var assert = require('assert');
var sinon = require('sinon');
var _ = require('lodash');

DEBUG = true;

describe('app', function() {
    var app,
        appConfig;

    beforeEach(function() {
        app = require('../app.js')();
        appConfig = app.appConfig;
    });

    it('blank', function() {
        assert(app);
    });

    describe('-> resolveEntryPoint', function() {
        it('Не падает когда devPages нет в конфиге', function(done) {
            appConfig.config = {};
            appConfig.loadModule = function() {};

            appConfig.resolveEntryPoint();
            done();
        });
    });

    describe.skip('-> getModificators', function() {
        var mods;
        var appInstance;
        var moduleWrapper;

        before(function() {
            appInstance = app().instance;
            moduleWrapper = {
                type: 'online'
            };
        });

        it('Элемент moduleWrapper.block()[0] есть объект', function() {
            moduleWrapper.block = function() {
                return [{className: 'online_visible online_holy_glob'}];
            };
            mods = appInstance.getModificators(moduleWrapper);
            assert(!mods.visible, 'Пока не умеем распозновать модификаторы без значения типа online_visible');
            // пока умеем распозновать только модификаторы со значениями типа online_holy_glob => { holy: 'glob' }
            assert.ok(mods.holy == 'glob');
        });

        it('Элемент moduleWrapper.block()[0] есть null', function() {
            moduleWrapper.block = function() {
                return [null];
            };
            mods = appInstance.getModificators(moduleWrapper);
            assert.ok(mods);
        });
    });

    describe.skip('-> cookie', function() {
        it('Выставление значения на сервере', function() {
            var callback = sinon.spy();
            app.on('cookie', callback);

            app.cookie('cookieName', 'cookieVal');
            assert.equal(app.cookie('cookieName'), 'cookieVal', 'app.cookie должен вернуть выставленное ранее значение');

            assert(callback.calledOnce, 'callback должен был быть вызван единажды');
        });

        it('Чтение на сервере клиентских кук', function() {
            var value = 'qwebaksfgahli8';

            app.init({
                cookies: {
                    key: value
                }
            });

            assert.equal(app.cookie('key'), value, 'app.cookie должен вернуть выставленное на клиенте значение');

            app.removeCookie('key');
            assert(!app.cookie('key'), 'app.cookie не должен вернуть выставленное на клиенте значение, ведь его удалили выше');
        });
    });

    describe('-> mod', function() {
        it('Вызов без аргументов', function(done) {
            try {
                appConfig.mod();
            } catch (e) {
                done();
            }
        });

        it('Вызов без объекта модификаторов', function() {
            app.internals.moduleDescriptors = {
                '1': {
                    moduleConf: {},
                    mods: {}
                }
            };

            var mods = appConfig.mod('1');

            assert.deepEqual(mods, {});
        });

        it('jQuery-like', function() {
            app.internals.moduleDescriptors = {
                '1': {
                    moduleConf: {},
                    mods: {}
                }
            };

            var val = appConfig.mod('1', 'key');
            assert.equal(val, undefined);

            val = appConfig.mod('1', 'key', 999);
            assert.deepEqual(val, {key: 999});

            val = appConfig.mod('1', 'key');
            assert.equal(val, 999);
        });

        it('Вызов с объектом модификаторов', function() {
            var setMods = {
                key: 'value',
                logic: true,
                'null': null,
                num: Infinity,
                nu: 999
            };

            app.internals.moduleDescriptors = {
                '1': {
                    moduleConf: {},
                    mods: {}
                }
            };

            var mods = appConfig.mod('1', setMods);

            assert.deepEqual(mods, setMods);

            mods = appConfig.mod('1');

            assert.deepEqual(mods, setMods);
        });

        it('Extend модификаторов', function() {
            var mods1 = {
                key: null
            };
            var mods2 = {
                key2: undefined
            };

            app.internals.moduleDescriptors = {
                '1': {
                    moduleConf: {},
                    mods: {}
                }
            };

            var mods = appConfig.mod('1', mods1);
            assert.deepEqual(mods, mods1);

            mods = appConfig.mod('1', mods2);
            assert.deepEqual(mods, _.extend(mods1, mods2));
        });

        it('modHandlers', function() {
            var setMods = {
                key: 'value',
                logic: true,
                'null': null,
                num: Infinity,
                nu: 999,
                u: undefined
            };

            app.internals.moduleDescriptors = {
                '1': {
                    moduleConf: {
                        modHandlers: {
                            num: function(val) {
                                settedVal = val;

                                var mods = appConfig.mod('1');
                                assert.deepEqual(mods, setMods, 'Модификатор уже должен быть выставлен, до вызова связанного modHandlers');
                            }
                        }
                    },
                    mods: {}
                }
            };

            var spy = sinon.spy(app.internals.moduleDescriptors['1'].moduleConf.modHandlers, 'num');

            appConfig.mod('1', setMods);

            assert(spy.withArgs(Infinity).calledOnce, 'Обработчик должен быть вызван 1 раз');
        });
    });
});<commit_msg>add tests for app.init #91<commit_after>var assert = require('assert');
var sinon = require('sinon');
var _ = require('lodash');

DEBUG = true;

describe('app', function() {
    var app,
        appIntance,
        appConfig;

    beforeEach(function() {
        app = require('../app.js')();
        appIntance = app.instance;
        appConfig = app.appConfig;
    });

    it('blank', function() {
        assert(app);
    });

    describe('-> init', function() {
        it('Правильное значение поля _stage', function() {
            appIntance.init({}, _.noop);
            assert(appIntance._stage == 'init', 'Поле _stage должно иметь значение "init"');
        });

        it('Данные записались в registry', function() {
            var data = {
                host: '1',
                protocol: '2',
                port: '3'
            };
            appIntance.init(data, _.noop);
            assert(appIntance.registry.get('host') == '1' && appIntance.registry.get('protocol') == '2' && appIntance.registry.get('port') == '3',
                'Переданные данные должны были записаться в registry');
        });

        it('Данные записались в cookie', function() {
            var data = {
                cookies: {
                    a: '1'
                }
            };
            appIntance.init(data, _.noop);
            assert(appIntance.cookie('a') == '1', 'Переданные cookie должны были записаться');
        });

        it('Вызывается callback после инициализации', function() {
            var callback = sinon.spy();
            appIntance.init({}, callback);
            assert(callback.calledOnce, 'Функция callback должны быть вызвана единажды');
        });

        it('Функции beforeInit выполняются, инициализация продолжается', function() {
            var beforeInit = sinon.spy(function(cb) {
                cb();
            });
            var callback = sinon.spy();

            appIntance.on('beforeInit', function(params) {
                params.waitFor(beforeInit);
            });

            appIntance.init({}, callback);
            assert(beforeInit.calledOnce, 'Функция beforeInit должны быть вызвана единажды');
            assert(callback.calledOnce, 'Функция callback должны быть вызвана единажды');
        });

        it('Функции beforeInit без коллбэка выполняются, инициализация продолжается', function() {
            var beforeInit = sinon.spy();
            var callback = sinon.spy();

            appIntance.on('beforeInit', function(params) {
                params.waitFor(beforeInit);
            });

            appIntance.init({}, callback);
            assert(beforeInit.calledOnce, 'Функция beforeInit должны быть вызвана единажды');
            assert(callback.calledOnce, 'Функция callback должны быть вызвана единажды');
        });

        it('Функции, переданные в beforeInit не являются функциями', function() {
            var callback = sinon.spy();

            appIntance.on('beforeInit', function(params) {
                params.waitFor();
            });

            appIntance.init({}, callback);
            assert(callback.calledOnce, 'Функция callback должны быть вызвана единажды, инициализация не сломалась');
        });
    });

    describe('-> resolveEntryPoint', function() {
        it('Не падает когда devPages нет в конфиге', function(done) {
            appConfig.config = {};
            appConfig.loadModule = function() {};

            appConfig.resolveEntryPoint();
            done();
        });
    });

    describe.skip('-> getModificators', function() {
        var mods;
        var appInstance;
        var moduleWrapper;

        before(function() {
            appInstance = app().instance;
            moduleWrapper = {
                type: 'online'
            };
        });

        it('Элемент moduleWrapper.block()[0] есть объект', function() {
            moduleWrapper.block = function() {
                return [{className: 'online_visible online_holy_glob'}];
            };
            mods = appInstance.getModificators(moduleWrapper);
            assert(!mods.visible, 'Пока не умеем распозновать модификаторы без значения типа online_visible');
            // пока умеем распозновать только модификаторы со значениями типа online_holy_glob => { holy: 'glob' }
            assert.ok(mods.holy == 'glob');
        });

        it('Элемент moduleWrapper.block()[0] есть null', function() {
            moduleWrapper.block = function() {
                return [null];
            };
            mods = appInstance.getModificators(moduleWrapper);
            assert.ok(mods);
        });
    });

    describe.skip('-> cookie', function() {
        it('Выставление значения на сервере', function() {
            var callback = sinon.spy();
            app.on('cookie', callback);

            app.cookie('cookieName', 'cookieVal');
            assert.equal(app.cookie('cookieName'), 'cookieVal', 'app.cookie должен вернуть выставленное ранее значение');

            assert(callback.calledOnce, 'callback должен был быть вызван единажды');
        });

        it('Чтение на сервере клиентских кук', function() {
            var value = 'qwebaksfgahli8';

            app.init({
                cookies: {
                    key: value
                }
            });

            assert.equal(app.cookie('key'), value, 'app.cookie должен вернуть выставленное на клиенте значение');

            app.removeCookie('key');
            assert(!app.cookie('key'), 'app.cookie не должен вернуть выставленное на клиенте значение, ведь его удалили выше');
        });
    });

    describe('-> mod', function() {
        it('Вызов без аргументов', function(done) {
            try {
                appConfig.mod();
            } catch (e) {
                done();
            }
        });

        it('Вызов без объекта модификаторов', function() {
            app.internals.moduleDescriptors = {
                '1': {
                    moduleConf: {},
                    mods: {}
                }
            };

            var mods = appConfig.mod('1');

            assert.deepEqual(mods, {});
        });

        it('jQuery-like', function() {
            app.internals.moduleDescriptors = {
                '1': {
                    moduleConf: {},
                    mods: {}
                }
            };

            var val = appConfig.mod('1', 'key');
            assert.equal(val, undefined);

            val = appConfig.mod('1', 'key', 999);
            assert.deepEqual(val, {key: 999});

            val = appConfig.mod('1', 'key');
            assert.equal(val, 999);
        });

        it('Вызов с объектом модификаторов', function() {
            var setMods = {
                key: 'value',
                logic: true,
                'null': null,
                num: Infinity,
                nu: 999
            };

            app.internals.moduleDescriptors = {
                '1': {
                    moduleConf: {},
                    mods: {}
                }
            };

            var mods = appConfig.mod('1', setMods);

            assert.deepEqual(mods, setMods);

            mods = appConfig.mod('1');

            assert.deepEqual(mods, setMods);
        });

        it('Extend модификаторов', function() {
            var mods1 = {
                key: null
            };
            var mods2 = {
                key2: undefined
            };

            app.internals.moduleDescriptors = {
                '1': {
                    moduleConf: {},
                    mods: {}
                }
            };

            var mods = appConfig.mod('1', mods1);
            assert.deepEqual(mods, mods1);

            mods = appConfig.mod('1', mods2);
            assert.deepEqual(mods, _.extend(mods1, mods2));
        });

        it('modHandlers', function() {
            var setMods = {
                key: 'value',
                logic: true,
                'null': null,
                num: Infinity,
                nu: 999,
                u: undefined
            };

            app.internals.moduleDescriptors = {
                '1': {
                    moduleConf: {
                        modHandlers: {
                            num: function(val) {
                                settedVal = val;

                                var mods = appConfig.mod('1');
                                assert.deepEqual(mods, setMods, 'Модификатор уже должен быть выставлен, до вызова связанного modHandlers');
                            }
                        }
                    },
                    mods: {}
                }
            };

            var spy = sinon.spy(app.internals.moduleDescriptors['1'].moduleConf.modHandlers, 'num');

            appConfig.mod('1', setMods);

            assert(spy.withArgs(Infinity).calledOnce, 'Обработчик должен быть вызван 1 раз');
        });
    });
});<|endoftext|>


<commit_before>'use strict';

function Expedition( NpolarApiSecurity, ExpeditionResource) {
  'ngInject';

  const schema = 'http://api.npolar.no/schema/expedition-1';

  return Object.assign(ExpeditionResource, {

     schema,

     create: function() {

      let ship_type = "researchVessel";
      let use_limitation = "none";
      let availability ="unrestricted";
      let lang = "en";

      //let id = PublicationResource.randomUUID();
      let e = {  ship_type, use_limitation, availability, lang };
      console.debug(e);
      return e;

    },

     hashiObject: function(file) {
       console.debug('hashiObject', file);
      return {
        url: file.uri,
        filename: file.filename,
        // icon
        length: file.file_size,
        md5sum: (file.hash||'md5:').split('md5:')[1],
        content_type: file.type
      };
    },

  fileObject: function(hashi) {
      console.debug('fileObject', hashi);
      return {
        uri: hashi.url,
        filename: hashi.filename,
        length: hashi.file_size,
        hash: 'md5:'+hashi.md5sum,
        type: hashi.content_type
      };
    }

 });

}
module.exports = Expedition;<commit_msg>removed ship_type<commit_after>'use strict';

function Expedition( NpolarApiSecurity, ExpeditionResource) {
  'ngInject';

  const schema = 'http://api.npolar.no/schema/expedition-1';

  return Object.assign(ExpeditionResource, {

     schema,

     create: function() {

      let use_limitation = "none";
      let availability ="unrestricted";
      let lang = "en";

      //let id = PublicationResource.randomUUID();
      let e = {  use_limitation, availability, lang };
      console.debug(e);
      return e;

    },

     hashiObject: function(file) {
       console.debug('hashiObject', file);
      return {
        url: file.uri,
        filename: file.filename,
        // icon
        length: file.file_size,
        md5sum: (file.hash||'md5:').split('md5:')[1],
        content_type: file.type
      };
    },

  fileObject: function(hashi) {
      console.debug('fileObject', hashi);
      return {
        uri: hashi.url,
        filename: hashi.filename,
        length: hashi.file_size,
        hash: 'md5:'+hashi.md5sum,
        type: hashi.content_type
      };
    }

 });

}
module.exports = Expedition;
<|endoftext|>


<commit_before>'use strict';

function Expedition( NpolarApiSecurity, ExpeditionResource) {
  'ngInject';

  const schema = 'http://api.npolar.no/schema/expedition-1';

  return Object.assign(ExpeditionResource, {

     schema,

     create: function() {

      let use_limitation = "none";
      let availability ="unrestricted";
      let lang = "en";

      //let id = PublicationResource.randomUUID();
      let e = {  use_limitation, availability, lang };
      console.debug(e);
      return e;

    },

     hashiObject: function(file) {
       console.debug('hashiObject', file);
      return {
        url: file.uri,
        filename: file.filename,
        // icon
        length: file.file_size,
        md5sum: (file.hash||'md5:').split('md5:')[1],
        content_type: file.type
      };
    },

  fileObject: function(hashi) {
      console.debug('fileObject', hashi);
      return {
        uri: hashi.url,
        filename: hashi.filename,
        length: hashi.file_size,
        hash: 'md5:'+hashi.md5sum,
        type: hashi.content_type
      };
    }

 });

}
module.exports = Expedition;
<commit_msg>restriction update<commit_after>'use strict';

function Expedition( NpolarApiSecurity, ExpeditionResource) {
  'ngInject';

  const schema = 'http://api.npolar.no/schema/expedition-1';

  return Object.assign(ExpeditionResource, {

     schema,

     create: function() {

      let availability ="by negotiation";
      let lang = "en";

      //let id = PublicationResource.randomUUID();
      let e = {  availability, lang };
      console.debug(e);
      return e;

    },

     hashiObject: function(file) {
       console.debug('hashiObject', file);
      return {
        url: file.uri,
        filename: file.filename,
        // icon
        length: file.file_size,
        md5sum: (file.hash||'md5:').split('md5:')[1],
        content_type: file.type
      };
    },

  fileObject: function(hashi) {
      console.debug('fileObject', hashi);
      return {
        uri: hashi.url,
        filename: hashi.filename,
        length: hashi.file_size,
        hash: 'md5:'+hashi.md5sum,
        type: hashi.content_type
      };
    }

 });

}
module.exports = Expedition;
<|endoftext|>


<commit_before>'use strict';

import Component from './Component.js';

describe('ES6 Component', function () {

  let component;
  let htmlElement;

  beforeEach(()=>{
    htmlElement = document.createElement('div');
    component = new Component(htmlElement);
  });

  it('.init method should be defined', ()=>{
    expect(component.init).to.not.be.an('undefined');
  });
  it('should fail', () => {
    expect(true).to.be.false;
  });
});<commit_msg>feat(karma) unit tests for Component/Component.js<commit_after>'use strict';

import Component from './Component.js';

describe('components/Component/Component.js', function () {

  let component;
  let htmlElement;

  beforeEach(()=>{
    htmlElement = document.createElement('div');
    component = new Component(htmlElement);
  });

  it('.init method should be defined', ()=>{
    expect(component.init).to.not.be.an('undefined');
  });
  it('.init() should return this', () => {
    expect(component.init()).to.be.an.instanceOf(Component);
  });
  it('.show() should display block', () => {
    component.show();
    expect(component.domNode.style.display).to.be.equal('block');
  });
  it('.hide() should display none', () => {
    component.hide();
    expect(component.domNode.style.display).to.be.equal('none');
  });
});<|endoftext|>