<commit_before>'use strict';

// Required args: type
function alter_workers(args){
    args = core_args({
      'args': args,
      'defaults': {
        'amount': 1,
      },
    });

    if(daylight_passed > 0
      || args['amount'] > resources['people']['unemployed']){
        return;
    }

    if(resources[args['type']]['workers'] > 0
      || args['amount'] > 0){
        resources['people']['unemployed'] -= args['amount'];
        resources[args['type']]['bonus'] += args['amount'] * resource_defaults[args['type']]['multiplier'];
        resources[args['type']]['workers'] += args['amount'];

    }else{
        resources[args['type']]['workers'] = 0;
    }

    document.getElementById(args['type'] + '-bonus').innerHTML =
      (resources[args['type']]['bonus'] >= 0 ? '+' : '') + resources[args['type']]['bonus'];
    document.getElementById(args['type'] + '-workers').innerHTML = resources[args['type']]['workers'];

    document.getElementById('unemployed-workers').innerHTML = resources['people']['unemployed'];
}

function day(){
    core_storage_save();

    // If day is not over, continue.
    if(daylight_passed < 5){
        // If day just started, clear previous days events and change start-day link to text.
        if(daylight_passed === 0){
            if(Number.isNaN(core_storage_data['day-duration'])
              || core_storage_data['day-duration'] <= 0){
                core_storage_data['day-duration'] = 600;
            }

            document.getElementById('day-events').innerHTML = '';
            document.getElementById('start-day').innerHTML = 'Day Progressing...';
        }

        let output = '';

        // Generate random event value.
        let event = Math.random();
        let event_result = 0;

        // No event.
        if(event < .72){
            output = '-----';

        // Food event.
        }else if(event < .78){
            // Generate food value for this event.
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                // Food lost.
                resources['food']['amount'] -= event_result;

                if(resources['food']['amount'] < 0){
                    // Lose 2 gold per food under 0.
                    resources['gold']['amount'] += resources['food']['amount'] * 2;
                    resources['food']['amount'] = 0;
                }

                output = 'Bugs! -';

            }else{
                // Food gained.
                resources['food']['amount'] += event_result;
                output = 'Rain! +';
            }
            output += event_result + ' Food';

        // Gold event.
        }else if(event < .84){
            // Generate gold value for this event.
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                // Lose gold, negative gold OK.
                resources['gold']['amount'] -= event_result;
                output = 'Theives! -';

            }else{
                // Gain gold.
                resources['gold']['amount'] += event_result;
                output = 'Mining! +';
            }

            output += event_result + ' Gold';

        // Stone event.
        }else if(event < .9){
            // Generate stone value for this event.
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                // Lose stone.
                resources['stone']['amount'] -= event_result;

                if(resources['stone']['amount'] < 0){
                    // Lose 2 gold per stone under 0.
                    resources['gold']['amount'] += resources['stone']['amount'] * 2;
                    resources['gold']['stone'] = 0;
                }

                output = 'Repair! -';

            }else{
                // Gain stone.
                resources['stone']['amount'] += event_result;
                output = 'Mining! +';
            }
            output += event_result + ' Stone';

        // Population event.
        }else if(event < .96){
            if(core_random_boolean()){
                // Lose person.
                if(resources['people']['amount'] > 0){
                    resources['people']['amount'] -= 1;
                    delete_people(0);
                }
                output = 'Sickness! -';

            }else{
                // Gain person.
                resources['people']['amount'] += 1;
                resources['people']['unemployed'] += 1;
                output = 'Recruitment! +';
            }

            output += '1 Population';

        // Other events, not yet implemented.
        }else if(event < .99){
            event_result = core_random_integer({
              'max': 2,
            });
            if(event_result === 0){
                output = 'Battle Event (NYI)';

            }else{
                output = 'Other Event (NYI)';
            }

        // Daily resource bonus event.
        }else{
            // Generate which resource will have daily bonus increased.
            event_result = core_random_integer({
              'max': 4,
            });

            // Food daily bonus increase.
            if(event_result === 0){
                output = 'Seeds! +1 Food/day';
                resources['food']['bonus'] += 1;

            // Gold daily bonus increase.
            }else if(event_result === 1){
                output = 'Veins! +1 Gold/day';
                resources['gold']['bonus'] += 1;

            // Population daily bonus increase.
            }else if(event_result === 2){
                output = 'Popularity! +1 Population/day';
                resources['people']['bonus'] += 1;

            // Stone daily bonus increase.
            }else{
                output = 'Rocks! +1 Stone/day';
                resources['stone']['bonus'] += 1;

            }
        }

        // Add event to list of day-events.
        document.getElementById('day-events').innerHTML += output + '
';

        // More daylight has passed.
        daylight_passed += 1;

        // If day is not over, wait core_storage_data['day-duration'] ms for next event,
        //   which is set by the day-duration input field.
        if(daylight_passed < 5){
            core_interval_modify({
              'clear': 'clearTimeout',
              'id': 'day',
              'interval': core_storage_data['day-duration'],
              'set': 'setTimeout',
              'todo': day,
            });
        }
    }

    if(daylight_passed >= 5){
        // End day.
        block_unload = true;
        daylight_passed = 0;

        // Update resources with daily bonuses.
        for(let resource in resources){
            resources[resource]['amount'] += resources[resource]['bonus'];
        }
        resources['people']['unemployed'] += resources['people']['bonus'];

        // Calculate if there is not enough food to feed the current population.
        if(resources['food']['amount'] + resources['food']['bonus'] < 0){
            // If not enough food, decrease population and workers.
            delete_people(resources['people']['amount'] - 1);
            resources['people']['amount'] -=
              resources['people']['amount']
              - (resources['food']['amount'] + resources['food']['bonus']);

            if(resources['people']['amount'] < 0){
                resources['people']['amount'] = 0;
            }

            resources['food']['amount'] = 0;
            resources['food']['bonus'] = 0;
        }

        // Update start-day text with start new day or game over message.
        document.getElementById('start-day').innerHTML = resources['people']['amount'] > 0
          ? start_new_day
          : 'Your Castle Has Fallen. :(
<input onclick=new_game() type=button value="Start Over">';
    }

    // Update food bonus based on current population.
    resources['food']['bonus'] = resources['food']['workers'] * 2 - resources['people']['amount'];

    // Update text displays.
    for(let resource in resources){
        document.getElementById(resource).innerHTML = resources[resource]['amount'];
        document.getElementById(resource + '-bonus').innerHTML = (resources[resource]['bonus'] >= 0 ? '+' : '') + resources[resource]['bonus'];
    }
    document.getElementById('unemployed-workers').innerHTML = resources['people']['unemployed'];
}

function delete_people(count){
    do{
        // Decrease unemployed workers first.
        if(resources['people']['unemployed'] > 0){
            resources['people']['unemployed'] -= 1;

        // If no unemployed workers, decrease people workers.
        }else if(resources['people']['workers'] > 0){
            resources['people']['bonus'] -= 1;
            resources['people']['workers'] -= 1;

            document.getElementById('people-bonus').innerHTML = resources['people']['workers'];
            document.getElementById('people-workers').innerHTML = resources['people']['workers'];

        // If no people workers, decrease stone workers.
        }else if(resources['stone']['workers'] > 0){
            resources['stone']['bonus'] -= 1;
            resources['stone']['workers'] -= 1;

            document.getElementById('stone-bonus').innerHTML = resources['stone']['workers'];
            document.getElementById('stone-workers').innerHTML = resources['stone']['workers'];

        // If no stone workers, decrease gold workers.
        }else if(resources['gold']['workers'] > 0){
            resources['gold']['bonus'] -= 1;
            resources['gold']['workers'] -= 1;

            document.getElementById('gold-bonus').innerHTML = resources['gold']['workers'];
            document.getElementById('gold-workers').innerHTML = resources['gold']['workers'];

        // If no gold workers, decrease food workers.
        }else{
            resources['food']['workers'] -= 1;
            document.getElementById('food-workers').innerHTML = resources['food']['workers'];
        }
    }while(count--);
}

function new_game(){
    block_unload = false;
    daylight_passed = 0;

    let tbody = '';
    for(let resource in resource_defaults){
        resources[resource] = resources[resource] || {};

        resources[resource]['amount'] = resource_defaults[resource]['amount'];
        resources[resource]['bonus'] = resource_defaults[resource]['bonus'];
        resources[resource]['workers'] = resource_defaults[resource]['workers'];

        tbody += '
' + resource
          + '' + resources[resource]['amount']
          + '' + resources[resource]['bonus']
          + '<input onclick="alter_workers({type:\'' + resource + '\',})" type=button value=+>'
            + ' ' + resources[resource]['workers'] + ' '
            + '<input onclick="alter_workers({amount:-1,type:\'' + resource + '\',})" type=button value=—>';
    }

    resources['people']['unemployed'] = resource_defaults['people']['unemployed'];

    document.getElementById('day-events').innerHTML = '';
    document.getElementById('start-day').innerHTML = start_new_day;
    document.getElementById('tbody').innerHTML = tbody;

    document.getElementById('unemployed-workers').innerHTML = resource_defaults['people']['unemployed'];
}
<commit_msg>replaced some innerHTML with textContent<commit_after>'use strict';

// Required args: type
function alter_workers(args){
    args = core_args({
      'args': args,
      'defaults': {
        'amount': 1,
      },
    });

    if(daylight_passed > 0
      || args['amount'] > resources['people']['unemployed']){
        return;
    }

    if(resources[args['type']]['workers'] > 0
      || args['amount'] > 0){
        resources['people']['unemployed'] -= args['amount'];
        resources[args['type']]['bonus'] += args['amount'] * resource_defaults[args['type']]['multiplier'];
        resources[args['type']]['workers'] += args['amount'];

    }else{
        resources[args['type']]['workers'] = 0;
    }

    document.getElementById(args['type'] + '-bonus').textContent =
      (resources[args['type']]['bonus'] >= 0 ? '+' : '') + resources[args['type']]['bonus'];
    document.getElementById(args['type'] + '-workers').textContent = resources[args['type']]['workers'];

    document.getElementById('unemployed-workers').textContent = resources['people']['unemployed'];
}

function day(){
    core_storage_save();

    // If day is not over, continue.
    if(daylight_passed < 5){
        // If day just started, clear previous days events and change start-day link to text.
        if(daylight_passed === 0){
            if(Number.isNaN(core_storage_data['day-duration'])
              || core_storage_data['day-duration'] <= 0){
                core_storage_data['day-duration'] = 600;
            }

            document.getElementById('day-events').textContent = '';
            document.getElementById('start-day').textContent = 'Day Progressing...';
        }

        let output = '';

        // Generate random event value.
        let event = Math.random();
        let event_result = 0;

        // No event.
        if(event < .72){
            output = '-----';

        // Food event.
        }else if(event < .78){
            // Generate food value for this event.
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                // Food lost.
                resources['food']['amount'] -= event_result;

                if(resources['food']['amount'] < 0){
                    // Lose 2 gold per food under 0.
                    resources['gold']['amount'] += resources['food']['amount'] * 2;
                    resources['food']['amount'] = 0;
                }

                output = 'Bugs! -';

            }else{
                // Food gained.
                resources['food']['amount'] += event_result;
                output = 'Rain! +';
            }
            output += event_result + ' Food';

        // Gold event.
        }else if(event < .84){
            // Generate gold value for this event.
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                // Lose gold, negative gold OK.
                resources['gold']['amount'] -= event_result;
                output = 'Theives! -';

            }else{
                // Gain gold.
                resources['gold']['amount'] += event_result;
                output = 'Mining! +';
            }

            output += event_result + ' Gold';

        // Stone event.
        }else if(event < .9){
            // Generate stone value for this event.
            event_result = core_random_integer({
              'max': 2,
            }) + 1;

            if(core_random_boolean()){
                // Lose stone.
                resources['stone']['amount'] -= event_result;

                if(resources['stone']['amount'] < 0){
                    // Lose 2 gold per stone under 0.
                    resources['gold']['amount'] += resources['stone']['amount'] * 2;
                    resources['gold']['stone'] = 0;
                }

                output = 'Repair! -';

            }else{
                // Gain stone.
                resources['stone']['amount'] += event_result;
                output = 'Mining! +';
            }
            output += event_result + ' Stone';

        // Population event.
        }else if(event < .96){
            if(core_random_boolean()){
                // Lose person.
                if(resources['people']['amount'] > 0){
                    resources['people']['amount'] -= 1;
                    delete_people(0);
                }
                output = 'Sickness! -';

            }else{
                // Gain person.
                resources['people']['amount'] += 1;
                resources['people']['unemployed'] += 1;
                output = 'Recruitment! +';
            }

            output += '1 Population';

        // Other events, not yet implemented.
        }else if(event < .99){
            event_result = core_random_integer({
              'max': 2,
            });
            if(event_result === 0){
                output = 'Battle Event (NYI)';

            }else{
                output = 'Other Event (NYI)';
            }

        // Daily resource bonus event.
        }else{
            // Generate which resource will have daily bonus increased.
            event_result = core_random_integer({
              'max': 4,
            });

            // Food daily bonus increase.
            if(event_result === 0){
                output = 'Seeds! +1 Food/day';
                resources['food']['bonus'] += 1;

            // Gold daily bonus increase.
            }else if(event_result === 1){
                output = 'Veins! +1 Gold/day';
                resources['gold']['bonus'] += 1;

            // Population daily bonus increase.
            }else if(event_result === 2){
                output = 'Popularity! +1 Population/day';
                resources['people']['bonus'] += 1;

            // Stone daily bonus increase.
            }else{
                output = 'Rocks! +1 Stone/day';
                resources['stone']['bonus'] += 1;

            }
        }

        // Add event to list of day-events.
        document.getElementById('day-events').innerHTML += output + '
';

        // More daylight has passed.
        daylight_passed += 1;

        // If day is not over, wait core_storage_data['day-duration'] ms for next event,
        //   which is set by the day-duration input field.
        if(daylight_passed < 5){
            core_interval_modify({
              'clear': 'clearTimeout',
              'id': 'day',
              'interval': core_storage_data['day-duration'],
              'set': 'setTimeout',
              'todo': day,
            });
        }
    }

    if(daylight_passed >= 5){
        // End day.
        block_unload = true;
        daylight_passed = 0;

        // Update resources with daily bonuses.
        for(let resource in resources){
            resources[resource]['amount'] += resources[resource]['bonus'];
        }
        resources['people']['unemployed'] += resources['people']['bonus'];

        // Calculate if there is not enough food to feed the current population.
        if(resources['food']['amount'] + resources['food']['bonus'] < 0){
            // If not enough food, decrease population and workers.
            delete_people(resources['people']['amount'] - 1);
            resources['people']['amount'] -=
              resources['people']['amount']
              - (resources['food']['amount'] + resources['food']['bonus']);

            if(resources['people']['amount'] < 0){
                resources['people']['amount'] = 0;
            }

            resources['food']['amount'] = 0;
            resources['food']['bonus'] = 0;
        }

        // Update start-day text with start new day or game over message.
        document.getElementById('start-day').innerHTML = resources['people']['amount'] > 0
          ? start_new_day
          : 'Your Castle Has Fallen. :(
<input onclick=new_game() type=button value="Start Over">';
    }

    // Update food bonus based on current population.
    resources['food']['bonus'] = resources['food']['workers'] * 2 - resources['people']['amount'];

    // Update text displays.
    for(let resource in resources){
        document.getElementById(resource).textContent = resources[resource]['amount'];
        document.getElementById(resource + '-bonus').textContent = (resources[resource]['bonus'] >= 0 ? '+' : '') + resources[resource]['bonus'];
    }
    document.getElementById('unemployed-workers').textContent = resources['people']['unemployed'];
}

function delete_people(count){
    do{
        // Decrease unemployed workers first.
        if(resources['people']['unemployed'] > 0){
            resources['people']['unemployed'] -= 1;

        // If no unemployed workers, decrease people workers.
        }else if(resources['people']['workers'] > 0){
            resources['people']['bonus'] -= 1;
            resources['people']['workers'] -= 1;

            document.getElementById('people-bonus').textContent = resources['people']['workers'];
            document.getElementById('people-workers').textContent = resources['people']['workers'];

        // If no people workers, decrease stone workers.
        }else if(resources['stone']['workers'] > 0){
            resources['stone']['bonus'] -= 1;
            resources['stone']['workers'] -= 1;

            document.getElementById('stone-bonus').textContent = resources['stone']['workers'];
            document.getElementById('stone-workers').textContent = resources['stone']['workers'];

        // If no stone workers, decrease gold workers.
        }else if(resources['gold']['workers'] > 0){
            resources['gold']['bonus'] -= 1;
            resources['gold']['workers'] -= 1;

            document.getElementById('gold-bonus').textContent = resources['gold']['workers'];
            document.getElementById('gold-workers').textContent = resources['gold']['workers'];

        // If no gold workers, decrease food workers.
        }else{
            resources['food']['workers'] -= 1;
            document.getElementById('food-workers').textContent = resources['food']['workers'];
        }
    }while(count--);
}

function new_game(){
    block_unload = false;
    daylight_passed = 0;

    let tbody = '';
    for(let resource in resource_defaults){
        resources[resource] = resources[resource] || {};

        resources[resource]['amount'] = resource_defaults[resource]['amount'];
        resources[resource]['bonus'] = resource_defaults[resource]['bonus'];
        resources[resource]['workers'] = resource_defaults[resource]['workers'];

        tbody += '
' + resource
          + '' + resources[resource]['amount']
          + '' + resources[resource]['bonus']
          + '<input onclick="alter_workers({type:\'' + resource + '\',})" type=button value=+>'
            + ' ' + resources[resource]['workers'] + ' '
            + '<input onclick="alter_workers({amount:-1,type:\'' + resource + '\',})" type=button value=—>';
    }

    resources['people']['unemployed'] = resource_defaults['people']['unemployed'];

    document.getElementById('day-events').textContent = '';
    document.getElementById('start-day').innerHTML = start_new_day;
    document.getElementById('tbody').innerHTML = tbody;

    document.getElementById('unemployed-workers').textContent = resource_defaults['people']['unemployed'];
}
<|endoftext|>


<commit_before>function Products() {
    this.products = {};
}

Products.prototype = {
    constructor: Products,

    addProduct: function (productToAdd) {
        var productName = productToAdd["product_name"];
        this.products[productName] = productToAdd;
    },

    getProduct: function (productName) {
        return this.products[productName];
    },

    getProductNames: function () {
        return Object.keys(this.products);
    }
};

var products = new Products();

function productSelectionChanged() {
    var selectedText = $('.selectpicker').find("option:selected").text();
    var selectedProduct = products.getProduct(selectedText);
    $('#product_name_value').text(selectedProduct['product_name']);
    $('#proteins_value').text(selectedProduct['proteins']);
    $('#carbohydrates_value').text(selectedProduct['carbohydrates']);
    $('#fats_value').text(selectedProduct['fats']);
    $('#nutritive_value_value').text(selectedProduct['nutritive_value']);
}

var Product = Backbone.Model.extend({
    defaults: {
        product_name: '',
        proteins: 0,
        carbohydrates: 0,
        fats: 0,
        nutritive_value: 0,
        weight: 0
    },

    effectiveValue: function (name) {
        return this.get(name) * this.get('weight') / 100;
    }
});

var ProductList = Backbone.Collection.extend({
    model: Product,

    summaryValue: function (name) {
        var mapped = _.map(this.models, function (product) {
            return product.effectiveValue(name)
        });
        return _.reduce(mapped, function (memo, num) {
            return memo + num;
        }, 0.0);
    }
});

var Meal = Backbone.Model.extend({
    defaults: {
        name: 'MealX',
        productList: new ProductList()
    },

    initialize: function () {
        var productList = new ProductList();
        this.set('productList', productList);
        this.listenTo(productList, 'change', function () {
            this.trigger('change', this);
        });
    },

    summaryValue: function (name) {
        return this.get('productList').summaryValue(name);
    }
});

var MealList = Backbone.Collection.extend({
    model: Meal,

    initialize: function () {
        var productList = new ProductList();
        this.set('productList', productList);
    },

    summaryValue: function (name) {
        var mapped = _.map(this.models, function (meal) {
            return meal.summaryValue(name);
        });

        return _.reduce(mapped, function (memo, num) {
            return memo + num;
        }, 0.0);
    }
});

$(function () {
    var ProductView = Backbone.View.extend({
        tagName: 'tr',

        events: {
            "change input": "inputChanged"
        },

        initialize: function () {
            _.bindAll(this, 'render', 'inputChanged', 'effectiveValue');
            this.model.bind('change', this.render, this);
        },

        render: function () {
            $(this.el).html('<input type="text" class="form-control" value="' + this.model.get('weight') + '"></input>	' + this.model.get('product_name') + '	' + this.effectiveValue('proteins') + '	' + this.effectiveValue('carbohydrates') + '	' + this.effectiveValue('fats') + '	' + this.effectiveValue('nutritive_value') + '	');
            return this;
        },

        inputChanged: function (evt) {
            var value = $(evt.currentTarget).val();
            this.model.set('weight', value);
        },

        effectiveValue: function (param_name) {
            return this.model.effectiveValue(param_name).toFixed(2);
        }
    });

    var ProductListView = Backbone.View.extend({
        tagName: 'table',
        className: 'table',

        initialize: function () {
            _.bindAll(this, 'render', 'appendProduct', 'summaryValue', 'updateSum');
            this.model.bind('add', this.appendProduct);
            this.model.bind('change', this.updateSum, this);
        },

        render: function () {
            $(this.el).html('
Product weight	Product Name	Proteins	Carbohydrates	Fats	Nutritive value
');
            $(this.el).append('

');
            $(this.el).append('

Summary

');

            var self = this;
            _(this.model.models).each(function (product) {
                self.appendProduct(product);
            });

            this.updateSum();

            return this;
        },

        appendProduct: function (product) {
            var productView = new ProductView({
                model: product
            });
            $('tbody', this.el).append(productView.render().el);
        },

        updateSum: function () {
            $("td.proteins_sum", this.el).text(this.summaryValue("proteins"));
            $("td.carbohydrates_sum", this.el).text(this.summaryValue("carbohydrates"));
            $("td.fats_sum", this.el).text(this.summaryValue("fats"));
            $("td.nutritive_value_sum", this.el).text(this.summaryValue("nutritive_value"));
        },

        summaryValue: function (param_name) {
            return this.model.summaryValue(param_name).toFixed(2);
        }
    });

    var MealView = Backbone.View.extend({
        tagName: 'div',
        className: 'panel panel-default',

        events: {
            'click button.delete': 'remove',
            'click button.add_product': 'addProduct'
        },

        initialize: function () {
            _.bindAll(this, 'render', 'unrender', 'remove', 'addProduct');

            this.model.bind('change', this.render);
            this.model.bind('remove', this.unrender);
            this.model.bind('addProduct', this.addProduct);
            this.productListView = new ProductListView({
                model: this.model.get('productList')
            });
        },

        render: function () {
            $(this.el).html('

' + this.model.get('name') + '

<button type="button" class="btn btn-success add_product">Add Product</button>

<button type="button" class="btn btn-danger delete">Remove Meal</button>

');

            $('div.panel-body', this.el).append(this.productListView.render().el);
            return this;
        },

        unrender: function () {
            $(this.el).remove();
        },

        remove: function () {
            this.model.destroy();
        },

        addProduct: function () {
            var selectedText = $('.selectpicker').find("option:selected").text();
            var selectedProduct = products.getProduct(selectedText);
            var product = new Product();
            product.set({
                product_name: selectedProduct["product_name"],
                proteins: selectedProduct["proteins"],
                carbohydrates: selectedProduct["carbohydrates"],
                fats: selectedProduct["fats"],
                nutritive_value: selectedProduct["nutritive_value"]
            });
            this.model.get('productList').add(product);
        }

    });

    var MealListView = Backbone.View.extend({

        el: $('#meals_container'),

        events: {
            'click button#add_meal': 'addMeal'
        },

        initialize: function () {
            _.bindAll(this, 'render', 'addMeal', 'appendMeal', 'updateSummaries');
            this.mealList = new MealList();
            this.mealList.bind('add', this.appendMeal);
            this.mealList.bind('change', this.updateSummaries);
            this.counter = 0;
            this.render();
        },

        render: function () {
            $(this.el).html('

');
            $('div.meals_panel', this.el).append('

Meals
<button id="add_meal" type="button" class="btn btn-success">Add Meal</button>
');
            $('div.meals_panel', this.el).append('

');
            $('div.meals_panel', this.el).append('

');
            $('div.meals_summary', this.el).append('

Summary

Proteins	Carbohydrates	Fats	Nutritive value

');

            this.updateSummaries();
        },

        addMeal: function () {
            this.counter++;
            var meal = new Meal();
            meal.set({
                name: 'Meal ' + this.counter
            });
            this.mealList.add(meal);
        },

        appendMeal: function (meal) {
            var mealView = new MealView({
                model: meal
            });
            $('div.meal_list', this.el).append(mealView.render().el);
        },

        updateSummaries: function () {
            $("td.proteins_sum", "div.meals_summary", this.el).text(this.mealList.summaryValue("proteins"));
            $("td.carbohydrates_sum", "div.meals_summary", this.el).text(this.mealList.summaryValue("carbohydrates"));
            $("td.fats_sum", "div.meals_summary", this.el).text(this.mealList.summaryValue("fats"));
            $("td.nutritive_value_sum", "div.meals_summary", this.el).text(this.mealList.summaryValue("nutritive_value"));
        }
    });
    var mealListView = new MealListView();

    var xmlhttp = new XMLHttpRequest();
    var url = "http://192.168.0.14:9201/products/_search?size=1000";

    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            var myArr = JSON.parse(xmlhttp.responseText);
            var hits = myArr["hits"]["hits"];

            hits.forEach(function (hit) {
                var product = hit["_source"];
                products.addProduct(product);
            });

            products.getProductNames().forEach(function (productName) {
                var product_selector = document.getElementById("product_selector");
                var option = document.createElement("option");
                option.text = productName;
                product_selector.add(option);
            });

            $('.selectpicker').change(productSelectionChanged);

            $('.selectpicker').selectpicker('refresh');
            productSelectionChanged();
        }
    };
    xmlhttp.open("GET", url, true);
    xmlhttp.send();

});
<commit_msg>updating summary values when removing meal and rounding summary values<commit_after>function Products() {
    this.products = {};
}

Products.prototype = {
    constructor: Products,

    addProduct: function (productToAdd) {
        var productName = productToAdd["product_name"];
        this.products[productName] = productToAdd;
    },

    getProduct: function (productName) {
        return this.products[productName];
    },

    getProductNames: function () {
        return Object.keys(this.products);
    }
};

var products = new Products();

function productSelectionChanged() {
    var selectedText = $('.selectpicker').find("option:selected").text();
    var selectedProduct = products.getProduct(selectedText);
    $('#product_name_value').text(selectedProduct['product_name']);
    $('#proteins_value').text(selectedProduct['proteins']);
    $('#carbohydrates_value').text(selectedProduct['carbohydrates']);
    $('#fats_value').text(selectedProduct['fats']);
    $('#nutritive_value_value').text(selectedProduct['nutritive_value']);
}

var Product = Backbone.Model.extend({
    defaults: {
        product_name: '',
        proteins: 0,
        carbohydrates: 0,
        fats: 0,
        nutritive_value: 0,
        weight: 0
    },

    effectiveValue: function (name) {
        return this.get(name) * this.get('weight') / 100;
    }
});

var ProductList = Backbone.Collection.extend({
    model: Product,

    summaryValue: function (name) {
        var mapped = _.map(this.models, function (product) {
            return product.effectiveValue(name)
        });
        return _.reduce(mapped, function (memo, num) {
            return memo + num;
        }, 0.0);
    }
});

var Meal = Backbone.Model.extend({
    defaults: {
        name: 'MealX',
        productList: new ProductList()
    },

    initialize: function () {
        var productList = new ProductList();
        this.set('productList', productList);
        this.listenTo(productList, 'change', function () {
            this.trigger('change', this);
        });
    },

    summaryValue: function (name) {
        return this.get('productList').summaryValue(name);
    }
});

var MealList = Backbone.Collection.extend({
    model: Meal,

    initialize: function () {
        var productList = new ProductList();
        this.set('productList', productList);
    },

    summaryValue: function (name) {
        var mapped = _.map(this.models, function (meal) {
            return meal.summaryValue(name);
        });

        return _.reduce(mapped, function (memo, num) {
            return memo + num;
        }, 0.0);
    }
});

$(function () {
    var ProductView = Backbone.View.extend({
        tagName: 'tr',

        events: {
            "change input": "inputChanged"
        },

        initialize: function () {
            _.bindAll(this, 'render', 'inputChanged', 'effectiveValue');
            this.model.bind('change', this.render, this);
        },

        render: function () {
            $(this.el).html('<input type="text" class="form-control" value="' + this.model.get('weight') + '"></input>	' + this.model.get('product_name') + '	' + this.effectiveValue('proteins') + '	' + this.effectiveValue('carbohydrates') + '	' + this.effectiveValue('fats') + '	' + this.effectiveValue('nutritive_value') + '	');
            return this;
        },

        inputChanged: function (evt) {
            var value = $(evt.currentTarget).val();
            this.model.set('weight', value);
        },

        effectiveValue: function (param_name) {
            return this.model.effectiveValue(param_name).toFixed(2);
        }
    });

    var ProductListView = Backbone.View.extend({
        tagName: 'table',
        className: 'table',

        initialize: function () {
            _.bindAll(this, 'render', 'appendProduct', 'summaryValue', 'updateSum');
            this.model.bind('add', this.appendProduct);
            this.model.bind('change', this.updateSum, this);
        },

        render: function () {
            $(this.el).html('
Product weight	Product Name	Proteins	Carbohydrates	Fats	Nutritive value
');
            $(this.el).append('

');
            $(this.el).append('

Summary

');

            var self = this;
            _(this.model.models).each(function (product) {
                self.appendProduct(product);
            });

            this.updateSum();

            return this;
        },

        appendProduct: function (product) {
            var productView = new ProductView({
                model: product
            });
            $('tbody', this.el).append(productView.render().el);
        },

        updateSum: function () {
            $("td.proteins_sum", this.el).text(this.summaryValue("proteins"));
            $("td.carbohydrates_sum", this.el).text(this.summaryValue("carbohydrates"));
            $("td.fats_sum", this.el).text(this.summaryValue("fats"));
            $("td.nutritive_value_sum", this.el).text(this.summaryValue("nutritive_value"));
        },

        summaryValue: function (param_name) {
            return this.model.summaryValue(param_name).toFixed(2);
        }
    });

    var MealView = Backbone.View.extend({
        tagName: 'div',
        className: 'panel panel-default',

        events: {
            'click button.delete': 'remove',
            'click button.add_product': 'addProduct'
        },

        initialize: function () {
            _.bindAll(this, 'render', 'unrender', 'remove', 'addProduct');

            this.model.bind('change', this.render);
            this.model.bind('remove', this.unrender);
            this.model.bind('addProduct', this.addProduct);
            this.productListView = new ProductListView({
                model: this.model.get('productList')
            });
        },

        render: function () {
            $(this.el).html('

' + this.model.get('name') + '

<button type="button" class="btn btn-success add_product">Add Product</button>

<button type="button" class="btn btn-danger delete">Remove Meal</button>

');

            $('div.panel-body', this.el).append(this.productListView.render().el);
            return this;
        },

        unrender: function () {
            $(this.el).remove();
        },

        remove: function () {
            this.model.destroy();
        },

        addProduct: function () {
            var selectedText = $('.selectpicker').find("option:selected").text();
            var selectedProduct = products.getProduct(selectedText);
            var product = new Product();
            product.set({
                product_name: selectedProduct["product_name"],
                proteins: selectedProduct["proteins"],
                carbohydrates: selectedProduct["carbohydrates"],
                fats: selectedProduct["fats"],
                nutritive_value: selectedProduct["nutritive_value"]
            });
            this.model.get('productList').add(product);
        }

    });

    var MealListView = Backbone.View.extend({

        el: $('#meals_container'),

        events: {
            'click button#add_meal': 'addMeal'
        },

        initialize: function () {
            _.bindAll(this, 'render', 'addMeal', 'appendMeal', 'updateSummaries', 'summaryValue');
            this.mealList = new MealList();
            this.mealList.bind('add', this.appendMeal);
            this.mealList.bind('change', this.updateSummaries);
            this.mealList.bind('remove', this.updateSummaries);
            this.counter = 0;
            this.render();
        },

        render: function () {
            $(this.el).html('

');
            $('div.meals_panel', this.el).append('

Meals
<button id="add_meal" type="button" class="btn btn-success">Add Meal</button>
');
            $('div.meals_panel', this.el).append('

');
            $('div.meals_panel', this.el).append('

');
            $('div.meals_summary', this.el).append('

Summary

Proteins	Carbohydrates	Fats	Nutritive value

');

            this.updateSummaries();
        },

        addMeal: function () {
            this.counter++;
            var meal = new Meal();
            meal.set({
                name: 'Meal ' + this.counter
            });
            this.mealList.add(meal);
        },

        appendMeal: function (meal) {
            var mealView = new MealView({
                model: meal
            });
            $('div.meal_list', this.el).append(mealView.render().el);
        },

        updateSummaries: function () {
            $("td.proteins_sum", "div.meals_summary", this.el).text(this.summaryValue("proteins"));
            $("td.carbohydrates_sum", "div.meals_summary", this.el).text(this.summaryValue("carbohydrates"));
            $("td.fats_sum", "div.meals_summary", this.el).text(this.summaryValue("fats"));
            $("td.nutritive_value_sum", "div.meals_summary", this.el).text(this.summaryValue("nutritive_value"));
        },

        summaryValue: function (name) {
            return this.mealList.summaryValue(name).toFixed(2);
        }
    });
    var mealListView = new MealListView();

    var xmlhttp = new XMLHttpRequest();
    var url = "http://192.168.0.14:9201/products/_search?size=1000";

    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            var myArr = JSON.parse(xmlhttp.responseText);
            var hits = myArr["hits"]["hits"];

            hits.forEach(function (hit) {
                var product = hit["_source"];
                products.addProduct(product);
            });

            products.getProductNames().forEach(function (productName) {
                var product_selector = document.getElementById("product_selector");
                var option = document.createElement("option");
                option.text = productName;
                product_selector.add(option);
            });

            $('.selectpicker').change(productSelectionChanged);

            $('.selectpicker').selectpicker('refresh');
            productSelectionChanged();
        }
    };
    xmlhttp.open("GET", url, true);
    xmlhttp.send();

});
<|endoftext|>


<commit_before>jQuery(function() {
    var $ = jQuery,    // just in case. Make sure it's not an other libaray.

        $wrap = $('#uploader'),

        // 图片容器
        $queue = $('

')
            .appendTo( $wrap.find('.queueList') ),

        // 状态栏，包括进度和控制按钮
        $statusBar = $wrap.find('.statusBar'),

        // 文件总体选择信息。
        $info = $statusBar.find('.info'),

        // 上传按钮
        $upload = $wrap.find('.uploadBtn'),

        // 没选择文件之前的内容。
        $placeHolder = $wrap.find('.placeholder'),

        // 总体进度条
        $progress = $statusBar.find('.progress').hide(),

        // 添加的文件数量
        fileCount = 0,

        // 添加的文件总大小
        fileSize = 0,

        // 优化retina, 在retina下这个值是2
        ratio = window.devicePixelRatio || 1,

        // 缩略图大小
        thumbnailWidth = 110 * ratio,
        thumbnailHeight = 110 * ratio,

        // 可能有pedding, ready, uploading, confirm, done.
        state = 'pedding',

        // 所有文件的进度信息，key为file id
        percentages = {},

        supportTransition = (function(){
            var s = document.createElement('p').style,
                r = 'transition' in s ||
                      'WebkitTransition' in s ||
                      'MozTransition' in s ||
                      'msTransition' in s ||
                      'OTransition' in s;
            s = null;
            return r;
        })(),

        // WebUploader实例
        uploader;

    if ( !WebUploader.Uploader.support() ) {
        alert( 'Web Uploader 不支持您的浏览器！如果你使用的是IE浏览器，请尝试升级 flash 播放器');
        throw new Error( 'WebUploader does not support the browser you are using.' );
    }

    // 实例化
    uploader = WebUploader.create({
        pick: {
            id: '#filePicker',
            label: '点击选择图片'
        },
        dnd: '#uploader .queueList',
        paste: document.body,

        accept: {
            title: 'Images',
            extensions: 'gif,jpg,jpeg,bmp,png',
            mimeTypes: 'image/*'
        },

        // swf文件路径
        swf: BASE_URL + '/js/Uploader.swf',

        disableGlobalDnd: true,

        chunked: true,
        // server: 'http://webuploader.duapp.com/server/fileupload.php',
        server: 'http://2betop.net/fileupload.php',
        fileNumLimit: 300,
        fileSizeLimit: 200 * 1024 * 1024,    // 200 M
        fileSingleSizeLimit: 50 * 1024 * 1024    // 50 M
    });

    // 添加“添加文件”的按钮，
    uploader.addButton({
        id: '#filePicker2',
        label: '继续添加'
    });

    // 当有文件添加进来时执行，负责view的创建
    function addFile( file ) {
        var $li = $( '
' +
                '
' + file.name + '
' +
                '

'+
                '

' +
                '
' ),

            $btns = $('
' +
                '删除' +
                '向右旋转' +
                '向左旋转
').appendTo( $li ),
            $prgress = $li.find('p.progress span'),
            $wrap = $li.find( 'p.imgWrap' ),
            $info = $('

'),

            showError = function( code ) {
                switch( code ) {
                    case 'exceed_size':
                        text = '文件大小超出';
                        break;

                    case 'interrupt':
                        text = '上传暂停';
                        break;

                    default:
                        text = '上传失败，请重试';
                        break;
                }

                $info.text( text ).appendTo( $li );
            };

        if ( file.getStatus() === 'invalid' ) {
            showError( file.statusText );
        } else {
            // @todo lazyload
            $wrap.text( '预览中' );
            uploader.makeThumb( file, function( error, src ) {
                if ( error ) {
                    $wrap.text( '不能预览' );
                    return;
                }

                var img = $('');
                $wrap.empty().append( img );
            }, thumbnailWidth, thumbnailHeight );

            percentages[ file.id ] = [ file.size, 0 ];
            file.rotation = 0;
        }

        file.on('statuschange', function( cur, prev ) {
            if ( prev === 'progress' ) {
                $prgress.hide().width(0);
            } else if ( prev === 'queued' ) {
                $li.off( 'mouseenter mouseleave' );
                $btns.remove();
            }

            // 成功
            if ( cur === 'error' || cur === 'invalid' ) {
                console.log( file.statusText );
                showError( file.statusText );
                percentages[ file.id ][ 1 ] = 1;
            } else if ( cur === 'interrupt' ) {
                showError( 'interrupt' );
            } else if ( cur === 'queued' ) {
                percentages[ file.id ][ 1 ] = 0;
            } else if ( cur === 'progress' ) {
                $info.remove();
                $prgress.css('display', 'block');
            } else if ( cur === 'complete' ) {
                $li.append( '' );
            }

            $li.removeClass( 'state-' + prev ).addClass( 'state-' + cur );
        });

        $li.on( 'mouseenter', function() {
            $btns.stop().animate({height: 30});
        });

        $li.on( 'mouseleave', function() {
            $btns.stop().animate({height: 0});
        });

        $btns.on( 'click', 'span', function() {
            var index = $(this).index(),
                deg;

            switch ( index ) {
                case 0:
                    uploader.removeFile( file );
                    return;

                case 1:
                    file.rotation += 90;
                    break;

                case 2:
                    file.rotation -= 90;
                    break;
            }

            if ( supportTransition ) {
                deg = 'rotate(' + file.rotation + 'deg)';
                $wrap.css({
                    '-webkit-transform': deg,
                    '-mos-transform': deg,
                    '-o-transform': deg,
                    'transform': deg
                });
            } else {
                $wrap.css( 'filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+ (~~((file.rotation/90)%4 + 4)%4) +')');
                // use jquery animate to rotation
                // $({
                //     rotation: rotation
                // }).animate({
                //     rotation: file.rotation
                // }, {
                //     easing: 'linear',
                //     step: function( now ) {
                //         now = now * Math.PI / 180;

                //         var cos = Math.cos( now ),
                //             sin = Math.sin( now );

                //         $wrap.css( 'filter', "progid:DXImageTransform.Microsoft.Matrix(M11=" + cos + ",M12=" + (-sin) + ",M21=" + sin + ",M22=" + cos + ",SizingMethod='auto expand')");
                //     }
                // });
            }

        });

        $li.appendTo( $queue );
    }

    // 负责view的销毁
    function removeFile( file ) {
        var $li = $('#'+file.id);

        delete percentages[ file.id ];
        updateTotalProgress();
        $li.off().find('.file-panel').off().end().remove();
    }

    function updateTotalProgress() {
        var loaded = 0,
            total = 0,
            spans = $progress.children(),
            percent;

        $.each( percentages, function( k, v ) {
            total += v[ 0 ];
            loaded += v[ 0 ] * v[ 1 ];
        } );

        percent = total ? loaded / total : 0;

        spans.eq( 0 ).text( Math.round( percent * 100 ) + '%' );
        spans.eq( 1 ).css( 'width', Math.round( percent * 100 ) + '%' );
        updateStatus();
    }

    function updateStatus() {
        var text = '', stats;

        if ( state === 'ready' ) {
            text = '选中' + fileCount + '张图片，共' +
                    WebUploader.formatSize( fileSize ) + '。';
        } else if ( state === 'confirm' ) {
            stats = uploader.getStats();
            if ( stats.uploadFailNum ) {
                text = '已成功上传' + stats.successNum+ '张照片至XX相册，'+
                    stats.uploadFailNum + '张照片上传失败，重新上传失败图片或忽略'
            }

        } else {
            stats = uploader.getStats();
            text = '共' + fileCount + '张（' +
                    WebUploader.formatSize( fileSize )  +
                    '），已上传' + stats.successNum + '张';

            if ( stats.uploadFailNum ) {
                text += '，失败' + stats.uploadFailNum + '张';
            }
        }

        $info.html( text );
    }

    function setState( val ) {
        var file, stats;

        if ( val === state ) {
            return;
        }

        $upload.removeClass( 'state-' + state );
        $upload.addClass( 'state-' + val );
        state = val;

        switch ( state ) {
            case 'pedding':
                $placeHolder.removeClass( 'element-invisible' );
                $queue.parent().removeClass('filled');
                $queue.hide();
                $statusBar.addClass( 'element-invisible' );
                uploader.refresh();
                break;

            case 'ready':
                $placeHolder.addClass( 'element-invisible' );
                $( '#filePicker2' ).removeClass( 'element-invisible');
                $queue.parent().addClass('filled');
                $queue.show();
                $statusBar.removeClass('element-invisible');
                uploader.refresh();
                break;

            case 'uploading':
                $( '#filePicker2' ).addClass( 'element-invisible' );
                $progress.show();
                $upload.text( '暂停上传' );
                break;

            case 'paused':
                $progress.show();
                $upload.text( '继续上传' );
                break;

            case 'confirm':
                $progress.hide();
                $upload.text( '开始上传' ).addClass( 'disabled' );

                stats = uploader.getStats();
                if ( stats.successNum && !stats.uploadFailNum ) {
                    setState( 'finish' );
                    return;
                }
                break;
            case 'finish':
                stats = uploader.getStats();
                if ( stats.successNum ) {
                    alert( '上传成功' );
                } else {
                    // 没有成功的图片，重设
                    state = 'done';
                    location.reload();
                }
                break;
        }

        updateStatus();
    }

    uploader.onUploadProgress = function( file, percentage ) {
        var $li = $('#'+file.id),
            $percent = $li.find('.progress span');

        $percent.css( 'width', percentage * 100 + '%' );
        percentages[ file.id ][ 1 ] = percentage;
        updateTotalProgress();
    };

    uploader.onFileQueued = function( file ) {
        fileCount++;
        fileSize += file.size;

        if ( fileCount === 1 ) {
            $placeHolder.addClass( 'element-invisible' );
            $statusBar.show();
        }

        addFile( file );
        setState( 'ready' );
        updateTotalProgress();
    };

    uploader.onFileDequeued = function( file ) {
        fileCount--;
        fileSize -= file.size;

        if ( !fileCount ) {
            setState( 'pedding' );
        }

        removeFile( file );
        updateTotalProgress();

    };

    uploader.on( 'all', function( type ) {
        var stats;
        switch( type ) {
            case 'uploadFinished':
                setState( 'confirm' );
                break;

            case 'startUpload':
                setState( 'uploading' );
                break;

            case 'stopUpload':
                setState( 'paused' );
                break;

        }
    });

    uploader.onError = function( code ) {
        alert( 'Eroor: ' + code );
    };

    $upload.on('click', function() {
        if ( $(this).hasClass( 'disabled' ) ) {
            return false;
        }

        if ( state === 'ready' ) {
            uploader.upload();
        } else if ( state === 'paused' ) {
            uploader.upload();
        } else if ( state === 'uploading' ) {
            uploader.stop();
        }
    });

    $info.on( 'click', '.retry', function() {
        uploader.retry();
    } );

    $info.on( 'click', '.ignore', function() {
        alert( 'todo' );
    } );

    $upload.addClass( 'state-' + state );
    updateTotalProgress();
});<commit_msg>程序自动提交，源码请查看tree/master/jekyll目录<commit_after>jQuery(function() {
    var $ = jQuery,    // just in case. Make sure it's not an other libaray.

        $wrap = $('#uploader'),

        // 图片容器
        $queue = $('

')
            .appendTo( $wrap.find('.queueList') ),

        // 状态栏，包括进度和控制按钮
        $statusBar = $wrap.find('.statusBar'),

        // 文件总体选择信息。
        $info = $statusBar.find('.info'),

        // 上传按钮
        $upload = $wrap.find('.uploadBtn'),

        // 没选择文件之前的内容。
        $placeHolder = $wrap.find('.placeholder'),

        // 总体进度条
        $progress = $statusBar.find('.progress').hide(),

        // 添加的文件数量
        fileCount = 0,

        // 添加的文件总大小
        fileSize = 0,

        // 优化retina, 在retina下这个值是2
        ratio = window.devicePixelRatio || 1,

        // 缩略图大小
        thumbnailWidth = 110 * ratio,
        thumbnailHeight = 110 * ratio,

        // 可能有pedding, ready, uploading, confirm, done.
        state = 'pedding',

        // 所有文件的进度信息，key为file id
        percentages = {},

        supportTransition = (function(){
            var s = document.createElement('p').style,
                r = 'transition' in s ||
                      'WebkitTransition' in s ||
                      'MozTransition' in s ||
                      'msTransition' in s ||
                      'OTransition' in s;
            s = null;
            return r;
        })(),

        // WebUploader实例
        uploader;

    if ( !WebUploader.Uploader.support() ) {
        alert( 'Web Uploader 不支持您的浏览器！如果你使用的是IE浏览器，请尝试升级 flash 播放器');
        throw new Error( 'WebUploader does not support the browser you are using.' );
    }

    // 实例化
    uploader = WebUploader.create({
        pick: {
            id: '#filePicker',
            label: '点击选择图片'
        },
        dnd: '#uploader .queueList',
        paste: document.body,

        accept: {
            title: 'Images',
            extensions: 'gif,jpg,jpeg,bmp,png',
            mimeTypes: 'image/*'
        },

        // swf文件路径
        swf: BASE_URL + '/js/Uploader.swf',

        disableGlobalDnd: true,

        chunked: true,
        // server: 'http://webuploader.duapp.com/server/fileupload.php',
        server: 'http://2betop.net/fileupload.php',
        fileNumLimit: 300,
        fileSizeLimit: 5 * 1024 * 1024,    // 200 M
        fileSingleSizeLimit: 1 * 1024 * 1024    // 50 M
    });

    // 添加“添加文件”的按钮，
    uploader.addButton({
        id: '#filePicker2',
        label: '继续添加'
    });

    // 当有文件添加进来时执行，负责view的创建
    function addFile( file ) {
        var $li = $( '
' +
                '
' + file.name + '
' +
                '

'+
                '

' +
                '
' ),

            $btns = $('
' +
                '删除' +
                '向右旋转' +
                '向左旋转
').appendTo( $li ),
            $prgress = $li.find('p.progress span'),
            $wrap = $li.find( 'p.imgWrap' ),
            $info = $('

'),

            showError = function( code ) {
                switch( code ) {
                    case 'exceed_size':
                        text = '文件大小超出';
                        break;

                    case 'interrupt':
                        text = '上传暂停';
                        break;

                    default:
                        text = '上传失败，请重试';
                        break;
                }

                $info.text( text ).appendTo( $li );
            };

        if ( file.getStatus() === 'invalid' ) {
            showError( file.statusText );
        } else {
            // @todo lazyload
            $wrap.text( '预览中' );
            uploader.makeThumb( file, function( error, src ) {
                if ( error ) {
                    $wrap.text( '不能预览' );
                    return;
                }

                var img = $('');
                $wrap.empty().append( img );
            }, thumbnailWidth, thumbnailHeight );

            percentages[ file.id ] = [ file.size, 0 ];
            file.rotation = 0;
        }

        file.on('statuschange', function( cur, prev ) {
            if ( prev === 'progress' ) {
                $prgress.hide().width(0);
            } else if ( prev === 'queued' ) {
                $li.off( 'mouseenter mouseleave' );
                $btns.remove();
            }

            // 成功
            if ( cur === 'error' || cur === 'invalid' ) {
                console.log( file.statusText );
                showError( file.statusText );
                percentages[ file.id ][ 1 ] = 1;
            } else if ( cur === 'interrupt' ) {
                showError( 'interrupt' );
            } else if ( cur === 'queued' ) {
                percentages[ file.id ][ 1 ] = 0;
            } else if ( cur === 'progress' ) {
                $info.remove();
                $prgress.css('display', 'block');
            } else if ( cur === 'complete' ) {
                $li.append( '' );
            }

            $li.removeClass( 'state-' + prev ).addClass( 'state-' + cur );
        });

        $li.on( 'mouseenter', function() {
            $btns.stop().animate({height: 30});
        });

        $li.on( 'mouseleave', function() {
            $btns.stop().animate({height: 0});
        });

        $btns.on( 'click', 'span', function() {
            var index = $(this).index(),
                deg;

            switch ( index ) {
                case 0:
                    uploader.removeFile( file );
                    return;

                case 1:
                    file.rotation += 90;
                    break;

                case 2:
                    file.rotation -= 90;
                    break;
            }

            if ( supportTransition ) {
                deg = 'rotate(' + file.rotation + 'deg)';
                $wrap.css({
                    '-webkit-transform': deg,
                    '-mos-transform': deg,
                    '-o-transform': deg,
                    'transform': deg
                });
            } else {
                $wrap.css( 'filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+ (~~((file.rotation/90)%4 + 4)%4) +')');
                // use jquery animate to rotation
                // $({
                //     rotation: rotation
                // }).animate({
                //     rotation: file.rotation
                // }, {
                //     easing: 'linear',
                //     step: function( now ) {
                //         now = now * Math.PI / 180;

                //         var cos = Math.cos( now ),
                //             sin = Math.sin( now );

                //         $wrap.css( 'filter', "progid:DXImageTransform.Microsoft.Matrix(M11=" + cos + ",M12=" + (-sin) + ",M21=" + sin + ",M22=" + cos + ",SizingMethod='auto expand')");
                //     }
                // });
            }

        });

        $li.appendTo( $queue );
    }

    // 负责view的销毁
    function removeFile( file ) {
        var $li = $('#'+file.id);

        delete percentages[ file.id ];
        updateTotalProgress();
        $li.off().find('.file-panel').off().end().remove();
    }

    function updateTotalProgress() {
        var loaded = 0,
            total = 0,
            spans = $progress.children(),
            percent;

        $.each( percentages, function( k, v ) {
            total += v[ 0 ];
            loaded += v[ 0 ] * v[ 1 ];
        } );

        percent = total ? loaded / total : 0;

        spans.eq( 0 ).text( Math.round( percent * 100 ) + '%' );
        spans.eq( 1 ).css( 'width', Math.round( percent * 100 ) + '%' );
        updateStatus();
    }

    function updateStatus() {
        var text = '', stats;

        if ( state === 'ready' ) {
            text = '选中' + fileCount + '张图片，共' +
                    WebUploader.formatSize( fileSize ) + '。';
        } else if ( state === 'confirm' ) {
            stats = uploader.getStats();
            if ( stats.uploadFailNum ) {
                text = '已成功上传' + stats.successNum+ '张照片至XX相册，'+
                    stats.uploadFailNum + '张照片上传失败，重新上传失败图片或忽略'
            }

        } else {
            stats = uploader.getStats();
            text = '共' + fileCount + '张（' +
                    WebUploader.formatSize( fileSize )  +
                    '），已上传' + stats.successNum + '张';

            if ( stats.uploadFailNum ) {
                text += '，失败' + stats.uploadFailNum + '张';
            }
        }

        $info.html( text );
    }

    function setState( val ) {
        var file, stats;

        if ( val === state ) {
            return;
        }

        $upload.removeClass( 'state-' + state );
        $upload.addClass( 'state-' + val );
        state = val;

        switch ( state ) {
            case 'pedding':
                $placeHolder.removeClass( 'element-invisible' );
                $queue.parent().removeClass('filled');
                $queue.hide();
                $statusBar.addClass( 'element-invisible' );
                uploader.refresh();
                break;

            case 'ready':
                $placeHolder.addClass( 'element-invisible' );
                $( '#filePicker2' ).removeClass( 'element-invisible');
                $queue.parent().addClass('filled');
                $queue.show();
                $statusBar.removeClass('element-invisible');
                uploader.refresh();
                break;

            case 'uploading':
                $( '#filePicker2' ).addClass( 'element-invisible' );
                $progress.show();
                $upload.text( '暂停上传' );
                break;

            case 'paused':
                $progress.show();
                $upload.text( '继续上传' );
                break;

            case 'confirm':
                $progress.hide();
                $upload.text( '开始上传' ).addClass( 'disabled' );

                stats = uploader.getStats();
                if ( stats.successNum && !stats.uploadFailNum ) {
                    setState( 'finish' );
                    return;
                }
                break;
            case 'finish':
                stats = uploader.getStats();
                if ( stats.successNum ) {
                    alert( '上传成功' );
                } else {
                    // 没有成功的图片，重设
                    state = 'done';
                    location.reload();
                }
                break;
        }

        updateStatus();
    }

    uploader.onUploadProgress = function( file, percentage ) {
        var $li = $('#'+file.id),
            $percent = $li.find('.progress span');

        $percent.css( 'width', percentage * 100 + '%' );
        percentages[ file.id ][ 1 ] = percentage;
        updateTotalProgress();
    };

    uploader.onFileQueued = function( file ) {
        fileCount++;
        fileSize += file.size;

        if ( fileCount === 1 ) {
            $placeHolder.addClass( 'element-invisible' );
            $statusBar.show();
        }

        addFile( file );
        setState( 'ready' );
        updateTotalProgress();
    };

    uploader.onFileDequeued = function( file ) {
        fileCount--;
        fileSize -= file.size;

        if ( !fileCount ) {
            setState( 'pedding' );
        }

        removeFile( file );
        updateTotalProgress();

    };

    uploader.on( 'all', function( type ) {
        var stats;
        switch( type ) {
            case 'uploadFinished':
                setState( 'confirm' );
                break;

            case 'startUpload':
                setState( 'uploading' );
                break;

            case 'stopUpload':
                setState( 'paused' );
                break;

        }
    });

    uploader.onError = function( code ) {
        alert( 'Eroor: ' + code );
    };

    $upload.on('click', function() {
        if ( $(this).hasClass( 'disabled' ) ) {
            return false;
        }

        if ( state === 'ready' ) {
            uploader.upload();
        } else if ( state === 'paused' ) {
            uploader.upload();
        } else if ( state === 'uploading' ) {
            uploader.stop();
        }
    });

    $info.on( 'click', '.retry', function() {
        uploader.retry();
    } );

    $info.on( 'click', '.ignore', function() {
        alert( 'todo' );
    } );

    $upload.addClass( 'state-' + state );
    updateTotalProgress();
});<|endoftext|>


<commit_before>"use strict";
process.title = "HaruBot v" + require('./package.json').version;

const Discordie = require("discordie");
const authToken = require("./auth.json").token;

/**
 * Helpers
 */
const logHelper = require("./helpers/log.js");
const messageHelper = require("./helpers/message.js");
const guildEventsHelper = require("./helpers/guildevents.js");

/* Events constant */
const Events = Discordie.Events;

/* Create Client */
let Client = new Discordie({
	autoReconnect: true,
	delay: 1000
});

/* Connect */
Client.connect({ token: authToken });

Client.Dispatcher.on(Events.GATEWAY_READY, e => {
	Client.User.setGame("fishing...");
	logHelper.connection(Client, Client.Guilds.length, Client.Users.length, Client.Channels.length);
});

Client.Dispatcher.on(Events.MESSAGE_CREATE, e => {
	messageHelper.messageHelper(Client, e.message);
});

/**
 * Guild Events
 */

Client.Dispatcher.on(Events.GUILD_CREATE, e => {
	guildEventsHelper.handleGuildCreateEvent(e.guild, e.becameAvailable);
});

Client.Dispatcher.on(Events.GUILD_DELETE, e => {
	guildEventsHelper.handleGuildDeleteEvent(e.guildId);
});

Client.Dispatcher.on(Events.GUILD_UNAVAILABLE, e => {
	guildEventsHelper.handleGuildDeleteEvent(e.guildId);
});

Client.Dispatcher.on(Events.GUILD_MEMBER_ADD, e => {
	guildEventsHelper.handleNewMember(e.guild, e.member);
});

Client.Dispatcher.on(Events.GUILD_MEMBER_REMOVE, e => {
	guildEventsHelper.handleMemberRemove(e.guild, e.user);
});

Client.Dispatcher.on(Events.GUILD_MEMBER_UPDATE, e => {
	guildEventsHelper.handleMemberUpdate(e.guild, e.member, e.rolesAdded, e.rolesRemoved, e.previousNick);
});

Client.Dispatcher.on(Events.GUILD_BAN_ADD, e => {
	guildEventsHelper.handleBan(e.guild, e.user);
});

Client.Dispatcher.on(Events.GUILD_BAN_REMOVE, e => {
	guildEventsHelper.handleUnban(e.guild, e.user);
});

/**
 * Update server count on Abal's website
 */
if (auth.abalToken) {
	setInterval(() => {
		eventsHelper.updateServerCount(Client.User.id, Client.Guilds.length, auth.abalToken);
	}, 2000000);
}
<commit_msg>Fixed require on main file<commit_after>"use strict";
process.title = "HaruBot v" + require('./package.json').version;

const Discordie = require("discordie");
const auth = require("./auth.json");
const authToken = require("./auth.json").token;

/**
 * Helpers
 */
const logHelper = require("./helpers/log.js");
const messageHelper = require("./helpers/message.js");
const guildEventsHelper = require("./helpers/guildevents.js");

/* Events constant */
const Events = Discordie.Events;

/* Create Client */
let Client = new Discordie({
	autoReconnect: true,
	delay: 1000
});

/* Connect */
Client.connect({ token: authToken });

Client.Dispatcher.on(Events.GATEWAY_READY, e => {
	Client.User.setGame("fishing...");
	logHelper.connection(Client, Client.Guilds.length, Client.Users.length, Client.Channels.length);
});

Client.Dispatcher.on(Events.MESSAGE_CREATE, e => {
	messageHelper.messageHelper(Client, e.message);
});

/**
 * Guild Events
 */

Client.Dispatcher.on(Events.GUILD_CREATE, e => {
	guildEventsHelper.handleGuildCreateEvent(e.guild, e.becameAvailable);
});

Client.Dispatcher.on(Events.GUILD_DELETE, e => {
	guildEventsHelper.handleGuildDeleteEvent(e.guildId);
});

Client.Dispatcher.on(Events.GUILD_UNAVAILABLE, e => {
	guildEventsHelper.handleGuildDeleteEvent(e.guildId);
});

Client.Dispatcher.on(Events.GUILD_MEMBER_ADD, e => {
	guildEventsHelper.handleNewMember(e.guild, e.member);
});

Client.Dispatcher.on(Events.GUILD_MEMBER_REMOVE, e => {
	guildEventsHelper.handleMemberRemove(e.guild, e.user);
});

Client.Dispatcher.on(Events.GUILD_MEMBER_UPDATE, e => {
	guildEventsHelper.handleMemberUpdate(e.guild, e.member, e.rolesAdded, e.rolesRemoved, e.previousNick);
});

Client.Dispatcher.on(Events.GUILD_BAN_ADD, e => {
	guildEventsHelper.handleBan(e.guild, e.user);
});

Client.Dispatcher.on(Events.GUILD_BAN_REMOVE, e => {
	guildEventsHelper.handleUnban(e.guild, e.user);
});

/**
 * Update server count on Abal's website
 */
if (auth.abalToken) {
	setInterval(() => {
		eventsHelper.updateServerCount(Client.User.id, Client.Guilds.length, auth.abalToken);
	}, 2000000);
}
<|endoftext|>


<commit_before>var config = require('../lib/config')()
var tape     = require('tape')
var tools = require('./lib/tools')
var etcdjs = require('etcdjs')
var stubs = require('./lib/stubs')
var flatten = require('etcd-flatten')
var etcdserver = tools.etcd()
var exec = require('child_process').exec

var etcd = etcdjs('127.0.0.1:4001')

var stubwriter = tools.stubwriter()
var core = tools.core()

etcdserver.stop(tape, true)
etcdserver.reset(tape)
etcdserver.start(tape)
tools.pause(tape, 2)
etcdserver.check(tape)

stubwriter.singlenetwork(etcd, tape)

core.deploy(tape)

var pid = null
tape('check the proc deployment', function(t){

	etcd.get('/proc', {
		recursive:true
	}, function(err, result){
		if(err){
			t.fail(err, 'load proc data')
			t.end()
			return
		}
		result = flatten(result.node)
		result = tools.processObject(result, function(key){
			return key
		})

		var job
		var key
		Object.keys(result || {}).forEach(function(jkey){
			job = result[jkey]
			key = jkey

		})

		t.equal(job.stack, 'core', 'stack')
		t.equal(job.name, 'registry', 'name')
		t.equal(job.image, 'registry', 'image')
		t.equal(job.tag, 'default', 'tag')
		t.equal(job.id, 'core-default-registry-' + job.pid, 'id')
		t.equal(key, '/proc/core/default/registry/' + job.pid, 'key')

		pid = job.pid

		t.end()
	})
})

tape('run the dispatch', function(t){

	exec('viking dispatch', function(err, stdout){
		if(err){
			t.fail(err, 'dispatch')
			t.end()
			return
		}
		console.log(stdout.toString())
		t.pass('dispatch')
		t.end()
	})

})

tape('check the dispatch /run', function(t){

	etcd.get('/run', {
		recursive:true
	}, function(err, result){
		if(err){
			t.fail(err, 'load proc data')
			t.end()
			return
		}
		result = flatten(result.node)

		t.equal(result['/run/core/default/registry/' + pid], 'viking-0', 'the /run is set to the hostname')
		t.end()

	})
})

etcdserver.stop(tape)<commit_msg>dont muck about<commit_after>var config = require('../lib/config')()
var tape     = require('tape')
var tools = require('./lib/tools')
var etcdjs = require('etcdjs')
var stubs = require('./lib/stubs')
var flatten = require('etcd-flatten')
var etcdserver = tools.etcd()
var exec = require('child_process').exec

var etcd = etcdjs('127.0.0.1:4001')

var stubwriter = tools.stubwriter()
var core = tools.core()

etcdserver.stop(tape, true)
etcdserver.reset(tape)
etcdserver.start(tape)
tools.pause(tape, 2)
etcdserver.check(tape)

stubwriter.singlenetwork(etcd, tape)

core.deploy(tape)

var pid = null
tape('check the proc deployment', function(t){

	etcd.get('/proc', {
		recursive:true
	}, function(err, result){
		if(err){
			t.fail(err, 'load proc data')
			t.end()
			return
		}
		result = flatten(result.node)
		result = tools.processObject(result, function(key){
			return key
		})

		var job
		var key
		Object.keys(result || {}).forEach(function(jkey){
			job = result[jkey]
			key = jkey

		})

		t.equal(job.stack, 'core', 'stack')
		t.equal(job.name, 'registry', 'name')
		t.equal(job.image, 'registry', 'image')
		t.equal(job.tag, 'default', 'tag')
		t.equal(job.id, 'core-default-registry-' + job.pid, 'id')
		t.equal(key, '/proc/core/default/registry/' + job.pid, 'key')

		pid = job.pid

		t.end()
	})
})

tape('run the dispatch', function(t){

	exec('viking dispatch', function(err, stdout){
		if(err){
			t.fail(err, 'dispatch')
			t.end()
			return
		}
		console.log(stdout.toString())
		t.pass('dispatch')
		t.end()
	})

})

tape('check the dispatch /run', function(t){

	etcd.get('/run', {
		recursive:true
	}, function(err, result){
		if(err){
			t.fail(err, 'load proc data')
			t.end()
			return
		}
		result = flatten(result.node)

		t.equal(result['/run/core/default/registry/' + pid], 'viking-0', 'the /run is set to the hostname')
		t.end()

	})
})

etcdserver.stop(tape)<|endoftext|>


<commit_before>var $window = $(window);
var $document = $(document);
var $pagesSpacer = $('.pagesSpacer');
var $pagesContainer = $('.pagesContainer');
var $pages = $('.pageSingle');
var $header = $('.header');

var html;
var maxPageNumber = 3;
var currentPage = 1;
var pageCount = 1;
var pageHeight = $pages.height();
var screenHeight = $window.height();
var pagePlaceholder = $header.height();
var scrollValue;
var prevScroll;
var firstRun = true;
var pagesViewport;
var pagesObjHeight;
var nextPageTriggerHeight;
var prevPageTriggerHeight;
var pagesCurrentHeight;
var deletedPages = 0;

var scrollAmount = {up: 0, down: 0};

function loadPage(position, printPageNumber) {
	html = '
' + printPageNumber + '
';
	if (position === 'ini') {
		$pagesContainer.prepend(html);
	} else if (position === 'end') {
		$pagesContainer.append(html);
	}
	$pages = $('.pageSingle');
}

function loadNextPage() {
	if (pagesViewport > nextPageTriggerHeight) {
		pageCount++;
		loadPage('end', pageCount);
	}
}

function loadPrevPage() { // console.log('aqui');
	if ((pagesViewport < prevPageTriggerHeight) && (deletedPages > 0)) {
	// if (pagesViewport < prevPageTriggerHeight){
		console.info('load prev page');
		loadPage('ini', (currentPage - 1));
		deletedPages--;
		$('.deletedPageValue').text(deletedPages);
		$pagesSpacer.height(deletedPages * pageHeight);
	}
}

function removePage(position) {
	if (position === 'first') {

		$pages.splice(0,1);
		$('.pageSingle:first-child').remove();
		deletedPages++;
		$('.deletedPageValue').text(deletedPages);
		$pagesSpacer.height(deletedPages * pageHeight);
	} else if (position === 'last') {
		// $pages.pop();
		$pages.splice($pages.length-1,1);
		$('.pageSingle:last-child').remove();
	}
}

function currentPageControl(direction) {
	if (direction === 'down') {
		if (pagesViewport > pagesCurrentHeight) {
			currentPage++;
		}
	} else if (direction === 'up') {
		if ((pagesViewport < pagesCurrentHeight - (pageHeight * 1.5)) && (currentPage > 1)){
			currentPage--;
		}
	}

	$('.currentPageValue').text(currentPage);
}

function onScroll() { console.log(currentPage);
	scrollValue = $document.scrollTop();

	pagesViewport = screenHeight - pagePlaceholder;
	pagesObjHeight = pageHeight * pageCount;
	pagesCurrentHeight = pageHeight * currentPage;

	// screen half way through last visible page
	nextPageTriggerHeight = pagesObjHeight - pageHeight / 2;

	// screen half way through first visible page
	prevPageTriggerHeight = $pagesSpacer.height() + pageHeight * 1.5;

	// check if the screen is at half size
	if ((pagesViewport > (pageHeight / 2)) && (firstRun)) {
		pageCount++;
		loadPage('end', pageCount);
		firstRun = false;
	}

	if (prevScroll > scrollValue) { // scroll up
		scrollAmount.up = scrollValue;

		pagesViewport = pagesViewport + scrollValue;

		currentPageControl('up');
		loadPrevPage();

		if ($pages.length > maxPageNumber) {
			removePage('last');
		}
	} else if (prevScroll < scrollValue) { // scroll down
		scrollAmount.down = scrollValue;

		pagesViewport = pagesViewport + scrollValue;

		currentPageControl('down');
		loadNextPage();

		if ($pages.length > maxPageNumber) {
			removePage('first');
		}
	}

	// for visual aid (do not include)
	$('.scrollDownValue').text(scrollAmount.down);
	$('.scrollUpValue').text(scrollAmount.up);

	prevScroll = scrollValue;
}

onScroll();
// $(window).on('scroll', _.debounce(onScroll, 50));
$(window).on('scroll', onScroll);<commit_msg>Loading pages from bottom to top works. Issue: if scrolling down then up then down again, extra pages are not created.<commit_after>var $window = $(window);
var $document = $(document);
var $pagesSpacer = $('.pagesSpacer');
var $pagesContainer = $('.pagesContainer');
var $pages = $('.pageSingle');
var $header = $('.header');

var html;
var maxPageNumber = 3;
var currentPage = 1;
var pageCount = 1;
var pageHeight = $pages.height();
var screenHeight = $window.height();
var pagePlaceholder = $header.height();
var scrollValue;
var prevScroll;
var firstRun = true;
var pagesViewport;
var pagesObjHeight;
var nextPageTriggerHeight;
var prevPageTriggerHeight;
var pagesCurrentHeight;
var deletedPages = 0;

var scrollAmount = {up: 0, down: 0};

function loadPage(position, printPageNumber) {
	html = '
' + printPageNumber + '
';
	if (position === 'ini') {
		$pagesContainer.prepend(html);
	} else if (position === 'end') {
		$pagesContainer.append(html);
	}
	$pages = $('.pageSingle');
}

function loadNextPage() {
	if (pagesViewport > nextPageTriggerHeight) {
		pageCount++;
		loadPage('end', pageCount);
	}
}

function loadPrevPage() { // console.log('aqui');
	if ((pagesViewport < prevPageTriggerHeight) && (deletedPages > 0)) {
	// if (pagesViewport < prevPageTriggerHeight){
		console.info('load prev page');
		loadPage('ini', (currentPage - 1));
		deletedPages--;
		$('.deletedPageValue').text(deletedPages);
		$pagesSpacer.height(deletedPages * pageHeight);
	}
}

function removePage(position) {
	if (position === 'first') {

		$pages.splice(0,1);
		$('.pageSingle:first-child').remove();
		deletedPages++;
		$('.deletedPageValue').text(deletedPages);
		$pagesSpacer.height(deletedPages * pageHeight);
	} else if (position === 'last') {
		// $pages.pop();
		$pages.splice($pages.length-1,1);
		$('.pageSingle:last-child').remove();
	}
}

function currentPageControl(direction) {
	if (direction === 'down') {
		if (pagesViewport > pagesCurrentHeight) {
			currentPage++;
		}
	} else if (direction === 'up') {
		if ((pagesViewport < (pagesCurrentHeight - pageHeight * 0.5)) && (currentPage > 1)) {
			currentPage--;
		}
	}

	$('.currentPageValue').text(currentPage);
}

function onScroll() { console.log(currentPage);
	scrollValue = $document.scrollTop();

	pagesViewport = screenHeight - pagePlaceholder;
	pagesObjHeight = pageHeight * pageCount;
	pagesCurrentHeight = pageHeight * currentPage;

	// screen half way through last visible page
	nextPageTriggerHeight = pagesObjHeight - pageHeight / 2;

	// screen half way through first visible page
	prevPageTriggerHeight = $pagesSpacer.height() + pageHeight * 1.5;

	// check if the screen is at half size
	if ((pagesViewport > (pageHeight / 2)) && (firstRun)) {
		pageCount++;
		loadPage('end', pageCount);
		firstRun = false;
	}

	if (prevScroll > scrollValue) { // scroll up
		scrollAmount.up = scrollValue;

		pagesViewport = pagesViewport + scrollValue;

		currentPageControl('up');
		loadPrevPage();

		if ($pages.length > maxPageNumber) {
			removePage('last');
		}
	} else if (prevScroll < scrollValue) { // scroll down
		scrollAmount.down = scrollValue;

		pagesViewport = pagesViewport + scrollValue;

		currentPageControl('down');
		loadNextPage();

		if ($pages.length > maxPageNumber) {
			removePage('first');
		}
	}

	// for visual aid (do not include)
	$('.scrollDownValue').text(scrollAmount.down);
	$('.scrollUpValue').text(scrollAmount.up);

	prevScroll = scrollValue;
}

onScroll();
// $(window).on('scroll', _.debounce(onScroll, 50));
$(window).on('scroll', onScroll);<|endoftext|>