<commit_before>function graph(graphId, type) {

    var id = '#'.concat(graphId);

    var height = 20;
    var stroke_width = 1;
    var box_fill = "#FFF";
    var stroke_color = "#000";

    var font_size = 8;
    var red_band = Number($(id).parent().find($(".band-red")).html());
    var green_band = Number($(id).parent().find($(".band-green")).html());
    var blue_band = Number($(id).parent().find($(".band-blue")).html());
    var red_color = "#c02137";
    var green_color = "#4e9c62";
    var blue_color = "#00668e";

    var xLowNorm = 400;
    var widthNorm = 2294;

    var bandLegend = {};
    bandLegend["1"] = "Band 1: Coastal aerosol";
    bandLegend["2"] = "Band 2: Blue";
    bandLegend["3"] = "Band 3: Green";
    bandLegend["4"] = "Band 4: Red";
    bandLegend["5"] = "Band 5: Near Infrared (NIR)";
    bandLegend["6"] = "Band 6: SWIR 1";
    bandLegend["7"] = "Band 7: SWIR 2";
    bandLegend["9"] = "Band 9: Cirrus";

    if(type == "reference"){
        width = $(".preview-container").width();

        waveLengths = [[435, 451, 1, "#6ca4d3"],
                       [452, 512, 2, blue_color],
                       [533, 590, 3, green_color],
                       [636, 673, 4, red_color],
                       [851, 879, 5, "#c5a3be"],
                       [1566, 1651, 6, "#d49979"],
                       [2107, 2294, 7, "#999b98"],
                       [1362, 1384, 9, "#7f87b5"]];

        svgBar = d3.selectAll(id)
        .append("svg")
        .attr("width", width)
        .attr("height", height + stroke_width)
        .attr('class', 'spectrumMap');

        svgBar.append("rect")
        .attr("x", 0 + "px")
        .attr("y", 0 + "px")
        .attr("width", width)
        .attr("height", height + stroke_width);

        svgBar.selectAll("rect")
        .data(waveLengths, function(d){return d;})
        .enter()
        .append("rect")
        .attr("stroke-width", stroke_width)
        .attr("stroke", stroke_color)
        .attr("fill", function (d){ return (d[3]); })
        .attr("x", function (d){ return (width * ((d[0] - xLowNorm) / widthNorm)) + "px"; })
        .attr("y", 0 + "px")
        .attr("width", function (d){ return (width * (d[1] - d[0]) / (widthNorm - xLowNorm)) + "px"; })
        .attr("height", height + "px");

        svgBar.selectAll("text")
            .data(waveLengths, function(d){return d;})
            .enter()
            .append("text")
            .attr("x", function (d){ return (width * ((d[0] - xLowNorm) / widthNorm)) + "px"; })
            .attr("y", 0 + "px")
            .attr("text-anchor", "middle")
            .attr("dx", function (d){ return ((width * (d[1] - d[0]) / (widthNorm - xLowNorm)) / 2) + "px"; })
            .attr("dy", height / 2 + font_size / 2)
            .attr("font-size", font_size)
            .text(function(d) { return d[2]; });

    }else if(type == "preview"){
        width = $(id).parent().width();

        waveLengths = [[435, 451, 1, box_fill],
                       [452, 512, 2, box_fill],
                       [533, 590, 3, box_fill],
                       [636, 673, 4, box_fill],
                       [851, 879, 5, box_fill],
                       [1566, 1651, 6, box_fill],
                       [2107, 2294, 7, box_fill],
                       [1362, 1384, 9, box_fill]];

        for (var j in waveLengths){
            if(waveLengths[j][2] == red_band){
                waveLengths[j][3] = red_color;
            }else if(waveLengths[j][2] == blue_band){
                waveLengths[j][3] = blue_color;
            }else if(waveLengths[j][2] == green_band){
                waveLengths[j][3] = green_color;
            }
        }

        svgBar = d3.selectAll(id)
        .append("svg")
        .attr("width", width)
        .attr("height", height + stroke_width)
        .attr('class', 'spectrumMap');

        var yoffset = $(id).parent().find($("img")).height();
        var tip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([2 * yoffset / 3, 0])
        .html(
            "
" + bandLegend[String(red_band)] + " ----> Band 4: Red" + "
"+
            "
" + bandLegend[String(green_band)] + " ----> Band 3: Green" + "
"+
            "
" + bandLegend[String(blue_band)] + " ----> Band 2: Blue" + "
"
            );

        svgBar.call(tip);

        svgBar.append("rect")
        .attr("x", 0 + "px")
        .attr("y", 0 + "px")
        .attr("width", width)
        .attr("height", height + stroke_width)
        .on('mouseover', tip.show)
        .on('mouseout', tip.hide);

        svgBar.selectAll("rect")
        .data(waveLengths, function(d){return d;})
        .enter()
        .append("rect")
        .attr("stroke-width", stroke_width)
        .attr("stroke", stroke_color)
        .attr("fill", function (d){ return (d[3]); })
        .attr("x", function (d){ return (width * ((d[0] - xLowNorm) / widthNorm)) + "px"; })
        .attr("y", 0 + "px")
        .attr("width", function (d){ return (width * (d[1] - d[0]) / (widthNorm - xLowNorm)) + "px"; })
        .attr("height", height + "px")
        .attr("pointer-events", "none");

    }

}

$(document).ready(function(){
    $(".preview").each(function(){
        graphId = $(this).find($(".graph")).attr("id");
        graph(graphId, "preview");
        });

    $("#reference").each(function(){
        graphId = $(this).attr("id");
        graph(graphId, "reference");
        });
});

$(window).on('resize', function (){
    $(".graph").contents().remove();

    $(".preview").each(function(){
        graphId = $(this).find($(".graph")).attr("id");
        graph(graphId, "preview");
        });

    $("#reference").each(function(){
        graphId = $(this).attr("id");
        graph(graphId, "reference");
        });
});
<commit_msg>#84 Change default band to black.<commit_after>function graph(graphId, type) {

    var id = '#'.concat(graphId);

    var height = 20;
    var stroke_width = 1;
    var box_fill = "#FFF";
    var stroke_color = "#000";

    var font_size = 8;
    var red_band = Number($(id).parent().find($(".band-red")).html());
    var green_band = Number($(id).parent().find($(".band-green")).html());
    var blue_band = Number($(id).parent().find($(".band-blue")).html());
    var red_color = "#c02137";
    var green_color = "#4e9c62";
    var blue_color = "#00668e";

    var xLowNorm = 400;
    var widthNorm = 2294;

    var bandLegend = {};
    bandLegend["1"] = "Band 1: Coastal aerosol";
    bandLegend["2"] = "Band 2: Blue";
    bandLegend["3"] = "Band 3: Green";
    bandLegend["4"] = "Band 4: Red";
    bandLegend["5"] = "Band 5: Near Infrared (NIR)";
    bandLegend["6"] = "Band 6: SWIR 1";
    bandLegend["7"] = "Band 7: SWIR 2";
    bandLegend["9"] = "Band 9: Cirrus";

    if(type == "reference"){
        width = $(".preview-container").width();

        waveLengths = [[435, 451, 1, "#6ca4d3"],
                       [452, 512, 2, blue_color],
                       [533, 590, 3, green_color],
                       [636, 673, 4, red_color],
                       [851, 879, 5, "#c5a3be"],
                       [1566, 1651, 6, "#d49979"],
                       [2107, 2294, 7, "#999b98"],
                       [1362, 1384, 9, "#7f87b5"]];

        svgBar = d3.selectAll(id)
        .append("svg")
        .attr("width", width)
        .attr("height", height + stroke_width)
        .attr('class', 'spectrumMap');

        svgBar.append("rect")
        .attr("x", 0 + "px")
        .attr("y", 0 + "px")
        .attr("width", width)
        .attr("height", height + stroke_width);

        svgBar.selectAll("rect")
        .data(waveLengths, function(d){return d;})
        .enter()
        .append("rect")
        .attr("stroke-width", stroke_width)
        .attr("stroke", stroke_color)
        .attr("fill", function (d){ return (d[3]); })
        .attr("x", function (d){ return (width * ((d[0] - xLowNorm) / widthNorm)) + "px"; })
        .attr("y", 0 + "px")
        .attr("width", function (d){ return (width * (d[1] - d[0]) / (widthNorm - xLowNorm)) + "px"; })
        .attr("height", height + "px");

        svgBar.selectAll("text")
            .data(waveLengths, function(d){return d;})
            .enter()
            .append("text")
            .attr("x", function (d){ return (width * ((d[0] - xLowNorm) / widthNorm)) + "px"; })
            .attr("y", 0 + "px")
            .attr("text-anchor", "middle")
            .attr("dx", function (d){ return ((width * (d[1] - d[0]) / (widthNorm - xLowNorm)) / 2) + "px"; })
            .attr("dy", height / 2 + font_size / 2)
            .attr("font-size", font_size)
            .text(function(d) { return d[2]; });

    }else if(type == "preview"){
        width = $(id).parent().width();

        waveLengths = [[435, 451, 1, box_fill],
                       [452, 512, 2, box_fill],
                       [533, 590, 3, box_fill],
                       [636, 673, 4, box_fill],
                       [851, 879, 5, box_fill],
                       [1566, 1651, 6, box_fill],
                       [2107, 2294, 7, box_fill],
                       [1362, 1384, 9, box_fill]];

        for (var j in waveLengths){
            if(waveLengths[j][2] == red_band){
                waveLengths[j][3] = red_color;
            }else if(waveLengths[j][2] == blue_band){
                waveLengths[j][3] = blue_color;
            }else if(waveLengths[j][2] == green_band){
                waveLengths[j][3] = green_color;
            }else{
                waveLengths[j][3] = "black";
            }
        }

        svgBar = d3.selectAll(id)
        .append("svg")
        .attr("width", width)
        .attr("height", height + stroke_width)
        .attr('class', 'spectrumMap');

        var yoffset = $(id).parent().find($("img")).height();
        var tip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([2 * yoffset / 3, 0])
        .html(
            "
" + bandLegend[String(red_band)] + " ----> Band 4: Red" + "
"+
            "
" + bandLegend[String(green_band)] + " ----> Band 3: Green" + "
"+
            "
" + bandLegend[String(blue_band)] + " ----> Band 2: Blue" + "
"
            );

        svgBar.call(tip);

        svgBar.append("rect")
        .attr("x", 0 + "px")
        .attr("y", 0 + "px")
        .attr("width", width)
        .attr("height", height + stroke_width)
        .on('mouseover', tip.show)
        .on('mouseout', tip.hide);

        svgBar.selectAll("rect")
        .data(waveLengths, function(d){return d;})
        .enter()
        .append("rect")
        .attr("stroke-width", stroke_width)
        .attr("stroke", stroke_color)
        .attr("fill", function (d){ return (d[3]); })
        .attr("x", function (d){ return (width * ((d[0] - xLowNorm) / widthNorm)) + "px"; })
        .attr("y", 0 + "px")
        .attr("width", function (d){ return (width * (d[1] - d[0]) / (widthNorm - xLowNorm)) + "px"; })
        .attr("height", height + "px")
        .attr("pointer-events", "none");

    }

}

$(document).ready(function(){
    $(".preview").each(function(){
        graphId = $(this).find($(".graph")).attr("id");
        graph(graphId, "preview");
        });

    $("#reference").each(function(){
        graphId = $(this).attr("id");
        graph(graphId, "reference");
        });
});

$(window).on('resize', function (){
    $(".graph").contents().remove();

    $(".preview").each(function(){
        graphId = $(this).find($(".graph")).attr("id");
        graph(graphId, "preview");
        });

    $("#reference").each(function(){
        graphId = $(this).attr("id");
        graph(graphId, "reference");
        });
});
<|endoftext|>


<commit_before><commit_msg>adding gems and assets back after successful heroku deploy<commit_after>$(document).on('page:change', function() {
  // var getFieldCount = function() {
  //   var accountType = $('#account_type').val();
  //   return $('.field.' + accountType).size();
  // };

  // Add classes to label each field under its account type for later easy grabbing in jQueries
  var accountFields = {}
  try {
    accountFields = JSON.parse($('#account_fields').val());
  } catch(jsonException) {
    //ignore errors without crashing
  }
  for (var accountType in accountFields) {
    var fields = accountFields[accountType];
    for (field of fields) {
      var field = $('#account_' + field).closest('.field');
      field.addClass(accountType);
    }
  }

  if ($('#edit_account').size() > 0) {
    var showCorrectFieldsPerAccountType = function() {
      $('.field').hide();
      var accountType = $('#account_type').val();
      var fields = accountFields[accountType];
      for (field of fields) {
        var field = $('#account_' + field).closest('.field');
        field.show();
      }
    };
    $('#account_type').change(showCorrectFieldsPerAccountType);
    showCorrectFieldsPerAccountType();
  }

  if ($('#new_account').size() > 0) {
    var showCorrectFieldsPerAccountType = function() {
      $('.field').hide();
      var accountType = $('#account_type').val();
      var fields = accountFields[accountType];
      for (field of fields) {
        var field = $('#account_' + field).closest('.field');
        field.show();
      }
    };
    $('#account_type').change(showCorrectFieldsPerAccountType);
    showCorrectFieldsPerAccountType();

    $("#account_type").prepend("<option value='' selected='selected'>Please Select</option>");
  }

});
<|endoftext|>


<commit_before>$(document).ready(function(){
  var correctCharacters = $('#typingContent pre').text().split("");
  var correctWords = 0;
  var characterIndex = 0;
  var incorrectStrokes = {};
  var start_time = new Date();
  var mistake = false;
  var finished = false;

  $(document).keyup(function(e) {
    if (e.keyCode === 27) typingFinished();
  });

  var rx = /INPUT|SELECT|TEXTAREA/i;
  var transitionTime = 500;
  $(document).bind("keydown keypress", function(e){
    if( e.which == 8 ){ // 8 == backspace
      if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
          e.preventDefault();
      }
    }
  });

  $('.textarea').bind('keyup, mouseup', function(e) {
    if(e.which == 9) { e.preventDefault(); }
  });

  // Dom Logic
  var toggleText = function(){
    $('#typingContent').hide(transitionTime);
    $('#options').show(transitionTime);
    $('#stats').show(transitionTime);
    $('html').off();
  }
  var typingFinished = function(e){
    toggleText();
    showChart(incorrectStrokes);
    $('#doneButton').hide();
  }

  $('#doneButton').on("click", typingFinished);
  var isFinished = function(){
    if(finished){
      return true;
    }else if(characterIndex>=correctCharacters.length){
      finished = true
      typingFinished();
      toggleText();
      return true;
    }else{
      return false;
    }
  };

  var showStats = function(){
    updateWastedStrokes();
    updateWPM();
  };

  var goToNextNonWhitespace = function(){
    while(characterIndex<correctCharacters.length){
      if(correctCharacters[characterIndex]===" "|| correctCharacters[characterIndex]==="\n"|| correctCharacters[characterIndex]==="\t"){
        highlightGreen(characterIndex);
        characterIndex++;
      }
      else{
        break;
      }
    }
  }

  var preparePage = function(){
    var highlightable = [];
    $('#options').hide();
    $('#stats').hide();
    correctCharacters.forEach(function(value, index, a){
      if(value==="\n"){value=" "+value};
      highlightable.push(""+ value +"");
    });
    $('#typingContent pre').html(highlightable.join(""));
    goToNextNonWhitespace();
    highlightCurrent();
  }

  var highlightCurrent = function(){
    highlightYellow(characterIndex);
  };

  var highlightGreen = function(index){
    $('span[data-character-index='+ index +']').removeClass().addClass('green');
  };

  var highlightYellow = function(index){
    $('span[data-character-index='+ index +']').removeClass().addClass('yellow');
  }

  var highlightRed = function(index){
    $('span[data-character-index='+ index +']').removeClass().addClass('red');
  }

  // Stat Logic
  var updateWPM = function(){
    var time_spent = (new Date()).getTime() - start_time;
    $('#wpm').html(Math.ceil(correctWords/(time_spent/60000)));
  }

  var updateWastedStrokes = function(){
    var totalStrokes = 0;
    for (var keyCode in incorrectStrokes)
      totalStrokes += incorrectStrokes[keyCode];

    $('#stats span#strokes').text(totalStrokes);
  }

  var trackIncorrectStroke = function(keyCode){
    incorrectStrokes[keyCode] = incorrectStrokes[keyCode] + 1 || 1;
  };

  var validateKeyCorrectness = function(keyCode, currentChar) {
    var charIsCorrect = (currentChar === String.fromCharCode(keyCode));
    var newline = (correctCharacters[characterIndex] === "\n" && keyCode === 13);

    if (isFinished())
      return;

    if ((charIsCorrect || newline) && !mistake) {
      highlightGreen(characterIndex);
      characterIndex++;
      if (newline) {
        goToNextNonWhitespace();
        isFinished();
      }
      highlightCurrent();
    } else if (keyCode === 8 && mistake) {
      highlightCurrent();
      mistake = false;
    } else {
      trackIncorrectStroke(keyCode);
      highlightRed(characterIndex);
      mistake = true;
    }
  }

  var updateWordCount = function(keyCode, currentChar) {
    var newWordChars = {"\n": 13, " ": 32, "/": 47, "=": 61, ".": 46, ">": 62, ")": 41, ";": 59};
    if (newWordChars[currentChar] === keyCode && !mistake)
      correctWords++;
  }

  var checkKeyPress = function(keyCode){
    var currentChar = correctCharacters[characterIndex];
    updateWordCount(keyCode, currentChar);
    validateKeyCorrectness(keyCode, currentChar);
    showStats();
  }

  $("html").keypress(function(keyEvent){
    keyEvent.preventDefault();
    if(keyEvent.which !== 8)
      checkKeyPress(keyEvent.keyCode);
  })

  $("html").keyup(function(keyEvent){
    if(keyEvent.which === 8)
      checkKeyPress(keyEvent.keyCode);
  });

  preparePage();

});<commit_msg>edit error log to show keys user was trying to type instead of ones that they typed on accident<commit_after>$(document).ready(function(){
  var correctCharacters = $('#typingContent pre').text().split("");
  var correctWords = 0;
  var characterIndex = 0;
  var incorrectStrokes = {};
  var start_time = new Date();
  var mistake = false;
  var finished = false;

  $(document).keyup(function(e) {
    if (e.keyCode === 27) typingFinished();
  });

  var rx = /INPUT|SELECT|TEXTAREA/i;
  var transitionTime = 500;
  $(document).bind("keydown keypress", function(e){
    if( e.which == 8 ){ // 8 == backspace
      if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
          e.preventDefault();
      }
    }
  });

  $('.textarea').bind('keyup, mouseup', function(e) {
    if(e.which == 9) { e.preventDefault(); }
  });

  // Dom Logic
  var toggleText = function(){
    $('#typingContent').hide(transitionTime);
    $('#options').show(transitionTime);
    $('#stats').show(transitionTime);
    $('html').off();
  }
  var typingFinished = function(e){
    toggleText();
    showChart(incorrectStrokes);
    $('#doneButton').hide();
  }

  $('#doneButton').on("click", typingFinished);
  var isFinished = function(){
    if(finished){
      return true;
    }else if(characterIndex>=correctCharacters.length){
      finished = true
      typingFinished();
      toggleText();
      return true;
    }else{
      return false;
    }
  };

  var showStats = function(){
    updateWastedStrokes();
    updateWPM();
  };

  var goToNextNonWhitespace = function(){
    while(characterIndex<correctCharacters.length){
      if(correctCharacters[characterIndex]===" "|| correctCharacters[characterIndex]==="\n"|| correctCharacters[characterIndex]==="\t"){
        highlightGreen(characterIndex);
        characterIndex++;
      }
      else{
        break;
      }
    }
  }

  var preparePage = function(){
    var highlightable = [];
    $('#options').hide();
    $('#stats').hide();
    correctCharacters.forEach(function(value, index, a){
      if(value==="\n"){value=" "+value};
      highlightable.push(""+ value +"");
    });
    $('#typingContent pre').html(highlightable.join(""));
    goToNextNonWhitespace();
    highlightCurrent();
  }

  var highlightCurrent = function(){
    highlightYellow(characterIndex);
  };

  var highlightGreen = function(index){
    $('span[data-character-index='+ index +']').removeClass().addClass('green');
  };

  var highlightYellow = function(index){
    $('span[data-character-index='+ index +']').removeClass().addClass('yellow');
  }

  var highlightRed = function(index){
    $('span[data-character-index='+ index +']').removeClass().addClass('red');
  }

  // Stat Logic
  var updateWPM = function(){
    var time_spent = (new Date()).getTime() - start_time;
    $('#wpm').html(Math.ceil(correctWords/(time_spent/60000)));
  }

  var updateWastedStrokes = function(){
    var totalStrokes = 0;
    for (var keyCode in incorrectStrokes)
      totalStrokes += incorrectStrokes[keyCode];

    $('#stats span#strokes').text(totalStrokes);
  }

  var trackIncorrectStroke = function(keyCode){
    incorrectStrokes[keyCode] = incorrectStrokes[keyCode] + 1 || 1;
  };

  var validateKeyCorrectness = function(keyCode, currentChar) {
    var charIsCorrect = (currentChar === String.fromCharCode(keyCode));
    var newline = (correctCharacters[characterIndex] === "\n" && keyCode === 13);

    if (isFinished())
      return;

    if ((charIsCorrect || newline) && !mistake) {
      highlightGreen(characterIndex);
      characterIndex++;
      if (newline) {
        goToNextNonWhitespace();
        isFinished();
      }
      highlightCurrent();
    } else if (keyCode === 8 && mistake) {
      highlightCurrent();
      mistake = false;
    } else {
      trackIncorrectStroke(currentChar.charCodeAt(0));
      highlightRed(characterIndex);
      mistake = true;
    }
  }

  var updateWordCount = function(keyCode, currentChar) {
    var newWordChars = {"\n": 13, " ": 32, "/": 47, "=": 61, ".": 46, ">": 62, ")": 41, ";": 59};
    if (newWordChars[currentChar] === keyCode && !mistake)
      correctWords++;
  }

  var checkKeyPress = function(keyCode){
    var currentChar = correctCharacters[characterIndex];
    updateWordCount(keyCode, currentChar);
    validateKeyCorrectness(keyCode, currentChar);
    showStats();
  }

  $("html").keypress(function(keyEvent){
    keyEvent.preventDefault();
    if(keyEvent.which !== 8)
      checkKeyPress(keyEvent.keyCode);
  })

  $("html").keyup(function(keyEvent){
    if(keyEvent.which === 8)
      checkKeyPress(keyEvent.keyCode);
  });

  preparePage();

});<|endoftext|>


<commit_before>//    Copyright 2017 Operation Paws for Homes
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

$( function () {

    $(document).on('click', '.toggle-edit-comment', function(e){
      var $parent = $(e.target).parents('form.edit_comment');
      isEditing = $($parent).data("editing");

      if (isEditing) {
        showComment($parent);
      }
      else {
        editComment($parent);
      }
      $($parent).data("editing", !isEditing);
    });

  $('body').on('ajax:success', 'form#new_comment', function(event,result,status) {
    var $form = $(event.target);
    // so it worked, add to the comment list
    refresh_comments(result);

    // reset the form validation class
    $form.removeClass('was-validated')

    // clear comment field for next comment
    $('.comment_content').val('');

    // Turn the POST button back on
    $('.comment_submit').prop('disabled', false);
  });

  $('body').on('ajax:success', 'form.edit_comment', function(event,result,status) {
    var $form = $(event.target);
    var comment_id = $form.find("div[id^=comment_content]").attr('id').match(/\d+/)[0]
    $('.read-only-comment#comment_content_'+comment_id).closest('form').closest('.row').replaceWith(result);
  });

});

function editComment($parent) {
  $parent.find('.read-only-comment').hide();
  $parent.find('.editable-comment').show();
  $parent.find('.toggle-edit-comment').removeClass('btn-primary').text('Cancel');
  $parent.find('.save-edit-comment').show();
}

function showComment($parent) {
  $parent.find('.read-only-comment').show();
  $parent.find('.editable-comment').hide();
  $parent.find('.toggle-edit-comment').addClass('btn-primary').text('Edit');
  $parent.find('.save-edit-comment').hide();
}

function refresh_comments(data) {
  $("[id^='comment_table']").prepend(data);
  $("[id^='all_table']").prepend(data);
}
<commit_msg>comments are now editable on touch devices<commit_after>//    Copyright 2017 Operation Paws for Homes
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

$( function () {

    $(document).on('click touchstart', '.toggle-edit-comment', function(e){
      var $parent = $(e.target).parents('form.edit_comment');
      isEditing = $($parent).data("editing");

      if (isEditing) {
        showComment($parent);
      }
      else {
        editComment($parent);
      }
      $($parent).data("editing", !isEditing);
    });

  $('body').on('ajax:success', 'form#new_comment', function(event,result,status) {
    var $form = $(event.target);
    // so it worked, add to the comment list
    refresh_comments(result);

    // reset the form validation class
    $form.removeClass('was-validated')

    // clear comment field for next comment
    $('.comment_content').val('');

    // Turn the POST button back on
    $('.comment_submit').prop('disabled', false);
  });

  $('body').on('ajax:success', 'form.edit_comment', function(event,result,status) {
    var $form = $(event.target);
    var comment_id = $form.find("div[id^=comment_content]").attr('id').match(/\d+/)[0]
    $('.read-only-comment#comment_content_'+comment_id).closest('form').closest('.row').replaceWith(result);
  });

});

function editComment($parent) {
  $parent.find('.read-only-comment').hide();
  $parent.find('.editable-comment').show();
  $parent.find('.toggle-edit-comment').removeClass('btn-primary').text('Cancel');
  $parent.find('.save-edit-comment').show();
}

function showComment($parent) {
  $parent.find('.read-only-comment').show();
  $parent.find('.editable-comment').hide();
  $parent.find('.toggle-edit-comment').addClass('btn-primary').text('Edit');
  $parent.find('.save-edit-comment').hide();
}

function refresh_comments(data) {
  $("[id^='comment_table']").prepend(data);
  $("[id^='all_table']").prepend(data);
}
<|endoftext|>


<commit_before>window.LARA = {
  /****************************************************************************
   @function addPopup: Ask LARA to add a new popup window
   @arg {IPopupOptions} popupOptions
   @returns {IPopupController} popupController

   Note that many options closely resemble jQuery UI dialog options which is used under the hood.
   You can refer to jQuery UI API docs in many cases: https://api.jqueryui.com/dialog
   Only `content` is required. Other options have reasonable default values (subject to change,
   so if you expect particular behaviour, provide necessary options explicitly).

   React warning: if you use React to render content, remember to call `ReactDOM.unmountComponentAtNode(content)`
   in `onRemove` handler.

   interface IPopupOptions {
     content: HTMLElement | string;
     autoOpen?: boolean;
     closeOnEscape?: boolean;
     // Removes popup HTMLElement when it is closed by the user. Otherwise, it will stay hidden and might be
     // reopened programmatically.
     removeOnClose?: boolean;
     title?: string;
     closeButton?: boolean;
     color?: string;
     modal?: boolean;
     draggable?: boolean;
     resizable?: boolean;
     // Please see: https://api.jqueryui.com/dialog/#option-position
     position?: { my: string, at: string, of: HTMLElement};
     width?: number;
     // number in px or "auto"
     height?: number | string;
     padding?: number;
     backgroundColor?: string;
     titlebarColor?: string;
     onOpen?: () => void;
     onClose?: () => void;
     // Triggered when a dialog is about to close. If canceled (by returning false), the dialog will not close.
     onBeforeClose?: () => boolean;
     onResize?: () => void;
     onDragStart?: () => void;
     onDragStop?: () => void;
   }

   interface IPopupController {
     // Opens popup (makes sense only if autoOpen option is set to false during initialization).
     open: () => void;
     // Closes popup (display: none). Also removes HTML element from DOM tree if `removeOnClose` is equal to true.
     close: () => void;
     // Removes HTML element from DOM tree.
     remove: () => void;
   }
   ****************************************************************************/
   OPEN_POPUP_DEFAULT_OPTIONS: {
    title: '',
    autoOpen: true,
    closeButton: true,
    closeOnEscape: false,
    removeOnClose: true,
    modal: false,
    draggable: true,
    resizable: true,
    width: 300,
    height: 'auto',
    padding: 10,
    // Note that dialogClass is intentionally undocumented. Styling uses class makes us depend on the
    // current dialog implementation. It might be necessary for LARA themes, although plugins should not use it.
    dialogClass: '',
    backgroundColor: '',
    titlebarColor: '',
    position: { my: "center", at: "center", of: window },
    onOpen: null,
    onClose: null,
    onBeforeClose: null,
    onResize: null,
    onDragStart: null,
    onDragStop: null
  },

  addPopup: function (options) {
    options = $.extend({}, this.OPEN_POPUP_DEFAULT_OPTIONS, options);
    if (!options.content) {
      throw new Error('LARA.addPopup - content option is required');
    }
    if (options.dialogClass) {
      console.warn('LARA.addPopup - dialogClass option is discouraged and should not be used by plugins');
    }
    var $content = typeof options.content === 'string' ? $('' + options.content + '') : $(options.content);
    var $dialog = null;
    var remove = function () {
      if (options.onRemove) {
        options.onRemove();
      }
      $dialog.remove();
    }
    $content.dialog({
      title: options.title,
      autoOpen: options.autoOpen,
      closeOnEscape: options.closeOnEscape,
      modal: options.modal,
      draggable: options.draggable,
      width: options.width,
      height: options.height,
      resizable: options.resizable,
      // Note that dialogClass is intentionally undocumented. Styling uses class makes us depend on the
      // current dialog implementation. It might be necessary for LARA themes, although plugins should not use it.
      dialogClass: options.dialogClass,
      position: options.position,
      open: options.onOpen,
      close: function () {
        if (options.onClose) {
          options.onClose();
        }
        // Remove dialog from DOM tree.
        if (options.removeOnClose) {
          remove();
        }
      },
      beforeClose: options.onBeforeClose,
      resize: options.onResize,
      dragStart: options.onDragStart,
      dragStop: options.onDragStop
    });
    $dialog = $content.closest('.ui-dialog');
    $dialog.css('background', options.backgroundColor);
    $dialog.find('.ui-dialog-titlebar').css('background', options.titlebarColor);
    $dialog.find('.ui-dialog-content').css('padding', options.padding);
    if (!options.closeButton) {
      $dialog.find('.ui-dialog-titlebar-close').remove();
    }

    // IPopupController implementation.
    return {
      open: function () {
        $content.dialog('open');
      },
      close: function () {
        $content.dialog('close');
      },
      remove: remove
    }
  },

  /****************************************************************************
   @function saveUserState: Ask LARA to save the users state for the plugin
   @arg {ILaraPluginRef} pluginInstance - The plugin trying to save data
   @arg {string} state - A JSON string representing serialized plugin state.
   @returns Promise
  ****************************************************************************/
  saveUserState: function (pluginInstance, state) {
    console.log('Plugin', pluginInstance, 'wants to save a state:', state);
  },

  /****************************************************************************
  @function decorateContent: Ask LARA to decorate authored content (text / html)
  @arg {string[]} words - a list of case-insensitive words to be decorated
      can use limited regex
  @arg {string} replace - the replacement string.
      Can include '$1' representing the matched word.
  @arg {IEventListeners} listeners - one or more { type, listener } tuples
  interface IEventListener {
    type: string;
    listener: (evt: Event) => void;
  }

  type IEventListeners = IEventListener | IEventListener[];
  @returns void
  ****************************************************************************/
  decorateContent: function (words, replace, wordClass, listeners) {
    var domClasses = ['question-txt', 'intro-txt'];
    var options = {
      words: words,
      replace: replace
    }
    TextDecorator.decorateDOMClasses(domClasses, options, wordClass, listeners);
    var debuggingListener = {
      type: 'click',
      listener: function (evt)  {
        alert("You clicked: ", evt.target.textContent, "!");
      }
    };
    TextDecorator.addEventListeners(wordClass, [debuggingListener]);
  },

  /****************************************************************************
   private variables to keep track of our plugins.
  ****************************************************************************/
  _pluginClasses: {},
  _plugins:[],
  _plugin_labels:[],

  _pluginError: function(e, other) {
    console.group("LARA Plugin Error");
    console.error(e);
    console.dir(other);
    console.groupEnd();
  },

  _nameForPlugin: function(plugin) {
    return(plugin.name || "(unknown)");
  },

  /**************************************************************
  @function init
  This method is called to initialize the external scripts
  Called at runtime by LARA to create an instance of the plugin
  as would happen in `views/plugin/_show.html.haml`
  @arg {string} label - the the script identifier.
  @arg {IRuntimContext} runtimeContext - context for the plugin

  // Its likely we dont need most of these context values. TBD.
  Interface IRuntimeContext {
    name: string;         // Name of the plugin
    url: string;          // Url from which the plugin was loaded
    pluginId: string;     // Active record ID of the plugin scope id
    authorData: string;   // The authored configuration for this instance
    learnerData: string;  // The saved learner data for this instance
    div: DomNode;         // reserved DomNode for the plugin in ther runtime.
  }
  **************************************************************/
  initPlugin: function(_label, runtimeContext) {
    var constructor = this._pluginClasses[_label];
    var config = {};
    var plugin = null;
    if (typeof constructor == 'function') {
      try {
        if (typeof runtimeContext.config == 'string'){
          config = JSON.parse(runtimeContext.config);
          delete runtimeContext.config;
        }
        plugin = new constructor(config, runtimeContext);
        this._plugins.push(plugin);
        this._plugin_labels.push(_label);
      }
      catch(e) {
        this._pluginError(e, runtimeContext);
      }
      console.log('Plugin', _label, 'is now registered');
    }
    else {
      console.error("No plugin registered for label:", _label);
    }
  },

  /**************************************************************
   @function register
   Register a new external script as `label` with `_class `
   @arg label - the identifier of the sctipt
   @arg Class - the Plugin Class being associated with the identifier
   @example: `ExternalScripts.register('debugger', Dubugger)`
   **************************************************************/
  registerPlugin: function(_label, _class) {
    if(typeof _class == 'function') {
      if(this._pluginClasses[_label]) {
        console.error("Duplicate Plugin for label " + _label);
      }
      else {
        this._pluginClasses[_label] = _class;
      }
    }
  },
};
<commit_msg>Cleanup decorateText docs, rm debugging code<commit_after>window.LARA = {
  /****************************************************************************
   @function addPopup: Ask LARA to add a new popup window
   @arg {IPopupOptions} popupOptions
   @returns {IPopupController} popupController

   Note that many options closely resemble jQuery UI dialog options which is used under the hood.
   You can refer to jQuery UI API docs in many cases: https://api.jqueryui.com/dialog
   Only `content` is required. Other options have reasonable default values (subject to change,
   so if you expect particular behaviour, provide necessary options explicitly).

   React warning: if you use React to render content, remember to call `ReactDOM.unmountComponentAtNode(content)`
   in `onRemove` handler.

   interface IPopupOptions {
     content: HTMLElement | string;
     autoOpen?: boolean;
     closeOnEscape?: boolean;
     // Removes popup HTMLElement when it is closed by the user. Otherwise, it will stay hidden and might be
     // reopened programmatically.
     removeOnClose?: boolean;
     title?: string;
     closeButton?: boolean;
     color?: string;
     modal?: boolean;
     draggable?: boolean;
     resizable?: boolean;
     // Please see: https://api.jqueryui.com/dialog/#option-position
     position?: { my: string, at: string, of: HTMLElement};
     width?: number;
     // number in px or "auto"
     height?: number | string;
     padding?: number;
     backgroundColor?: string;
     titlebarColor?: string;
     onOpen?: () => void;
     onClose?: () => void;
     // Triggered when a dialog is about to close. If canceled (by returning false), the dialog will not close.
     onBeforeClose?: () => boolean;
     onResize?: () => void;
     onDragStart?: () => void;
     onDragStop?: () => void;
   }

   interface IPopupController {
     // Opens popup (makes sense only if autoOpen option is set to false during initialization).
     open: () => void;
     // Closes popup (display: none). Also removes HTML element from DOM tree if `removeOnClose` is equal to true.
     close: () => void;
     // Removes HTML element from DOM tree.
     remove: () => void;
   }
   ****************************************************************************/
   OPEN_POPUP_DEFAULT_OPTIONS: {
    title: '',
    autoOpen: true,
    closeButton: true,
    closeOnEscape: false,
    removeOnClose: true,
    modal: false,
    draggable: true,
    resizable: true,
    width: 300,
    height: 'auto',
    padding: 10,
    // Note that dialogClass is intentionally undocumented. Styling uses class makes us depend on the
    // current dialog implementation. It might be necessary for LARA themes, although plugins should not use it.
    dialogClass: '',
    backgroundColor: '',
    titlebarColor: '',
    position: { my: "center", at: "center", of: window },
    onOpen: null,
    onClose: null,
    onBeforeClose: null,
    onResize: null,
    onDragStart: null,
    onDragStop: null
  },

  addPopup: function (options) {
    options = $.extend({}, this.OPEN_POPUP_DEFAULT_OPTIONS, options);
    if (!options.content) {
      throw new Error('LARA.addPopup - content option is required');
    }
    if (options.dialogClass) {
      console.warn('LARA.addPopup - dialogClass option is discouraged and should not be used by plugins');
    }
    var $content = typeof options.content === 'string' ? $('' + options.content + '') : $(options.content);
    var $dialog = null;
    var remove = function () {
      if (options.onRemove) {
        options.onRemove();
      }
      $dialog.remove();
    }
    $content.dialog({
      title: options.title,
      autoOpen: options.autoOpen,
      closeOnEscape: options.closeOnEscape,
      modal: options.modal,
      draggable: options.draggable,
      width: options.width,
      height: options.height,
      resizable: options.resizable,
      // Note that dialogClass is intentionally undocumented. Styling uses class makes us depend on the
      // current dialog implementation. It might be necessary for LARA themes, although plugins should not use it.
      dialogClass: options.dialogClass,
      position: options.position,
      open: options.onOpen,
      close: function () {
        if (options.onClose) {
          options.onClose();
        }
        // Remove dialog from DOM tree.
        if (options.removeOnClose) {
          remove();
        }
      },
      beforeClose: options.onBeforeClose,
      resize: options.onResize,
      dragStart: options.onDragStart,
      dragStop: options.onDragStop
    });
    $dialog = $content.closest('.ui-dialog');
    $dialog.css('background', options.backgroundColor);
    $dialog.find('.ui-dialog-titlebar').css('background', options.titlebarColor);
    $dialog.find('.ui-dialog-content').css('padding', options.padding);
    if (!options.closeButton) {
      $dialog.find('.ui-dialog-titlebar-close').remove();
    }

    // IPopupController implementation.
    return {
      open: function () {
        $content.dialog('open');
      },
      close: function () {
        $content.dialog('close');
      },
      remove: remove
    }
  },

  /****************************************************************************
   @function saveUserState: Ask LARA to save the users state for the plugin
   @arg {ILaraPluginRef} pluginInstance - The plugin trying to save data
   @arg {string} state - A JSON string representing serialized plugin state.
   @returns Promise
  ****************************************************************************/
  saveUserState: function (pluginInstance, state) {
    console.log('Plugin', pluginInstance, 'wants to save a state:', state);
  },

  /****************************************************************************
  @function decorateContent: Ask LARA to decorate authored content (text / html)
  @arg {string[]} words - a list of case-insensitive words to be decorated. Can use limited regex.
  @arg {string} replace - the replacement string. Can include '$1' representing the matched word.
  @arg {wordClass} wordClass - CSS class used in replacement string. Necessary only if `listeners` are provided too.
  @arg {IEventListeners} listeners - one or more { type, listener } tuples. Note that events are added to `wordClass`
      described above. It's client code responsibility to use this class in the `replace` string.
  @returns void

  interface IEventListener {
    type: string;
    listener: (evt: Event) => void;
  }

  type IEventListeners = IEventListener | IEventListener[];
  ****************************************************************************/
  decorateContent: function (words, replace, wordClass, listeners) {
    var domClasses = ['question-txt', 'intro-txt'];
    var options = {
      words: words,
      replace: replace
    }
    TextDecorator.decorateDOMClasses(domClasses, options, wordClass, listeners);
  },

  /****************************************************************************
   private variables to keep track of our plugins.
  ****************************************************************************/
  _pluginClasses: {},
  _plugins:[],
  _plugin_labels:[],

  _pluginError: function(e, other) {
    console.group("LARA Plugin Error");
    console.error(e);
    console.dir(other);
    console.groupEnd();
  },

  _nameForPlugin: function(plugin) {
    return(plugin.name || "(unknown)");
  },

  /**************************************************************
  @function init
  This method is called to initialize the external scripts
  Called at runtime by LARA to create an instance of the plugin
  as would happen in `views/plugin/_show.html.haml`
  @arg {string} label - the the script identifier.
  @arg {IRuntimContext} runtimeContext - context for the plugin

  // Its likely we dont need most of these context values. TBD.
  Interface IRuntimeContext {
    name: string;         // Name of the plugin
    url: string;          // Url from which the plugin was loaded
    pluginId: string;     // Active record ID of the plugin scope id
    authorData: string;   // The authored configuration for this instance
    learnerData: string;  // The saved learner data for this instance
    div: DomNode;         // reserved DomNode for the plugin in ther runtime.
  }
  **************************************************************/
  initPlugin: function(_label, runtimeContext) {
    var constructor = this._pluginClasses[_label];
    var config = {};
    var plugin = null;
    if (typeof constructor == 'function') {
      try {
        if (typeof runtimeContext.config == 'string'){
          config = JSON.parse(runtimeContext.config);
          delete runtimeContext.config;
        }
        plugin = new constructor(config, runtimeContext);
        this._plugins.push(plugin);
        this._plugin_labels.push(_label);
      }
      catch(e) {
        this._pluginError(e, runtimeContext);
      }
      console.log('Plugin', _label, 'is now registered');
    }
    else {
      console.error("No plugin registered for label:", _label);
    }
  },

  /**************************************************************
   @function register
   Register a new external script as `label` with `_class `
   @arg label - the identifier of the sctipt
   @arg Class - the Plugin Class being associated with the identifier
   @example: `ExternalScripts.register('debugger', Dubugger)`
   **************************************************************/
  registerPlugin: function(_label, _class) {
    if(typeof _class == 'function') {
      if(this._pluginClasses[_label]) {
        console.error("Duplicate Plugin for label " + _label);
      }
      else {
        this._pluginClasses[_label] = _class;
      }
    }
  },
};
<|endoftext|>


<commit_before>//// CONSTRUCTOR ////

function Project(project) {
  this.id = project.id
  this.title = project.title
  this.description = project.description
  this.dueDate = moment(project.due_date)
  this.completed = project.completed
  this.updatedAt = moment(project.updated_at)
  this.project_teams = project.project_teams
  this.team = project.team
  this.teamMembers = project.team_members
  this.tasks = project.tasks
  this.isCompleted = project.is_completed
  this.teamMember = project.is_team_member
  this.isPastDueDate = project.is_past_due_date
  this.remainingTasks = project.remaining_tasks_count
  this.unassignedTasks = project.unassigned_tasks_count
}

//// PROTOTYPE METHODS ////

Project.prototype.formatDueDate = function() {
  let dueDateFormat
    if (this.isPastDueDate){
      dueDateFormat = `<p class="left red-text" style="margin: 0">${this.dueDate.format('dddd, D MMMM YYYY')}</p><br>`
    } else {
      dueDateFormat = `<p class="left" style="margin: 0">${this.dueDate.format('dddd, D MMMM YYYY')}</p><br>`
    }
    return dueDateFormat
}

Project.prototype.formatTasks = function(task) {
  let taskIcon
    if (task.completed) {
      taskIcon = `

          doneCompleted: ${task.updated_at}

`
    } else if (task.user_id == null) {
      taskIcon = `
        add
`
    } else if (task.is_current_user_task) {
      taskIcon = `

          turned_in

`
    } else {taskIcon=''}

  let taskDueDate
    if (task.is_past_due_date){
      taskDueDate = `<p class="left red-text" style="margin: 0">${task.due_date}</p><br>`
    } else {
      taskDueDate = `<p class="left" style="margin: 0">${task.due_date}</p><br>`
    }

  let username = task.user ? `<p><strong>Assigned to:</strong> ${task.user}</p>` : ''

  let taskFormat = `

    ${taskIcon}

${task.title}e

${task.content}

      ${username}
      Due Date

      ${taskDueDate}

        delete

    `

  return taskFormat
}

Project.prototype.formatIndex = function() {
  let icon
    if (this.isCompleted){
      icon = `
                done_all Project Completed: ${this.updatedAt.format('dddd, D MMMM YYYY')}

`
    } else if (this.teamMember){
      icon = `<i class="material-icons teal-text">lock_open</i>`
    } else {
      icon = `add

`
    }

  let projectHtml = `

      ${icon}

${this.title}

${this.description}

          Due Date

          ${this.formatDueDate()}

  `
  return projectHtml
}

Project.prototype.formatShow = function() {
  let completedIcon
    if (this.isCompleted) {
      completedIcon = `done_all Project Completed: ${this.updatedAt.format('dddd, D MMMM YYYY')}

`
    } else { completedIcon = ''}

  let projectDetails = `

      ${this.title}

      ${this.description}

`

  let projectShowHtml = `
    ${completedIcon}
    ${projectDetails}

      Due date

      ${this.formatDueDate()}

Tasks Overview

          Incompleted
          Unassigned
          Completed
          Total

        ${this.remainingTasks}
        ${this.unassignedTasks}
        ${this.remainingTasks - this.unassignedTasks}
        ${this.tasks.length}

      menu

note_add

mode_edit

            delete

          fast_rewind

  `
  return projectShowHtml
}

//// EVENT LISTENERS ////

const bindClickHandlers = () => {
  $('.all-projects').on('click', e => {
    e.preventDefault()
    history.pushState(null, null, '/projects')
    $.get('/projects.json', projects => {
      $('#main').html('
All Projects
')
      $.each(projects, (idx,val) => {
        let project = new Project(val)
        let projectHtml = project.formatIndex()
        $('#main').append(projectHtml)
      })
      bindShowListeners()
      $('.tooltipped').tooltip({delay: 50})
    })
  })

  $('#new_task').on('submit', e => {
    e.preventDefault()
    let id = e.currentTarget.id
    history.pushState(null, null, `/projects/${id}`)
    $.post(e.currentTarget.action, $(e.target).serialize(), resp => {
      $('#main').html('')
      let project = new Project(resp)
      let projectShowHtml = project.formatShow()
      $('#main').append(projectShowHtml)
      $.each(project.tasks, (idx,task) => {
        let taskHtml = project.formatTasks(task)
        $('#main').append(taskHtml)
      })
      $('.tooltipped').tooltip({delay: 50})
    })
  })
}

const bindShowListeners = () => {
  $('.show').on('click', e => {
    e.preventDefault()
    let id = e.currentTarget.id
    history.pushState(null, null, `/projects/${id}`)
    $.get('/projects/' + id + '.json', val => {
      $('#main').html('')
      let project = new Project(val)
      let projectShowHtml = project.formatShow()
      $('#main').append(projectShowHtml)
      $.each(project.tasks, (idx,task) => {
        let taskHtml = project.formatTasks(task)
        $('#main').append(taskHtml)
      })
      $('.tooltipped').tooltip({delay: 50})
    })
  })
}

$(() => {
  bindClickHandlers()
  bindShowListeners()
})<commit_msg>refactered id in $('#new_task'). also changed e.target to e.currentTarget<commit_after>//// CONSTRUCTOR ////

function Project(project) {
  this.id = project.id
  this.title = project.title
  this.description = project.description
  this.dueDate = moment(project.due_date)
  this.completed = project.completed
  this.updatedAt = moment(project.updated_at)
  this.project_teams = project.project_teams
  this.team = project.team
  this.teamMembers = project.team_members
  this.tasks = project.tasks
  this.isCompleted = project.is_completed
  this.teamMember = project.is_team_member
  this.isPastDueDate = project.is_past_due_date
  this.remainingTasks = project.remaining_tasks_count
  this.unassignedTasks = project.unassigned_tasks_count
}

//// PROTOTYPE METHODS ////

Project.prototype.formatDueDate = function() {
  let dueDateFormat
    if (this.isPastDueDate){
      dueDateFormat = `<p class="left red-text" style="margin: 0">${this.dueDate.format('dddd, D MMMM YYYY')}</p><br>`
    } else {
      dueDateFormat = `<p class="left" style="margin: 0">${this.dueDate.format('dddd, D MMMM YYYY')}</p><br>`
    }
    return dueDateFormat
}

Project.prototype.formatTasks = function(task) {
  let taskIcon
    if (task.completed) {
      taskIcon = `

          doneCompleted: ${task.updated_at}

`
    } else if (task.user_id == null) {
      taskIcon = `
        add
`
    } else if (task.is_current_user_task) {
      taskIcon = `

          turned_in

`
    } else {taskIcon=''}

  let taskDueDate
    if (task.is_past_due_date){
      taskDueDate = `<p class="left red-text" style="margin: 0">${task.due_date}</p><br>`
    } else {
      taskDueDate = `<p class="left" style="margin: 0">${task.due_date}</p><br>`
    }

  let username = task.user ? `<p><strong>Assigned to:</strong> ${task.user}</p>` : ''

  let taskFormat = `

    ${taskIcon}

${task.title}e

${task.content}

      ${username}
      Due Date

      ${taskDueDate}

        delete

    `

  return taskFormat
}

Project.prototype.formatIndex = function() {
  let icon
    if (this.isCompleted){
      icon = `
                done_all Project Completed: ${this.updatedAt.format('dddd, D MMMM YYYY')}

`
    } else if (this.teamMember){
      icon = `<i class="material-icons teal-text">lock_open</i>`
    } else {
      icon = `add

`
    }

  let projectHtml = `

      ${icon}

${this.title}

${this.description}

          Due Date

          ${this.formatDueDate()}

  `
  return projectHtml
}

Project.prototype.formatShow = function() {
  let completedIcon
    if (this.isCompleted) {
      completedIcon = `done_all Project Completed: ${this.updatedAt.format('dddd, D MMMM YYYY')}

`
    } else { completedIcon = ''}

  let projectDetails = `

      ${this.title}

      ${this.description}

`

  let projectShowHtml = `
    ${completedIcon}
    ${projectDetails}

      Due date

      ${this.formatDueDate()}

Tasks Overview

          Incompleted
          Unassigned
          Completed
          Total

        ${this.remainingTasks}
        ${this.unassignedTasks}
        ${this.remainingTasks - this.unassignedTasks}
        ${this.tasks.length}

      menu

note_add

mode_edit

            delete

          fast_rewind

  `
  return projectShowHtml
}

//// EVENT LISTENERS ////

const bindClickHandlers = () => {
  $('.all-projects').on('click', e => {
    e.preventDefault()
    history.pushState(null, null, '/projects')
    $.get('/projects.json', projects => {
      $('#main').html('
All Projects
')
      $.each(projects, (idx,val) => {
        let project = new Project(val)
        let projectHtml = project.formatIndex()
        $('#main').append(projectHtml)
      })
      bindShowListeners()
      $('.tooltipped').tooltip({delay: 50})
    })
  })

  $('#new_task').on('submit', e => {
    e.preventDefault()
    let id = e.currentTarget.getAttribute('project')
    history.pushState(null, null, `/projects/${id}`)
    $.post(e.currentTarget.action, $(e.currentTarget).serialize(), resp => {
      $('#main').html('')
      let project = new Project(resp)
      let projectShowHtml = project.formatShow()
      $('#main').append(projectShowHtml)
      $.each(project.tasks, (idx,task) => {
        let taskHtml = project.formatTasks(task)
        $('#main').append(taskHtml)
      })
      $('.tooltipped').tooltip({delay: 50})
    })
  })
}

const bindShowListeners = () => {
  $('.show').on('click', e => {
    e.preventDefault()
    let id = e.currentTarget.id
    history.pushState(null, null, `/projects/${id}`)
    $.get('/projects/' + id + '.json', val => {
      $('#main').html('')
      let project = new Project(val)
      let projectShowHtml = project.formatShow()
      $('#main').append(projectShowHtml)
      $.each(project.tasks, (idx,task) => {
        let taskHtml = project.formatTasks(task)
        $('#main').append(taskHtml)
      })
      $('.tooltipped').tooltip({delay: 50})
    })
  })
}

$(() => {
  bindClickHandlers()
  bindShowListeners()
})<|endoftext|>


<commit_before>// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.
// You can use CoffeeScript in this file: http://coffeescript.org/

window.onload = function () {
  $.getJSON('/readings.json', function(data) {

    dataPoints = [];
    dataPoints[0] = [];
    dataPoints[1] = [];
    for (var i = 0; i < data.length; i++) {
      var date = new Date(data[i].created_at);
      var temperature = parseFloat(data[i].temperature);
      var humidity = parseFloat(data[i].humidity);
      dataPoints[0].push({
        x: date, y: temperature
      });
      dataPoints[1].push({
        x: date, y: humidity
      });
    }

    var stripOpacity = .4;

    var aleStrip = {
      opacity: stripOpacity,
      startValue:20,
      endValue:22,
      color:"#FCF6B1",
      label:"Ale"
    };

    var lagerStrip = {
      opacity: stripOpacity,
      startValue: 7,
      endValue: 13,
      color:"#2274A5",
      label:"Lager"
    }

    var moldStrip = {
      opacity: stripOpacity,
      startValue: 45,
      endValue: 100,
      color: "#DCEED1",
      label: "Possible Mold"
    }

    loadChart('temperature-chart' ,dataPoints[0], {color: '#FCBA04', axisY: { title: "Temperature ℃", stripLines: [aleStrip, lagerStrip]}});
    loadChart('humidity-chart' ,dataPoints[1], {color: '#A50104', axisY: { title: "Humidity %", stripLines: [moldStrip]}});

  })
};

var loadChart = function(container, dataPoints, options) {
  var data = [
        {
          // Change type to "doughnut", "line", "splineArea", etc.
          type: "spline",
          dataPoints: dataPoints
        }
      ]

  if (options) {
    for (key in options) {
      data[0][key] = options[key];
    }
  }

  var axisY = {};
  if (options.axisY) {
    axisY = options.axisY;
  }

  var chart = new CanvasJS.Chart(container, {
      title:{
        //text: "Basement Conditions"
      },
      axisY: axisY,
      data: data,

    });
    chart.render();
};<commit_msg>Set yAxis min and max<commit_after>// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.
// You can use CoffeeScript in this file: http://coffeescript.org/

window.onload = function () {
  $.getJSON('/readings.json', function(data) {

    dataPoints = [];
    dataPoints[0] = [];
    dataPoints[1] = [];
    for (var i = 0; i < data.length; i++) {
      var date = new Date(data[i].created_at);
      var temperature = parseFloat(data[i].temperature);
      var humidity = parseFloat(data[i].humidity);
      dataPoints[0].push({
        x: date, y: temperature
      });
      dataPoints[1].push({
        x: date, y: humidity
      });
    }

    var stripOpacity = .1;

    var aleStrip = {
      opacity: stripOpacity,
      startValue:20,
      endValue:22,
      color:"#FCBA04",
      label:"Ale"
    };
    var lagerStrip = {
      opacity: stripOpacity,
      startValue: 7,
      endValue: 13,
      color:"#2274A5",
      label:"Lager"
    }
    var tempAxisY = {
      minimum: 5,
      maximum: 25,
      title: "Temperature ℃",
      stripLines: [aleStrip, lagerStrip]
    };

    var moldStrip = {
      opacity: stripOpacity,
      startValue: 45,
      endValue: 100,
      color: "#6FED21",
      label: "Possible Mold"
    }
    var humidAxisY = {
      minimum: 0,
      maximum: 100,
      title: "Humidity %",
      stripLines: [moldStrip]
    };

    loadChart('temperature-chart' ,dataPoints[0], {color: '#FCBA04', axisY: tempAxisY});
    loadChart('humidity-chart' ,dataPoints[1], {color: '#A50104', axisY: humidAxisY});

  })
};

var loadChart = function(container, dataPoints, options) {
  var data = [
        {
          // Change type to "doughnut", "line", "splineArea", etc.
          type: "spline",
          dataPoints: dataPoints
        }
      ]

  if (options) {
    for (key in options) {
      data[0][key] = options[key];
    }
  }

  var axisY = {};
  if (options.axisY) {
    axisY = options.axisY;
  }

  var chart = new CanvasJS.Chart(container, {
      title:{
        //text: "Basement Conditions"
      },
      axisY: axisY,
      data: data,

    });
    chart.render();
};<|endoftext|>


<commit_before>class Service {
  constructor(jsonData){
    this.id = jsonData.id;
    this.service_name = jsonData.service_name;
    this.description = jsonData.description;
    this.start_time = jsonData.start_time;
    this.end_time = jsonData.end_time;
  }
  displayService(){
    const html = [
      `<h2>Order #${this.id}</h2>`,
      '
',
      `<li>Service Name: ${this.service_name}</li>`,
      `<li>Service Description: ${this.description}</li>`,
      `<li>Service Start Time: ${this.start_time}</li>`,
      `<li>Service End Time: ${this.end_time}</li>`,
      '
'
    ].join('')
    return html;
  }
}//end Service

$(document).on('turbolinks:load', function() {
  $('#new_service').submit(function(event){
    event.preventDefault();

    $.ajax({
      url: this.action,
      data: $(this).serialize(),
      dataType: "json",
      type: this.method,

      success: function(response){
        let service = new Service(response);
        $("form").html(service.displayService());
      },

      error: function(errorResponse){
        let error = $.parseJSON(errorResponse.responseText);
        let html = [
          '
',
          '<button type="button" class="close" data-dismiss="alert" aria-label="Close">',
          '×',
          '</button>',
          '
Please fix the following errors:
',
          '
'
        ]

        for (let errorMessage in error) {
          html.push(`<li>${errorMessage}</li>`);
        }
        html.push('
', '
');

        // NOTE: place error message above the form
        $(".container.service.form").before(html.join(''));

      }// end error

    });//end ajax()

  });//end submit()
});//end on('turbolinks:load')
<commit_msg>Add complete option to ajax and re-enable submit button<commit_after>class Service {
  constructor(jsonData){
    this.id = jsonData.id;
    this.service_name = jsonData.service_name;
    this.description = jsonData.description;
    this.start_time = jsonData.start_time;
    this.end_time = jsonData.end_time;
  }
  displayService(){
    const html = [
      `<h2>Order #${this.id}</h2>`,
      '
',
      `<li>Service Name: ${this.service_name}</li>`,
      `<li>Service Description: ${this.description}</li>`,
      `<li>Service Start Time: ${this.start_time}</li>`,
      `<li>Service End Time: ${this.end_time}</li>`,
      '
'
    ].join('')
    return html;
  }
}//end Service

$(document).on('turbolinks:load', function() {
  $('#new_service').submit(function(event){
    event.preventDefault();

    $.ajax({
      url: this.action,
      data: $(this).serialize(),
      dataType: "json",
      type: this.method,

      success: function(response){
        let service = new Service(response);
        $("form").html(service.displayService());
      },

      error: function(errorResponse){
        let error = $.parseJSON(errorResponse.responseText);
        let html = [
          '
',
          '<button type="button" class="close" data-dismiss="alert" aria-label="Close">',
          '×',
          '</button>',
          '
Please fix the following errors:
',
          '
'
        ]

        for (let errorMessage in error) {
          html.push(`<li>${errorMessage}</li>`);
        }
        html.push('
', '
');

        // NOTE: place error message above the form
        $(".container.service.form").before(html.join(''));

      },// end error

      complete: function(){
        // NOTE: enable submit button after preventDefault()
        $('input[type="submit"]').prop('disabled', false);
      }//end complete:

    });//end ajax()

  });//end submit()
});//end on('turbolinks:load')
<|endoftext|>


<commit_before>export function capitalizeFirstLetter (string) {
  return string.charAt(0).toUpperCase() + string.slice(1)
}

export function shortenNumber (number, decimals, abbreviate) {
  decimals = (decimals === undefined) ? 0 : decimals
  abbreviate = (abbreviate === undefined) ? true : abbreviate
  let k = 'K'
  let m = 'M'
  let b = 'B'
  if (!abbreviate) {
    k = 'Thousand'
    m = 'Million'
    b = 'Billion'
  }
  if (number >= 1000000000) {
    return `${Number((number / 1000000000).toFixed(decimals))} ${b}`
  } else if (number >= 1000000) {
    return `${Number((number / 1000000).toFixed(decimals))} ${m}`
  } else if (number >= 1000) {
    return `${Number((number / 1000).toFixed(decimals))} ${k}`
  } else {
    return number
  }
}
<commit_msg>Set function to work with negative numbers as well<commit_after>export function capitalizeFirstLetter (string) {
  return string.charAt(0).toUpperCase() + string.slice(1)
}

export function shortenNumber (number, decimals, abbreviate) {
  decimals = (decimals === undefined) ? 0 : decimals
  abbreviate = (abbreviate === undefined) ? true : abbreviate
  let k = 'K'
  let m = 'M'
  let b = 'B'
  if (!abbreviate) {
    k = 'Thousand'
    m = 'Million'
    b = 'Billion'
  }
  if (Math.abs(number) >= 1000000000) {
    return `${Number((number / 1000000000).toFixed(decimals))} ${b}`
  } else if (Math.abs(number) >= 1000000) {
    return `${Number((number / 1000000).toFixed(decimals))} ${m}`
  } else if (Math.abs(number) >= 1000) {
    return `${Number((number / 1000).toFixed(decimals))} ${k}`
  } else {
    return number
  }
}
<|endoftext|>


<commit_before>import React from 'react';
import { Dimmer, Loader } from 'semantic-ui-react';
import Spacer from '../Spacer';
import AlbumList from '../AlbumList';
import ArtistTags from './ArtistTags';
import SimilarArtists from './SimilarArtists';
import PopularTracks from './PopularTracks';

import styles from './styles.scss';
import artPlaceholder from '../../../resources/media/art_placeholder.png';
import { artistInfoStart } from '../../actions';

class ArtistView extends React.Component {
  constructor(props) {
    super(props);
    this.isLoading = this.isLoading.bind(this);
  }

  isLoading() {
    return (
      this.props.artist.loading ||
      !this.props.artist.lastfm ||
      this.props.artist.lastfm.loading
    );
  }

  render() {
    let {
      artist,
      history,
      albumInfoSearch,
      addToQueue,
      selectSong,
      startPlayback,
      clearQueue,
      artistInfoSearchByName,
      musicSources,
    } = this.props;
    return (

        <Dimmer.Dimmable>
          <Dimmer active={this.isLoading()}>
            <Loader />
          </Dimmer>

          {!this.isLoading() && (

                    <div
                      className={styles.artist_avatar}
                      style={{
                        background: `url('${
                          artist.images[1]
                            ? artist.images[1].resource_url
                            : artPlaceholder
                        }')`,
                        backgroundRepeat: 'noRepeat',
                        backgroundPosition: 'center',
                        backgroundSize: 'cover',
                      }}
                    />

{artist.name}

                      {artist.lastfm.loading && (

                        <ArtistTags
                          tags={artist.lastfm.artist.tags.tag}
                          history={history}
                        />
                      )}

          )}

            {!this.isLoading() && artist.lastfm.loading && (
              <PopularTracks
                tracks={artist.lastfm.toptracks}
                artist={artist}
                addToQueue={addToQueue}
                selectSong={selectSong}
                startPlayback={startPlayback}
                clearQueue={clearQueue}
                musicSources={musicSources}
              />
            )}

            {!this.isLoading() && artist.lastfm.loading && (

              <SimilarArtists
                artists={artist.lastfm.artist.similar.artist}
                artistInfoSearchByName={artistInfoSearchByName}
                history={history}
              />
            )}

          <AlbumList
            albums={artist.releases}
            albumInfoSearch={albumInfoSearch}
            history={history}
          />
        </Dimmer.Dimmable>

    );
  }
}
export default ArtistView;
<commit_msg>Simplification of ArtistView<commit_after>import React from 'react';
import { Dimmer, Loader } from 'semantic-ui-react';
import Spacer from '../Spacer';
import AlbumList from '../AlbumList';
import ArtistTags from './ArtistTags';
import SimilarArtists from './SimilarArtists';
import PopularTracks from './PopularTracks';

import styles from './styles.scss';
import artPlaceholder from '../../../resources/media/art_placeholder.png';
import { artistInfoStart } from '../../actions';

class ArtistView extends React.Component {
  constructor(props) {
    super(props);
    this.isLoading = this.isLoading.bind(this);
  }

  isLoading() {
    return (
      this.props.artist.loading ||
      !this.props.artist.lastfm ||
      this.props.artist.lastfm.loading
    );
  }

  renderArtistHeader(artist, history) {
    return (

{artist.name}

            {artist.lastfm.artist !== undefined && (
              <ArtistTags
                tags={artist.lastfm.artist.tags.tag}
                history={history}
              />
            )}

    );
  }

  renderPopularTrack() {
    let {
      artist,
      addToQueue,
      selectSong,
      startPlayback,
      clearQueue,
      musicSources,
    } = this.props;
    return (
      !this.isLoading() &&
      artist.lastfm.toptracks && (
        <PopularTracks
          tracks={artist.lastfm.toptracks}
          artist={artist}
          addToQueue={addToQueue}
          selectSong={selectSong}
          startPlayback={startPlayback}
          clearQueue={clearQueue}
          musicSources={musicSources}
        />
      )
    );
  }

  renderSimilarArtists() {
    let { artist, history, artistInfoSearchByName } = this.props;

    return (
      !this.isLoading() &&
      artist.lastfm.artist !== undefined && (
        <SimilarArtists
          artists={artist.lastfm.artist.similar.artist}
          artistInfoSearchByName={artistInfoSearchByName}
          history={history}
        />
      )
    );
  }

  renderHeaderBanner() {
    let { artist, history } = this.props;

    return (

        {this.renderArtistHeader(artist, history)}

    );
  }

  render() {
    let { artist, history, albumInfoSearch } = this.props;
    return (

        <Dimmer.Dimmable>
          <Dimmer active={this.isLoading()}>
            <Loader />
          </Dimmer>

          {!this.isLoading() && (

{this.renderHeaderBanner()}

          )}

            {this.renderPopularTrack()}

            {this.renderSimilarArtists()}

          <AlbumList
            albums={artist.releases}
            albumInfoSearch={albumInfoSearch}
            history={history}
          />
        </Dimmer.Dimmable>

    );
  }
}
export default ArtistView;
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import purebem from 'purebem';

import { JoinButton } from 'app/components';

const block = purebem.of('search-result-item');

const SearchResultItem = React.createClass({

    propTypes: {
        item: PropTypes.object.isRequired
    },

    render() {
        const { item } = this.props;

        return (

                { item.title }
                { item.uname }
                { item.dateStart }
                { item.dateEnd }
                <JoinButton data={ item } />

        );
    }

});

export default SearchResultItem;
<commit_msg>prop update<commit_after>import React, { PropTypes } from 'react';
import purebem from 'purebem';

import { JoinButton } from 'app/components';

const block = purebem.of('search-result-item');

const SearchResultItem = React.createClass({

    propTypes: {
        item: PropTypes.object.isRequired
    },

    render() {
        const { item } = this.props;

        return (

                { item.title }
                { item.uname }
                { item.dateStart }
                { item.dateEnd }
                <JoinButton project={ item } />

        );
    }

});

export default SearchResultItem;
<|endoftext|>


<commit_before>import Ember from 'ember';

const { Component, computed, inject, isPresent } = Ember;
const { service } = inject;
const { alias, sort } = computed;

export default Component.extend({
  store: service(),
  i18n: service(),
  flashMessages: service(),
  subject: null,
  classNames: ['detail-taxonomies'],
  tagName: 'section',

  /**
   * The ID of the currently selected vocabulary.
   *
   * @property vocabId
   * @type {int|null}
   * @public
   */
  vocabId: null,

  /**
   * Defines the sort order for currently associated terms.
   *
   * @property
   * @type {Array}
   * @public
   */
  termsSorting: [
    'vocabulary.school.title',
    'vocabulary.title',
    //'titleWithParentTitles.content', // @todo does not work, sorting on 'title instead. Revisit [ST 2016/02/19]
    'title',
  ],

  /**
   * All currently selected terms, in sort order.
   * @property sortedTerms
   * @type {Ember.computed}
   * @public
   */
  sortedTerms: sort('selectedTerms', 'termsSorting'),

  /**
   * The currently selected vocabulary, defaults to the first assignable vocabulary if no user selection was made.
   *
   * @property selectedVocabulary
   * @type {Ember.computed}
   * @public
   */
  selectedVocabulary: computed('subject.assignableVocabularies.[]', 'vocabId', function(){
    let vocabs = this.get('subject.assignableVocabularies');
    if(isPresent(this.get('vocabId'))){
      let vocab = vocabs.find(v => {
        return v.get('id') === this.get('vocabId');
      });
      if(vocab){
        return vocab;
      }
    }
    return vocabs.get('firstObject');
  }),

  actions: {
    add: function (term) {
      this.sendAction('add', term);
    },
    remove: function (term) {
      this.sendAction('remove', term);
    },
    changeSelectedVocabulary(vocabId) {
      this.set('vocabId', vocabId)
    }
  }
});
<commit_msg>rm deconstructed alias from tax mngnr.<commit_after>import Ember from 'ember';

const { Component, computed, inject, isPresent } = Ember;
const { service } = inject;
const { sort } = computed;

export default Component.extend({
  store: service(),
  i18n: service(),
  flashMessages: service(),
  subject: null,
  classNames: ['detail-taxonomies'],
  tagName: 'section',

  /**
   * The ID of the currently selected vocabulary.
   *
   * @property vocabId
   * @type {int|null}
   * @public
   */
  vocabId: null,

  /**
   * Defines the sort order for currently associated terms.
   *
   * @property
   * @type {Array}
   * @public
   */
  termsSorting: [
    'vocabulary.school.title',
    'vocabulary.title',
    //'titleWithParentTitles.content', // @todo does not work, sorting on 'title instead. Revisit [ST 2016/02/19]
    'title',
  ],

  /**
   * All currently selected terms, in sort order.
   * @property sortedTerms
   * @type {Ember.computed}
   * @public
   */
  sortedTerms: sort('selectedTerms', 'termsSorting'),

  /**
   * The currently selected vocabulary, defaults to the first assignable vocabulary if no user selection was made.
   *
   * @property selectedVocabulary
   * @type {Ember.computed}
   * @public
   */
  selectedVocabulary: computed('subject.assignableVocabularies.[]', 'vocabId', function(){
    let vocabs = this.get('subject.assignableVocabularies');
    if(isPresent(this.get('vocabId'))){
      let vocab = vocabs.find(v => {
        return v.get('id') === this.get('vocabId');
      });
      if(vocab){
        return vocab;
      }
    }
    return vocabs.get('firstObject');
  }),

  actions: {
    add: function (term) {
      this.sendAction('add', term);
    },
    remove: function (term) {
      this.sendAction('remove', term);
    },
    changeSelectedVocabulary(vocabId) {
      this.set('vocabId', vocabId)
    }
  }
});
<|endoftext|>


<commit_before>'use strict';

const userMiddleware = require('../middlewares/user');
const errorMiddleware = require('../middlewares/error');
const authorizationMiddleware = require('../middlewares/authorization');
const connectionParamsMiddleware = require('../middlewares/connection-params');
const { initializeProfilerMiddleware } = require('../middlewares/profiler');
const rateLimitsMiddleware = require('../middlewares/rate-limit');
const dbQuotaMiddleware = require('../middlewares/db-quota');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimitsMiddleware;
const errorHandlerFactory = require('../services/error_handler_factory');
const StreamCopy = require('../services/stream_copy');
const StreamCopyMetrics = require('../services/stream_copy_metrics');
const zlib = require('zlib');
const { PassThrough } = require('stream');

function CopyController(metadataBackend, userDatabaseService, userLimitsService, logger) {
    this.metadataBackend = metadataBackend;
    this.userDatabaseService = userDatabaseService;
    this.userLimitsService = userLimitsService;
    this.logger = logger;
}

CopyController.prototype.route = function (app) {
    const { base_url } = global.settings;

    const copyFromMiddlewares = endpointGroup => {
        return [
            initializeProfilerMiddleware('copyfrom'),
            userMiddleware(this.metadataBackend),
            rateLimitsMiddleware(this.userLimitsService, endpointGroup),
            authorizationMiddleware(this.metadataBackend),
            connectionParamsMiddleware(this.userDatabaseService),
            validateCopyQuery(),
            dbQuotaMiddleware(),
            handleCopyFrom(this.logger),
            errorHandler(),
            errorMiddleware()
        ];
    };

    const copyToMiddlewares = endpointGroup => {
        return [
            initializeProfilerMiddleware('copyto'),
            userMiddleware(this.metadataBackend),
            rateLimitsMiddleware(this.userLimitsService, endpointGroup),
            authorizationMiddleware(this.metadataBackend),
            connectionParamsMiddleware(this.userDatabaseService),
            validateCopyQuery(),
            handleCopyTo(this.logger),
            errorHandler(),
            errorMiddleware()
        ];
    };

    app.post(`${base_url}/sql/copyfrom`, copyFromMiddlewares(RATE_LIMIT_ENDPOINTS_GROUPS.COPY_FROM));
    app.get(`${base_url}/sql/copyto`, copyToMiddlewares(RATE_LIMIT_ENDPOINTS_GROUPS.COPY_TO));
};

function handleCopyTo (logger) {
    return function handleCopyToMiddleware (req, res, next) {
        const sql = req.query.q;
        const { userDbParams, user } = res.locals;
        const filename = req.query.filename || 'carto-sql-copyto.dmp';

        const streamCopy = new StreamCopy(sql, userDbParams);
        const metrics = new StreamCopyMetrics(logger, 'copyto', sql, user);

        res.header("Content-Disposition", `attachment; filename=${encodeURIComponent(filename)}`);
        res.header("Content-Type", "application/octet-stream");

        streamCopy.getPGStream(StreamCopy.ACTION_TO, (err, pgstream) => {
            if (err) {
                return next(err);
            }

            pgstream
                .on('data', data => metrics.addSize(data.length))
                .on('error', err => {
                    metrics.end(null, err);
                    pgstream.unpipe(res);

                    return next(err);
                })
                .on('end', () => metrics.end( streamCopy.getRowCount(StreamCopy.ACTION_TO) ))
                .pipe(res)
                .on('close', () => {
                    const err = new Error('Connection closed by client');
                    pgstream.emit('cancelQuery', err);
                    pgstream.emit('error', err);
                })
                .on('error', err => {
                    pgstream.emit('error', err);
                });
        });
    };
}

function handleCopyFrom (logger) {
    return function handleCopyFromMiddleware (req, res, next) {
        const sql = req.query.q;
        const { userDbParams, user, dbRemainingQuota } = res.locals;
        const isGzip = req.get('content-encoding') === 'gzip';
        const copy_from_max_post_size = global.settings.copy_from_max_post_size || 1.99 * 1024 * 1024 * 1024; // 1.99 GB
        const copy_from_max_post_size_pretty = global.settings.copy_from_max_post_size_pretty || '2 GB';

        const streamCopy = new StreamCopy(sql, userDbParams);
        const metrics = new StreamCopyMetrics(logger, 'copyfrom', sql, user, isGzip);

        streamCopy.getPGStream(StreamCopy.ACTION_FROM, (err, pgstream) => {
            if (err) {
                return next(err);
            }

            req
                .on('data', data => isGzip ? metrics.addGzipSize(data.length) : undefined)
                .on('error', err => {
                    metrics.end(null, err);
                    pgstream.emit('error', err);
                })
                .on('close', () => {
                    const err = new Error('Connection closed by client');
                    pgstream.emit('cancelQuery', err);
                    pgstream.emit('error', err);
                })
                .pipe(isGzip ? zlib.createGunzip() : new PassThrough())
                .on('data', data => {
                    metrics.addSize(data.length);

                    if(metrics.size > dbRemainingQuota) {
                        const quotaError = new Error('DB Quota exceeded');
                        metrics.end(null, quotaError);
                        req.unpipe(pgstream);
                        return next(quotaError);
                    }
                    if((metrics.gzipSize || metrics.size) > copy_from_max_post_size) {
                        const maxPostSizeError = new Error(`COPY FROM maximum POST size of ${copy_from_max_post_size_pretty} exceeded`);
                        metrics.end(null, maxPostSizeError);
                        req.unpipe(pgstream);
                        return next(maxPostSizeError);
                    }
                })
                .pipe(pgstream)
                .on('error', err => {
                    metrics.end(null, err);
                    req.unpipe(pgstream);
                    return next(err);
                })
                .on('end', () => {
                    metrics.end( streamCopy.getRowCount(StreamCopy.ACTION_FROM) );

                    const { time, rows } = metrics;

                    if (!rows) {
                        return next(new Error("No rows copied"));
                    }

                    res.send({
                        time,
                        total_rows: rows
                    });
                });
        });
    };
}

function validateCopyQuery () {
    return function validateCopyQueryMiddleware (req, res, next) {
        const sql = req.query.q;

        if (!sql) {
            return next(new Error("SQL is missing"));
        }

        if (!sql.toUpperCase().startsWith("COPY ")) {
            return next(new Error("SQL must start with COPY"));
        }

        next();
    };
}

function errorHandler () {
    return function errorHandlerMiddleware (err, req, res, next) {
        if (res.headersSent) {
            console.error("EXCEPTION REPORT: " + err.stack);
            const errorHandler = errorHandlerFactory(err);
            res.write(JSON.stringify(errorHandler.getResponse()));
            res.end();
        } else {
            return next(err);
        }
    };
}

module.exports = CopyController;
<commit_msg>Please jshint<commit_after>'use strict';

const userMiddleware = require('../middlewares/user');
const errorMiddleware = require('../middlewares/error');
const authorizationMiddleware = require('../middlewares/authorization');
const connectionParamsMiddleware = require('../middlewares/connection-params');
const { initializeProfilerMiddleware } = require('../middlewares/profiler');
const rateLimitsMiddleware = require('../middlewares/rate-limit');
const dbQuotaMiddleware = require('../middlewares/db-quota');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimitsMiddleware;
const errorHandlerFactory = require('../services/error_handler_factory');
const StreamCopy = require('../services/stream_copy');
const StreamCopyMetrics = require('../services/stream_copy_metrics');
const zlib = require('zlib');
const { PassThrough } = require('stream');

function CopyController(metadataBackend, userDatabaseService, userLimitsService, logger) {
    this.metadataBackend = metadataBackend;
    this.userDatabaseService = userDatabaseService;
    this.userLimitsService = userLimitsService;
    this.logger = logger;
}

CopyController.prototype.route = function (app) {
    const { base_url } = global.settings;

    const copyFromMiddlewares = endpointGroup => {
        return [
            initializeProfilerMiddleware('copyfrom'),
            userMiddleware(this.metadataBackend),
            rateLimitsMiddleware(this.userLimitsService, endpointGroup),
            authorizationMiddleware(this.metadataBackend),
            connectionParamsMiddleware(this.userDatabaseService),
            validateCopyQuery(),
            dbQuotaMiddleware(),
            handleCopyFrom(this.logger),
            errorHandler(),
            errorMiddleware()
        ];
    };

    const copyToMiddlewares = endpointGroup => {
        return [
            initializeProfilerMiddleware('copyto'),
            userMiddleware(this.metadataBackend),
            rateLimitsMiddleware(this.userLimitsService, endpointGroup),
            authorizationMiddleware(this.metadataBackend),
            connectionParamsMiddleware(this.userDatabaseService),
            validateCopyQuery(),
            handleCopyTo(this.logger),
            errorHandler(),
            errorMiddleware()
        ];
    };

    app.post(`${base_url}/sql/copyfrom`, copyFromMiddlewares(RATE_LIMIT_ENDPOINTS_GROUPS.COPY_FROM));
    app.get(`${base_url}/sql/copyto`, copyToMiddlewares(RATE_LIMIT_ENDPOINTS_GROUPS.COPY_TO));
};

function handleCopyTo (logger) {
    return function handleCopyToMiddleware (req, res, next) {
        const sql = req.query.q;
        const { userDbParams, user } = res.locals;
        const filename = req.query.filename || 'carto-sql-copyto.dmp';

        const streamCopy = new StreamCopy(sql, userDbParams);
        const metrics = new StreamCopyMetrics(logger, 'copyto', sql, user);

        res.header("Content-Disposition", `attachment; filename=${encodeURIComponent(filename)}`);
        res.header("Content-Type", "application/octet-stream");

        streamCopy.getPGStream(StreamCopy.ACTION_TO, (err, pgstream) => {
            if (err) {
                return next(err);
            }

            pgstream
                .on('data', data => metrics.addSize(data.length))
                .on('error', err => {
                    metrics.end(null, err);
                    pgstream.unpipe(res);

                    return next(err);
                })
                .on('end', () => metrics.end( streamCopy.getRowCount(StreamCopy.ACTION_TO) ))
                .pipe(res)
                .on('close', () => {
                    const err = new Error('Connection closed by client');
                    pgstream.emit('cancelQuery', err);
                    pgstream.emit('error', err);
                })
                .on('error', err => {
                    pgstream.emit('error', err);
                });
        });
    };
}

function handleCopyFrom (logger) {
    return function handleCopyFromMiddleware (req, res, next) {
        const sql = req.query.q;
        const { userDbParams, user, dbRemainingQuota } = res.locals;
        const isGzip = req.get('content-encoding') === 'gzip';
        const copy_from_max_post_size = global.settings.copy_from_max_post_size || 1.99 * 1024 * 1024 * 1024; // 1.99 GB
        const copy_from_max_post_size_pretty = global.settings.copy_from_max_post_size_pretty || '2 GB';

        const streamCopy = new StreamCopy(sql, userDbParams);
        const metrics = new StreamCopyMetrics(logger, 'copyfrom', sql, user, isGzip);

        streamCopy.getPGStream(StreamCopy.ACTION_FROM, (err, pgstream) => {
            if (err) {
                return next(err);
            }

            req
                .on('data', data => isGzip ? metrics.addGzipSize(data.length) : undefined)
                .on('error', err => {
                    metrics.end(null, err);
                    pgstream.emit('error', err);
                })
                .on('close', () => {
                    const err = new Error('Connection closed by client');
                    pgstream.emit('cancelQuery', err);
                    pgstream.emit('error', err);
                })
                .pipe(isGzip ? zlib.createGunzip() : new PassThrough())
                .on('data', data => {
                    metrics.addSize(data.length);

                    if(metrics.size > dbRemainingQuota) {
                        const quotaError = new Error('DB Quota exceeded');
                        metrics.end(null, quotaError);
                        req.unpipe(pgstream);
                        return next(quotaError);
                    }
                    if((metrics.gzipSize || metrics.size) > copy_from_max_post_size) {
                        const maxPostSizeError = new Error(
                            `COPY FROM maximum POST size of ${copy_from_max_post_size_pretty} exceeded`
                        );
                        metrics.end(null, maxPostSizeError);
                        req.unpipe(pgstream);
                        return next(maxPostSizeError);
                    }
                })
                .pipe(pgstream)
                .on('error', err => {
                    metrics.end(null, err);
                    req.unpipe(pgstream);
                    return next(err);
                })
                .on('end', () => {
                    metrics.end( streamCopy.getRowCount(StreamCopy.ACTION_FROM) );

                    const { time, rows } = metrics;

                    if (!rows) {
                        return next(new Error("No rows copied"));
                    }

                    res.send({
                        time,
                        total_rows: rows
                    });
                });
        });
    };
}

function validateCopyQuery () {
    return function validateCopyQueryMiddleware (req, res, next) {
        const sql = req.query.q;

        if (!sql) {
            return next(new Error("SQL is missing"));
        }

        if (!sql.toUpperCase().startsWith("COPY ")) {
            return next(new Error("SQL must start with COPY"));
        }

        next();
    };
}

function errorHandler () {
    return function errorHandlerMiddleware (err, req, res, next) {
        if (res.headersSent) {
            console.error("EXCEPTION REPORT: " + err.stack);
            const errorHandler = errorHandlerFactory(err);
            res.write(JSON.stringify(errorHandler.getResponse()));
            res.end();
        } else {
            return next(err);
        }
    };
}

module.exports = CopyController;
<|endoftext|>


<commit_before>module.exports = {

	process : function(ctx, step, next) {
		var name = step.name;
		if(typeof styles != 'undefined') {
			for(var style in styles) {
				var value = styles[style];
				setCSSStyle(ctx, style, value);
			}
		}
		else {
			setCSSStyle(ctx, style, value);
		}
		setTimeout(next, 1);
	}
}

var setCSSStyle = function(ctx, style, value) {
	ctx.wv.ios.stringByEvaluatingJavaScriptFromString('document.getElementById("' + name + '").style.' + style + ' = "' + value + '"');
}<commit_msg>#65 bug with name<commit_after>module.exports = {

	process : function(ctx, step, next) {
		var name = step.name;
		if(typeof styles != 'undefined') {
			for(var style in styles) {
				var value = styles[style];
				setCSSStyle(ctx, name, style, value);
			}
		}
		else {
			setCSSStyle(ctx, name, style, value);
		}
		setTimeout(next, 1);
	}
}

var setCSSStyle = function(ctx, name, style, value) {
	ctx.wv.ios.stringByEvaluatingJavaScriptFromString('document.getElementById("' + name + '").style.' + style + ' = "' + value + '"');
}<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
	Schema = mongoose.Schema;

/**
 * Article Schema
 */
var ArticleSchema = new Schema({
	created: {
		type: Date,
		default: Date.now
	},
	title: {
		type: String,
		default: '',
		trim: true,
		required: 'Title cannot be blank'
	},
	content: {
		type: String,
		default: '',
		trim: true
	},
    topic: {
        type: String
    },
    rate:{
        type:Number,
        default: 0.0
    },
    vote:{
        type:Number,
        default:0
    },
    max:{
        type:Number,
        default:5
    },
    isReadonly:{
        type:Boolean,
        default:false
    },
    userName:{
        type : String,
        default:''
    },
	user: {
		type: Schema.ObjectId,
		ref: 'User'
	},
	blog:{
		type: Schema.ObjectId,
		ref:'Blog'
	}
});

mongoose.model('Article', ArticleSchema);
<commit_msg>12/07   - 21:00<commit_after>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
	Schema = mongoose.Schema;

/**
 * Article Schema
 */
var ArticleSchema = new Schema({
	created: {
		type: Date,
		default: Date.now
	},
	title: {
		type: String,
		default: '',
		trim: true,
		required: 'Title cannot be blank'
	},
    subtitle:{
        type: String
    },
    enlace:{
        type:String
    },
	content: {
		type: String,
		default: '',
		trim: true
	},
    topic: {
        type: String
    },
    rate:{
        type:Number,
        default: 0.0
    },
    vote:{
        type:Number,
        default:0
    },
    max:{
        type:Number,
        default:5
    },
    isReadonly:{
        type:Boolean,
        default:false
    },
    userName:{
        type : String,
        default:''
    },
	user: {
		type: Schema.ObjectId,
		ref: 'User'
	},
	blog:{
		type: Schema.ObjectId,
		ref:'Blog'
	}
});

mongoose.model('Article', ArticleSchema);
<|endoftext|>


<commit_before>import * as Constants from '../constants/add_users_constants';

const initialState = {
  user1: "",
  user2: ""
}

const screenNames = ( state = initialState, action ) => {
  switch ( action.type ) {
    case Constants.ADD_SCREEN_NAMES:
      return Object.assign( {}, state, {
        user1ScreenName: action.user1ScreenName,
        user2ScreenName: action.user2ScreenName
      });
    default:
      return state
  };
};

export default screenNames;
<commit_msg>add and remove debugger from user reducers<commit_after>import * as Constants from '../constants/add_users_constants';

const initialState = {
  user1: "",
  user2: ""
}

const screenNames = ( state = initialState, action ) => {
  switch ( action.type ) {
    case Constants.ADD_SCREEN_NAMES:
      return Object.assign( {}, state, {
        user1: action.user1ScreenName,
        user2: action.user2ScreenName
      });
    default:
      return state
  };
};

export default screenNames;
<|endoftext|>


<commit_before>(function () {
    'use strict';

    angular
      .module('password.reset')
      .controller('AlternatesController', AlternatesController);

    function AlternatesController(dataService, $routeParams, config,
                                  dialogService) {
        var vm = this;

        vm.allMethods = [];
        vm.phones = [];
        vm.emails = [];
        vm.super = [];
        vm.spouse = [];
        vm.primary = [];

        vm.getHelp = getHelp;

        activate();

        //////////////////////////////////////////////////////////////////

        function activate() {
            dataService
              .get('reset/' + $routeParams.resetId)
              .then(retrievedMethods, failedToRetrieveMethods)
              .finally(dialogService.close);

            dialogService.progress();
        }

        function retrievedMethods(response) {
            vm.allMethods = response.data.methods;

            vm.allMethods.forEach(function (method) {
                switch (method.type) {
                    case 'primary'   : vm.primary.push(method); break;
                    case 'phone'     : vm.phones.push(method) ; break;
                    case 'spouse'    : vm.spouse.push(method) ; break;
                    case 'supervisor': vm.super.push(method)  ; break;
                    default          : vm.emails.push(method) ;
                }
            });
            console.log('gottem2.0');
            dialogService.close();
        }

        function failedToRetrieveMethods(response) {
            dialogService
              .fail('Unable to retrieve alternate methods.',
                    response.data);
        }

        function getHelp() {
            dialogService.help(config.support);
        }
    }
})();
<commit_msg>add more print statements<commit_after>(function () {
    'use strict';

    angular
      .module('password.reset')
      .controller('AlternatesController', AlternatesController);

    function AlternatesController(dataService, $routeParams, config,
                                  dialogService) {
        var vm = this;

        vm.allMethods = [];
        vm.phones = [];
        vm.emails = [];
        vm.super = [];
        vm.spouse = [];
        vm.primary = [];

        vm.getHelp = getHelp;

        activate();

        //////////////////////////////////////////////////////////////////

        function activate() {
            console.log('dinosaurs');
            dataService
              .get('reset/' + $routeParams.resetId)
              .then(retrievedMethods, failedToRetrieveMethods)
              .finally(dialogService.close);

            dialogService.progress();
        }

        function retrievedMethods(response) {
            console.log('maybe');
            vm.allMethods = response.data.methods;
            console.log('hawaii');
            vm.allMethods.forEach(function (method) {
                switch (method.type) {
                    case 'primary'   : vm.primary.push(method); break;
                    case 'phone'     : vm.phones.push(method) ; break;
                    case 'spouse'    : vm.spouse.push(method) ; break;
                    case 'supervisor': vm.super.push(method)  ; break;
                    default          : vm.emails.push(method) ;
                }
            });
            console.log('gottem2.0');
            dialogService.close();
        }

        function failedToRetrieveMethods(response) {
            dialogService
              .fail('Unable to retrieve alternate methods.',
                    response.data);
        }

        function getHelp() {
            dialogService.help(config.support);
        }
    }
})();
<|endoftext|>