<commit_before>// Requiring and exporting JSUS
var JSUS = require('./../node_modules/JSUS').JSUS;
module.exports.JSUS = JSUS;

var util = require('util'),
fs = require('fs'),
path = require('path'),
should = require('should'),
NDDB = require('./../index').NDDB;

var db, db2;
var options;

var filename = {
    standard: __dirname + '/data.csv',
    escapeTesting: __dirname + '/data.escapetest.csv',
    simon: __dirname + '/data.simon.csv'
};

var lastItem = {
    A: "10",
    B: "11",
    C: "12",
    D: "Z4"
};

var lastItemUnescaped = {
    '"A"': '"10"',
    '"B"': '"11"',
    '"C"': '"12"',
    '"D"': '"Z4"'
};

// To be used. Maybe.
var items = [
    {
        id: '123456',
        time: '098765',
        data: {
            a: 1,
            b: 2,
            c: "the butler said: \"ah.\""
        }
    },
    {
        id: '123456',
        time: '098765',
        data: {
            a: 1,
            b: 2,
            c: 'the butler said: "ah, not now."'
        },
    },
];

function getTests(m, it) {

    var db;

    it('should ' + m + ' a csv file with default options', function(done) {
        db = new NDDB();
        db[m](filename.standard, function() {
            db.size().should.eql(4);
            db.last().should.be.eql(lastItem);
            done();
        });

    });

    it('should ' + m + ' a csv file with empty options', function(done) {
        db = new NDDB();
        db[m](filename.standard, {}, function() {
            db.size().should.eql(4);
            db.last().should.be.eql(lastItem);
            done();
        });
    });

    it('should ' + m + ' a csv file with without quotes', function(done) {
        db = new NDDB();
        options = {
            quote: '-'
        };
        db[m](filename.standard, options, function() {
            db.size().should.eql(4);
            db.last().should.be.eql(lastItemUnescaped);
            done();
        });
    });
    it('should ' + m + ' a csv file with pre-defined headers', function(done) {

        db = new NDDB();
        options = {
            headers: ['q', 'w', 'e', 'r']
        };
        db[m](filename.standard, options, function() {
            db.size().should.eql(5);
            db.first().should.be.eql({
                q: 'A',
                w: 'B',
                e: 'C',
                r: 'D'
            });
            db.last().should.be.eql({
                q: "10",
                w: "11",
                e: "12",
                r: "Z4"
            });
            done();
        });
    });

    it('should ' + m + ' a csv file with default options and unescape '
    +'separators, quotes and escape characters, and handle \n', function(done) {
        db = new NDDB();
        db[m](filename.simon, function() {
            db.size().should.eql(3);
            db.first().should.be.eql({
                // Sentence containing tab, quote, seperator, linebreak and
                //  escape.
                Messages: 'Simon:\t"How are you, Stacey?"\nStacey:\t"\\o.o/"',
                TimeStamp: '16/3/8:2132'
            });
            db.next().should.be.eql({
                Messages: 'Simon: "Are you coming Saturday?"',
                TimeStamp: '16/3/8:2134'
            });
            db.next().should.be.eql({
                Messages: 'Stacey: "Yeah, sure \\P"',
                TimeStamp: '16/3/8:2139'
            });
            done();
        });

    });

   it('should ' + m + ' a csv file with pre-defined adapter', function(done) {
        db = new NDDB();
        options = {
            headers: ['q', 'w', 'e', 'r']
        };
        db[m](filename.standard, options, function() {
            db.size().should.eql(5);
            db.first().should.be.eql({
                q: 'A',
                w: 'B',
                e: 'C',
                r: 'D'
            });
            db.last().should.be.eql({
                q: "10",
                w: "11",
                e: "12",
                r: "Z4"
            });
            done();
        });
    });

    it('should ' + m + ' a csv file with def. options and unescape separators',
       function(done) {
           db = new NDDB();
           db[m](filename.escapeTesting, function() {
               db.size().should.eql(4);
               db.first();
               db.next();
               db.next().should.be.eql({
                   A: '7,5',
                   B: '8',
                   C: '9',
                   D: 'Z3'
               });
               done();
           });

       });
}

function getSaveTests(m, it) {

    it('should load, ' + m + ', and reload a csv file', function(done) {
        db = new NDDB();
        db.load(filename.standard, function() {
            db.size().should.eql(4);
            db2 = new NDDB();
            db[m](__dirname + '/data.currenttest.csv', function() {
                db2.load(__dirname + '/data.currenttest.csv', function() {
                    db2.size().should.eql(4);
                    db2.last().should.be.eql(lastItem);
                    done();
                });
            });
        });
    });
}

describe('#load(".csv")', function() {
    getTests('load', it);
});

describe('#loadSync(".csv")', function() {
    getTests('loadSync', it);
});

describe('#save(".csv")', function() {
    getSaveTests('save', it);
});

describe('#saveSync(".csv")', function() {
    getSaveTests('saveSync', it);
});
<commit_msg>Added adapter test (fails);<commit_after>// Requiring and exporting JSUS
var JSUS = require('./../node_modules/JSUS').JSUS;
module.exports.JSUS = JSUS;

var util = require('util'),
fs = require('fs'),
path = require('path'),
should = require('should'),
NDDB = require('./../index').NDDB;

var db, db2;
var options;

var filename = {
    standard: __dirname + '/data.csv',
    escapeTesting: __dirname + '/data.escapetest.csv',
    simon: __dirname + '/data.simon.csv'
};

var lastItem = {
    A: "10",
    B: "11",
    C: "12",
    D: "Z4"
};

var lastItemUnescaped = {
    '"A"': '"10"',
    '"B"': '"11"',
    '"C"': '"12"',
    '"D"': '"Z4"'
};

// To be used. Maybe.
var items = [
    {
        id: '123456',
        time: '098765',
        data: {
            a: 1,
            b: 2,
            c: "the butler said: \"ah.\""
        }
    },
    {
        id: '123456',
        time: '098765',
        data: {
            a: 1,
            b: 2,
            c: 'the butler said: "ah, not now."'
        },
    },
];

function getTests(m, it) {

    var db;

    it('should ' + m + ' a csv file with default options', function(done) {
        db = new NDDB();
        db[m](filename.standard, function() {
            db.size().should.eql(4);
            db.last().should.be.eql(lastItem);
            done();
        });

    });

    it('should ' + m + ' a csv file with empty options', function(done) {
        db = new NDDB();
        db[m](filename.standard, {}, function() {
            db.size().should.eql(4);
            db.last().should.be.eql(lastItem);
            done();
        });
    });

    it('should ' + m + ' a csv file with without quotes', function(done) {
        db = new NDDB();
        options = {
            quote: '-'
        };
        db[m](filename.standard, options, function() {
            db.size().should.eql(4);
            db.last().should.be.eql(lastItemUnescaped);
            done();
        });
    });
    it('should ' + m + ' a csv file with pre-defined headers', function(done) {

        db = new NDDB();
        options = {
            headers: ['q', 'w', 'e', 'r']
        };
        db[m](filename.standard, options, function() {
            db.size().should.eql(5);
            db.first().should.be.eql({
                q: 'A',
                w: 'B',
                e: 'C',
                r: 'D'
            });
            db.last().should.be.eql({
                q: "10",
                w: "11",
                e: "12",
                r: "Z4"
            });
            done();
        });
    });

    it('should ' + m + ' a csv file with default options and unescape '
    +'separators, quotes and escape characters, and handle \n', function(done) {
        db = new NDDB();
        db[m](filename.simon, function() {
            db.size().should.eql(3);
            db.first().should.be.eql({
                // Sentence containing tab, quote, seperator, linebreak and
                //  escape.
                Messages: 'Simon:\t"How are you, Stacey?"\nStacey:\t"\\o.o/"',
                TimeStamp: '16/3/8:2132'
            });
            db.next().should.be.eql({
                Messages: 'Simon: "Are you coming Saturday?"',
                TimeStamp: '16/3/8:2134'
            });
            db.next().should.be.eql({
                Messages: 'Stacey: "Yeah, sure \\P"',
                TimeStamp: '16/3/8:2139'
            });
            done();
        });

    });

   it('should ' + m + ' a csv file with pre-defined adapter', function(done) {
        var options;

        // Doubles all floats
        options = {
            adapter: function(input) {
                var out;
                // Convert to number
                out = parseFloat(input);
                return (isNaN(out) ? input : 2*out + "");
            },
            headers: ['q', 'w', 'e', 'r']
        };

        db = new NDDB();

        db[m](filename.standard, options, function() {
            db.size().should.eql(5);
            db.first().should.be.eql({
                q: 'A',
                w: 'B',
                e: 'C',
                r: 'D'
            });
            db.last().should.be.eql({
                q: "20",
                w: "22",
                e: "24",
                r: "Z4"
            });
            done();
        });
    });

    it('should ' + m + ' a csv file with def. options and unescape separators',
       function(done) {
           db = new NDDB();
           db[m](filename.escapeTesting, function() {
               db.size().should.eql(4);
               db.first();
               db.next();
               db.next().should.be.eql({
                   A: '7,5',
                   B: '8',
                   C: '9',
                   D: 'Z3'
               });
               done();
           });

       });
}

function getSaveTests(m, it) {

    it('should load, ' + m + ', and reload a csv file', function(done) {
        db = new NDDB();
        db.load(filename.standard, function() {
            db.size().should.eql(4);
            db2 = new NDDB();
            db[m](__dirname + '/data.currenttest.csv', function() {
                db2.load(__dirname + '/data.currenttest.csv', function() {
                    db2.size().should.eql(4);
                    db2.last().should.be.eql(lastItem);
                    done();
                });
            });
        });
    });
}

describe('#load(".csv")', function() {
    getTests('load', it);
});

describe('#loadSync(".csv")', function() {
    getTests('loadSync', it);
});

describe('#save(".csv")', function() {
    getSaveTests('save', it);
});

describe('#saveSync(".csv")', function() {
    getSaveTests('saveSync', it);
});
<|endoftext|>


<commit_before>$(document).ready(function() {
  if (!swfobject.hasFlashPlayerVersion("9.0.18")) {
    $(".alt-invite").hide();
    $("#invitations").css("margin-right", 0)
  }
  var table = $('table.touch-scrollable');
  var parent = $('table.touch-scrollable').parent();

  // Scroll Notice
  var scrollNotice = $('div.scroll-notice')
  var scrollRight = $('div.scroll-notice.forward')
  var scrollLeft = $('div.scroll-notice.backward')

  var getCurrentOffset = function() {
    var totalOffset = table.width() - parent.innerWidth();
    var currentOffset = (totalOffset - parent.scrollLeft())

    return { total: totalOffset, current: currentOffset };
  }

  var setLabel = function() {
    var offsets = getCurrentOffset()

    if (offsets.total > 0) {
      scrollNotice.addClass('visible');
      if (offsets.current === 0) {
        scrollRight.removeClass('visible');
      } else if (offsets.current === offsets.total) {
        scrollLeft.removeClass('visible');
      }
    }
  };

  setLabel();

  scrollNotice.click(function() {
    var offsets = getCurrentOffset()
    var isRight = $(this).is('.forward');
    var distanceToScroll = isRight ? offsets.current + (offsets.total - offsets.current) : 0;

    parent.animate({ scrollLeft: distanceToScroll }, 300);
  });

  parent.scroll(function() {
    setLabel();
  });

  $(window).resize(function() {
    setLabel();
  });

  // Editable Event Name
  $('.event-name.editable h1').click(function(){
    $(this).hide();
    $('.event-name input').show().focus();
  });

  $('.event-name.editable input').blur(function(){
    $.ajax(
      {
        type: 'PUT',
        dataType:'json',
        url: document.URL,
        data: { event: { name: $(this).val() } },
      }
      ).success(function(){
          $('.event-name h1').text($('.event-name input').val());
          $('.event-name input').hide();
          $('.event-name h1').show();
        }
        );

  })
});
<commit_msg>Remove extra newline<commit_after>$(document).ready(function() {
  if (!swfobject.hasFlashPlayerVersion("9.0.18")) {
    $(".alt-invite").hide();
    $("#invitations").css("margin-right", 0)
  }
  var table = $('table.touch-scrollable');
  var parent = $('table.touch-scrollable').parent();

  // Scroll Notice
  var scrollNotice = $('div.scroll-notice')
  var scrollRight = $('div.scroll-notice.forward')
  var scrollLeft = $('div.scroll-notice.backward')

  var getCurrentOffset = function() {
    var totalOffset = table.width() - parent.innerWidth();
    var currentOffset = (totalOffset - parent.scrollLeft())

    return { total: totalOffset, current: currentOffset };
  }

  var setLabel = function() {
    var offsets = getCurrentOffset()

    if (offsets.total > 0) {
      scrollNotice.addClass('visible');
      if (offsets.current === 0) {
        scrollRight.removeClass('visible');
      } else if (offsets.current === offsets.total) {
        scrollLeft.removeClass('visible');
      }
    }
  };

  setLabel();

  scrollNotice.click(function() {
    var offsets = getCurrentOffset()
    var isRight = $(this).is('.forward');
    var distanceToScroll = isRight ? offsets.current + (offsets.total - offsets.current) : 0;

    parent.animate({ scrollLeft: distanceToScroll }, 300);
  });

  parent.scroll(function() {
    setLabel();
  });

  $(window).resize(function() {
    setLabel();
  });

  // Editable Event Name
  $('.event-name.editable h1').click(function(){
    $(this).hide();
    $('.event-name input').show().focus();
  });

  $('.event-name.editable input').blur(function(){
    $.ajax(
      {
        type: 'PUT',
        dataType:'json',
        url: document.URL,
        data: { event: { name: $(this).val() } },
      }
      ).success(function(){
          $('.event-name h1').text($('.event-name input').val());
          $('.event-name input').hide();
          $('.event-name h1').show();
        }
        );

  })
});
<|endoftext|>


<commit_before>//= require introjs

L.easyButton('fa-question-circle', function(btn, map) {
  introJs().setOption('showProgress', true)
  .setOption("nextLabel", " Próximo ")
  .setOption("prevLabel", "Anterior")
  .setOption("skipLabel", "Fechar")
  .setOption("showStepNumbers", false).start();
}).addTo(map);

$(".leaflet-control-zoom")
  .attr("data-intro", "Oi")
  .attr("data-step", "3")
  .attr("data-position", "auto");
$(".leaflet-bar.easy-button-container.leaflet-control").eq(0)
  .attr("data-intro", "Rota")
  .attr("data-step", "4")
  .attr("data-position", "auto");
  $(".leaflet-bar.easy-button-container.leaflet-control").eq(1)
    .attr("data-intro", "Rota")
    .attr("data-step", "6")
    .attr("data-position", "auto");
$(".leaflet-control-layers.leaflet-control")
  .attr("data-intro", "Filtro")
  .attr("data-step", "5")
  .attr("data-position", "auto");

  introJs().setOption('showProgress', true)
  .setOption("nextLabel", " Próximo ")
  .setOption("prevLabel", "Anterior")
  .setOption("skipLabel", "Fechar")
  .setOption("showStepNumbers", false).start();
<commit_msg>Creating local storage for tutorial<commit_after>//= require introjs

var introJs = introJs().setOption("nextLabel", " Próximo ")
.setOption("prevLabel", "Anterior")
.setOption("skipLabel", "Fechar")
.setOption("doneLabel", "Fechar")
.setOption("showStepNumbers", false);

L.easyButton('fa-question-circle', function(btn, map) {
  introJs.start();
}).addTo(map);

$(".navbar")
  .attr("data-intro",
  "
Welcome!
 ao Onde é? Unb Aqui iremos mostrar como utilizar o nosso site")
  .attr("data-step", "1")
  .attr("data-tooltipClass", "tutorialStyle")
  .attr("data-position", "auto");
$("#searchContainer")
  .attr("data-intro",
  "Aqui é possível pesquisar qualquer prédio, sala e departamento")
  .attr("data-step", "2")
  .attr("data-position", "auto");
$(".leaflet-control-zoom")
  .attr("data-intro", "Oi")
  .attr("data-step", "3")
  .attr("data-position", "auto");
$(".leaflet-bar.easy-button-container.leaflet-control").eq(0)
  .attr("data-intro", "Rota")
  .attr("data-step", "4")
  .attr("data-position", "auto");
$(".leaflet-control-layers.leaflet-control")
  .attr("data-intro", "Filtro")
  .attr("data-step", "5")
  .attr("data-position", "auto");
$(".leaflet-bar.easy-button-container.leaflet-control").eq(1)
  .attr("data-intro", "Rota")
  .attr("data-step", "6")
  .attr("data-position", "auto");
$(".leaflet-contextmenu")
  .attr("data-intro", "Context")
  .attr("data-step", "7")
  .attr("data-position", "auto");
$(".leaflet-bar.easy-button-container.leaflet-control").eq(1)
  .attr("data-intro", "Botão Tutorial")
  .attr("data-step", "8")
  .attr("data-position", "auto");

introJs.oncomplete(function() {
  map.contextmenu.hide();
  localStorage.setItem("hideTutorial", true);
});
introJs.onexit(function(){
  localStorage.setItem("hideTutorial", true);
});

window.addEventListener("load", function() {
  if(!localStorage.hasOwnProperty('hideTutorial')){
    introJs.start();
  }
});

introJs.onchange(function(element){
  var step = $(element).data("step");
  if (step == 7){
    var center = map.getCenter();
    map.contextmenu.showAt(center);
  } else {
    map.contextmenu.hide();
  }
});
<|endoftext|>


<commit_before>$(document).on("turbolinks:load", function() {

    //set to true after we've initialised the page
    var initialised = false;

    //template used to explain the graphs
    var explainTemplate = Handlebars.compile("Graphing {{supply}} consumption on {{first_date}} " +
        "{{#if whole_school}}{{#if second_date}}and {{second_date}}{{/if}}{{/if}}" +
        " for {{first_meter}}{{#unless whole_school}}{{#if second_meter}} and {{second_meter}}{{/if}}{{/unless}}.");
    //template for updating data availability
    var dataRangesTemplate = Handlebars.compile("{{supply }} data is available from {{min}} to {{max}}");

    //explain the current state of the form, to help explain what the graph is currently showing
    function explain() {
        whole_school = $("input[type=radio][name=compare]:checked").val() == "whole-school";
        first_meter = whole_school ? $("#whole-school #meter option:selected").text() : $("#within-school #meter option:selected").text();
        first_date = whole_school ? $("#whole-school #first-date-picker").val() : $("#within-school #first-date-picker").val()
        data = {
            whole_school: whole_school,
            supply: $("#supply").val(),
            first_meter: first_meter,
            second_meter: $("#second_meter option:selected").val() == "" ? null : $("#second_meter option:selected").text(),
            school: $("#school").html(),
            homepage: $("#school").attr("href"),
            first_date: first_date,
            second_date: $("#to-date-picker").val() == "" ? null : $("#to-date-picker").val()
        };
        $("#graph-explainer").html( explainTemplate(data) );
    }

    //create a Cdate object used by the calendar picker
    //have to use these objects when setting min/max dates when using a custom data format
    function datetoCdate(date) {
        parts = date.split("-");
        if (parts.length < 3) {
            return null;
        }
        return $.calendars.newDate(parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2]))
    }

    //called by event handlers that need to update the graph
    //they should have already made any changes to the form we're using, so this just updates
    //the explanation and then triggers the data load
    function updateChart(el) {
        explain();
        chart = Chartkick.charts["chart"];
        current_source = chart.getDataSource();
        new_source = current_source.split("?")[0] + "?" + $(el.form).serialize();
        chart.updateData(new_source);
        if (chart.getChartObject()) {
            chart.getChartObject().showLoading();
        }
    }

    //ensure that the user can only select those meters which are for the currently
    //selected supply
    function enableMeters(supply, force) {
        if (supply == "electricity") {
            $("option[data-supply-type='gas']").hide();
            $("option[data-supply-type='electricity']").show();

        } else {
            $("option[data-supply-type='electricity']").hide();
            $("option[data-supply-type='gas']").show();
        }
        if (force == true) {
            //when switching, reset state, so select all meters and no second selection
            $(".meter-filter option[value='all']").prop("selected", true);
            $("#second_meter option:first").prop("selected", true);

            $("#first-meter").val($("#meter").val());
        }
    }

    //set the minimum and maximum selectable dates in the calendar pickers
    //the dates may vary based on the supply
    //if the currently selected date is greater (or lower) than the new min/max
    //then the dates are updated. otherwise the control sets an empty value
    function setMinMaxDates(supply) {
        min = datetoCdate( $("#" + supply + "-start").attr("data-date") );
        max = datetoCdate( $("#" + supply + "-end").attr("data-date") );

        //just in case date isn't valid
        if (min == null || max == null) {
            return;
        }

        $("#data-availability").html( dataRangesTemplate({
            supply: $("input[type=radio][name=supplyType]:checked").parent("label").text(),
            min: min.formatDate('DD, d MM yyyy'),
            max: max.formatDate('DD, d MM yyyy')
        }));

        $(".date-picker").each(function() {
            selected_date = $(this).calendarsPicker("getDate");
            if (selected_date.length > 0 && selected_date > max) {
                $(this).calendarsPicker("setDate", max);
            }
            if (selected_date.length > 0 && selected_date < min) {
                $(this).calendarsPicker("setDate", min);
            }
            $(this).calendarsPicker("option", {
                minDate: min,
                maxDate: max
            });
        });
    }

    //Initialise this page
    if ($(".charts").length > 0) {
        console.log("init function");
        supply = $("input[name=supplyType]:checked").val();

        $(".first-date-picker").each( function() {
            $(this).calendarsPicker({
                dateFormat: 'DD, d MM yyyy',
                defaultDate: datetoCdate( $("#first-date").val() ),
                selectDefaultDate: true,
                onSelect: function(dates) {
                    console.log("select first-date");
                    $("#first-date").val(dates);
                    if (initialised) updateChart(this);
                }
            });
        });

        $(".to-date-picker").each( function() {
            $(this).calendarsPicker({
                dateFormat: 'DD, d MM yyyy',
                defaultDate: datetoCdate( $("#to-date").val() ),
                selectDefaultDate: true,
                onSelect: function(dates) {
                    console.log("select second-date");
                    $("#to-date").val(dates);
                    if (initialised) updateChart(this);
                }
            });
        });

        setMinMaxDates(supply);
        enableMeters(supply, false);
        explain();
        console.log("done");
        initialised = true;
    }

    //TODO tidy up the code
    $(document).on('change', 'input[type=radio][name=supplyType]', function() {
        initialised = false;
        if (this.value == 'electricity') {
            $(".card").removeClass("gas-card");

            $("div.indicator-light").removeClass("gas-light");
            $("div.indicator-light").addClass("electricity-light");
            $("div.indicator-dark").removeClass("gas-dark");
            $("div.indicator-dark").addClass("electricity-dark");

            $("#gas-interpretation").hide();
            $("#electricity-interpretation").show();

            $(".card").addClass("electricity-card");
        } else {
            $("option[data-supply-type='electricity']").hide();
            $("option[data-supply-type='gas']").show();

            $(".card").removeClass("electricity-card");

            $("div.indicator-light").removeClass("electricity-light");
            $("div.indicator-light").addClass("gas-light");
            $("div.indicator-dark").removeClass("electricity-dark");
            $("div.indicator-dark").addClass("gas-dark");

            $("#electricity-interpretation").hide();
            $("#gas-interpretation").show();

            $(".card").addClass("gas-card");
        }
        //after we've changed supply we need to ensure min/max dates are
        //correct, and that only the correct meters are enabled
        $("#supply").val(this.value);
        enableMeters(this.value, true);
        setMinMaxDates(this.value);
        updateChart(this);
        initialised = true;
    });

    $(document).on('change', 'input[type=radio][name=compare]', function() {
        if (this.value === "within-school") {
            $("#comparison").val("within-school");
            $("#whole-school").hide();
            $("#within-school").show();
            $("#first-meter").val($("#within-school #meter").val());
            $("#first-date").val($("#within-school #first-date-picker").val());

        } else {
            $("#comparison").val("whole-school");
            $("#within-school").hide();
            $("#whole-school").show();
            $("#first-meter").val($("#whole-school #meter").val());
            $("#first-date").val($("#whole-school #first-date-picker").val());

        }
        explain();
        updateChart(this);
    });

    $(document).on('change', '.meter-filter', function() {
        $("#first-meter").val($(this).val());
        updateChart(this);
    });

    $(document).on('change', '.second-meter-filter', function() {
        $("#second-meter").val($(this).val());
        updateChart(this);
    });

});

<commit_msg>Force colours as column chart doesn't switch properly based on json config<commit_after>$(document).on("turbolinks:load", function() {

    //set to true after we've initialised the page
    var initialised = false;

    //template used to explain the graphs
    var explainTemplate = Handlebars.compile("Graphing {{supply}} consumption on {{first_date}} " +
        "{{#if whole_school}}{{#if second_date}}and {{second_date}}{{/if}}{{/if}}" +
        " for {{first_meter}}{{#unless whole_school}}{{#if second_meter}} and {{second_meter}}{{/if}}{{/unless}}.");
    //template for updating data availability
    var dataRangesTemplate = Handlebars.compile("{{supply }} data is available from {{min}} to {{max}}");

    //explain the current state of the form, to help explain what the graph is currently showing
    function explain() {
        whole_school = $("input[type=radio][name=compare]:checked").val() == "whole-school";
        first_meter = whole_school ? $("#whole-school #meter option:selected").text() : $("#within-school #meter option:selected").text();
        first_date = whole_school ? $("#whole-school #first-date-picker").val() : $("#within-school #first-date-picker").val()
        data = {
            whole_school: whole_school,
            supply: $("#supply").val(),
            first_meter: first_meter,
            second_meter: $("#second_meter option:selected").val() == "" ? null : $("#second_meter option:selected").text(),
            school: $("#school").html(),
            homepage: $("#school").attr("href"),
            first_date: first_date,
            second_date: $("#to-date-picker").val() == "" ? null : $("#to-date-picker").val()
        };
        $("#graph-explainer").html( explainTemplate(data) );
    }

    //create a Cdate object used by the calendar picker
    //have to use these objects when setting min/max dates when using a custom data format
    function datetoCdate(date) {
        parts = date.split("-");
        if (parts.length < 3) {
            return null;
        }
        return $.calendars.newDate(parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2]))
    }

    //called by event handlers that need to update the graph
    //they should have already made any changes to the form we're using, so this just updates
    //the explanation and then triggers the data load
    function updateChart(el) {
        explain();
        if ($("#supply").val() == "electricity") {
            colors = ["#3bc0f0","#232b49"]
        } else {
            colors = ["#ffac21", "#ff4500"]
        }
        chart = Chartkick.charts["chart"];
        current_source = chart.getDataSource();
        new_source = current_source.split("?")[0] + "?" + $(el.form).serialize();
        chart.updateData(new_source, {colors: colors});
        if (chart.getChartObject()) {
            chart.getChartObject().showLoading();
        }
    }

    //ensure that the user can only select those meters which are for the currently
    //selected supply
    function enableMeters(supply, force) {
        if (supply == "electricity") {
            $("option[data-supply-type='gas']").hide();
            $("option[data-supply-type='electricity']").show();

        } else {
            $("option[data-supply-type='electricity']").hide();
            $("option[data-supply-type='gas']").show();
        }
        if (force == true) {
            //when switching, reset state, so select all meters and no second selection
            $(".meter-filter option[value='all']").prop("selected", true);
            $("#second_meter option:first").prop("selected", true);

            $("#first-meter").val($("#meter").val());
        }
    }

    //set the minimum and maximum selectable dates in the calendar pickers
    //the dates may vary based on the supply
    //if the currently selected date is greater (or lower) than the new min/max
    //then the dates are updated. otherwise the control sets an empty value
    function setMinMaxDates(supply) {
        min = datetoCdate( $("#" + supply + "-start").attr("data-date") );
        max = datetoCdate( $("#" + supply + "-end").attr("data-date") );

        //just in case date isn't valid
        if (min == null || max == null) {
            return;
        }

        $("#data-availability").html( dataRangesTemplate({
            supply: $("input[type=radio][name=supplyType]:checked").parent("label").text(),
            min: min.formatDate('DD, d MM yyyy'),
            max: max.formatDate('DD, d MM yyyy')
        }));

        $(".date-picker").each(function() {
            selected_date = $(this).calendarsPicker("getDate");
            if (selected_date.length > 0 && selected_date > max) {
                $(this).calendarsPicker("setDate", max);
            }
            if (selected_date.length > 0 && selected_date < min) {
                $(this).calendarsPicker("setDate", min);
            }
            $(this).calendarsPicker("option", {
                minDate: min,
                maxDate: max
            });
        });
    }

    //Initialise this page
    if ($(".charts").length > 0) {
        console.log("init function");
        supply = $("input[name=supplyType]:checked").val();

        $(".first-date-picker").each( function() {
            $(this).calendarsPicker({
                dateFormat: 'DD, d MM yyyy',
                defaultDate: datetoCdate( $("#first-date").val() ),
                selectDefaultDate: true,
                onSelect: function(dates) {
                    console.log("select first-date");
                    $("#first-date").val(dates);
                    if (initialised) updateChart(this);
                }
            });
        });

        $(".to-date-picker").each( function() {
            $(this).calendarsPicker({
                dateFormat: 'DD, d MM yyyy',
                defaultDate: datetoCdate( $("#to-date").val() ),
                selectDefaultDate: true,
                onSelect: function(dates) {
                    console.log("select second-date");
                    $("#to-date").val(dates);
                    if (initialised) updateChart(this);
                }
            });
        });

        setMinMaxDates(supply);
        enableMeters(supply, false);
        explain();
        console.log("done");
        initialised = true;
    }

    //TODO tidy up the code
    $(document).on('change', 'input[type=radio][name=supplyType]', function() {
        initialised = false;
        if (this.value == 'electricity') {
            $(".card").removeClass("gas-card");

            $("div.indicator-light").removeClass("gas-light");
            $("div.indicator-light").addClass("electricity-light");
            $("div.indicator-dark").removeClass("gas-dark");
            $("div.indicator-dark").addClass("electricity-dark");

            $("#gas-interpretation").hide();
            $("#electricity-interpretation").show();

            $(".card").addClass("electricity-card");
        } else {
            $("option[data-supply-type='electricity']").hide();
            $("option[data-supply-type='gas']").show();

            $(".card").removeClass("electricity-card");

            $("div.indicator-light").removeClass("electricity-light");
            $("div.indicator-light").addClass("gas-light");
            $("div.indicator-dark").removeClass("electricity-dark");
            $("div.indicator-dark").addClass("gas-dark");

            $("#electricity-interpretation").hide();
            $("#gas-interpretation").show();

            $(".card").addClass("gas-card");
        }
        //after we've changed supply we need to ensure min/max dates are
        //correct, and that only the correct meters are enabled
        $("#supply").val(this.value);
        enableMeters(this.value, true);
        setMinMaxDates(this.value);
        updateChart(this);
        initialised = true;
    });

    $(document).on('change', 'input[type=radio][name=compare]', function() {
        if (this.value === "within-school") {
            $("#comparison").val("within-school");
            $("#whole-school").hide();
            $("#within-school").show();
            $("#first-meter").val($("#within-school #meter").val());
            $("#first-date").val($("#within-school #first-date-picker").val());

        } else {
            $("#comparison").val("whole-school");
            $("#within-school").hide();
            $("#whole-school").show();
            $("#first-meter").val($("#whole-school #meter").val());
            $("#first-date").val($("#whole-school #first-date-picker").val());

        }
        explain();
        updateChart(this);
    });

    $(document).on('change', '.meter-filter', function() {
        $("#first-meter").val($(this).val());
        updateChart(this);
    });

    $(document).on('change', '.second-meter-filter', function() {
        $("#second-meter").val($(this).val());
        updateChart(this);
    });

});

<|endoftext|>


<commit_before>var order;

jQuery(function() {
  Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'));
  order.setupForm();
});

order = {
  setupForm: function() {
    $('.process_order').submit(function() {
      var $form = $(this);
      $('input[type=submit]').attr('disabled', true);
      // Move to redlight theme
      $('.stripe-error, .alert-stripe-checkout, .stripe-error-terms').remove();
      $('#stripe_card_error').html('');
      $('.field_with_errors').each(function()
      {
        $(this).find('input').unwrap();
        $(this).find('select').unwrap();
      });
      // end
      if ($('#stripe_card_number').length) {
        order.validateForm($form);
        return false;
      } else {
        return true;
      }
    });
  },
  processCard: function() {
    var card;
    card = {
      number: $('#stripe_card_number').val(),
      cvc: $('#stripe_card_code').val(),
      expMonth: $('#stripe_card_month').val(),
      expYear: $('#stripe_card_year').val()
    };
    Stripe.createToken(card, order.handleStripeResponse);
  },
  handleStripeResponse: function(status, response) {
    if (status === 200) {
      $('#order_stripe_card_token').val(response.id);
      $('.process_order')[0].submit();
    } else {
      $('#stripe_card_error').text(response.error.message);
      $('#stripe-form-fields input, #stripe-form-fields select').each(function()
      {
        $(this).wrap('

');
      });
      $('.checkout-body').prepend('

Please complete all of the required fields

');
      $('.checkout').prepend('
An error ocurred with your order. Please try again.
');
      $('input[type=submit]').attr('disabled', false);
      $('#checkoutLoadingModal').modal('hide');
    }
  },
  validateForm: function(form)
  {
    $.ajax(
    {
      url: '/carts/stripe/confirm',
      type: 'POST',
      data: form.serialize(),
      dataType: 'json',
      success: function (data)
      {
        order.processCard();
      },
      error: function(xhr, evt, status)
      {
        order.jsonErrors(xhr, evt, status, form);
      }
    });
  },
  jsonErrors: function(xhr, evt, status, form)
  {
    var content, value, _i, _len, _ref, $this;
    $this = form;
    errorKeys = $.parseJSON(xhr.responseText).errors;
    $('input[type=submit]').attr('disabled', false);
    $('#checkoutLoadingModal').modal('hide');

    // Move to redlight theme
    $.each(errorKeys, function(index, value)
    {
      var $input = $('#' + value);
      if (value === 'terms')
      {
        $('You must tick the box in order to place your order.').insertBefore('input[type="hidden"][name="order[terms]"]');
      }
      $input.wrap('

')
    });
    $('.checkout-body').prepend('

Please complete all of the required fields

');
    $('.checkout').prepend('
An error ocurred with your order. Please try again.
');
    // end
  }
};<commit_msg>Finished the stripe js modifications.<commit_after>var order;

jQuery(function() {
  Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'));
  order.setupForm();
});

order = {
  setupForm: function() {
    $('.process_order').submit(function() {
      var $form = $(this);
      $('input[type=submit]').attr('disabled', true);
      $('.stripe-error, .alert-stripe-checkout, .stripe-error-terms').remove();
      $('#stripe_card_error').html('');
      $('.field_with_errors').each(function()
      {
        $(this).find('input').unwrap();
        $(this).find('select').unwrap();
      });
      if ($('#stripe_card_number').length) {
        order.validateForm($form);
        return false;
      } else {
        return true;
      }
    });
  },
  processCard: function() {
    var card;
    card = {
      number: $('#stripe_card_number').val(),
      cvc: $('#stripe_card_code').val(),
      expMonth: $('#stripe_card_month').val(),
      expYear: $('#stripe_card_year').val()
    };
    Stripe.createToken(card, order.handleStripeResponse);
  },
  handleStripeResponse: function(status, response) {
    if (status === 200) {
      $('#order_stripe_card_token').val(response.id);
      $('.process_order')[0].submit();
    } else {
      $('#stripe_card_error').text(response.error.message);
      $('#stripe-form-fields input, #stripe-form-fields select').each(function()
      {
        $(this).wrap('

');
      });
      stripeCheckoutErrors();
      $('input[type=submit]').attr('disabled', false);
      $('#checkoutLoadingModal').modal('hide');
    }
  },
  validateForm: function(form)
  {
    $.ajax(
    {
      url: '/carts/stripe/confirm',
      type: 'POST',
      data: form.serialize(),
      dataType: 'json',
      success: function (data)
      {
        order.processCard();
      },
      error: function(xhr, evt, status)
      {
        order.jsonErrors(xhr, evt, status, form);
      }
    });
  },
  jsonErrors: function(xhr, evt, status, form)
  {
    var content, value, _i, _len, _ref, $this;
    $this = form;
    errorKeys = $.parseJSON(xhr.responseText).errors;
    $('input[type=submit]').attr('disabled', false);
    $('#checkoutLoadingModal').modal('hide');

    $.each(errorKeys, function(index, value)
    {
      var $input = $('#' + value);
      if (value === 'terms')
      {
        stripeTermsValidationMessage();
      }
      $input.wrap('

')
    });
    stripeCheckoutErrors();
  }
};<|endoftext|>


<commit_before>var strains;
var professions;
var skill_cat;

var selected_strain;
var selected_professions;

var last_popover_skill;

var generate_strains_select_box = function() {
  var s = $('<select></select>')
            .attr('id', 'strain-selector');

  var header = $('<option>Select Strain</option>');
  s.append(header);

  $.each(strains, function(index, value) {
    var t = $('<option></option>')
              .append(value);
    s.append(t);
  })

  $('#setup-strain').append(s);
  $('#strain-selector').multiselect({
    buttonWidth: '100%',
    onDropdownShow: disable_popover,
    dropRight: true,
    maxHeight: 512,
    onChange: function(option, checked) {
      selected_strain = option.text();
      recalculate();
      replan();
    }
  });
};

var generate_professions_select_box = function() {
  var s = $('<select><select>')
            .attr('id', 'profession-selector')
            .attr('multiple', true);

  $.each(professions, function(index, value) {
    var t = $('<option></option>')
              .attr('profession', value);
    t.append(value);
    s.append(t);
  })

  $('div#setup-profession').append(s);
  $('#profession-selector').multiselect({
    buttonWidth: '100%',
    buttonText: function(options, selected) {
      if (options.length == 0) {
        return 'Select Professions';
      } else {
        var labels = [];
        options.each(function() {
          labels.push($(this).text());
        })

        return labels.join(', ');
      }
    },

    maxHeight: 512,
    onDropdownShow: disable_popover,
    onChange: function(option, checked) {
      var selected_options = $('#profession-selector option:selected');
      if (selected_options.length >= 3) {
        var non_selected_options = $('#profession-selector option').filter(function() {
          return !$(this).is(':selected');
        })

        non_selected_options.each(function() {
          var input = $('input[value="' + $(this).val() + '"]');
          //input.prop('faded', true);
          input.prop('disabled', true);
          input.parent().addClass('text-muted');
        })
      } else {
        $('#profession-selector option').each(function() {
          var input = $('input[value="' + $(this).val() + '"]');
          //input.prop('faded', false);
          input.prop('disabled', false);
          input.parent().removeClass('text-muted');
        });
      }

      selected_professions = new Array();
      selected_options.each(function() {
        selected_professions.push($(this).text());
      })

      recalculate();
      replan();
    }
  })
};

var generate_skill_cat = function() {
  var skills = Object.keys(skill_cat);
  skills.sort();

  // var s = $('

')
  //           .addClass('list-group')
  //           .attr('id', 'graphical-list');
  var s = $('#graphical-list');

  var col_classes = 'col-xs-12 col-sm-6 col-md-4 col-lg-3';
  if (is_builder) {
    col_classes = 'col-xs-12 col-lg-6';
  }

  $.each(skills, function(index, skill_name) {
    var t = $('

')
              .addClass('list-group-item skill-draggable faded clickable-skill ' + col_classes)
              .attr('skill-name', skill_name)
              .append('' + skill_name + '')

              .append('')
              .append('                  ');

    s.append(t);
  })

  $('div#graphical-list').append(s);
  $('.graphical-container')
    //.css('max-height', '90vh')
    .css('margin-left', '-4px')
    .css('margin-right', '0px');
  recalculate();
  attach_anchor();

  if (is_builder) {
    attach_drag_functor();
  }
};

function attach_anchor() {
  var target_element;
  $('li.clickable-skill').on('click', function() {
    if ($(this).hasClass('no-click')) {
      return;
    }

    var is_popped_over = $('.popover').hasClass('in');
    disable_popover();

    target_element = $(this).find('span.skill-label');
    //target_element = $(this).find('span.pseudo-point');
    var skill_name = $(this).find('span.skill-label').text();
    var min_cost = parseInt($(this).find('span.badge').text());
    //var containing_element = target_element.parent().parent().parent();

    var y_position = $(this).position().top;
    var window_height = $(window).height();
    var data_placement = 'right';

    if (y_position < 100) {
      data_placement = 'bottom';
    } else if (y_position > window_height - 200) {
      data_placement = 'top';
    }
    //console.log(top_id);
    if (target_element.attr('popover-applied') != 'true') {
      target_element
        .attr('popover-applied', true)
        .attr('data-trigger', 'click')
        .attr('data-placement', data_placement)
        .attr('data-html', true)
        //.attr('data-container', 'body')
        //.attr('data-viewport', '#' + top_id)
    }
    target_element.attr('data-content', pull_skill_cat_data(skill_name, min_cost));

    if (is_popped_over && last_popover_skill == skill_name) {
      target_element.popover('hide');
    } else {
      target_element.popover('show');
      last_popover_skill = skill_name;
    }

    // $('.popover').off('click').on('click', function() {
    //   $(this).hide();
    // })
  })

  $('li.clickable-skill').on('taphold', function() {
    console.log('taphold');
  })
}

function pull_skill_cat_data(skill, min_cost) {
  var data = skill_cat[skill];
  var by_strain = new Object();
  var strain_preq = null;
  var by_open = new Array();
  var by_profession = new Object();
  var s = '';

  $.each(data, function(class_type, class_data) {
    switch (class_type) {
      case "innate":
        $.each(class_data, function(index, innate_strain) {
          by_strain[innate_strain] = 3;
        });
        break;
      case "open":
        by_open.push('Open: ' + class_data);
        break;
      case "innate_preq":
        strain_preq = class_data;
        break;
      default:
        by_profession[class_type] = data[class_type];
    }
  });

  if (Object.keys(by_strain).length > 0) {
    $.each(by_strain, function(strain_name, cost) {
      var class_name = 'skill-not-accessible';
      if (strain_name == selected_strain) {
        class_name = 'text-primary';
      }

      if (cost == min_cost && class_name != 'skill-not-accessible') {
        class_name = 'skill-cheapest';
      }

      var f = '' + strain_name + ': ' + cost + '';
      s += f + '
'

      if (strain_preq && strain_preq[strain_name]) {
        var concat = new Array();
        var combinator = strain_preq[strain_name].predicate == 'and' ? ' & ' : ' | ';
        $.each(strain_preq[strain_name].list, function(preq_skill, _junk) {
          concat.push(preq_skill + ' (3)');
        })
        s += '« ' + concat.join(combinator) + '
';
      }
    });

    s += '
';
  }

  if (by_open.length > 0) {
    s += by_open.join('
') + '
';
  }

  if (Object.keys(by_profession).length > 0) {
    $.each(by_profession, function(profession_name, pdata) {
      var class_name = 'skill-not-accessible';
      var preq;
      if (selected_professions != undefined &&
          selected_professions.indexOf(profession_name) != -1) {
        class_name = 'text-primary';
        preq = find_preq(profession_name, skill, pdata);
      }

      if (pdata.cost == min_cost && class_name != 'skill-not-accessible') {
        class_name = 'skill-cheapest';
      }

      var f = '' + profession_name + ': ' + pdata.cost + '';
      s += f + '
';
      if (preq && preq.length > 0) {
        s += '' + preq + '
';
      }
    })
  }

  return s;
}

function find_preq(profession, skill, pdata) {
  var s = '';

  if (pdata.preq == null) {
    return '';
  } else {
    var combinator = pdata.preq.predicate == 'and' ? ' & ' : ' | ';
    var cost = skill_cat[skill][profession].cost;

    //s += Object.keys(pdata.preq.list).join(combinator) + ' (' + cost + ')';

    var concat = new Array();
    $.each(pdata.preq.list, function(preq_skill, _junk) {
      //s += find_preq(profession, preq_skill, skill_cat[preq_skill][profession]);
      if (skill_cat[preq_skill][profession]) {
        concat.push(preq_skill + ' (' + skill_cat[preq_skill][profession].cost + ')');
      } else {
        concat.push(preq_skill + ' (Open: 9)');
      }
    });
    s += concat.join(combinator);
  }

  return ' « ' + s;
}

function recalculate() {
  var detect_has_innate = function(data) {
    var strain_index = data.innate.indexOf(selected_strain);
    return strain_index == -1 ? 99 : 3;
  }

  var detect_is_open_skill = function(data) {
    return data.open || 99;
  }

  var detect_is_profession_skill = function(data) {
    var min_cost = 99;
    var is_available = false;

    $.each(selected_professions, function(index, profession) {
      if (data[profession] != undefined) {
        if (data[profession].cost < min_cost) {
          min_cost = data[profession].cost;
        }
        is_available = is_available || true;
      }
    });

    return min_cost;
  }

  var detect_available_skill = function(skill_name, data) {
    var min_cost = 99;
    var is_available = false;

    min_cost = Math.min(min_cost, detect_is_profession_skill(data));
    min_cost = Math.min(min_cost, detect_has_innate(data));
    min_cost = Math.min(min_cost, detect_is_open_skill(data));

    var o = $('[skill-name="' + skill_name + '"]');
    if (min_cost != 99) {
      o.removeClass('faded')
      o.find('.badge').text(min_cost)
      o.find('.clickable-skill').removeClass('link-faded');
    } else {
      o.addClass('faded')
      o.find('.badge').text('')
      o.find('.clickable-skill').addClass('link-faded');
    }
  };

  $.each(skill_cat, function(skill_name, skill_data) {
    detect_available_skill(skill_name, skill_data);
  });

  update_availability();
  disable_popover();
}

function update_search_result(value) {
  disable_popover();

  var pattern = new RegExp(value);
  $('#only-available-checkbox').prop('checked', false);
  $('#graphical-list').find('[skill-name]').each(function() {
    var matcher = $(this).attr('skill-name').toLowerCase();

    if (matcher.match(pattern)) {
      $(this).show();
    } else {
      $(this).hide();
    }
  })
}

function update_availability() {
  disable_popover();
  var only_available = $('#only-available-checkbox').prop('checked');

  if (only_available) {
    $('.list-group-item').show();
    $('#graphical').find('.list-group-item.faded').hide();
  } else {
    $('.list-group-item.faded').show();

  }
}

function disable_popover() {
  $('.popover').popover('hide');
}

$(function() {
  $.ajaxSetup({cache: false});

  $.getJSON('/strains.json', function(strains_json_data) {
    strains = strains_json_data;
    generate_strains_select_box();
  });

  $.getJSON('/professions.json', function(professions_json_data) {
    professions = professions_json_data;
    generate_professions_select_box();
  });

  $.getJSON('/skill_cat.json', function(skill_cat_json_data) {
    skill_cat = skill_cat_json_data;
    generate_skill_cat();
  });

  $('#search-input').on('keyup', function(e) {
    var query = $(this).val().trim().toLowerCase();

    if (query.length == 0) {
      update_search_result(query);
    } else if (e.which == 13) {
      e.preventDefault();
      update_search_result(query);
    }
  });

  $('#only-available-checkbox').on('change', update_availability);
  update_availability();

  if (!is_builder) {
    var target_max_height = $(window).height() - $('#setup').height() - 32;
    $('#graphical').css('max-height', target_max_height);
  }
});

<commit_msg>Incomplete popover dynamic placement.<commit_after>var strains;
var professions;
var skill_cat;

var selected_strain;
var selected_professions;

var last_popover_skill = '';

var generate_strains_select_box = function() {
  var s = $('<select></select>')
            .attr('id', 'strain-selector');

  var header = $('<option>Select Strain</option>');
  s.append(header);

  $.each(strains, function(index, value) {
    var t = $('<option></option>')
              .append(value);
    s.append(t);
  })

  $('#setup-strain').append(s);
  $('#strain-selector').multiselect({
    buttonWidth: '100%',
    onDropdownShow: disable_popover,
    dropRight: true,
    maxHeight: 512,
    onChange: function(option, checked) {
      selected_strain = option.text();
      recalculate();
      replan();
    }
  });
};

var generate_professions_select_box = function() {
  var s = $('<select><select>')
            .attr('id', 'profession-selector')
            .attr('multiple', true);

  $.each(professions, function(index, value) {
    var t = $('<option></option>')
              .attr('profession', value);
    t.append(value);
    s.append(t);
  })

  $('div#setup-profession').append(s);
  $('#profession-selector').multiselect({
    buttonWidth: '100%',
    buttonText: function(options, selected) {
      if (options.length == 0) {
        return 'Select Professions';
      } else {
        var labels = [];
        options.each(function() {
          labels.push($(this).text());
        })

        return labels.join(', ');
      }
    },

    maxHeight: 512,
    onDropdownShow: disable_popover,
    onChange: function(option, checked) {
      var selected_options = $('#profession-selector option:selected');
      if (selected_options.length >= 3) {
        var non_selected_options = $('#profession-selector option').filter(function() {
          return !$(this).is(':selected');
        })

        non_selected_options.each(function() {
          var input = $('input[value="' + $(this).val() + '"]');
          //input.prop('faded', true);
          input.prop('disabled', true);
          input.parent().addClass('text-muted');
        })
      } else {
        $('#profession-selector option').each(function() {
          var input = $('input[value="' + $(this).val() + '"]');
          //input.prop('faded', false);
          input.prop('disabled', false);
          input.parent().removeClass('text-muted');
        });
      }

      selected_professions = new Array();
      selected_options.each(function() {
        selected_professions.push($(this).text());
      })

      recalculate();
      replan();
    }
  })
};

var generate_skill_cat = function() {
  var skills = Object.keys(skill_cat);
  skills.sort();

  // var s = $('

')
  //           .addClass('list-group')
  //           .attr('id', 'graphical-list');
  var s = $('#graphical-list');

  var col_classes = 'col-xs-12 col-sm-6 col-md-4 col-lg-3';
  if (is_builder) {
    col_classes = 'col-xs-12 col-lg-6';
  }

  $.each(skills, function(index, skill_name) {
    var t = $('

')
              .addClass('list-group-item skill-draggable faded clickable-skill ' + col_classes)
              .attr('skill-name', skill_name)
              .append('' + skill_name + '')
              .append('');
              //.append('                  ');

    s.append(t);
  })

  $('div#graphical-list').append(s);
  $('.graphical-container')
    //.css('max-height', '90vh')
    .css('margin-left', '-4px')
    .css('margin-right', '0px');
  recalculate();
  attach_anchor();

  if (is_builder) {
    attach_drag_functor();
  }
};

function attach_anchor() {
  var target_element;
  $('li.clickable-skill').on('click', function() {
    if ($(this).hasClass('no-click')) {
      return;
    }

    var is_popped_over = $('.popover').hasClass('in');
    disable_popover();

    target_element = $(this).find('span.skill-label');
    //target_element = $(this).find('span.pseudo-point');
    var skill_name = $(this).find('span.skill-label').text();
    var min_cost = parseInt($(this).find('span.badge').text());
    //var containing_element = target_element.parent().parent().parent();

    var y_position = $(this).position().top;
    var window_height = $(window).height();
    var data_placement = 'right';

    if (y_position < 100) {
      data_placement = 'bottom';
    } else if (y_position > window_height - 200) {
      data_placement = 'top';
    }

    var text_content = target_element.html();
    if (data_placement != 'right') {
      if (target_element.width() < 100) {
        var diff = (100 - target_element.width()) / 2;

        for (i = 0; i < diff; i++) {
          text_content += ' '
        }

        target_element.html(text_content);
      }
    } else {
      text_content = text_content.replace(/\&nbsp\;/g, '');
      target_element.html(text_content);
    }
    //console.log(top_id);
    if (target_element.attr('popover-applied') != 'true') {
      target_element
        .attr('popover-applied', true)
        .attr('data-trigger', 'click')
        .attr('data-html', true)
        //.attr('data-container', 'body')
        //.attr('data-viewport', '#' + top_id)
    }

    //target_element.attr('data-placement', data_placement)
    target_element.attr('data-content', pull_skill_cat_data(skill_name, min_cost));

    skill_name = skill_name.trim();
    var is_reclick = last_popover_skill.localeCompare(skill_name) == 0;

    if (is_popped_over && is_reclick) {
      target_element.popover('hide');
      //target_element.popover('destroy');
      last_popover_skill = '';
    } else {
      // target_element.popover('destroy');

      // console.log('recreating');

      // console.log(target_element);
      // // target_element
      // //   .attr('popover-applied', true)
      // //   .attr('data-trigger', 'click')
      // //   .attr('data-html', true)
      // //   .attr('data-content', pull_skill_cat_data(skill_name, min_cost));
      target_element.popover({
        placement: data_placement
      });
      // try {

      // } catch(err) {
      //   console.log(err);
      // }

      target_element.popover('show');
      last_popover_skill = skill_name;
    }

    // $('.popover').off('click').on('click', function() {
    //   $(this).hide();
    // })
  })
}

function pull_skill_cat_data(skill, min_cost) {
  var data = skill_cat[skill];
  var by_strain = new Object();
  var strain_preq = null;
  var by_open = new Array();
  var by_profession = new Object();
  var s = '';

  $.each(data, function(class_type, class_data) {
    switch (class_type) {
      case "innate":
        $.each(class_data, function(index, innate_strain) {
          by_strain[innate_strain] = 3;
        });
        break;
      case "open":
        by_open.push('Open: ' + class_data);
        break;
      case "innate_preq":
        strain_preq = class_data;
        break;
      default:
        by_profession[class_type] = data[class_type];
    }
  });

  if (Object.keys(by_strain).length > 0) {
    $.each(by_strain, function(strain_name, cost) {
      var class_name = 'skill-not-accessible';
      if (strain_name == selected_strain) {
        class_name = 'text-primary';
      }

      if (cost == min_cost && class_name != 'skill-not-accessible') {
        class_name = 'skill-cheapest';
      }

      var f = '' + strain_name + ': ' + cost + '';
      s += f + '
'

      if (strain_preq && strain_preq[strain_name]) {
        var concat = new Array();
        var combinator = strain_preq[strain_name].predicate == 'and' ? ' & ' : ' | ';
        $.each(strain_preq[strain_name].list, function(preq_skill, _junk) {
          concat.push(preq_skill + ' (3)');
        })
        s += '« ' + concat.join(combinator) + '
';
      }
    });

    s += '
';
  }

  if (by_open.length > 0) {
    s += by_open.join('
') + '
';
  }

  if (Object.keys(by_profession).length > 0) {
    $.each(by_profession, function(profession_name, pdata) {
      var class_name = 'skill-not-accessible';
      var preq;
      if (selected_professions != undefined &&
          selected_professions.indexOf(profession_name) != -1) {
        class_name = 'text-primary';
        preq = find_preq(profession_name, skill, pdata);
      }

      if (pdata.cost == min_cost && class_name != 'skill-not-accessible') {
        class_name = 'skill-cheapest';
      }

      var f = '' + profession_name + ': ' + pdata.cost + '';
      s += f + '
';
      if (preq && preq.length > 0) {
        s += '' + preq + '
';
      }
    })
  }

  return s;
}

function find_preq(profession, skill, pdata) {
  var s = '';

  if (pdata.preq == null) {
    return '';
  } else {
    var combinator = pdata.preq.predicate == 'and' ? ' & ' : ' | ';
    var cost = skill_cat[skill][profession].cost;

    //s += Object.keys(pdata.preq.list).join(combinator) + ' (' + cost + ')';

    var concat = new Array();
    $.each(pdata.preq.list, function(preq_skill, _junk) {
      //s += find_preq(profession, preq_skill, skill_cat[preq_skill][profession]);
      if (skill_cat[preq_skill][profession]) {
        concat.push(preq_skill + ' (' + skill_cat[preq_skill][profession].cost + ')');
      } else {
        concat.push(preq_skill + ' (Open: 9)');
      }
    });
    s += concat.join(combinator);
  }

  return ' « ' + s;
}

function recalculate() {
  var detect_has_innate = function(data) {
    var strain_index = data.innate.indexOf(selected_strain);
    return strain_index == -1 ? 99 : 3;
  }

  var detect_is_open_skill = function(data) {
    return data.open || 99;
  }

  var detect_is_profession_skill = function(data) {
    var min_cost = 99;
    var is_available = false;

    $.each(selected_professions, function(index, profession) {
      if (data[profession] != undefined) {
        if (data[profession].cost < min_cost) {
          min_cost = data[profession].cost;
        }
        is_available = is_available || true;
      }
    });

    return min_cost;
  }

  var detect_available_skill = function(skill_name, data) {
    var min_cost = 99;
    var is_available = false;

    min_cost = Math.min(min_cost, detect_is_profession_skill(data));
    min_cost = Math.min(min_cost, detect_has_innate(data));
    min_cost = Math.min(min_cost, detect_is_open_skill(data));

    var o = $('[skill-name="' + skill_name + '"]');
    if (min_cost != 99) {
      o.removeClass('faded')
      o.find('.badge').text(min_cost)
      o.find('.clickable-skill').removeClass('link-faded');
    } else {
      o.addClass('faded')
      o.find('.badge').text('')
      o.find('.clickable-skill').addClass('link-faded');
    }
  };

  $.each(skill_cat, function(skill_name, skill_data) {
    detect_available_skill(skill_name, skill_data);
  });

  update_availability();
  disable_popover();
}

function update_search_result(value) {
  disable_popover();

  var pattern = new RegExp(value);
  $('#only-available-checkbox').prop('checked', false);
  $('#graphical-list').find('[skill-name]').each(function() {
    var matcher = $(this).attr('skill-name').toLowerCase();

    if (matcher.match(pattern)) {
      $(this).show();
    } else {
      $(this).hide();
    }
  })
}

function update_availability() {
  disable_popover();
  var only_available = $('#only-available-checkbox').prop('checked');

  if (only_available) {
    $('.list-group-item').show();
    $('#graphical').find('.list-group-item.faded').hide();
  } else {
    $('.list-group-item.faded').show();

  }
}

function disable_popover() {
  $('.popover').popover('hide');
}

$(function() {
  $.ajaxSetup({cache: false});

  $.getJSON('/strains.json', function(strains_json_data) {
    strains = strains_json_data;
    generate_strains_select_box();
  });

  $.getJSON('/professions.json', function(professions_json_data) {
    professions = professions_json_data;
    generate_professions_select_box();
  });

  $.getJSON('/skill_cat.json', function(skill_cat_json_data) {
    skill_cat = skill_cat_json_data;
    generate_skill_cat();
  });

  $('#search-input').on('keyup', function(e) {
    var query = $(this).val().trim().toLowerCase();

    if (query.length == 0) {
      update_search_result(query);
    } else if (e.which == 13) {
      e.preventDefault();
      update_search_result(query);
    }
  });

  $('#only-available-checkbox').on('change', update_availability);
  update_availability();

  if (!is_builder) {
    var target_max_height = $(window).height() - $('#setup').height() - 32;
    $('#graphical').css('max-height', target_max_height);
  }
});

<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { TimePicker } from '@blueprintjs/datetime';

export default class CountdownTimer extends React.Component {
  render() {
    return <TimePicker />;
  }
}

CountdownTimer.propTypes = {
  timer: PropTypes.number.isRequired
};
<commit_msg>feat: Show arrows on time picker<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { TimePicker } from '@blueprintjs/datetime';

export default class CountdownTimer extends Component {
  render() {
    return (
      <TimePicker
        showArrowButtons
      />
    );
  }
}

CountdownTimer.propTypes = {
  timer: PropTypes.number.isRequired
};
<|endoftext|>


<commit_before>import axios from 'axios'
import { hashHistory } from 'react-router'

/* ----- ----- ----- CONSTANTS ----- ----- ----- */

const SET_ORDER = 'SET_ORDER'

/* ----- ----- ----- ACTION CREATORS ----- ----- */

const setOrder = order => ({
  type: SET_ORDER,
  order
})

/* ----- ----- ----- REDUCER ----- ----- ----- ----- */

const initialOrderState = {
  currentOrder: {},
}

const reducer = (state = initialOrderState, action) => {
  const newState = Object.assign({}, state)

  switch (action.type) {
  case SET_ORDER:
    newState.currentOrder = action.order
    return newState
  default:
    return state
  }
}

export default reducer

/* ----- ----- THUNK ACTION CREATORS ----- ----- */

export const createOrder = (address, email, items) =>
  dispatch => {
    console.log('MADE IT TO DISPATCH - AXIOS REQUEST IS NEXT!')
    axios.post('/api/order', { address, email, items })
    .then(res => res.data)
    .then(order => {
      dispatch(setOrder(order))
    })
    .catch(err => console.error(`Order unsuccessful`, err))
  }

export const getOrder = orderId =>
  dispatch => {
    axios.get(`/api/order/${orderId}`)
    .then(res => res.data)
    .then(order => dispatch(setOrder(order)))
    .catch(err => console.error(err))
  }
<commit_msg>feat(order): connected successful order to thank you page<commit_after>import axios from 'axios'
import { browserHistory, hashHistory } from 'react-router'

/* ----- ----- ----- CONSTANTS ----- ----- ----- */

const SET_ORDER = 'SET_ORDER'

/* ----- ----- ----- ACTION CREATORS ----- ----- */

const setOrder = order => ({
  type: SET_ORDER,
  order
})

/* ----- ----- ----- REDUCER ----- ----- ----- ----- */

const initialOrderState = {
  currentOrder: {},
}

const reducer = (state = initialOrderState, action) => {
  const newState = Object.assign({}, state)

  switch (action.type) {
  case SET_ORDER:
    newState.currentOrder = action.order
    return newState
  default:
    return state
  }
}

export default reducer

/* ----- ----- THUNK ACTION CREATORS ----- ----- */

export const createOrder = (address, email, items) =>
  dispatch => {
    console.log('MADE IT TO DISPATCH - AXIOS REQUEST IS NEXT!')
    axios.post('/api/order', { address, email, items })
    .then(res => res.data)
    .then(order => {
      dispatch(setOrder(order))
      browserHistory.push(`order/${order.id}`)
    })
    .catch(err => console.error(`Order unsuccessful`, err))
  }

export const getOrder = orderId =>
  dispatch => {
    axios.get(`/api/order/${orderId}`)
    .then(res => res.data)
    .then(order => dispatch(setOrder(order)))
    .catch(err => console.error(err))
  }
<|endoftext|>


<commit_before>import '../../css/browser/stack'

import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { FormattedMessage as T, FormattedRelative as D, intlShape } from 'react-intl'

import { emptyStack, fetchStack, viewWebentity } from '../../actions/stacks'
import { setTabUrl, openTab } from '../../actions/tabs'
import { HYPHE_TAB_ID } from '../../constants'

class BrowserStack extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      selectedStackName: this.props.selectedStack && this.props.selectedStack.name,
      selectedWebentityId: null
    }
  }

  // auto display first webentity in newly filled stack
  componentWillReceiveProps (props) {
    if (!this.props.selectedStack && props.selectedStack && props.webentities.length) {
      this.selectWebentity(props.webentities[0])
    }
  }

  // also called by refresh button
  fill () {
    const stack = this.props.stacks.find(s => s.name === this.state.selectedStackName)
    this.props.fetchStack(this.props.server.url, this.props.corpus, stack)
  }

  selectWebentity (webentity) {
    this.setState({ selectedWebentityId: webentity.id })
    this.props.viewWebentity(webentity)
    if (this.props.activeTabId && this.props.activeTabId !== HYPHE_TAB_ID) {
      this.props.setTabUrl(webentity.homepage, this.props.activeTabId)
    } else {
      this.props.openTab(webentity.homepage)
    }
  }

  // used by Prev (-1) / Next (+1) buttons
  rotateWebentity (offset) {
    const { webentities } = this.props
    const idx = webentities.findIndex(x => x.id === this.state.selectedWebentityId)
    let webentity
    if (idx === 0 && offset === -1) {
      webentity = webentities[webentities.length - 1]
    } else if (idx === webentities.length - 1 && offset === 1) {
      webentity = webentities[0]
    } else {
      webentity = webentities[idx + offset]
    }
    this.selectWebentity(webentity)
  }

  // top row
  renderFiller () {
    const { lastRefresh, selectedStack, stacks, webentities, status } = this.props
    const viewCount = webentities.filter(x => x.viewed).length

    if (!selectedStack) {
      return (

            <select className="form-control"
              defaultValue={ this.state.selectedStackName }
              onChange={ (evt) => { if (evt.target.value) this.setState({ selectedStackName: evt.target.value }) } }>
              <option key="prompt" value="">{ this.context.intl.formatMessage({ id: 'select-stack' }) }</option>
              { stacks.filter(s => (
                  status.corpus.memory_structure.webentities[s.condition]
                ))
                .map(s => (
                  <option key={ s.name } value={ s.name }>{ s.description }</option>
                ))
              }
            </select>
            <button className="btn btn-default"
              onClick={ () => this.fill() }>

              <T id="fill" />
            </button>

      )
    }
    return (

            { selectedStack.name }

            { selectedStack.description }

          <T id="viewed" /> { viewCount } / { webentities.length }

          <T id="refreshed-ago" values={ { relative: <D value={ lastRefresh } /> } } />
          <button className="btn btn-default"
              onClick={ () => this.fill() }>

            <T id="refresh" />
          </button>

          <button className="btn btn-default"
              onClick={ () => this.props.emptyStack() }>

            <T id="empty" />
          </button>

    )
  }

  // bottom row
  renderWesSelector () {
    const { webentities } = this.props
    const viewed = this.context.intl.formatMessage({ id: 'viewed' })

    return (

          <button className="btn btn-default browser-stack-wes-prev"
            onClick={ () => this.rotateWebentity(-1) }>

            <T id="previous" />
          </button>

          <select className="form-control"
            value={ this.state.selectedWebentityId }
            onChange={ (evt) => this.selectWebentity(webentities.find(x => x.id === evt.target.value)) }>
            { webentities.map((w, i) => (
              <option key={ w.id } value={ w.id }>#{ i + 1 } - { w.viewed ? `[${viewed}] - ` : '' } { w.name } ({ w.homepage })</option>
            )) }
          </select>

          <button className="btn btn-default browser-stack-wes-next"
            onClick={ () => this.rotateWebentity(1) }>
            <T id="next" />

          </button>

    )
  }

  render () {
    return (

        { this.renderFiller() }
        { this.props.selectedStack ? this.renderWesSelector() : null }

    )
  }
}

BrowserStack.contextTypes = {
  intl: intlShape
}

BrowserStack.propTypes = {
  activeTabId: PropTypes.string,
  corpus: PropTypes.object.isRequired,
  status: PropTypes.object.isRequired,
  lastRefresh: PropTypes.number,
  server: PropTypes.object.isRequired,
  selectedStack: PropTypes.any,
  stacks: PropTypes.array.isRequired,
  webentities: PropTypes.array.isRequired,

  emptyStack: PropTypes.func.isRequired,
  fetchStack: PropTypes.func.isRequired,
  setTabUrl: PropTypes.func.isRequired,
  openTab: PropTypes.func.isRequired,
  viewWebentity: PropTypes.func.isRequired
}

const mapStateToProps = ({ corpora, servers, stacks, tabs }) => ({
  activeTabId: tabs.activeTab && tabs.activeTab.id,
  corpus: corpora.selected,
  status: corpora.status,
  lastRefresh: stacks.lastRefresh,
  server: servers.selected,
  selectedStack: stacks.selected,
  stacks: stacks.list,
  webentities: stacks.webentities
})

const mapDispatchToProps = {
  emptyStack,
  fetchStack,
  setTabUrl,
  openTab,
  viewWebentity
}

export default connect(mapStateToProps, mapDispatchToProps)(BrowserStack)
<commit_msg>remove temp error<commit_after>import '../../css/browser/stack'

import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { FormattedMessage as T, FormattedRelative as D, intlShape } from 'react-intl'

import { emptyStack, fetchStack, viewWebentity } from '../../actions/stacks'
import { setTabUrl, openTab } from '../../actions/tabs'
import { HYPHE_TAB_ID } from '../../constants'

class BrowserStack extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      selectedStackName: this.props.selectedStack && this.props.selectedStack.name,
      selectedWebentityId: null
    }
  }

  // auto display first webentity in newly filled stack
  componentWillReceiveProps (props) {
    if (!this.props.selectedStack && props.selectedStack && props.webentities.length) {
      this.selectWebentity(props.webentities[0])
    }
  }

  // also called by refresh button
  fill () {
    const stack = this.props.stacks.find(s => s.name === this.state.selectedStackName)
    this.props.fetchStack(this.props.server.url, this.props.corpus, stack)
  }

  selectWebentity (webentity) {
    this.setState({ selectedWebentityId: webentity.id })
    this.props.viewWebentity(webentity)
    if (this.props.activeTabId && this.props.activeTabId !== HYPHE_TAB_ID) {
      this.props.setTabUrl(webentity.homepage, this.props.activeTabId)
    } else {
      this.props.openTab(webentity.homepage)
    }
  }

  // used by Prev (-1) / Next (+1) buttons
  rotateWebentity (offset) {
    const { webentities } = this.props
    const idx = webentities.findIndex(x => x.id === this.state.selectedWebentityId)
    let webentity
    if (idx === 0 && offset === -1) {
      webentity = webentities[webentities.length - 1]
    } else if (idx === webentities.length - 1 && offset === 1) {
      webentity = webentities[0]
    } else {
      webentity = webentities[idx + offset]
    }
    this.selectWebentity(webentity)
  }

  // top row
  renderFiller () {
    const { lastRefresh, selectedStack, stacks, webentities, status } = this.props
    const viewCount = webentities.filter(x => x.viewed).length

    if (!selectedStack) {
      return (

            <select className="form-control"
              defaultValue={ this.state.selectedStackName }
              onChange={ (evt) => { if (evt.target.value) this.setState({ selectedStackName: evt.target.value }) } }>
              <option key="prompt" value="">{ this.context.intl.formatMessage({ id: 'select-stack' }) }</option>
              { stacks.filter(s => (
                  status.corpus.memory_structure && status.corpus.memory_structure.webentities[s.condition]
                ))
                .map(s => (
                  <option key={ s.name } value={ s.name }>{ s.description }</option>
                ))
              }
            </select>
            <button className="btn btn-default"
              onClick={ () => this.fill() }>

              <T id="fill" />
            </button>

      )
    }
    return (

            { selectedStack.name }

            { selectedStack.description }

          <T id="viewed" /> { viewCount } / { webentities.length }

          <T id="refreshed-ago" values={ { relative: <D value={ lastRefresh } /> } } />
          <button className="btn btn-default"
              onClick={ () => this.fill() }>

            <T id="refresh" />
          </button>

          <button className="btn btn-default"
              onClick={ () => this.props.emptyStack() }>

            <T id="empty" />
          </button>

    )
  }

  // bottom row
  renderWesSelector () {
    const { webentities } = this.props
    const viewed = this.context.intl.formatMessage({ id: 'viewed' })

    return (

          <button className="btn btn-default browser-stack-wes-prev"
            onClick={ () => this.rotateWebentity(-1) }>

            <T id="previous" />
          </button>

          <select className="form-control"
            value={ this.state.selectedWebentityId }
            onChange={ (evt) => this.selectWebentity(webentities.find(x => x.id === evt.target.value)) }>
            { webentities.map((w, i) => (
              <option key={ w.id } value={ w.id }>#{ i + 1 } - { w.viewed ? `[${viewed}] - ` : '' } { w.name } ({ w.homepage })</option>
            )) }
          </select>

          <button className="btn btn-default browser-stack-wes-next"
            onClick={ () => this.rotateWebentity(1) }>
            <T id="next" />

          </button>

    )
  }

  render () {
    return (

        { this.renderFiller() }
        { this.props.selectedStack ? this.renderWesSelector() : null }

    )
  }
}

BrowserStack.contextTypes = {
  intl: intlShape
}

BrowserStack.propTypes = {
  activeTabId: PropTypes.string,
  corpus: PropTypes.object.isRequired,
  status: PropTypes.object.isRequired,
  lastRefresh: PropTypes.number,
  server: PropTypes.object.isRequired,
  selectedStack: PropTypes.any,
  stacks: PropTypes.array.isRequired,
  webentities: PropTypes.array.isRequired,

  emptyStack: PropTypes.func.isRequired,
  fetchStack: PropTypes.func.isRequired,
  setTabUrl: PropTypes.func.isRequired,
  openTab: PropTypes.func.isRequired,
  viewWebentity: PropTypes.func.isRequired
}

const mapStateToProps = ({ corpora, servers, stacks, tabs }) => ({
  activeTabId: tabs.activeTab && tabs.activeTab.id,
  corpus: corpora.selected,
  status: corpora.status,
  lastRefresh: stacks.lastRefresh,
  server: servers.selected,
  selectedStack: stacks.selected,
  stacks: stacks.list,
  webentities: stacks.webentities
})

const mapDispatchToProps = {
  emptyStack,
  fetchStack,
  setTabUrl,
  openTab,
  viewWebentity
}

export default connect(mapStateToProps, mapDispatchToProps)(BrowserStack)
<|endoftext|>


<commit_before>import React from 'react';

import FlashesStore from '../../../stores/FlashesStore';
import PusherStore from '../../../stores/PusherStore';

import Flash from './flash';

const FLASH_CONN_ERROR_ID = 'FLASH_CONN_ERROR';

class Flashes extends React.PureComponent {
  state = {
    flashes: [],
    lastConnected: true // assume we were connected when the page loaded
  };

  componentWillMount() {
    if (FlashesStore.preloaded) {
      this.setState({ flashes: FlashesStore.preloaded });
    }
  }

  componentDidMount() {
    FlashesStore.on('flash', this.handleStoreChange);
    PusherStore.on('unavailable', this.handleConnectionError);
    PusherStore.on('connected', this.handleConnectionSuccess);
  }

  componentWillUnmount() {
    FlashesStore.off('flash', this.handleStoreChange);
    PusherStore.off('unavailable', this.handleConnectionError);
    PusherStore.off('connected', this.handleConnectionSuccess);
  }

  handleStoreChange = (payload) => {
    this.setState({ flashes: this.state.flashes.concat(payload) });
  };

  hasConnectionErrorFlash() {
    return this.state.flashes.length > 0 && this.state.flashes[0].id === FLASH_CONN_ERROR_ID;
  }

  // show a flash when there's a push connection issue
  handleConnectionError = () => {
    if (this.hasConnectionErrorFlash() || !this.state.lastConnected) {
      // try not to be irritating; don't add a new flash when
      // we're showing one, or when we haven't reconnected yet.
      //
      // this means we don't add a new flash if the user
      // dismissed one before a connection was restored
      // (kinder for those with flaky connections! <3)
      return;
    }

    const connectionFlash = {
      id: FLASH_CONN_ERROR_ID,
      type: FlashesStore.ERROR,
      message: Couldn’t connect to Buildkite for push updates. We’ll try to reconnect! Information won’t update automatically for now.
    };

    // prepend the flash
    this.setState({
      flashes: [connectionFlash].concat(this.state.flashes),
      lastConnected: false
    });
  };

  // hide connection error flash (if it exists!) when reconnected
  handleConnectionSuccess = () => {
    const newState = {
      // make it known that we got a good connection!
      lastConnected: true
    };

    // as the flash is always prepended (and no other flash is),
    // we can slice from the front rather than filter or find index
    if (this.hasConnectionErrorFlash()) {
      newState.flashes = this.state.flashes.slice(1);
    }

    this.setState(newState);
  };

  render() {
    if (this.state.flashes.length > 0) {
      return (

          {this.state.flashes.map((flash) => (
            <Flash
              key={flash.id}
              flash={flash}
              onRemoveClick={this.handleFlashRemove}
            />
          ))}

      );
    } else {
      return null;
    }
  }

  handleFlashRemove = (flash) => {
    this.setState({
      flashes: this.state.flashes.filter(
        (nextFlash) => flash.id !== nextFlash.id
      )
    });
  };
}

export default Flashes;
<commit_msg>Add a note about Pusher connection events<commit_after>import React from 'react';

import FlashesStore from '../../../stores/FlashesStore';
import PusherStore from '../../../stores/PusherStore';

import Flash from './flash';

const FLASH_CONN_ERROR_ID = 'FLASH_CONN_ERROR';

class Flashes extends React.PureComponent {
  state = {
    flashes: [],
    lastConnected: true // assume we were connected when the page loaded
  };

  componentWillMount() {
    if (FlashesStore.preloaded) {
      this.setState({ flashes: FlashesStore.preloaded });
    }
  }

  componentDidMount() {
    FlashesStore.on('flash', this.handleStoreChange);
    PusherStore.on('unavailable', this.handleConnectionError);
    PusherStore.on('connected', this.handleConnectionSuccess);
  }

  componentWillUnmount() {
    FlashesStore.off('flash', this.handleStoreChange);
    PusherStore.off('unavailable', this.handleConnectionError);
    PusherStore.off('connected', this.handleConnectionSuccess);
  }

  handleStoreChange = (payload) => {
    this.setState({ flashes: this.state.flashes.concat(payload) });
  };

  hasConnectionErrorFlash() {
    return this.state.flashes.length > 0 && this.state.flashes[0].id === FLASH_CONN_ERROR_ID;
  }

  // show a flash when there's a push connection issue
  //
  // NOTE: Pusher only sends this event if the following conditions are met;
  //        1. The websocket timed out (30 seconds by default)
  //        2. Reconnecting the websocket (after 10 seconds) failed
  //       Thus, this can only happen once in a given 40 second period.
  handleConnectionError = () => {
    if (this.hasConnectionErrorFlash() || !this.state.lastConnected) {
      // try not to be irritating; don't add a new flash when
      // we're showing one, or when we haven't reconnected yet.
      //
      // this means we don't add a new flash if the user
      // dismissed one before a connection was restored
      // (kinder for those with flaky connections! <3)
      return;
    }

    const connectionFlash = {
      id: FLASH_CONN_ERROR_ID,
      type: FlashesStore.ERROR,
      message: Couldn’t connect to Buildkite for push updates. We’ll try to reconnect! Information won’t update automatically for now.
    };

    // prepend the flash
    this.setState({
      flashes: [connectionFlash].concat(this.state.flashes),
      lastConnected: false
    });
  };

  // hide connection error flash (if it exists!) when reconnected
  handleConnectionSuccess = () => {
    const newState = {
      // make it known that we got a good connection!
      lastConnected: true
    };

    // as the flash is always prepended (and no other flash is),
    // we can slice from the front rather than filter or find index
    if (this.hasConnectionErrorFlash()) {
      newState.flashes = this.state.flashes.slice(1);
    }

    this.setState(newState);
  };

  render() {
    if (this.state.flashes.length > 0) {
      return (

          {this.state.flashes.map((flash) => (
            <Flash
              key={flash.id}
              flash={flash}
              onRemoveClick={this.handleFlashRemove}
            />
          ))}

      );
    } else {
      return null;
    }
  }

  handleFlashRemove = (flash) => {
    this.setState({
      flashes: this.state.flashes.filter(
        (nextFlash) => flash.id !== nextFlash.id
      )
    });
  };
}

export default Flashes;
<|endoftext|>


<commit_before>import { take, takeLatest, call, put, cancel, select } from 'redux-saga/effects'
import { LOCATION_CHANGE } from 'react-router-redux'
import api from 'services'
import { makeSelectLocale } from 'containers/LanguageProvider/selectors'
import { selectSearchKey } from './selectors'
import { PICTOGRAMS, pictograms, AUTOCOMPLETE, autocomplete } from './actions'

function* pictogramsGetData() {
  try {
    const searchText = yield select(selectSearchKey())
    console.log ('searchText:' + searchText)
    const response = yield call(api.fetchPictograms, searchText)
    // console.log(' EN JSON:' + response.toJSON())
    yield put(pictograms.success(response))
  } catch (error) {
    yield put(pictograms.failure(error.message))
  } finally {
    // When done, we tell Redux we're not in the middle of a request any more
    // yield put({type: SENDING_REQUEST, sending: false})
  }
}

function* autoCompleteGetData() {
  try {
    const locale = yield select(makeSelectLocale())
    const response = yield call(api.keywords, locale)
    const { words } = response
    // console.log(' EN JSON:' + response.toJSON())
    yield put(autocomplete.success(locale, words))
  } catch (error) {
    yield put(autocomplete.failure(error.message))
  } finally {
    // When done, we tell Redux we're not in the middle of a request any more
    // yield put({type: SENDING_REQUEST, sending: false})
  }
}

/**
 * Root saga manages watcher lifecycle
 */
export function* autoCompleteData() {
  const watcher = yield takeLatest(AUTOCOMPLETE.REQUEST, autoCompleteGetData)
  // Suspend execution until location changes
  yield take(LOCATION_CHANGE)
  yield cancel(watcher)
}

export function* pictogramsData() {
  const watcher = yield takeLatest(PICTOGRAMS.REQUEST, pictogramsGetData)
  // Suspend execution until location changes
  yield take(LOCATION_CHANGE)
  yield cancel(watcher)
}

// All sagas to be loaded
export default [pictogramsGetData, autoCompleteData]
<commit_msg>remove debug<commit_after>import { take, takeLatest, call, put, cancel, select } from 'redux-saga/effects'
import { LOCATION_CHANGE } from 'react-router-redux'
import api from 'services'
import { makeSelectLocale } from 'containers/LanguageProvider/selectors'
import { selectSearchKey } from './selectors'
import { PICTOGRAMS, pictograms, AUTOCOMPLETE, autocomplete } from './actions'

function* pictogramsGetData() {
  try {
    const searchText = yield select(selectSearchKey())
    const response = yield call(api.fetchPictograms, searchText)
    yield put(pictograms.success(response))
  } catch (error) {
    yield put(pictograms.failure(error.message))
  } finally {
    // When done, we tell Redux we're not in the middle of a request any more
    // yield put({type: SENDING_REQUEST, sending: false})
  }
}

function* autoCompleteGetData() {
  try {
    const locale = yield select(makeSelectLocale())
    const response = yield call(api.keywords, locale)
    const { words } = response
    yield put(autocomplete.success(locale, words))
  } catch (error) {
    yield put(autocomplete.failure(error.message))
  } finally {
    // When done, we tell Redux we're not in the middle of a request any more
    // yield put({type: SENDING_REQUEST, sending: false})
  }
}

/**
 * Root saga manages watcher lifecycle
 */
export function* autoCompleteData() {
  const watcher = yield takeLatest(AUTOCOMPLETE.REQUEST, autoCompleteGetData)
  // Suspend execution until location changes
  yield take(LOCATION_CHANGE)
  yield cancel(watcher)
}

export function* pictogramsData() {
  const watcher = yield takeLatest(PICTOGRAMS.REQUEST, pictogramsGetData)
  // Suspend execution until location changes
  yield take(LOCATION_CHANGE)
  yield cancel(watcher)
}

// All sagas to be loaded
export default [pictogramsGetData, autoCompleteData]
<|endoftext|>


<commit_before>'use strict';

var BaseCommand = require('commander').Command,
	Migrator = require('../../lib/migrator'),
	utils = require('../../lib/utils'),
	inherits = require('util').inherits,
	Steppy = require('twostep').Steppy;

function Command(nameAndArgs, params) {
	params = params || {};
	nameAndArgs = nameAndArgs || '';
	var args = nameAndArgs.split(/ +/),
		name = args.shift();
	BaseCommand.call(this, name);

	this.parseExpectedArgs(args);

	this._initParams = params.initParams;
}
inherits(Command, BaseCommand);

exports.Command = Command;

var originalCommand = Command.prototype.command;
Command.prototype.command = function(command) {
	if (command instanceof BaseCommand) {
		this.commands.push(command);
		command.parent = this;
		return command;
	} else {
		return originalCommand.apply(this, arguments);
	}
};

Command.prototype.asyncAction = function(func) {
	var self = this;
	self.action(function() {
		var args = utils.slice(arguments);
		Steppy(
			function() {
				self.init(self.parent, self._initParams);

				args.push(this.slot());
				func.apply(self, args);
			},
			function(err) {
				if (err) {
					self.onError(err);
					process.exit(1);
				} else {
					if (self.parent.exit) process.exit();
				}

			}
		);
	});
};

/*
 * Init logger. Log levels: debug, log, info, error
 * `debug` could be enabled by --trace
 * `log` could be supressed by --silent
 * `info`, `error` will be shown anyway
 */
Command.prototype._initLogger = function(params) {
	var logger = utils.extend({}, console);

	logger.debug = params.trace ? logger.log : utils.noop;

	if (params.silent) {
		logger.log = utils.noop;
	}

	this.logger = logger;
};

Command.prototype.init = function(params, opts) {
	opts = opts || {};

	Command.initialized = true;

	this._initLogger(this.parent);

	var migrator = new Migrator(params);

	if (!opts.skipDirCheck && !migrator.isDirExists()) {
		handleError(new Error(
			'Migrations directory: ' + migrator.params.dir + ' doesn`t exist.\n' +
			'You should run `init` command to initialize migrations or change\n' +
			'`dir` option.'
		));
	}

	this.logger.debug('current parameters:', migrator.params);

	this.migrator = migrator;
};

Command.prototype.onError = function(err) {
	if (this.trace || this.parent.trace) {
		this.logger.error(err.stack || err);
	} else {
		this.logger.error(err.message);
	}
};

Command.prototype._filterMigrationNames = function(params, callback) {
	this.migrator.filterMigrationNames({
		by: params.by,
		names: params.names,
		tag: params.tag
	}, function(err, filterResult) {
		callback(err, filterResult && filterResult.names);
	});
};

Command.prototype.execute = function(params, callback) {
	var self = this;
	Steppy(
		function() {
			self.migrator.connect(this.slot());
		},
		function() {
			self._execute(params, this.slot());
		},
		function(err) {
			self.migrator.disconnect(function() {
				callback(err)
			});
		}
	);
};

Command.isInitialized = function() {
	return Boolean(Command.initialized);
};
<commit_msg>fix error handling at init<commit_after>'use strict';

var BaseCommand = require('commander').Command,
	Migrator = require('../../lib/migrator'),
	utils = require('../../lib/utils'),
	inherits = require('util').inherits,
	Steppy = require('twostep').Steppy;

function Command(nameAndArgs, params) {
	params = params || {};
	nameAndArgs = nameAndArgs || '';
	var args = nameAndArgs.split(/ +/),
		name = args.shift();
	BaseCommand.call(this, name);

	this.parseExpectedArgs(args);

	this._initParams = params.initParams;
}
inherits(Command, BaseCommand);

exports.Command = Command;

var originalCommand = Command.prototype.command;
Command.prototype.command = function(command) {
	if (command instanceof BaseCommand) {
		this.commands.push(command);
		command.parent = this;
		return command;
	} else {
		return originalCommand.apply(this, arguments);
	}
};

Command.prototype.asyncAction = function(func) {
	var self = this;
	self.action(function() {
		var args = utils.slice(arguments);
		Steppy(
			function() {
				self.init(self.parent, self._initParams);

				args.push(this.slot());
				func.apply(self, args);
			},
			function(err) {
				if (err) {
					self.onError(err);
					process.exit(1);
				} else {
					if (self.parent.exit) process.exit();
				}

			}
		);
	});
};

/*
 * Init logger. Log levels: debug, log, info, error
 * `debug` could be enabled by --trace
 * `log` could be supressed by --silent
 * `info`, `error` will be shown anyway
 */
Command.prototype._initLogger = function(params) {
	var logger = utils.extend({}, console);

	logger.debug = params.trace ? logger.log : utils.noop;

	if (params.silent) {
		logger.log = utils.noop;
	}

	this.logger = logger;
};

Command.prototype.init = function(params, opts) {
	opts = opts || {};

	Command.initialized = true;

	this._initLogger(this.parent);

	var migrator = new Migrator(params);

	if (!opts.skipDirCheck && !migrator.isDirExists()) {
		throw new Error(
			'Migrations directory: ' + migrator.params.dir + ' doesn`t exist.\n' +
			'You should run `init` command to initialize migrations or change\n' +
			'`dir` option.'
		);
	}

	this.logger.debug('current parameters:', migrator.params);

	this.migrator = migrator;
};

Command.prototype.onError = function(err) {
	if (this.trace || this.parent.trace) {
		this.logger.error(err.stack || err);
	} else {
		this.logger.error(err.message);
	}
};

Command.prototype._filterMigrationNames = function(params, callback) {
	this.migrator.filterMigrationNames({
		by: params.by,
		names: params.names,
		tag: params.tag
	}, function(err, filterResult) {
		callback(err, filterResult && filterResult.names);
	});
};

Command.prototype.execute = function(params, callback) {
	var self = this;
	Steppy(
		function() {
			self.migrator.connect(this.slot());
		},
		function() {
			self._execute(params, this.slot());
		},
		function(err) {
			self.migrator.disconnect(function() {
				callback(err)
			});
		}
	);
};

Command.isInitialized = function() {
	return Boolean(Command.initialized);
};
<|endoftext|>