<commit_before>/*---------------------------------------------------------
 * OpenERP web_graph
 *---------------------------------------------------------*/

openerp.web_graph = function (openerp) {
var COLOR_PALETTE = [
    '#cc99ff', '#ccccff', '#48D1CC', '#CFD784', '#8B7B8B', '#75507b',
    '#b0008c', '#ff0000', '#ff8e00', '#9000ff', '#0078ff', '#00ff00',
    '#e6ff00', '#ffff00', '#905000', '#9b0000', '#840067', '#9abe00',
    '#ffc900', '#510090', '#0000c9', '#009b00', '#75507b', '#3465a4',
    '#73d216', '#c17d11', '#edd400', '#fcaf3e', '#ef2929', '#ff00c9',
    '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f', '#f57900',
    '#cc0000', '#d400a8'];

var QWeb = openerp.web.qweb;
openerp.web.views.add('graph', 'openerp.web_graph.GraphView');
openerp.web_graph.GraphView = openerp.web.View.extend({

    init: function(parent, dataset, view_id, options) {
        this._super(parent);
        this.set_default_options(options);
        this.dataset = dataset;
        this.view_id = view_id;

        this.first_field = null;
        this.abscissa = null;
        this.ordinate = null;
        this.columns = [];
        this.group_field = null;
        this.is_loaded = $.Deferred();

        this.renderer = null;
    },
    stop: function () {
        if (this.renderer) {
            clearTimeout(this.renderer);
        }
        this._super();
    },
    do_show: function () {
        this.$element.show();
    },
    do_hide: function () {
        this.$element.hide();
    },
    start: function() {
        var self = this;
        this._super();
        var loaded;
        if (this.embedded_view) {
            loaded = $.when([self.embedded_view]);
        } else {
            loaded = this.rpc('/web/view/load', {
                    model: this.dataset.model,
                    view_id: this.view_id,
                    view_type: 'graph'
            });
        }
        return $.when(
            this.dataset.call('fields_get', []),
            loaded)
            .then(function (fields_result, view_result) {
                self.fields = fields_result[0];
                self.fields_view = view_result[0];
                self.on_loaded();
            });
    },
    /**
     * Returns all object fields involved in the graph view
     */
    list_fields: function () {
        var fs = [this.abscissa];
        fs.push.apply(fs, _(this.columns).pluck('name'));
        if (this.group_field) {
            fs.push(this.group_field);
        }
        return fs;
    },
    on_loaded: function() {
        this.chart = this.fields_view.arch.attrs.type || 'pie';
        this.orientation = this.fields_view.arch.attrs.orientation || 'vertical';

        _.each(this.fields_view.arch.children, function (field) {
            var attrs = field.attrs;
            if (attrs.group) {
                this.group_field = attrs.name;
            } else if(!this.abscissa) {
                this.first_field = this.abscissa = attrs.name;
            } else {
                this.columns.push({
                    name: attrs.name,
                    operator: attrs.operator || '+'
                });
            }
        }, this);
        this.ordinate = this.columns[0].name;
        this.is_loaded.resolve();
    },
    schedule_chart: function(results) {
        var self = this;
        this.$element.html(QWeb.render("GraphView", {
            "fields_view": this.fields_view,
            "chart": this.chart,
            'element_id': this.element_id
        }));

        var fields = _(this.columns).pluck('name').concat([this.abscissa]);
        if (this.group_field) { fields.push(this.group_field); }
        // transform search result into usable records (convert from OpenERP
        // value shapes to usable atomic types
        var records = _(results).map(function (result) {
            var point = {};
            _(result).each(function (value, field) {
                if (!_(fields).contains(field)) { return; }
                if (value === false) { point[field] = false; return; }
                switch (self.fields[field].type) {
                case 'selection':
                    point[field] = _(self.fields[field].selection).detect(function (choice) {
                        return choice[0] === value;
                    })[1];
                    break;
                case 'many2one':
                    point[field] = value[1];
                    break;
                case 'integer': case 'float': case 'char':
                case 'date': case 'datetime':
                    point[field] = value;
                    break;
                default:
                    throw new Error(
                        "Unknown field type " + self.fields[field].type
                        + "for field " + field + " (" + value + ")");
                }
            });
            return point;
        });
        // aggregate data, because dhtmlx is crap. Aggregate on abscissa field,
        // leave split on group field => max m*n records where m is the # of
        // values for the abscissa and n is the # of values for the group field
        var graph_data = [];
        _(records).each(function (record) {
            var abscissa = record[self.abscissa],
                group = record[self.group_field];
            var r = _(graph_data).detect(function (potential) {
                return potential[self.abscissa] === abscissa
                        && (!self.group_field
                            || potential[self.group_field] === group);
            });
            var datapoint = r || {};

            datapoint[self.abscissa] = abscissa;
            if (self.group_field) { datapoint[self.group_field] = group; }
            _(self.columns).each(function (column) {
                var val = record[column.name],
                    aggregate = datapoint[column.name];
                switch(column.operator) {
                case '+':
                    datapoint[column.name] = (aggregate || 0) + val;
                    return;
                case '*':
                    datapoint[column.name] = (aggregate || 1) * val;
                    return;
                case 'min':
                    datapoint[column.name] = (aggregate || Infinity) > val
                                           ? val
                                           : aggregate;
                    return;
                case 'max':
                    datapoint[column.name] = (aggregate || -Infinity) < val
                                           ? val
                                           : aggregate;
                }
            });

            if (!r) { graph_data.push(datapoint); }
        });
        graph_data = _(graph_data).sortBy(function (point) {
            return point[self.abscissa] + '[[--]]' + point[self.group_field];
        });

        if (this.chart == 'bar') {
            return this.schedule_bar(graph_data);
        } else if (this.chart == "pie") {
            return this.schedule_pie(graph_data);
        }
    },

    schedule_bar: function(results) {
        var self = this;

        var group_list, view_chart;
        if (!this.group_field) {
            view_chart = (this.orientation === 'horizontal') ? 'barH' : 'bar';
            group_list = _(this.columns).map(function (column, index) {
                return {
                    group: column.name,
                    text: self.fields[column.name].string,
                    color: COLOR_PALETTE[index % (COLOR_PALETTE.length)]
                }
            });
        } else {
            // dhtmlx handles clustered bar charts (> 1 column per abscissa
            // value) and stacked bar charts (basically the same but with the
            // columns on top of one another instead of side by side), but it
            // does not handle clustered stacked bar charts
            if (this.columns.length > 1) {
                this.$element.text(
                    'OpenERP Web does not support combining grouping and '
                  + 'multiple columns in graph at this time.');
                throw new Error(
                    'dhtmlx can not handle columns counts of that magnitude');
            }
            // transform series for clustered charts into series for stacked
            // charts
            view_chart = (this.orientation === 'horizontal')
                    ? 'stackedBarH' : 'stackedBar';
            group_list = _(results).chain()
                    .pluck(this.group_field)
                    .uniq()
                    .map(function (value, index) {
                        return {
                            group: self.ordinate + '_' +
                                    value.toLowerCase().replace(/\s/g, '_'),
                            text: value,
                            color: COLOR_PALETTE[index % COLOR_PALETTE.length]
                        };
                    }).value();

            results = _(results).chain()
                .groupBy(function (record) { return record[self.abscissa]; })
                .map(function (records) {
                    var r = {};
                    // second argument is coerced to a str, no good for boolean
                    r[self.abscissa] = records[0][self.abscissa];
                    _(records).each(function (record) {
                        var key = _.sprintf('%s_%s',
                            self.ordinate,
                            record[self.group_field].toLowerCase().replace(/\s/g, '_'));
                        r[key] = record[self.ordinate];
                    });
                    return r;
                })
                .value();
        }

        var abscissa_description = {
            title: "" + this.fields[this.abscissa].string + "",
            template: function (obj) {
                return obj[self.abscissa] || 'Undefined';
            }
        };

        var ordinate_description = {
            lines: true,
            title: "" + this.fields[this.ordinate].string + ""
        };

        var x_axis, y_axis;
        if (self.orientation == 'horizontal') {
            x_axis = ordinate_description;
            y_axis = abscissa_description;
        } else {
            x_axis = abscissa_description;
            y_axis = ordinate_description;
        }

        var renderer = function () {
            if (self.$element.is(':hidden')) {
                self.renderer = setTimeout(renderer, 100);
                return;
            }
            self.renderer = null;
            var bar_chart = new dhtmlXChart({
                view: view_chart,
                container: self.element_id+"-barchart",
                value:"#"+group_list[0].group+"#",
                gradient: "3d",
                border: false,
                width: 1024,
                tooltip:{
                    template: _.sprintf("#%s#, %s=#%s#",
                        self.abscissa, group_list[0].text, group_list[0].group)
                },
                radius: 0,
                color:group_list[0].color,
                origin:0,
                xAxis: x_axis,
                yAxis: y_axis,
                padding: {
                    left: 75
                },
                legend: {
                    values: group_list,
                    align:"left",
                    valign:"top",
                    layout: "x",
                    marker: {
                        type:"round",
                        width:12
                    }
                }
            });
            for (var m = 1; m<group_list.length;m++){
                var column = group_list[m];
                if (column.group === self.group_field) { continue; }
                bar_chart.addSeries({
                    value: "#"+column.group+"#",
                    tooltip:{
                        template: _.sprintf("#%s#, %s=#%s#",
                            self.abscissa, column.text, column.group)
                    },
                    color: column.color
                });
            }
            bar_chart.parse(results, "json");
            self.$element.find("#"+self.element_id+"-barchart").height(
                self.$element.find("#"+self.element_id+"-barchart").height()+50);
            bar_chart.attachEvent("onItemClick", function(id) {
                self.open_list_view(bar_chart.get(id));
            });
        };
        if (this.renderer) {
            clearTimeout(this.renderer);
        }
        this.renderer = setTimeout(renderer, 0);
    },
    schedule_pie: function(result) {
        var self = this;
        var renderer = function () {
            if (self.$element.is(':hidden')) {
                self.renderer = setTimeout(renderer, 100);
                return;
            }
            self.renderer = null;
            var chart =  new dhtmlXChart({
                view:"pie3D",
                container:self.element_id+"-piechart",
                value:"#"+self.ordinate+"#",
                pieInnerText:function(obj) {
                    var sum = chart.sum("#"+self.ordinate+"#");
                    var val = obj[self.ordinate] / sum * 100 ;
                    return val.toFixed(1) + "%";
                },
                tooltip:{
                    template:"#"+self.abscissa+"#"+"="+"#"+self.ordinate+"#"
                },
                gradient:"3d",
                height: 20,
                radius: 200,
                legend: {
                    width: 300,
                    align:"left",
                    valign:"top",
                    layout: "x",
                    marker:{
                        type:"round",
                        width:12
                    },
                    template:function(obj){
                        return obj[self.abscissa] || 'Undefined';
                    }
                }
            });
            chart.parse(result,"json");
            chart.attachEvent("onItemClick", function(id) {
                self.open_list_view(chart.get(id));
            });
        };
        if (this.renderer) {
            clearTimeout(this.renderer);
        }
        this.renderer = setTimeout(renderer, 0);
    },
    open_list_view : function (id){
        var self = this;
        if($(".dhx_tooltip").is(":visible")) {
            $(".dhx_tooltip").remove('div');
        }
        id = id[this.abscissa];
        if (typeof id == 'object'){
            id = id[0];
        }

        var record_id = this.abscissa;
        var modes = ["list", "form", "graph"];
        var views = [];
        _.each(modes, function(mode) {
            var view = [false, mode];
            if (self.fields.views && self.fields.views[mode]) {
                view.push(self.fields.views[mode]);
            }
            views.push(view);
        });
        this.do_action({
            "res_model" : this.dataset.model,
            "domain" : [[record_id, '=', id], ['id','in',this.dataset.ids]],
            "views" : views,
            "type" : "ir.actions.act_window",
            "auto_search" : true,
            "view_type" : "list",
            "view_mode" : "list"
        });
    },

    do_search: function(domain, context, group_by) {
        var self = this;
        return $.when(this.is_loaded).pipe(function() {
            // TODO: handle non-empty group_by with read_group?
            if (!_(group_by).isEmpty()) {
                self.abscissa = group_by[0];
            } else {
                self.abscissa = self.first_field;
            }
            return self.dataset.read_slice(self.list_fields(), {}, $.proxy(self, 'schedule_chart'));
        });
    }
});
};
// vim:et fdc=0 fdl=0:
<commit_msg>[FIX] graph tooltips remaining on screen after clicking them<commit_after>/*---------------------------------------------------------
 * OpenERP web_graph
 *---------------------------------------------------------*/

openerp.web_graph = function (openerp) {
var COLOR_PALETTE = [
    '#cc99ff', '#ccccff', '#48D1CC', '#CFD784', '#8B7B8B', '#75507b',
    '#b0008c', '#ff0000', '#ff8e00', '#9000ff', '#0078ff', '#00ff00',
    '#e6ff00', '#ffff00', '#905000', '#9b0000', '#840067', '#9abe00',
    '#ffc900', '#510090', '#0000c9', '#009b00', '#75507b', '#3465a4',
    '#73d216', '#c17d11', '#edd400', '#fcaf3e', '#ef2929', '#ff00c9',
    '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f', '#f57900',
    '#cc0000', '#d400a8'];

var QWeb = openerp.web.qweb;
openerp.web.views.add('graph', 'openerp.web_graph.GraphView');
openerp.web_graph.GraphView = openerp.web.View.extend({

    init: function(parent, dataset, view_id, options) {
        this._super(parent);
        this.set_default_options(options);
        this.dataset = dataset;
        this.view_id = view_id;

        this.first_field = null;
        this.abscissa = null;
        this.ordinate = null;
        this.columns = [];
        this.group_field = null;
        this.is_loaded = $.Deferred();

        this.renderer = null;
    },
    stop: function () {
        if (this.renderer) {
            clearTimeout(this.renderer);
        }
        this._super();
    },
    do_show: function () {
        this.$element.show();
    },
    do_hide: function () {
        this.$element.hide();
    },
    start: function() {
        var self = this;
        this._super();
        var loaded;
        if (this.embedded_view) {
            loaded = $.when([self.embedded_view]);
        } else {
            loaded = this.rpc('/web/view/load', {
                    model: this.dataset.model,
                    view_id: this.view_id,
                    view_type: 'graph'
            });
        }
        return $.when(
            this.dataset.call('fields_get', []),
            loaded)
            .then(function (fields_result, view_result) {
                self.fields = fields_result[0];
                self.fields_view = view_result[0];
                self.on_loaded();
            });
    },
    /**
     * Returns all object fields involved in the graph view
     */
    list_fields: function () {
        var fs = [this.abscissa];
        fs.push.apply(fs, _(this.columns).pluck('name'));
        if (this.group_field) {
            fs.push(this.group_field);
        }
        return fs;
    },
    on_loaded: function() {
        this.chart = this.fields_view.arch.attrs.type || 'pie';
        this.orientation = this.fields_view.arch.attrs.orientation || 'vertical';

        _.each(this.fields_view.arch.children, function (field) {
            var attrs = field.attrs;
            if (attrs.group) {
                this.group_field = attrs.name;
            } else if(!this.abscissa) {
                this.first_field = this.abscissa = attrs.name;
            } else {
                this.columns.push({
                    name: attrs.name,
                    operator: attrs.operator || '+'
                });
            }
        }, this);
        this.ordinate = this.columns[0].name;
        this.is_loaded.resolve();
    },
    schedule_chart: function(results) {
        var self = this;
        this.$element.html(QWeb.render("GraphView", {
            "fields_view": this.fields_view,
            "chart": this.chart,
            'element_id': this.element_id
        }));

        var fields = _(this.columns).pluck('name').concat([this.abscissa]);
        if (this.group_field) { fields.push(this.group_field); }
        // transform search result into usable records (convert from OpenERP
        // value shapes to usable atomic types
        var records = _(results).map(function (result) {
            var point = {};
            _(result).each(function (value, field) {
                if (!_(fields).contains(field)) { return; }
                if (value === false) { point[field] = false; return; }
                switch (self.fields[field].type) {
                case 'selection':
                    point[field] = _(self.fields[field].selection).detect(function (choice) {
                        return choice[0] === value;
                    })[1];
                    break;
                case 'many2one':
                    point[field] = value[1];
                    break;
                case 'integer': case 'float': case 'char':
                case 'date': case 'datetime':
                    point[field] = value;
                    break;
                default:
                    throw new Error(
                        "Unknown field type " + self.fields[field].type
                        + "for field " + field + " (" + value + ")");
                }
            });
            return point;
        });
        // aggregate data, because dhtmlx is crap. Aggregate on abscissa field,
        // leave split on group field => max m*n records where m is the # of
        // values for the abscissa and n is the # of values for the group field
        var graph_data = [];
        _(records).each(function (record) {
            var abscissa = record[self.abscissa],
                group = record[self.group_field];
            var r = _(graph_data).detect(function (potential) {
                return potential[self.abscissa] === abscissa
                        && (!self.group_field
                            || potential[self.group_field] === group);
            });
            var datapoint = r || {};

            datapoint[self.abscissa] = abscissa;
            if (self.group_field) { datapoint[self.group_field] = group; }
            _(self.columns).each(function (column) {
                var val = record[column.name],
                    aggregate = datapoint[column.name];
                switch(column.operator) {
                case '+':
                    datapoint[column.name] = (aggregate || 0) + val;
                    return;
                case '*':
                    datapoint[column.name] = (aggregate || 1) * val;
                    return;
                case 'min':
                    datapoint[column.name] = (aggregate || Infinity) > val
                                           ? val
                                           : aggregate;
                    return;
                case 'max':
                    datapoint[column.name] = (aggregate || -Infinity) < val
                                           ? val
                                           : aggregate;
                }
            });

            if (!r) { graph_data.push(datapoint); }
        });
        graph_data = _(graph_data).sortBy(function (point) {
            return point[self.abscissa] + '[[--]]' + point[self.group_field];
        });

        if (this.chart == 'bar') {
            return this.schedule_bar(graph_data);
        } else if (this.chart == "pie") {
            return this.schedule_pie(graph_data);
        }
    },

    schedule_bar: function(results) {
        var self = this;

        var group_list, view_chart;
        if (!this.group_field) {
            view_chart = (this.orientation === 'horizontal') ? 'barH' : 'bar';
            group_list = _(this.columns).map(function (column, index) {
                return {
                    group: column.name,
                    text: self.fields[column.name].string,
                    color: COLOR_PALETTE[index % (COLOR_PALETTE.length)]
                }
            });
        } else {
            // dhtmlx handles clustered bar charts (> 1 column per abscissa
            // value) and stacked bar charts (basically the same but with the
            // columns on top of one another instead of side by side), but it
            // does not handle clustered stacked bar charts
            if (this.columns.length > 1) {
                this.$element.text(
                    'OpenERP Web does not support combining grouping and '
                  + 'multiple columns in graph at this time.');
                throw new Error(
                    'dhtmlx can not handle columns counts of that magnitude');
            }
            // transform series for clustered charts into series for stacked
            // charts
            view_chart = (this.orientation === 'horizontal')
                    ? 'stackedBarH' : 'stackedBar';
            group_list = _(results).chain()
                    .pluck(this.group_field)
                    .uniq()
                    .map(function (value, index) {
                        return {
                            group: self.ordinate + '_' +
                                    value.toLowerCase().replace(/\s/g, '_'),
                            text: value,
                            color: COLOR_PALETTE[index % COLOR_PALETTE.length]
                        };
                    }).value();

            results = _(results).chain()
                .groupBy(function (record) { return record[self.abscissa]; })
                .map(function (records) {
                    var r = {};
                    // second argument is coerced to a str, no good for boolean
                    r[self.abscissa] = records[0][self.abscissa];
                    _(records).each(function (record) {
                        var key = _.sprintf('%s_%s',
                            self.ordinate,
                            record[self.group_field].toLowerCase().replace(/\s/g, '_'));
                        r[key] = record[self.ordinate];
                    });
                    return r;
                })
                .value();
        }

        var abscissa_description = {
            title: "" + this.fields[this.abscissa].string + "",
            template: function (obj) {
                return obj[self.abscissa] || 'Undefined';
            }
        };

        var ordinate_description = {
            lines: true,
            title: "" + this.fields[this.ordinate].string + ""
        };

        var x_axis, y_axis;
        if (self.orientation == 'horizontal') {
            x_axis = ordinate_description;
            y_axis = abscissa_description;
        } else {
            x_axis = abscissa_description;
            y_axis = ordinate_description;
        }

        var renderer = function () {
            if (self.$element.is(':hidden')) {
                self.renderer = setTimeout(renderer, 100);
                return;
            }
            self.renderer = null;
            var bar_chart = new dhtmlXChart({
                view: view_chart,
                container: self.element_id+"-barchart",
                value:"#"+group_list[0].group+"#",
                gradient: "3d",
                border: false,
                width: 1024,
                tooltip:{
                    template: _.sprintf("#%s#, %s=#%s#",
                        self.abscissa, group_list[0].text, group_list[0].group)
                },
                radius: 0,
                color:group_list[0].color,
                origin:0,
                xAxis: x_axis,
                yAxis: y_axis,
                padding: {
                    left: 75
                },
                legend: {
                    values: group_list,
                    align:"left",
                    valign:"top",
                    layout: "x",
                    marker: {
                        type:"round",
                        width:12
                    }
                }
            });
            for (var m = 1; m<group_list.length;m++){
                var column = group_list[m];
                if (column.group === self.group_field) { continue; }
                bar_chart.addSeries({
                    value: "#"+column.group+"#",
                    tooltip:{
                        template: _.sprintf("#%s#, %s=#%s#",
                            self.abscissa, column.text, column.group)
                    },
                    color: column.color
                });
            }
            bar_chart.parse(results, "json");
            self.$element.find("#"+self.element_id+"-barchart").height(
                self.$element.find("#"+self.element_id+"-barchart").height()+50);
            bar_chart.attachEvent("onItemClick", function(id) {
                self.open_list_view(bar_chart.get(id));
            });
        };
        if (this.renderer) {
            clearTimeout(this.renderer);
        }
        this.renderer = setTimeout(renderer, 0);
    },
    schedule_pie: function(result) {
        var self = this;
        var renderer = function () {
            if (self.$element.is(':hidden')) {
                self.renderer = setTimeout(renderer, 100);
                return;
            }
            self.renderer = null;
            var chart =  new dhtmlXChart({
                view:"pie3D",
                container:self.element_id+"-piechart",
                value:"#"+self.ordinate+"#",
                pieInnerText:function(obj) {
                    var sum = chart.sum("#"+self.ordinate+"#");
                    var val = obj[self.ordinate] / sum * 100 ;
                    return val.toFixed(1) + "%";
                },
                tooltip:{
                    template:"#"+self.abscissa+"#"+"="+"#"+self.ordinate+"#"
                },
                gradient:"3d",
                height: 20,
                radius: 200,
                legend: {
                    width: 300,
                    align:"left",
                    valign:"top",
                    layout: "x",
                    marker:{
                        type:"round",
                        width:12
                    },
                    template:function(obj){
                        return obj[self.abscissa] || 'Undefined';
                    }
                }
            });
            chart.parse(result,"json");
            chart.attachEvent("onItemClick", function(id) {
                self.open_list_view(chart.get(id));
            });
        };
        if (this.renderer) {
            clearTimeout(this.renderer);
        }
        this.renderer = setTimeout(renderer, 0);
    },
    open_list_view : function (id){
        var self = this;
        // unconditionally nuke tooltips before switching view
        $(".dhx_tooltip").remove('div');
        id = id[this.abscissa];
        if (typeof id == 'object'){
            id = id[0];
        }

        var record_id = this.abscissa;
        var modes = ["list", "form", "graph"];
        var views = [];
        _.each(modes, function(mode) {
            var view = [false, mode];
            if (self.fields.views && self.fields.views[mode]) {
                view.push(self.fields.views[mode]);
            }
            views.push(view);
        });
        this.do_action({
            "res_model" : this.dataset.model,
            "domain" : [[record_id, '=', id], ['id','in',this.dataset.ids]],
            "views" : views,
            "type" : "ir.actions.act_window",
            "auto_search" : true,
            "view_type" : "list",
            "view_mode" : "list"
        });
    },

    do_search: function(domain, context, group_by) {
        var self = this;
        return $.when(this.is_loaded).pipe(function() {
            // TODO: handle non-empty group_by with read_group?
            if (!_(group_by).isEmpty()) {
                self.abscissa = group_by[0];
            } else {
                self.abscissa = self.first_field;
            }
            return self.dataset.read_slice(self.list_fields(), {}, $.proxy(self, 'schedule_chart'));
        });
    }
});
};
// vim:et fdc=0 fdl=0:
<|endoftext|>


<commit_before>import WinJS from "winjs";
import LifeCycle from "./common/lifecycle";
import Container from "./container";
import async from "async";
import Logging from "./log";
import Configuration from "./configuration";
import Builder from "./builder";
import ApplicationException from "./exception/base";
import MathHelper from "./helper/math";
import Package from '../package.json';
import PluginBase from "./plugin/base";
import BindingMode from "./binding/mode";
import BindingTemplate from "./binding/template";
import WinJSHelper from "./helper/winjs";

let singelton = null;
export default class Application extends LifeCycle {
  constructor() {
    super();

    if (!singelton) {
      singelton = this;

      this._application = this;

      this._builder = new Builder(this);
      this._container = new Container(this);
      this._configuration = new Configuration(this);
      this._isConfigured = false;
      this._isLoaded = false;
      this._isPaused = false;
      this._instanceKey = MathHelper.v4;
      this._package = Package;
      this._bindingMode = new BindingMode(this);
      this._bindingTemplate = new BindingTemplate(this);
      this._plugins = [];

      // TODO: make instance based
      this._logger = Logging;
    }

    require("./winjs.shim");

    WinJSHelper.markForProcessing(this);
    WinJSHelper.markForProcessing(this._bindingTemplate);
    WinJSHelper.markForProcessing(this._bindingMode);
  }

  static get Instance() {
    return singelton;
  }

  get container() {
    return this._container;
  }

  get logger() {
    return this._logger;
  }

  get builder() {
    return this._builder;
  }

  get configuration() {
    return this._configuration;
  }

  get isConfigured() {
    return this._isConfigured;
  }

  get isLoaded() {
    return this._isLoaded;
  }

  get isPaused() {
    return this._isPaused;
  }

  get instanceKey() {
    return this._instanceKey;
  }

  get plugins() {
    return this._plugins;
  }

  get Binding() {
    return {
      Mode: this._bindingMode,
      Template: this._bindingTemplate
    }
  }

  configure(options, done) {
    var that = this;
    options = options || {};
    options.instanceKey = options.instanceKey || this.instanceKey;
    this._instanceKey = options.instanceKey;
    options.plugins = options.plugins || [];
    async.waterfall([
        function(cb) {
          var appConfig = options["app-config"];
          if (appConfig)
            that.configuration.file(appConfig, cb);
          else
            return cb();
        }
      ],
      function(err) {
        if (err)
          return done(err);

        // Filter down invalid stuffs
        that._plugins = options.plugins.filter(function(p) {
          return p.prototype instanceof PluginBase;
        });

        // setup the framework services/providers
        if (!that.container.isProviderRegistered("lokiStorage"))
          that.container.registerProvider("lokiStorage", require('./provider/loki-storage'));
        if (!that.container.isProviderRegistered("localStorage"))
          that.container.registerProvider("localStorage", require('./provider/local-storage'));

        if (!that.container.isServiceRegistered("navigation"))
          that.container.registerService("navigation", require('./service/navigation'));
        if (!that.container.isServiceRegistered("message"))
          that.container.registerService("message", require('./service/message'));
        if (!that.container.isServiceRegistered("application"))
          that.container.registerService("application", require('./service/application'));
        if (!that.container.isServiceRegistered("data"))
          that.container.registerService("data", require('./service/data'));

        that._isConfigured = true;

        return done();
      });
  }

  load(options, done) {
    var that = this;

    if (!this.isConfigured)
      return done(new ApplicationException("Call configure before load"));

    super.loadComponent(options, function(err) {
      if (err)
        return done(err);

      var messageHooks = options.messageHooks || {};
      async.each(that.container.getServiceKeys(),
        function(key, keyCb) {
          var serviceInstance = that.container.getService(key);
          serviceInstance.loadComponent({}, keyCb);
        },
        function(err) {
          if (err)
            return done(err);

          var MessageService = that.container.getService("message");
          for (var handler in messageHooks)
            MessageService.register(handler, messageHooks[handler]);

          that._isLoaded = true;
          that._isPaused = false;

          MessageService.send("applicationReadyMessage");

          async.each(that._plugins,
            function(pluginDef, pluginCb) {
              var plugin = new pluginDef(pluginDef, that);
              plugin.loadComponent(options, pluginCb);
            },
            function(err) {
              if (err)
                return done(err);

              return done();
            });
        });
    });
  }

  unload(options, done) {
    var that = this;

    if (!this.isConfigured)
      return done(new ApplicationException("Call configure calling unload"));

    if (!this.isLoaded)
      return done(new ApplicationException("Call load before calling unload"));

    super.unloadComponent(options, function(err) {
      if (err)
        return done(err);

      async.each(that.container.getServiceKeys(),
        function(key, keyCb) {
          var serviceInstance = that.container.getService(key);
          serviceInstance.unloadComponent({}, keyCb);
        },
        function(err) {
          if (err)
            return done(err);

          that._isLoaded = false;
          that._isPaused = false;

          return done();
        });
    })
  }

  pause(options, done) {
    var that = this;

    if (!this.isConfigured)
      return done(new ApplicationException("Call configure calling pause"));

    if (!this.isLoaded)
      return done(new ApplicationException("Call load before calling pause"));

    if (this.isPaused)
      return done(new ApplicationException("Application already paused"));

    super.pause(options, function(err) {
      if (err)
        return done(err);

      async.each(that.container.getServiceKeys(),
        function(key, keyCb) {
          var serviceInstance = that.container.getService(key);
          serviceInstance.pause({}, keyCb);
        },
        function(err) {
          if (err)
            return done(err);

          that._isPaused = true;

          return done();
        });
    })
  }

  resume(options, done) {
    var that = this;

    if (!this.isConfigured)
      return done(new ApplicationException("Call configure calling resume"));

    if (!this.isLoaded)
      return done(new ApplicationException("Call load before calling resume"));

    if (!this.isPaused)
      return done(new ApplicationException("Call pause before calling resume"));

    super.resume(options, function(err) {
      if (err)
        return done(err);
      async.each(that.container.getServiceKeys(),
        function(key, keyCb) {
          var serviceInstance = that.container.getService(key);
          serviceInstance.resume({}, keyCb);
        },
        function(err) {
          if (err)
            return done(err);

          that._isPaused = false;

          return done();
        });
    })
  }

  WinJSPageDefine(viewKey, templateUri, baseClassDef, isItem) {
    var that = this;
    isItem = isItem || false;
    var existingBaseClass = WinJS.UI.Pages.define(templateUri);
    if (baseClassDef && existingBaseClass != baseClassDef) {
      var extendedClassDef = WinJS.UI.Pages.define(templateUri, {}, baseClassDef);
      that.application.container.overrideView(viewKey, extendedClassDef);
      that.configuration.set("pages:" + (isItem ? "item-" : "") + viewKey + ":template", templateUri);
      return extendedClassDef;
    }
    return existingBaseClass;
  }

};
<commit_msg>Travis CI auto-merge of master from build 860 - [ci skip]<commit_after>import WinJS from "winjs";
import LifeCycle from "./common/lifecycle";
import Container from "./container";
import async from "async";
import Logging from "./log";
import Configuration from "./configuration";
import Builder from "./builder";
import ApplicationException from "./exception/base";
import MathHelper from "./helper/math";
import Package from '../package.json';
import PluginBase from "./plugin/base";
import BindingMode from "./binding/mode";
import BindingTemplate from "./binding/template";
import WinJSHelper from "./helper/winjs";

let singelton = null;
export default class Application extends LifeCycle {
  constructor() {
    super();

    if (!singelton) {
      singelton = this;

      this._application = this;

      this._builder = new Builder(this);
      this._container = new Container(this);
      this._configuration = new Configuration(this);
      this._isConfigured = false;
      this._isLoaded = false;
      this._isPaused = false;
      this._instanceKey = MathHelper.v4;
      this._package = Package;
      this._bindingMode = new BindingMode(this);
      this._bindingTemplate = new BindingTemplate(this);
      this._plugins = [];

      // TODO: make instance based
      this._logger = Logging;
    }

    require("./winjs.shim");

    WinJSHelper.markForProcessing(this);
    WinJSHelper.markForProcessing(this._bindingTemplate);
    WinJSHelper.markForProcessing(this._bindingMode);
  }

  static get Instance() {
    return singelton;
  }

  get container() {
    return this._container;
  }

  get logger() {
    return this._logger;
  }

  get builder() {
    return this._builder;
  }

  get configuration() {
    return this._configuration;
  }

  get isConfigured() {
    return this._isConfigured;
  }

  get isLoaded() {
    return this._isLoaded;
  }

  get isPaused() {
    return this._isPaused;
  }

  get instanceKey() {
    return this._instanceKey;
  }

  get plugins() {
    return this._plugins;
  }

  get Binding() {
    return {
      Mode: this._bindingMode,
      Template: this._bindingTemplate
    }
  }

  configure(options, done) {
    var that = this;
    options = options || {};
    options.instanceKey = options.instanceKey || this.instanceKey;
    this._instanceKey = options.instanceKey;
    options.plugins = options.plugins || [];
    async.waterfall([
        function(cb) {
          var appConfig = options["app-config"];
          if (appConfig)
            that.configuration.file(appConfig, cb);
          else
            return cb();
        }
      ],
      function(err) {
        if (err)
          return done(err);

        // Filter down invalid stuffs
        that._plugins = options.plugins.filter(function(p) {
          return p.prototype instanceof PluginBase;
        });

        // setup the framework services/providers
        if (!that.container.isProviderRegistered("lokiStorage"))
          that.container.registerProvider("lokiStorage", require('./provider/loki-storage'));
        if (!that.container.isProviderRegistered("localStorage"))
          that.container.registerProvider("localStorage", require('./provider/local-storage'));

        if (!that.container.isServiceRegistered("navigation"))
          that.container.registerService("navigation", require('./service/navigation'));
        if (!that.container.isServiceRegistered("message"))
          that.container.registerService("message", require('./service/message'));
        if (!that.container.isServiceRegistered("application"))
          that.container.registerService("application", require('./service/application'));
        if (!that.container.isServiceRegistered("data"))
          that.container.registerService("data", require('./service/data'));

        that._isConfigured = true;

        return done();
      });
  }

  load(options, done) {
    var that = this;

    if (!this.isConfigured)
      return done(new ApplicationException("Call configure before load"));

    super.loadComponent(options, function(err) {
      if (err)
        return done(err);

      var messageHooks = options.messageHooks || {};
      async.each(that.container.getServiceKeys(),
        function(key, keyCb) {
          var serviceInstance = that.container.getService(key);
          serviceInstance.loadComponent({}, keyCb);
        },
        function(err) {
          if (err)
            return done(err);

          var MessageService = that.container.getService("message");
          for (var handler in messageHooks)
            MessageService.register(handler, messageHooks[handler]);

          that._isLoaded = true;
          that._isPaused = false;

          MessageService.send("applicationReadyMessage");

          async.each(that._plugins,
            function(pluginDef, pluginCb) {
              var plugin = new pluginDef(that);
              plugin.loadComponent(options, pluginCb);
            },
            function(err) {
              if (err)
                return done(err);

              return done();
            });
        });
    });
  }

  unload(options, done) {
    var that = this;

    if (!this.isConfigured)
      return done(new ApplicationException("Call configure calling unload"));

    if (!this.isLoaded)
      return done(new ApplicationException("Call load before calling unload"));

    super.unloadComponent(options, function(err) {
      if (err)
        return done(err);

      async.each(that.container.getServiceKeys(),
        function(key, keyCb) {
          var serviceInstance = that.container.getService(key);
          serviceInstance.unloadComponent({}, keyCb);
        },
        function(err) {
          if (err)
            return done(err);

          that._isLoaded = false;
          that._isPaused = false;

          return done();
        });
    })
  }

  pause(options, done) {
    var that = this;

    if (!this.isConfigured)
      return done(new ApplicationException("Call configure calling pause"));

    if (!this.isLoaded)
      return done(new ApplicationException("Call load before calling pause"));

    if (this.isPaused)
      return done(new ApplicationException("Application already paused"));

    super.pause(options, function(err) {
      if (err)
        return done(err);

      async.each(that.container.getServiceKeys(),
        function(key, keyCb) {
          var serviceInstance = that.container.getService(key);
          serviceInstance.pause({}, keyCb);
        },
        function(err) {
          if (err)
            return done(err);

          that._isPaused = true;

          return done();
        });
    })
  }

  resume(options, done) {
    var that = this;

    if (!this.isConfigured)
      return done(new ApplicationException("Call configure calling resume"));

    if (!this.isLoaded)
      return done(new ApplicationException("Call load before calling resume"));

    if (!this.isPaused)
      return done(new ApplicationException("Call pause before calling resume"));

    super.resume(options, function(err) {
      if (err)
        return done(err);
      async.each(that.container.getServiceKeys(),
        function(key, keyCb) {
          var serviceInstance = that.container.getService(key);
          serviceInstance.resume({}, keyCb);
        },
        function(err) {
          if (err)
            return done(err);

          that._isPaused = false;

          return done();
        });
    })
  }

  WinJSPageDefine(viewKey, templateUri, baseClassDef, isItem) {
    var that = this;
    isItem = isItem || false;
    var existingBaseClass = WinJS.UI.Pages.define(templateUri);
    if (baseClassDef && existingBaseClass != baseClassDef) {
      var extendedClassDef = WinJS.UI.Pages.define(templateUri, {}, baseClassDef);
      that.application.container.overrideView(viewKey, extendedClassDef);
      that.configuration.set("pages:" + (isItem ? "item-" : "") + viewKey + ":template", templateUri);
      return extendedClassDef;
    }
    return existingBaseClass;
  }

};
<|endoftext|>


<commit_before>// Øvelse 1
var tal1 = 3;
var tal2 = 7;

console.log(tal1 + tal2);
console.log(tal1 - tal2);
console.log(tal1 * tal2);
console.log(tal1 / tal2);
console.log(tal1 % tal2);
console.log(++tal1);
console.log(tal1++);
console.log(tal1);

// Øvelse 2

var tal = 12;
var tel = 22;

tal += 5;
console.log(tal);

tal -= 5;
console.log(tal);

tel *= 2;
console.log(tel);

tel /= 2;
console.log(tel);

tal %= 122;
console.log(tal);

// Øvelse 3
var tal = 2;

if (3 -= 1) {
    console.log(tal);
}<commit_msg>Operatorer færdiggjort!<commit_after>// Øvelse 1
var tal1 = 3;
var tal2 = 7;

console.log(tal1 + tal2);
console.log(tal1 - tal2);
console.log(tal1 * tal2);
console.log(tal1 / tal2);
console.log(tal1 % tal2);
console.log(++tal1);
console.log(tal1++);
console.log(tal1);

// Øvelse 2

var tal = 12;
var tel = 22;

tal += 5;
console.log(tal);

tal -= 5;
console.log(tal);

tel *= 2;
console.log(tel);

tel /= 2;
console.log(tel);

tal %= 122;
console.log(tal);

// Øvelse 3 & 4

var alder = 22;
var fodselsaar = 1995;

if (alder >= 18 || fodselsaar >= 1999){
    console.log("Congrats, you're old enough!");
} else {
    console.log("Sorry, but you're not old enough bud!");
}<|endoftext|>


<commit_before>/**
 * The examples provided by Facebook are for non-commercial testing and
 * evaluation purposes only.
 *
 * Facebook reserves all rights not expressly granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
 * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @flow
 */
'use strict';

var React = require('react-native');
var ViewExample = require('./ViewExample');
var createExamplePage = require('./createExamplePage');
var {
  AlertIOS,
  PixelRatio,
  ScrollView,
  StyleSheet,
  Text,
  TouchableHighlight,
  View,
} = React;

var EmptyPage = React.createClass({

  render: function() {
    return (
      <View style={[styles.emptyPage, this.props.customStyle]}>
        <Text style={styles.emptyPageText}>
          {this.props.text}
        </Text>
      </View>
    );
  },

});

var NavigatorIOSExample = React.createClass({

  statics: {
    title: '<NavigatorIOS>',
    description: 'iOS navigation capabilities',
  },
  componentDidMount:function(){
    this.counter = 10;
  },
  render: function() {
    var recurseTitle = 'Recurse Navigation';
    if (!this.props.topExampleRoute) {
      recurseTitle += ' - more examples here';
    }
    return (
      <ScrollView style={styles.list}>
        <View style={styles.line}/>
        <View style={styles.group}>
          <View style={styles.row}>
            <Text style={styles.rowNote}>
              See <UIExplorerApp> for top-level usage.
            </Text>
          </View>
        </View>
        <View style={styles.line}/>
        <View style={styles.groupSpace}/>
        <View style={styles.line}/>
        <View style={styles.group}>
          {this._renderRow(recurseTitle, () => {
            this.props.navigator.push({
              title: NavigatorIOSExample.title,
              component: NavigatorIOSExample,
              backButtonTitle: 'Custom Back',
              passProps: {topExampleRoute: this.props.topExampleRoute || this.props.route},
            });
          })}
          {this._renderRow('Push View Example', () => {
            this.props.navigator.push({
              title: 'Very Long Custom View Example Title',
              component: createExamplePage(null, ViewExample),
            });
          })}
          {this._renderRow('Change rightButtonTitle', () => {
            this.props.navigator.updateNavBar({rightButtonTitle:(this.counter++) + "",onRightButtonPress:()=>{
              this.counter = 10;
              this.props.navigator.updateNavBar({rightButtonTitle:null});
            }});
          })}
          {this._renderRow('Custom Right Button', () => {
            this.props.navigator.push({
              title: NavigatorIOSExample.title,
              component: EmptyPage,
              rightButtonTitle: 'Cancel',
              onRightButtonPress: () => this.props.navigator.pop(),
              passProps: {
                text: 'This page has a right button in the nav bar',
              }
            });
          })}
          {this._renderRow('Custom Title Icon', () => {
            this.props.navigator.push({
              titleIcon: require('image!uie_thumb_normal'),
              component: EmptyPage,
              rightButtonTitle: 'Cancel',
              onRightButtonPress: () => this.props.navigator.pop(),
              passProps: {
                text: 'This page has a custom title icon in the nav bar',
              }
            });
          })}
          {this._renderRow('Transparent navigation bar', () => {
            this.props.navigator.push({
              titleIcon: require('image!uie_thumb_normal'),
              component: EmptyPage,
              navigationBarTransparent: true,
              rightButtonTitle: 'Cancel',
              onRightButtonPress: () => this.props.navigator.pop(),
              passProps: {
                text: 'This page has a custom title icon and a transparent navigation bar in the nav bar',
                customStyle: {backgroundColor:"#527FE4"}
              }
            });
          })}
          {this._renderRow('Custom Left & Right Icons', () => {
            this.props.navigator.push({
              title: NavigatorIOSExample.title,
              component: EmptyPage,
              leftButtonTitle: 'Custom Left',
              onLeftButtonPress: () => this.props.navigator.pop(),
              rightButtonIcon: require('image!NavBarButtonPlus'),
              onRightButtonPress: () => {
                AlertIOS.alert(
                  'Bar Button Action',
                  'Recognized a tap on the bar button icon',
                  [
                    {
                      text: 'OK',
                      onPress: () => console.log('Tapped OK'),
                    },
                  ]
                );
              },
              passProps: {
                text: 'This page has an icon for the right button in the nav bar',
              }
            });
          })}
          {this._renderRow('Pop', () => {
            this.props.navigator.pop();
          })}
          {this._renderRow('Pop to top', () => {
            this.props.navigator.popToTop();
          })}
          {this._renderRow('Replace here', () => {
            var prevRoute = this.props.route;
            this.props.navigator.replace({
              title: 'New Navigation',
              component: EmptyPage,
              rightButtonTitle: 'Undo',
              onRightButtonPress: () => this.props.navigator.replace(prevRoute),
              passProps: {
                text: 'The component is replaced, but there is currently no ' +
                  'way to change the right button or title of the current route',
              }
            });
          })}
          {this._renderReplacePrevious()}
          {this._renderReplacePreviousAndPop()}
          {this._renderPopToTopNavExample()}
        </View>
        <View style={styles.line}/>
      </ScrollView>
    );
  },

  _renderPopToTopNavExample: function() {
    if (!this.props.topExampleRoute) {
      return null;
    }
    return this._renderRow('Pop to top NavigatorIOSExample', () => {
      this.props.navigator.popToRoute(this.props.topExampleRoute);
    });
  },

  _renderReplacePrevious: function() {
    if (!this.props.topExampleRoute) {
      // this is to avoid replacing the UIExplorerList at the top of the stack
      return null;
    }
    return this._renderRow('Replace previous', () => {
      this.props.navigator.replacePrevious({
        title: 'Replaced',
        component: EmptyPage,
        passProps: {
          text: 'This is a replaced "previous" page',
        },
        wrapperStyle: styles.customWrapperStyle,
      });
    });
  },

  _renderReplacePreviousAndPop: function() {
    if (!this.props.topExampleRoute) {
      // this is to avoid replacing the UIExplorerList at the top of the stack
      return null;
    }
    return this._renderRow('Replace previous and pop', () => {
      this.props.navigator.replacePreviousAndPop({
        title: 'Replaced and Popped',
        component: EmptyPage,
        passProps: {
          text: 'This is a replaced "previous" page',
        },
        wrapperStyle: styles.customWrapperStyle,
      });
    });
  },

  _renderRow: function(title: string, onPress: Function) {
    return (
      <View>
        <TouchableHighlight onPress={onPress}>
          <View style={styles.row}>
            <Text style={styles.rowText}>
              {title}
            </Text>
          </View>
        </TouchableHighlight>
        <View style={styles.separator} />
      </View>
    );
  },
});

var styles = StyleSheet.create({
  customWrapperStyle: {
    backgroundColor: '#bbdddd',
  },
  emptyPage: {
    flex: 1,
    paddingTop: 64,
  },
  emptyPageText: {
    margin: 10,
  },
  list: {
    backgroundColor: '#eeeeee',
    marginTop: 10,
  },
  group: {
    backgroundColor: 'white',
  },
  groupSpace: {
    height: 15,
  },
  line: {
    backgroundColor: '#bbbbbb',
    height: 1 / PixelRatio.get(),
  },
  row: {
    backgroundColor: 'white',
    justifyContent: 'center',
    paddingHorizontal: 15,
    paddingVertical: 15,
  },
  separator: {
    height: 1 / PixelRatio.get(),
    backgroundColor: '#bbbbbb',
    marginLeft: 15,
  },
  rowNote: {
    fontSize: 17,
  },
  rowText: {
    fontSize: 17,
    fontWeight: '500',
  },
});

module.exports = NavigatorIOSExample;
<commit_msg>Travis FIX<commit_after>/**
 * The examples provided by Facebook are for non-commercial testing and
 * evaluation purposes only.
 *
 * Facebook reserves all rights not expressly granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
 * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @flow
 */
'use strict';

var React = require('react-native');
var ViewExample = require('./ViewExample');
var createExamplePage = require('./createExamplePage');
var {
  AlertIOS,
  PixelRatio,
  ScrollView,
  StyleSheet,
  Text,
  TouchableHighlight,
  View,
} = React;

var EmptyPage = React.createClass({

  render: function() {
    return (
      <View style={[styles.emptyPage, this.props.customStyle]}>
        <Text style={styles.emptyPageText}>
          {this.props.text}
        </Text>
      </View>
    );
  },

});

var NavigatorIOSExample = React.createClass({

  statics: {
    title: '<NavigatorIOS>',
    description: 'iOS navigation capabilities',
  },
  counter: 10,
  render: function() {
    var recurseTitle = 'Recurse Navigation';
    if (!this.props.topExampleRoute) {
      recurseTitle += ' - more examples here';
    }
    return (
      <ScrollView style={styles.list}>
        <View style={styles.line}/>
        <View style={styles.group}>
          <View style={styles.row}>
            <Text style={styles.rowNote}>
              See <UIExplorerApp> for top-level usage.
            </Text>
          </View>
        </View>
        <View style={styles.line}/>
        <View style={styles.groupSpace}/>
        <View style={styles.line}/>
        <View style={styles.group}>
          {this._renderRow(recurseTitle, () => {
            this.props.navigator.push({
              title: NavigatorIOSExample.title,
              component: NavigatorIOSExample,
              backButtonTitle: 'Custom Back',
              passProps: {topExampleRoute: this.props.topExampleRoute || this.props.route},
            });
          })}
          {this._renderRow('Push View Example', () => {
            this.props.navigator.push({
              title: 'Very Long Custom View Example Title',
              component: createExamplePage(null, ViewExample),
            });
          })}
          {this._renderRow('Change rightButtonTitle', () => {
            this.props.navigator.updateNavBar({rightButtonTitle:(this.counter++) + "",onRightButtonPress:()=>{
              this.counter = 10;
              this.props.navigator.updateNavBar({rightButtonTitle:null});
            }});
          })}
          {this._renderRow('Custom Right Button', () => {
            this.props.navigator.push({
              title: NavigatorIOSExample.title,
              component: EmptyPage,
              rightButtonTitle: 'Cancel',
              onRightButtonPress: () => this.props.navigator.pop(),
              passProps: {
                text: 'This page has a right button in the nav bar',
              }
            });
          })}
          {this._renderRow('Custom Title Icon', () => {
            this.props.navigator.push({
              titleIcon: require('image!uie_thumb_normal'),
              component: EmptyPage,
              rightButtonTitle: 'Cancel',
              onRightButtonPress: () => this.props.navigator.pop(),
              passProps: {
                text: 'This page has a custom title icon in the nav bar',
              }
            });
          })}
          {this._renderRow('Transparent navigation bar', () => {
            this.props.navigator.push({
              titleIcon: require('image!uie_thumb_normal'),
              component: EmptyPage,
              navigationBarTransparent: true,
              rightButtonTitle: 'Cancel',
              onRightButtonPress: () => this.props.navigator.pop(),
              passProps: {
                text: 'This page has a custom title icon and a transparent navigation bar in the nav bar',
                customStyle: {backgroundColor:"#527FE4"}
              }
            });
          })}
          {this._renderRow('Custom Left & Right Icons', () => {
            this.props.navigator.push({
              title: NavigatorIOSExample.title,
              component: EmptyPage,
              leftButtonTitle: 'Custom Left',
              onLeftButtonPress: () => this.props.navigator.pop(),
              rightButtonIcon: require('image!NavBarButtonPlus'),
              onRightButtonPress: () => {
                AlertIOS.alert(
                  'Bar Button Action',
                  'Recognized a tap on the bar button icon',
                  [
                    {
                      text: 'OK',
                      onPress: () => console.log('Tapped OK'),
                    },
                  ]
                );
              },
              passProps: {
                text: 'This page has an icon for the right button in the nav bar',
              }
            });
          })}
          {this._renderRow('Pop', () => {
            this.props.navigator.pop();
          })}
          {this._renderRow('Pop to top', () => {
            this.props.navigator.popToTop();
          })}
          {this._renderRow('Replace here', () => {
            var prevRoute = this.props.route;
            this.props.navigator.replace({
              title: 'New Navigation',
              component: EmptyPage,
              rightButtonTitle: 'Undo',
              onRightButtonPress: () => this.props.navigator.replace(prevRoute),
              passProps: {
                text: 'The component is replaced, but there is currently no ' +
                  'way to change the right button or title of the current route',
              }
            });
          })}
          {this._renderReplacePrevious()}
          {this._renderReplacePreviousAndPop()}
          {this._renderPopToTopNavExample()}
        </View>
        <View style={styles.line}/>
      </ScrollView>
    );
  },

  _renderPopToTopNavExample: function() {
    if (!this.props.topExampleRoute) {
      return null;
    }
    return this._renderRow('Pop to top NavigatorIOSExample', () => {
      this.props.navigator.popToRoute(this.props.topExampleRoute);
    });
  },

  _renderReplacePrevious: function() {
    if (!this.props.topExampleRoute) {
      // this is to avoid replacing the UIExplorerList at the top of the stack
      return null;
    }
    return this._renderRow('Replace previous', () => {
      this.props.navigator.replacePrevious({
        title: 'Replaced',
        component: EmptyPage,
        passProps: {
          text: 'This is a replaced "previous" page',
        },
        wrapperStyle: styles.customWrapperStyle,
      });
    });
  },

  _renderReplacePreviousAndPop: function() {
    if (!this.props.topExampleRoute) {
      // this is to avoid replacing the UIExplorerList at the top of the stack
      return null;
    }
    return this._renderRow('Replace previous and pop', () => {
      this.props.navigator.replacePreviousAndPop({
        title: 'Replaced and Popped',
        component: EmptyPage,
        passProps: {
          text: 'This is a replaced "previous" page',
        },
        wrapperStyle: styles.customWrapperStyle,
      });
    });
  },

  _renderRow: function(title: string, onPress: Function) {
    return (
      <View>
        <TouchableHighlight onPress={onPress}>
          <View style={styles.row}>
            <Text style={styles.rowText}>
              {title}
            </Text>
          </View>
        </TouchableHighlight>
        <View style={styles.separator} />
      </View>
    );
  },
});

var styles = StyleSheet.create({
  customWrapperStyle: {
    backgroundColor: '#bbdddd',
  },
  emptyPage: {
    flex: 1,
    paddingTop: 64,
  },
  emptyPageText: {
    margin: 10,
  },
  list: {
    backgroundColor: '#eeeeee',
    marginTop: 10,
  },
  group: {
    backgroundColor: 'white',
  },
  groupSpace: {
    height: 15,
  },
  line: {
    backgroundColor: '#bbbbbb',
    height: 1 / PixelRatio.get(),
  },
  row: {
    backgroundColor: 'white',
    justifyContent: 'center',
    paddingHorizontal: 15,
    paddingVertical: 15,
  },
  separator: {
    height: 1 / PixelRatio.get(),
    backgroundColor: '#bbbbbb',
    marginLeft: 15,
  },
  rowNote: {
    fontSize: 17,
  },
  rowText: {
    fontSize: 17,
    fontWeight: '500',
  },
});

module.exports = NavigatorIOSExample;
<|endoftext|>


<commit_before>import React from 'react'
import {compose} from 'recompose'
import {connect} from 'react-redux'
import {push} from 'react-router-redux'
import {reduxForm, Field, SubmissionError, getFormValues} from 'redux-form'
import {RaisedButton, MenuItem} from 'material-ui'
import {
  TextField,
  Toggle,
  SelectField,
} from 'redux-form-material-ui'
import {omit, isEmpty, map, get, reject, pickBy, forEach} from 'lodash'
import {graphql, gql} from 'react-apollo'
import {humanize} from 'inflection'
import DropzoneS3Uploader from 'react-dropzone-s3-uploader'
import {showNotification} from '../actions'
import upsertPage from '../graphql/upsertPage.gql'
import siteQuery from '../graphql/site.gql'
import {t} from '../common/utils'
import common from '../common.scss'

const required = value => isEmpty(value) && 'Cannot be blank'

class PageEditorGeneral extends React.Component {
  constructor(p) {
    super(p)
    this.state = {}
  }

  onSubmit(data) {
    const page = omit(data, '__typename', 'sections')
    const newPage = !data.id
    return this.props.mutate({variables: {page, locale: this.props.locale}})
      .then(({data}) => {
        this.props.showNotification("Page saved")
        if (newPage) {
          this.props.push(`/site/page/${data.upsertPage.id}`)
        }
      })
      .catch((error) => {
        throw new SubmissionError(error.graphQLErrors[0].errors)
      })
  }

  get properties() {
    return get(this.props.siteData, ['site', 'layouts', this.props.page.layout, 'properties'], [])
  }

  render() {
    if (this.props.data.loading || this.props.siteData.loading) {
      return null
    }
    const {handleSubmit, pristine, submitting, locale, data: {pages}, siteData: {site}} = this.props
    const layouts = site.layouts
    const validParents = reject(pages, parent => parent.id === get(this.props.page, 'id'))
    return (
      <form onSubmit={handleSubmit((data) => this.onSubmit(data))}>
        <Field name="title" component={TextField} hintText="Page title" floatingLabelText="Title" validate={required} floatingLabelFixed
          fullWidth className={common.formControl} />
        <Field name="linkText" component={TextField} hintText="How page appears in the menus" floatingLabelText="Link text"
          fullWidth floatingLabelFixed className={common.formControl} />
        <Field name="slug" component={TextField} hintText="Slug is used for the URL" floatingLabelText="Slug"
          fullWidth floatingLabelFixed className={common.formControl} />
        <Field name="description" component={TextField} hintText="SEO description" floatingLabelText="Paragraph about your page"
          fullWidth multiLine={true} rows={2} rowsMax={2} floatingLabelFixed className={common.formControl} />
        <Field name="keywords" component={TextField} hintText="SEO keywords" floatingLabelText="Keywords to be added to the global ones"
          fullWidth multiLine={true} rows={2} rowsMax={2} floatingLabelFixed className={common.formControl} />
        <Field
          name="layout"
          component={SelectField}
          hintText="Page base layout"
          floatingLabelText="Layout"
          validate={required}
          className={common.formControl}
          fullWidth
        >
          {map(layouts, ({name}, key) => <MenuItem value={key} primaryText={name} key={key} />)}
        </Field>
        <Field
          name="parent"
          component={SelectField}
          hintText="Parent page"
          floatingLabelText="Parent page"
          className={common.formControl}
          fullWidth
        >
          <MenuItem value={null} primaryText={Root} />
          {map(validParents, ({title, id}) => <MenuItem value={id} primaryText={t(title, locale)} key={id} />)}
        </Field>
        <Field name="published" component={Toggle} label="Published" />
        {map(this.properties, prop => this.renderPropetyField(prop))}

          <RaisedButton label="Save" primary={true} disabled={pristine || submitting} type="submit" />

      </form>)
  }

  renderPropetyField(prop) {
    const {key} = prop
    if (prop.type === 'text') {
      return (
        <Field
          name={`properties.${key}`}
          key={key}
          component={TextField}
          floatingLabelText={humanize(key)}
          fullWidth floatingLabelFixed
          multiLine
          rows={2}
          className={common.formControl}
        />
      )
    } else if (prop.type === 'boolean') {
      return <Field key={key} name={`properties.${key}`} component={Toggle} label={humanize(key)} />
    } else if (prop.type === 'image') {
      const val = get(this.props.formValues, ['properties', key])
      return (

        {humanize(key)}
        <DropzoneS3Uploader
          onFinish={params => {
            this.props.change(`properties.${key}`, `https://${process.env.REACT_APP_S3_BUCKET}.s3.amazonaws.com/${params.fileKey}`)
          }}
          s3Url={`https://${process.env.REACT_APP_S3_BUCKET}.s3.amazonaws.com`}
          maxSize={1024 * 1024 * 5}
          upload={{
            signingUrl: '/admin/api/s3/sign',
            signingUrlWithCredentials: true,
          }}
          passChildrenProps={false}
        >
          {!isEmpty(val) &&

          }
          {isEmpty(val) &&

Drop an image here

          }
        </DropzoneS3Uploader>
        {!isEmpty(val) &&  this.props.change(`properties.${key}`, '')}
        />}

)
    } else if (prop.type === 'file') {
      const val = get(this.props.formValues, ['properties', key])
      return (

        {humanize(key)}
        <DropzoneS3Uploader
          onFinish={params => {
            this.props.change(`properties.${key}`, {
              url: params.fileKey,
              name: params.file.name,
              type: params.file.type,
              size: params.file.size,
            })
          }}
          s3Url={`https://${process.env.REACT_APP_S3_BUCKET}.s3.amazonaws.com`}
          maxSize={1024 * 1024 * 50}
          upload={{
            signingUrl: '/admin/api/s3/sign',
            signingUrlWithCredentials: true,
          }}
          passChildrenProps={false}
        >
          {!isEmpty(val) &&
            <a href={`https://${process.env.REACT_APP_S3_BUCKET}.s3.amazonaws.com/${val.url}`} style={{display: 'block', height: '100%', textAlign: 'center', lineHeight: '200px'}}>

          }
          {isEmpty(val) &&

Drop an file here

          }
        </DropzoneS3Uploader>
        {!isEmpty(val) &&  this.props.change(`properties.${key}`, null)}
        />}

)
    } else {
      return (
        <Field
          name={`properties.${key}`}
          key={key}
          component={TextField}
          floatingLabelText={humanize(key)}
          fullWidth floatingLabelFixed
          className={common.formControl}
        />
      )
    }

  }
}

const mapStateToProps = ({app, ...state}, {page, siteData}) => {
  const initialValues = {
    ...page,
    parent: get(page.parent, 'id'),
    title: t(page.title, app.locale),
    linkText: t(page.linkText, app.locale),
    properties: {...page.properties} || {},
  }

  if (page.layout) {
    const localizedProperties = pickBy(siteData.site.layouts[page.layout].properties, 'localized')
    forEach(localizedProperties, (prop, key) => {
      initialValues.properties[key] = t(get(page.properties, key), app.locale)
    })
  }

  return {
    locale: app.locale,
    formValues: {...initialValues, ...getFormValues('page')(state)},
    initialValues
  }
}

const listAllPages = gql`
  query {
    pages {
      id
      title
    }
  }
`

const enhance = compose(
  graphql(siteQuery, {name: 'siteData'}),
  graphql(listAllPages),
  graphql(upsertPage, {
    options: {
      refetchQueries: [
        'pages',
      ],
    }
  }),
  connect(mapStateToProps, {showNotification, push}),
  reduxForm({form: 'page', enableReinitialize: true, keepDirtyOnReinitialize: true}),
)

export default enhance(PageEditorGeneral)
<commit_msg>added html property type<commit_after>import React from 'react'
import {compose} from 'recompose'
import {connect} from 'react-redux'
import {push} from 'react-router-redux'
import {reduxForm, Field, SubmissionError, getFormValues} from 'redux-form'
import {RaisedButton, MenuItem} from 'material-ui'
import {
  TextField,
  Toggle,
  SelectField,
} from 'redux-form-material-ui'
import {omit, isEmpty, map, get, reject, pickBy, forEach} from 'lodash'
import {graphql, gql} from 'react-apollo'
import {humanize} from 'inflection'
import DropzoneS3Uploader from 'react-dropzone-s3-uploader'
import {showNotification} from '../actions'
import upsertPage from '../graphql/upsertPage.gql'
import siteQuery from '../graphql/site.gql'
import {t} from '../common/utils'
import common from '../common.scss'
import {RedactorField as Redactor} from '../redactor'

const required = value => isEmpty(value) && 'Cannot be blank'

class PageEditorGeneral extends React.Component {
  constructor(p) {
    super(p)
    this.state = {}
  }

  onSubmit(data) {
    const page = omit(data, '__typename', 'sections')
    const newPage = !data.id
    return this.props.mutate({variables: {page, locale: this.props.locale}})
      .then(({data}) => {
        this.props.showNotification("Page saved")
        if (newPage) {
          this.props.push(`/site/page/${data.upsertPage.id}`)
        }
      })
      .catch((error) => {
        throw new SubmissionError(error.graphQLErrors[0].errors)
      })
  }

  get properties() {
    return get(this.props.siteData, ['site', 'layouts', this.props.page.layout, 'properties'], [])
  }

  render() {
    if (this.props.data.loading || this.props.siteData.loading) {
      return null
    }
    const {handleSubmit, pristine, submitting, locale, data: {pages}, siteData: {site}} = this.props
    const layouts = site.layouts
    const validParents = reject(pages, parent => parent.id === get(this.props.page, 'id'))
    return (
      <form onSubmit={handleSubmit((data) => this.onSubmit(data))}>
        <Field name="title" component={TextField} hintText="Page title" floatingLabelText="Title" validate={required} floatingLabelFixed
          fullWidth className={common.formControl} />
        <Field name="linkText" component={TextField} hintText="How page appears in the menus" floatingLabelText="Link text"
          fullWidth floatingLabelFixed className={common.formControl} />
        <Field name="slug" component={TextField} hintText="Slug is used for the URL" floatingLabelText="Slug"
          fullWidth floatingLabelFixed className={common.formControl} />
        <Field name="description" component={TextField} hintText="SEO description" floatingLabelText="Paragraph about your page"
          fullWidth multiLine={true} rows={2} rowsMax={2} floatingLabelFixed className={common.formControl} />
        <Field name="keywords" component={TextField} hintText="SEO keywords" floatingLabelText="Keywords to be added to the global ones"
          fullWidth multiLine={true} rows={2} rowsMax={2} floatingLabelFixed className={common.formControl} />
        <Field
          name="layout"
          component={SelectField}
          hintText="Page base layout"
          floatingLabelText="Layout"
          validate={required}
          className={common.formControl}
          fullWidth
        >
          {map(layouts, ({name}, key) => <MenuItem value={key} primaryText={name} key={key} />)}
        </Field>
        <Field
          name="parent"
          component={SelectField}
          hintText="Parent page"
          floatingLabelText="Parent page"
          className={common.formControl}
          fullWidth
        >
          <MenuItem value={null} primaryText={Root} />
          {map(validParents, ({title, id}) => <MenuItem value={id} primaryText={t(title, locale)} key={id} />)}
        </Field>
        <Field name="published" component={Toggle} label="Published" />
        {map(this.properties, prop => this.renderPropetyField(prop))}

          <RaisedButton label="Save" primary={true} disabled={pristine || submitting} type="submit" />

      </form>)
  }

  renderPropetyField(prop) {
    const {key} = prop
    if (prop.type === 'text') {
      return (
        <Field
          name={`properties.${key}`}
          key={key}
          component={TextField}
          floatingLabelText={humanize(key)}
          fullWidth floatingLabelFixed
          multiLine
          rows={2}
          className={common.formControl}
        />
      )
    } else if (prop.type === 'html') {
      return (
        <Field
          name={`properties.${key}`}
          key={key}
          component={Redactor}
          label={humanize(key)}
        />
      )
    } else if (prop.type === 'boolean') {
      return <Field key={key} name={`properties.${key}`} component={Toggle} label={humanize(key)} />
    } else if (prop.type === 'image') {
      const val = get(this.props.formValues, ['properties', key])
      return (

        {humanize(key)}
        <DropzoneS3Uploader
          onFinish={params => {
            this.props.change(`properties.${key}`, `https://${process.env.REACT_APP_S3_BUCKET}.s3.amazonaws.com/${params.fileKey}`)
          }}
          s3Url={`https://${process.env.REACT_APP_S3_BUCKET}.s3.amazonaws.com`}
          maxSize={1024 * 1024 * 5}
          upload={{
            signingUrl: '/admin/api/s3/sign',
            signingUrlWithCredentials: true,
          }}
          passChildrenProps={false}
        >
          {!isEmpty(val) &&

          }
          {isEmpty(val) &&

Drop an image here

          }
        </DropzoneS3Uploader>
        {!isEmpty(val) &&  this.props.change(`properties.${key}`, '')}
        />}

)
    } else if (prop.type === 'file') {
      const val = get(this.props.formValues, ['properties', key])
      return (

        {humanize(key)}
        <DropzoneS3Uploader
          onFinish={params => {
            this.props.change(`properties.${key}`, {
              url: params.fileKey,
              name: params.file.name,
              type: params.file.type,
              size: params.file.size,
            })
          }}
          s3Url={`https://${process.env.REACT_APP_S3_BUCKET}.s3.amazonaws.com`}
          maxSize={1024 * 1024 * 50}
          upload={{
            signingUrl: '/admin/api/s3/sign',
            signingUrlWithCredentials: true,
          }}
          passChildrenProps={false}
        >
          {!isEmpty(val) &&
            <a href={`https://${process.env.REACT_APP_S3_BUCKET}.s3.amazonaws.com/${val.url}`} style={{display: 'block', height: '100%', textAlign: 'center', lineHeight: '200px'}}>

          }
          {isEmpty(val) &&

Drop an file here

          }
        </DropzoneS3Uploader>
        {!isEmpty(val) &&  this.props.change(`properties.${key}`, null)}
        />}

)
    } else {
      return (
        <Field
          name={`properties.${key}`}
          key={key}
          component={TextField}
          floatingLabelText={humanize(key)}
          fullWidth floatingLabelFixed
          className={common.formControl}
        />
      )
    }

  }
}

const mapStateToProps = ({app, ...state}, {page, siteData}) => {
  const initialValues = {
    ...page,
    parent: get(page.parent, 'id'),
    title: t(page.title, app.locale),
    linkText: t(page.linkText, app.locale),
    properties: {...page.properties} || {},
  }

  if (page.layout) {
    const localizedProperties = pickBy(siteData.site.layouts[page.layout].properties, 'localized')
    forEach(localizedProperties, (prop, key) => {
      initialValues.properties[key] = t(get(page.properties, key), app.locale)
    })
  }

  return {
    locale: app.locale,
    formValues: {...initialValues, ...getFormValues('page')(state)},
    initialValues
  }
}

const listAllPages = gql`
  query {
    pages {
      id
      title
    }
  }
`

const enhance = compose(
  graphql(siteQuery, {name: 'siteData'}),
  graphql(listAllPages),
  graphql(upsertPage, {
    options: {
      refetchQueries: [
        'pages',
      ],
    }
  }),
  connect(mapStateToProps, {showNotification, push}),
  reduxForm({form: 'page', enableReinitialize: true, keepDirtyOnReinitialize: true}),
)

export default enhance(PageEditorGeneral)
<|endoftext|>


<commit_before>Model[ARRAY] = function ArrayModel(def){

	var model = function(array) {
		array = defaultTo(model[DEFAULT], array);

		var proxy;
		model[VALIDATE](array);
		if(isProxySupported){
			proxy = new Proxy(array, {
				get: function (arr, key) {
					if(key === CONSTRUCTOR){
						return model;
					} else if(ARRAY_MUTATOR_METHODS.indexOf(key) >= 0){
						return proxifyArrayMethod(arr, key, model);
					}
					return arr[key];
				},
				set: function (arr, key, val) {
					setArrayKey(arr, key, val, model);
				},
				getPrototypeOf: function(){
					return model[PROTO];
				}
			});
		} else {
			proxy = Object.create(Array[PROTO]);
			for(var key in array){
				if(array.hasOwnProperty(key)){
					proxifyArrayKey(proxy, array, key, model);
				}
			}
			defineProperty(proxy, "length", { get: function() { return array.length; } });
			defineProperty(proxy, "toJSON", { value: function() { return array; } });
			ARRAY_MUTATOR_METHODS.forEach(function (method) {
				define(proxy, method, proxifyArrayMethod(array, method, model, proxy));
			});
			setConstructor(proxy, model);
		}

		return proxy;
	};

	setConstructorProto(model, Array[PROTO]);
	initModel(model, def, Model[ARRAY]);
	return model;
};

setConstructorProto(Model[ARRAY], Model[PROTO]);
var ArrayModelProto = Model[ARRAY][PROTO];

ArrayModelProto.toString = function(stack){
	return ARRAY + ' of ' + toString(this[DEFINITION], stack);
};

// private methods
define(ArrayModelProto, VALIDATOR, function(arr, path, callStack, errorStack){
	if(!is(Array, arr)){
		var err = {};
		err[EXPECTED] = this;
		err[RECEIVED] = arr;
		err[PATH] = path;
		errorStack.push(err);
	} else {
		for(var i=0, l=arr.length; i<l; i++){
			checkDefinition(arr[i], this[DEFINITION], (path||ARRAY)+'['+i+']', callStack, errorStack);
		}
	}
	checkAssertions(arr, this);
});

function proxifyArrayKey(proxy, array, key, model){
	defineProperty(proxy, key, {
		enumerable: true,
		get: function () {
			return array[key];
		},
		set: function (val) {
			setArrayKey(array, key, val, model);
		}
	});
}

function proxifyArrayMethod(array, method, model, proxy){
	return function() {
		var testArray = array.slice();
		Array[PROTO][method].apply(testArray, arguments);
		model[VALIDATE](testArray);
		if(!isProxySupported){
			for(var key in testArray){
				if(testArray.hasOwnProperty(key) && !(key in proxy)){
					proxifyArrayKey(proxy, array, key, model);
				}
			}
		}
		return Array[PROTO][method].apply(array, arguments);
	};
}

function setArrayKey(array, key, value, model){
	if(parseInt(key) === +key && key >= 0){
		value = autocast(value, model[DEFINITION]);
		checkDefinition(value, model[DEFINITION], ARRAY+'['+key+']', [], model[ERROR_STACK]);
	}
	var testArray = array.slice();
	testArray[key] = value;
	checkAssertions(testArray, model);
	model[UNSTACK]();
	array[key] = value;
}<commit_msg>add automatic casting on array init and mutator method<commit_after>Model[ARRAY] = function ArrayModel(def){

	var model = function(array) {
		array = defaultTo(model[DEFAULT], array);

		var proxy;
		model[VALIDATE](array);
		if(isProxySupported){
			proxy = new Proxy(array, {
				get: function (arr, key) {
					if(key === CONSTRUCTOR){
						return model;
					} else if(ARRAY_MUTATOR_METHODS.indexOf(key) >= 0){
						return proxifyArrayMethod(arr, key, model);
					}
					return arr[key];
				},
				set: function (arr, key, val) {
					setArrayKey(arr, key, val, model);
				},
				getPrototypeOf: function(){
					return model[PROTO];
				}
			});
		} else {
			proxy = Object.create(Array[PROTO]);
			for(var key in array){
				if(array.hasOwnProperty(key)){
					proxifyArrayKey(proxy, array, key, model);
				}
			}
			defineProperty(proxy, "length", { get: function() { return array.length; } });
			defineProperty(proxy, "toJSON", { value: function() { return array; } });
			ARRAY_MUTATOR_METHODS.forEach(function (method) {
				define(proxy, method, proxifyArrayMethod(array, method, model, proxy));
			});
			setConstructor(proxy, model);
		}

		return proxy;
	};

	setConstructorProto(model, Array[PROTO]);
	initModel(model, def, Model[ARRAY]);
	return model;
};

setConstructorProto(Model[ARRAY], Model[PROTO]);
var ArrayModelProto = Model[ARRAY][PROTO];

ArrayModelProto.toString = function(stack){
	return ARRAY + ' of ' + toString(this[DEFINITION], stack);
};

// private methods
define(ArrayModelProto, VALIDATOR, function(arr, path, callStack, errorStack){
	if(!is(Array, arr)){
		var err = {};
		err[EXPECTED] = this;
		err[RECEIVED] = arr;
		err[PATH] = path;
		errorStack.push(err);
	} else {
		for(var i=0, l=arr.length; i<l; i++){
			arr[i] = autocast(arr[i], this[DEFINITION]);
			checkDefinition(arr[i], this[DEFINITION], (path||ARRAY)+'['+i+']', callStack, errorStack);
		}
	}
	checkAssertions(arr, this);
});

function proxifyArrayKey(proxy, array, key, model){
	defineProperty(proxy, key, {
		enumerable: true,
		get: function () {
			return array[key];
		},
		set: function (val) {
			setArrayKey(array, key, val, model);
		}
	});
}

function proxifyArrayMethod(array, method, model, proxy){
	return function() {
		var testArray = array.slice();
		Array[PROTO][method].apply(testArray, arguments);
		model[VALIDATE](testArray);
		if(!isProxySupported){
			for(var key in testArray){
				if(testArray.hasOwnProperty(key) && !(key in proxy)){
					proxifyArrayKey(proxy, array, key, model);
				}
			}
		}

		var returnValue = Array[PROTO][method].apply(array, arguments);
		for(var i=0, l=array.length; i<l; i++) {
			array[i] = autocast(array[i], model[DEFINITION]);
		}
		return returnValue;
	};
}

function setArrayKey(array, key, value, model){
	if(parseInt(key) === +key && key >= 0){
		value = autocast(value, model[DEFINITION]);
		checkDefinition(value, model[DEFINITION], ARRAY+'['+key+']', [], model[ERROR_STACK]);
	}
	var testArray = array.slice();
	testArray[key] = value;
	checkAssertions(testArray, model);
	model[UNSTACK]();
	array[key] = value;
}<|endoftext|>


<commit_before>import {extendModel, initModel, Model, stackError, unstackErrors} from "./model"
import {cast, checkAssertions, checkDefinition, extendDefinition, formatDefinition} from "./definition"
import {_validate, extend, isArray, isFunction, proxifyFn, proxifyModel, setConstructor} from "./helpers"

const ARRAY_MUTATORS = ["pop", "push", "reverse", "shift", "sort", "splice", "unshift"]

export default function ArrayModel(def) {

	const model = function (array = model.default) {
		if (!model.validate(array)) return
		return proxifyModel(array, model, {
			get(arr, key) {
				let val = arr[key];
				if (!isFunction(val)) return val

				return proxifyFn(val, (fn, ctx, args) => {
					if (ARRAY_MUTATORS.includes(key)) {
						const testArray = arr.slice()
						fn.apply(testArray, args)
						model.validate(testArray)
					}

					const returnValue = fn.apply(arr, args)
					array.forEach((a, i) => arr[i] = cast(a, model.definition))
					return returnValue
				})
			},

			set(arr, key, val) {
				return setArrayKey(arr, key, val, model)
			},

			deleteProperty(arr, key){
				return !(key in arr) || setArrayKey(arr, key, undefined, model)
			}
		})
	}

	extend(model, Array)
	setConstructor(model, ArrayModel)
	initModel(model, def)
	return model
}

extend(ArrayModel, Model, {
	toString(stack){
		return 'Array of ' + formatDefinition(this.definition, stack)
	},

	[_validate](arr, path, errors, stack){
		if (isArray(arr))
			arr.forEach((a, i) => {
				arr[i] = checkDefinition(a, this.definition, `${path || "Array"}[${i}]`, errors, stack, true)
			})
		else stackError(errors, this, arr, path)

		checkAssertions(arr, this, path, errors)
	},

	extend(...newParts){
		return extendModel(new ArrayModel(extendDefinition(this.definition, newParts)), this)
	}
})

function setArrayKey(array, key, value, model) {
	let path = `Array[${key}]`;
	if (parseInt(key) === +key && key >= 0)
		value = checkDefinition(value, model.definition, path, model.errors, [], true)

	const testArray = array.slice()
	testArray[key] = value
	checkAssertions(testArray, model, path)
	const isSuccess = !unstackErrors(model)
	if (isSuccess) array[key] = value
	return isSuccess
}<commit_msg>optimized array models proxyfied mutators<commit_after>import {extendModel, initModel, Model, stackError, unstackErrors} from "./model"
import {cast, checkAssertions, checkDefinition, extendDefinition, formatDefinition} from "./definition"
import {_validate, extend, isArray, proxifyFn, proxifyModel, setConstructor} from "./helpers"

const ARRAY_MUTATORS = ["pop", "push", "reverse", "shift", "sort", "splice", "unshift"];

export default function ArrayModel(def) {

	const model = function (array = model.default) {
		if (!model.validate(array)) return

		const mutators = {}
		for(let method of ARRAY_MUTATORS) {
			mutators[method] = proxifyFn([][method], (fn, ctx, args) => {
				const testArray = array.slice()
				fn.apply(testArray, args)
				model.validate(testArray)

				const returnValue = fn.apply(array, args)
				array.forEach((a, i) => array[i] = cast(a, model.definition))
				return returnValue
			})
		}

		return proxifyModel(array, model, {
			get(arr, key) {
				return key in mutators ? mutators[key] : arr[key]
			},

			set(arr, key, val) {
				return setArrayKey(arr, key, val, model)
			},

			deleteProperty(arr, key){
				return !(key in arr) || setArrayKey(arr, key, undefined, model)
			}
		})
	}

	extend(model, Array)
	setConstructor(model, ArrayModel)
	initModel(model, def)
	return model
}

extend(ArrayModel, Model, {
	toString(stack){
		return 'Array of ' + formatDefinition(this.definition, stack)
	},

	[_validate](arr, path, errors, stack){
		if (isArray(arr))
			arr.forEach((a, i) => {
				arr[i] = checkDefinition(a, this.definition, `${path || "Array"}[${i}]`, errors, stack, true)
			})
		else stackError(errors, this, arr, path)

		checkAssertions(arr, this, path, errors)
	},

	extend(...newParts){
		return extendModel(new ArrayModel(extendDefinition(this.definition, newParts)), this)
	}
})

function setArrayKey(array, key, value, model) {
	let path = `Array[${key}]`;
	if (parseInt(key) === +key && key >= 0)
		value = checkDefinition(value, model.definition, path, model.errors, [], true)

	const testArray = array.slice()
	testArray[key] = value
	checkAssertions(testArray, model, path)
	const isSuccess = !unstackErrors(model)
	if (isSuccess) array[key] = value
	return isSuccess
}<|endoftext|>


<commit_before>import expect from 'expect';
import Incarnate from './Incarnate';

const MOCK_INSTANCE = {};
const MOCK_DEPENDENCY = {};
const MOCK_DEPENDENCY_DEPENDENCY = {};

module.exports = {
  'Incarnate': {
    'should be a function': () => {
      expect(Incarnate).toBeA(Function);
    },
    'should resolve a path': () => {
      const instance = Incarnate('mock', {
        'mock': {
          args: [],
          factory: () => {
            return MOCK_INSTANCE;
          }
        }
      }, {});

      expect(instance).toEqual(MOCK_INSTANCE);
    },
    'should resolve an injected dependency': () => {
      const instance = Incarnate('mock', {
        'mock-dep': {
          args: [],
          factory: () => {
            return MOCK_DEPENDENCY;
          }
        },
        'mock': {
          args: [
            'mock-dep'
          ],
          factory: (mockDep) => {
            return mockDep;
          }
        }
      }, {});

      expect(instance).toEqual(MOCK_DEPENDENCY);
    },
    'should resolve injected dependencies recursively': () => {
      const instance = Incarnate('mock', {
        'mock-dep-dep': {
          args: [],
          factory: () => {
            return MOCK_DEPENDENCY_DEPENDENCY;
          }
        },
        'mock-dep': {
          args: [
            'mock-dep-dep'
          ],
          factory: (mockDepDep) => {
            return mockDepDep;
          }
        },
        'mock': {
          args: [
            'mock-dep'
          ],
          factory: (mockDep) => {
            return mockDep;
          }
        }
      }, {});

      expect(instance).toEqual(MOCK_DEPENDENCY_DEPENDENCY);
    }
  }
};
<commit_msg>test(Incarnate) Improve DI resolution test be using toBe for exact equality (===).<commit_after>import expect from 'expect';
import Incarnate from './Incarnate';

const MOCK_INSTANCE = {};
const MOCK_DEPENDENCY = {};
const MOCK_DEPENDENCY_DEPENDENCY = {};

module.exports = {
  'Incarnate': {
    'should be a function': () => {
      expect(Incarnate).toBeA(Function);
    },
    'should resolve a path': () => {
      const instance = Incarnate('mock', {
        'mock': {
          args: [],
          factory: () => {
            return MOCK_INSTANCE;
          }
        }
      }, {});

      expect(instance).toBe(MOCK_INSTANCE);
    },
    'should resolve an injected dependency': () => {
      const instance = Incarnate('mock', {
        'mock-dep': {
          args: [],
          factory: () => {
            return MOCK_DEPENDENCY;
          }
        },
        'mock': {
          args: [
            'mock-dep'
          ],
          factory: (mockDep) => {
            return mockDep;
          }
        }
      }, {});

      expect(instance).toBe(MOCK_DEPENDENCY);
    },
    'should resolve injected dependencies recursively': () => {
      const instance = Incarnate('mock', {
        'mock-dep-dep': {
          args: [],
          factory: () => {
            return MOCK_DEPENDENCY_DEPENDENCY;
          }
        },
        'mock-dep': {
          args: [
            'mock-dep-dep'
          ],
          factory: (mockDepDep) => {
            return mockDepDep;
          }
        },
        'mock': {
          args: [
            'mock-dep'
          ],
          factory: (mockDep) => {
            return mockDep;
          }
        }
      }, {});

      expect(instance).toBe(MOCK_DEPENDENCY_DEPENDENCY);
    }
  }
};
<|endoftext|>


<commit_before>let answer = document.getElementById('answer');
let attempt = document.getElementById('attempt');
let messageLabel = document.getElementById('message');

function guess() {
    let input = document.getElementById('user-guess');
    //add functionality to guess function here
    if (answer.value == '' || attempt.value == ''){
      setHiddenFields();
    }

      if(!validateInput(input.value))
      {
        return;
      }
      attempt.value++;

}

function setHiddenFields () {
    attempt.value = "0"
    answer.value = Math.floor(Math.random() * 10000).toString() ;

    while(answer.value.length < 4)
    {
      answer.value = "0" + answer.value;
    }
}

function setMessage(message){

    messageLabel.innerHTML = message;

}

function validateInput(input){

    if(input.length == 4){
          return true;
    }
    else{

      setMessage("Guesses must be exactly 4 characters long.");
      return false;
    }

}

function getResults(input){
  let html = '
' + input + '
';

  for(i = 0; i< input.length; i++)
  {
    if(input.charAt(i) == answer.value.charAt(i) )
    {
      html += '';
    }
    else if(answer.value.indexOf(input.charAt(i) > -1))
    {
      html += '';
    }
    else
      {
        html += '';
      }
    }
    html += '

'
    document.getElementById('results').innerHTML += html;
    else false;
  }
<commit_msg>return instead of else<commit_after>let answer = document.getElementById('answer');
let attempt = document.getElementById('attempt');
let messageLabel = document.getElementById('message');

function guess() {
    let input = document.getElementById('user-guess');
    //add functionality to guess function here
    if (answer.value == '' || attempt.value == ''){
      setHiddenFields();
    }

      if(!validateInput(input.value))
      {
        return;
      }
      attempt.value++;

}

function setHiddenFields () {
    attempt.value = "0"
    answer.value = Math.floor(Math.random() * 10000).toString() ;

    while(answer.value.length < 4)
    {
      answer.value = "0" + answer.value;
    }
}

function setMessage(message){

    messageLabel.innerHTML = message;

}

function validateInput(input){

    if(input.length == 4){
          return true;
    }
    else{

      setMessage("Guesses must be exactly 4 characters long.");
      return false;
    }

}

function getResults(input){
  let html = '
' + input + '
';

  for(i = 0; i< input.length; i++)
  {
    if(input.charAt(i) == answer.value.charAt(i) )
    {
      html += '';
    }
    else if(answer.value.indexOf(input.charAt(i) > -1))
    {
      html += '';
    }
    else
      {
        html += '';
      }
    }
    html += '

'
    document.getElementById('results').innerHTML += html;

    if(input == answer.value)
    {
      return true;
    }
    return false;
  }
<|endoftext|>