<commit_before>var search = search || {};

(function ($) {
    /**
     * Search Logic.
     *
     * @param {object} options configuration options
     */
    function Search(options)
    {
        this.formId = options.hasOwnProperty('formId') ? options.formId : '#SearchFilterForm';
        this.addFieldId = options.hasOwnProperty('addFieldId') ? options.addFieldId : '#addFilter';
        this.model = '';
        this.fieldProperties = {};
        this.fieldTypeOperators = {};
        this.associationLabels = {};
        this.deleteBtnHtml = '
' +
            '' +
                '' +
            '' +
        '
';
        this.operatorSelectHtml = '<select ' +
            'name="criteria[{{field}}][{{timestamp}}][operator]" ' +
            'class="form-control input-sm">' +
            '{{options}}' +
        '</select>';
        this.operatorOptionHtml = '<option value="{{value}}" {{selected}}>{{label}}</option>';
        this.fieldTypeHtml = '<input' +
            ' type="hidden"' +
            ' name="criteria[{{field}}][{{timestamp}}][type]"' +
            ' value="{{type}}"' +
        '>';
        this.fieldLabelHtml = '{{label}}';
        this.fieldInputHtml = '
{{fieldType}}' +
            '
' +
                '
{{fieldLabel}}
' +
                '
{{fieldOperator}}
' +
                '
{{fieldInput}}
' +
                '
{{deleteButton}}
' +
            '
' +
        '
';
    }

    /**
     * Initialize method.
     *
     * @return {undefined}
     */
    Search.prototype.init = function () {
        this._onfieldSelect();
    };

    /**
     * Re-generate criteria fields on form submit.
     *
     * @param  {object} criteriaFields preset criteria fields
     * @return {undefined}
     */
    Search.prototype.generateCriteriaFields = function (criteriaFields) {
        var that = this;
        if (!$.isEmptyObject(criteriaFields)) {
            $.each(criteriaFields, function (k, v) {
                if ('object' !== typeof v) {
                    return;
                }
                $.each(v, function (i, j) {
                    that._generateField(k, that.fieldProperties[k], j.value, j.operator);
                });
            });
        }
    };

    /**
     * Search model setter.
     *
     * @param {string} model Model name
     */
    Search.prototype.setModel = function (model) {
        this.model = model;
    };

    /**
     * Field properties setter.
     *
     * @param {object} fieldProperties field properties
     */
    Search.prototype.setFieldProperties = function (fieldProperties) {
        this.fieldProperties = fieldProperties;
    };

    /**
     * Search model setter.
     *
     * @param {string} model Model name
     */
    Search.prototype.setAssociationLabels = function (associationLabels) {
        this.associationLabels = associationLabels;
    };

    /**
     * Method that generates field on field dropdown select.
     *
     * @return {undefined}
     */
    Search.prototype._onfieldSelect = function () {
        var that = this;
        $(this.addFieldId).change(function () {
            if ('' !== this.value) {
                that._generateField(this.value, that.fieldProperties[this.value]);
                this.value = '';
            }
        });
    };

    /**
     * Remove button click logic.
     *
     * @return {undefined}
     */
    Search.prototype._onRemoveBtnClick = function () {
        $(this.formId).on('click', 'a.search-field-remover', function (event) {
            event.preventDefault();
            $(this).parents('.search-field-wrapper').remove();
        });
    };

    /**
     * Method that generates form field.
     *
     * @param  {string}    field       field name
     * @param  {object}    properties  field properties
     * @param  {string}    value       field value
     * @param  {string}    operator    field operator
     * @return {undefined}
     */
    Search.prototype._generateField = function (field, properties, value, operator) {
        var timestamp = Math.round(1000000 * Math.random());

        var inputHtml = this.fieldInputHtml;
        inputHtml = inputHtml.replace('{{fieldType}}', this._generateFieldType(field, properties.type, timestamp));
        inputHtml = inputHtml.replace('{{fieldLabel}}', this._generateFieldLabel(field, properties.label));
        inputHtml = inputHtml.replace(
            '{{fieldOperator}}',
            this._generateSearchOperator(field, properties.operators, timestamp, operator)
        );
        inputHtml = inputHtml.replace(
            '{{fieldInput}}',
            this._generateFieldInput(field, properties.input, timestamp, value)
        );
        inputHtml = inputHtml.replace('{{deleteButton}}', this.deleteBtnHtml);

        $(this.formId + ' fieldset').append(inputHtml);

        this._onRemoveBtnClick();
    };

    /**
     * Generates and returns field label html.
     *
     * @param  {string} field field name
     * @param  {string} label field label
     * @return {string}
     */
    Search.prototype._generateFieldLabel = function (field, label) {
        var input = this.fieldLabelHtml;

        var tableName = field.substr(0, field.indexOf('.'));

        var suffix = '';
        if (this.model !== tableName) {
            suffix = this.associationLabels.hasOwnProperty(tableName) ?
                this.associationLabels[tableName] :
                tableName;
            suffix = ' (' + suffix + ')';
        }

        return input.replace('{{label}}', label + suffix);
    };

    /**
     * Generates and returns field type hidden input html.
     *
     * @param  {string} field     field name
     * @param  {string} type      field type
     * @param  {number} timestamp timestamp
     * @return {string}
     */
    Search.prototype._generateFieldType = function (field, type, timestamp) {
        var input = this.fieldTypeHtml;

        return input.replace('{{field}}', field).replace('{{timestamp}}', timestamp).replace('{{type}}', type);
    };

    /**
     * Generates and returns field operator html.
     *
     * @param  {string} field       field name
     * @param  {string} type        field type
     * @param  {number} timestamp   timestamp
     * @param  {string} setOperator field set operator
     * @return {string}
     */
    Search.prototype._generateSearchOperator = function (field, operators, timestamp, setOperator) {
        var that = this;

        var options = '';
        $.each(operators, function (k, v) {
            var option = that.operatorOptionHtml;
            option = option.replace('{{value}}', k);
            option = option.replace('{{label}}', v.label);
            if (k === setOperator) {
                option = option.replace('{{selected}}', 'selected');
            } else {
                option = option.replace('{{selected}}', '');
            }
            options += option;
        });

        var select = this.operatorSelectHtml;

        return select.replace('{{field}}', field).replace('{{timestamp}}', timestamp).replace('{{options}}', options);
    };

    /**
     * Generates and returns field input html.
     *
     * @param  {string} field      field name
     * @param  {object} properties field properties
     * @param  {number} timestamp  timestamp
     * @param  {string} value      field value
     * @return {string}
     */
    Search.prototype._generateFieldInput = function (field, input, timestamp, value) {
        var name = 'criteria[' + field + '][' + timestamp + '][value]';
        if ('undefined' === typeof value) {
            value = '';
        }

        var result = input.content
            .replace(/{{name}}/g, name)
            .replace(/{{value}}/g, value)
            .replace(/{{id}}/g, timestamp)
            .replace(/(["|\s])(input-group)(["|\s])/g, '$1$2 input-group-sm$3')
            .replace(/(["|\s])(form-control)(["|\s])/g, '$1$2 input-sm$3');

        if (value) {
            result = this._handleSpecialInputs(result, value);
        }

        return result;
    };

    /**
     * Handle special inputs such as checkbox and select.
     * Select will set the correct option as 'selected'
     * and checkbox will set the checked flag if value
     * is true.
     *
     * @param  {string} element Input element
     * @param  {string} value   Input value
     * @return {string}
     */
    Search.prototype._handleSpecialInputs = function (element, value) {
        var html = $(element);

        // handle select2 inputs
        if (0 < $(html).find('select[data-type="select2"]').length) {
            value = Array === value.constructor ? value : [value];
            value.forEach(function (val) {
                $(html).find('select').append('<option value="' + val + '" selected="selected"></option>');
            });

            return html.get(0).outerHTML;
        }

        // handle select element
        var has_select = $(html).find('select');
        if (html.is('select') || 0 < has_select.length) {
            $(html).find('option').each(function () {
                if (this.value !== value) {
                    return true;
                }
                $(this).attr('selected', 'selected');

                return false;
            });

            return html.get(0).outerHTML;
        }

        // handle checkbox element
        var has_checkbox = $(html).find(':checkbox');
        if (html.is(':checkbox') || 0 < has_checkbox.length) {
            $(html).find(':checkbox').each(function () {
                // convert string to int with + and then to boolean with !!
                // @link http://stackoverflow.com/a/16313488/2562232
                var checked = !! + value;
                $(this).attr('checked', checked);

                return false;
            });

            return html.get(0).outerHTML;
        }

        return element;
    };

    search = new Search({
        addFieldId: '#addFilter',
        formId: '#SearchFilterForm'
    });

    search.init();

})(jQuery);
<commit_msg>Generate field method now returns field html instead of appending it to the form (task #5527)<commit_after>var search = search || {};

(function ($) {
    /**
     * Search Logic.
     *
     * @param {object} options configuration options
     */
    function Search(options)
    {
        this.formId = options.hasOwnProperty('formId') ? options.formId : '#SearchFilterForm';
        this.addFieldId = options.hasOwnProperty('addFieldId') ? options.addFieldId : '#addFilter';
        this.model = '';
        this.fieldProperties = {};
        this.fieldTypeOperators = {};
        this.associationLabels = {};
        this.deleteBtnHtml = '
' +
            '' +
                '' +
            '' +
        '
';
        this.operatorSelectHtml = '<select ' +
            'name="criteria[{{field}}][{{timestamp}}][operator]" ' +
            'class="form-control input-sm">' +
            '{{options}}' +
        '</select>';
        this.operatorOptionHtml = '<option value="{{value}}" {{selected}}>{{label}}</option>';
        this.fieldTypeHtml = '<input' +
            ' type="hidden"' +
            ' name="criteria[{{field}}][{{timestamp}}][type]"' +
            ' value="{{type}}"' +
        '>';
        this.fieldLabelHtml = '{{label}}';
        this.fieldInputHtml = '
{{fieldType}}' +
            '
' +
                '
{{fieldLabel}}
' +
                '
{{fieldOperator}}
' +
                '
{{fieldInput}}
' +
                '
{{deleteButton}}
' +
            '
' +
        '
';
    }

    /**
     * Initialize method.
     *
     * @return {undefined}
     */
    Search.prototype.init = function () {
        this._onfieldSelect();
    };

    /**
     * Re-generate criteria fields on form submit.
     *
     * @param  {object} criteriaFields preset criteria fields
     * @return {undefined}
     */
    Search.prototype.generateCriteriaFields = function (criteriaFields) {
        var that = this;
        if (!$.isEmptyObject(criteriaFields)) {
            $.each(criteriaFields, function (k, v) {
                if ('object' !== typeof v) {
                    return;
                }
                $.each(v, function (i, j) {
                    // append to search form
                    $(that.formId + ' fieldset').append(
                        that._generateField(k, that.fieldProperties[k], j.value, j.operator)
                    );
                });
            });
        }
    };

    /**
     * Search model setter.
     *
     * @param {string} model Model name
     */
    Search.prototype.setModel = function (model) {
        this.model = model;
    };

    /**
     * Field properties setter.
     *
     * @param {object} fieldProperties field properties
     */
    Search.prototype.setFieldProperties = function (fieldProperties) {
        this.fieldProperties = fieldProperties;
    };

    /**
     * Search model setter.
     *
     * @param {string} model Model name
     */
    Search.prototype.setAssociationLabels = function (associationLabels) {
        this.associationLabels = associationLabels;
    };

    /**
     * Method that generates field on field dropdown select.
     *
     * @return {undefined}
     */
    Search.prototype._onfieldSelect = function () {
        var that = this;
        $(this.addFieldId).change(function () {
            if ('' !== this.value) {
                // append to search form
                $(that.formId + ' fieldset').append(
                    that._generateField(this.value, that.fieldProperties[this.value])
                );

                this.value = '';
            }
        });
    };

    /**
     * Remove button click logic.
     *
     * @return {undefined}
     */
    Search.prototype._onRemoveBtnClick = function () {
        $(this.formId).on('click', 'a.search-field-remover', function (event) {
            event.preventDefault();
            $(this).parents('.search-field-wrapper').remove();
        });
    };

    /**
     * Method that generates form field.
     *
     * @param  {string}    field       field name
     * @param  {object}    properties  field properties
     * @param  {string}    value       field value
     * @param  {string}    operator    field operator
     * @return {undefined}
     */
    Search.prototype._generateField = function (field, properties, value, operator) {
        var timestamp = Math.round(1000000 * Math.random());

        var inputHtml = this.fieldInputHtml;
        inputHtml = inputHtml.replace('{{fieldType}}', this._generateFieldType(field, properties.type, timestamp));
        inputHtml = inputHtml.replace('{{fieldLabel}}', this._generateFieldLabel(field, properties.label));
        inputHtml = inputHtml.replace(
            '{{fieldOperator}}',
            this._generateSearchOperator(field, properties.operators, timestamp, operator)
        );
        inputHtml = inputHtml.replace(
            '{{fieldInput}}',
            this._generateFieldInput(field, properties.input, timestamp, value)
        );
        inputHtml = inputHtml.replace('{{deleteButton}}', this.deleteBtnHtml);

        this._onRemoveBtnClick();

        return inputHtml;
    };

    /**
     * Generates and returns field label html.
     *
     * @param  {string} field field name
     * @param  {string} label field label
     * @return {string}
     */
    Search.prototype._generateFieldLabel = function (field, label) {
        var input = this.fieldLabelHtml;

        var tableName = field.substr(0, field.indexOf('.'));

        var suffix = '';
        if (this.model !== tableName) {
            suffix = this.associationLabels.hasOwnProperty(tableName) ?
                this.associationLabels[tableName] :
                tableName;
            suffix = ' (' + suffix + ')';
        }

        return input.replace('{{label}}', label + suffix);
    };

    /**
     * Generates and returns field type hidden input html.
     *
     * @param  {string} field     field name
     * @param  {string} type      field type
     * @param  {number} timestamp timestamp
     * @return {string}
     */
    Search.prototype._generateFieldType = function (field, type, timestamp) {
        var input = this.fieldTypeHtml;

        return input.replace('{{field}}', field).replace('{{timestamp}}', timestamp).replace('{{type}}', type);
    };

    /**
     * Generates and returns field operator html.
     *
     * @param  {string} field       field name
     * @param  {string} type        field type
     * @param  {number} timestamp   timestamp
     * @param  {string} setOperator field set operator
     * @return {string}
     */
    Search.prototype._generateSearchOperator = function (field, operators, timestamp, setOperator) {
        var that = this;

        var options = '';
        $.each(operators, function (k, v) {
            var option = that.operatorOptionHtml;
            option = option.replace('{{value}}', k);
            option = option.replace('{{label}}', v.label);
            if (k === setOperator) {
                option = option.replace('{{selected}}', 'selected');
            } else {
                option = option.replace('{{selected}}', '');
            }
            options += option;
        });

        var select = this.operatorSelectHtml;

        return select.replace('{{field}}', field).replace('{{timestamp}}', timestamp).replace('{{options}}', options);
    };

    /**
     * Generates and returns field input html.
     *
     * @param  {string} field      field name
     * @param  {object} properties field properties
     * @param  {number} timestamp  timestamp
     * @param  {string} value      field value
     * @return {string}
     */
    Search.prototype._generateFieldInput = function (field, input, timestamp, value) {
        var name = 'criteria[' + field + '][' + timestamp + '][value]';
        if ('undefined' === typeof value) {
            value = '';
        }

        var result = input.content
            .replace(/{{name}}/g, name)
            .replace(/{{value}}/g, value)
            .replace(/{{id}}/g, timestamp)
            .replace(/(["|\s])(input-group)(["|\s])/g, '$1$2 input-group-sm$3')
            .replace(/(["|\s])(form-control)(["|\s])/g, '$1$2 input-sm$3');

        if (value) {
            result = this._handleSpecialInputs(result, value);
        }

        return result;
    };

    /**
     * Handle special inputs such as checkbox and select.
     * Select will set the correct option as 'selected'
     * and checkbox will set the checked flag if value
     * is true.
     *
     * @param  {string} element Input element
     * @param  {string} value   Input value
     * @return {string}
     */
    Search.prototype._handleSpecialInputs = function (element, value) {
        var html = $(element);

        // handle select2 inputs
        if (0 < $(html).find('select[data-type="select2"]').length) {
            value = Array === value.constructor ? value : [value];
            value.forEach(function (val) {
                $(html).find('select').append('<option value="' + val + '" selected="selected"></option>');
            });

            return html.get(0).outerHTML;
        }

        // handle select element
        var has_select = $(html).find('select');
        if (html.is('select') || 0 < has_select.length) {
            $(html).find('option').each(function () {
                if (this.value !== value) {
                    return true;
                }
                $(this).attr('selected', 'selected');

                return false;
            });

            return html.get(0).outerHTML;
        }

        // handle checkbox element
        var has_checkbox = $(html).find(':checkbox');
        if (html.is(':checkbox') || 0 < has_checkbox.length) {
            $(html).find(':checkbox').each(function () {
                // convert string to int with + and then to boolean with !!
                // @link http://stackoverflow.com/a/16313488/2562232
                var checked = !! + value;
                $(this).attr('checked', checked);

                return false;
            });

            return html.get(0).outerHTML;
        }

        return element;
    };

    search = new Search({
        addFieldId: '#addFilter',
        formId: '#SearchFilterForm'
    });

    search.init();

})(jQuery);
<|endoftext|>


<commit_before>var search = search || {};

(function($) {
    /**
     * Search Logic.
     * @param {object} options configuration options
     */
    function Search(options) {
        this.formId = options.hasOwnProperty('formId') ? options.formId : '#SearchFilterForm';
        this.addFieldId = options.hasOwnProperty('addFieldId') ? options.addFieldId : '#addFilter';
        this.fieldProperties = {};
        this.fieldTypeOperators = {};
    }

    /**
     * Initialize method.
     * @return {void}
     */
    Search.prototype.init = function() {
        this._onfieldSelect();
    };

    Search.prototype.generateCriteriaFields = function(criteriaFields) {
        if (!$.isEmptyObject(criteriaFields)) {
            $.each(criteriaFields, function(k, v) {
                if ('object' === typeof v) {
                    data = v[Object.keys(v)[0]];
                    that._generateField(k, that.fieldProperties[k], data.value, data.operator);
                }
            });
        }
    };

    Search.prototype.setFieldProperties = function(fieldProperties) {
        this.fieldProperties = fieldProperties;
    };

    Search.prototype.setFieldTypeOperators = function(fieldTypeOperators) {
        this.fieldTypeOperators = fieldTypeOperators;
    };

    Search.prototype._onfieldSelect = function() {
        that = this;
        $(this.addFieldId).change(function() {
            if ('' !== this.value) {
                var props = that.fieldProperties[this.value];
                that._generateField(this.value, props);
                this.value = '';
            }
        });
    };

    Search.prototype._generateField = function(field, properties, value, operator) {
        var timestamp = new Date().getUTCMilliseconds();
        var inputHtml = '';
        inputHtml += '
';
            inputHtml += this._generateFieldLabel(properties);
            inputHtml += this._generateFieldType(field, properties.type, timestamp);
            inputHtml += '
';
                inputHtml += '
';
                    inputHtml += this._generateFieldOperator(field, properties.type, timestamp, operator);
                inputHtml += '
';
                inputHtml += '
';
                    inputHtml += this._generateFieldInput(field, properties, timestamp, value);
                inputHtml += '
';
            inputHtml += '
';
        inputHtml += '
';
        $(this.formId + ' fieldset').append(inputHtml);
    };

    Search.prototype._generateFieldLabel = function(properties) {
        var result = '';
        result += '' + properties.label + '';

        return result;
    };

    Search.prototype._generateFieldType = function(field, type, timestamp) {
        var result = '';
        result += '<input type="hidden" name="' + field + '[' + timestamp + '][type]" value="' + type + '">';

        return result;
    };

    Search.prototype._generateFieldOperator = function(field, type, timestamp, operator) {
        var result = '';
        if (this.fieldTypeOperators.hasOwnProperty(type)) {
            result += '<select name="' + field + '[' + timestamp + '][operator]" class="form-control input-sm">';
            $.each(this.fieldTypeOperators[type], function(k, v) {
                result += '<option value="' + k + '"';
                if (operator === k) {
                    result += ' selected';
                }
                result += '>';
                result += v + '</option>';
            });
            result += '</select>';
        }

        return result;
    };

    Search.prototype._generateFieldInput = function(field, properties, timestamp, value) {
        var result = '';
        if ('undefined' === typeof value) {
            value = '';
        }
        switch (properties.type) {
            case 'list':
                result += '<select name="' + field + '[' + timestamp + '][value]" class="form-control input-sm">';
                $.each(properties.fieldOptions, function(k, v) {
                    result += '<option value="' + k + '">' + v + '</option>';
                });
                result += '</select>';
                break;
            case 'boolean':
                result += '<input type="hidden" name="' + field + '[' + timestamp + '][value]" value="0">';
                result += '<input type="checkbox" name="' + field + '[' + timestamp + '][value]" = value="1">';
                break;
            default:
                result += '<input type="' + properties.type + '" name="' + field + '[' + timestamp + '][value]"';
                result += ' class="form-control input-sm" value="' + value + '">';
        }

        return result;
    };

    search = new Search({
        addFieldId: '#addFilter',
        formId: '#SearchFilterForm'
    });

    search.init();

})(jQuery);
<commit_msg>missing documentation (task #1596)<commit_after>var search = search || {};

(function($) {
    /**
     * Search Logic.
     *
     * @param {object} options configuration options
     */
    function Search(options) {
        this.formId = options.hasOwnProperty('formId') ? options.formId : '#SearchFilterForm';
        this.addFieldId = options.hasOwnProperty('addFieldId') ? options.addFieldId : '#addFilter';
        this.fieldProperties = {};
        this.fieldTypeOperators = {};
    }

    /**
     * Initialize method.
     *
     * @return {undefined}
     */
    Search.prototype.init = function() {
        this._onfieldSelect();
    };

    /**
     * Re-generate criteria fields on form submit.
     *
     * @param  {object} criteriaFields preset criteria fields
     * @return {undefined}
     */
    Search.prototype.generateCriteriaFields = function(criteriaFields) {
        if (!$.isEmptyObject(criteriaFields)) {
            $.each(criteriaFields, function(k, v) {
                if ('object' === typeof v) {
                    data = v[Object.keys(v)[0]];
                    that._generateField(k, that.fieldProperties[k], data.value, data.operator);
                }
            });
        }
    };

    /**
     * Field properties setter.
     *
     * @param {object} fieldProperties field properties
     */
    Search.prototype.setFieldProperties = function(fieldProperties) {
        this.fieldProperties = fieldProperties;
    };

    /**
     * Field type operators setter.
     *
     * @param {object} fieldTypeOperators field type operators
     */
    Search.prototype.setFieldTypeOperators = function(fieldTypeOperators) {
        this.fieldTypeOperators = fieldTypeOperators;
    };

    /**
     * Method that generates field on field dropdown select.
     *
     * @return {undefined}
     */
    Search.prototype._onfieldSelect = function() {
        that = this;
        $(this.addFieldId).change(function() {
            if ('' !== this.value) {
                that._generateField(this.value, that.fieldProperties[this.value]);
                this.value = '';
            }
        });
    };

    /**
     * Method that generates form field.
     *
     * @param  {string}    field       field name
     * @param  {object}    properties  field properties
     * @param  {string}    value       field value
     * @param  {string}    setOperator field set operator
     * @return {undefined}
     */
    Search.prototype._generateField = function(field, properties, value, setOperator) {
        var timestamp = new Date().getUTCMilliseconds();
        var inputHtml = '';
        inputHtml += '
';
            inputHtml += this._generateFieldLabel(properties.label);
            inputHtml += this._generateFieldType(field, properties.type, timestamp);
            inputHtml += '
';
                inputHtml += '
';
                    inputHtml += this._generateFieldOperator(field, properties.type, timestamp, setOperator);
                inputHtml += '
';
                inputHtml += '
';
                    inputHtml += this._generateFieldInput(field, properties, timestamp, value);
                inputHtml += '
';
            inputHtml += '
';
        inputHtml += '
';
        $(this.formId + ' fieldset').append(inputHtml);
    };

    /**
     * Generates and returns field label html.
     *
     * @param  {object} label field label
     * @return {string}
     */
    Search.prototype._generateFieldLabel = function(label) {
        var result = '';
        result += '' + label + '';

        return result;
    };

    /**
     * Generates and returns field type hidden input html.
     *
     * @param  {string} field     field name
     * @param  {string} type      field type
     * @param  {string} timestamp timestamp
     * @return {string}
     */
    Search.prototype._generateFieldType = function(field, type, timestamp) {
        var result = '';
        result += '<input type="hidden" name="' + field + '[' + timestamp + '][type]" value="' + type + '">';

        return result;
    };

    /**
     * Generates and returns field operator html.
     *
     * @param  {string} field       field name
     * @param  {string} type        field type
     * @param  {string} timestamp   timestamp
     * @param  {string} setOperator field set operator
     * @return {string}
     */
    Search.prototype._generateFieldOperator = function(field, type, timestamp, setOperator) {
        var result = '';
        if (this.fieldTypeOperators.hasOwnProperty(type)) {
            result += '<select name="' + field + '[' + timestamp + '][operator]" class="form-control input-sm">';
            $.each(this.fieldTypeOperators[type], function(k, v) {
                result += '<option value="' + k + '"';
                if (setOperator === k) {
                    result += ' selected';
                }
                result += '>';
                result += v + '</option>';
            });
            result += '</select>';
        }

        return result;
    };

    /**
     * Generates and returns field input html.
     *
     * @param  {string} field      field name
     * @param  {object} properties field properties
     * @param  {string} timestamp  timestamp
     * @param  {string} value      field value
     * @return {string}
     */
    Search.prototype._generateFieldInput = function(field, properties, timestamp, value) {
        var result = '';
        if ('undefined' === typeof value) {
            value = '';
        }
        switch (properties.type) {
            case 'list':
                result += '<select name="' + field + '[' + timestamp + '][value]" class="form-control input-sm">';
                $.each(properties.fieldOptions, function(k, v) {
                    result += '<option value="' + k + '">' + v + '</option>';
                });
                result += '</select>';
                break;
            case 'boolean':
                result += '<input type="hidden" name="' + field + '[' + timestamp + '][value]" value="0">';
                result += '<input type="checkbox" name="' + field + '[' + timestamp + '][value]" = value="1">';
                break;
            default:
                result += '<input type="' + properties.type + '" name="' + field + '[' + timestamp + '][value]"';
                result += ' class="form-control input-sm" value="' + value + '">';
        }

        return result;
    };

    search = new Search({
        addFieldId: '#addFilter',
        formId: '#SearchFilterForm'
    });

    search.init();

})(jQuery);
<|endoftext|>


<commit_before>export const sym = id => `@@redux-saga/${id}`
export const TASK  = sym('TASK')
export const MATCH = sym('MATCH')
export const CANCEL = sym('cancelPromise')
export const konst = v => () => v
export const kTrue = konst(true)
export const kFalse = konst(false)
export const noop = () => {}
export const ident = v => v

export function check(value, predicate, error) {
  if(!predicate(value)) {
    log('error', 'uncaught at check', error)
    throw new Error(error)
  }
}

export const is = {
  undef     : v => v === null || v === undefined,
  notUndef  : v => v !== null && v !== undefined,
  func      : f => typeof f === 'function',
  number    : n => typeof n === 'number',
  array     : Array.isArray,
  promise   : p => p && is.func(p.then),
  iterator  : it => it && is.func(it.next) && is.func(it.throw),
  task      : t => t && t[TASK],
  take      : ch => ch && is.func(ch.take),
  put       : ch => ch && is.func(ch.put),
  observable: ob => ob && is.func(ob.subscribe),
  buffer    : buf => buf && is.func(buf.isEmpty) && is.func(buf.take) && is.func(buf.put),
  pattern   : pat => pat && ((typeof pat === 'string') || is.func(pat) || is.array(pat))
}

export function remove(array, item) {
  const index = array.indexOf(item)
  if(index >= 0) {
    array.splice(index, 1)
  }
}

export function deferred(props = {}) {
  let def = {...props}
  const promise = new Promise((resolve, reject) => {
    def.resolve = resolve
    def.reject = reject
  })
  def.promise = promise
  return def
}

export function arrayOfDeffered(length) {
  const arr = []
  for (var i = 0; i < length; i++) {
    arr.push(deferred())
  }
  return arr
}

export function delay(ms, val=true) {
  let timeoutId
  const promise = new Promise(resolve => {
    timeoutId = setTimeout(() => resolve(val), ms)
  })

  promise[CANCEL] = () => clearTimeout(timeoutId)

  return promise
}

export function createMockTask() {
  let running = true
  let result, error

  return {
    [TASK]: true,
    isRunning: () => running,
    result: () => result,
    error: () => error,

    setRunning : b => running = b,
    setResult  : r => result = r,
    setError   : e => error = e
  }
}

export function autoInc(seed = 0) {
  return () => ++seed
}

const kThrow = err => { throw err }
export function makeIterator(next, thro = kThrow, name = '') {
  const iterator = {name, next, throw: thro}
  if(typeof Symbol !== 'undefined') {
    iterator[Symbol.iterator] = () => iterator
  }
  return iterator
}

/**
  Print error in a useful way whether in a browser environment
  (with expandable error stack traces), or in a node.js environment
  (text-only log output)
 **/
export function log(level, message, error) {
  /*eslint-disable no-console*/
  if(typeof window === 'undefined') {
    console.log(`redux-saga ${level}: ${message}\n${(error && error.stack) || error}`)
  } else {
    console[level].call(console, message, error)
  }
}

export const internalErr = err => new Error(`
  redux-saga: Error checking hooks detected an inconsisten state. This is likely a bug
  in redux-saga code and not yours. Thanks for reporting this in the project's github repo.
  Error: ${err}
`)
<commit_msg>Handle symbol patterns properly<commit_after>export const sym = id => `@@redux-saga/${id}`
export const TASK  = sym('TASK')
export const MATCH = sym('MATCH')
export const CANCEL = sym('cancelPromise')
export const konst = v => () => v
export const kTrue = konst(true)
export const kFalse = konst(false)
export const noop = () => {}
export const ident = v => v

export function check(value, predicate, error) {
  if(!predicate(value)) {
    log('error', 'uncaught at check', error)
    throw new Error(error)
  }
}

export const is = {
  undef     : v => v === null || v === undefined,
  notUndef  : v => v !== null && v !== undefined,
  func      : f => typeof f === 'function',
  number    : n => typeof n === 'number',
  array     : Array.isArray,
  promise   : p => p && is.func(p.then),
  iterator  : it => it && is.func(it.next) && is.func(it.throw),
  task      : t => t && t[TASK],
  take      : ch => ch && is.func(ch.take),
  put       : ch => ch && is.func(ch.put),
  observable: ob => ob && is.func(ob.subscribe),
  buffer    : buf => buf && is.func(buf.isEmpty) && is.func(buf.take) && is.func(buf.put),
  pattern   : pat => pat && ((typeof pat === 'string') || (typeof pat === 'symbol') || is.func(pat) || is.array(pat))
}

export function remove(array, item) {
  const index = array.indexOf(item)
  if(index >= 0) {
    array.splice(index, 1)
  }
}

export function deferred(props = {}) {
  let def = {...props}
  const promise = new Promise((resolve, reject) => {
    def.resolve = resolve
    def.reject = reject
  })
  def.promise = promise
  return def
}

export function arrayOfDeffered(length) {
  const arr = []
  for (var i = 0; i < length; i++) {
    arr.push(deferred())
  }
  return arr
}

export function delay(ms, val=true) {
  let timeoutId
  const promise = new Promise(resolve => {
    timeoutId = setTimeout(() => resolve(val), ms)
  })

  promise[CANCEL] = () => clearTimeout(timeoutId)

  return promise
}

export function createMockTask() {
  let running = true
  let result, error

  return {
    [TASK]: true,
    isRunning: () => running,
    result: () => result,
    error: () => error,

    setRunning : b => running = b,
    setResult  : r => result = r,
    setError   : e => error = e
  }
}

export function autoInc(seed = 0) {
  return () => ++seed
}

const kThrow = err => { throw err }
export function makeIterator(next, thro = kThrow, name = '') {
  const iterator = {name, next, throw: thro}
  if(typeof Symbol !== 'undefined') {
    iterator[Symbol.iterator] = () => iterator
  }
  return iterator
}

/**
  Print error in a useful way whether in a browser environment
  (with expandable error stack traces), or in a node.js environment
  (text-only log output)
 **/
export function log(level, message, error) {
  /*eslint-disable no-console*/
  if(typeof window === 'undefined') {
    console.log(`redux-saga ${level}: ${message}\n${(error && error.stack) || error}`)
  } else {
    console[level].call(console, message, error)
  }
}

export const internalErr = err => new Error(`
  redux-saga: Error checking hooks detected an inconsisten state. This is likely a bug
  in redux-saga code and not yours. Thanks for reporting this in the project's github repo.
  Error: ${err}
`)
<|endoftext|>


<commit_before>/* eslint-disable no-unused-vars*/
/* eslint-disable no-trailing-spaces*/
/**
 * Class for Inverted Index.
 *
 * @class
 */
class InvertedIndexClass {
    /**
     * Class Instantiation.
     */
  constructor() {
    this.index = {};
    this.books = {};
    this.parsedBooks = {};
  }
    /**
     * returns created index
     * @returns{object};
     */
  getIndex() {
    return this.index;
  }
    /**
     * Valid Files
     *
     * Checks if the passed in JSON object is valid
     *
     * @param {object} jsonObj accepts a json file and checks if it is valid
     * @returns {array} returns an array, the first value being true or
     * false and the second value being an error message
     */
  validFiles(jsonObj) {
    try {
      if (jsonObj === ' ' || jsonObj === '' || jsonObj === '""') {
        return [false, 'Error, empty file'];
      }
      this.parsedBooks = JSON.parse(jsonObj);
      const validityCheck = false;
      if (!this.parsedBooks.length) {
        throw new Error('Invalid Format');
      }
      this.parsedBooks.forEach((entry) => {
        if (entry.title === undefined || entry.text === undefined) {
          throw new Error('Invalid Format');
        }
      });
      return [true, 'Success'];
    } catch (error) {
      if (error.message === 'Invalid Format') {
        return [false, 'this Index takes books with Title and Text property only'];
      } else if (error.name === 'SyntaxError') {
        return [false, 'Invalid JSON file'];
      }
    }
  }
    /**
     * create Index
     *
     * creates an index of words
     *
     * @param{string}  filename accepts a string name for a file;
     * @param{object} books is a json object for which an index is to be created
     * @returns{object};
     */
  createIndex(filename, books) {
    this.index[filename] = {};
    this.books = books;

    for (let i = 0; i < books.length; i += 1) {
      const textIndex = books[i].text.toLowerCase().match(/\w+/g);
      for (let j = 0; j < textIndex.length; j += 1) {
        if (this.index[filename][textIndex[j]] === undefined) {
          this.index[filename][textIndex[j]] = {};
          this.index[filename][textIndex[j]][i] = true;
        } else {
          this.index[filename][textIndex[j]][i] = true;
        }
      }
    }
    return this.index;
  }
    /**
     * Search Index
     *
     * Searches through the indexes for the specified search terms
     *
     * @param {string} queries
     * @param{string} filename
     * @return {Object} An Object Containing the Various words and their Locations.
     */
  searchIndex(queries, filename) {
    let filesToSearch = [];
    const searchResult = {};
    if (!filename) {
      filesToSearch = filesToSearch.concat(Object.keys(this.index));
    } else {
      filesToSearch.push(filename);
    }
    filesToSearch.forEach((searchKey) => {
      searchResult[searchKey] = {};
      if (typeof (queries) === typeof []) {
        queries = queries.join();
      }
      queries = queries.toLowerCase().match(/\w+/g);
      for (let word = 0; word < queries.length; word += 1) {
        if (this.index[searchKey][queries[word]]) {
          searchResult[searchKey][queries[word]] = this.index[searchKey][queries[word]];
        }
      }
    });
    return searchResult;
  }
}
<commit_msg>fixed order of methods<commit_after>/* eslint-disable no-unused-vars*/
/* eslint-disable no-trailing-spaces*/
/**
 * Class for Inverted Index.
 *
 * @class
 */
class InvertedIndexClass {
    /**
     * Class Instantiation.
     */
  constructor() {
    this.index = {};
    this.books = {};
    this.parsedBooks = {};
  }

    /**
     * create Index
     *
     * creates an index of words
     *
     * @param{string}  filename accepts a string name for a file;
     * @param{object} books is a json object for which an index is to be created
     * @returns{object};
     */
  createIndex(filename, books) {
    this.index[filename] = {};
    this.books = books;

    for (let i = 0; i < books.length; i += 1) {
      const textIndex = books[i].text.toLowerCase().match(/[\w']+/g);
      for (let j = 0; j < textIndex.length; j += 1) {
        if (this.index[filename][textIndex[j]] === undefined) {
          this.index[filename][textIndex[j]] = {};
          this.index[filename][textIndex[j]][i] = true;
        } else {
          this.index[filename][textIndex[j]][i] = true;
        }
      }
    }
    return this.index;
  }
  /**
     * returns created index
     *
     * @returns{object};
     */
  getIndex() {
    return this.index;
  }
    /**
     * Search Index
     *
     * Searches through the indexes for the specified search terms
     *
     * @param {string} queries
     * @param{string} filename
     * @return {Object} An Object Containing the Various words and their Locations.
     */
  searchIndex(queries, filename) {
    let filesToSearch = [];
    const searchResult = {};
    if (!filename) {
      filesToSearch = filesToSearch.concat(Object.keys(this.index));
    } else {
      filesToSearch.push(filename);
    }
    filesToSearch.forEach((searchKey) => {
      searchResult[searchKey] = {};
      if (typeof (queries) === typeof []) {
        queries = queries.join();
      }
      queries = queries.toLowerCase().match(/\w+/g);
      for (let word = 0; word < queries.length; word += 1) {
        if (this.index[searchKey][queries[word]]) {
          searchResult[searchKey][queries[word]] = this.index[searchKey][queries[word]];
        }
      }
    });
    return searchResult;
  }
  /**
     * Valid Files
     *
     * Checks if the passed in JSON object is valid
     *
     * @param {object} jsonObj accepts a json file and checks if it is valid
     * @returns {array} returns an array, the first value being true or
     * false and the second value being an error message
     */
  validFiles(jsonObj) {
    try {
      if (jsonObj === ' ' || jsonObj === '' || jsonObj === '""') {
        return [false, 'Error, empty file'];
      }
      this.parsedBooks = JSON.parse(jsonObj);
      const validityCheck = false;
      if (!this.parsedBooks.length) {
        throw new Error('Invalid Format');
      }
      this.parsedBooks.forEach((entry) => {
        if (entry.title === undefined || entry.text === undefined) {
          throw new Error('Invalid Format');
        }
      });
      return [true, 'Success'];
    } catch (error) {
      if (error.message === 'Invalid Format') {
        return [false, 'this Index takes books with Title and Text property only'];
      } else if (error.name === 'SyntaxError') {
        return [false, 'Invalid JSON file'];
      }
    }
  }
}
<|endoftext|>


<commit_before>/* jshint browser:true,jquery:true */

;(function($, window, document, undefined) {
  "use strict";
  /*jshint scripturl:true, -W084*/

  var $window = $(window), $document = $(document);

  var TARGETS = {
    'Facebook': 'https://www.facebook.com/sharer/sharer.php?u={$url}&t={$title}',
    'Twitter': 'https://twitter.com/intent/tweet?text={$title}&url={$url}&via={$via}',
    'LinkedIn': 'https://www.linkedin.com/shareArticle?mini=true&url={$url}&title={$title}',
    'Google+': 'https://plus.google.com/share?url={$url}',
    'OilPro': 'http://oilpro.com/links/submit?url={$url}',
    'Print': 'javascript:window.print()',
    'Email': 'mailto:?subject={$title}&body={$url}'
  };

  var PLUGIN_NAME = 'BEShare';
  var defaults = {
    'type': 'popup',
    'targets': ['Facebook', 'Twitter'],
    'class': PLUGIN_NAME,
    'prefix': 'icon-',
    'suffix': '',
    'aria-prefix': 'Share on ',
    'width': '626',
    'height': '436',
    'via': '',
    'onShare': null,
    'altLink': null
  };

  // Mini template engine.
  function template(tpl, data) {
    var re = /\{\$([^}]+)?\}/g, match;
    while(match = re.exec(tpl)) {
      tpl = tpl.replace(match[0], data[match[1]]);
    }
    return tpl;
  }

  function move($element, offset) {
    if (!offset) {
      offset = {
        'top': '-9999px',
        'left': '-9999px'
      };
    }
    $element.css(offset);
  }

  function Plugin(element, options) {
    this.element = $(element);
    this.options = $.extend({}, defaults, options);

    this._name = PLUGIN_NAME;
    this.init();
  }

  Plugin.prototype.init = function() {
    var options = this.options, $container;
    if (options.type === "inline") {
      $container = this.element;
    } else {
      $container = $('
');
      $container.appendTo(document.body);
      $container.css({
        'position': 'absolute'
      });
      move($container);
    }
    this.container = $container;
    $container.addClass(options['class']);

    var targets = options.targets;
    if ($.type(targets) === 'string') {
      // @TODO: Parse string 'ServiceA,ServiceB|ServiceC,ServiceD'
    }

    var i, total = targets.length;
    for (i = 0; i < total; i++) {
      this.add(targets[i]);
    }

    if (options.type === 'popup') {
      this.element.on('click.'+PLUGIN_NAME, function(event) {
        // Stop the event from bubbling up to the below handler.
        event.stopPropagation();

        var position = $(this).offset();

        move($container, position);
        $container.addClass('active');
        return false;
      });

      // Clicking anywhere outside will close the popup.
      $document.on('click.'+PLUGIN_NAME, function(event) {
        if(!$(event.target).closest('.'+options['class']).length) {
          if ($container.hasClass('active')) {
            $container.removeClass('active');
            move($container);
          }
        }
      });
    }
  };

  Plugin.prototype.add = function(targetName) {
    var options = this.options;
    var target = TARGETS[targetName];
    if (!target) {
      // Any string not of a target is output as is.
      this.container.append(targetName);
      return this;
    }

    var builtUrl = this.element.attr('href') || document.location.href;

    if(options.altLink) {
      builtUrl = builtUrl + "/" + (this.element.attr('rel') || '');
    }

    var url = template(target, {
      url: encodeURIComponent(builtUrl),
      title: encodeURIComponent(document.title),
      via: encodeURIComponent(options.via)
    });

    var $link = $('' + targetName + '');

    switch (targetName) {
      case 'Print':
        $link.attr('title', 'Print this page');
        break;
      case 'Email':
        $link.attr('title', 'Share this page via Email');
        break;
      default:
        $link.attr('title', 'Share this page on ' + targetName);
        break;
    }

    if (url.indexOf('http') === 0) {
      // External links
      $link.attr('target', '_blank');
      $link.on('click.'+PLUGIN_NAME, function() {
        window.open(url, PLUGIN_NAME, 'toolbar=0,status=0,width='+options.width+',height='+options.height);

        if (options.onShare) {
          options.onShare(targetName);
        }
        return false;
      });
    }

    $link.addClass(options.prefix + targetName.toLowerCase().replace('+','plus') + options.suffix);
    $link.attr('aria-label', options["aria-prefix"] + targetName.toLowerCase().replace('+','plus'));
    $link.appendTo(this.container);
    return this;
  };

  $.fn[PLUGIN_NAME] = function(options) {
    return this.each(function() {
      if (!$.data(this, 'plugin_' + PLUGIN_NAME)) {
        $.data(this, 'plugin_' + PLUGIN_NAME,
        new Plugin( this, options ));
      }
    });
  };
})(jQuery, window, document);
<commit_msg>Make message (title) configurable<commit_after>/* jshint browser:true,jquery:true */

;(function($, window, document, undefined) {
  "use strict";
  /*jshint scripturl:true, -W084*/

  var $window = $(window), $document = $(document);

  var TARGETS = {
    'Facebook': 'https://www.facebook.com/sharer/sharer.php?u={$url}&t={$title}',
    'Twitter': 'https://twitter.com/intent/tweet?text={$title}&url={$url}&via={$via}',
    'LinkedIn': 'https://www.linkedin.com/shareArticle?mini=true&url={$url}&title={$title}',
    'Google+': 'https://plus.google.com/share?url={$url}',
    'OilPro': 'http://oilpro.com/links/submit?url={$url}',
    'Print': 'javascript:window.print()',
    'Email': 'mailto:?subject={$title}&body={$url}'
  };

  var PLUGIN_NAME = 'BEShare';
  var defaults = {
    'type': 'popup',
    'targets': ['Facebook', 'Twitter'],
    'class': PLUGIN_NAME,
    'prefix': 'icon-',
    'suffix': '',
    'aria-prefix': 'Share on ',
    'width': '626',
    'height': '436',
    'message': document.title,
    'via': '',
    'onShare': null,
    'altLink': null
  };

  // Mini template engine.
  function template(tpl, data) {
    var re = /\{\$([^}]+)?\}/g, match;
    while(match = re.exec(tpl)) {
      tpl = tpl.replace(match[0], data[match[1]]);
    }
    return tpl;
  }

  function move($element, offset) {
    if (!offset) {
      offset = {
        'top': '-9999px',
        'left': '-9999px'
      };
    }
    $element.css(offset);
  }

  function Plugin(element, options) {
    this.element = $(element);
    this.options = $.extend({}, defaults, options);

    this._name = PLUGIN_NAME;
    this.init();
  }

  Plugin.prototype.init = function() {
    var options = this.options, $container;
    if (options.type === "inline") {
      $container = this.element;
    } else {
      $container = $('
');
      $container.appendTo(document.body);
      $container.css({
        'position': 'absolute'
      });
      move($container);
    }
    this.container = $container;
    $container.addClass(options['class']);

    var targets = options.targets;
    if ($.type(targets) === 'string') {
      // @TODO: Parse string 'ServiceA,ServiceB|ServiceC,ServiceD'
    }

    var i, total = targets.length;
    for (i = 0; i < total; i++) {
      this.add(targets[i]);
    }

    if (options.type === 'popup') {
      this.element.on('click.'+PLUGIN_NAME, function(event) {
        // Stop the event from bubbling up to the below handler.
        event.stopPropagation();

        var position = $(this).offset();

        move($container, position);
        $container.addClass('active');
        return false;
      });

      // Clicking anywhere outside will close the popup.
      $document.on('click.'+PLUGIN_NAME, function(event) {
        if(!$(event.target).closest('.'+options['class']).length) {
          if ($container.hasClass('active')) {
            $container.removeClass('active');
            move($container);
          }
        }
      });
    }
  };

  Plugin.prototype.add = function(targetName) {
    var options = this.options;
    var target = TARGETS[targetName];
    if (!target) {
      // Any string not of a target is output as is.
      this.container.append(targetName);
      return this;
    }

    var builtUrl = this.element.attr('href') || document.location.href;

    if(options.altLink) {
      builtUrl = builtUrl + "/" + (this.element.attr('rel') || '');
    }

    var url = template(target, {
      url: encodeURIComponent(builtUrl),
      title: encodeURIComponent(options.message),
      via: encodeURIComponent(options.via)
    });

    var $link = $('' + targetName + '');

    switch (targetName) {
      case 'Print':
        $link.attr('title', 'Print this page');
        break;
      case 'Email':
        $link.attr('title', 'Share this page via Email');
        break;
      default:
        $link.attr('title', 'Share this page on ' + targetName);
        break;
    }

    if (url.indexOf('http') === 0) {
      // External links
      $link.attr('target', '_blank');
      $link.on('click.'+PLUGIN_NAME, function() {
        window.open(url, PLUGIN_NAME, 'toolbar=0,status=0,width='+options.width+',height='+options.height);

        if (options.onShare) {
          options.onShare(targetName);
        }
        return false;
      });
    }

    $link.addClass(options.prefix + targetName.toLowerCase().replace('+','plus') + options.suffix);
    $link.attr('aria-label', options["aria-prefix"] + targetName.toLowerCase().replace('+','plus'));
    $link.appendTo(this.container);
    return this;
  };

  $.fn[PLUGIN_NAME] = function(options) {
    return this.each(function() {
      if (!$.data(this, 'plugin_' + PLUGIN_NAME)) {
        $.data(this, 'plugin_' + PLUGIN_NAME,
        new Plugin( this, options ));
      }
    });
  };
})(jQuery, window, document);
<|endoftext|>


<commit_before>const path = require('path')
const cleanRE = /\W+/g

exports.encode = function (source) {
  if (Array.isArray(source)) {
    var key = source.slice()
    key.map(seg => seg.replace(cleanRE, ''))
    key[key.length - 1] += '.json'
    return path.join.apply(null, key)
  }
  return source.replace(cleanRE, '') + '.json'
}

exports.decode = function (source) {
  return source.split(path.sep)
}

exports.buffer = false;
exports.type = 'fs';

<commit_msg>might as well permit non-contiguous whitespace, but this requires trim to prevent leading and trailing spaces<commit_after>const path = require('path')
const cleanRE = /\W+/g

exports.encode = function (source) {
  if (Array.isArray(source)) {
    var key = source.slice()
    key.map(seg => seg.replace(cleanRE, ' ').trim())
    key[key.length - 1] += '.json'
    return path.join.apply(null, key)
  }
  return source.replace(cleanRE, '').trim() + '.json'
}

exports.decode = function (source) {
  return source.split(path.sep)
}

exports.buffer = false;
exports.type = 'fs';

<|endoftext|>


<commit_before>/**
 * @file
 * @author zdying
 */
var express = require('express');
var colors = require('colors');
var path = require('path');
var fs = require('fs');
var open = require("open");

var logger = log.namespace('Server');
// var Compiler = require('./Compiler');
var Compiler = require('../compiler');

var clients = {};
var clientId = 0;

var docSVG = fs.readFileSync(path.resolve(__dirname, 'source', 'image', 'Document.svg'));
var fileSVG = fs.readFileSync(path.resolve(__dirname, 'source', 'image', 'File.svg'));
var folderSVG = fs.readFileSync(path.resolve(__dirname, 'source', 'image', 'Folder.svg'));

function Server(port, openBrowser){
    this.app = express();
    this.compilers = {};

    this.app.all('*', function(req, res, next){
        req.url = req.url.replace(/[\?\#].*$/, '');
        req._startTime = Date.now();
        logger.debug('request -', req.url);
        next();
    });

    // this.app.get('/__webpack_hmr', function(req, res, next){
    //     req.socket.setKeepAlive(true);
    //     res.writeHead(200, {
    //         'Access-Control-Allow-Origin': '*',
    //         'Content-Type': 'text/event-stream;charset=utf-8',
    //         'Transfer-Encoding': 'chunked',
    //         'Cache-Control': 'no-cache, no-transform',
    //         'Connection': 'keep-alive'
    //     });
    //     res.write('\n');
    //     var id = clientId++;
    //     clients[id] = res;
    //     req.on("close", function(){
    //         delete clients[id];
    //     });
    //
    //     setInterval(function(){
    //         res.write("data: \uD83D\uDC93\n\n");
    //     }, 2000)
    // });

    this.app.get('/favicon.ico', function(req, res, next){
        this.sendFile(req, __dirname + '/source/favicon.ico');
    }.bind(this));

    this.app.all('*', function(req, res, next){
        var url = req.url;
        // var filePath = path.resolve('.' + url);
        var filePath = __hii__.cwd + url;
        var projInfo = this.getProjectInfoFromURL(url);

        logger.debug('projInfo:' + JSON.stringify(projInfo));

        if(projInfo){
            var projectName = projInfo.projectName;
            var fileExt = projInfo.fileExt;
            var env = projInfo.env;
            var compiler = this.compilers[projectName];

            if(!compiler){
                compiler = this.compilers[projectName] = new Compiler(projectName);
            }

            if(fileExt === 'scss'){
                // 编译sass文件
                return compiler.compileSASS(filePath, function(err, css, time, result){
                    if(err){
                        res.statusCode = 500;
                        res.end(err.stack || err.message)
                    }else{
                        res.setHeader('Content-Type', 'text/css');
                        res.end(css);
                        logger.debug('*.sass', '-', filePath.bold, 'compiled', (time + 'ms').magenta);
                    }
                    logger.access(req);
                });
            }else if(fileExt === 'js'){
                if(env === 'prd'/* || req.url.indexOf('hot-update.js') !== -1*/){
                    return compiler.compile('loc', function(){
                        this.sendCompiledFile(req, projInfo)
                    }.bind(this))
                }else if(env === 'dev'){
                    filePath = filePath.replace(/@(\w+)\.(\w+)/, '@dev.$2');

                    logger.debug(req.url, '==>', filePath);

                    if(fs.statSync(filePath).isFile()){
                        this.sendFile(req, filePath)
                    }
                }else if(env === 'src' || env === 'loc'){
                    this.sendFile(req)
                }
            }else if(fileExt === 'css'){
                if(fs.existsSync(filePath)){
                    this.sendFile(req, filePath);
                }else{
                    var userConfig = require(path.resolve('.', projInfo.projectName, 'hii.config.js'));
                    var entry = userConfig.entry;
                    var entries = Object.keys(entry);

                    if(entries.indexOf(projInfo.fileName) !== -1){
                        // 处理css文件
                        res.setHeader('Content-Type', 'text/css');
                        logger.debug('css -', filePath.bold, 'replaced');
                        res.end('/* The `css` code in development environment has been moved to the `js` file */');
                        logger.access(req);
                    }else{
                        // will return 404
                        this.sendFile(req, filePath);
                    }
                }
            }else{
                // 其它文件
                filePath = filePath.replace(/\/prd\//, '/src/');

                logger.debug(req.url, '==>', filePath);
                try{
                    if(fs.statSync(filePath).isFile()){
                        this.sendFile(req, filePath)
                    }
                }catch(e){
                    res.statusCode = 404;
                    res.end('404 Not Found');
                    logger.error(e);
                    logger.access(req);
                }
            }
        }else{
            try{
                var stat = fs.statSync(filePath);
                if(stat.isDirectory()){
                    fs.readdir(filePath, function(err, files){
                        if(err){
                            logger.error(err);
                        }else{
                            res.setHeader('Content-Type', 'text/html');

                            var html = [
                                '',
                                '
'
                            ];
                            html.push('
');
                            html.push(      '', folderSVG, '../');
                            html.push('
');
                            var filesItem = files.map(function(fileName){
                                if(fileName.slice(0, 1) === '.'){
                                    logger.debug('hide system file/directory', fileName.bold);
                                    // 不显示系统隐藏文件
                                    return
                                }

                                var isFile = fs.statSync(filePath + '/' + fileName).isFile();

                                return [
                                    '
',
                                        '',
                                            isFile ? (fileName.indexOf('.') === -1 ? fileSVG : docSVG) : folderSVG,
                                            fileName,
                                        '',
                                    '
'
                                ].join('')
                            });

                            html.push.apply(html, filesItem);

                            html.push('
');
                        }

                        res.end(html.join(''));

                        logger.access(req);
                    });
                }else{
                    this.sendFile(req)
                }
            }catch(e){
                res.statusCode = 404;
                res.end('404 Not Found');

                logger.error(e);
                logger.access(req);
            }
        }
    }.bind(this));

    var server = this.app.listen(port);

    server.on('error', function(err){
        if(err.code === 'EADDRINUSE'){
            console.log('port', String(port).bold.yellow, 'is already in use.');
            server.close();
        }else{
            console.log(err.message);
        }
    });

    server.on('listening', function(){
        var url = 'http://127.0.0.1:' + port;
        openBrowser && open(url);

        console.log();
        console.log('hiipack started at', url.green.bold);
        console.log('current workspace ', __hiipack__.cwd.green.bold);
        console.log();

        logger.debug('__hii__', '-',  JSON.stringify(__hiipack__));
    });

    process.on("SIGINT", function(){
        console.log('\b\b  ');
        console.log('Bye Bye.'.bold.yellow);
        process.exit()
    });

    process.on('SIGTERM', function(){
        console.log('Bye Bye.'.bold.yellow);
        process.exit()
    });
}

Server.prototype = {
    constructor: Server,
    /**
     * 发送文件
     * @param req
     * @param filePath
     * @param env
     */
    sendFile: function(req, filePath){
        filePath = filePath || __hii__.cwd + req.url;

        logger.debug('send file: ' + filePath.bold);

        var res = req.res;

        res.sendFile(filePath, function(err){
            if(err){
                res.statusCode = 404;
                res.end('404 Not Found');
                logger.error(err);
            }
            logger.access(req);
        });
    },

    getProjectInfoFromURL: function(url){
        //  url,  projectName,    env,    folder, fileName, version, fileExt,     paramsAndHash
        var reg = /\/(.*?)\/(src|prd|loc|dev)(\/.*)?\/(.*?)(@\w+)?(?:\.(\w+))([\#\?].*)?$/;
        var result = url.match(reg);

        if(result){
            return {
                projectName: result[1],
                env: result[2],
                folder: result[3],
                fileName: result[4],
                version: result[5],
                fileExt: result[6],
                paramsAndHash: result[7]
            }
        }else{
            return null
        }
    },

    sendCompiledFile: function(req, projInfo){
        var filePath = __hii__.tmpdir + req.url;
        filePath = filePath.replace(/@[\w+]+\.(js|css)/, '.$1').replace(/\/prd\//, '/loc/');
        this.sendFile(req, filePath);
        // var content = mfs.readFileSync(filePath)//.toString();
        // req.res.setHeader('Content-Type', 'text/javascript');
        // req.res.setHeader('Content-Length', content.length);
        // req.res.send(content)
    }
};

function publish(data){
    for(var id in clients){
        clients[id].write("data: " + JSON.stringify(data) + "\n\n");
    }
}

function buildModuleMap(modules){
    var map = {};
    modules.forEach(function(module){
        map[module.id] = module.name;
    });
    return map;
}

module.exports = Server;<commit_msg>fix bug<commit_after>/**
 * @file
 * @author zdying
 */
var express = require('express');
var colors = require('colors');
var path = require('path');
var fs = require('fs');
var open = require("open");

var logger = log.namespace('Server');
// var Compiler = require('./Compiler');
var Compiler = require('../compiler');

var clients = {};
var clientId = 0;

var docSVG = fs.readFileSync(path.resolve(__dirname, 'source', 'image', 'Document.svg'));
var fileSVG = fs.readFileSync(path.resolve(__dirname, 'source', 'image', 'File.svg'));
var folderSVG = fs.readFileSync(path.resolve(__dirname, 'source', 'image', 'Folder.svg'));

function Server(port, openBrowser){
    this.app = express();
    this.compilers = {};

    this.app.all('*', function(req, res, next){
        req.url = req.url.replace(/[\?\#].*$/, '');
        req._startTime = Date.now();
        logger.debug('request -', req.url);
        next();
    });

    // this.app.get('/__webpack_hmr', function(req, res, next){
    //     req.socket.setKeepAlive(true);
    //     res.writeHead(200, {
    //         'Access-Control-Allow-Origin': '*',
    //         'Content-Type': 'text/event-stream;charset=utf-8',
    //         'Transfer-Encoding': 'chunked',
    //         'Cache-Control': 'no-cache, no-transform',
    //         'Connection': 'keep-alive'
    //     });
    //     res.write('\n');
    //     var id = clientId++;
    //     clients[id] = res;
    //     req.on("close", function(){
    //         delete clients[id];
    //     });
    //
    //     setInterval(function(){
    //         res.write("data: \uD83D\uDC93\n\n");
    //     }, 2000)
    // });

    this.app.get('/favicon.ico', function(req, res, next){
        this.sendFile(req, __dirname + '/source/favicon.ico');
    }.bind(this));

    this.app.all('*', function(req, res, next){
        var url = req.url;
        // var filePath = path.resolve('.' + url);
        var filePath = __hii__.cwd + url;
        var projInfo = this.getProjectInfoFromURL(url);

        logger.debug('projInfo:' + JSON.stringify(projInfo));

        if(projInfo){
            var projectName = projInfo.projectName;
            var fileExt = projInfo.fileExt;
            var env = projInfo.env;
            var compiler = this.compilers[projectName];

            if(!compiler){
                compiler = this.compilers[projectName] = new Compiler(projectName);
            }

            if(fileExt === 'scss'){
                // 编译sass文件
                return compiler.compileSASS(filePath, function(err, css, time, result){
                    if(err){
                        res.statusCode = 500;
                        res.end(err.stack || err.message)
                    }else{
                        res.setHeader('Content-Type', 'text/css');
                        res.end(css);
                        logger.debug('*.sass', '-', filePath.bold, 'compiled', (time + 'ms').magenta);
                    }
                    logger.access(req);
                });
            }else if(fileExt === 'js'){
                if(env === 'prd'/* || req.url.indexOf('hot-update.js') !== -1*/){
                    return compiler.compile('loc', function(){
                        this.sendCompiledFile(req, projInfo)
                    }.bind(this))
                }else if(env === 'dev'){
                    filePath = filePath.replace(/@(\w+)\.(\w+)/, '@dev.$2');

                    logger.debug(req.url, '==>', filePath);

                    if(fs.statSync(filePath).isFile()){
                        this.sendFile(req, filePath)
                    }
                }else if(env === 'src' || env === 'loc'){
                    this.sendFile(req)
                }
            }else if(fileExt === 'css'){
                if(fs.existsSync(filePath)){
                    this.sendFile(req, filePath);
                }else{
                    var userConfig = require(path.resolve(__hii__.cwd, projInfo.projectName, 'hii.config.js'));
                    var entry = userConfig.entry;
                    var entries = Object.keys(entry);

                    if(entries.indexOf(projInfo.fileName) !== -1){
                        // 处理css文件
                        res.setHeader('Content-Type', 'text/css');
                        logger.debug('css -', filePath.bold, 'replaced');
                        res.end('/* The `css` code in development environment has been moved to the `js` file */');
                        logger.access(req);
                    }else{
                        // will return 404
                        this.sendFile(req, filePath);
                    }
                }
            }else{
                // 其它文件
                filePath = filePath.replace(/\/prd\//, '/src/');

                logger.debug(req.url, '==>', filePath);
                try{
                    if(fs.statSync(filePath).isFile()){
                        this.sendFile(req, filePath)
                    }
                }catch(e){
                    res.statusCode = 404;
                    res.end('404 Not Found');
                    logger.error(e);
                    logger.access(req);
                }
            }
        }else{
            try{
                var stat = fs.statSync(filePath);
                if(stat.isDirectory()){
                    fs.readdir(filePath, function(err, files){
                        if(err){
                            logger.error(err);
                        }else{
                            res.setHeader('Content-Type', 'text/html');

                            var html = [
                                '',
                                '
'
                            ];
                            html.push('
');
                            html.push(      '', folderSVG, '../');
                            html.push('
');
                            var filesItem = files.map(function(fileName){
                                if(fileName.slice(0, 1) === '.'){
                                    logger.debug('hide system file/directory', fileName.bold);
                                    // 不显示系统隐藏文件
                                    return
                                }

                                var isFile = fs.statSync(filePath + '/' + fileName).isFile();

                                return [
                                    '
',
                                        '',
                                            isFile ? (fileName.indexOf('.') === -1 ? fileSVG : docSVG) : folderSVG,
                                            fileName,
                                        '',
                                    '
'
                                ].join('')
                            });

                            html.push.apply(html, filesItem);

                            html.push('
');
                        }

                        res.end(html.join(''));

                        logger.access(req);
                    });
                }else{
                    this.sendFile(req)
                }
            }catch(e){
                res.statusCode = 404;
                res.end('404 Not Found');

                logger.error(e);
                logger.access(req);
            }
        }
    }.bind(this));

    var server = this.app.listen(port);

    server.on('error', function(err){
        if(err.code === 'EADDRINUSE'){
            console.log('port', String(port).bold.yellow, 'is already in use.');
            server.close();
        }else{
            console.log(err.message);
        }
    });

    server.on('listening', function(){
        var url = 'http://127.0.0.1:' + port;
        openBrowser && open(url);

        console.log();
        console.log('hiipack started at', url.green.bold);
        console.log('current workspace ', __hiipack__.cwd.green.bold);
        console.log();

        logger.debug('__hii__', '-',  JSON.stringify(__hiipack__));
    });

    process.on("SIGINT", function(){
        console.log('\b\b  ');
        console.log('Bye Bye.'.bold.yellow);
        process.exit()
    });

    process.on('SIGTERM', function(){
        console.log('Bye Bye.'.bold.yellow);
        process.exit()
    });
}

Server.prototype = {
    constructor: Server,
    /**
     * 发送文件
     * @param req
     * @param filePath
     * @param env
     */
    sendFile: function(req, filePath){
        filePath = filePath || __hii__.cwd + req.url;

        logger.debug('send file: ' + filePath.bold);

        var res = req.res;

        res.sendFile(filePath, function(err){
            if(err){
                res.statusCode = 404;
                res.end('404 Not Found');
                logger.error(err);
            }
            logger.access(req);
        });
    },

    getProjectInfoFromURL: function(url){
        //  url,  projectName,    env,    folder, fileName, version, fileExt,     paramsAndHash
        var reg = /\/(.*?)\/(src|prd|loc|dev)(\/.*)?\/(.*?)(@\w+)?(?:\.(\w+))([\#\?].*)?$/;
        var result = url.match(reg);

        if(result){
            return {
                projectName: result[1],
                env: result[2],
                folder: result[3],
                fileName: result[4],
                version: result[5],
                fileExt: result[6],
                paramsAndHash: result[7]
            }
        }else{
            return null
        }
    },

    sendCompiledFile: function(req, projInfo){
        var filePath = __hii__.tmpdir + req.url;
        filePath = filePath.replace(/@[\w+]+\.(js|css)/, '.$1').replace(/\/prd\//, '/loc/');
        this.sendFile(req, filePath);
        // var content = mfs.readFileSync(filePath)//.toString();
        // req.res.setHeader('Content-Type', 'text/javascript');
        // req.res.setHeader('Content-Length', content.length);
        // req.res.send(content)
    }
};

function publish(data){
    for(var id in clients){
        clients[id].write("data: " + JSON.stringify(data) + "\n\n");
    }
}

function buildModuleMap(modules){
    var map = {};
    modules.forEach(function(module){
        map[module.id] = module.name;
    });
    return map;
}

module.exports = Server;<|endoftext|>


<commit_before>var PIXI = require('pixi.js');
var MapModel = require('./map-model.js')

/*
 * Create a RefugeeMap backed
 * by the given RefugeeModel
 */
var RefugeeMap = function(refugeeModel, mapModel) {
  this.refugeeModel = refugeeModel;
  this.mapModel = mapModel;
  this.width = 1200;
  this.height = 1200;

  if (window.HD_RESOLUTION) {
    this.width = 1920;
    this.height = 1080;
  }

  this.initialize();
  this.graphics = {};
  this.sprites = {};
  this.arrivedRefugeesByCountry = {};

  this.refugeeModel.onRefugeeUpdated = this.onRefugeeUpdated.bind(this);
  this.refugeeModel.onRefugeeFinished = this.onRefugeeFinished.bind(this);
  this.refugeeModel.onRefugeeStarted = this.onRefugeeStarted.bind(this);
};

RefugeeMap.prototype.initialize = function() {
  var lo = 26.2206322; // x
  var la = 46.0485818; // y

  this.projection = d3.geo.mercator()
    .center([0, la])
    .rotate([-lo, 0])
    //.parallels([la - 10, la + 10])
    .scale(this.height*0.55)
    .translate([this.width / 2, this.height / 2]);

  this.svg = d3.select("#canvas-wrap").append("svg")
   .attr("width", this.width)
   .attr("height", this.height);

  window.projection = this.projection;

  this.initializePixiCanvas();
  this.drawBorders();

  d3.select('#canvas-wrap')
    .style('width', this.width + "px")
    .style('height', this.height + "px");
}

RefugeeMap.prototype.initializePixiCanvas = function() {
  PIXI.dontSayHello = true;
  PIXI.utils._saidHello = true;
  PIXI.doNotSayHello = true;
  PIXI.AUTO_PREVENT_DEFAULT = false;

  this.renderer = new PIXI.CanvasRenderer(
  //this.renderer = new PIXI.CanvasRenderer(
      this.width, this.height,
      {transparent: true,
      antialias: true,
      preserveDrawingBuffer: true,
      clearBeforeRender: false});

  d3.select('#canvas-wrap').node().appendChild(this.renderer.view);
  this.renderer.plugins.interaction.autoPreventDefault = false;

  this.renderer.preserveDrawingBuffer = true;
  this.renderer.clearBeforeRender = false;

  //this.stage.interactive = false;

    //this.refugeeContainer = new PIXI.ParticleContainer(
    //	200000,
    //	[false, true, false, false, true],
  //	200000);

  this.stage = new PIXI.Container();

  this.refugeeContainer = new PIXI.Container();
  this.refugeeContainer.alpha = 1.0;
  this.stage.addChild(this.refugeeContainer);

  this.barContainer = new PIXI.Container();
  this.barContainer.alpha = 0.7;
  this.stage.addChild(this.barContainer);

  this.refugeeTexture = new PIXI.Texture.fromImage(
    "one-white-pixel.png",
    new PIXI.math.Rectangle(0, 0, 1, 1));

  //this.refugeeContainer.

  // var g = new PIXI.Graphics();
  // g.blendMode = PIXI.BLEND_MODES.MULTIPLY;
  // g.beginFill(0xFFFFFF, 0.05);
  // g.drawRect(0, 0, this.width, this.height);
  // this.refugeeContainer.addChild(g);

  //var rect = PIXI.Rectangle(0, 0, this.width; this.height);

     //var matrix = [
    //    0.2, 0, 0, 0, 0,
    //    0, 0.2, 0, 0, 0,
    //    0, 0, 0.2, 0, 0,
    //    0, 0, 0, 0, 0
    //];

  //var filter = new PIXI.filters.ColorMatrixFilter();
  //filter.matrix = matrix;
  //this.refugeeContainer.filters = [filter];
}

RefugeeMap.prototype.onRefugeeStarted = function(r) {
  r.sprite = new PIXI.Sprite(this.refugeeTexture);
  r.sprite.alpha = 1.0;
  this.refugeeContainer.addChild(r.sprite);
}

RefugeeMap.prototype.onRefugeeFinished = function(r) {
  this.refugeeContainer.removeChild(r.sprite);
  this.refugeeArrivedAt(r.destinationCountry, r.endPoint);
}

RefugeeMap.prototype.onRefugeeUpdated = function(r) {
  var loc = r.location;
  var point = this.projection(loc);
  r.sprite.position.x = point[0];
  r.sprite.position.y = point[1];
}

// RefugeeMap.prototype.drawRefugeePositionsPixi = function() {

// 	// var length = this.refugeeModel.activeRefugees.length;
// 	// for (var i = 0; i < length; i++) {
// 	// 	var r = this.refugeeModel.activeRefugees[i];
// 	// 	var key = r.endMomentUnix;
// 	//     var s = this.sprites[key];

// 	//     if (!s) {
// 	//     	s = new PIXI.Sprite(this.texture);
// 	//     	this.refugeeContainer.addChild(s);
// 	//     	this.sprites[key] = s;

// 	// 		r.onFinished.push(function() {
// 	// 	 		this.refugeeContainer.removeChild(s);
// 	// 		}.bind(this));
// 	//     }
// 	// 	var loc = r.getLocation(this.refugeeModel.currentMoment);
// 	// 	var point = this.projection(loc);
// 	// 	s.position.x = point[0];
// 	// 	s.position.y = point[1];
// 	// 	s.alpha = 0.7;
// 	// }

//     this.refugeeModel.activeRefugees.forEach(function(r) {
// 		if (!r.sprite) {
// 	    	r.sprite = new PIXI.Sprite(this.refugeeTexture);
// 	    	this.refugeeContainer.addChild(r.sprite);

// 			r.onFinished.push(function() {
// 		 		this.refugeeContainer.removeChild(r.sprite);
// 		 		this.refugeeArrivedAt(r.destinationCountry, r.endPoint);
// 			}.bind(this));
// 	    }

// 		var loc = r.getLocation(this.refugeeModel.currentMoment);
// 		var point = this.projection(loc);
// 		r.sprite.position.x = point[0];
// 		r.sprite.position.y = point[1];
//     }.bind(this));
// }

RefugeeMap.prototype.drawRefugeePositions = function() {
  return this.drawRefugeePositionsPixi();
}

RefugeeMap.prototype.drawRefugeeCountsPixi = function() {
  //if (this.barContainer) {
  //	this.stage.removeChild(this.barContainer);
  //}

  //this.barContainer = new PIXI.Container();
  //this.barContainer.alpha = 0.7;

  this.barContainer.removeChildren();

  for (var country in this.arrivedRefugeesByCountry) {
    var bar = new PIXI.Graphics();
    var count = this.arrivedRefugeesByCountry[country].count / 100;
    var coordinates = this.projection(this.arrivedRefugeesByCountry[country].point);
    var color = MapModel.isInMainlandEurope(country) ? 0xFFFFFF : 0xFF0000;
    bar.beginFill(color);
    bar.lineStyle(1, color);
    bar.drawRect(coordinates[0], coordinates[1], 5, -count);
    this.barContainer.addChild(bar);
  };

  //this.stage.addChild(this.barContainer);
}

RefugeeMap.prototype.drawRefugeeCounts = function() {
  return this.drawRefugeeCountsPixi();
}

RefugeeMap.prototype.render = function() {
  this.renderer.render(this.stage);

  var g = d3.select("canvas").node().getContext("2d");
  //g.fillStyle = "rgba(0, 0, 0, 0.9999)";
  g.fillStyle = "rgba(0, 0, 0, 0.95)";

  var prevAlpha = g.globalAlpha;
  var prev = g.globalCompositeOperation;
  g.globalAlpha = 0.90;
  g.globalCompositeOperation = "destination-in";
  g.fillRect(0, 0, this.width, this.height);
  g.globalCompositeOperation = prev;
  g.globalAlpha = prevAlpha;
}

RefugeeMap.prototype.drawBorders = function() {
  var path = d3.geo.path().projection(this.projection);
  this.svg.append("path")
      .datum(this.mapModel.featureData)
      .attr("d", path);
}

RefugeeMap.prototype.drawLines = function() {
  this.refugeeModel.refugees.forEach(function(refugee) {
    this.drawRefugeeLine(refugee);
  }.bind(this));
}

RefugeeMap.prototype.drawRefugeeLine = function(refugee) {
  var sp = this.projection(refugee.startPoint);
  var ep = this.projection(refugee.endPoint);
  this.svg.append("line")
    .attr("x1", sp[0])
    .attr("y1", sp[1])
    .attr("x2", ep[0])
    .attr("y2", ep[1])
    .attr("stroke", "white");
}

// Note: Will currently display bar at location where first refugee arrives at in the country
RefugeeMap.prototype.refugeeArrivedAt = function(country, point) {
  if (!this.arrivedRefugeesByCountry[country]) {
    this.arrivedRefugeesByCountry[country] = {
      point: point,
      count: 1
    };
  } else {
    this.arrivedRefugeesByCountry[country].count++;
  }
}

module.exports = RefugeeMap;

// RefugeeMap.prototype.drawRefugeePositionsSVG = function() {
// 	var sel = this.svg.selectAll('.refugee')
// 		.data(this.refugeeModel.refugees);

// 	sel
// 		.attr("cx", function(d) {
// 			var loc = d.getLocation(this.refugeeModel.currentMoment);
// 			return this.projection(loc)[0];
// 		}.bind(this))
// 		.attr("cy", function(d) {
// 			var loc = d.getLocation(this.refugeeModel.currentMoment);
// 			return this.projection(loc)[1];
// 		}.bind(this));

// 	sel.enter()
// 		.append('circle')
// 		.classed('refugee', true)
// 		.attr("cx", function(d) {
// 			var loc = d.getLocation(this.refugeeModel.currentMoment);
// 			return this.projection(loc)[0];
// 		}.bind(this))
// 		.attr("cy", function(d) {
// 			var loc = d.getLocation(this.refugeeModel.currentMoment);
// 			return this.projection(loc)[1];
// 		}.bind(this))
// 		.attr("r", 1)
// 		.attr("fill", "white");
// }
<commit_msg>Using Pixi.math is deprecated<commit_after>var PIXI = require('pixi.js');
var MapModel = require('./map-model.js')

/*
 * Create a RefugeeMap backed
 * by the given RefugeeModel
 */
var RefugeeMap = function(refugeeModel, mapModel) {
  this.refugeeModel = refugeeModel;
  this.mapModel = mapModel;
  this.width = 1200;
  this.height = 1200;

  if (window.HD_RESOLUTION) {
    this.width = 1920;
    this.height = 1080;
  }

  this.initialize();
  this.graphics = {};
  this.sprites = {};
  this.arrivedRefugeesByCountry = {};

  this.refugeeModel.onRefugeeUpdated = this.onRefugeeUpdated.bind(this);
  this.refugeeModel.onRefugeeFinished = this.onRefugeeFinished.bind(this);
  this.refugeeModel.onRefugeeStarted = this.onRefugeeStarted.bind(this);
};

RefugeeMap.prototype.initialize = function() {
  var lo = 26.2206322; // x
  var la = 46.0485818; // y

  this.projection = d3.geo.mercator()
    .center([0, la])
    .rotate([-lo, 0])
    //.parallels([la - 10, la + 10])
    .scale(this.height*0.55)
    .translate([this.width / 2, this.height / 2]);

  this.svg = d3.select("#canvas-wrap").append("svg")
   .attr("width", this.width)
   .attr("height", this.height);

  window.projection = this.projection;

  this.initializePixiCanvas();
  this.drawBorders();

  d3.select('#canvas-wrap')
    .style('width', this.width + "px")
    .style('height', this.height + "px");
}

RefugeeMap.prototype.initializePixiCanvas = function() {
  PIXI.dontSayHello = true;
  PIXI.utils._saidHello = true;
  PIXI.doNotSayHello = true;
  PIXI.AUTO_PREVENT_DEFAULT = false;

  this.renderer = new PIXI.CanvasRenderer(
  //this.renderer = new PIXI.CanvasRenderer(
      this.width, this.height,
      {transparent: true,
      antialias: true,
      preserveDrawingBuffer: true,
      clearBeforeRender: false});

  d3.select('#canvas-wrap').node().appendChild(this.renderer.view);
  this.renderer.plugins.interaction.autoPreventDefault = false;

  this.renderer.preserveDrawingBuffer = true;
  this.renderer.clearBeforeRender = false;

  //this.stage.interactive = false;

    //this.refugeeContainer = new PIXI.ParticleContainer(
    //	200000,
    //	[false, true, false, false, true],
  //	200000);

  this.stage = new PIXI.Container();

  this.refugeeContainer = new PIXI.Container();
  this.refugeeContainer.alpha = 1.0;
  this.stage.addChild(this.refugeeContainer);

  this.barContainer = new PIXI.Container();
  this.barContainer.alpha = 0.7;
  this.stage.addChild(this.barContainer);

  this.refugeeTexture = new PIXI.Texture.fromImage(
    "one-white-pixel.png",
    new PIXI.Rectangle(0, 0, 1, 1));

  //this.refugeeContainer.

  // var g = new PIXI.Graphics();
  // g.blendMode = PIXI.BLEND_MODES.MULTIPLY;
  // g.beginFill(0xFFFFFF, 0.05);
  // g.drawRect(0, 0, this.width, this.height);
  // this.refugeeContainer.addChild(g);

  //var rect = PIXI.Rectangle(0, 0, this.width; this.height);

     //var matrix = [
    //    0.2, 0, 0, 0, 0,
    //    0, 0.2, 0, 0, 0,
    //    0, 0, 0.2, 0, 0,
    //    0, 0, 0, 0, 0
    //];

  //var filter = new PIXI.filters.ColorMatrixFilter();
  //filter.matrix = matrix;
  //this.refugeeContainer.filters = [filter];
}

RefugeeMap.prototype.onRefugeeStarted = function(r) {
  r.sprite = new PIXI.Sprite(this.refugeeTexture);
  r.sprite.alpha = 1.0;
  this.refugeeContainer.addChild(r.sprite);
}

RefugeeMap.prototype.onRefugeeFinished = function(r) {
  this.refugeeContainer.removeChild(r.sprite);
  this.refugeeArrivedAt(r.destinationCountry, r.endPoint);
}

RefugeeMap.prototype.onRefugeeUpdated = function(r) {
  var loc = r.location;
  var point = this.projection(loc);
  r.sprite.position.x = point[0];
  r.sprite.position.y = point[1];
}

// RefugeeMap.prototype.drawRefugeePositionsPixi = function() {

// 	// var length = this.refugeeModel.activeRefugees.length;
// 	// for (var i = 0; i < length; i++) {
// 	// 	var r = this.refugeeModel.activeRefugees[i];
// 	// 	var key = r.endMomentUnix;
// 	//     var s = this.sprites[key];

// 	//     if (!s) {
// 	//     	s = new PIXI.Sprite(this.texture);
// 	//     	this.refugeeContainer.addChild(s);
// 	//     	this.sprites[key] = s;

// 	// 		r.onFinished.push(function() {
// 	// 	 		this.refugeeContainer.removeChild(s);
// 	// 		}.bind(this));
// 	//     }
// 	// 	var loc = r.getLocation(this.refugeeModel.currentMoment);
// 	// 	var point = this.projection(loc);
// 	// 	s.position.x = point[0];
// 	// 	s.position.y = point[1];
// 	// 	s.alpha = 0.7;
// 	// }

//     this.refugeeModel.activeRefugees.forEach(function(r) {
// 		if (!r.sprite) {
// 	    	r.sprite = new PIXI.Sprite(this.refugeeTexture);
// 	    	this.refugeeContainer.addChild(r.sprite);

// 			r.onFinished.push(function() {
// 		 		this.refugeeContainer.removeChild(r.sprite);
// 		 		this.refugeeArrivedAt(r.destinationCountry, r.endPoint);
// 			}.bind(this));
// 	    }

// 		var loc = r.getLocation(this.refugeeModel.currentMoment);
// 		var point = this.projection(loc);
// 		r.sprite.position.x = point[0];
// 		r.sprite.position.y = point[1];
//     }.bind(this));
// }

RefugeeMap.prototype.drawRefugeePositions = function() {
  return this.drawRefugeePositionsPixi();
}

RefugeeMap.prototype.drawRefugeeCountsPixi = function() {
  //if (this.barContainer) {
  //	this.stage.removeChild(this.barContainer);
  //}

  //this.barContainer = new PIXI.Container();
  //this.barContainer.alpha = 0.7;

  this.barContainer.removeChildren();

  for (var country in this.arrivedRefugeesByCountry) {
    var bar = new PIXI.Graphics();
    var count = this.arrivedRefugeesByCountry[country].count / 100;
    var coordinates = this.projection(this.arrivedRefugeesByCountry[country].point);
    var color = MapModel.isInMainlandEurope(country) ? 0xFFFFFF : 0xFF0000;
    bar.beginFill(color);
    bar.lineStyle(1, color);
    bar.drawRect(coordinates[0], coordinates[1], 5, -count);
    this.barContainer.addChild(bar);
  };

  //this.stage.addChild(this.barContainer);
}

RefugeeMap.prototype.drawRefugeeCounts = function() {
  return this.drawRefugeeCountsPixi();
}

RefugeeMap.prototype.render = function() {
  this.renderer.render(this.stage);

  var g = d3.select("canvas").node().getContext("2d");
  //g.fillStyle = "rgba(0, 0, 0, 0.9999)";
  g.fillStyle = "rgba(0, 0, 0, 0.95)";

  var prevAlpha = g.globalAlpha;
  var prev = g.globalCompositeOperation;
  g.globalAlpha = 0.90;
  g.globalCompositeOperation = "destination-in";
  g.fillRect(0, 0, this.width, this.height);
  g.globalCompositeOperation = prev;
  g.globalAlpha = prevAlpha;
}

RefugeeMap.prototype.drawBorders = function() {
  var path = d3.geo.path().projection(this.projection);
  this.svg.append("path")
      .datum(this.mapModel.featureData)
      .attr("d", path);
}

RefugeeMap.prototype.drawLines = function() {
  this.refugeeModel.refugees.forEach(function(refugee) {
    this.drawRefugeeLine(refugee);
  }.bind(this));
}

RefugeeMap.prototype.drawRefugeeLine = function(refugee) {
  var sp = this.projection(refugee.startPoint);
  var ep = this.projection(refugee.endPoint);
  this.svg.append("line")
    .attr("x1", sp[0])
    .attr("y1", sp[1])
    .attr("x2", ep[0])
    .attr("y2", ep[1])
    .attr("stroke", "white");
}

// Note: Will currently display bar at location where first refugee arrives at in the country
RefugeeMap.prototype.refugeeArrivedAt = function(country, point) {
  if (!this.arrivedRefugeesByCountry[country]) {
    this.arrivedRefugeesByCountry[country] = {
      point: point,
      count: 1
    };
  } else {
    this.arrivedRefugeesByCountry[country].count++;
  }
}

module.exports = RefugeeMap;

// RefugeeMap.prototype.drawRefugeePositionsSVG = function() {
// 	var sel = this.svg.selectAll('.refugee')
// 		.data(this.refugeeModel.refugees);

// 	sel
// 		.attr("cx", function(d) {
// 			var loc = d.getLocation(this.refugeeModel.currentMoment);
// 			return this.projection(loc)[0];
// 		}.bind(this))
// 		.attr("cy", function(d) {
// 			var loc = d.getLocation(this.refugeeModel.currentMoment);
// 			return this.projection(loc)[1];
// 		}.bind(this));

// 	sel.enter()
// 		.append('circle')
// 		.classed('refugee', true)
// 		.attr("cx", function(d) {
// 			var loc = d.getLocation(this.refugeeModel.currentMoment);
// 			return this.projection(loc)[0];
// 		}.bind(this))
// 		.attr("cy", function(d) {
// 			var loc = d.getLocation(this.refugeeModel.currentMoment);
// 			return this.projection(loc)[1];
// 		}.bind(this))
// 		.attr("r", 1)
// 		.attr("fill", "white");
// }
<|endoftext|>


<commit_before>/* entities.js
 * Stuff that moves and reacts to physics
 */
'use strict';

/* Point
 *
 * public:
 * - x
 * - y
 * - step(gravity)
 *
 * private:
 * - vx
 * - vy
 * - dx
 * - dy
 */
class Point {

  constructor(x, y, friction, airFriction) {

    // TODO: should I use point IDs???
    // this.id = id++; // debug

    // position
    this.x = x;
    this.y = y;
    // velocity
    this.dx = 0;
    this.dy = 0;
    // previous position for inertia
    this.vx = x;
    this.vy = y;

    this.friction = friction || 0;
    this.airFriction = (airFriction !== undefined) ? airFriction : 1;
  }

  step(gravity) {
    this.dx = (this.x - this.vx) * this.airFriction + gravity.x;
    this.dy = (this.y - this.vy) * this.airFriction + gravity.y;
    this.vx = this.x;
    this.vy = this.y;
    this.x += this.dx;
    this.y += this.dy;
  }

}

/* Stick
 *
 * public:
 * - resolve()
 *
 * private:
 * - p
 * - q
 * - restLength
 */
class Stick {

  constructor (p, q) {
    this.p = p;
    this.q = q;
    this.restLength = this.length;
  }

  get dx() {
    return this.p.x - this.q.x;
  }

  get dy() {
    return this.p.y - this.q.y;
  }

  get length() {
    let dx = this.dx;
    let dy = this.dy;
    return Math.sqrt(dx * dx + dy * dy);
  }

  get diff() {
    return (this.length - this.restLength) / this.length * 0.5;
  }

  // set dx(x) {}, set dy(x) {}, set length(x) {}, set diff(x) {},

  shouldCrash(crashed) {
    return crashed;
  }

  shouldResolve() {
    return true;
  }

  doResolve() {
    let dx = this.dx * this.diff;
    let dy = this.dy * this.diff;
    this.p.x -= dx;
    this.p.y -= dy;
    this.q.x += dx;
    this.q.y += dy;
  }

  resolve(crashed) {
    if (this.shouldResolve(crashed)) {
      this.doResolve();
    }
    return this.shouldCrash(crashed);
  }

}

/* BindStick
 *
 * public:
 * - resolve()
 *
 * private:
 * - p
 * - q
 * - restLength
 * - endurance
 */
class BindStick extends Stick {

  constructor(p, q, endurance) {
    super(p, q);
    this.endurance = endurance * this.restLength * 0.5;
  }

  shouldCrash(crashed) {
    return crashed || this.diff > this.endurance;
  }

  shouldResolve(crashed) {
    return !this.shouldCrash(crashed);
  }

}

/* RepelStick
 *
 * public:
 * - resolve()
 *
 * private:
 * - p
 * - q
 * - restLength
 */
class RepelStick extends Stick {

  shouldResolve() {
    return this.length < this.restLength;
  }

}

/* Stick
 *
 * public:
 * - resolve()
 *
 * private:
 * - p
 * - q
 * - restLength
 */
class ScarfStick extends Stick {

  doResolve() {
    this.q.x += this.dx * this.diff * 2;
    this.q.y += this.dy * this.diff * 2;
  }

}

module.exports = {
  Point: Point,
  Stick: Stick,
  BindStick: BindStick,
  RepelStick: RepelStick,
  ScarfStick: ScarfStick
};
<commit_msg>implement ClockwiseCrashJoint + combine constraints under Constraint<commit_after>/* entities.js
 * Stuff that moves and reacts to physics
 */
'use strict';

/* Point
 *
 * public:
 * - x
 * - y
 * - step(gravity)
 *
 * private:
 * - vx
 * - vy
 * - dx
 * - dy
 */
class Point {

  constructor(x, y, friction = 0, airFriction = 1) {

    // TODO: should I use point IDs???
    // this.id = id++; // debug

    // position
    this.x = x;
    this.y = y;
    // velocity
    this.dx = 0;
    this.dy = 0;
    // previous position for inertia
    this.vx = x;
    this.vy = y;

    this.friction = friction;
    this.airFriction = airFriction;
  }

  step(gravity) {
    this.dx = (this.x - this.vx) * this.airFriction + gravity.x;
    this.dy = (this.y - this.vy) * this.airFriction + gravity.y;
    this.vx = this.x;
    this.vy = this.y;
    this.x += this.dx;
    this.y += this.dy;
  }

}

class Constraint {

  shouldCrash(crashed) {
    return crashed;
  }

  shouldResolve() {
    return true;
  }

  doResolve() {
    throw new Error('Not implemented');
  }

  resolve(crashed) {
    if (this.shouldResolve(crashed)) {
      this.doResolve();
    }
    return this.shouldCrash(crashed);
  }

}

/* Stick
 *
 * public:
 * - resolve()
 *
 * private:
 * - p
 * - q
 * - restLength
 */
class Stick extends Constraint {

  constructor (p, q) {
    this.p = p;
    this.q = q;
    this.restLength = this.length;
  }

  get dx() {
    return this.p.x - this.q.x;
  }

  get dy() {
    return this.p.y - this.q.y;
  }

  get length() {
    let dx = this.dx;
    let dy = this.dy;
    return Math.sqrt(dx * dx + dy * dy);
  }

  get diff() {
    return (this.length - this.restLength) / this.length * 0.5;
  }

  // set dx(x) {}, set dy(x) {}, set length(x) {}, set diff(x) {},

  doResolve() {
    let dx = this.dx * this.diff;
    let dy = this.dy * this.diff;
    this.p.x -= dx;
    this.p.y -= dy;
    this.q.x += dx;
    this.q.y += dy;
  }

}

/* BindStick
 *
 * public:
 * - resolve()
 *
 * private:
 * - p
 * - q
 * - restLength
 * - endurance
 */
class BindStick extends Stick {

  constructor(p, q, endurance) {
    super(p, q);
    this.endurance = endurance * this.restLength * 0.5;
  }

  shouldCrash(crashed) {
    return crashed || this.diff > this.endurance;
  }

  shouldResolve(crashed) {
    return !this.shouldCrash(crashed);
  }

}

/* RepelStick
 *
 * public:
 * - resolve()
 *
 * private:
 * - p
 * - q
 * - restLength
 */
class RepelStick extends Stick {

  shouldResolve() {
    return this.length < this.restLength;
  }

}

/* Stick
 *
 * public:
 * - resolve()
 *
 * private:
 * - p
 * - q
 * - restLength
 */
class ScarfStick extends Stick {

  doResolve() {
    this.q.x += this.dx * this.diff * 2;
    this.q.y += this.dy * this.diff * 2;
  }

}

class Joint extends Constraint {

  constructor(s, t, p = null) {
    this.s = s;
    this.t = t;
    this.p = p;
  }

}

// allow kramuals
class ClockwiseCrashJoint extends Joint {

  constructor(s, t) {
    super(s, t);
  }

  isClockwise() {
    return this.s.dx * this.t.dy - this.s.dy * this.t.dx >= 0;
  }

  shouldResolve() {
    return false;
  }

  shouldCrash(crashed) {
    return crashed || !this.isClockwise();
  }

}

module.exports = {
  Point,
  Stick,
  BindStick,
  RepelStick,
  ScarfStick,
  ClockwiseCrashJoint
};
<|endoftext|>