<commit_before>(function ($) {

    $(document).on("cmck", function (e, params) {

        switch (params.type) {

            case 'editForm.init':
            case 'sequenceForm.init':
            case 'sequenceForm.refresh':

                $('.formelement-file-modal-button').click(function () {

                    // get the input field
                    var input = $($(this).attr('data-input'));

                    parent.cmck_set_var('fe_file_property', input);

                    parent.cmck_modal($(this).attr('href'));

                    return false;
                });

                $('.formelement-file-modal-button-view').click(function () {

                    var id = $(this).attr('data-input');
                    var value = $(id).val();

                    $(parent.document).find('#modal_files_file_zoom_title').html(value);
                    $(parent.document).find('#modal_files_file_zoom_iframe').attr('src', $(this).attr('href') + value);

                    $.ajax({
                        url: $(this).attr('href') + value,
                        type: 'HEAD'
                    }).always(function (o) {
                        if (o.status == 404) { // ignore all other errors, especially missing Access-Control-Allow-Origin header
                            alert('File not found. Please check file path.');
                        }
                        else {
                            parent.cmck_modal_id('modal_files_file_zoom');
                        }
                    });

                    return false;
                });

                $('.formelement-file-modal-button-download').click(function () {

                    var id = $(this).attr('data-input');
                    var value = $(id).val();

                    if (value.trim() != '') {

                        value = $(this).attr('href') + value;

                        $.ajax({
                            url: value,
                            type: 'HEAD',
                            success: function () {
                                window.location.href = value;
                                return false;
                            },
                            error: function () {
                                alert('File not found. Please check file path.');
                            }
                        });
                    }

                    return false;
                });

                $('.formelement-file input, .formelement-image input').on('change', function () {

                    var id = '#' + $(this).attr('id') + '_preview';
                    var value = $(this).val();

                    $(id).hide();
                    $(id + ' a').attr('href', '');
                    $(id + ' img').attr('src', '');

                    if (value) {

                        if (value.toLowerCase().match(/\.(jpeg|jpg|gif|png)$/) != null) {
                            var url_view = $(this).attr('data-url-view') + value;

                            $.ajax({
                                url: url_view,
                                type: 'HEAD',
                                error: function () {
                                    $(id).hide();
                                },
                                success: function () {
                                    $(id).show();
                                    $(id + ' a').attr('href', url_view);
                                    $(id + ' img').attr('src', url_view);
                                }
                            });
                        }
                    }

                });
                break;

        }

    });

    /* ---------------------------------------- */
})(jQuery);

<commit_msg>again refactoring file existence check<commit_after>(function ($) {

    $(document).on("cmck", function (e, params) {

        switch (params.type) {

            case 'editForm.init':
            case 'sequenceForm.init':
            case 'sequenceForm.refresh':

                $('.formelement-file-modal-button').click(function () {

                    // get the input field
                    var input = $($(this).attr('data-input'));

                    parent.cmck_set_var('fe_file_property', input);

                    parent.cmck_modal($(this).attr('href'));

                    return false;
                });

                $('.formelement-file-modal-button-view').click(function () {

                    var id = $(this).attr('data-input');
                    var value = $(id).val();

                    $(parent.document).find('#modal_files_file_zoom_title').html(value);
                    $(parent.document).find('#modal_files_file_zoom_iframe').attr('src', $(this).attr('href') + value);

                    $.ajax({
                        url : $(this).attr('href') + value,
                        type: 'HEAD'
                    }).always(function (o) {

                        if (o != undefined && o.status == 404) { // ignore all other errors, especially missing Access-Control-Allow-Origin header
                            alert('File not found. Please check file path.');
                        }
                        else {
                            parent.cmck_modal_id('modal_files_file_zoom');
                        }
                    });

                    return false;
                });

                $('.formelement-file-modal-button-download').click(function () {

                    var id = $(this).attr('data-input');
                    var value = $(id).val();

                    if (value.trim() != '') {

                        value = $(this).attr('href') + value;

                        $.ajax({
                            url : value,
                            type: 'HEAD'
                        }).always(function (o) {

                            if (o != undefined && o.status == 404) { // ignore all other errors, especially missing Access-Control-Allow-Origin header
                                alert('File not found. Please check file path.');
                            }
                            else {
                                window.location.href = value;
                                return false;
                            }
                        });

                    }

                    return false;
                });

                $('.formelement-file input, .formelement-image input').on('change', function () {

                    var id = '#' + $(this).attr('id') + '_preview';
                    var value = $(this).val();

                    $(id).hide();
                    $(id + ' a').attr('href', '');
                    $(id + ' img').attr('src', '');

                    if (value) {

                        if (value.toLowerCase().match(/\.(jpeg|jpg|gif|png)$/) != null) {
                            var url_view = $(this).attr('data-url-view') + value;

                            $.ajax({
                                url    : url_view,
                                type   : 'HEAD',
                                error  : function () {
                                    $(id).hide();
                                },
                                success: function () {
                                    $(id).show();
                                    $(id + ' a').attr('href', url_view);
                                    $(id + ' img').attr('src', url_view);
                                }
                            });
                        }
                    }

                });
                break;

        }

    });

    /* ---------------------------------------- */
})(jQuery);

<|endoftext|>


<commit_before>define([
        '../Core/ArcType',
        '../Core/defaultValue',
        '../Core/defined',
        '../Core/defineProperties',
        '../Core/DeveloperError',
        '../Core/Event',
        './createMaterialPropertyDescriptor',
        './createPropertyDescriptor'
    ], function(
        ArcType,
        defaultValue,
        defined,
        defineProperties,
        DeveloperError,
        Event,
        createMaterialPropertyDescriptor,
        createPropertyDescriptor) {
    'use strict';

    /**
     * Describes a polyline. The first two positions define a line segment,
     * and each additional position defines a line segment from the previous position. The segments
     * can be linear connected points, great arcs, or clamped to terrain.
     *
     * @alias PolylineGraphics
     * @constructor
     *
     * @param {Object} [options] Object with the following properties:
     * @param {Property} [options.positions] A Property specifying the array of {@link Cartesian3} positions that define the line strip.
     * @param {ArcType} [options.arcType=ArcType.GEODESIC] The type of line the polyline segments must follow.
     * @param {Property} [options.clampToGround=false] A boolean Property specifying whether the Polyline should be clamped to the ground.
     * @param {Property} [options.width=1.0] A numeric Property specifying the width in pixels.
     * @param {Property} [options.show=true] A boolean Property specifying the visibility of the polyline.
     * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to draw the polyline.
     * @param {MaterialProperty} [options.depthFailMaterial] A property specifying the material used to draw the polyline when it is below the terrain.
     * @param {Property} [options.granularity=Cesium.Math.RADIANS_PER_DEGREE] A numeric Property specifying the angular distance between each latitude and longitude if arcType is not ArcType.NONE.
     * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the polyline casts or receives shadows from each light source.
     * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this polyline will be displayed.
     * @param {Property} [options.classificationType=ClassificationType.BOTH] An enum Property specifying whether this polyline will classify terrain, 3D Tiles, or both when on the ground.
     * @param {Property} [options.zIndex=0] A Property specifying the zIndex used for ordering ground geometry. Only has an effect if `clampToGround` is true and polylines on terrain is supported.
     *
     * @see Entity
     * @demo {@link https://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Polyline.html|Cesium Sandcastle Polyline Demo}
     */
    function PolylineGraphics(options) {
        this._show = undefined;
        this._showSubscription = undefined;
        this._material = undefined;
        this._materialSubscription = undefined;
        this._depthFailMaterial = undefined;
        this._depthFailMaterialSubscription = undefined;
        this._positions = undefined;
        this._positionsSubscription = undefined;
        this._followSurface = undefined;
        this._followSurfaceSubscription = undefined;
        this._arcType = undefined;
        this._arcTypeSubscription = undefined;
        this._clampToGround = undefined;
        this._clampToGroundSubscription = undefined;
        this._granularity = undefined;
        this._granularitySubscription = undefined;
        this._widthSubscription = undefined;
        this._width = undefined;
        this._widthSubscription = undefined;
        this._shadows = undefined;
        this._shadowsSubscription = undefined;
        this._distanceDisplayCondition = undefined;
        this._distanceDisplayConditionSubscription = undefined;
        this._classificationType = undefined;
        this._classificationTypeSubscription = undefined;
        this._zIndex = undefined;
        this._zIndexSubscription = undefined;

        this._definitionChanged = new Event();

        this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
    }

    defineProperties(PolylineGraphics.prototype, {
        /**
         * Gets the event that is raised whenever a property or sub-property is changed or modified.
         * @memberof PolylineGraphics.prototype
         *
         * @type {Event}
         * @readonly
         */
        definitionChanged : {
            get : function() {
                return this._definitionChanged;
            }
        },

        /**
         * Gets or sets the boolean Property specifying the visibility of the polyline.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default true
         */
        show : createPropertyDescriptor('show'),

        /**
         * Gets or sets the Property specifying the material used to draw the polyline.
         * @memberof PolylineGraphics.prototype
         * @type {MaterialProperty}
         * @default Color.WHITE
         */
        material : createMaterialPropertyDescriptor('material'),

        /**
         * Gets or sets the Property specifying the material used to draw the polyline when it fails the depth test.
         *

         * Requires the EXT_frag_depth WebGL extension to render properly. If the extension is not supported,
         * there may be artifacts.
         *

         * @memberof PolylineGraphics.prototype
         * @type {MaterialProperty}
         * @default undefined
         */
        depthFailMaterial : createMaterialPropertyDescriptor('depthFailMaterial'),

        /**
         * Gets or sets the Property specifying the array of {@link Cartesian3}
         * positions that define the line strip.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         */
        positions : createPropertyDescriptor('positions'),

        /**
         * Gets or sets the numeric Property specifying the width in pixels.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default 1.0
         */
        width : createPropertyDescriptor('width'),

        /**
         * Gets or sets the boolean Property specifying whether the line segments
         * should be great arcs or linearly connected.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @deprecated This property has been deprecated. Use {@link PolylineGraphics#arcType} instead.
         * @default true
         */
        followSurface : createPropertyDescriptor('followSurface'),

        /**
         * Gets or sets the {@link ArcType} Property specifying whether the line segments should be great arcs, rhumb lines or linearly connected.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @deprecated This property has been deprecated. Use {@link PolylineGraphics#arcType} instead.
         * @default ArcType.GEODESIC
         */
        arcType : createPropertyDescriptor('arcType'),

        /**
         * Gets or sets the boolean Property specifying whether the polyline
         * should be clamped to the ground.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default false
         */
        clampToGround : createPropertyDescriptor('clampToGround'),

        /**
         * Gets or sets the numeric Property specifying the angular distance between each latitude and longitude if arcType is not ArcType.NONE and clampToGround is false.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default Cesium.Math.RADIANS_PER_DEGREE
         */
        granularity : createPropertyDescriptor('granularity'),

        /**
         * Get or sets the enum Property specifying whether the polyline
         * casts or receives shadows from each light source.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default ShadowMode.DISABLED
         */
        shadows : createPropertyDescriptor('shadows'),

        /**
         * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this polyline will be displayed.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         */
        distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition'),

        /**
         * Gets or sets the {@link ClassificationType} Property specifying whether this polyline will classify terrain, 3D Tiles, or both when on the ground.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default ClassificationType.BOTH
         */
        classificationType : createPropertyDescriptor('classificationType'),

        /**
         * Gets or sets the zIndex Property specifying the ordering of the polyline. Only has an effect if `clampToGround` is true and polylines on terrain is supported.
         * @memberof RectangleGraphics.prototype
         * @type {ConstantProperty}
         * @default 0
         */
        zIndex : createPropertyDescriptor('zIndex')
    });

    /**
     * Duplicates this instance.
     *
     * @param {PolylineGraphics} [result] The object onto which to store the result.
     * @returns {PolylineGraphics} The modified result parameter or a new instance if one was not provided.
     */
    PolylineGraphics.prototype.clone = function(result) {
        if (!defined(result)) {
            return new PolylineGraphics(this);
        }
        result.show = this.show;
        result.material = this.material;
        result.depthFailMaterial = this.depthFailMaterial;
        result.positions = this.positions;
        result.width = this.width;
        result.followSurface = this.followSurface;
        result.arcType = this.arcType;
        result.clampToGround = this.clampToGround;
        result.granularity = this.granularity;
        result.shadows = this.shadows;
        result.distanceDisplayCondition = this.distanceDisplayCondition;
        result.classificationType = this.classificationType;
        result.zIndex = this.zIndex;

        return result;
    };

    /**
     * Assigns each unassigned property on this object to the value
     * of the same property on the provided source object.
     *
     * @param {PolylineGraphics} source The object to be merged into this object.
     */
    PolylineGraphics.prototype.merge = function(source) {
        //>>includeStart('debug', pragmas.debug);
        if (!defined(source)) {
            throw new DeveloperError('source is required.');
        }
        //>>includeEnd('debug');

        this.show = defaultValue(this.show, source.show);
        this.material = defaultValue(this.material, source.material);
        this.depthFailMaterial = defaultValue(this.depthFailMaterial, source.depthFailMaterial);
        this.positions = defaultValue(this.positions, source.positions);
        this.width = defaultValue(this.width, source.width);
        this.followSurface = defaultValue(this.followSurface, source.followSurface);
        this.arcType = defaultValue(this.arcType, source.arcType);
        this.clampToGround = defaultValue(this.clampToGround, source.clampToGround);
        this.granularity = defaultValue(this.granularity, source.granularity);
        this.shadows = defaultValue(this.shadows, source.shadows);
        this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
        this.classificationType = defaultValue(this.classificationType, source.classificationType);
        this.zIndex = defaultValue(this.zIndex, source.zIndex);
    };

    return PolylineGraphics;
});
<commit_msg>fix documentation error.<commit_after>define([
        '../Core/ArcType',
        '../Core/defaultValue',
        '../Core/defined',
        '../Core/defineProperties',
        '../Core/DeveloperError',
        '../Core/Event',
        './createMaterialPropertyDescriptor',
        './createPropertyDescriptor'
    ], function(
        ArcType,
        defaultValue,
        defined,
        defineProperties,
        DeveloperError,
        Event,
        createMaterialPropertyDescriptor,
        createPropertyDescriptor) {
    'use strict';

    /**
     * Describes a polyline. The first two positions define a line segment,
     * and each additional position defines a line segment from the previous position. The segments
     * can be linear connected points, great arcs, or clamped to terrain.
     *
     * @alias PolylineGraphics
     * @constructor
     *
     * @param {Object} [options] Object with the following properties:
     * @param {Property} [options.positions] A Property specifying the array of {@link Cartesian3} positions that define the line strip.
     * @param {ArcType} [options.arcType=ArcType.GEODESIC] The type of line the polyline segments must follow.
     * @param {Property} [options.clampToGround=false] A boolean Property specifying whether the Polyline should be clamped to the ground.
     * @param {Property} [options.width=1.0] A numeric Property specifying the width in pixels.
     * @param {Property} [options.show=true] A boolean Property specifying the visibility of the polyline.
     * @param {MaterialProperty} [options.material=Color.WHITE] A Property specifying the material used to draw the polyline.
     * @param {MaterialProperty} [options.depthFailMaterial] A property specifying the material used to draw the polyline when it is below the terrain.
     * @param {Property} [options.granularity=Cesium.Math.RADIANS_PER_DEGREE] A numeric Property specifying the angular distance between each latitude and longitude if arcType is not ArcType.NONE.
     * @param {Property} [options.shadows=ShadowMode.DISABLED] An enum Property specifying whether the polyline casts or receives shadows from each light source.
     * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this polyline will be displayed.
     * @param {Property} [options.classificationType=ClassificationType.BOTH] An enum Property specifying whether this polyline will classify terrain, 3D Tiles, or both when on the ground.
     * @param {Property} [options.zIndex=0] A Property specifying the zIndex used for ordering ground geometry. Only has an effect if `clampToGround` is true and polylines on terrain is supported.
     *
     * @see Entity
     * @demo {@link https://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Polyline.html|Cesium Sandcastle Polyline Demo}
     */
    function PolylineGraphics(options) {
        this._show = undefined;
        this._showSubscription = undefined;
        this._material = undefined;
        this._materialSubscription = undefined;
        this._depthFailMaterial = undefined;
        this._depthFailMaterialSubscription = undefined;
        this._positions = undefined;
        this._positionsSubscription = undefined;
        this._followSurface = undefined;
        this._followSurfaceSubscription = undefined;
        this._arcType = undefined;
        this._arcTypeSubscription = undefined;
        this._clampToGround = undefined;
        this._clampToGroundSubscription = undefined;
        this._granularity = undefined;
        this._granularitySubscription = undefined;
        this._widthSubscription = undefined;
        this._width = undefined;
        this._widthSubscription = undefined;
        this._shadows = undefined;
        this._shadowsSubscription = undefined;
        this._distanceDisplayCondition = undefined;
        this._distanceDisplayConditionSubscription = undefined;
        this._classificationType = undefined;
        this._classificationTypeSubscription = undefined;
        this._zIndex = undefined;
        this._zIndexSubscription = undefined;

        this._definitionChanged = new Event();

        this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
    }

    defineProperties(PolylineGraphics.prototype, {
        /**
         * Gets the event that is raised whenever a property or sub-property is changed or modified.
         * @memberof PolylineGraphics.prototype
         *
         * @type {Event}
         * @readonly
         */
        definitionChanged : {
            get : function() {
                return this._definitionChanged;
            }
        },

        /**
         * Gets or sets the boolean Property specifying the visibility of the polyline.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default true
         */
        show : createPropertyDescriptor('show'),

        /**
         * Gets or sets the Property specifying the material used to draw the polyline.
         * @memberof PolylineGraphics.prototype
         * @type {MaterialProperty}
         * @default Color.WHITE
         */
        material : createMaterialPropertyDescriptor('material'),

        /**
         * Gets or sets the Property specifying the material used to draw the polyline when it fails the depth test.
         *

         * Requires the EXT_frag_depth WebGL extension to render properly. If the extension is not supported,
         * there may be artifacts.
         *

         * @memberof PolylineGraphics.prototype
         * @type {MaterialProperty}
         * @default undefined
         */
        depthFailMaterial : createMaterialPropertyDescriptor('depthFailMaterial'),

        /**
         * Gets or sets the Property specifying the array of {@link Cartesian3}
         * positions that define the line strip.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         */
        positions : createPropertyDescriptor('positions'),

        /**
         * Gets or sets the numeric Property specifying the width in pixels.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default 1.0
         */
        width : createPropertyDescriptor('width'),

        /**
         * Gets or sets the boolean Property specifying whether the line segments
         * should be great arcs or linearly connected.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @deprecated This property has been deprecated. Use {@link PolylineGraphics#arcType} instead.
         * @default true
         */
        followSurface : createPropertyDescriptor('followSurface'),

        /**
         * Gets or sets the {@link ArcType} Property specifying whether the line segments should be great arcs, rhumb lines or linearly connected.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default ArcType.GEODESIC
         */
        arcType : createPropertyDescriptor('arcType'),

        /**
         * Gets or sets the boolean Property specifying whether the polyline
         * should be clamped to the ground.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default false
         */
        clampToGround : createPropertyDescriptor('clampToGround'),

        /**
         * Gets or sets the numeric Property specifying the angular distance between each latitude and longitude if arcType is not ArcType.NONE and clampToGround is false.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default Cesium.Math.RADIANS_PER_DEGREE
         */
        granularity : createPropertyDescriptor('granularity'),

        /**
         * Get or sets the enum Property specifying whether the polyline
         * casts or receives shadows from each light source.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default ShadowMode.DISABLED
         */
        shadows : createPropertyDescriptor('shadows'),

        /**
         * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this polyline will be displayed.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         */
        distanceDisplayCondition : createPropertyDescriptor('distanceDisplayCondition'),

        /**
         * Gets or sets the {@link ClassificationType} Property specifying whether this polyline will classify terrain, 3D Tiles, or both when on the ground.
         * @memberof PolylineGraphics.prototype
         * @type {Property}
         * @default ClassificationType.BOTH
         */
        classificationType : createPropertyDescriptor('classificationType'),

        /**
         * Gets or sets the zIndex Property specifying the ordering of the polyline. Only has an effect if `clampToGround` is true and polylines on terrain is supported.
         * @memberof RectangleGraphics.prototype
         * @type {ConstantProperty}
         * @default 0
         */
        zIndex : createPropertyDescriptor('zIndex')
    });

    /**
     * Duplicates this instance.
     *
     * @param {PolylineGraphics} [result] The object onto which to store the result.
     * @returns {PolylineGraphics} The modified result parameter or a new instance if one was not provided.
     */
    PolylineGraphics.prototype.clone = function(result) {
        if (!defined(result)) {
            return new PolylineGraphics(this);
        }
        result.show = this.show;
        result.material = this.material;
        result.depthFailMaterial = this.depthFailMaterial;
        result.positions = this.positions;
        result.width = this.width;
        result.followSurface = this.followSurface;
        result.arcType = this.arcType;
        result.clampToGround = this.clampToGround;
        result.granularity = this.granularity;
        result.shadows = this.shadows;
        result.distanceDisplayCondition = this.distanceDisplayCondition;
        result.classificationType = this.classificationType;
        result.zIndex = this.zIndex;

        return result;
    };

    /**
     * Assigns each unassigned property on this object to the value
     * of the same property on the provided source object.
     *
     * @param {PolylineGraphics} source The object to be merged into this object.
     */
    PolylineGraphics.prototype.merge = function(source) {
        //>>includeStart('debug', pragmas.debug);
        if (!defined(source)) {
            throw new DeveloperError('source is required.');
        }
        //>>includeEnd('debug');

        this.show = defaultValue(this.show, source.show);
        this.material = defaultValue(this.material, source.material);
        this.depthFailMaterial = defaultValue(this.depthFailMaterial, source.depthFailMaterial);
        this.positions = defaultValue(this.positions, source.positions);
        this.width = defaultValue(this.width, source.width);
        this.followSurface = defaultValue(this.followSurface, source.followSurface);
        this.arcType = defaultValue(this.arcType, source.arcType);
        this.clampToGround = defaultValue(this.clampToGround, source.clampToGround);
        this.granularity = defaultValue(this.granularity, source.granularity);
        this.shadows = defaultValue(this.shadows, source.shadows);
        this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
        this.classificationType = defaultValue(this.classificationType, source.classificationType);
        this.zIndex = defaultValue(this.zIndex, source.zIndex);
    };

    return PolylineGraphics;
});
<|endoftext|>


<commit_before>$(document).ready( function() {
    //  Super wonky includes
    $.getScript("../Utility/input_validation.js");

    //  global variables
    var startInput = $("#startDate");
    var endInput = $("#endDate");
    var dueInput = $("#dueDate");
    var statsStartEndText = $("#statsStartToEnd");
    var statsDueStartText = $("#statsDueToStart");
    var submitButton = $("#submitButton");
    var resetButton = $("#resetButton");

    //  function to validate input before enabling the submit button
    function validateInput() {
        if (submitButton.val().length > 0 &&
                dateIsValid(startDate.val()) &&
                dateIsValid(endDate.val()) &&
                dateIsValid(dueDate.val())) {
            submitButton.prop("disabled", false);
        }
    }

    //  function to update statistics of term
    function updateStats() {
        //  horrifyingly large ammount of variables required for calculations
        var msecs_to_day = 1000*60*60*24;
        var day_names = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
        var startDate = new Date(startInput.val());
        var endDate = new Date(endInput.val());
        var startMsec = startDate.getTime();
        var endMsec = endDate.getTime();
        var dueMsec = (new Date(dueInput.val())).getTime();
        var start_to_end_days = Math.ceil((endMsec - startMsec) / msecs_to_day);
        var start_to_end_weeks = Math.ceil(start_to_end_days / 7);
        var due_to_start_days = Math.ceil((startMsec - dueMsec) / msecs_to_day);

        //  calculates term duration
        if (startInput.val() != "" && endInput.val() != "") {
            statsStartEndText.text("Term Duration: ~" + start_to_end_weeks + " weeks (" + start_to_end_days + " days), " + day_names[startDate.getDay()] + " to " + day_names[endDate.getDay()]);
        } else {
            statsStartEndText.text("Term Duration: UNKNOWN");
        }

        //  calculates time between due date and start of term
        if (startInput.val() != "" && dueInput.val() != "") {
            statsDueStartText.text("Due Date: " + due_to_start_days + " days before start");
        } else {
            statsDueStartText.text("Due Date: UNKNOWN");
        }

        // statsObj.text("Due  --- " + due_to_start_days + " days --->  Start  --- " + start_to_end_weeks + " weeks --->  End");
    }

    //  initialized JQuery datepickers
    startInput.datepicker();
    endInput.datepicker();
    dueInput.datepicker();

    //  function for when start date is changed/selected
    startInput.change( function() {
        if ($(this).val() != "") {
            //  variables
            var currentStart = $(this).datepicker("getDate");
            var defaultEnd = new Date(currentStart);
            var endMin = new Date(currentStart);
            var defaultDue = new Date(currentStart);
            var dueMax = new Date(currentStart);

            //  calculate default dates for end and due dates
            defaultEnd.setDate(currentStart.getDate() + 76);
            endMin.setDate(currentStart.getDate() + 1);
            defaultDue.setDate(currentStart.getDate() - 7);
            dueMax.setDate(currentStart.getDate() - 1);

            //  enable end date, set default date and min date
            endInput.datepicker("option", {
                defaultDate: defaultEnd,
                minDate: endMin,
                disabled: false
            });
            //enable due date, set default date and max date
            endInput.val(defaultEnd.toLocaleDateString());
            dueInput.datepicker("option", {
                defaultDate: defaultDue,
                maxDate: dueMax,
                disabled: false
            });
            dueInput.val(defaultDue.toLocaleDateString());

            //  update term stats
            updateStats();
            validateInput();
        }
    });

    //  update stats when end date changed/selected
    endInput.change( function() {
        if ($(this).val() != "") { updateStats(); }
        validateInput();
    });

    //  update stats when due date changed/selected
    dueInput.change( function() {
        if ($(this).val() != "") { updateStats(); }
        validateInput();
    });

    resetButton.click( function() {
        endDate.prop("disabled", true);
        dueDate.prop("disabled", true);
});
<commit_msg>US206 - more bug fixes<commit_after>$(document).ready( function() {
    //  Super wonky includes
    $.getScript("../Utility/input_validation.js");

    //  global variables
    var startInput = $("#startDate");
    var endInput = $("#endDate");
    var dueInput = $("#dueDate");
    var statsStartEndText = $("#statsStartToEnd");
    var statsDueStartText = $("#statsDueToStart");
    var submitButton = $("#submitButton");
    var resetButton = $("#resetButton");

    //  function to validate input before enabling the submit button
    function validateInput() {
        if (submitButton.val().length > 0 &&
                dateIsValid(startDate.val()) &&
                dateIsValid(endDate.val()) &&
                dateIsValid(dueDate.val())) {
            submitButton.prop("disabled", false);
        }
    }

    //  function to update statistics of term
    function updateStats() {
        //  horrifyingly large ammount of variables required for calculations
        var msecs_to_day = 1000*60*60*24;
        var day_names = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
        var startDate = new Date(startInput.val());
        var endDate = new Date(endInput.val());
        var startMsec = startDate.getTime();
        var endMsec = endDate.getTime();
        var dueMsec = (new Date(dueInput.val())).getTime();
        var start_to_end_days = Math.ceil((endMsec - startMsec) / msecs_to_day);
        var start_to_end_weeks = Math.ceil(start_to_end_days / 7);
        var due_to_start_days = Math.ceil((startMsec - dueMsec) / msecs_to_day);

        //  calculates term duration
        if (startInput.val() != "" && endInput.val() != "") {
            statsStartEndText.text("Term Duration: ~" + start_to_end_weeks + " weeks (" + start_to_end_days + " days), " + day_names[startDate.getDay()] + " to " + day_names[endDate.getDay()]);
        } else {
            statsStartEndText.text("Term Duration: UNKNOWN");
        }

        //  calculates time between due date and start of term
        if (startInput.val() != "" && dueInput.val() != "") {
            statsDueStartText.text("Due Date: " + due_to_start_days + " days before start");
        } else {
            statsDueStartText.text("Due Date: UNKNOWN");
        }

        // statsObj.text("Due  --- " + due_to_start_days + " days --->  Start  --- " + start_to_end_weeks + " weeks --->  End");
    }

    //  initialized JQuery datepickers
    startInput.datepicker();
    endInput.datepicker();
    dueInput.datepicker();

    //  function for when start date is changed/selected
    startInput.change( function() {
        if ($(this).val() != "") {
            //  variables
            var currentStart = $(this).datepicker("getDate");
            var defaultEnd = new Date(currentStart);
            var endMin = new Date(currentStart);
            var defaultDue = new Date(currentStart);
            var dueMax = new Date(currentStart);

            //  calculate default dates for end and due dates
            defaultEnd.setDate(currentStart.getDate() + 76);
            endMin.setDate(currentStart.getDate() + 1);
            defaultDue.setDate(currentStart.getDate() - 7);
            dueMax.setDate(currentStart.getDate() - 1);

            //  enable end date, set default date and min date
            endInput.datepicker("option", {
                defaultDate: defaultEnd,
                minDate: endMin,
                disabled: false
            });
            //enable due date, set default date and max date
            endInput.val(defaultEnd.toLocaleDateString());
            dueInput.datepicker("option", {
                defaultDate: defaultDue,
                maxDate: dueMax,
                disabled: false
            });
            dueInput.val(defaultDue.toLocaleDateString());

            //  update term stats
            updateStats();
            validateInput();
        }
    });

    //  update stats when end date changed/selected
    endInput.change( function() {
        if ($(this).val() != "") { updateStats(); }
        validateInput();
    });

    //  update stats when due date changed/selected
    dueInput.change( function() {
        if ($(this).val() != "") { updateStats(); }
        validateInput();
    });

    resetButton.click( function() {
        endInput.prop("disabled", true);
        dueInput.prop("disabled", true);
    });
});
<|endoftext|>


<commit_before>var makeChannel = require('./channel');

module.exports = wrapNodeSocket;

// Given a duplex node stream, return a culvert duplex channel.
function wrapNodeSocket(socket, reportError) {
  // Data traveling from node socket to consumer
  var incoming = makeChannel();
  // Data traveling from consumer to node socket
  var outgoing = makeChannel();

  var onDrain2 = wrapHandler(onReadable, onError);
  onTake = wrapHandler(onTake, onError);

  var paused = false;
  var ended = false;

  outgoing.take(onTake);
  socket.on("error", onError);
  socket.on("drain", wrap(onDrain, onError));
  socket.on("readable", wrap(onReadable, onError));
  socket.on("end", wrap(onEnd, onError));

  function onError(err) {
    if (err.code === "EPIPE" || err.code === "ECONNRESET") {
      return onEnd();
    }
    if (reportError) return reportError(err);
    console.error(err.stack);
  }

  function onTake(data) {
    if (ended) return;
    // console.log("TAKE", data);
    if (data === undefined) {
      ended = true;
      return socket.end();
    }
    if (socket.write(data)) {
      outgoing.take(onTake);
    }
    else {
      if (!paused) paused = true;
    }
  }

  function onDrain() {
    if (paused) {
      paused = false;
      outgoing.take(onTake);
    }
  }

  function onEnd() {
    if (ended) return;
    ended = true;
    incoming.put(undefined);
  }

  function onReadable() {
    if (ended) return;
    while (true) {
      var chunk = socket.read();
      // console.log("READ", chunk);
      if (!chunk) return;
      if (!incoming.put(chunk)) {
        incoming.drain(onDrain2);
        return;
      }
    }
  }

  var originalOut = outgoing.put;
  var originalInn = incoming.put;

  function setCodecs() {
    var out = originalOut;
    var inn = originalInn;
    for (var i = 0, l = arguments.length; i < l; ++i) {
      var codec = arguments[i];
      if (codec.encoder) out = codec.encoder(out);
      if (codec.decoder) inn = codec.decoder(inn);
    }
    outgoing.put = out;
    incoming.put = inn;
  }

  return {
    put: function (item) {
      return outgoing.put(item);
    },
    drain: outgoing.drain,
    take: incoming.take,
    setCodecs: setCodecs
  };
}

function wrap(fn, onError) {
  if (!onError) return fn;
  return function (value) {
    try {
      return fn(value);
    }
    catch (err) {
      return onError(err);
    }
  };
}

function wrapHandler(fn, onError) {
  if (!onError) {
    return function (err, value) {
      if (err) throw err;
      return fn(value);
    };
  }
  return function (err, value) {
    if (err) return onError(err);
    try {
      return fn(value);
    }
    catch (err) {
      return onError(err);
    }
  };
}<commit_msg>Expose more codec mutating<commit_after>var makeChannel = require('./channel');

module.exports = wrapNodeSocket;

// Given a duplex node stream, return a culvert duplex channel.
function wrapNodeSocket(socket, reportError) {
  // Data traveling from node socket to consumer
  var incoming = makeChannel();
  // Data traveling from consumer to node socket
  var outgoing = makeChannel();

  var onDrain2 = wrapHandler(onReadable, onError);
  onTake = wrapHandler(onTake, onError);

  var codecs = [];

  var paused = false;
  var ended = false;

  outgoing.take(onTake);
  socket.on("error", onError);
  socket.on("drain", wrap(onDrain, onError));
  socket.on("readable", wrap(onReadable, onError));
  socket.on("end", wrap(onEnd, onError));

  function onError(err) {
    if (err.code === "EPIPE" || err.code === "ECONNRESET") {
      return onEnd();
    }
    if (reportError) return reportError(err);
    console.error(err.stack);
  }

  function onTake(data) {
    if (ended) return;
    // console.log("TAKE", data);
    if (data === undefined) {
      ended = true;
      return socket.end();
    }
    if (socket.write(data)) {
      outgoing.take(onTake);
    }
    else {
      if (!paused) paused = true;
    }
  }

  function onDrain() {
    if (paused) {
      paused = false;
      outgoing.take(onTake);
    }
  }

  function onEnd() {
    if (ended) return;
    ended = true;
    incoming.put(undefined);
  }

  function onReadable() {
    if (ended) return;
    while (true) {
      var chunk = socket.read();
      // console.log("READ", chunk);
      if (!chunk) return;
      if (!incoming.put(chunk)) {
        incoming.drain(onDrain2);
        return;
      }
    }
  }

  var originalOut = outgoing.put;
  var originalInn = incoming.put;

  function setCodecs() {
    var out = originalOut;
    var inn = originalInn;
    codecs = [].slice.call(arguments);
    for (var i = 0, l = arguments.length; i < l; ++i) {
      var codec = arguments[i];
      if (codec.encoder) out = codec.encoder(out);
      if (codec.decoder) inn = codec.decoder(inn);
    }
    outgoing.put = out;
    incoming.put = inn;
  }

  function getCodecs() {
    return codecs;
  }

  function addCodec(codec) {
    codecs.push(codec);
    if (codec.encoder) outgoing.put = codec.encoder(outgoing.put);
    if (codec.decoder) incoming.put = codec.decoder(incoming.put);
  }

  return {
    put: function (item) {
      return outgoing.put(item);
    },
    drain: outgoing.drain,
    take: incoming.take,
    setCodecs: setCodecs,
    getCodecs: getCodecs,
    addCodec: addCodec,
  };
}

function wrap(fn, onError) {
  if (!onError) return fn;
  return function (value) {
    try {
      return fn(value);
    }
    catch (err) {
      return onError(err);
    }
  };
}

function wrapHandler(fn, onError) {
  if (!onError) {
    return function (err, value) {
      if (err) throw err;
      return fn(value);
    };
  }
  return function (err, value) {
    if (err) return onError(err);
    try {
      return fn(value);
    }
    catch (err) {
      return onError(err);
    }
  };
}<|endoftext|>


<commit_before>import Ember from 'ember';
import layout from '../templates/components/notification-list';

export default Ember.Component.extend({
  layout,

  classNameBindings: ['importantNotifications:has-important-notifications'],

  ordering: ['important:desc', 'created:desc'],

  /**
   * Notifications to show.
   *
   * @type {Ember.Array}
   */
  notifications: [],

  /**
   * Number of notifications to show.
   *
   * @type {Number}
   */
  numNotifications: 3,

  /**
   * Whether the notification list should be rendered.
   *
   * @type {Boolean}
   */
  renderNotifications: false,

  /**
   * Text to show if there are no notifications.
   *
   * @type {String}
   */
  noNotificationsText: 'You have no notifications yet.',

  /**
   * Notifications ordered by importance and date.
   *
   * @type {Ember.Array}
   */
  orderedNotifications: Ember.computed.sort('notifications', 'ordering'),

  /**
   * The `numNotifications` first notifications, ordered by importance and
   * date.
   *
   * @type {Ember.Array}
   */
  topNotifications: Ember.computed('orderedNotifications', function () {
    const notifications = this.get('orderedNotifications');

    return notifications.slice(0, this.get('numNotifications'));
  }),

  importantNotifications: Ember.computed.filterBy(
    'orderedNotifications', 'important'
  ),

  /**
   * Show the list of notifications.
   *
   * Notifications not previously seen get their `seen` attribute set to true.
   */
  showNotifications () {
    this.set('renderNotifications', true);

    this.get('topNotifications').filterBy('seen', false).forEach(unseen => {
      unseen.set('seen', true);
      unseen.save();
    });
  },

  /**
   * Hide the list of notifications.
   */
  hideNotifications () {
    this.set('renderNotifications', false);
  },

  /**
   * Add an event listener on the document for hiding the notification list
   * when clicks happen outside it.
   */
  setupEventListeners: Ember.on('didInsertElement', function () {
    const documentClickEvent = event => {
      if (!this.element.contains(event.target)) {
        this.hideNotifications();
      }
    };

    this.set('_documentClickEvent', documentClickEvent);

    document.addEventListener('click', documentClickEvent, true);
  }),

  /**
   * Remove the click event listener on the document.
   */
  cleanupDocumentEventListener: Ember.on('willDestroyElement', function () {
    document.removeEventListener(
      'click', this.get('_documentClickEvent'), true
    );
  }),

  actions: {
    /**
     * Toggle visibility of the notification list.
     */
    toggleVisibility () {
      if (this.get('renderNotifications')) {
        this.hideNotifications();
      }
      else {
        this.showNotifications();
      }
    },
  },
});
<commit_msg>Fix binding of important notifications class<commit_after>import Ember from 'ember';
import layout from '../templates/components/notification-list';

export default Ember.Component.extend({
  layout,

  classNameBindings: ['hasImportantNotifications'],

  ordering: ['important:desc', 'created:desc'],

  /**
   * Notifications to show.
   *
   * @type {Ember.Array}
   */
  notifications: [],

  /**
   * Number of notifications to show.
   *
   * @type {Number}
   */
  numNotifications: 3,

  /**
   * Whether the notification list should be rendered.
   *
   * @type {Boolean}
   */
  renderNotifications: false,

  /**
   * Text to show if there are no notifications.
   *
   * @type {String}
   */
  noNotificationsText: 'You have no notifications yet.',

  /**
   * Notifications ordered by importance and date.
   *
   * @type {Ember.Array}
   */
  orderedNotifications: Ember.computed.sort('notifications', 'ordering'),

  /**
   * The `numNotifications` first notifications, ordered by importance and
   * date.
   *
   * @type {Ember.Array}
   */
  topNotifications: Ember.computed('orderedNotifications', function () {
    const notifications = this.get('orderedNotifications');

    return notifications.slice(0, this.get('numNotifications'));
  }),

  importantNotifications: Ember.computed.filterBy(
    'orderedNotifications', 'important'
  ),

  hasImportantNotifications: Ember.computed.notEmpty('importantNotifications'),

  /**
   * Show the list of notifications.
   *
   * Notifications not previously seen get their `seen` attribute set to true.
   */
  showNotifications () {
    this.set('renderNotifications', true);

    this.get('topNotifications').filterBy('seen', false).forEach(unseen => {
      unseen.set('seen', true);
      unseen.save();
    });
  },

  /**
   * Hide the list of notifications.
   */
  hideNotifications () {
    this.set('renderNotifications', false);
  },

  /**
   * Add an event listener on the document for hiding the notification list
   * when clicks happen outside it.
   */
  setupEventListeners: Ember.on('didInsertElement', function () {
    const documentClickEvent = event => {
      if (!this.element.contains(event.target)) {
        this.hideNotifications();
      }
    };

    this.set('_documentClickEvent', documentClickEvent);

    document.addEventListener('click', documentClickEvent, true);
  }),

  /**
   * Remove the click event listener on the document.
   */
  cleanupDocumentEventListener: Ember.on('willDestroyElement', function () {
    document.removeEventListener(
      'click', this.get('_documentClickEvent'), true
    );
  }),

  actions: {
    /**
     * Toggle visibility of the notification list.
     */
    toggleVisibility () {
      if (this.get('renderNotifications')) {
        this.hideNotifications();
      }
      else {
        this.showNotifications();
      }
    },
  },
});
<|endoftext|>


<commit_before>/* jshint expr: true */
import Ember from 'ember';
import layout from '../templates/components/power-select-tree';
const { get, set, isBlank, computed, A, Component, $ } = Ember;

export default Component.extend({
  layout,
  classNames: ['ember-power-select-tree'],
  defaultLabelOpt: 'label',
  __selectedOptions: null,
  advancedTreeOptions: computed('treeOptions.[]', function() {
    return A(get(this, 'treeOptions'))
      .map(o => this._collapsableOption(o))
      .map(o => this._buildPath(o));
  }),
  currentOptions: computed('advancedTreeOptions.[]', '__selectedOptions.[]', function() {
    const __selectedOptions = get(this, '__selectedOptions');
    return get(this, 'advancedTreeOptions')
      .map(o => this._treeTraverse(o, (node) => this._setChecked(node, __selectedOptions)));
  }),

  groupedSelectedOptions: computed('__selectedOptions.[]', function() {
    return A(get(this, '__selectedOptions')).reduce((prev, curr) => {
      const humanPath = get(curr, 'humanPath') || '';
      const group = prev.findBy('humanPath', humanPath);
      if (group) {
        get(group, 'options').pushObject(curr);
      } else {
        prev.pushObject(
          {humanPath, options: A([curr]),
          nodeName: get(A(humanPath.split(' > ')), 'lastObject')});
      }

      return prev;
    }, A()).sortBy('humanPath');
  }),

  init() {
    this._super(...arguments);

    if (!get(this, 'labelOpt')) {
      set(this, 'labelOpt', get(this, 'defaultLabelOpt'));
    }

    this._setSelectedOptions();
  },

  didReceiveAttrs() {
    this._super(...arguments);
    if (!isBlank(get(this, 'selectedOptions'))) {
      this._setSelectedOptions();
    }
  },

  _setSelectedOptions() {
    const selectedOptions = A(get(this, 'selectedOptions'));
    let leaves = get(this, 'advancedTreeOptions')
      .map(o => this._treeTraverse(o, (node) => this._setChecked(node, selectedOptions)))
      .map(o => this._getLeaves(o));
    let node;
    let filteredOptions = selectedOptions.map(opt => {
      node = [].concat(...leaves).find(
        leaf => get(opt, 'key') === get(leaf, 'key') && get(opt, 'type') === get(leaf, 'type')
      );
      return node ? node : opt;
    });
    set(this, '__selectedOptions', isBlank(selectedOptions) ? A() : filteredOptions);
  },

  _setChecked(o, __selectedOptions, isChecked = true) {
    if (A(__selectedOptions).find(
      opt => get(opt, 'key') === get(o, 'key') && get(opt, 'type') === get(o, 'type')
    )) {
      set(o, 'isChecked', isChecked);
    }
  },

  _buildPath(node, currPath = A()) {
    let newNode = Ember.$.extend(true, {}, node);
    const path = get(node, 'path');
    if (path && path.length) {
      set(newNode, 'humanPath', path.join(' > '));
      return newNode;
    }

    if (!get(node, 'nodeName') && currPath.length) {
      set(newNode, 'humanPath', currPath.join(' > '));
      set(newNode, 'path', currPath);
    } else {
      currPath.push(get(node, 'nodeName'));
      set(newNode, 'options', A(get(node, 'options')).map(
        o => this._buildPath(o, [].concat(...currPath)))
      );
      currPath = A();
    }

    return newNode;
  },

  _collapsableOption(opt) {
    const isSelectable = get(opt, 'isSelectable');
    const isChecked = leaf => get(leaf, 'isChecked');
    const isOptChecked = get(opt, 'isChecked');
    const groupName = get(opt, 'groupName');
    const options = get(opt, 'options') || [];
    const isCollapsed = get(opt, 'isCollapsed') || true;
    if (groupName) {
      return {
        isSelectable,
        isCollapsed,
        isChecked: options.some(isChecked) || isOptChecked || false,
        nodeName: groupName,
        options: options.map(o => this._collapsableOption(o))
      };
    }

    set(opt, 'isSelectable', true);
    set(opt, 'isChecked', !!isOptChecked);
    return opt;
  },

  _getLeaves(root, leaves = A()) {
    (get(root, 'options') || A()).forEach(
      o => !o.nodeName ? leaves.pushObject(o) : this._getLeaves(o, leaves)
    );
    return leaves;
  },

  _treeTraverse(root, visit) {
    visit(root);
    const options = A(get(root, 'options'));
    if (options.length) {
      options.forEach(o => this._treeTraverse(o, visit));
    }

    return root;
  },

  _findInternalNode(root, nameOrPath) {
    if (get(root, 'nodeName') === nameOrPath || get(root, 'humanPath') === nameOrPath) {
      return root;
    }
    let tmp, node;
    A(get(root, 'options')).forEach(o => {
      tmp = this._findInternalNode(o, nameOrPath);
      if (tmp) {
        node = tmp;
      }
    });

    return node;
  },

  onTreeSelectionChange(opts) {
    return get(this, 'onTreeSelectionChange')(opts);
  },

  scrollDropdownToSelected(el) {
    const container = $('.ember-power-select-tree-list').first();
    const scrollTop = $(el).offset().top - container.offset().top + container.scrollTop();
    return container.animate({ scrollTop }, 500);
  },

  actions: {
    handleSearch() {
      get(this, 'handleSearch')(...arguments);
      return false; // prevents default searching behaviour
    },
    onToggleGroup(group, evt) {
      // Check if checkbox or container is clicked
      const tagName = get(evt, 'target.tagName').toLowerCase();
      if (tagName === 'label' || tagName === 'input') {
        return;
      }
      set(group, 'isCollapsed', !get(group, 'isCollapsed'));

      return this.scrollDropdownToSelected(get(evt, 'target'));
    },
    removeNodeOrLeaf(nodeOrLeaf) {
      const __selectedOptions = get(this, '__selectedOptions');
      const isNode = !get(nodeOrLeaf, 'key');
      const key = isNode ? 'humanPath' : 'key';
      __selectedOptions.removeObjects(
        __selectedOptions.filterBy(key, get(nodeOrLeaf, key))
      );
      this._treeTraverse(nodeOrLeaf, o => set(o, 'isChecked', false));
      if (isNode) { // unchecks the group itself
        set(
          this._findInternalNode(
            {options: get(this, 'currentOptions')},
            get(nodeOrLeaf, 'nodeName') || get(nodeOrLeaf, 'humanPath')), 'isChecked', false
        );
      }
      set(this, '__selectedOptions', __selectedOptions);
    },
    handleChecked(nodeOrLeaf) {
      const newVal = !get(nodeOrLeaf, 'isChecked');
      const _setChecked = node => set(node, 'isChecked', newVal);
      const __selectedOptions = A(get(this, '__selectedOptions'));
      const __selectedOptionsKeys = __selectedOptions.map(o => get(o, 'key'));
      const nodeKey = get(nodeOrLeaf, 'key');
      const leaves = this._getLeaves(nodeOrLeaf);

      this._treeTraverse(nodeOrLeaf, _setChecked);

      if (get(nodeOrLeaf, 'nodeName')) {
        !newVal ?
          leaves.forEach(l => __selectedOptions.removeObject(__selectedOptions.findBy('key', get(l, 'key')))) :
          __selectedOptions.pushObjects(leaves.filter(l => !__selectedOptionsKeys.includes(get(l, 'key'))));
      } else {
        !newVal ?
          __selectedOptions.removeObject(__selectedOptions.findBy('key', nodeKey)) :
          __selectedOptions.pushObject(nodeOrLeaf);
      }

      set(this, '__selectedOptions', __selectedOptions);
      this.onTreeSelectionChange(__selectedOptions);
    }
  }
});
<commit_msg>FIX: always set humanPath<commit_after>/* jshint expr: true */
import Ember from 'ember';
import layout from '../templates/components/power-select-tree';
const { get, set, isBlank, computed, A, Component, $ } = Ember;

export default Component.extend({
  layout,
  classNames: ['ember-power-select-tree'],
  defaultLabelOpt: 'label',
  __selectedOptions: null,
  advancedTreeOptions: computed('treeOptions.[]', function() {
    return A(get(this, 'treeOptions'))
      .map(o => this._collapsableOption(o))
      .map(o => this._buildPath(o));
  }),
  currentOptions: computed('advancedTreeOptions.[]', '__selectedOptions.[]', function() {
    const __selectedOptions = get(this, '__selectedOptions');
    return get(this, 'advancedTreeOptions')
      .map(o => this._treeTraverse(o, (node) => this._setChecked(node, __selectedOptions)));
  }),

  groupedSelectedOptions: computed('__selectedOptions.[]', function() {
    return A(get(this, '__selectedOptions')).reduce((prev, curr) => {
      const humanPath = get(curr, 'humanPath') || '';
      const group = prev.findBy('humanPath', humanPath);
      if (group) {
        get(group, 'options').pushObject(curr);
      } else {
        prev.pushObject(
          {humanPath, options: A([curr]),
          nodeName: get(A(humanPath.split(' > ')), 'lastObject')});
      }

      return prev;
    }, A()).sortBy('humanPath');
  }),

  init() {
    this._super(...arguments);

    if (!get(this, 'labelOpt')) {
      set(this, 'labelOpt', get(this, 'defaultLabelOpt'));
    }

    this._setSelectedOptions();
  },

  didReceiveAttrs() {
    this._super(...arguments);
    if (!isBlank(get(this, 'selectedOptions'))) {
      this._setSelectedOptions();
    }
  },

  _setSelectedOptions() {
    const selectedOptions = A(get(this, 'selectedOptions'));
    let leaves = get(this, 'advancedTreeOptions')
      .map(o => this._treeTraverse(o, (node) => this._setChecked(node, selectedOptions)))
      .map(o => this._getLeaves(o));
    let node;
    let filteredOptions = selectedOptions.map(opt => {
      node = [].concat(...leaves).find(
        leaf => get(opt, 'key') === get(leaf, 'key') && get(opt, 'type') === get(leaf, 'type')
      );

      if (node) {
        return node;
      }

      set(opt, 'humanPath', get(opt, 'path').join(' > '));
      return opt;
    });
    set(this, '__selectedOptions', isBlank(selectedOptions) ? A() : filteredOptions);
  },

  _setChecked(o, __selectedOptions, isChecked = true) {
    if (A(__selectedOptions).find(
      opt => get(opt, 'key') === get(o, 'key') && get(opt, 'type') === get(o, 'type')
    )) {
      set(o, 'isChecked', isChecked);
    }
  },

  _buildPath(node, currPath = A()) {
    let newNode = Ember.$.extend(true, {}, node);
    const path = get(node, 'path');
    if (path && path.length) {
      set(newNode, 'humanPath', path.join(' > '));
      return newNode;
    }

    if (!get(node, 'nodeName') && currPath.length) {
      set(newNode, 'humanPath', currPath.join(' > '));
      set(newNode, 'path', currPath);
    } else {
      currPath.push(get(node, 'nodeName'));
      set(newNode, 'options', A(get(node, 'options')).map(
        o => this._buildPath(o, [].concat(...currPath)))
      );
      currPath = A();
    }

    return newNode;
  },

  _collapsableOption(opt) {
    const isSelectable = get(opt, 'isSelectable');
    const isChecked = leaf => get(leaf, 'isChecked');
    const isOptChecked = get(opt, 'isChecked');
    const groupName = get(opt, 'groupName');
    const options = get(opt, 'options') || [];
    const isCollapsed = get(opt, 'isCollapsed') || true;
    if (groupName) {
      return {
        isSelectable,
        isCollapsed,
        isChecked: options.some(isChecked) || isOptChecked || false,
        nodeName: groupName,
        options: options.map(o => this._collapsableOption(o))
      };
    }

    set(opt, 'isSelectable', true);
    set(opt, 'isChecked', !!isOptChecked);
    return opt;
  },

  _getLeaves(root, leaves = A()) {
    (get(root, 'options') || A()).forEach(
      o => !o.nodeName ? leaves.pushObject(o) : this._getLeaves(o, leaves)
    );
    return leaves;
  },

  _treeTraverse(root, visit) {
    visit(root);
    const options = A(get(root, 'options'));
    if (options.length) {
      options.forEach(o => this._treeTraverse(o, visit));
    }

    return root;
  },

  _findInternalNode(root, nameOrPath) {
    if (get(root, 'nodeName') === nameOrPath || get(root, 'humanPath') === nameOrPath) {
      return root;
    }
    let tmp, node;
    A(get(root, 'options')).forEach(o => {
      tmp = this._findInternalNode(o, nameOrPath);
      if (tmp) {
        node = tmp;
      }
    });

    return node;
  },

  onTreeSelectionChange(opts) {
    return get(this, 'onTreeSelectionChange')(opts);
  },

  scrollDropdownToSelected(el) {
    const container = $('.ember-power-select-tree-list').first();
    const scrollTop = $(el).offset().top - container.offset().top + container.scrollTop();
    return container.animate({ scrollTop }, 500);
  },

  actions: {
    handleSearch() {
      get(this, 'handleSearch')(...arguments);
      return false; // prevents default searching behaviour
    },
    onToggleGroup(group, evt) {
      // Check if checkbox or container is clicked
      const tagName = get(evt, 'target.tagName').toLowerCase();
      if (tagName === 'label' || tagName === 'input') {
        return;
      }
      set(group, 'isCollapsed', !get(group, 'isCollapsed'));

      return this.scrollDropdownToSelected(get(evt, 'target'));
    },
    removeNodeOrLeaf(nodeOrLeaf) {
      const __selectedOptions = get(this, '__selectedOptions');
      const isNode = !get(nodeOrLeaf, 'key');
      const key = isNode ? 'humanPath' : 'key';
      __selectedOptions.removeObjects(
        __selectedOptions.filterBy(key, get(nodeOrLeaf, key))
      );
      this._treeTraverse(nodeOrLeaf, o => set(o, 'isChecked', false));
      if (isNode) { // unchecks the group itself
        set(
          this._findInternalNode(
            {options: get(this, 'currentOptions')},
            get(nodeOrLeaf, 'nodeName') || get(nodeOrLeaf, 'humanPath')), 'isChecked', false
        );
      }
      set(this, '__selectedOptions', __selectedOptions);
    },
    handleChecked(nodeOrLeaf) {
      const newVal = !get(nodeOrLeaf, 'isChecked');
      const _setChecked = node => set(node, 'isChecked', newVal);
      const __selectedOptions = A(get(this, '__selectedOptions'));
      const __selectedOptionsKeys = __selectedOptions.map(o => get(o, 'key'));
      const nodeKey = get(nodeOrLeaf, 'key');
      const leaves = this._getLeaves(nodeOrLeaf);

      this._treeTraverse(nodeOrLeaf, _setChecked);

      if (get(nodeOrLeaf, 'nodeName')) {
        !newVal ?
          leaves.forEach(l => __selectedOptions.removeObject(__selectedOptions.findBy('key', get(l, 'key')))) :
          __selectedOptions.pushObjects(leaves.filter(l => !__selectedOptionsKeys.includes(get(l, 'key'))));
      } else {
        !newVal ?
          __selectedOptions.removeObject(__selectedOptions.findBy('key', nodeKey)) :
          __selectedOptions.pushObject(nodeOrLeaf);
      }

      set(this, '__selectedOptions', __selectedOptions);
      this.onTreeSelectionChange(__selectedOptions);
    }
  }
});
<|endoftext|>


<commit_before>"use strict";

/* global studyUtils */
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "(EXPORTED_SYMBOLS|StudyTelemetryCollector)" }]*/

const { utils: Cu } = Components;
Cu.import("resource://gre/modules/Console.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

const EXPORTED_SYMBOLS = this.EXPORTED_SYMBOLS = ["StudyTelemetryCollector"];

/*
Note: All combinations of below ended up with Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIXPCComponents_Utils.import]
when trying to access the studyUtils object

const BASERESOURCE = "esper-pioneer-shield-study";
// const STUDYUTILSPATH = `resource://${BASERESOURCE}/StudyUtils.jsm`;
// const STUDYUTILSPATH = `${__SCRIPT_URI_SPEC__}/../../${studyConfig.studyUtilsPath}`;
// const { studyUtils } = Cu.import(STUDYUTILSPATH, {});
// XPCOMUtils.defineLazyModuleGetter(this, "studyUtils", STUDYUTILSPATH);
*/

/**
 * Note: Setting studyUtils in this constructor due to above comments
 */
class StudyTelemetryCollector {
  constructor(studyUtils, variation) {
    this.variation = variation;
    this.studyUtils = studyUtils;
  }

  start() {
  }
}
<commit_msg>Naive collection of esper-specific telemetry which are not already present in the default shield ping payload<commit_after>"use strict";

/* global studyUtils */
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "(EXPORTED_SYMBOLS|StudyTelemetryCollector)" }]*/

const { utils: Cu } = Components;
Cu.import("resource://gre/modules/Console.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

const EXPORTED_SYMBOLS = this.EXPORTED_SYMBOLS = ["StudyTelemetryCollector"];

/*
Note: All combinations of below ended up with Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIXPCComponents_Utils.import]
when trying to access the studyUtils object

const BASERESOURCE = "esper-pioneer-shield-study";
// const STUDYUTILSPATH = `resource://${BASERESOURCE}/StudyUtils.jsm`;
// const STUDYUTILSPATH = `${__SCRIPT_URI_SPEC__}/../../${studyConfig.studyUtilsPath}`;
// const { studyUtils } = Cu.import(STUDYUTILSPATH, {});
// XPCOMUtils.defineLazyModuleGetter(this, "studyUtils", STUDYUTILSPATH);
*/

// telemetry utils
const { TelemetrySession } = Cu.import("resource://gre/modules/TelemetrySession.jsm", null);

/**
 * Note: Setting studyUtils in this constructor due to above comments
 */
class StudyTelemetryCollector {

  constructor(studyUtils, variation) {
    this.variation = variation;
    this.studyUtils = studyUtils;
  }

  start() {

    this.studyUtils.telemetry({ event: "esper-init" });

    try {
      this.collectAndSendTelemetry();
    } catch (ex) {
      // TODO: how are errors during study execution reported?
      // this.studyUtils.telemetryError();
      Components.utils.reportError(ex);
    }

  }

  collectAndSendTelemetry() {

    const shieldPingAttributes = this.collectShieldPingAttributes();

    this.studyUtils.telemetry({
      event: "telemetry-payload",
      ...shieldPingAttributes,
    });

  }

  collectShieldPingAttributes() {

    console.log("TelemetrySession", TelemetrySession);

    const REASON_GATHER_PAYLOAD = "gather-payload";
    const telemetrySessionPayload = TelemetrySession.getPayload(REASON_GATHER_PAYLOAD);

    console.log("telemetrySessionPayload", telemetrySessionPayload);

    const shieldPingAttributes = {
      completeTelemetrySessionPayload: JSON.stringify(telemetrySessionPayload),
    };

    shieldPingAttributes.uptime = telemetrySessionPayload.simpleMeasurements.uptime;
    shieldPingAttributes.total_time = telemetrySessionPayload.simpleMeasurements.totalTime;
    shieldPingAttributes.profile_subsession_counter = telemetrySessionPayload.info.profileSubsessionCounter;
    shieldPingAttributes.subsession_start_date = telemetrySessionPayload.info.subsessionStartDate;
    shieldPingAttributes.timezone_offset = telemetrySessionPayload.info.timezoneOffset;

    shieldPingAttributes.places_bookmarks_count = JSON.stringify(telemetrySessionPayload.processes.content.histograms.PLACES_BOOKMARKS_COUNT);
    shieldPingAttributes.places_pages_count = JSON.stringify(telemetrySessionPayload.processes.content.histograms.PLACES_PAGES_COUNT);
    shieldPingAttributes.search_counts = JSON.stringify(telemetrySessionPayload.processes.content.histograms.SEARCH_COUNT);

    shieldPingAttributes.scalar_parent_browser_engagement_window_open_event_count = telemetrySessionPayload.processes.parent.scalars["browser.engagement.window_open_event_count"];
    shieldPingAttributes.scalar_parent_browser_engagement_total_uri_count = telemetrySessionPayload.processes.parent.scalars["browser.engagement.total_uri_count"];
    shieldPingAttributes.scalar_parent_browser_engagement_navigation_urlbar = telemetrySessionPayload.processes.parent.scalars["browser.engagement.navigation_urlbar"];
    shieldPingAttributes.scalar_parent_browser_engagement_navigation_contextmenu = telemetrySessionPayload.processes.parent.scalars["browser.engagement.navigation_contextmenu"];
    shieldPingAttributes.scalar_parent_browser_engagement_tab_open_event_count = telemetrySessionPayload.processes.parent.scalars["browser.engagement.tab_open_event_count"];
    shieldPingAttributes.scalar_parent_browser_engagement_navigation_searchbar = telemetrySessionPayload.processes.parent.scalars["browser.engagement.navigation_searchbar"];
    shieldPingAttributes.scalar_parent_browser_engagement_navigation_about_newtab = telemetrySessionPayload.processes.parent.scalars["browser.engagement.navigation_about_newtab"];
    shieldPingAttributes.scalar_parent_browser_engagement_unique_domains_count = telemetrySessionPayload.processes.parent.scalars["browser.engagement.unique_domains_count"];
    shieldPingAttributes.scalar_parent_browser_engagement_max_concurrent_window_count = telemetrySessionPayload.processes.parent.scalars["browser.engagement.max_concurrent_window_count"];
    shieldPingAttributes.scalar_parent_browser_engagement_max_concurrent_tab_count = telemetrySessionPayload.processes.parent.scalars["browser.engagement.max_concurrent_tab_count"];
    shieldPingAttributes.scalar_parent_browser_engagement_unfiltered_uri_count = telemetrySessionPayload.processes.parent.scalars["browser.engagement.unfiltered_uri_count"];

    console.log("shieldPingAttributes", shieldPingAttributes);

    // shield ping attributes must be strings
    for (const attribute in shieldPingAttributes) {
      shieldPingAttributes[attribute] = String(shieldPingAttributes[attribute]);
    }

    return shieldPingAttributes;

  }

}
<|endoftext|>


<commit_before>var Promise = require('bluebird');
var rekt    = require('rekt');
var Token   = requireLocal('models/token.js');
var config  = requireLocal('config/config.js');
var jwt     = require('jwt-simple');
var _       = require('lodash');

/** Wraps jwt.decode into a promise */
function decode(token, secret) {
  return new Promise(function(resolve, reject) {
    if (_.isUndefined(token)) {
      reject(new rekt.BadRequest('Every request must include a token.'));
    } else {
      try {
        var decoded = jwt.decode(token, secret);
        resolve(decoded);
      } catch (err) {
        var error = new rekt.BadRequest('Badly formed token.');
        console.log('err', error);
        reject(error);
      }
    }
  });
}

/**
 * Attempts to find a token in the database with the decoded subject and
 * resolves with the result.
 */
function validateToken(decoded) {
  var subject = decoded.sub;
  console.log('subject:', subject);
  return new Promise(function(resolve, reject) {
    if (_.isUndefined(subject)) {
      var error = new rekt.BadRequest('Token needs subject field.');
      reject(error);
    }
    Token.findOne({
      subject: subject
    }, function(err, result) {
      if (err) {
        var error = new rekt.BadRequest('Invalid Token');
        console.log(['Invalid', ip, subject, url, verb].join(' | '));
        reject(error);
      } else if (result) {
        console.log('Requested by', subject);
        resolve(result);
      }
    });
  });
}

module.exports = function(router) {
  router.use('/', function(req, res, next) {
    var url  = req.protocol + '://' + req.get('host') + req.originalUrl;
    var ip   = req.ip;
    var verb = req.method;

    var token = (req.body && req.body.access_token)   ||
                (req.query && req.query.access_token) ||
                req.headers['x-access-token'];

    if (!_.isUndefined(token)) {
      decode(token, config.secret)
        .then(validateToken)
        .then(function(result) {

          next();
        })
        .catch(function(err) {
          console.log(err);
          res.status(err.status);
          res.send(err);
        });
    } else {
      var err = new rekt.BadRequest('Missing Token');
      console.log(['Missing', ip, url, verb].join(' | '));
      res.status(err.status);
      res.send(err);
    }
  });
}
<commit_msg>Fixing app error<commit_after>var Promise = require('bluebird');
var rekt    = require('rekt');
var Token   = requireLocal('models/token.js');
var config  = requireLocal('config/config.js');
var jwt     = require('jwt-simple');
var _       = require('lodash');

/** Wraps jwt.decode into a promise */
function decode(token, secret) {
  return new Promise(function(resolve, reject) {
    if (_.isUndefined(token)) {
      reject(new rekt.BadRequest('Every request must include a token.'));
    } else {
      try {
        var decoded = jwt.decode(token, secret);
        resolve(decoded);
      } catch (err) {
        var error = new rekt.BadRequest('Badly formed token.');
        console.log('err', error);
        reject(error);
      }
    }
  });
}

/**
 * Attempts to find a token in the database with the decoded subject and
 * resolves with the result.
 */
function validateToken(decoded) {
  var subject = decoded.sub;
  console.log('subject:', subject);
  return new Promise(function(resolve, reject) {
    if (_.isUndefined(subject)) {
      var error = new rekt.BadRequest('Token needs subject field.');
      reject(error);
    }
    Token.findOne({
      subject: subject
    }, function(err, result) {
      if (err) {
        var error = new rekt.BadRequest('Invalid Token');
        console.log(['Invalid', ip, subject, url, verb].join(' | '));
        reject(error);
      } else if (result) {
        console.log('Requested by', subject);
        resolve(result);
      }
    });
  });
}

module.exports = function(router) {
  router.use('/', function(req, res, next) {
    var url  = req.protocol + '://' + req.get('host') + req.originalUrl;
    var ip   = req.ip;
    var verb = req.method;

    var token = (req.body && req.body.access_token)   ||
                (req.query && req.query.access_token) ||
                req.headers['x-access-token'];

    if (!_.isUndefined(token)) {
      decode(token, config.secret)
        .then(validateToken)
        .then(function(result) {

          next();
        })
        .catch(function(err) {
          console.log(err);
          res.status(err.status);
          res.send(JSON.stringify(err));
        });
    } else {
      var err = new rekt.BadRequest('Missing Token');
      console.log(['Missing', ip, url, verb].join(' | '));
      res.status(err.status);
      res.send(err);
    }
  });
}
<|endoftext|>


<commit_before>/*
 * catch 404 and forward to error handler
 */
function _404(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
}

/*
 * development error handler
 * will print stacktrace
 */
function dev_500(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error.html', {
        message: err.message,
        error: err
    });
}

/*
 * production error handler
 * no stacktraces leaked to user
 */
function _500(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error.html', {
        message: err.message,
        error: {}
    });
}

module.exports = function(app, config){
    app.use(_404);
    if (app.get('env') === 'development') app.use(dev_500);
    app.use(_500);
};<commit_msg>ROUTES: handle 404 and 500<commit_after>/*
 * catch 404 and forward to error handler
 */
function _404(req, res, next) {
    res.status(404).render('404', {
        url: req.originalUrl,
        error: 'Not found'
    });
}

/*
 * production error handler
 * no stacktraces leaked to user
 */
function _500(err, req, res, next) {
    // treat as 404
    if (err.message
        && (~err.message.indexOf('not found')
        || (~err.message.indexOf('Cast to ObjectId failed')))) {
            return next();
    }

    console.error(err.stack);
    // error page
    res.status(500).render('500', { error: err.stack });
}

module.exports = function(app, config){
    app.use(_500);
    app.use(_404);
};<|endoftext|>


<commit_before>var Preferences = require('./../config/Preferences.js');

var Utility = require('./../modules/Utility.js'),
    User    = require('./../modules/user.js'),
    db      = require('./../modules/db.js');

var fs      = require('fs'),
    _       = require('underscore'),
    mongo   = require('mongojs');

module.exports = {
    events: function(req, res) {
        //86400s = 1d
        var start = new Date(req.query.start * 1000),
            end = new Date(req.query.end * 1000),
            query = {};
        switch(req.query.filter) {
            case 'all':
                query = {};
                break;
            case 'hideCancelled':
                query = {cancelled: false};
                break;
            case 'unstaffed':
                query = {cancelled: false };
                break;
            case 'onlyMine':
                query = {shifts: { $elemMatch: { staff: User.getUser(req) } }};
                break;
            case 'recentVideo':
                query = {video: true};
                break;
            default:
                query = {};
        }
        query = _.extend(query, {'start': {$gte: start, $lt: end}});
        db.events.find(query, function(err, events) {
            if (err || !events) {
                console.log(req.url);
                console.log("No events found:" + err);
            } else {
                if(req.query.filter === 'unstaffed') {
                    //filter them manually because empty shifts seem like real shifts
                    events = _.filter(events, function (event) {
                        return Utility.fullShiftNumber(event) < event.staffNeeded;
                    });
                }
                res.json(events);
            }
        });
        //console.log("Req for events starting at " + start.toDateString() + " and ending before " + end.toDateString());
    },
    patch: function(req, res) {
        var query = req.body;

        //eventEdited = true, if the event was actually edited except regular stuff
        var eventEdited = !_.isEmpty(_.difference(_.keys(query), ['shifts', 'notes', 'inventory', 'staffNeeded']));

        if (!_.isEmpty(_.difference(_.keys(query), ['shifts', 'notes', 'inventory'])) && User.permission(req) < 10) {
            res.status(400).json({
                ok: false
            });
            return false;
        }

        if (_.has(query, "shifts")) {
            query.shifts = query.shifts.map(function(shift) {
                if (!_.has(shift, "id")) {
                    shift.id = mongo.ObjectId();
                } else {
                    shift.id = mongo.ObjectId(shift.id);
                }
                shift.start = new Date(shift.start);
                shift.end   = new Date(shift.end);
                return shift;
            });
        }
        if (_.has(query, "notes")) {
            query.notes = query.notes.map(function(note) {
                if (!_.has(note, "id")) {
                    note.id = mongo.ObjectId();
                } else {
                    note.id = mongo.ObjectId(note.id);
                }
                return note;
            });
        }

        if (_.has(query, "start")) {
            query.start = new Date(query.start);
        }
        if (_.has(query, "end")) {
            query.end = new Date(query.end);
        }
        if (_.has(query, "eventStart")) {
            query.eventStart = new Date(query.eventStart);
        }
        if (_.has(query, "eventEnd")) {
            query.eventEnd = new Date(query.eventEnd);
        }

        db.events.findAndModify({
              query: {_id: mongo.ObjectId(req.params.id)},
              update:{$set: query}
            }, function(err, updated) {
                if (err || !updated) {
                    return;
                }
                res.json(query);

                var previous = _.clone(updated);
                updated = _.extend(updated, query);

                //Send notifications
                if (_.has(query, "shifts")) {
                    //Check for new shifts
                    var added = [];
                    if(previous.shifts.length < updated.shifts.length) {
                      added = _.difference(updated.shifts, previous.shifts);
                    }

                    //Check for removed shifts
                    var removed = [];
                    if(previous.shifts.length > updated.shifts.length) {
                      removed = _.difference(previous.shifts, updated.shifts);
                    }

                    var signedUp  = [],
                        withdrawn = [];

                    try {
                        if(previous.shifts.length === updated.shifts.length) {
                          //Check for shifts signed up
                          signedUp = previous.shifts.filter(function(shift) {
                            return shift.staff === '';
                          }).map(function(shift) {
                            var newer = _.findWhere(updated.shifts.map(function(x) {x.id = x.id.toString(); return x;}), {id: shift.id.toString()});

                            if(_.isUndefined(newer)) {
                              throw new Error('Shift should be found if the same shifts.length');
                            }
                            return newer;
                          });

                          //Check for shifts withdrawn
                          withdrawn = updated.shifts.filter(function(shift) {
                            return shift.staff === '';
                          }).map(function(shift) {
                            var older = _.findWhere(previous.shifts.map(function(x) {x.id = x.id.toString(); return x;}), {id: shift.id.toString()});

                            if(_.isUndefined(older)) {
                              throw new Error('Shift should be found if the same shifts.length');
                            }
                            return older;
                          });
                        }
                    } catch(e) {
                      console.error(e);
                    }

                    var newShifts     = added.concat(signedUp),
                        removedShifts = removed.concat(withdrawn);

                    newShifts.forEach(function(shift) {
                        Utility.sendSingleMail({
                            to: shift.staff + '@wesleyan.edu',
                            subject:'You have a new shift! : ' + updated.title,
                            html: ejs.render(fs.readFileSync(__dirname + '/../views/mail/newShift.ejs', 'utf8'), {'app': req.app, 'event': updated, 'shift': shift})
                        });
                    });
                    removedShifts.forEach(function(shift) {
                        Utility.sendSingleMail({
                            to: shift.staff + '@wesleyan.edu',
                            subject:'You have a removed shift! : ' + updated.title,
                            html: ejs.render(fs.readFileSync(__dirname + '/../views/mail/removeShift.ejs', 'utf8'), {'app': req.app, 'event': updated, 'shift': shift})
                        });
                    });
                }

                // Handle notifications for the existing staff of edited events
                if(eventEdited) {
                    //Send e-mails to the registered staff after update
                    var smtpTransport = Utility.smtpTransport();

                    updated.shifts.forEach(function(shift) {
                        if(shift.staff === '') {
                            return false;
                        }

                        var staffMailOptions = {
                            from: Preferences.mail.fromString,
                            to: shift.staff + "@wesleyan.edu",
                            subject: "Updated Event for " + shift.staff + " (IMPORTANT)",
                        };
                        var items = {
                            'update': [{
                                'event': updated,
                                'shift': _.findWhere(updated.shifts, {
                                    staff: shift.staff
                                })
                            }],
                            remove: []
                        };
                        staffMailOptions.html = ejs.render(fs.readFileSync(__dirname + '/../views/mail/normalUpdate.ejs', 'utf8'), {'app': req.app, 'items': items});

                        smtpTransport.sendMail(staffMailOptions, function(error, response) {
                            if (error) {
                                console.log(error);
                            } else {
                                //console.log("Message sent: " + response.message);
                            }
                        });
                    });
                    //e-mails sent
                }
                //end of eventEdited
            });
    },
    delete: function(req, res) {
        if(User.permission(req) < 10) {
            res.status(400).json({ok: false});
            return;
        }
        db.events.remove({_id: mongo.ObjectId(req.params.id)}, function(err, removed) {
            if(err || !removed) {
              res.status(400).json({ok: false});
              return;
            }
            res.json({ok: true});
          });
    }
};
<commit_msg>Fix: Edited events are not updated with EMS information now<commit_after>var Preferences = require('./../config/Preferences.js');

var Utility = require('./../modules/Utility.js'),
    User    = require('./../modules/user.js'),
    db      = require('./../modules/db.js');

var fs      = require('fs'),
    _       = require('underscore'),
    mongo   = require('mongojs');

module.exports = {
    events: function(req, res) {
        //86400s = 1d
        var start = new Date(req.query.start * 1000),
            end = new Date(req.query.end * 1000),
            query = {};
        switch(req.query.filter) {
            case 'all':
                query = {};
                break;
            case 'hideCancelled':
                query = {cancelled: false};
                break;
            case 'unstaffed':
                query = {cancelled: false };
                break;
            case 'onlyMine':
                query = {shifts: { $elemMatch: { staff: User.getUser(req) } }};
                break;
            case 'recentVideo':
                query = {video: true};
                break;
            default:
                query = {};
        }
        query = _.extend(query, {'start': {$gte: start, $lt: end}});
        db.events.find(query, function(err, events) {
            if (err || !events) {
                console.log(req.url);
                console.log("No events found:" + err);
            } else {
                if(req.query.filter === 'unstaffed') {
                    //filter them manually because empty shifts seem like real shifts
                    events = _.filter(events, function (event) {
                        return Utility.fullShiftNumber(event) < event.staffNeeded;
                    });
                }
                res.json(events);
            }
        });
        //console.log("Req for events starting at " + start.toDateString() + " and ending before " + end.toDateString());
    },
    patch: function(req, res) {
        var query = req.body;

        //eventEdited = true, if the event was actually edited except regular stuff
        var eventEdited = !_.isEmpty(_.difference(_.keys(query), ['shifts', 'notes', 'inventory', 'staffNeeded']));

        if (!_.isEmpty(_.difference(_.keys(query), ['shifts', 'notes', 'inventory'])) && User.permission(req) < 10) {
            res.status(400).json({
                ok: false
            });
            return false;
        }

        if (_.has(query, "shifts")) {
            query.shifts = query.shifts.map(function(shift) {
                if (!_.has(shift, "id")) {
                    shift.id = mongo.ObjectId();
                } else {
                    shift.id = mongo.ObjectId(shift.id);
                }
                shift.start = new Date(shift.start);
                shift.end   = new Date(shift.end);
                return shift;
            });
        }
        if (_.has(query, "notes")) {
            query.notes = query.notes.map(function(note) {
                if (!_.has(note, "id")) {
                    note.id = mongo.ObjectId();
                } else {
                    note.id = mongo.ObjectId(note.id);
                }
                return note;
            });
        }

        if (_.has(query, "start")) {
            query.start = new Date(query.start);
        }
        if (_.has(query, "end")) {
            query.end = new Date(query.end);
        }
        if (_.has(query, "eventStart")) {
            query.eventStart = new Date(query.eventStart);
        }
        if (_.has(query, "eventEnd")) {
            query.eventEnd = new Date(query.eventEnd);
        }

        if(eventEdited) {
          query.updated = true;
        }

        db.events.findAndModify({
              query: {_id: mongo.ObjectId(req.params.id)},
              update:{$set: query}
            }, function(err, updated) {
                if (err || !updated) {
                    return;
                }
                res.json(query);

                var previous = _.clone(updated);
                updated = _.extend(updated, query);

                //Send notifications
                if (_.has(query, "shifts")) {
                    //Check for new shifts
                    var added = [];
                    if(previous.shifts.length < updated.shifts.length) {
                      added = _.difference(updated.shifts, previous.shifts);
                    }

                    //Check for removed shifts
                    var removed = [];
                    if(previous.shifts.length > updated.shifts.length) {
                      removed = _.difference(previous.shifts, updated.shifts);
                    }

                    var signedUp  = [],
                        withdrawn = [];

                    try {
                        if(previous.shifts.length === updated.shifts.length) {
                          //Check for shifts signed up
                          signedUp = previous.shifts.filter(function(shift) {
                            return shift.staff === '';
                          }).map(function(shift) {
                            var newer = _.findWhere(updated.shifts.map(function(x) {x.id = x.id.toString(); return x;}), {id: shift.id.toString()});

                            if(_.isUndefined(newer)) {
                              throw new Error('Shift should be found if the same shifts.length');
                            }
                            return newer;
                          });

                          //Check for shifts withdrawn
                          withdrawn = updated.shifts.filter(function(shift) {
                            return shift.staff === '';
                          }).map(function(shift) {
                            var older = _.findWhere(previous.shifts.map(function(x) {x.id = x.id.toString(); return x;}), {id: shift.id.toString()});

                            if(_.isUndefined(older)) {
                              throw new Error('Shift should be found if the same shifts.length');
                            }
                            return older;
                          });
                        }
                    } catch(e) {
                      console.error(e);
                    }

                    var newShifts     = added.concat(signedUp),
                        removedShifts = removed.concat(withdrawn);

                    newShifts.forEach(function(shift) {
                        Utility.sendSingleMail({
                            to: shift.staff + '@wesleyan.edu',
                            subject:'You have a new shift! : ' + updated.title,
                            html: ejs.render(fs.readFileSync(__dirname + '/../views/mail/newShift.ejs', 'utf8'), {'app': req.app, 'event': updated, 'shift': shift})
                        });
                    });
                    removedShifts.forEach(function(shift) {
                        Utility.sendSingleMail({
                            to: shift.staff + '@wesleyan.edu',
                            subject:'You have a removed shift! : ' + updated.title,
                            html: ejs.render(fs.readFileSync(__dirname + '/../views/mail/removeShift.ejs', 'utf8'), {'app': req.app, 'event': updated, 'shift': shift})
                        });
                    });
                }

                // Handle notifications for the existing staff of edited events
                if(eventEdited) {
                    //Send e-mails to the registered staff after update
                    var smtpTransport = Utility.smtpTransport();

                    updated.shifts.forEach(function(shift) {
                        if(shift.staff === '') {
                            return false;
                        }

                        var staffMailOptions = {
                            from: Preferences.mail.fromString,
                            to: shift.staff + "@wesleyan.edu",
                            subject: "Updated Event for " + shift.staff + " (IMPORTANT)",
                        };
                        var items = {
                            'update': [{
                                'event': updated,
                                'shift': _.findWhere(updated.shifts, {
                                    staff: shift.staff
                                })
                            }],
                            remove: []
                        };
                        staffMailOptions.html = ejs.render(fs.readFileSync(__dirname + '/../views/mail/normalUpdate.ejs', 'utf8'), {'app': req.app, 'items': items});

                        smtpTransport.sendMail(staffMailOptions, function(error, response) {
                            if (error) {
                                console.log(error);
                            } else {
                                //console.log("Message sent: " + response.message);
                            }
                        });
                    });
                    //e-mails sent
                }
                //end of eventEdited
            });
    },
    delete: function(req, res) {
        if(User.permission(req) < 10) {
            res.status(400).json({ok: false});
            return;
        }
        db.events.remove({_id: mongo.ObjectId(req.params.id)}, function(err, removed) {
            if(err || !removed) {
              res.status(400).json({ok: false});
              return;
            }
            res.json({ok: true});
          });
    }
};
<|endoftext|>