<commit_before>var HealthChecker = (function(){
    var storeLifetime = 5 * 60 * 1000; //1 minute
    var serverStatusInterval = 20000; //every 20 seconds
    var store = {};
    var healthChecking = true;

    var clockOffset = 0;

    var addMeasureFunc = function(category,success,duration){
        if (!(category in store)){
            store[category] = timedQueue(storeLifetime);
        }
        var catStore = store[category];
        catStore.enqueue({
            instant:new Date().getTime(),
            duration:duration,
            success:success
        });
        updateGraph();
    };
    var setLatencyIndeterminate = function(isIndeterminate){
        $("#healthStatus")
            .attr("low",isIndeterminate? 11 : 4)
            .attr("high",isIndeterminate? 12 : 8)
            .attr("optimum",isIndeterminate? 13 : 10)
    };
    var check = function(){
        var clientStart = new Date().getTime();
        var reportableHealthObj = describeHealthFunction();
        var url = "/reportLatency";
        if ("latency" in reportableHealthObj){
            var reportableHealth = reportableHealthObj.latency;
            url = sprintf("%s?minLatency=%s&maxLatency=%s&meanLatency=%s&sampleCount=%s",url,reportableHealth.min,reportableHealth.max,reportableHealth.average,reportableHealth.count)
        }
        setLatencyIndeterminate(true);
        $.ajax(url,{
            method:"GET",
            success:function(response){
                if( response.includes("<html") ) {
                    // Redirect to the url if it returned HTML instead of the latency, as it's likely to be the auth page.
                    window.location.href = url;
                }
                else {
                    setLatencyIndeterminate(false);
                    var nowTime = new Date();
                    var timeObj = JSON.parse(response);
                    var time = timeObj.serverWorkTime;
                    var serverWorkTime = parseInt(time);
                    var totalTime = new Date().getTime() - clientStart;
                    var latency = (totalTime - serverWorkTime) / 2;

                    var serverSideTime = timeObj.serverTime;
                    clockOffset = nowTime.getTime() - (serverSideTime + latency);
                    addMeasureFunc("serverResponse",true,serverWorkTime);
                    addMeasureFunc("latency",true,latency);
                    _.delay(check,serverStatusInterval);
                }
            },
            dataType:"text",
            error:function(){
                setLatencyIndeterminate(true);
                addMeasureFunc("latency",false,(new Date().getTime() - clientStart) / 2);
                _.delay(check,serverStatusInterval);
            }
        });
    };
    var updateGraph = _.throttle(function(){
        var checkData = getAggregatedMeasuresFunc(1000);
        var describedData = describeHealthFunction();
        HealthCheckViewer.refreshDisplays(checkData,describedData);
    },1000);
    var resumeHealthCheckFunc = function(immediate){
        healthChecking = true;
        if (immediate){
            check();
        } else {
            _.delay(check,serverStatusInterval);
        }
    };
    var pauseHealthCheckFunc = function(){
        healthChecking = false;
    };
    var getMeasuresFunc = function(){
        return _.mapValues(store,function(v){return v.items();});
    };
    var getAggregatedMeasuresFunc = function(granularity){
        return _.mapValues(store,function(v){
            var set = {};
            _.forEach(v.items(),function(item){
                var sample = (Math.floor(item.instant / granularity) * granularity);
                var oldValue = set[sample];
                var obj = oldValue ? oldValue : {
                    count:0,
                    avg:undefined,
                    successCount:0,
                    min:undefined,
                    max:undefined,
                    instant:sample
                };
                obj.count += 1;
                if (item.success){
                    obj.successCount += 1;
                }
                if (obj.min == undefined || obj.min > item.duration){
                    obj.min = item.duration;
                }
                if (obj.max == undefined || obj.max < item.duration){
                    obj.max = item.duration;
                }
                if (obj.avg == undefined){
                    obj.avg = item.duration;
                } else {
                    obj.avg = ((item.duration - obj.avg) / obj.count) + obj.avg;
                }
                set[sample] = obj;
            });
            return _.values(set);
        });
    };
    var describeHealthFunction = function(){
        return _.mapValues(store,function(catStore,k){
            var v = catStore.items();
            var count = v.length;
            var durations = _.map(v,"duration");
            if (count > 0){
                return {
                    name:k,
                    count:count,
                    max:_.max(durations),
                    min:_.min(durations),
                    average:_.mean(durations),
                    recent:_.mean(_.takeRight(durations,10)),
                    successful:count == 0 || v[count-1].success,
                    successRate:_.countBy(v,"success")[true] / count
                };
            }
        });
    };
    $(function(){
        resumeHealthCheckFunc(true);
    });
    return {
        getTimeOffset:function(){
            return clockOffset;
        },
        getServerTime:function(){
            return new Date(new Date().getTime() + clockOffset);
        },
        check:check,
        resumeHealthCheck:resumeHealthCheckFunc,
        pauseHealthCheck:pauseHealthCheckFunc,
        addMeasure:addMeasureFunc,
        getMeasures:getMeasuresFunc,
        getAggregatedMeasures:getAggregatedMeasuresFunc,
        describeHealth:describeHealthFunction
    }
})();

var augmentArguments = function(args){
    args[_.size(args)] = new Date().getTime();
    return args;
};

var serverResponse = function(responseObj){
    HealthChecker.addMeasure(responseObj.command,responseObj.success,responseObj.duration);
    if ("instant" in responseObj){
        var startTime = responseObj.instant;
        var totalTime = new Date().getTime() - startTime;
        var latency = (totalTime - responseObj.duration) / 2;
        HealthChecker.addMeasure("latency",responseObj.success,latency);
    }
    if ("success" in responseObj && responseObj.success == false){
        console.log(responseObj);
        errorAlert(sprintf("error in %s",responseObj.command),responseObj.response || "Error encountered");
    }
};

var HealthCheckViewer = (function(){
    var viewing = false;
    var healthCheckContainer = {};
    $("#healthCheckListing");
    var healthCheckItemTemplate = {};
    var charts = {};
    var min = 0;
    var max = 13;
    var high = 8;
    var low = 4;
    var healthy = false;
    $(function(){
        healthCheckContainer = $("#healthCheckListing");
        healthCheckItemTemplate = healthCheckContainer.find(".healthCheckItem").clone();
        healthCheckContainer.empty();
    });
    var pauseFunc = function(){
        viewing = false;
    };
    // data extractors
    var errorDataFunc = function(samples){
        return _.filter(_.map(samples,function(d){
            return {
                x:d.instant,
                y:d.count - d.successCount
            };
        }),function(d){return d.y > 0;});
    };
    var averageDataFunc = function(samples){
        return _.map(samples,function(d){
            return {
                x:d.instant,
                y:d.avg //- d.min
            };
        });
    };
    var minDataFunc = function(samples){
        return _.map(samples,function(d){
            return {
                x:d.instant,
                y:d.min
            };
        });
    };
    var maxDataFunc = function(samples){
        return _.map(samples,function(d){
            return {
                x:d.instant,
                y:d.max //- d.avg
            };
        });
    };

    var adjustTimeFunc = function(samples){
        var now = new Date().getTime();
        return _.map(samples,function(d){
            d.instant = (d.instant - now) / 1000;
            return d;
        });
    };

    var generateGraphFromCategory = function(categoryName,rawCategory){
        if (!(categoryName in charts)){
            var category = adjustTimeFunc(rawCategory);
            var rootElem = healthCheckItemTemplate.clone();
            var canvas = $("<canvas />").addClass("healthCheckCanvas").css({"margin-top":"-20px"});
            rootElem.html(canvas);
            healthCheckContainer.append(rootElem);
            var options = {
                title: {
                    display: true,
                    text: categoryName,
                    padding:20
                },
                legend:{
                    display:false
                },
                scales: {
                    yAxes: [
                        {
                            id:"durationAxis",
                            scaleLabel:{
                                display:true,
                                labelString:"time taken (ms)"
                            },
                            type: "linear",
                            stacked: false,
                            display:true,
                            position:"left",
                            ticks: {
                            }
                        },
                        {
                            id:"errorAxis",
                            scaleLabel:{
                                display:true,
                                labelString:"errors"
                            },
                            type: "linear",
                            stacked: true,
                            display:true,
                            position:"right",
                            ticks: {
                                beginAtZero:true,
                                min:0,
                                stepSize:1
                            }
                        }
                    ],
                    xAxes: [{
                        type: "linear",
                        position: "bottom",
                        scaleLabel:{
                            display:true,
                            labelString:"time (seconds)"
                        },
                        ticks: {
                            beginAtZero:true
                        }
                    }]
                },
                hover:{
                    mode:"x-axis"
                },
                elements:{
                    line: {
                        fill: false
                    },
                    bar: {
                        fill:true
                    }
                }
            };
            var data = {
                labels: _.map(category,"instant"),
                datasets:[
                    {
                        type:"line",
                        label:"error count",
                        data:errorDataFunc(category),
                        fill:true,
                        borderColor:"rgba(0,0,0,0.5)",
                        backgroundColor:"rgba(255,0,0,0.3)",
                        borderWidth:1,
                        pointRadius:0,
                        pointHoverRadius:3,
                        pointHitRadius:5,
                        lineTension:0,
                        stepped:true,
                        yAxisID: "errorAxis"
                    },
                    {
                        label:"min",
                        type:"line",
                        data:minDataFunc(category),
                        fill:true,
                        pointRadius:0,
                        pointHoverRadius:3,
                        pointHitRadius:5,
                        borderColor:"rgba(155,197,61,1)",
                        backgroundColor:"rgba(155,197,61,0.3)",
                        borderWidth:1,
                        lineTension:0.1,
                        yAxisID: "durationAxis"
                    },
                    {
                        label:"avg",
                        type:"line",
                        data:averageDataFunc(category),
                        fill:true,
                        pointRadius:0,
                        pointHoverRadius:3,
                        pointHitRadius:5,
                        borderColor:"rgba(250,121,33,1)",
                        backgroundColor:"rgba(250,121,33,0.3)",
                        borderWidth:1,
                        lineTension:0.1,
                        yAxisID: "durationAxis"
                    },
                    {
                        label:"max",
                        type:"line",
                        data:maxDataFunc(category),
                        fill:true,
                        pointRadius:0,
                        pointHoverRadius:3,
                        pointHitRadius:5,
                        borderColor:"rgba(229,89,52,1)",
                        backgroundColor:"rgba(229,89,52,0.3)",
                        borderWidth:1,
                        lineTension:0.1,
                        yAxisID: "durationAxis"
                    }

                ]
            };
            var chartDesc = {
                type:"bar",
                data: data,
                options: options
            };
            var chart = new Chart(canvas[0].getContext("2d"),chartDesc);
            console.log("New chart",categoryName);
            charts[categoryName] = chart;
        }
    };
    var resumeFunc = function(){
        viewing = true;
        var checkData = HealthChecker.getAggregatedMeasures(1000);
        var descriptionData = HealthChecker.describeHealth();
        refreshFunc(checkData,descriptionData);
        _.forEach(checkData,function(rawCategory,categoryName){
            generateGraphFromCategory(categoryName,rawCategory);
        });
    };
    var summarizeHealth = function(data){
        var health = 10;
        if(data.latency){
            health -= Math.min(8,data.latency.recent / 100);
        }
        if(data.render){
            health -= Math.min(8,data.render.recent / 20);
        }
        $(".meters").css("background-color", (function(){
            if (_.some(["latency","serverResponse"], function(category){
                    return category in data && (data[category] == undefined || data[category].successRate < 1);
                })){
                return "red";
            }
            else
            {
                return "transparent";
            }
        })());
        var wasHealthy = healthy;
        healthy = _.every(["latency", "serverResponse"], function (category) {
            return category in data && data[category] != undefined && data[category].successful;
        });
        if( wasHealthy != healthy ) {
            blit();
        }
        $("#healthStatus").prop({
            max:max,
            low:low,
            high:high,
            min:min,
            value:health
        });
    };
    var cells = {};
    var c = function(selector){
        if(selector in cells){
            return cells[selector];
        }
        return cells[selector] = $(selector);
    };
    var refreshFunc = function(checkData,descriptionData){
        WorkQueue.enqueue(function(){
            summarizeHealth(descriptionData);
        });
        if(viewing){
            var overallLatencyData = descriptionData["latency"];
            if (overallLatencyData != undefined){
                c(".healthCheckSummaryLatencyContainer").show();
                c(".latencyAverage").text(parseInt(overallLatencyData.average));
                c(".worstLatency").text(parseInt(overallLatencyData.min));
                c(".bestLatency").text(parseInt(overallLatencyData.max));
                c(".successRate").text(parseInt(overallLatencyData.successRate * 100));
                if (overallLatencyData.average > 200){
                    c(".latencyHumanReadable").text("poor");
                } else if (overallLatencyData.average > 50){
                    c(".latencyHumanReadable").text("moderate");
                } else if (overallLatencyData.average > 20){
                    c(".latencyHumanReadable").text("good");
                }
            } else {
                c(".healthCheckSummaryLatencyContainer").hide();
            }
            var overallServerResponseData = descriptionData["serverResponse"];
            if (overallServerResponseData != undefined){
                c(".heathCheckSummaryServerResponseContainer").show();
                var serverHealthData = overallServerResponseData.average;
                c(".serverResponseAverage").text(parseInt(serverHealthData));
                var humanReadableServerHealthData = serverHealthData > 2 ? "poor" : "good";
                c(".serverResponseHumanReadable").text(humanReadableServerHealthData);
            } else {
                c(".heathCheckSummaryServerResponseContainer").hide();
            }
            _.forEach(checkData,function(rawCategory,categoryName){
                var category = adjustTimeFunc(rawCategory);
                if (!(categoryName in charts)){
                    generateGraphFromCategory(categoryName,rawCategory);
                }
                var chart = charts[categoryName];
                chart.data.datasets[0].data = errorDataFunc(category);
                chart.data.datasets[1].data = minDataFunc(category);
                chart.data.datasets[2].data = averageDataFunc(category);
                chart.data.datasets[3].data = maxDataFunc(category);
                chart.update();
            });
        }
    };
    var healthyFunc = function(){
      return healthy;
    };
    return {
        resume:resumeFunc,
        pause:pauseFunc,
        refreshDisplays:refreshFunc,
        healthy:healthyFunc
    };
})();
<commit_msg>METL-603: METL-603: Use strict equality, and updated health and color logic to be complementary. Updated storeLifetime comment to reflect reality.<commit_after>var HealthChecker = (function(){
    var storeLifetime = 5 * 60 * 1000; //5 minutes
    var serverStatusInterval = 20000; //every 20 seconds
    var store = {};
    var healthChecking = true;

    var clockOffset = 0;

    var addMeasureFunc = function(category,success,duration){
        if (!(category in store)){
            store[category] = timedQueue(storeLifetime);
        }
        var catStore = store[category];
        catStore.enqueue({
            instant:new Date().getTime(),
            duration:duration,
            success:success
        });
        updateGraph();
    };
    var setLatencyIndeterminate = function(isIndeterminate){
        $("#healthStatus")
            .attr("low",isIndeterminate? 11 : 4)
            .attr("high",isIndeterminate? 12 : 8)
            .attr("optimum",isIndeterminate? 13 : 10)
    };
    var check = function(){
        var clientStart = new Date().getTime();
        var reportableHealthObj = describeHealthFunction();
        var url = "/reportLatency";
        if ("latency" in reportableHealthObj){
            var reportableHealth = reportableHealthObj.latency;
            url = sprintf("%s?minLatency=%s&maxLatency=%s&meanLatency=%s&sampleCount=%s",url,reportableHealth.min,reportableHealth.max,reportableHealth.average,reportableHealth.count)
        }
        setLatencyIndeterminate(true);
        $.ajax(url,{
            method:"GET",
            success:function(response){
                if( response.includes("<html") ) {
                    // Redirect to the url if it returned HTML instead of the latency, as it's likely to be the auth page.
                    window.location.href = url;
                }
                else {
                    setLatencyIndeterminate(false);
                    var nowTime = new Date();
                    var timeObj = JSON.parse(response);
                    var time = timeObj.serverWorkTime;
                    var serverWorkTime = parseInt(time);
                    var totalTime = new Date().getTime() - clientStart;
                    var latency = (totalTime - serverWorkTime) / 2;

                    var serverSideTime = timeObj.serverTime;
                    clockOffset = nowTime.getTime() - (serverSideTime + latency);
                    addMeasureFunc("serverResponse",true,serverWorkTime);
                    addMeasureFunc("latency",true,latency);
                    _.delay(check,serverStatusInterval);
                }
            },
            dataType:"text",
            error:function(){
                setLatencyIndeterminate(true);
                addMeasureFunc("latency",false,(new Date().getTime() - clientStart) / 2);
                _.delay(check,serverStatusInterval);
            }
        });
    };
    var updateGraph = _.throttle(function(){
        var checkData = getAggregatedMeasuresFunc(1000);
        var describedData = describeHealthFunction();
        HealthCheckViewer.refreshDisplays(checkData,describedData);
    },1000);
    var resumeHealthCheckFunc = function(immediate){
        healthChecking = true;
        if (immediate){
            check();
        } else {
            _.delay(check,serverStatusInterval);
        }
    };
    var pauseHealthCheckFunc = function(){
        healthChecking = false;
    };
    var getMeasuresFunc = function(){
        return _.mapValues(store,function(v){return v.items();});
    };
    var getAggregatedMeasuresFunc = function(granularity){
        return _.mapValues(store,function(v){
            var set = {};
            _.forEach(v.items(),function(item){
                var sample = (Math.floor(item.instant / granularity) * granularity);
                var oldValue = set[sample];
                var obj = oldValue ? oldValue : {
                    count:0,
                    avg:undefined,
                    successCount:0,
                    min:undefined,
                    max:undefined,
                    instant:sample
                };
                obj.count += 1;
                if (item.success){
                    obj.successCount += 1;
                }
                if (obj.min == undefined || obj.min > item.duration){
                    obj.min = item.duration;
                }
                if (obj.max == undefined || obj.max < item.duration){
                    obj.max = item.duration;
                }
                if (obj.avg == undefined){
                    obj.avg = item.duration;
                } else {
                    obj.avg = ((item.duration - obj.avg) / obj.count) + obj.avg;
                }
                set[sample] = obj;
            });
            return _.values(set);
        });
    };
    var describeHealthFunction = function(){
        return _.mapValues(store,function(catStore,k){
            var v = catStore.items();
            var count = v.length;
            var durations = _.map(v,"duration");
            if (count > 0){
                return {
                    name:k,
                    count:count,
                    max:_.max(durations),
                    min:_.min(durations),
                    average:_.mean(durations),
                    recent:_.mean(_.takeRight(durations,10)),
                    successful:count == 0 || v[count-1].success,
                    successRate:_.countBy(v,"success")[true] / count
                };
            }
        });
    };
    $(function(){
        resumeHealthCheckFunc(true);
    });
    return {
        getTimeOffset:function(){
            return clockOffset;
        },
        getServerTime:function(){
            return new Date(new Date().getTime() + clockOffset);
        },
        check:check,
        resumeHealthCheck:resumeHealthCheckFunc,
        pauseHealthCheck:pauseHealthCheckFunc,
        addMeasure:addMeasureFunc,
        getMeasures:getMeasuresFunc,
        getAggregatedMeasures:getAggregatedMeasuresFunc,
        describeHealth:describeHealthFunction
    }
})();

var augmentArguments = function(args){
    args[_.size(args)] = new Date().getTime();
    return args;
};

var serverResponse = function(responseObj){
    HealthChecker.addMeasure(responseObj.command,responseObj.success,responseObj.duration);
    if ("instant" in responseObj){
        var startTime = responseObj.instant;
        var totalTime = new Date().getTime() - startTime;
        var latency = (totalTime - responseObj.duration) / 2;
        HealthChecker.addMeasure("latency",responseObj.success,latency);
    }
    if ("success" in responseObj && responseObj.success == false){
        console.log(responseObj);
        errorAlert(sprintf("error in %s",responseObj.command),responseObj.response || "Error encountered");
    }
};

var HealthCheckViewer = (function(){
    var viewing = false;
    var healthCheckContainer = {};
    $("#healthCheckListing");
    var healthCheckItemTemplate = {};
    var charts = {};
    var min = 0;
    var max = 13;
    var high = 8;
    var low = 4;
    var healthy = false;
    $(function(){
        healthCheckContainer = $("#healthCheckListing");
        healthCheckItemTemplate = healthCheckContainer.find(".healthCheckItem").clone();
        healthCheckContainer.empty();
    });
    var pauseFunc = function(){
        viewing = false;
    };
    // data extractors
    var errorDataFunc = function(samples){
        return _.filter(_.map(samples,function(d){
            return {
                x:d.instant,
                y:d.count - d.successCount
            };
        }),function(d){return d.y > 0;});
    };
    var averageDataFunc = function(samples){
        return _.map(samples,function(d){
            return {
                x:d.instant,
                y:d.avg //- d.min
            };
        });
    };
    var minDataFunc = function(samples){
        return _.map(samples,function(d){
            return {
                x:d.instant,
                y:d.min
            };
        });
    };
    var maxDataFunc = function(samples){
        return _.map(samples,function(d){
            return {
                x:d.instant,
                y:d.max //- d.avg
            };
        });
    };

    var adjustTimeFunc = function(samples){
        var now = new Date().getTime();
        return _.map(samples,function(d){
            d.instant = (d.instant - now) / 1000;
            return d;
        });
    };

    var generateGraphFromCategory = function(categoryName,rawCategory){
        if (!(categoryName in charts)){
            var category = adjustTimeFunc(rawCategory);
            var rootElem = healthCheckItemTemplate.clone();
            var canvas = $("<canvas />").addClass("healthCheckCanvas").css({"margin-top":"-20px"});
            rootElem.html(canvas);
            healthCheckContainer.append(rootElem);
            var options = {
                title: {
                    display: true,
                    text: categoryName,
                    padding:20
                },
                legend:{
                    display:false
                },
                scales: {
                    yAxes: [
                        {
                            id:"durationAxis",
                            scaleLabel:{
                                display:true,
                                labelString:"time taken (ms)"
                            },
                            type: "linear",
                            stacked: false,
                            display:true,
                            position:"left",
                            ticks: {
                            }
                        },
                        {
                            id:"errorAxis",
                            scaleLabel:{
                                display:true,
                                labelString:"errors"
                            },
                            type: "linear",
                            stacked: true,
                            display:true,
                            position:"right",
                            ticks: {
                                beginAtZero:true,
                                min:0,
                                stepSize:1
                            }
                        }
                    ],
                    xAxes: [{
                        type: "linear",
                        position: "bottom",
                        scaleLabel:{
                            display:true,
                            labelString:"time (seconds)"
                        },
                        ticks: {
                            beginAtZero:true
                        }
                    }]
                },
                hover:{
                    mode:"x-axis"
                },
                elements:{
                    line: {
                        fill: false
                    },
                    bar: {
                        fill:true
                    }
                }
            };
            var data = {
                labels: _.map(category,"instant"),
                datasets:[
                    {
                        type:"line",
                        label:"error count",
                        data:errorDataFunc(category),
                        fill:true,
                        borderColor:"rgba(0,0,0,0.5)",
                        backgroundColor:"rgba(255,0,0,0.3)",
                        borderWidth:1,
                        pointRadius:0,
                        pointHoverRadius:3,
                        pointHitRadius:5,
                        lineTension:0,
                        stepped:true,
                        yAxisID: "errorAxis"
                    },
                    {
                        label:"min",
                        type:"line",
                        data:minDataFunc(category),
                        fill:true,
                        pointRadius:0,
                        pointHoverRadius:3,
                        pointHitRadius:5,
                        borderColor:"rgba(155,197,61,1)",
                        backgroundColor:"rgba(155,197,61,0.3)",
                        borderWidth:1,
                        lineTension:0.1,
                        yAxisID: "durationAxis"
                    },
                    {
                        label:"avg",
                        type:"line",
                        data:averageDataFunc(category),
                        fill:true,
                        pointRadius:0,
                        pointHoverRadius:3,
                        pointHitRadius:5,
                        borderColor:"rgba(250,121,33,1)",
                        backgroundColor:"rgba(250,121,33,0.3)",
                        borderWidth:1,
                        lineTension:0.1,
                        yAxisID: "durationAxis"
                    },
                    {
                        label:"max",
                        type:"line",
                        data:maxDataFunc(category),
                        fill:true,
                        pointRadius:0,
                        pointHoverRadius:3,
                        pointHitRadius:5,
                        borderColor:"rgba(229,89,52,1)",
                        backgroundColor:"rgba(229,89,52,0.3)",
                        borderWidth:1,
                        lineTension:0.1,
                        yAxisID: "durationAxis"
                    }

                ]
            };
            var chartDesc = {
                type:"bar",
                data: data,
                options: options
            };
            var chart = new Chart(canvas[0].getContext("2d"),chartDesc);
            console.log("New chart",categoryName);
            charts[categoryName] = chart;
        }
    };
    var resumeFunc = function(){
        viewing = true;
        var checkData = HealthChecker.getAggregatedMeasures(1000);
        var descriptionData = HealthChecker.describeHealth();
        refreshFunc(checkData,descriptionData);
        _.forEach(checkData,function(rawCategory,categoryName){
            generateGraphFromCategory(categoryName,rawCategory);
        });
    };
    var summarizeHealth = function(data){
        var health = 10;
        if(data.latency){
            health -= Math.min(8,data.latency.recent / 100);
        }
        if(data.render){
            health -= Math.min(8,data.render.recent / 20);
        }
        $(".meters").css("background-color", (function(){
            if (_.some(["latency","serverResponse"], function(category){
                    return !(category in data) || (data[category] === undefined || data[category].successRate < 1);
                })){
                return "red";
            }
            else
            {
                return "transparent";
            }
        })());
        var wasHealthy = healthy;
        healthy = _.every(["latency", "serverResponse"], function (category) {
            return category in data && data[category] !== undefined && data[category].successful;
        });
        if( wasHealthy != healthy ) {
            blit();
        }
        $("#healthStatus").prop({
            max:max,
            low:low,
            high:high,
            min:min,
            value:health
        });
    };
    var cells = {};
    var c = function(selector){
        if(selector in cells){
            return cells[selector];
        }
        return cells[selector] = $(selector);
    };
    var refreshFunc = function(checkData,descriptionData){
        WorkQueue.enqueue(function(){
            summarizeHealth(descriptionData);
        });
        if(viewing){
            var overallLatencyData = descriptionData["latency"];
            if (overallLatencyData != undefined){
                c(".healthCheckSummaryLatencyContainer").show();
                c(".latencyAverage").text(parseInt(overallLatencyData.average));
                c(".worstLatency").text(parseInt(overallLatencyData.min));
                c(".bestLatency").text(parseInt(overallLatencyData.max));
                c(".successRate").text(parseInt(overallLatencyData.successRate * 100));
                if (overallLatencyData.average > 200){
                    c(".latencyHumanReadable").text("poor");
                } else if (overallLatencyData.average > 50){
                    c(".latencyHumanReadable").text("moderate");
                } else if (overallLatencyData.average > 20){
                    c(".latencyHumanReadable").text("good");
                }
            } else {
                c(".healthCheckSummaryLatencyContainer").hide();
            }
            var overallServerResponseData = descriptionData["serverResponse"];
            if (overallServerResponseData != undefined){
                c(".heathCheckSummaryServerResponseContainer").show();
                var serverHealthData = overallServerResponseData.average;
                c(".serverResponseAverage").text(parseInt(serverHealthData));
                var humanReadableServerHealthData = serverHealthData > 2 ? "poor" : "good";
                c(".serverResponseHumanReadable").text(humanReadableServerHealthData);
            } else {
                c(".heathCheckSummaryServerResponseContainer").hide();
            }
            _.forEach(checkData,function(rawCategory,categoryName){
                var category = adjustTimeFunc(rawCategory);
                if (!(categoryName in charts)){
                    generateGraphFromCategory(categoryName,rawCategory);
                }
                var chart = charts[categoryName];
                chart.data.datasets[0].data = errorDataFunc(category);
                chart.data.datasets[1].data = minDataFunc(category);
                chart.data.datasets[2].data = averageDataFunc(category);
                chart.data.datasets[3].data = maxDataFunc(category);
                chart.update();
            });
        }
    };
    var healthyFunc = function(){
      return healthy;
    };
    return {
        resume:resumeFunc,
        pause:pauseFunc,
        refreshDisplays:refreshFunc,
        healthy:healthyFunc
    };
})();
<|endoftext|>


<commit_before>'use strict';
const hasOwnProperty = require('has-own-property');
const tokens = require('../../utils/tokens');
const operators = require('./enums/operators');

const QUOTING = {
	NO: {value: 'NO'},
	ESCAPE: {value: 'ESCAPE'},
	SINGLE: {close: '\'', value: 'SINGLE'},
	DOUBLE: {close: '"', value: 'DOUBLE'},
	PARAMETER: {close: '}', value: 'PARAMETER'},
	BACKTICK_COMMAND: {close: '`', value: 'BACKTICK_COMMAND'},
	COMMAND: {close: ')', value: 'COMMAND'},
	ARITHMETIC: {close: '))', value: 'ARITHMETIC'}
};

const QUOTING_DELIM = {
	'\\': QUOTING.ESCAPE,
	'\'': QUOTING.SINGLE,
	'"': QUOTING.DOUBLE,
	'`': QUOTING.BACKTICK_COMMAND,
	'${': QUOTING.PARAMETER,
	'$(': QUOTING.COMMAND,
	'$((': QUOTING.ARITHMETIC
};

const isOperator = op => hasOwnProperty(operators, op);

const mkLoc = (lineNumber, columnNumber) => ({
	startLine: lineNumber,
	startColumn: columnNumber
});

class TokenDelimiterState {
	constructor(charIterator) {
		this.charIterator = charIterator;
		this.lineNumber = 0;
		this.columnNumber = 0;
		this.prevLineNumber = 0;
		this.prevColumnNumber = 0;
		this.isComment = false;
		this.quoting = QUOTING.NO;
		this.prevQuoting = null;
		this.setEmptyToken();
	}

	isArithmeticExpansionStart(char) {
		return this.quotingCharacter(char) === QUOTING.ARITHMETIC;
	}

	removingLastChar() {
		if (this.token.TOKEN) {
			// remove slash from token
			this.token.TOKEN = this.token.TOKEN.slice(0, -1);
			if (this.token.TOKEN === '') {
				delete this.token.TOKEN;
				this.setEmptyToken();
			}
		}
	}

	isExpandingCommand() {
		return this.quoting === QUOTING.COMMAND;
	}

	canStartComment(currentCharacter) {
		return currentCharacter === '#';
	}

	canEndComment(currentCharacter) {
		return this.isComment && currentCharacter === '\n';
	}

	canContinueComment(currentCharacter) {
		return this.isComment && currentCharacter !== '\n';
	}

	startComment() {
		this.isComment = true;
	}

	endComment() {
		this.isComment = false;
	}

	canStartQuoting(currentCharacter) {
		return this.quotingCharacter(currentCharacter) && !this.isQuoting();
	}

	setCurrentQuoting(currentCharacter) {
		this.quoting = this.quotingCharacter(currentCharacter);
	}

	canCloseCurrentQuoting(ch) {
		const lastCh = this.charIterator.behind(1);
		const penultCh = this.charIterator.behind(2);
		return (this.quoting.close === ch && lastCh !== '\\') ||
			(this.quoting.close === lastCh + ch && penultCh !== '\\');
	}

	isQuoting() {
		return this.quoting !== QUOTING.NO;
	}

	isQuotingDouble() {
		return this.quoting === QUOTING.DOUBLE;
	}

	isQuotingWord() {
		return this.quoting === QUOTING.SINGLE || this.quoting === QUOTING.DOUBLE;
	}

	resetQuoting() {
		this.quoting = QUOTING.NO;
	}

	setArithmeticQuoting() {
		this.quoting = QUOTING.ARITHMETIC;
	}

	setEscaping() {
		this.quoting = QUOTING.ESCAPE;
		this.prevQuoting = QUOTING.DOUBLE;
	}

	resetEscaping() {
		this.quoting = this.prevQuoting || QUOTING.NO;
		this.prevQuoting = null;
	}

	isEscaping() {
		return this.quoting === QUOTING.ESCAPE;
	}

	setOperatorToken(text) {
		this.token = tokens.mkToken(
			'OPERATOR',
			text,
			mkLoc(this.lineNumber, this.columnNumber)
		);
	}

	setNewLineToken() {
		this.token = tokens.mkToken(
			'NEWLINE',
			'\n',
			mkLoc(this.lineNumber, this.columnNumber)
		);
	}

	setGenericToken(text) {
		this.token = {
			TOKEN: text,
			loc: mkLoc(this.lineNumber, this.columnNumber)
		};
	}

	setEmptyToken() {
		this.token = tokens.mkToken(
			'EMPTY',
			true,
			mkLoc(this.lineNumber, this.columnNumber)
		);
	}

	setEOFToken() {
		this.token = {
			EOF: true,
			loc: mkLoc(this.prevLineNumber, this.prevColumnNumber)
		};
	}

	savePreviousLoc() {
		this.prevLineNumber = this.lineNumber;
		this.prevColumnNumber = this.columnNumber;
	}

	advanceLoc(currentCharacter) {
		this.savePreviousLoc();
		if (currentCharacter === '\n') {
			this.lineNumber++;
			this.columnNumber = 0;
		} else {
			this.columnNumber++;
		}
	}

	canAppendToOperator(currentCharacter) {
		return this.quoting === QUOTING.NO &&
				isOperator(this.token.OPERATOR + currentCharacter);
	}

	finalizeCurrentToken() {
		Object.assign(this.token.loc, {
			endLine: this.prevLineNumber,
			endColumn: this.prevColumnNumber
		});
		if (!Object.isFrozen(this.token)) {
			this.token._ = {};
			Object.freeze(this.token);
		}

		return this.token;
	}

	currentTokenIsOperatorPart() {
		return this.token.OPERATOR;
	}

	currentTokenIsEmpty() {
		return Boolean(this.token.EMPTY) || this.token.TOKEN === '';
	}

	currentTokenIsGeneric() {
		return Boolean(this.token.TOKEN);
	}

	currentTokenIsCompleteOperator() {
		return isOperator(this.token.OPERATOR);
	}

	appendToOperator(currentCharacter) {
		this.token = tokens.appendTo(this.token, currentCharacter);
	}

	appendToGenericToken(currentCharacter) {
		this.token.TOKEN += currentCharacter;
	}

	quotingCharacter(ch) {
		const lastCh = this.charIterator.behind(1);
		const penultCh = this.charIterator.behind(2);

		return QUOTING_DELIM[penultCh + lastCh + ch] ||
		QUOTING_DELIM[lastCh + ch] ||
		QUOTING_DELIM[ch];
	}

	isOperatorStart(ch) {
		const lastCh = this.charIterator.behind(1);
		return lastCh !== '$' && '()|&!;<>'.indexOf(ch) !== -1;
	}
}

module.exports = TokenDelimiterState;
<commit_msg>setEOFToken switched to token utils<commit_after>'use strict';
const hasOwnProperty = require('has-own-property');
const tokens = require('../../utils/tokens');
const operators = require('./enums/operators');

const QUOTING = {
	NO: {value: 'NO'},
	ESCAPE: {value: 'ESCAPE'},
	SINGLE: {close: '\'', value: 'SINGLE'},
	DOUBLE: {close: '"', value: 'DOUBLE'},
	PARAMETER: {close: '}', value: 'PARAMETER'},
	BACKTICK_COMMAND: {close: '`', value: 'BACKTICK_COMMAND'},
	COMMAND: {close: ')', value: 'COMMAND'},
	ARITHMETIC: {close: '))', value: 'ARITHMETIC'}
};

const QUOTING_DELIM = {
	'\\': QUOTING.ESCAPE,
	'\'': QUOTING.SINGLE,
	'"': QUOTING.DOUBLE,
	'`': QUOTING.BACKTICK_COMMAND,
	'${': QUOTING.PARAMETER,
	'$(': QUOTING.COMMAND,
	'$((': QUOTING.ARITHMETIC
};

const isOperator = op => hasOwnProperty(operators, op);

const mkLoc = (lineNumber, columnNumber) => ({
	startLine: lineNumber,
	startColumn: columnNumber
});

class TokenDelimiterState {
	constructor(charIterator) {
		this.charIterator = charIterator;
		this.lineNumber = 0;
		this.columnNumber = 0;
		this.prevLineNumber = 0;
		this.prevColumnNumber = 0;
		this.isComment = false;
		this.quoting = QUOTING.NO;
		this.prevQuoting = null;
		this.setEmptyToken();
	}

	isArithmeticExpansionStart(char) {
		return this.quotingCharacter(char) === QUOTING.ARITHMETIC;
	}

	removingLastChar() {
		if (this.token.TOKEN) {
			// remove slash from token
			this.token.TOKEN = this.token.TOKEN.slice(0, -1);
			if (this.token.TOKEN === '') {
				delete this.token.TOKEN;
				this.setEmptyToken();
			}
		}
	}

	isExpandingCommand() {
		return this.quoting === QUOTING.COMMAND;
	}

	canStartComment(currentCharacter) {
		return currentCharacter === '#';
	}

	canEndComment(currentCharacter) {
		return this.isComment && currentCharacter === '\n';
	}

	canContinueComment(currentCharacter) {
		return this.isComment && currentCharacter !== '\n';
	}

	startComment() {
		this.isComment = true;
	}

	endComment() {
		this.isComment = false;
	}

	canStartQuoting(currentCharacter) {
		return this.quotingCharacter(currentCharacter) && !this.isQuoting();
	}

	setCurrentQuoting(currentCharacter) {
		this.quoting = this.quotingCharacter(currentCharacter);
	}

	canCloseCurrentQuoting(ch) {
		const lastCh = this.charIterator.behind(1);
		const penultCh = this.charIterator.behind(2);
		return (this.quoting.close === ch && lastCh !== '\\') ||
			(this.quoting.close === lastCh + ch && penultCh !== '\\');
	}

	isQuoting() {
		return this.quoting !== QUOTING.NO;
	}

	isQuotingDouble() {
		return this.quoting === QUOTING.DOUBLE;
	}

	isQuotingWord() {
		return this.quoting === QUOTING.SINGLE || this.quoting === QUOTING.DOUBLE;
	}

	resetQuoting() {
		this.quoting = QUOTING.NO;
	}

	setArithmeticQuoting() {
		this.quoting = QUOTING.ARITHMETIC;
	}

	setEscaping() {
		this.quoting = QUOTING.ESCAPE;
		this.prevQuoting = QUOTING.DOUBLE;
	}

	resetEscaping() {
		this.quoting = this.prevQuoting || QUOTING.NO;
		this.prevQuoting = null;
	}

	isEscaping() {
		return this.quoting === QUOTING.ESCAPE;
	}

	setOperatorToken(text) {
		this.token = tokens.mkToken(
			'OPERATOR',
			text,
			mkLoc(this.lineNumber, this.columnNumber)
		);
	}

	setNewLineToken() {
		this.token = tokens.mkToken(
			'NEWLINE',
			'\n',
			mkLoc(this.lineNumber, this.columnNumber)
		);
	}

	setGenericToken(text) {
		this.token = {
			TOKEN: text,
			loc: mkLoc(this.lineNumber, this.columnNumber)
		};
	}

	setEmptyToken() {
		this.token = tokens.mkToken(
			'EMPTY',
			true,
			mkLoc(this.lineNumber, this.columnNumber)
		);
	}

	setEOFToken() {
		this.token = tokens.mkToken(
			'EOF',
			true,
			mkLoc(this.prevLineNumber, this.prevColumnNumber)
		);
	}

	savePreviousLoc() {
		this.prevLineNumber = this.lineNumber;
		this.prevColumnNumber = this.columnNumber;
	}

	advanceLoc(currentCharacter) {
		this.savePreviousLoc();
		if (currentCharacter === '\n') {
			this.lineNumber++;
			this.columnNumber = 0;
		} else {
			this.columnNumber++;
		}
	}

	canAppendToOperator(currentCharacter) {
		return this.quoting === QUOTING.NO &&
				isOperator(this.token.OPERATOR + currentCharacter);
	}

	finalizeCurrentToken() {
		Object.assign(this.token.loc, {
			endLine: this.prevLineNumber,
			endColumn: this.prevColumnNumber
		});
		if (!Object.isFrozen(this.token)) {
			this.token._ = {};
			Object.freeze(this.token);
		}

		return this.token;
	}

	currentTokenIsOperatorPart() {
		return this.token.OPERATOR;
	}

	currentTokenIsEmpty() {
		return Boolean(this.token.EMPTY) || this.token.TOKEN === '';
	}

	currentTokenIsGeneric() {
		return Boolean(this.token.TOKEN);
	}

	currentTokenIsCompleteOperator() {
		return isOperator(this.token.OPERATOR);
	}

	appendToOperator(currentCharacter) {
		this.token = tokens.appendTo(this.token, currentCharacter);
	}

	appendToGenericToken(currentCharacter) {
		this.token.TOKEN += currentCharacter;
	}

	quotingCharacter(ch) {
		const lastCh = this.charIterator.behind(1);
		const penultCh = this.charIterator.behind(2);

		return QUOTING_DELIM[penultCh + lastCh + ch] ||
		QUOTING_DELIM[lastCh + ch] ||
		QUOTING_DELIM[ch];
	}

	isOperatorStart(ch) {
		const lastCh = this.charIterator.behind(1);
		return lastCh !== '$' && '()|&!;<>'.indexOf(ch) !== -1;
	}
}

module.exports = TokenDelimiterState;
<|endoftext|>


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

(function (mumuki) {
  var lastSubmission = {};

  function Laboratory(exerciseId){
    this.exerciseId = exerciseId;
  }

  function asString(json){
    return JSON.stringify(json);
  }

  function sameAsLastSolution(newSolution){
    return asString(lastSubmission.content) === asString(newSolution);
  }

  function lastSubmissionFinishedSuccessfully(){
    return lastSubmission.result && lastSubmission.result.status !== 'aborted';
  }

  function sendNewSolution(solution){
    var token = new mumuki.CsrfToken();
    var request = token.newRequest({
      type: 'POST',
      url: window.location.origin + window.location.pathname + '/solutions',
      data: solution
    });

    return $.ajax(request).done(function (result) {
      lastSubmission = { content: solution, result: result };
    });
  }

  Laboratory.prototype = {
    runLocalTests: function (solution) {
      if(lastSubmissionFinishedSuccessfully() && sameAsLastSolution(solution)){
        return $.Deferred().resolve(lastSubmission.result);
      } else {
        return sendNewSolution(solution);
      }
    },
    runTests: function(content) {
      return this.runLocalTests({ solution: content });
    }
  };

  mumuki.bridge = {
    Laboratory: Laboratory
  };

}(mumuki));
<commit_msg>clear lastSubmission when changing exercises<commit_after>var mumuki = mumuki || {};

(function (mumuki) {
  var lastSubmission = {};

  function Laboratory(exerciseId){
    this.exerciseId = exerciseId;
  }

  function asString(json){
    return JSON.stringify(json);
  }

  function sameAsLastSolution(newSolution){
    return asString(lastSubmission.content) === asString(newSolution);
  }

  function lastSubmissionFinishedSuccessfully(){
    return lastSubmission.result && lastSubmission.result.status !== 'aborted';
  }

  function sendNewSolution(solution){
    var token = new mumuki.CsrfToken();
    var request = token.newRequest({
      type: 'POST',
      url: window.location.origin + window.location.pathname + '/solutions',
      data: solution
    });

    return $.ajax(request).done(function (result) {
      lastSubmission = { content: solution, result: result };
    });
  }

  mumuki.load(function () {
    lastSubmission = {};
  });

  Laboratory.prototype = {
    runLocalTests: function (solution) {
      if(lastSubmissionFinishedSuccessfully() && sameAsLastSolution(solution)){
        return $.Deferred().resolve(lastSubmission.result);
      } else {
        return sendNewSolution(solution);
      }
    },
    runTests: function(content) {
      return this.runLocalTests({ solution: content });
    }
  };

  mumuki.bridge = {
    Laboratory: Laboratory
  };

}(mumuki));
<|endoftext|>


<commit_before>/* eslint-disable no-underscore-dangle, class-methods-use-this, consistent-return, no-shadow, no-param-reassign */
/* global ListIssue */

import { __ } from '~/locale';
import ListLabel from './label';
import ListAssignee from './assignee';
import { urlParamsToObject } from '~/lib/utils/common_utils';
import boardsStore from '../stores/boards_store';
import ListMilestone from './milestone';

const PER_PAGE = 20;

const TYPES = {
  backlog: {
    isPreset: true,
    isExpandable: true,
    isBlank: false,
  },
  closed: {
    isPreset: true,
    isExpandable: true,
    isBlank: false,
  },
  blank: {
    isPreset: true,
    isExpandable: false,
    isBlank: true,
  },
  default: {
    // includes label, assignee, and milestone lists
    isPreset: false,
    isExpandable: true,
    isBlank: false,
  },
};

class List {
  constructor(obj, defaultAvatar) {
    this.id = obj.id;
    this._uid = this.guid();
    this.position = obj.position;
    this.title = obj.list_type === 'backlog' ? __('Open') : obj.title;
    this.type = obj.list_type;

    const typeInfo = this.getTypeInfo(this.type);
    this.preset = Boolean(typeInfo.isPreset);
    this.isExpandable = Boolean(typeInfo.isExpandable);
    this.isExpanded = true;
    this.page = 1;
    this.loading = true;
    this.loadingMore = false;
    this.issues = [];
    this.issuesSize = 0;
    this.defaultAvatar = defaultAvatar;

    if (obj.label) {
      this.label = new ListLabel(obj.label);
    } else if (obj.user) {
      this.assignee = new ListAssignee(obj.user);
      this.title = this.assignee.name;
    } else if (IS_EE && obj.milestone) {
      this.milestone = new ListMilestone(obj.milestone);
      this.title = this.milestone.title;
    }

    if (!typeInfo.isBlank && this.id) {
      this.getIssues().catch(() => {
        // TODO: handle request error
      });
    }
  }

  guid() {
    const s4 = () =>
      Math.floor((1 + Math.random()) * 0x10000)
        .toString(16)
        .substring(1);
    return `${s4()}${s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`;
  }

  save() {
    const entity = this.label || this.assignee || this.milestone;
    let entityType = '';
    if (this.label) {
      entityType = 'label_id';
    } else if (this.assignee) {
      entityType = 'assignee_id';
    } else if (IS_EE && this.milestone) {
      entityType = 'milestone_id';
    }

    return gl.boardService
      .createList(entity.id, entityType)
      .then(res => res.data)
      .then(data => {
        this.id = data.id;
        this.type = data.list_type;
        this.position = data.position;
        this.label = data.label;

        return this.getIssues();
      });
  }

  destroy() {
    const index = boardsStore.state.lists.indexOf(this);
    boardsStore.state.lists.splice(index, 1);
    boardsStore.updateNewListDropdown(this.id);

    gl.boardService.destroyList(this.id).catch(() => {
      // TODO: handle request error
    });
  }

  update() {
    gl.boardService.updateList(this.id, this.position).catch(() => {
      // TODO: handle request error
    });
  }

  nextPage() {
    if (this.issuesSize > this.issues.length) {
      if (this.issues.length / PER_PAGE >= 1) {
        this.page += 1;
      }

      return this.getIssues(false);
    }
  }

  getIssues(emptyIssues = true) {
    const data = {
      ...urlParamsToObject(boardsStore.filter.path),
      page: this.page,
    };

    if (this.label && data.label_name) {
      data.label_name = data.label_name.filter(label => label !== this.label.title);
    }

    if (emptyIssues) {
      this.loading = true;
    }

    return gl.boardService
      .getIssuesForList(this.id, data)
      .then(res => res.data)
      .then(data => {
        this.loading = false;
        this.issuesSize = data.size;

        if (emptyIssues) {
          this.issues = [];
        }

        this.createIssues(data.issues);

        return data;
      });
  }

  newIssue(issue) {
    this.addIssue(issue, null, 0);
    this.issuesSize += 1;

    return gl.boardService
      .newIssue(this.id, issue)
      .then(res => res.data)
      .then(data => this.onNewIssueResponse(issue, data));
  }

  createIssues(data) {
    data.forEach(issueObj => {
      this.addIssue(new ListIssue(issueObj, this.defaultAvatar));
    });
  }

  addIssue(issue, listFrom, newIndex) {
    let moveBeforeId = null;
    let moveAfterId = null;

    if (!this.findIssue(issue.id)) {
      if (newIndex !== undefined) {
        this.issues.splice(newIndex, 0, issue);

        if (this.issues[newIndex - 1]) {
          moveBeforeId = this.issues[newIndex - 1].id;
        }

        if (this.issues[newIndex + 1]) {
          moveAfterId = this.issues[newIndex + 1].id;
        }
      } else {
        this.issues.push(issue);
      }

      if (this.label) {
        issue.addLabel(this.label);
      }

      if (this.assignee) {
        if (listFrom && listFrom.type === 'assignee') {
          issue.removeAssignee(listFrom.assignee);
        }
        issue.addAssignee(this.assignee);
      }

      if (IS_EE && this.milestone) {
        if (listFrom && listFrom.type === 'milestone') {
          issue.removeMilestone(listFrom.milestone);
        }
        issue.addMilestone(this.milestone);
      }

      if (listFrom) {
        this.issuesSize += 1;

        this.updateIssueLabel(issue, listFrom, moveBeforeId, moveAfterId);
      }
    }
  }

  moveIssue(issue, oldIndex, newIndex, moveBeforeId, moveAfterId) {
    this.issues.splice(oldIndex, 1);
    this.issues.splice(newIndex, 0, issue);

    gl.boardService.moveIssue(issue.id, null, null, moveBeforeId, moveAfterId).catch(() => {
      // TODO: handle request error
    });
  }

  updateIssueLabel(issue, listFrom, moveBeforeId, moveAfterId) {
    gl.boardService
      .moveIssue(issue.id, listFrom.id, this.id, moveBeforeId, moveAfterId)
      .catch(() => {
        // TODO: handle request error
      });
  }

  findIssue(id) {
    return this.issues.find(issue => issue.id === id);
  }

  removeIssue(removeIssue) {
    this.issues = this.issues.filter(issue => {
      const matchesRemove = removeIssue.id === issue.id;

      if (matchesRemove) {
        this.issuesSize -= 1;
        issue.removeLabel(this.label);
      }

      return !matchesRemove;
    });
  }

  getTypeInfo(type) {
    return TYPES[type] || TYPES.default;
  }

  onNewIssueResponse(issue, data) {
    issue.id = data.id;
    issue.iid = data.iid;
    issue.project = data.project;
    issue.path = data.real_path;
    issue.referencePath = data.reference_path;
    issue.assignableLabelsEndpoint = data.assignable_labels_endpoint;

    if (this.issuesSize > 1) {
      const moveBeforeId = this.issues[1].id;
      gl.boardService.moveIssue(issue.id, null, null, null, moveBeforeId);
    }
  }
}

window.List = List;

export default List;
<commit_msg>Add missing ListIssue import<commit_after>/* eslint-disable no-underscore-dangle, class-methods-use-this, consistent-return, no-shadow, no-param-reassign */

import { __ } from '~/locale';
import ListLabel from './label';
import ListAssignee from './assignee';
import ListIssue from './issue';
import { urlParamsToObject } from '~/lib/utils/common_utils';
import boardsStore from '../stores/boards_store';
import ListMilestone from './milestone';

const PER_PAGE = 20;

const TYPES = {
  backlog: {
    isPreset: true,
    isExpandable: true,
    isBlank: false,
  },
  closed: {
    isPreset: true,
    isExpandable: true,
    isBlank: false,
  },
  blank: {
    isPreset: true,
    isExpandable: false,
    isBlank: true,
  },
  default: {
    // includes label, assignee, and milestone lists
    isPreset: false,
    isExpandable: true,
    isBlank: false,
  },
};

class List {
  constructor(obj, defaultAvatar) {
    this.id = obj.id;
    this._uid = this.guid();
    this.position = obj.position;
    this.title = obj.list_type === 'backlog' ? __('Open') : obj.title;
    this.type = obj.list_type;

    const typeInfo = this.getTypeInfo(this.type);
    this.preset = Boolean(typeInfo.isPreset);
    this.isExpandable = Boolean(typeInfo.isExpandable);
    this.isExpanded = true;
    this.page = 1;
    this.loading = true;
    this.loadingMore = false;
    this.issues = [];
    this.issuesSize = 0;
    this.defaultAvatar = defaultAvatar;

    if (obj.label) {
      this.label = new ListLabel(obj.label);
    } else if (obj.user) {
      this.assignee = new ListAssignee(obj.user);
      this.title = this.assignee.name;
    } else if (IS_EE && obj.milestone) {
      this.milestone = new ListMilestone(obj.milestone);
      this.title = this.milestone.title;
    }

    if (!typeInfo.isBlank && this.id) {
      this.getIssues().catch(() => {
        // TODO: handle request error
      });
    }
  }

  guid() {
    const s4 = () =>
      Math.floor((1 + Math.random()) * 0x10000)
        .toString(16)
        .substring(1);
    return `${s4()}${s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`;
  }

  save() {
    const entity = this.label || this.assignee || this.milestone;
    let entityType = '';
    if (this.label) {
      entityType = 'label_id';
    } else if (this.assignee) {
      entityType = 'assignee_id';
    } else if (IS_EE && this.milestone) {
      entityType = 'milestone_id';
    }

    return gl.boardService
      .createList(entity.id, entityType)
      .then(res => res.data)
      .then(data => {
        this.id = data.id;
        this.type = data.list_type;
        this.position = data.position;
        this.label = data.label;

        return this.getIssues();
      });
  }

  destroy() {
    const index = boardsStore.state.lists.indexOf(this);
    boardsStore.state.lists.splice(index, 1);
    boardsStore.updateNewListDropdown(this.id);

    gl.boardService.destroyList(this.id).catch(() => {
      // TODO: handle request error
    });
  }

  update() {
    gl.boardService.updateList(this.id, this.position).catch(() => {
      // TODO: handle request error
    });
  }

  nextPage() {
    if (this.issuesSize > this.issues.length) {
      if (this.issues.length / PER_PAGE >= 1) {
        this.page += 1;
      }

      return this.getIssues(false);
    }
  }

  getIssues(emptyIssues = true) {
    const data = {
      ...urlParamsToObject(boardsStore.filter.path),
      page: this.page,
    };

    if (this.label && data.label_name) {
      data.label_name = data.label_name.filter(label => label !== this.label.title);
    }

    if (emptyIssues) {
      this.loading = true;
    }

    return gl.boardService
      .getIssuesForList(this.id, data)
      .then(res => res.data)
      .then(data => {
        this.loading = false;
        this.issuesSize = data.size;

        if (emptyIssues) {
          this.issues = [];
        }

        this.createIssues(data.issues);

        return data;
      });
  }

  newIssue(issue) {
    this.addIssue(issue, null, 0);
    this.issuesSize += 1;

    return gl.boardService
      .newIssue(this.id, issue)
      .then(res => res.data)
      .then(data => this.onNewIssueResponse(issue, data));
  }

  createIssues(data) {
    data.forEach(issueObj => {
      this.addIssue(new ListIssue(issueObj, this.defaultAvatar));
    });
  }

  addIssue(issue, listFrom, newIndex) {
    let moveBeforeId = null;
    let moveAfterId = null;

    if (!this.findIssue(issue.id)) {
      if (newIndex !== undefined) {
        this.issues.splice(newIndex, 0, issue);

        if (this.issues[newIndex - 1]) {
          moveBeforeId = this.issues[newIndex - 1].id;
        }

        if (this.issues[newIndex + 1]) {
          moveAfterId = this.issues[newIndex + 1].id;
        }
      } else {
        this.issues.push(issue);
      }

      if (this.label) {
        issue.addLabel(this.label);
      }

      if (this.assignee) {
        if (listFrom && listFrom.type === 'assignee') {
          issue.removeAssignee(listFrom.assignee);
        }
        issue.addAssignee(this.assignee);
      }

      if (IS_EE && this.milestone) {
        if (listFrom && listFrom.type === 'milestone') {
          issue.removeMilestone(listFrom.milestone);
        }
        issue.addMilestone(this.milestone);
      }

      if (listFrom) {
        this.issuesSize += 1;

        this.updateIssueLabel(issue, listFrom, moveBeforeId, moveAfterId);
      }
    }
  }

  moveIssue(issue, oldIndex, newIndex, moveBeforeId, moveAfterId) {
    this.issues.splice(oldIndex, 1);
    this.issues.splice(newIndex, 0, issue);

    gl.boardService.moveIssue(issue.id, null, null, moveBeforeId, moveAfterId).catch(() => {
      // TODO: handle request error
    });
  }

  updateIssueLabel(issue, listFrom, moveBeforeId, moveAfterId) {
    gl.boardService
      .moveIssue(issue.id, listFrom.id, this.id, moveBeforeId, moveAfterId)
      .catch(() => {
        // TODO: handle request error
      });
  }

  findIssue(id) {
    return this.issues.find(issue => issue.id === id);
  }

  removeIssue(removeIssue) {
    this.issues = this.issues.filter(issue => {
      const matchesRemove = removeIssue.id === issue.id;

      if (matchesRemove) {
        this.issuesSize -= 1;
        issue.removeLabel(this.label);
      }

      return !matchesRemove;
    });
  }

  getTypeInfo(type) {
    return TYPES[type] || TYPES.default;
  }

  onNewIssueResponse(issue, data) {
    issue.id = data.id;
    issue.iid = data.iid;
    issue.project = data.project;
    issue.path = data.real_path;
    issue.referencePath = data.reference_path;
    issue.assignableLabelsEndpoint = data.assignable_labels_endpoint;

    if (this.issuesSize > 1) {
      const moveBeforeId = this.issues[1].id;
      gl.boardService.moveIssue(issue.id, null, null, null, moveBeforeId);
    }
  }
}

window.List = List;

export default List;
<|endoftext|>


<commit_before>(function($){
    $.fn.bootstrapTransfer = function(options) {
        var settings = $.extend({}, $.fn.bootstrapTransfer.defaults, options);
        var _this;
        /* #=============================================================================== */
        /* # Expose public functions */
        /* #=============================================================================== */
        this.populate = function(input) { _this.populate(input); };
        this.set_values = function(values) { _this.set_values(values); };
        this.get_values = function() { return _this.get_values(); };
        return this.each(function(){
            _this = $(this);
            /* #=============================================================================== */
            /* # Add widget markup */
            /* #=============================================================================== */
            _this.append($.fn.bootstrapTransfer.defaults.template);
            _this.addClass("bootstrap-transfer-container");
            /* #=============================================================================== */
            /* # Initialize internal variables */
            /* #=============================================================================== */
            _this.$filter_input = _this.find('.filter-input');
            _this.$remaining_select = _this.find('select.remaining');
            _this.$target_select = _this.find('select.target');
            _this.$add_btn = _this.find('.selector-add');
            _this.$remove_btn = _this.find('.selector-remove');
            _this.$choose_all_btn = _this.find('.selector-chooseall');
            _this.$clear_all_btn = _this.find('.selector-clearall');
            _this._remaining_list = [];
            _this._target_list = [];
            /* #=============================================================================== */
            /* # Apply settings */
            /* #=============================================================================== */
            /* target_id */
            if (settings.target_id != '') _this.$target_select.attr('id', settings.target_id);
            /* height */
            _this.find('select.remaining').css('height', settings.height + 'em');
            _this.find('select.target').css('height', settings.height + 4 + 'em');
            /* #=============================================================================== */
            /* # Wire internal events */
            /* #=============================================================================== */
            _this.$add_btn.click(function(){
                _this.move_elems(_this.$remaining_select.val(), false, true);
            });
            _this.$remove_btn.click(function(){
                _this.move_elems(_this.$target_select.val(), true, false);
            });
            _this.$choose_all_btn.click(function(){
                _this.move_all(false, true);
            });
            _this.$clear_all_btn.click(function(){
                _this.move_all(true, false);
            });
            _this.$filter_input.keyup(function(){
                _this.update_lists(true);
            });
            /* #=============================================================================== */
            /* # Implement public functions */
            /* #=============================================================================== */
            _this.populate = function(input) {
                // input: [{value:_, content:_}]
                _this.$filter_input.val('');
                for (var i in input) {
                    var e = input[i];
                    _this._remaining_list.push([{value:e.value, content:e.content}, true]);
                    _this._target_list.push([{value:e.value, content:e.content}, false]);
                }
                _this.update_lists(true);
            };
            _this.set_values = function(values) {
                _this.move_elems(values, false, true);
            };
            _this.get_values = function(){
                return _this.get_internal(_this.$target_select);
            };
            /* #=============================================================================== */
            /* # Implement private functions */
            /* #=============================================================================== */
            _this.get_internal = function(selector) {
                var res = [];
                selector.find('option').each(function() {
                    res.push($(this).val());
                })
                return res;
            };
            _this.to_dict = function(list) {
                var res = {};
                for (var i in list) res[list[i]] = true;
                return res;
            }
            _this.update_lists = function(force_hilite_off) {
                var old;
                if (!force_hilite_off) {
                    old = [_this.to_dict(_this.get_internal(_this.$remaining_select)),
                           _this.to_dict(_this.get_internal(_this.$target_select))];
                }
                _this.$remaining_select.empty();
                _this.$target_select.empty();
                var lists = [_this._remaining_list, _this._target_list];
                var source = [_this.$remaining_select, _this.$target_select];
                for (var i in lists) {
                    for (var j in lists[i]) {
                        var e = lists[i][j];
                        if (e[1]) {
                            var selected = '';
                            if (!force_hilite_off && settings.hilite_selection && !old[i].hasOwnProperty(e[0].value)) {
                                selected = 'selected="selected"';
                            }
                            source[i].append('<option ' + selected + 'value=' + e[0].value + '>' + e[0].content + '</option>');
                        }
                    }
                }
                _this.$remaining_select.find('option').each(function() {
                    var inner = _this.$filter_input.val().toLowerCase();
                    var outer = $(this).html().toLowerCase();
                    if (outer.indexOf(inner) == -1) {
                        $(this).remove();
                    }
                })
            };
            _this.move_elems = function(values, b1, b2) {
                for (var i in values) {
                    val = values[i];
                    for (var j in _this._remaining_list) {
                        var e = _this._remaining_list[j];
                        if (e[0].value == val) {
                            e[1] = b1;
                            _this._target_list[j][1] = b2;
                        }
                    }
                }
                _this.update_lists(false);
            };
            _this.move_all = function(b1, b2) {
                for (var i in _this._remaining_list) {
                    _this._remaining_list[i][1] = b1;
                    _this._target_list[i][1] = b2;
                }
                _this.update_lists(false);
            };
            _this.data('bootstrapTransfer', _this);
            return _this;
        });
    };
    $.fn.bootstrapTransfer.defaults = {
        'template':
            '
\

\

\

\

\

Not Selected
\

\

\

\

\

\

\
                                \

\
                              <input class="form-control filter-input form-control" type="text" placeholder="Search..." />\

\

\

\

\

\
                      <select class="filtered remaining form-control" multiple=true></select>\

\

\
                      <btn class="btn btn-default selector-chooseall">\
                        Choose All\
                        \
                      </btn>\

\

\

\

\

\
                    <btn class="btn btn-default selector selector-add">\
                      \
                    </btn>\
                    <btn class="btn btn-default selector selector-remove">\
                      \
                    </btn>\

\

\

\

\

\

Selected
\

\

\
                      <select class="filtered target form-control" multiple=true></select>\

\

\
                        <btn class="btn btn-default selector-clearall">\
                          \
                          Clear All\
                        </btn>\

\

\

\

\

',
        'height': 15,
        'hilite_selection': true,
        'target_id': ''
    }
})(jQuery);<commit_msg>TTPLAT-247 split out districts in front-end and back-end, add new org fields<commit_after>(function($){
    $.fn.bootstrapTransfer = function(options) {
        var settings = $.extend({}, $.fn.bootstrapTransfer.defaults, options);
        var _this;
        /* #=============================================================================== */
        /* # Expose public functions */
        /* #=============================================================================== */
        this.populate = function(input) { _this.populate(input); };
        this.set_values = function(values) { _this.set_values(values); };
        this.get_values = function() { return _this.get_values(); };
        return this.each(function(){
            _this = $(this);
            /* #=============================================================================== */
            /* # Add widget markup */
            /* #=============================================================================== */
            _this.append($.fn.bootstrapTransfer.defaults.template);
            _this.addClass("bootstrap-transfer-container");
            /* #=============================================================================== */
            /* # Initialize internal variables */
            /* #=============================================================================== */
            _this.$filter_input = _this.find('.filter-input');
            _this.$remaining_select = _this.find('select.remaining');
            _this.$target_select = _this.find('select.target');
            _this.$add_btn = _this.find('.selector-add');
            _this.$remove_btn = _this.find('.selector-remove');
            _this.$choose_all_btn = _this.find('.selector-chooseall');
            _this.$clear_all_btn = _this.find('.selector-clearall');
            _this._remaining_list = [];
            _this._target_list = [];
            /* #=============================================================================== */
            /* # Apply settings */
            /* #=============================================================================== */
            /* target_id */
            if (settings.target_id != '') _this.$target_select.attr('id', settings.target_id);
            /* height */
            _this.find('select.remaining').css('height', settings.height + 'em');
            _this.find('select.target').css('height', settings.height + 4 + 'em');
            /* #=============================================================================== */
            /* # Wire internal events */
            /* #=============================================================================== */
            _this.$add_btn.click(function(){
                _this.move_elems(_this.$remaining_select.val(), false, true);
            });
            _this.$remove_btn.click(function(){
                _this.move_elems(_this.$target_select.val(), true, false);
            });
            _this.$choose_all_btn.click(function(){
                _this.move_all(false, true);
            });
            _this.$clear_all_btn.click(function(){
                _this.move_all(true, false);
            });
            _this.$filter_input.keyup(function(){
                _this.update_lists(true);
            });
            /* #=============================================================================== */
            /* # Implement public functions */
            /* #=============================================================================== */
            _this.populate = function(input) {
                // input: [{value:_, content:_}]
                _this.$filter_input.val('');
                for (var i in input) {
                    var e = input[i];
                    _this._remaining_list.push([{value:e.value, content:e.content}, true]);
                    _this._target_list.push([{value:e.value, content:e.content}, false]);
                }
                _this.update_lists(true);
            };
            _this.set_values = function(values) {
                _this.move_elems(values, false, true);
            };
            _this.get_values = function(){
                return _this.get_internal(_this.$target_select);
            };
            /* #=============================================================================== */
            /* # Implement private functions */
            /* #=============================================================================== */
            _this.get_internal = function(selector) {
                var res = [];
                selector.find('option').each(function() {
                    res.push($(this).val());
                })
                return res;
            };
            _this.to_dict = function(list) {
                var res = {};
                for (var i in list) res[list[i]] = true;
                return res;
            }
            _this.update_lists = function(force_hilite_off) {
                var old;
                if (!force_hilite_off) {
                    old = [_this.to_dict(_this.get_internal(_this.$remaining_select)),
                           _this.to_dict(_this.get_internal(_this.$target_select))];
                }
                _this.$remaining_select.empty();
                _this.$target_select.empty();
                var lists = [_this._remaining_list, _this._target_list];
                var source = [_this.$remaining_select, _this.$target_select];
                for (var i in lists) {
                    for (var j in lists[i]) {
                        var e = lists[i][j];
                        if (e[1]) {
                            var selected = '';
                            if (!force_hilite_off && settings.hilite_selection && !old[i].hasOwnProperty(e[0].value)) {
                                selected = 'selected="selected"';
                            }
                            source[i].append('<option ' + selected + 'value=' + e[0].value + '>' + e[0].content + '</option>');
                        }
                    }
                }
                _this.$remaining_select.find('option').each(function() {
                    var inner = _this.$filter_input.val().toLowerCase();
                    var outer = $(this).html().toLowerCase();
                    if (outer.indexOf(inner) == -1) {
                        $(this).remove();
                    }
                })
            };
            _this.move_elems = function(values, b1, b2) {
                for (var i in values) {
                    val = values[i];
                    for (var j in _this._remaining_list) {
                        var e = _this._remaining_list[j];
                        if (e[0].value == val) {
                            e[1] = b1;
                            _this._target_list[j][1] = b2;
                        }
                    }
                }
                _this.update_lists(false);
            };
            _this.move_all = function(b1, b2) {
                for (var i in _this._remaining_list) {
                    _this._remaining_list[i][1] = b1;
                    _this._target_list[i][1] = b2;
                }
                _this.update_lists(false);
            };
            _this.data('bootstrapTransfer', _this);
            return _this;
        });
    };
    $.fn.bootstrapTransfer.defaults = {
        'template':
            '
\

\

\

\

\

Not Selected
\

\

\

\

\

\

\
                                \

\
                              <input class="form-control filter-input form-control" type="text" placeholder="Search..." />\

\

\

\

\

\
                      <select class="filtered remaining form-control" multiple=true></select>\

\

\
                      <btn class="btn btn-default selector-chooseall">\
                        Choose All\
                        \
                      </btn>\

\

\

\

\

\
                    <btn class="btn btn-default selector selector-add">\
                      \
                    </btn>\
                    <btn class="btn btn-default selector selector-remove">\
                      \
                    </btn>\

\

\

\

\

\

Selected
\

\

\
                      <select class="filtered target form-control" multiple=true></select>\

\

\
                        <btn class="btn btn-default selector-clearall">\
                          \
                          Clear All\
                        </btn>\

\

\

\

\

',
        'height': 15,
        'hilite_selection': true,
        'target_id': ''
    }
})(jQuery);<|endoftext|>


<commit_before>/**
 * The TabsView view.
 *
 * @return TabsView view (extends Backbone.View)
 */
define([
  'underscore',
  'handlebars',
  'd3',
  'map/presenters/TabsPresenter',
  'map/views/tabs/AnalysisView',
  'map/views/tabs/CountriesView',
  'map/views/tabs/BasemapsView',
  'map/views/tabs/HighresolutionView',
  'map/views/tabs/SubscribeView',
  'views/ShareView',
  'text!map/templates/tabs.handlebars',
  'text!map/templates/tabs-mobile.handlebars'
], function(_, Handlebars, d3, Presenter, AnalysisView, CountriesView, BasemapsView, HighresolutionView, SubscribeView, ShareView, tpl, tplMobile) {

  'use strict';

  var TabsView = Backbone.View.extend({

    el: '#module-tabs',

    events: {
      'click .tab' : 'toggleTabs',
      'click .share-mobile' : 'toggleShareMobile',
      'click .tab-mobile' : 'toggleTabsMobile',
      'click .tab-mobile-close' : 'hideTabsMobile',
      'click .tab-mobile-reset-country' : 'resetCountry',
      'click ul' : 'checkForestChangeAvailability'
    },

    template: Handlebars.compile(tpl),
    templateMobile: Handlebars.compile(tplMobile),

    initialize: function(map, countries) {
      this.map = map;
      this.countries = countries;
      this.presenter = new Presenter(this);
      // Render
      enquire.register("screen and (min-width:"+window.gfw.config.GFW_MOBILE+"px)", {
        match: _.bind(function(){
          this.render();
          this.cacheVars();
        },this)
      });
      enquire.register("screen and (max-width:"+window.gfw.config.GFW_MOBILE+"px)", {
        match: _.bind(function(){
          this.renderMobile();
          this.cacheVars();
        },this)
      });
      // this.setListeners();
    },

    cacheVars: function(){
      this.$tabs = this.$el.find('.tab');
      this.$tabMobileButtons = $('.tab-mobile');
      this.$tabMobileBackButtons = $('.tab-mobile-back');
      this.$settingsTabButton = $('#settings-tab-button');
      this.$tabsMobileContent = this.$el.find('.tab-mobile-content');
      this.$tabsContent = this.$el.find('.tab-content');
      this.$container = this.$el.find('.content');
    },

    // setListeners: function(){

    // },

    render: function(){
      this.$el.html(this.template());
      this.$el.removeClass('hide');
      this.initCustomViews();
    },

    renderMobile: function(){
      this.$el.html(this.templateMobile());
      this.$el.removeClass('hide');
      this.initCustomViews();
    },

    initCustomViews: function(){
      new AnalysisView(this.map, this.countries);
      // new CountriesView(this.map, this.countries);
      new BasemapsView(this.map, this.countries);
      new HighresolutionView(this.map, this.countries);

      var subscribeView = new SubscribeView(this.map, this.countries);
      $('body').append(subscribeView.el);
    },

    toggleTabs: function(e){
      if ($(e.currentTarget).hasClass('active')) {
        // Close all tabs and reset tabs styles
        this.$container.removeClass('active')
        this.$tabs.removeClass('inactive active');
        this.$tabsContent.removeClass('selected');
      }else{
        if (!$(e.currentTarget).hasClass('disabled')) {
          // Open current tab
          var id = $(e.currentTarget).data('tab');
          this.$container.addClass('active');

          // tabs
          this.$tabs.removeClass('active').addClass('inactive');
          $(e.currentTarget).removeClass('inactive').addClass('active');

          // tabs content
          this.$tabsContent.removeClass('selected');
          $('#'+ id).addClass('selected');

          //publish open tab
          this.presenter.onTabOpen(id);
        }
      }
    },

    toggleShareMobile: function(event){
      var shareView = new ShareView().share(event);
      $('body').append(shareView.el);
    },

    toggleTabsMobile: function(e){
      var tab = $(e.currentTarget).data('tab');
      var $tab = $('#'+tab);
      if (tab) {
        this.$tabMobileBackButtons.data('tab', 'settings-tab-mobile');
        if ($tab.hasClass('active') || $(e.currentTarget).hasClass('active')) {
          this.$tabMobileButtons.removeClass('active');
          this.$tabsMobileContent.removeClass('active');
        }else{
          this.$tabMobileButtons.removeClass('active');
          this.$settingsTabButton.addClass('active');
          this.$tabsMobileContent.removeClass('active');
          $tab.addClass('active');
        }
      }else{
        this.hideTabsMobile();
      }
    },

    hideTabsMobile: function(){
      this.$settingsTabButton.removeClass('active');
      this.$tabMobileButtons.removeClass('active');
      this.$tabsMobileContent.removeClass('active');
      this.presenter.onTabMobileClose();
    },

    resetCountry: function() {
      this.presenter.publishIso({
        country: null,
        region: null
      });
    },

    toggleMobileLayers: function(){
      var $tab = $('#settings-tab-mobile');
      // this.$tabMobileButtons.removeClass('active');
      // this.$settingsTabButton.addClass('active');
      // this.$tabsMobileContent.removeClass('active');
      $tab.addClass('active');
    },

    openTab: function(id, backbutton){
      if (!$(id).hasClass('active')) {
        $(id).trigger('click');

        // To control back buttons
        // if (backbutton) { $(id+'-back').data('tab', null);}
      }
    },

    checkForestChangeAvailability: function(e) {
      // If the user clicks the analysis icon and having this LI item an EVENT POINTER NONE style attribute, what the user actually clicks is the UL
      if (e.target.tagName === 'UL' && $('#analysis-tab-button').hasClass('disabled')) {
        mps.publish('Notification/open', ['notification-select-forest-change-layer']);
      }
    }
  });

  return TabsView;

});
<commit_msg>Tabs: country tab only works on mobile devices<commit_after>/**
 * The TabsView view.
 *
 * @return TabsView view (extends Backbone.View)
 */
define([
  'underscore',
  'handlebars',
  'd3',
  'map/presenters/TabsPresenter',
  'map/views/tabs/AnalysisView',
  'map/views/tabs/CountriesView',
  'map/views/tabs/BasemapsView',
  'map/views/tabs/HighresolutionView',
  'map/views/tabs/SubscribeView',
  'views/ShareView',
  'text!map/templates/tabs.handlebars',
  'text!map/templates/tabs-mobile.handlebars'
], function(_, Handlebars, d3, Presenter, AnalysisView, CountriesView, BasemapsView, HighresolutionView, SubscribeView, ShareView, tpl, tplMobile) {

  'use strict';

  var TabsView = Backbone.View.extend({

    el: '#module-tabs',

    events: {
      'click .tab' : 'toggleTabs',
      'click .share-mobile' : 'toggleShareMobile',
      'click .tab-mobile' : 'toggleTabsMobile',
      'click .tab-mobile-close' : 'hideTabsMobile',
      'click .tab-mobile-reset-country' : 'resetCountry',
      'click ul' : 'checkForestChangeAvailability'
    },

    template: Handlebars.compile(tpl),
    templateMobile: Handlebars.compile(tplMobile),

    initialize: function(map, countries) {
      this.map = map;
      this.countries = countries;
      this.presenter = new Presenter(this);
      // Render
      enquire.register("screen and (min-width:"+window.gfw.config.GFW_MOBILE+"px)", {
        match: _.bind(function(){
          this.render();
          this.cacheVars();
        },this)
      });
      enquire.register("screen and (max-width:"+window.gfw.config.GFW_MOBILE+"px)", {
        match: _.bind(function(){
          this.renderMobile();
          this.cacheVars();
        },this)
      });
      // this.setListeners();
    },

    cacheVars: function(){
      this.$tabs = this.$el.find('.tab');
      this.$tabMobileButtons = $('.tab-mobile');
      this.$tabMobileBackButtons = $('.tab-mobile-back');
      this.$settingsTabButton = $('#settings-tab-button');
      this.$tabsMobileContent = this.$el.find('.tab-mobile-content');
      this.$tabsContent = this.$el.find('.tab-content');
      this.$container = this.$el.find('.content');
    },

    // setListeners: function(){

    // },

    render: function(){
      this.$el.html(this.template());
      this.$el.removeClass('hide');
      this.initCustomViews();
    },

    renderMobile: function(){
      this.$el.html(this.templateMobile());
      this.$el.removeClass('hide');
      this.initCustomViews();
    },

    initCustomViews: function(){
      new AnalysisView(this.map, this.countries);
      new CountriesView(this.map, this.countries);
      new BasemapsView(this.map, this.countries);
      new HighresolutionView(this.map, this.countries);

      var subscribeView = new SubscribeView(this.map, this.countries);
      $('body').append(subscribeView.el);
    },

    toggleTabs: function(e){
      if ($(e.currentTarget).hasClass('active')) {
        // Close all tabs and reset tabs styles
        this.$container.removeClass('active')
        this.$tabs.removeClass('inactive active');
        this.$tabsContent.removeClass('selected');
      }else{
        if (!$(e.currentTarget).hasClass('disabled')) {
          // Open current tab
          var id = $(e.currentTarget).data('tab');
          this.$container.addClass('active');

          // tabs
          this.$tabs.removeClass('active').addClass('inactive');
          $(e.currentTarget).removeClass('inactive').addClass('active');

          // tabs content
          this.$tabsContent.removeClass('selected');
          $('#'+ id).addClass('selected');

          //publish open tab
          this.presenter.onTabOpen(id);
        }
      }
    },

    toggleShareMobile: function(event){
      var shareView = new ShareView().share(event);
      $('body').append(shareView.el);
    },

    toggleTabsMobile: function(e){
      var tab = $(e.currentTarget).data('tab');
      var $tab = $('#'+tab);
      if (tab) {
        this.$tabMobileBackButtons.data('tab', 'settings-tab-mobile');
        if ($tab.hasClass('active') || $(e.currentTarget).hasClass('active')) {
          this.$tabMobileButtons.removeClass('active');
          this.$tabsMobileContent.removeClass('active');
        }else{
          this.$tabMobileButtons.removeClass('active');
          this.$settingsTabButton.addClass('active');
          this.$tabsMobileContent.removeClass('active');
          $tab.addClass('active');
        }
      }else{
        this.hideTabsMobile();
      }
    },

    hideTabsMobile: function(){
      this.$settingsTabButton.removeClass('active');
      this.$tabMobileButtons.removeClass('active');
      this.$tabsMobileContent.removeClass('active');
      this.presenter.onTabMobileClose();
    },

    resetCountry: function() {
      this.presenter.publishIso({
        country: null,
        region: null
      });
    },

    toggleMobileLayers: function(){
      var $tab = $('#settings-tab-mobile');
      // this.$tabMobileButtons.removeClass('active');
      // this.$settingsTabButton.addClass('active');
      // this.$tabsMobileContent.removeClass('active');
      $tab.addClass('active');
    },

    openTab: function(id, backbutton){
      if (!$(id).hasClass('active')) {
        $(id).trigger('click');

        // To control back buttons
        // if (backbutton) { $(id+'-back').data('tab', null);}
      }
    },

    checkForestChangeAvailability: function(e) {
      // If the user clicks the analysis icon and having this LI item an EVENT POINTER NONE style attribute, what the user actually clicks is the UL
      if (e.target.tagName === 'UL' && $('#analysis-tab-button').hasClass('disabled')) {
        mps.publish('Notification/open', ['notification-select-forest-change-layer']);
      }
    }
  });

  return TabsView;

});
<|endoftext|>


<commit_before>Namespaced.declare('Scheddo');

Scheddo.YammerApi = {
  userAccessToken: undefined,

  isYammerUser: function(){
    return typeof this.userAccessToken !== 'undefined';
  },

  setAccessToken: function(token){
    yam.request.setAuthenticator('oauth2');
    yam.request.getAuthenticator({ auth: 'oauth2' }).setAuthToken(token);
  },

  groupMessage: function(message, group_id){
    var flashMessage = function(div, flash) {
      return function(){
        Scheddo.Util.setFlash(div, flash);
      };
    };

    var options = {
      url: '/api/v1/messages.json',
      method: 'POST',
      data: {
        body: message,
        group_id: group_id
      },
      success: flashMessage('flash-notice', 'Thank you for sharing sched.do!'),
      error: flashMessage('flash-error', 'There was an error with the request')
    };

    yam.request(options);
  },

  publicMessage: function(message){
    var flashMessage = function(div, flash) {
      return function(){
        Scheddo.Util.setFlash(div, flash);
      };
    };

    var options = {
      url: '/api/v1/messages.json',
      method: 'POST',
      data: { body: message },
      success: flashMessage('flash-notice', 'Thank you for sharing sched.do!'),
      error: flashMessage('flash-error', 'There was an error with the request')
    };

    yam.request(options);
  },

  getGroups: function(callback){
    var options = {
      url: '/api/v1/groups.json',
      method: 'GET',
      success: function(yammerData){
        groups = _.map(
          yammerData,
          Scheddo.Translators.translateGroup
        );
        callback(groups);
      }
    };

    yam.request(options);
  },

  autocomplete: function(translator){
    var maxGroupsReturned = 2;
    return {
      ranked: function(term, response, maxUsersReturned){
        if(typeof maxUsersReturned === 'undefined') {
          maxUsersReturned = 3
        };

        var options = {
          url: '/api/v1/autocomplete/ranked',
          method: 'GET',
          data: {
            prefix: term,
            models: 'user:' + maxUsersReturned + ',group:' + maxGroupsReturned},
          success: translator.normalizeTranslatedResponse(term, response)
        };

        yam.request(options);
      }
    }
  }
};
<commit_msg>Fix to use the yam.platform.request instead of yam.request<commit_after>Namespaced.declare('Scheddo');

Scheddo.YammerApi = {
  userAccessToken: undefined,

  isYammerUser: function(){
    return typeof this.userAccessToken !== 'undefined';
  },

  setAccessToken: function(token){
    yam.request.setAuthenticator('oauth2');
    yam.request.getAuthenticator({ auth: 'oauth2' }).setAuthToken(token);
  },

  groupMessage: function(message, group_id){
    var flashMessage = function(div, flash) {
      return function(){
        Scheddo.Util.setFlash(div, flash);
      };
    };

    var options = {
      url: '/api/v1/messages.json',
      method: 'POST',
      data: {
        body: message,
        group_id: group_id
      },
      success: flashMessage('flash-notice', 'Thank you for sharing sched.do!'),
      error: flashMessage('flash-error', 'There was an error with the request')
    };

    yam.platform.request(options);
  },

  publicMessage: function(message){
    var flashMessage = function(div, flash) {
      return function(){
        Scheddo.Util.setFlash(div, flash);
      };
    };

    var options = {
      url: '/api/v1/messages.json',
      method: 'POST',
      data: { body: message },
      success: flashMessage('flash-notice', 'Thank you for sharing sched.do!'),
      error: flashMessage('flash-error', 'There was an error with the request')
    };

    yam.platform.request(options);
  },

  getGroups: function(callback){
    var options = {
      url: '/api/v1/groups.json',
      method: 'GET',
      success: function(yammerData){
        groups = _.map(
          yammerData,
          Scheddo.Translators.translateGroup
        );
        callback(groups);
      }
    };

    yam.platform.request(options);
  },

  autocomplete: function(translator){
    var maxGroupsReturned = 2;
    return {
      ranked: function(term, response, maxUsersReturned){
        if(typeof maxUsersReturned === 'undefined') {
          maxUsersReturned = 3
        };

        var options = {
          url: '/api/v1/autocomplete/ranked',
          method: 'GET',
          data: {
            prefix: term,
            models: 'user:' + maxUsersReturned + ',group:' + maxGroupsReturned},
          success: translator.normalizeTranslatedResponse(term, response)
        };

        yam.platform.request(options);
      }
    }
  }
};
<|endoftext|>


<commit_before>'use strict';
import React from 'react';
import { formatThousands } from '../utils/format';

var PageFooter = React.createClass({
  displayName: 'PageFooter',

  propTypes: {
    measurements: React.PropTypes.number
  },
  render: function () {
    let copyright = this.props.measurements !== null
      ? `${formatThousands(this.props.measurements)} measurements captured`
      : 'Built';

    return (

Connect with us

Github

Slack

Twitter

Email

Subscribe to our newsletter

                <input type='text' placeholder='bruce@wayne.com' className='form__control form__control--medium' />
                <button className='button--subscribe' type='submit'>Subscribe</button>

            {copyright} with love by Development Seed and the OpenAQ team.

    );
  }
});

module.exports = PageFooter;
<commit_msg>Connect mailchimp newsletter form<commit_after>'use strict';
import React from 'react';
import { formatThousands } from '../utils/format';

var PageFooter = React.createClass({
  displayName: 'PageFooter',

  propTypes: {
    measurements: React.PropTypes.number
  },
  render: function () {
    let copyright = this.props.measurements !== null
      ? `${formatThousands(this.props.measurements)} measurements captured`
      : 'Built';

    return (

Connect with us

Github

Slack

Twitter

Email

Subscribe to our newsletter

              <form ref='newsletterForm' action='//openaq.us10.list-manage.com/subscribe/post?u=ca93b2911fff40db15f6e7203&id=e65a8618a1' method='post' id='mc-embedded-subscribe-form' name='mc-embedded-subscribe-form' target='_blank' noValidate>

                  <input type='email' name='EMAIL' id='mce-EMAIL' placeholder='bruce@wayne.com' className='form__control form__control--medium' required/>
                  <button className='button--subscribe' type='submit' onClick={() => this.refs.newsletterForm.reset()}>Subscribe</button>

                {/* real people should not fill this in and expect good things - do not remove this or risk form bot signups */}

                  <input type='text' name='b_ca93b2911fff40db15f6e7203_e65a8618a1' tabIndex='-1' value='' />

              </form>

            {copyright} with love by Development Seed and the OpenAQ team.

    );
  }
});

module.exports = PageFooter;
<|endoftext|>