<commit_before>var constraints = {
  "user[username]": {
    presence: true,
    length: {
      minimum: 4,
      maximum: 20
    }
  },
  "user[email]": {
    presence: true,
    email: true
  },
  "user[password]": {
    presence: true,
    length: {
      minimum: 6,
      maximum: 128
    }
  },
  "user[password_confirmation]": {
    presence: true,
    equality: {
      attribute: "user[password]",
      message: "^The passwords do not match"
    }
  },
  "user[current_password]": {
    presence: true,
    length: {
      minimum: 6,
      maximum: 128
    }
  },
  "user[learning_goal]": {
    length: {
      minimum: 4,
      maximum: 100
    }
  },
};

document.addEventListener('turbolinks:load', function() {
  var forms = document.querySelectorAll('.form');
  if (!forms) return;

  forms.forEach(function(form) {
    var inputs = form.querySelectorAll('.form__element');

    inputs.forEach(function(item) {
      item.addEventListener("change", function(ev) {
        var errors = validate(form, constraints, { fullMessages: false }) || {};
        showErrorsForInput(this, errors[this.name]);
      });
    });
  });
});

function showErrorsForInput(input, errors) {
  var inputParent = input.parentNode;
  var errorWrapper = findErrorWrapper(input) || createErrorWrapper(input, inputParent);
  var errorDiv = findErrorDiv(input) || createErrorDiv(input, inputParent);

  if (!errors) {
    errorWrapper.parentNode.insertBefore(input, errorWrapper);
    errorWrapper.parentNode.removeChild(errorWrapper);
    errorDiv.parentNode.removeChild(errorDiv);
    return;
  }

  errorWrapper.classList.add('field_with_errors');
  errorDiv.innerHTML = errors;
}

function findErrorWrapper(input) {
  if (input.parentNode.classList.contains('field_with_errors')) {
    return input.parentNode;
  } else {
    return null;
  }
}

function createErrorWrapper(input, inputParent) {
  var newDiv = document.createElement('div');
  inputParent.appendChild(newDiv);
  newDiv.appendChild(input);
  return newDiv;
}

function findErrorDiv(input) {
  return document.querySelector("." + input.id);
}

function createErrorDiv(input, inputParent) {
  var divName = document.createElement('div');
  divName.classList.add('form__error-message', 'push-down', input.id);
  inputParent.parentNode.insertBefore(divName, inputParent.nextSibling);
  return divName;
}
<commit_msg>stop form submit when input invalid<commit_after>var constraints = {
  "user[username]": {
    length: {
      minimum: 4,
      maximum: 20
    }
  },
  "user[email]": {
    email: true
  },
  "user[password]": {
    length: {
      minimum: 6,
      maximum: 128
    }
  },
  "user[password_confirmation]": {
    equality: {
      attribute: "user[password]",
      message: "^The passwords do not match"
    }
  },
  "user[current_password]": {
    length: {
      minimum: 6,
      maximum: 128
    }
  },
  "user[learning_goal]": {
    length: {
      minimum: 4,
      maximum: 100
    }
  },
};

document.addEventListener('turbolinks:load', function() {
  var forms = document.querySelectorAll('.form');
  if (!forms) return;

  forms.forEach(function(form) {

    form.addEventListener("submit", function(ev) {
      ev.preventDefault();
      handleFormSubmit(form);
      ev.stopPropagation();
    })

    var inputs = form.querySelectorAll('.form__element');

    inputs.forEach(function(item) {
      item.addEventListener("change", function(ev) {
        var errors = validate(form, constraints, { fullMessages: false }) || {};
        showErrorsForInput(this, errors[this.name]);
      });
    });
  });
});

function handleFormSubmit(form) {
  var formErrors = validate(form, constraints, { fullMessages: false });
  if (!formErrors) {
    form.submit();
  }
  showErrors(form, formErrors || {});
}

function showErrors(form, errors) {
  var formInputs = form.querySelectorAll('.form__element');
  formInputs.forEach(function(item) {
    showErrorsForInput(item, errors[item.name]);
  });
}

function showErrorsForInput(input, errors) {
  var inputParent = input.parentNode;
  var errorWrapper = findErrorWrapper(input) || createErrorWrapper(input, inputParent);
  var errorDiv = findErrorDiv(input) || createErrorDiv(input, inputParent);

  if (!errors) {
    errorWrapper.parentNode.insertBefore(input, errorWrapper);
    errorWrapper.parentNode.removeChild(errorWrapper);
    errorDiv.parentNode.removeChild(errorDiv);
    return;
  }

  errorWrapper.classList.add('field_with_errors');
  errorDiv.innerHTML = errors;
}

function findErrorWrapper(input) {
  if (input.parentNode.classList.contains('field_with_errors')) {
    return input.parentNode;
  } else {
    return null;
  }
}

function createErrorWrapper(input, inputParent) {
  var newDiv = document.createElement('div');
  inputParent.appendChild(newDiv);
  newDiv.appendChild(input);
  return newDiv;
}

function findErrorDiv(input) {
  return document.querySelector("." + input.id);
}

function createErrorDiv(input, inputParent) {
  var divName = document.createElement('div');
  divName.classList.add('form__error-message', 'push-down', input.id);
  inputParent.parentNode.insertBefore(divName, inputParent.nextSibling);
  return divName;
}
<|endoftext|>


<commit_before>function PingLayer() {
  // In seconds
  this.defaultDuration = 7;
  // radius
  this.defaultSize = 35;
  this.defaultPulseCount = 5;

  this.pings = [];
}
_.extend(PingLayer.prototype, {
  add: function(point, color) {
    this.pings.push(new Ping(point, color, this.defaultSize, this.defaultPulseCount, this.defaultDuration));
  },

  draw: function(drawing) {
    var livingPings = [];

    _.each(this.pings, function(ping) {
      ping.draw(drawing);
      if (!ping.finished) {
        livingPings.push(ping);
      }
    }, this);

    this.pings = livingPings;
  }
});

function Ping(point, color, maxSize, pulseCount, duration) {
  this.animationDuration = duration;
  this.pulseCount = pulseCount;
  this.maxSize = maxSize;
  this.color = color;
  this.point = point;
  this.startTime = null;
  this.finished = false;
}
_.extend(Ping.prototype, {
  draw: function(drawing) {
    var animationPoint = this.calculateEasing();

    var inverse = 1 - animationPoint;

    //drawing.drawCircle(this.point[0], this.point[1], this.maxSize * inverse, 3, this.color);
    drawing.drawCircle(this.point[0], this.point[1], this.maxSize * animationPoint, 3, this.color);
  },

  calculateEasing: function() {
    if (this.startTime == null) {
      this.startTime = new Date();
    }
    var durationPercent = (new Date() - this.startTime) / (this.animationDuration * 1000);
    if (durationPercent >= 1) {
      this.finished = true;
    }
    return this.easingFunction(durationPercent);
  },

  // Returns a value between 0 and 1 that represents the current position in the easing,
  // given a p between 0 and 1 representing the percent of duration expired
  easingFunction: function(p) {
    if (p >= 1) return 1;
    if (p <= 0) return 0;

    var pulseRange = 1.0 / (this.pulseCount * 2);
    var isDown = Math.floor(p / pulseRange) % 2;
    var pos = (p % pulseRange) / pulseRange;
    if (isDown == 1) pos = 1 - pos;
    return pos;
  }
});<commit_msg>Fixes ping easing function<commit_after>function PingLayer() {
  // In seconds
  this.defaultDuration = 7;
  // radius
  this.defaultSize = 50;
  this.defaultPulseCount = 5;

  this.pings = [];
}
_.extend(PingLayer.prototype, {
  add: function(point, color) {
    this.pings.push(new Ping(point, color, this.defaultSize, this.defaultPulseCount, this.defaultDuration));
  },

  draw: function(drawing) {
    var livingPings = [];

    _.each(this.pings, function(ping) {
      ping.draw(drawing);
      if (!ping.finished) {
        livingPings.push(ping);
      }
    }, this);

    this.pings = livingPings;
  }
});

function Ping(point, color, maxSize, pulseCount, duration) {
  this.animationDuration = duration;
  this.pulseCount = pulseCount;
  this.maxSize = maxSize;
  this.color = color;
  this.point = point;
  this.startTime = null;
  this.finished = false;
}
_.extend(Ping.prototype, {
  draw: function(drawing) {
    var animationPoint = this.calculateEasing();

    //drawing.drawCircle(this.point[0], this.point[1], this.maxSize * (1 - animationPoint), 3, this.color);
    drawing.drawCircle(this.point[0], this.point[1], (this.maxSize *0.25) * animationPoint, 3, this.color);
    drawing.drawCircle(this.point[0], this.point[1], this.maxSize * animationPoint, 3, this.color);
  },

  calculateEasing: function() {
    if (this.startTime == null) {
      this.startTime = new Date();
    }
    var durationPercent = (new Date() - this.startTime) / (this.animationDuration * 1000);
    if (durationPercent >= 1) {
      this.finished = true;
    }
    return this.easingFunction(durationPercent);
  },

  // Returns a value between 0 and 1 that represents the current position in the easing,
  // given a p between 0 and 1 representing the percent of duration expired
  easingFunction: function(p) {
    // The function
    //   f(x) = 0.5 - 0.5cos(x)
    // is a wave with max(y)=1, min(y)=0 and f(0)=0
    // It completes an oscillation in 2pi

    var maxX = this.pulseCount * (2 * Math.PI);
    var x = maxX * p;

    return 0.5 - (0.5 * Math.cos(x));
  }
});<|endoftext|>


<commit_before>// ------------------------------------ UI tools -----------------------------------------
var Ui = {
  // return true if the dialog of grid with "name" is open, unless return false
  isOpen: function() {
    return ($(".ui-dialog:visible").size() > 0);
  },

  // check if the grid is being edited
  isEditing: function() {
    var editing = false;
    $.each(gridManager.grids, function(){
      if(this.isEditing()) editing = true;
    });
    return editing;
  },

  // Resize grid
  resizeGrid: function(grid) {
    grid.resizeCanvas();
    grid.autosizeColumns();
    grid.filterPanel.generateFilters();
    $(window).resize(function() {
      grid.resizeCanvas();
      grid.autosizeColumns();
      grid.filterPanel.generateFilters();
    });
  },

  // Check if filter panel is open
  filterPanelOpen: function() {
    return ($('.slick-headerrow-columns:visible').size() > 0 && $( document.activeElement ).parent().attr('class') === 'slick-headerrow-columns');
  },

  // Check if can add or delete records
  addOrDeleteLocked: function() {
    return this.isEditing() || this.isOpen() || this.filterPanelOpen();
  },

  // Select grid names
  selectGridNames: function() {
    var gridContainers = $(".grid_container"), gridName;
    return $.map( gridContainers, function(container){
      gridName = $.trim($(container).attr("id").split("grid_")[1]);
      if (gridName) {
        return gridName;
      }
    });
  },

  // Refresh create form when continue create new record
  refreshCreateForm: function(grid) {
    var name = grid.name;
    $.get(grid.path + '/wulin_master_new_form' + grid.query, function(data){
      newFormDom = $(data);
      $('#' + name + '_form:visible form').replaceWith(newFormDom.find('form'));
      setTimeout(function(){ Ui.setupForm(grid, false); }, 350);
      Ui.setupComponents(grid);
    });
  },

  // Reset form
  resetForm: function(name) {
    $(':input','#new_' + name).not(':button, :submit, :reset, :hidden').not('[readonly]').val('').removeAttr('checked').removeAttr('selected');
    // For chosen
    $('ul.chzn-choices li.search-choice').remove();
  },

  // Create and open dialog
  openDialog: function(grid, action, options, callback) {
    var scope, width, height, name;
    name = grid.name;

    $.get(grid.path + '/' + action + grid.query, function(data){
      $( '#' + name + '_form').remove();

      $('body').append(data);

      scope = $( '#' + name + '_form');

      if (options) {
        width = options.form_dialog_width || 600;
        height = options.form_dialog_height || (scope.outerHeight() + 40);
      } else {
        width = 600;
        height = (scope.outerHeight() + 40);
      }
      scope.dialog({
        height: height,
        width: width,
        show: "blind",
        modal: true,
        create: function(event, ui) {
          Ui.setupForm(grid, false);
          if ($.isFunction(callback))
            callback();
        },
        close: function(event, ui) {
          scope.dialog('destroy');
          scope.remove();
        }
      });
    });
  },

  setupComponents: function(grid) {
    var name = grid.name;
    // setup select as chosen
    $('#' + name + '_form select[data-required="true"]').chosen();
    $('#' + name + '_form select[data-required="false"]').chosen({allow_single_deselect: true});

    $('#' + name + '_form select').off('change').on('change', function(){
      var flag = $('#' + name + '_form input.target_flag:checkbox[data-target="' + $(this).attr('data-target') + '"]');
      if (flag.size() > 0) flag.attr('checked', 'checked');
    });

    // setup datepicker
    $('#' + name + '_form input[data-date]').datepicker({ dateFormat: 'yy-mm-dd' });
    $('#' + name + '_form input[data-datetime]').datetimepicker({
      onlyTime: false,
      dateFormat: "yy-mm-dd",
      timeFormat: 'hh:mm',
      timeOnly: false,
      stepMinute: 1,
      minuteGrid: 0,
      beforeShow: function() { calendarOpen = true },
      onClose: function() { calendarOpen = false }
    });
    $('#' + name + '_form input[data-time]').timepicker({});
  },

  setupForm: function(grid, monitor) {
    var remotePath = [];
    var choicesColumn = [];
    var distinctColumn = [];
    var path;
    var name = grid.name;
    var scope = $('#' + name + '_form');
    var formType = scope.data('action');
    var columns = window[name + "_columns"] || grid.getColumns();
    var currentData = {};

    if (grid.loader)
      currentData = grid.loader.data[grid.getSelectedRows()[0]];

    // special handling for 'choices' and 'choices_column' options
    $.each(columns, function(i, n) {
      if (n['choices'] && typeof(n['choices']) == 'string') {
        if (n['distinct'] && formType != 'create') {
          distinctColumn.push([n.field, n['choices']]);
        } else {
          remotePath.push([n.field, n['choices']]);
        }
      } else if (n['choices_column']) {
        choicesColumn.push([n.field, currentData[n['choices_column']]]);
      }
    });

    // Fetch select options from remote
    if (remotePath.length > 0) {
      $.each(remotePath, function(i, n) {
        var field = n[0];
        var path = n[1];
        if (!path) return;

        var first_input;
        var target = $("select[data-column='" + field + "']", scope);
        var textAttr = target.attr('data-text-attr');
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();

          $.getJSON(path, function(itemdata){
            $.each(itemdata, function(index, value) {
              if ($.isPlainObject(value)) {
                target.append("<option value='" + value.id + "'>" + value[textAttr] + "</option>");
              } else {
                target.append("<option value='" + value + "'>" + value + "</option>");
              }
            });
            Ui.setupChosen(target, monitor);
          });

        }
      });
    }

    // Fetch distinct select options from remote
    if (distinctColumn.length > 0) {
      $.each(distinctColumn, function(i, n) {
        var field = n[0];
        var path = n[1];
        if (!path) return;

        var first_input;
        var target = $("select[data-column='" + field + "']", scope);
        var textAttr = target.attr('data-text-attr');
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();

          $.getJSON(path, function(itemdata){
            $.each(itemdata, function(index, value) {
              if ($.isPlainObject(value)) {
                target.append("<option value='" + value.id + "'>" + value[textAttr] + "</option>");
              } else {
                target.append("<option value='" + value + "'>" + value + "</option>");
              }
            });
            target.append("<option>Add new Option</option>");
          });

        }
      });
    }

    // Fetch select options from current data
    if (choicesColumn.length > 0) {
        $.each(choicesColumn, function(i, n) {
        var field = n[0];
        var first_input;
        var target = $("select[data-column='" + field + "']", scope);
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();
            $.each(n[1], function(index, value) {
              target.append("<option value='" + value + "'>" + value + "</option>");
            });
            Ui.setupChosen(target, monitor);
        }
      });
    }

    first_input = $( '#' + name + '_form input:text', scope).first();
    if (first_input.attr('data-date')) {
      first_input.focus();
    }
  },

  setupChosen: function(dom, monitor) {
    setTimeout(function(){
      var afterSetupChosen = dom.data('afterSetupChosen');
      if (dom.hasClass("chzn-done")) {
        dom.trigger("liszt:updated");
      } else {
        dom.chosen();
      }

      if( afterSetupChosen ) {
        afterSetupChosen();
      }
    }, 100);
  },

  // Close dialog
  closeDialog: function(name) {
    var $form = $( '#' + name + '_form' );

    window._focused = {};

    $form.dialog("destroy");
    $form.remove();
  },

  // Flash the notification
  flashNotice: function(ids, action) {
    var recordSize = $.isArray(ids) ? ids.length : ids.split(',').length,
    recordUnit = recordSize > 1 ? 'records' : 'record',
    actionDesc = action === 'delete' ? 'has been deleted!' : 'has been created!';

    if (recordSize > 0) {
      $('.notice_flash').remove();
      $('#indicators').before('
' + recordSize + ' ' + recordUnit + ' ' + actionDesc + '
');
      $('.notice_flash').fadeOut(7000);
    }
  },

  // Find the selected grid
  findCurrentGrid: function() {
    var currentGrid = null;
    currentGridContainer = $( document.activeElement ).parents('.grid_container');
    if (currentGridContainer.size() == 0) {
      return null;
    }
    gridName = currentGridContainer.attr('id').split('grid_')[1];

    if (gridManager.grids.length == 1) {
      currentGrid = gridManager.grids[0]
    } else {
      if (currentGridContainer.size() == 1) {
        currentGrid = gridManager.getGrid(gridName);
      } else {
        $.each(gridManager.grids, function(){
          if(this.getSelectedRows().length > 0) currentGrid = this;
        });
      }
    }
    return currentGrid;
  },

  formatData: function(grid, arrayData) {
    var data = {}, columns;
    columns = grid.loader.getColumns();
    $.each(columns, function(index, column){
      data[column['id']] = arrayData[index];
    })
    return data;
  }

};
<commit_msg>BUG - fix the bug: if no line selected, the pop up of create form will stucked by a js bug<commit_after>// ------------------------------------ UI tools -----------------------------------------
var Ui = {
  // return true if the dialog of grid with "name" is open, unless return false
  isOpen: function() {
    return ($(".ui-dialog:visible").size() > 0);
  },

  // check if the grid is being edited
  isEditing: function() {
    var editing = false;
    $.each(gridManager.grids, function(){
      if(this.isEditing()) editing = true;
    });
    return editing;
  },

  // Resize grid
  resizeGrid: function(grid) {
    grid.resizeCanvas();
    grid.autosizeColumns();
    grid.filterPanel.generateFilters();
    $(window).resize(function() {
      grid.resizeCanvas();
      grid.autosizeColumns();
      grid.filterPanel.generateFilters();
    });
  },

  // Check if filter panel is open
  filterPanelOpen: function() {
    return ($('.slick-headerrow-columns:visible').size() > 0 && $( document.activeElement ).parent().attr('class') === 'slick-headerrow-columns');
  },

  // Check if can add or delete records
  addOrDeleteLocked: function() {
    return this.isEditing() || this.isOpen() || this.filterPanelOpen();
  },

  // Select grid names
  selectGridNames: function() {
    var gridContainers = $(".grid_container"), gridName;
    return $.map( gridContainers, function(container){
      gridName = $.trim($(container).attr("id").split("grid_")[1]);
      if (gridName) {
        return gridName;
      }
    });
  },

  // Refresh create form when continue create new record
  refreshCreateForm: function(grid) {
    var name = grid.name;
    $.get(grid.path + '/wulin_master_new_form' + grid.query, function(data){
      newFormDom = $(data);
      $('#' + name + '_form:visible form').replaceWith(newFormDom.find('form'));
      setTimeout(function(){ Ui.setupForm(grid, false); }, 350);
      Ui.setupComponents(grid);
    });
  },

  // Reset form
  resetForm: function(name) {
    $(':input','#new_' + name).not(':button, :submit, :reset, :hidden').not('[readonly]').val('').removeAttr('checked').removeAttr('selected');
    // For chosen
    $('ul.chzn-choices li.search-choice').remove();
  },

  // Create and open dialog
  openDialog: function(grid, action, options, callback) {
    var scope, width, height, name;
    name = grid.name;

    $.get(grid.path + '/' + action + grid.query, function(data){
      $( '#' + name + '_form').remove();

      $('body').append(data);

      scope = $( '#' + name + '_form');

      if (options) {
        width = options.form_dialog_width || 600;
        height = options.form_dialog_height || (scope.outerHeight() + 40);
      } else {
        width = 600;
        height = (scope.outerHeight() + 40);
      }
      scope.dialog({
        height: height,
        width: width,
        show: "blind",
        modal: true,
        create: function(event, ui) {
          Ui.setupForm(grid, false);
          if ($.isFunction(callback))
            callback();
        },
        close: function(event, ui) {
          scope.dialog('destroy');
          scope.remove();
        }
      });
    });
  },

  setupComponents: function(grid) {
    var name = grid.name;
    // setup select as chosen
    $('#' + name + '_form select[data-required="true"]').chosen();
    $('#' + name + '_form select[data-required="false"]').chosen({allow_single_deselect: true});

    $('#' + name + '_form select').off('change').on('change', function(){
      var flag = $('#' + name + '_form input.target_flag:checkbox[data-target="' + $(this).attr('data-target') + '"]');
      if (flag.size() > 0) flag.attr('checked', 'checked');
    });

    // setup datepicker
    $('#' + name + '_form input[data-date]').datepicker({ dateFormat: 'yy-mm-dd' });
    $('#' + name + '_form input[data-datetime]').datetimepicker({
      onlyTime: false,
      dateFormat: "yy-mm-dd",
      timeFormat: 'hh:mm',
      timeOnly: false,
      stepMinute: 1,
      minuteGrid: 0,
      beforeShow: function() { calendarOpen = true },
      onClose: function() { calendarOpen = false }
    });
    $('#' + name + '_form input[data-time]').timepicker({});
  },

  setupForm: function(grid, monitor) {
    var remotePath = [];
    var choicesColumn = [];
    var distinctColumn = [];
    var path;
    var name = grid.name;
    var scope = $('#' + name + '_form');
    var formType = scope.data('action');
    var columns = window[name + "_columns"] || grid.getColumns();
    var currentData = {};

    if (grid.loader)
      currentData = grid.loader.data[grid.getSelectedRows()[0]];

    // special handling for 'choices' and 'choices_column' options
    $.each(columns, function(i, n) {
      if (n['choices'] && typeof(n['choices']) == 'string') {
        if (n['distinct'] && formType != 'create') {
          distinctColumn.push([n.field, n['choices']]);
        } else {
          remotePath.push([n.field, n['choices']]);
        }
      } else if (currentData && n['choices_column']) {
        choicesColumn.push([n.field, currentData[n['choices_column']]]);
      }
    });

    // Fetch select options from remote
    if (remotePath.length > 0) {
      $.each(remotePath, function(i, n) {
        var field = n[0];
        var path = n[1];
        if (!path) return;

        var first_input;
        var target = $("select[data-column='" + field + "']", scope);
        var textAttr = target.attr('data-text-attr');
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();

          $.getJSON(path, function(itemdata){
            $.each(itemdata, function(index, value) {
              if ($.isPlainObject(value)) {
                target.append("<option value='" + value.id + "'>" + value[textAttr] + "</option>");
              } else {
                target.append("<option value='" + value + "'>" + value + "</option>");
              }
            });
            Ui.setupChosen(target, monitor);
          });

        }
      });
    }

    // Fetch distinct select options from remote
    if (distinctColumn.length > 0) {
      $.each(distinctColumn, function(i, n) {
        var field = n[0];
        var path = n[1];
        if (!path) return;

        var first_input;
        var target = $("select[data-column='" + field + "']", scope);
        var textAttr = target.attr('data-text-attr');
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();

          $.getJSON(path, function(itemdata){
            $.each(itemdata, function(index, value) {
              if ($.isPlainObject(value)) {
                target.append("<option value='" + value.id + "'>" + value[textAttr] + "</option>");
              } else {
                target.append("<option value='" + value + "'>" + value + "</option>");
              }
            });
            target.append("<option>Add new Option</option>");
          });

        }
      });
    }

    // Fetch select options from current data
    if (choicesColumn.length > 0) {
        $.each(choicesColumn, function(i, n) {
        var field = n[0];
        var first_input;
        var target = $("select[data-column='" + field + "']", scope);
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();
            $.each(n[1], function(index, value) {
              target.append("<option value='" + value + "'>" + value + "</option>");
            });
            Ui.setupChosen(target, monitor);
        }
      });
    }

    first_input = $( '#' + name + '_form input:text', scope).first();
    if (first_input.attr('data-date')) {
      first_input.focus();
    }
  },

  setupChosen: function(dom, monitor) {
    setTimeout(function(){
      var afterSetupChosen = dom.data('afterSetupChosen');
      if (dom.hasClass("chzn-done")) {
        dom.trigger("liszt:updated");
      } else {
        dom.chosen();
      }

      if( afterSetupChosen ) {
        afterSetupChosen();
      }
    }, 100);
  },

  // Close dialog
  closeDialog: function(name) {
    var $form = $( '#' + name + '_form' );

    window._focused = {};

    $form.dialog("destroy");
    $form.remove();
  },

  // Flash the notification
  flashNotice: function(ids, action) {
    var recordSize = $.isArray(ids) ? ids.length : ids.split(',').length,
    recordUnit = recordSize > 1 ? 'records' : 'record',
    actionDesc = action === 'delete' ? 'has been deleted!' : 'has been created!';

    if (recordSize > 0) {
      $('.notice_flash').remove();
      $('#indicators').before('
' + recordSize + ' ' + recordUnit + ' ' + actionDesc + '
');
      $('.notice_flash').fadeOut(7000);
    }
  },

  // Find the selected grid
  findCurrentGrid: function() {
    var currentGrid = null;
    currentGridContainer = $( document.activeElement ).parents('.grid_container');
    if (currentGridContainer.size() == 0) {
      return null;
    }
    gridName = currentGridContainer.attr('id').split('grid_')[1];

    if (gridManager.grids.length == 1) {
      currentGrid = gridManager.grids[0]
    } else {
      if (currentGridContainer.size() == 1) {
        currentGrid = gridManager.getGrid(gridName);
      } else {
        $.each(gridManager.grids, function(){
          if(this.getSelectedRows().length > 0) currentGrid = this;
        });
      }
    }
    return currentGrid;
  },

  formatData: function(grid, arrayData) {
    var data = {}, columns;
    columns = grid.loader.getColumns();
    $.each(columns, function(index, column){
      data[column['id']] = arrayData[index];
    })
    return data;
  }

};
<|endoftext|>


<commit_before>/* global dialogFieldRefresh miqCheckForChanges miqCheckMaxLength miqJqueryRequest miqMenuChangeRow miqObserveRequest miqSendDateRequest miqSendOneTrans miqSerializeForm miqSparkle miqSparkleOn */

// MIQ unobtrusive javascript bindings run when document is fully loaded

$(document).ready(function () {
  // Bind call to prompt if leaving an active edit
  $(document).on('ajax:beforeSend', 'a[data-miq_check_for_changes]', function () {
    return miqCheckForChanges();
  });

  $(document).on('click', 'button[data-click_url]', function () {
    var el = $(this);
    var parms = $.parseJSON(el.attr('data-click_url'));
    var url = parms.url;
    var options = {};
    if (el.attr('data-miq_sparkle_on')) {
      options.beforeSend = true;
    }
    if (el.attr('data-miq_sparkle_off')) {
      options.complete = true;
    }
    var submit = el.attr('data-submit');
    if (typeof submit != "undefined")
      miqJqueryRequest(url, {data: miqSerializeForm(submit)});
    else
      miqJqueryRequest(url, options);

    return false;
  });

  // bind button click to call JS function to send up grid data
  $(document).on('click', 'button[data-grid_submit]', function () {
    return miqMenuChangeRow($(this).attr('data-grid_submit'), $(this));
  });

  // Bind call to check/display text area max length on keyup
  $(document).on('keyup', 'textarea[data-miq_check_max_length]', function () {
    miqCheckMaxLength(this);
  });

  // Bind the MIQ spinning Q to configured links
  $(document).on('ajax:beforeSend', 'a[data-miq_sparkle_on]', function () {
    // Call to miqSparkleOn since miqSparkle(true) checks XHR count, which is 0 before send
    miqSparkleOn();
  });
  $(document).on('ajax:complete', 'a[data-miq_sparkle_off]', function () {
    miqSparkle(false);
  });

  // Handle data-submit - triggered by handleRemote from jquery-ujs
  $(document).on('ajax:before', 'a[data-submit]', function () {
    var form_id = $(this).data('submit');
    // because handleRemote will send the element's data-params as the POST body
    $(this).data('params', miqSerializeForm(form_id));
  });

  // Bind in the observe support. If interval is configured, use the observe_field function
  var attemptAutoRefreshTrigger = function(parms) {
    return function() {
      if (parms.auto_refresh === true) {
        dialogFieldRefresh.triggerAutoRefresh(parms.field_id, parms.trigger);
      }
    };
  };

  var observeWithInterval = function(el, parms) {
    var interval = parms.interval;
    var url = parms.url;
    var submit = parms.submit;

    el.off(); // Use jQuery to turn off observe_field, prevents multi ajax transactions
    el.observe_field(interval, function () {
      var oneTrans = this.getAttribute('data-miq_send_one_trans'); // Grab one trans URL, if present
      if (typeof submit != "undefined") {
        // If submit element passed in
        miqObserveRequest(url, {
          data: miqSerializeForm(submit),
          done: attemptAutoRefreshTrigger(parms),
        });
      } else if (oneTrans) {
        miqSendOneTrans(url, {
          observe: true,
          done: attemptAutoRefreshTrigger(parms),
        });
      } else {
        // tack on the id and value to the URL
        var data = {};
        data[el.attr('id')] = el.prop('value');

        miqObserveRequest(url, {
          done: attemptAutoRefreshTrigger(parms),
          data: data,
        });
      }
    });
  };

  var observeOnChange = function(el, parms) {
    // No interval passed, use event observer
    el.off('change');
    el.on('change', _.debounce(function() {
      var id = el.attr('id');
      var value = el.prop('multiple') ? el.val() : encodeURIComponent(el.prop('value'));

      miqObserveRequest(parms.url, {
        no_encoding: true,
        data: id + '=' + value,
        beforeSend: !! el.attr('data-miq_sparkle_on'),
        complete: !! el.attr('data-miq_sparkle_off'),
        done: attemptAutoRefreshTrigger(parms),
      });
    }, 700, {leading: true, trailing: true}));
  };

  $(document).on('focus', '[data-miq_observe]', function () {
    var el = $(this);
    var parms = $.parseJSON(el.attr('data-miq_observe'));

    if (typeof parms.interval == "undefined") {
      observeOnChange(el, parms);
    } else {
      observeWithInterval(el, parms);
    }
  });

  $(document).on('click', '[data-miq_observe_checkbox]', function (event) {
    var el = $(this);
    var parms = $.parseJSON(el.attr('data-miq_observe_checkbox'));
    var url = parms.url;

    var id = el.attr('id');
    var value = encodeURIComponent(el.prop('checked') ? el.val() : 'null');

    miqObserveRequest(url, {
      no_encoding: true,
      data: id + '=' + value,
      beforeSend: !! el.attr('data-miq_sparkle_on'),
      complete: !! el.attr('data-miq_sparkle_off'),
      done: attemptAutoRefreshTrigger(parms),
    });

    event.stopPropagation();
  });

  ManageIQ.observeDate = function(el) {
    miqSendDateRequest(el);
  };

  $(document).on('changeDate clearDate', '[data-miq_observe_date]', function() {
    ManageIQ.observeDate($(this));
  });

  // Run this last to be sure all other UJS bindings have been run in case the focus field is observed
  $('[data-miq_focus]').each(function(_index) {
    this.focus();
  });
});
<commit_msg>observeWithInterval - fix clearing the handler<commit_after>/* global dialogFieldRefresh miqCheckForChanges miqCheckMaxLength miqJqueryRequest miqMenuChangeRow miqObserveRequest miqSendDateRequest miqSendOneTrans miqSerializeForm miqSparkle miqSparkleOn */

// MIQ unobtrusive javascript bindings run when document is fully loaded

$(document).ready(function () {
  // Bind call to prompt if leaving an active edit
  $(document).on('ajax:beforeSend', 'a[data-miq_check_for_changes]', function () {
    return miqCheckForChanges();
  });

  $(document).on('click', 'button[data-click_url]', function () {
    var el = $(this);
    var parms = $.parseJSON(el.attr('data-click_url'));
    var url = parms.url;
    var options = {};
    if (el.attr('data-miq_sparkle_on')) {
      options.beforeSend = true;
    }
    if (el.attr('data-miq_sparkle_off')) {
      options.complete = true;
    }
    var submit = el.attr('data-submit');
    if (typeof submit != "undefined")
      miqJqueryRequest(url, {data: miqSerializeForm(submit)});
    else
      miqJqueryRequest(url, options);

    return false;
  });

  // bind button click to call JS function to send up grid data
  $(document).on('click', 'button[data-grid_submit]', function () {
    return miqMenuChangeRow($(this).attr('data-grid_submit'), $(this));
  });

  // Bind call to check/display text area max length on keyup
  $(document).on('keyup', 'textarea[data-miq_check_max_length]', function () {
    miqCheckMaxLength(this);
  });

  // Bind the MIQ spinning Q to configured links
  $(document).on('ajax:beforeSend', 'a[data-miq_sparkle_on]', function () {
    // Call to miqSparkleOn since miqSparkle(true) checks XHR count, which is 0 before send
    miqSparkleOn();
  });
  $(document).on('ajax:complete', 'a[data-miq_sparkle_off]', function () {
    miqSparkle(false);
  });

  // Handle data-submit - triggered by handleRemote from jquery-ujs
  $(document).on('ajax:before', 'a[data-submit]', function () {
    var form_id = $(this).data('submit');
    // because handleRemote will send the element's data-params as the POST body
    $(this).data('params', miqSerializeForm(form_id));
  });

  // Bind in the observe support. If interval is configured, use the observe_field function
  var attemptAutoRefreshTrigger = function(parms) {
    return function() {
      if (parms.auto_refresh === true) {
        dialogFieldRefresh.triggerAutoRefresh(parms.field_id, parms.trigger);
      }
    };
  };

  var observeWithInterval = function(el, parms) {
    if (el.data('isObserved')) {
      return;
    }
    el.data('isObserved', true);

    var interval = parms.interval;
    var url = parms.url;
    var submit = parms.submit;

    el.observe_field(interval, function () {
      var oneTrans = this.getAttribute('data-miq_send_one_trans'); // Grab one trans URL, if present
      if (typeof submit != "undefined") {
        // If submit element passed in
        miqObserveRequest(url, {
          data: miqSerializeForm(submit),
          done: attemptAutoRefreshTrigger(parms),
        });
      } else if (oneTrans) {
        miqSendOneTrans(url, {
          observe: true,
          done: attemptAutoRefreshTrigger(parms),
        });
      } else {
        // tack on the id and value to the URL
        var data = {};
        data[el.attr('id')] = el.prop('value');

        miqObserveRequest(url, {
          done: attemptAutoRefreshTrigger(parms),
          data: data,
        });
      }
    });
  };

  var observeOnChange = function(el, parms) {
    // No interval passed, use event observer
    el.off('change');
    el.on('change', _.debounce(function() {
      var id = el.attr('id');
      var value = el.prop('multiple') ? el.val() : encodeURIComponent(el.prop('value'));

      miqObserveRequest(parms.url, {
        no_encoding: true,
        data: id + '=' + value,
        beforeSend: !! el.attr('data-miq_sparkle_on'),
        complete: !! el.attr('data-miq_sparkle_off'),
        done: attemptAutoRefreshTrigger(parms),
      });
    }, 700, {leading: true, trailing: true}));
  };

  $(document).on('focus', '[data-miq_observe]', function () {
    var el = $(this);
    var parms = $.parseJSON(el.attr('data-miq_observe'));

    if (typeof parms.interval == "undefined") {
      observeOnChange(el, parms);
    } else {
      observeWithInterval(el, parms);
    }
  });

  $(document).on('click', '[data-miq_observe_checkbox]', function (event) {
    var el = $(this);
    var parms = $.parseJSON(el.attr('data-miq_observe_checkbox'));
    var url = parms.url;

    var id = el.attr('id');
    var value = encodeURIComponent(el.prop('checked') ? el.val() : 'null');

    miqObserveRequest(url, {
      no_encoding: true,
      data: id + '=' + value,
      beforeSend: !! el.attr('data-miq_sparkle_on'),
      complete: !! el.attr('data-miq_sparkle_off'),
      done: attemptAutoRefreshTrigger(parms),
    });

    event.stopPropagation();
  });

  ManageIQ.observeDate = function(el) {
    miqSendDateRequest(el);
  };

  $(document).on('changeDate clearDate', '[data-miq_observe_date]', function() {
    ManageIQ.observeDate($(this));
  });

  // Run this last to be sure all other UJS bindings have been run in case the focus field is observed
  $('[data-miq_focus]').each(function(_index) {
    this.focus();
  });
});
<|endoftext|>


<commit_before>var ReportAProblem = {
  showErrorMessage: function (jqXHR) {
    var response = "
Sorry, we're unable to receive your message right now.
 " +
                   "
We have other ways for you to provide feedback on the " +
                   "support page.
"
    $('.report-a-problem-container').html(response);
  },

  promptUserToEnterValidData: function() {
    ReportAProblem.enableSubmitButton();
    $('
Please enter details of what you were doing.
').insertAfter('.report-a-problem-container h2');
  },

  disableSubmitButton: function() {
    $('.report-a-problem-container .button').attr("disabled", true);
  },

  enableSubmitButton: function() {
    $('.report-a-problem-container .button').attr("disabled", false);
  },

  showConfirmation: function(data) {
    $('.report-a-problem-container').html(data.message);
  },

  submit: function() {
    $('.report-a-problem-container .error-notification').remove();

    ReportAProblem.disableSubmitButton();
    $.ajax({
      type: "POST",
      url: "/feedback",
      dataType: "json",
      data: $('.report-a-problem-container form').serialize(),
      success: ReportAProblem.showConfirmation,
      error: function(jqXHR, status) {
        if (status === 'error' || !jqXHR.responseText) {
          if (jqXHR.status == 422) {
            ReportAProblem.promptUserToEnterValidData();
          }
          else {
            ReportAProblem.showErrorMessage();
          }
        }
      },
      statusCode: {
        500: ReportAProblem.showErrorMessage
      }
    });
    return false;
  }
}

$(document).ready(function() {
  // toggle for reporting a problem (on all content pages)
  $('.report-a-problem-toggle a').on('click', function() {
    $('.report-a-problem-container').toggle();
      return false;
  });

  // form submission for reporting a problem
  var $forms = $('.report-a-problem-container form, .report-a-problem form');
  $forms.append('<input type="hidden" name="javascript_enabled" value="true"/>');
  $forms.append($('<input type="hidden" name="referrer">').val(document.referrer || "unknown"));

  $('.report-a-problem-container form').submit(ReportAProblem.submit);

});
<commit_msg>update 'report-a-problem' ajax endpoint<commit_after>var ReportAProblem = {
  showErrorMessage: function (jqXHR) {
    var response = "
Sorry, we're unable to receive your message right now.
 " +
                   "
We have other ways for you to provide feedback on the " +
                   "support page.
"
    $('.report-a-problem-container').html(response);
  },

  promptUserToEnterValidData: function() {
    ReportAProblem.enableSubmitButton();
    $('
Please enter details of what you were doing.
').insertAfter('.report-a-problem-container h2');
  },

  disableSubmitButton: function() {
    $('.report-a-problem-container .button').attr("disabled", true);
  },

  enableSubmitButton: function() {
    $('.report-a-problem-container .button').attr("disabled", false);
  },

  showConfirmation: function(data) {
    $('.report-a-problem-container').html(data.message);
  },

  submit: function() {
    $('.report-a-problem-container .error-notification').remove();

    ReportAProblem.disableSubmitButton();
    $.ajax({
      type: "POST",
      url: "/contact/govuk/problem_reports",
      dataType: "json",
      data: $('.report-a-problem-container form').serialize(),
      success: ReportAProblem.showConfirmation,
      error: function(jqXHR, status) {
        if (status === 'error' || !jqXHR.responseText) {
          if (jqXHR.status == 422) {
            ReportAProblem.promptUserToEnterValidData();
          }
          else {
            ReportAProblem.showErrorMessage();
          }
        }
      },
      statusCode: {
        500: ReportAProblem.showErrorMessage
      }
    });
    return false;
  }
}

$(document).ready(function() {
  // toggle for reporting a problem (on all content pages)
  $('.report-a-problem-toggle a').on('click', function() {
    $('.report-a-problem-container').toggle();
      return false;
  });

  // form submission for reporting a problem
  var $forms = $('.report-a-problem-container form, .report-a-problem form');
  $forms.append('<input type="hidden" name="javascript_enabled" value="true"/>');
  $forms.append($('<input type="hidden" name="referrer">').val(document.referrer || "unknown"));

  $('.report-a-problem-container form').submit(ReportAProblem.submit);

});
<|endoftext|>


<commit_before>class_counter = 0;
has_classes = false;
selected_classes = {};

function ClassList(){}

ClassList.prototype.add_class_callback = function(event, ui) {
    var keycode = $.ui.keyCode;
    if( event.keyCode == keycode.TAB ) {
        /* If the user hit a tab, we don't want to add it just yet */
        return;
    }
    /* Prevent input box being filled */
    event.preventDefault();
    this.value = "";

    if ( ui.item ) {
        show_button();
        var class_id = ui.item.value;
        if( class_id in selected_classes ){
            /* return if the user as already selected the class*/
            pop_alert("error","class is already selected");
            return;
        } else {
            selected_classes[class_id] = class_counter;
        }

        /* Append the course to the currently populated list */
        var remove_course = $("<a/>").text("X").attr("href", "#").addClass("remove-link");
        var course_li = $("<li/>")
                            .append(remove_course)
                            .append($("<span/>")
                                .text(ui.item.label)
                                .addClass("code"))
                            .append($("<span/>")
                                .text(ui.item.title)
                                .addClass("title"))
                            .css("display", "none");
        course_li.appendTo(".user-course-list ul");
        course_li.slideDown();

        remove_course.click( function() {
            var removed = 0;
            // Search through the hidden form and remove this element
            $(".hidden-course-form").children().each( function(i) {
                if($(this).val() == class_id){
                    $(this).remove();
                    removed++;
                } else if ($(this).attr("name") == "size"){
                    var current_size = $(this).val();
                    $(this).val(current_size - removed );
                };
            });
            course_li.slideUp();
            $(this).remove();
            delete selected_classes[class_id];
        });

        /* Add the course id to our hidden form */
        add_course_id_to_hidden_form(class_id);
        class_counter++;

        /* use a form to keep track of count */
        $("<input>").val(class_counter)
            .attr("type", "hidden")
            .attr("name", "size")
            .appendTo(".hidden-course-form");
    }

}

function show_button() {
    if( has_classes ) return;
    $(".hidden-course-form .btn.primary.hidden").removeClass("hidden");
    $(".user-course-list span.hint")
        .animate({
            opacity: 0,
            display: 'none',
          }, 200, function() {
            $(this).slideUp();
          });
    has_classes = true;
};

/* In order to send a list of class ids to rails, we need to silently
   keep track of the class ids in a hidden form as well as send the size of the list */
var add_course_id_to_hidden_form = function( course_id ) {
    $("<input>").val(course_id)
        .attr("type", "hidden")
        .attr("name", class_counter)
        .appendTo(".hidden-course-form");
};
<commit_msg>fixed bug with adding duplicate courses<commit_after>class_counter = 0;
has_classes = false;
selected_classes = {};

function ClassList(){ }

ClassList.prototype.init = function() {
    console.log("init");
    $(".user-course-list ul li .code").each( function(i, element) {
        var class_id = element.innerHTML;
        selected_classes[class_id] = class_counter;
        class_counter++;
    });
}

ClassList.prototype.add_class_callback = function(event, ui) {
    var keycode = $.ui.keyCode;
    if( event.keyCode == keycode.TAB ) {
        /* If the user hit a tab, we don't want to add it just yet */
        return;
    }
    /* Prevent input box being filled */
    event.preventDefault();
    this.value = "";

    if ( ui.item ) {
        show_button();
        var class_id = ui.item.value;
        console.log(class_id);
        if( class_id in selected_classes ){
            /* return if the user as already selected the class*/
            pop_alert("error","class is already selected");
            return;
        } else {
            selected_classes[class_id] = class_counter;
        }

        /* Append the course to the currently populated list */
        var remove_course = $("<a/>").text("X").attr("href", "#").addClass("remove-link");
        var course_li = $("<li/>")
                            .append(remove_course)
                            .append($("<span/>")
                                .text(ui.item.label)
                                .addClass("code"))
                            .append($("<span/>")
                                .text(ui.item.title)
                                .addClass("title"))
                            .css("display", "none");
        course_li.appendTo(".user-course-list ul");
        course_li.slideDown();

        remove_course.click( function() {
            var removed = 0;
            // Search through the hidden form and remove this element
            $(".hidden-course-form").children().each( function(i) {
                if($(this).val() == class_id){
                    $(this).remove();
                    removed++;
                } else if ($(this).attr("name") == "size"){
                    var current_size = $(this).val();
                    $(this).val(current_size - removed );
                };
            });
            course_li.slideUp();
            $(this).remove();
            delete selected_classes[class_id];
        });

        /* Add the course id to our hidden form */
        add_course_id_to_hidden_form(class_id);
        class_counter++;

        /* use a form to keep track of count */
        $("<input>").val(class_counter)
            .attr("type", "hidden")
            .attr("name", "size")
            .appendTo(".hidden-course-form");
    }

}

function show_button() {
    if( has_classes ) return;
    $(".hidden-course-form .btn.primary.hidden").removeClass("hidden");
    $(".user-course-list span.hint")
        .animate({
            opacity: 0,
            display: 'none',
          }, 200, function() {
            $(this).slideUp();
          });
    has_classes = true;
};

/* In order to send a list of class ids to rails, we need to silently
   keep track of the class ids in a hidden form as well as send the size of the list */
var add_course_id_to_hidden_form = function( course_id ) {
    $("<input>").val(course_id)
        .attr("type", "hidden")
        .attr("name", class_counter)
        .appendTo(".hidden-course-form");
};
<|endoftext|>


<commit_before>const fs = require('fs');
const { join } = require('path');
const rimraf = require('rimraf-promise');

let stopped;

function pad(n, padding) {
	n = n + '';
	return n.length >= padding ? n : new Array(padding - n.length + 1).join('0') + n;
}

function getFilename(options, frameNumber) {
	return join(options.directory, options.prefix + pad(frameNumber, options.pngPadding) + '.png');
}

export function exportPNGs(options, iframe) {
	const gShaderToy = iframe.contentWindow.gShaderToy;

	const originalWidth = gShaderToy.mCanvas.width;
	const originalHeight = gShaderToy.mCanvas.height;

	const originalGetRealTime = iframe.contentWindow.getRealTime;

	const originalRequestAnimationFrame = gShaderToy.mEffect.RequestAnimationFrame;

	const originalIsPaused = gShaderToy.mIsPaused;

	let frameNumber = 0;
	const frameCount = options.duration * options.fps;
	let frameCountBeforeResolve = frameCount;

	let complete = false;
	stopped = false;

	let exportErr = null;

	return new Promise((resolve, reject) => {
		function saveFrame() {
			const filename = getFilename(options, frameNumber);
			return gShaderToy.mCanvas.toBlob((blob) => {
				const reader = new FileReader();
				reader.onload = () => {
					const buffer = new Buffer(reader.result);
					return fs.writeFile(filename, buffer, (err) => {
						if (err)
							return reject(err);

						--frameCountBeforeResolve;
						if (!frameCountBeforeResolve)
							return resolve();
					});
				};
				return reader.readAsArrayBuffer(blob);
			});
		}

		function render(originalRender) {
			if (stopped || frameNumber + 1 >= frameCount)
				complete = true;

			originalRender();

			if (stopped)
				return reject(new Error('Frame export was stopped.'));

			saveFrame();
			++frameNumber;
		}

		function RequestAnimationFrame(originalRender) {
			originalRequestAnimationFrame.call(gShaderToy.mEffect, complete ? originalRender : render.bind(this, originalRender));
		}

		function getRealTime() {
			return (options.start + frameNumber / options.fps) * 1000;
		}

		gShaderToy.resize(options.width, options.height);

		iframe.contentWindow.getRealTime = getRealTime;

		gShaderToy.mEffect.RequestAnimationFrame = RequestAnimationFrame;

		if (gShaderToy.mIsPaused) {
			gShaderToy.pauseTime();
		}

		gShaderToy.resetTime();
		gShaderToy.mTo = 0;
	})
		.catch((err) => {
			exportErr = err;
		})
		.then(() => {
			return new Promise((resolve, reject) => {
				gShaderToy.resize(originalWidth, originalHeight);

				iframe.contentWindow.getRealTime = originalGetRealTime;

				gShaderToy.mEffect.RequestAnimationFrame = originalRequestAnimationFrame;

				if (originalIsPaused) {
					gShaderToy.pauseTime();
				}

				if (exportErr)
					return reject(exportErr);
				else
					return resolve();
			});
		});
}

export function removePNGs(options) {
	const frameCount = options.duration * options.fps;
	const promises = [];
	for (let frameNumber = 0; frameNumber < frameCount; ++frameNumber) {
		promises.push(rimraf(getFilename(options, frameNumber)));
	}
	return Promise.all(promises);
}

export function stop() {
	stopped = true;
}
<commit_msg>Use native function for filename padding<commit_after>const fs = require('fs');
const { join } = require('path');
const rimraf = require('rimraf-promise');

let stopped;

function getFilename(options, frameNumber) {
	return join(options.directory, options.prefix + frameNumber.toString().padStart(options.pngPadding, '0') + '.png');
}

export function exportPNGs(options, iframe) {
	const gShaderToy = iframe.contentWindow.gShaderToy;

	const originalWidth = gShaderToy.mCanvas.width;
	const originalHeight = gShaderToy.mCanvas.height;

	const originalGetRealTime = iframe.contentWindow.getRealTime;

	const originalRequestAnimationFrame = gShaderToy.mEffect.RequestAnimationFrame;

	const originalIsPaused = gShaderToy.mIsPaused;

	let frameNumber = 0;
	const frameCount = options.duration * options.fps;
	let frameCountBeforeResolve = frameCount;

	let complete = false;
	stopped = false;

	let exportErr = null;

	return new Promise((resolve, reject) => {
		function saveFrame() {
			const filename = getFilename(options, frameNumber);
			return gShaderToy.mCanvas.toBlob((blob) => {
				const reader = new FileReader();
				reader.onload = () => {
					const buffer = new Buffer(reader.result);
					return fs.writeFile(filename, buffer, (err) => {
						if (err)
							return reject(err);

						--frameCountBeforeResolve;
						if (!frameCountBeforeResolve)
							return resolve();
					});
				};
				return reader.readAsArrayBuffer(blob);
			});
		}

		function render(originalRender) {
			if (stopped || frameNumber + 1 >= frameCount)
				complete = true;

			originalRender();

			if (stopped)
				return reject(new Error('Frame export was stopped.'));

			saveFrame();
			++frameNumber;
		}

		function RequestAnimationFrame(originalRender) {
			originalRequestAnimationFrame.call(gShaderToy.mEffect, complete ? originalRender : render.bind(this, originalRender));
		}

		function getRealTime() {
			return (options.start + frameNumber / options.fps) * 1000;
		}

		gShaderToy.resize(options.width, options.height);

		iframe.contentWindow.getRealTime = getRealTime;

		gShaderToy.mEffect.RequestAnimationFrame = RequestAnimationFrame;

		if (gShaderToy.mIsPaused) {
			gShaderToy.pauseTime();
		}

		gShaderToy.resetTime();
		gShaderToy.mTo = 0;
	})
		.catch((err) => {
			exportErr = err;
		})
		.then(() => {
			return new Promise((resolve, reject) => {
				gShaderToy.resize(originalWidth, originalHeight);

				iframe.contentWindow.getRealTime = originalGetRealTime;

				gShaderToy.mEffect.RequestAnimationFrame = originalRequestAnimationFrame;

				if (originalIsPaused) {
					gShaderToy.pauseTime();
				}

				if (exportErr)
					return reject(exportErr);
				else
					return resolve();
			});
		});
}

export function removePNGs(options) {
	const frameCount = options.duration * options.fps;
	const promises = [];
	for (let frameNumber = 0; frameNumber < frameCount; ++frameNumber) {
		promises.push(rimraf(getFilename(options, frameNumber)));
	}
	return Promise.all(promises);
}

export function stop() {
	stopped = true;
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Isvg from 'react-inlinesvg'
import FaExternalLink from 'react-icons/lib/fa/external-link'
import FaCircle from 'react-icons/lib/fa/circle'
import FaRepeat from 'react-icons/lib/fa/repeat'
import FaAngleDown from 'react-icons/lib/fa/angle-down'
import { btc, blockExplorer } from 'lib/utils'
import plus from 'icons/plus.svg'
import search from 'icons/search.svg'

import Value from 'components/Value'

import { FormattedNumber, FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'

import SuggestedNodes from '../SuggestedNodes'

import styles from './Network.scss'

class Network extends Component {
  constructor(props) {
    super(props)

    this.state = {
      refreshing: false
    }
  }

  render() {
    const {
      channels: {
        searchQuery,
        filterPulldown,
        filter,
        selectedChannel,
        loadingChannelPubkeys,
        closingChannelIds,
        channels,
        pendingChannels: { pending_open_channels }
      },
      currentChannels,
      balance,
      ticker,
      currentTicker,

      nodes,

      fetchChannels,
      openContactsForm,

      nonActiveFilters,
      toggleFilterPulldown,
      changeFilter,

      updateChannelSearchQuery,

      setSelectedChannel,

      closeChannel,

      suggestedNodesProps,

      network,

      currencyName,
      intl
    } = this.props

    const refreshClicked = () => {
      // turn the spinner on
      this.setState({ refreshing: true })

      // store event in icon so we dont get an error when react clears it
      const icon = this.repeat.childNodes

      // fetch channels
      fetchChannels()

      // wait for the svg to appear as child
      const svgTimeout = setTimeout(() => {
        if (icon[0].tagName === 'svg') {
          // spin icon for 1 sec
          icon[0].style.animation = 'spin 1000ms linear 1'
          clearTimeout(svgTimeout)
        }
      }, 1)

      // clear animation after the second so we can reuse it
      const refreshTimeout = setTimeout(() => {
        icon[0].style.animation = ''
        this.setState({ refreshing: false })
        clearTimeout(refreshTimeout)
      }, 1000)
    }

    // when the user clicks the action to close the channel
    const removeClicked = removeChannel => {
      closeChannel({
        channel_point: removeChannel.channel_point,
        chan_id: removeChannel.chan_id,
        force: !removeChannel.active
      })
    }

    // when a user clicks a channel
    const channelClicked = clickedChannel => {
      // selectedChannel === channel ? setSelectedChannel(null) : setSelectedChannel(channel)
      if (selectedChannel === clickedChannel) {
        setSelectedChannel(null)
      } else {
        setSelectedChannel(clickedChannel)
      }
    }

    const displayNodeName = displayedChannel => {
      // due to inconsistent API vals the remote nodes pubkey will be under remote_pubkey for active channels and
      // remote_node_pub for closing channels. remote_node_pubkey gets the remote pubkey depending on what type of
      // channel we have
      const remote_node_pubkey = displayedChannel.remote_pubkey || displayedChannel.remote_node_pub

      const node = nodes.find(n => n.pub_key === remote_node_pubkey)

      if (node && node.alias.length) {
        return node.alias
      }

      return displayedChannel.remote_pubkey
        ? displayedChannel.remote_pubkey.substring(0, 10)
        : displayedChannel.remote_node_pub.substring(0, 10)
    }

    const channelStatus = statusChannel => {
      // if the channel has a confirmation_height property that means it's pending
      if (Object.prototype.hasOwnProperty.call(statusChannel, 'confirmation_height')) {
        return 'pending'
      }

      // if the channel has a closing tx that means it's closing
      if (Object.prototype.hasOwnProperty.call(statusChannel, 'closing_txid')) {
        return 'closing'
      }

      // if the channel is in waiting_close_channels phase
      if (Object.prototype.hasOwnProperty.call(statusChannel, 'limbo_balance')) {
        return 'closing'
      }

      // if we are in the process of closing this channel
      if (closingChannelIds.includes(statusChannel.chan_id)) {
        return 'closing'
      }

      // if the channel isn't active that means the remote peer isn't online
      if (!statusChannel.active) {
        return 'offline'
      }

      // if all of the above conditionals fail we can assume the node is online :)
      return 'online'
    }

    const fiatAmount = btc.satoshisToFiat(
      balance.channelBalance,
      currentTicker[ticker.fiatTicker].last
    )
    const { refreshing } = this.state
    return (

              <FormattedMessage {...messages.title} />

              {Boolean(balance.channelBalance) && (
                <Value
                  value={balance.channelBalance}
                  currency={ticker.currency}
                  currentTicker={currentTicker}
                  fiatTicker={ticker.fiatTicker}
                />
              )}
              {Boolean(fiatAmount) && (

                  {'≈ '}
                  <FormattedNumber
                    currency={ticker.fiatTicker}
                    style="currency"
                    value={fiatAmount}
                  />

              )}

          <section
            className={`${styles.addChannel} hint--bottom-left`}
            onClick={openContactsForm}
            data-hint={intl.formatMessage({ ...messages.open_channel })}
          >

              <Isvg src={plus} />

          {loadingChannelPubkeys.length || pending_open_channels.length || channels.length ? (

                  {filter.name}{' '}

                    <FaAngleDown />

                <ul className={`${styles.filters} ${filterPulldown ? styles.active : undefined}`}>
                  {nonActiveFilters.map(f => (

 changeFilter(f)}>
                      {f.name}

                  ))}

                 {
                    this.repeat = ref
                  }}
                >
                  {refreshing ? <FaRepeat /> : <FormattedMessage {...messages.refresh} />}

          ) : (
            <SuggestedNodes {...suggestedNodesProps} />
          )}

            {loadingChannelPubkeys.length > 0 &&
              loadingChannelPubkeys.map(loadingPubkey => {
                // TODO(jimmymow): refactor this out. same logic is in displayNodeName above
                const node = nodes.find(n => loadingPubkey === n.pub_key)
                const nodeDisplay = () => {
                  if (node && node.alias.length) {
                    return node.alias
                  }

                  return loadingPubkey.substring(0, 10)
                }

                return (

                      <span
                        className={`${styles.loading} hint--right`}
                        data-hint={intl.formatMessage({ ...messages.loading })}
                      >

                      {nodeDisplay()}

                )
              })}
            {currentChannels.length > 0 &&
              currentChannels.map((channelObj, index) => {
                const channel = Object.prototype.hasOwnProperty.call(channelObj, 'channel')
                  ? channelObj.channel
                  : channelObj
                const pubkey = channel.remote_node_pub || channel.remote_pubkey

                return (

 channelClicked(channel)}
                  >

                      <span
                        className={`${styles[channelStatus(channelObj)]} hint--right`}
                        data-hint={intl.formatMessage({ ...messages[channelStatus(channelObj)] })}
                      >
                        {closingChannelIds.includes(channel.chan_id) ? (

                            <i className={`${styles.spinner} ${styles.closing}`} />

                        ) : (
                          <FaCircle />
                        )}

                      {displayNodeName(channel)}
                      {selectedChannel === channel && (

                            blockExplorer.showTransaction(
                              network,
                              channelObj.closing_txid || channel.channel_point.split(':')[0]
                            )
                          }
                        >
                          <FaExternalLink />

                      )}

{`${pubkey.substring(0, 30)}...`}

                            <FormattedMessage {...messages.pay_limit} />

                            <Value
                              value={channel.local_balance}
                              currency={ticker.currency}
                              currentTicker={currentTicker}
                              fiatTicker={ticker.fiatTicker}
                            />
                             {currencyName}

                            <FormattedMessage {...messages.req_limit} />

                            <Value
                              value={channel.remote_balance}
                              currency={ticker.currency}
                              currentTicker={currentTicker}
                              fiatTicker={ticker.fiatTicker}
                            />
                             {currencyName}

                        {closingChannelIds.includes(channel.chan_id) && (

                            <span
                              className={`${styles.loading} hint--right`}
                              data-hint={intl.formatMessage({ ...messages.closing })}
                            >
                              Closing <i className={`${styles.spinner} ${styles.closing}`} />

                        )}
                        {Object.prototype.hasOwnProperty.call(channel, 'active') &&
                          !closingChannelIds.includes(channel.chan_id) && (

 removeClicked(channel)}>

Disconnect

                          )}

                )
              })}

        {(loadingChannelPubkeys.length || pending_open_channels.length || channels.length) && (

            <label htmlFor="search" className={`${styles.label} ${styles.input}`}>
              <Isvg src={search} />

            <input
              id="search"
              type="text"
              className={`${styles.text} ${styles.input}`}
              placeholder={intl.formatMessage({ ...messages.search_placeholder })}
              value={searchQuery}
              onChange={event => updateChannelSearchQuery(event.target.value)}
            />

        )}

    )
  }
}

Network.propTypes = {
  currentChannels: PropTypes.array.isRequired,
  nodes: PropTypes.array.isRequired,
  nonActiveFilters: PropTypes.array.isRequired,

  channels: PropTypes.object.isRequired,
  balance: PropTypes.object.isRequired,
  currentTicker: PropTypes.object.isRequired,
  ticker: PropTypes.object.isRequired,
  suggestedNodesProps: PropTypes.object.isRequired,

  network: PropTypes.object.isRequired,

  fetchChannels: PropTypes.func.isRequired,
  openContactsForm: PropTypes.func.isRequired,
  toggleFilterPulldown: PropTypes.func.isRequired,
  changeFilter: PropTypes.func.isRequired,
  updateChannelSearchQuery: PropTypes.func.isRequired,
  setSelectedChannel: PropTypes.func.isRequired,
  closeChannel: PropTypes.func.isRequired,

  currencyName: PropTypes.string.isRequired
}

export default injectIntl(Network)
<commit_msg>fix(channels): display currencyName in network<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Isvg from 'react-inlinesvg'
import FaExternalLink from 'react-icons/lib/fa/external-link'
import FaCircle from 'react-icons/lib/fa/circle'
import FaRepeat from 'react-icons/lib/fa/repeat'
import FaAngleDown from 'react-icons/lib/fa/angle-down'
import { btc, blockExplorer } from 'lib/utils'
import plus from 'icons/plus.svg'
import search from 'icons/search.svg'

import Value from 'components/Value'

import { FormattedNumber, FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages'

import SuggestedNodes from '../SuggestedNodes'

import styles from './Network.scss'

class Network extends Component {
  constructor(props) {
    super(props)

    this.state = {
      refreshing: false
    }
  }

  render() {
    const {
      channels: {
        searchQuery,
        filterPulldown,
        filter,
        selectedChannel,
        loadingChannelPubkeys,
        closingChannelIds,
        channels,
        pendingChannels: { pending_open_channels }
      },
      currentChannels,
      balance,
      ticker,
      currentTicker,

      nodes,

      fetchChannels,
      openContactsForm,

      nonActiveFilters,
      toggleFilterPulldown,
      changeFilter,

      updateChannelSearchQuery,

      setSelectedChannel,

      closeChannel,

      suggestedNodesProps,

      network,

      currencyName,
      intl
    } = this.props

    const refreshClicked = () => {
      // turn the spinner on
      this.setState({ refreshing: true })

      // store event in icon so we dont get an error when react clears it
      const icon = this.repeat.childNodes

      // fetch channels
      fetchChannels()

      // wait for the svg to appear as child
      const svgTimeout = setTimeout(() => {
        if (icon[0].tagName === 'svg') {
          // spin icon for 1 sec
          icon[0].style.animation = 'spin 1000ms linear 1'
          clearTimeout(svgTimeout)
        }
      }, 1)

      // clear animation after the second so we can reuse it
      const refreshTimeout = setTimeout(() => {
        icon[0].style.animation = ''
        this.setState({ refreshing: false })
        clearTimeout(refreshTimeout)
      }, 1000)
    }

    // when the user clicks the action to close the channel
    const removeClicked = removeChannel => {
      closeChannel({
        channel_point: removeChannel.channel_point,
        chan_id: removeChannel.chan_id,
        force: !removeChannel.active
      })
    }

    // when a user clicks a channel
    const channelClicked = clickedChannel => {
      // selectedChannel === channel ? setSelectedChannel(null) : setSelectedChannel(channel)
      if (selectedChannel === clickedChannel) {
        setSelectedChannel(null)
      } else {
        setSelectedChannel(clickedChannel)
      }
    }

    const displayNodeName = displayedChannel => {
      // due to inconsistent API vals the remote nodes pubkey will be under remote_pubkey for active channels and
      // remote_node_pub for closing channels. remote_node_pubkey gets the remote pubkey depending on what type of
      // channel we have
      const remote_node_pubkey = displayedChannel.remote_pubkey || displayedChannel.remote_node_pub

      const node = nodes.find(n => n.pub_key === remote_node_pubkey)

      if (node && node.alias.length) {
        return node.alias
      }

      return displayedChannel.remote_pubkey
        ? displayedChannel.remote_pubkey.substring(0, 10)
        : displayedChannel.remote_node_pub.substring(0, 10)
    }

    const channelStatus = statusChannel => {
      // if the channel has a confirmation_height property that means it's pending
      if (Object.prototype.hasOwnProperty.call(statusChannel, 'confirmation_height')) {
        return 'pending'
      }

      // if the channel has a closing tx that means it's closing
      if (Object.prototype.hasOwnProperty.call(statusChannel, 'closing_txid')) {
        return 'closing'
      }

      // if the channel is in waiting_close_channels phase
      if (Object.prototype.hasOwnProperty.call(statusChannel, 'limbo_balance')) {
        return 'closing'
      }

      // if we are in the process of closing this channel
      if (closingChannelIds.includes(statusChannel.chan_id)) {
        return 'closing'
      }

      // if the channel isn't active that means the remote peer isn't online
      if (!statusChannel.active) {
        return 'offline'
      }

      // if all of the above conditionals fail we can assume the node is online :)
      return 'online'
    }

    const fiatAmount = btc.satoshisToFiat(
      balance.channelBalance,
      currentTicker[ticker.fiatTicker].last
    )
    const { refreshing } = this.state
    return (

              <FormattedMessage {...messages.title} />

              {Boolean(balance.channelBalance) && (

                  <Value
                    value={balance.channelBalance}
                    currency={ticker.currency}
                    currentTicker={currentTicker}
                    fiatTicker={ticker.fiatTicker}
                  />
                   {currencyName}

              )}
              {Boolean(fiatAmount) && (

                  {' ≈ '}
                  <FormattedNumber
                    currency={ticker.fiatTicker}
                    style="currency"
                    value={fiatAmount}
                  />

              )}

          <section
            className={`${styles.addChannel} hint--bottom-left`}
            onClick={openContactsForm}
            data-hint={intl.formatMessage({ ...messages.open_channel })}
          >

              <Isvg src={plus} />

          {loadingChannelPubkeys.length || pending_open_channels.length || channels.length ? (

                  {filter.name}{' '}

                    <FaAngleDown />

                <ul className={`${styles.filters} ${filterPulldown ? styles.active : undefined}`}>
                  {nonActiveFilters.map(f => (

 changeFilter(f)}>
                      {f.name}

                  ))}

                 {
                    this.repeat = ref
                  }}
                >
                  {refreshing ? <FaRepeat /> : <FormattedMessage {...messages.refresh} />}

          ) : (
            <SuggestedNodes {...suggestedNodesProps} />
          )}

            {loadingChannelPubkeys.length > 0 &&
              loadingChannelPubkeys.map(loadingPubkey => {
                // TODO(jimmymow): refactor this out. same logic is in displayNodeName above
                const node = nodes.find(n => loadingPubkey === n.pub_key)
                const nodeDisplay = () => {
                  if (node && node.alias.length) {
                    return node.alias
                  }

                  return loadingPubkey.substring(0, 10)
                }

                return (

                      <span
                        className={`${styles.loading} hint--right`}
                        data-hint={intl.formatMessage({ ...messages.loading })}
                      >

                      {nodeDisplay()}

                )
              })}
            {currentChannels.length > 0 &&
              currentChannels.map((channelObj, index) => {
                const channel = Object.prototype.hasOwnProperty.call(channelObj, 'channel')
                  ? channelObj.channel
                  : channelObj
                const pubkey = channel.remote_node_pub || channel.remote_pubkey

                return (

 channelClicked(channel)}
                  >

                      <span
                        className={`${styles[channelStatus(channelObj)]} hint--right`}
                        data-hint={intl.formatMessage({ ...messages[channelStatus(channelObj)] })}
                      >
                        {closingChannelIds.includes(channel.chan_id) ? (

                            <i className={`${styles.spinner} ${styles.closing}`} />

                        ) : (
                          <FaCircle />
                        )}

                      {displayNodeName(channel)}
                      {selectedChannel === channel && (

                            blockExplorer.showTransaction(
                              network,
                              channelObj.closing_txid || channel.channel_point.split(':')[0]
                            )
                          }
                        >
                          <FaExternalLink />

                      )}

{`${pubkey.substring(0, 30)}...`}

                            <FormattedMessage {...messages.pay_limit} />

                            <Value
                              value={channel.local_balance}
                              currency={ticker.currency}
                              currentTicker={currentTicker}
                              fiatTicker={ticker.fiatTicker}
                            />
                             {currencyName}

                            <FormattedMessage {...messages.req_limit} />

                            <Value
                              value={channel.remote_balance}
                              currency={ticker.currency}
                              currentTicker={currentTicker}
                              fiatTicker={ticker.fiatTicker}
                            />
                             {currencyName}

                        {closingChannelIds.includes(channel.chan_id) && (

                            <span
                              className={`${styles.loading} hint--right`}
                              data-hint={intl.formatMessage({ ...messages.closing })}
                            >
                              Closing <i className={`${styles.spinner} ${styles.closing}`} />

                        )}
                        {Object.prototype.hasOwnProperty.call(channel, 'active') &&
                          !closingChannelIds.includes(channel.chan_id) && (

 removeClicked(channel)}>

Disconnect

                          )}

                )
              })}

        {(loadingChannelPubkeys.length || pending_open_channels.length || channels.length) && (

            <label htmlFor="search" className={`${styles.label} ${styles.input}`}>
              <Isvg src={search} />

            <input
              id="search"
              type="text"
              className={`${styles.text} ${styles.input}`}
              placeholder={intl.formatMessage({ ...messages.search_placeholder })}
              value={searchQuery}
              onChange={event => updateChannelSearchQuery(event.target.value)}
            />

        )}

    )
  }
}

Network.propTypes = {
  currentChannels: PropTypes.array.isRequired,
  nodes: PropTypes.array.isRequired,
  nonActiveFilters: PropTypes.array.isRequired,

  channels: PropTypes.object.isRequired,
  balance: PropTypes.object.isRequired,
  currentTicker: PropTypes.object.isRequired,
  ticker: PropTypes.object.isRequired,
  suggestedNodesProps: PropTypes.object.isRequired,

  network: PropTypes.object.isRequired,

  fetchChannels: PropTypes.func.isRequired,
  openContactsForm: PropTypes.func.isRequired,
  toggleFilterPulldown: PropTypes.func.isRequired,
  changeFilter: PropTypes.func.isRequired,
  updateChannelSearchQuery: PropTypes.func.isRequired,
  setSelectedChannel: PropTypes.func.isRequired,
  closeChannel: PropTypes.func.isRequired,

  currencyName: PropTypes.string.isRequired
}

export default injectIntl(Network)
<|endoftext|>


<commit_before>/*
 *
 * AddHintContainer reducer
 *
 */

import { fromJS } from 'immutable';
import {
  DEFAULT_ACTION, GET_COORDINATES, GET_COORDINATES_SUCCESS, SUBMIT_COORDINATES,
  SUBMIT_COORDINATES_SUCCESS,
} from './constants';

const initialState = fromJS({
  loading: false,
  rdx: 0,
  rdy: 0,
  wgs: false,
  subarea: false,
  address: false,
  submittingSuccess: false,
  submitting: false,
});

function addHintContainerReducer(state = initialState, action) {
  switch (action.type) {
    case GET_COORDINATES:
      return state
        .set('loading', true)
        .set('successSuccess', false)
        .set('rdx', action.rdx)
        .set('rdy', action.rdy);
    case GET_COORDINATES_SUCCESS:
      return state
        .set('loading', false)
        .set('subarea', action.response.subarea)
        .set('address', action.response.address)
        .set('wgs', action.response.wgs);
    case SUBMIT_COORDINATES:
      return state
        .set('submitting', true);
    case SUBMIT_COORDINATES_SUCCESS:
      return state
        .set('submitting', false)
        .set('subarea', false)
        .set('address', false)
        .set('wgs', false)
        .set('rdx', false)
        .set('submittingSuccess', true)
        .set('rdy', false);
    case DEFAULT_ACTION:
      return state;
    default:
      return state;
  }
}

export default addHintContainerReducer;
<commit_msg>Bugfix for SuccessComponent<commit_after>/*
 *
 * AddHintContainer reducer
 *
 */

import { fromJS } from 'immutable';
import {
  DEFAULT_ACTION, GET_COORDINATES, GET_COORDINATES_SUCCESS, SUBMIT_COORDINATES,
  SUBMIT_COORDINATES_SUCCESS,
} from './constants';

const initialState = fromJS({
  loading: false,
  rdx: 0,
  rdy: 0,
  wgs: false,
  subarea: false,
  address: false,
  submittingSuccess: false,
  submitting: false,
});

function addHintContainerReducer(state = initialState, action) {
  switch (action.type) {
    case GET_COORDINATES:
      return state
        .set('loading', true)
        .set('submittingSuccess', false)
        .set('rdx', action.rdx)
        .set('rdy', action.rdy);
    case GET_COORDINATES_SUCCESS:
      return state
        .set('loading', false)
        .set('subarea', action.response.subarea)
        .set('address', action.response.address)
        .set('wgs', action.response.wgs);
    case SUBMIT_COORDINATES:
      return state
        .set('submitting', true);
    case SUBMIT_COORDINATES_SUCCESS:
      return state
        .set('submitting', false)
        .set('subarea', false)
        .set('address', false)
        .set('wgs', false)
        .set('rdx', false)
        .set('submittingSuccess', true)
        .set('rdy', false);
    case DEFAULT_ACTION:
      return state;
    default:
      return state;
  }
}

export default addHintContainerReducer;
<|endoftext|>


<commit_before>export default Ember.ObjectController.extend(Ember.Validations.Mixin, {
  actions: {
    /*
     * copy first line
     */
    copyFirstLine: function(){
      var datetimes = this.get('datetimes'),
          firstLine = datetimes[0];

      datetimes.forEach(function(datetime, key) {
        // skip first element
        if (key > 0) {
          var newTimes = [];
          firstLine.contents.times.forEach(function(time){
            newTimes.pushObject({
              value: time.value
            });
          });

          datetime.set('contents.times', newTimes);
        }
      });
    },

    /*
     * increase number of inputs fields for time
     */
    moreTimes: function(){
      this.set('datetimesInputFields', this.get('datetimesInputFields') + 1);

      this.get('datetimes').forEach(function(datetime){
        datetime.contents.times.pushObject({
          value: ''
        });
      });

      // update polyfill used for legacy support of html5 input time after new form elements have been insert
      // has to wait after dom is updated
      Ember.run.next(this, function() { $('input[type=time]').updatePolyfill(); });
    },

    /*
     * set new options depending on selected times
     */
    submitDatetimes: function(){
      var datetimes = this.get('datetimes'),
          newOptions = [],
          self = this;

      datetimes.forEach(function(datetime){
        datetime.contents.times.forEach(function(t){
          var date = new Date(datetime.contents.title),
              delimiter = '';

          // check if there is a value for time
          if (Ember.isEmpty(t.value)) {
            return;
          }

          // try to split time in minutes and hours
          var time = self.getHoursAndMinutesFromInput(t.value);

          // check time for valid format
          if (time !== false) {
            // hours and minutes seems valid, so update the date
            date.setHours(time.hours);
            date.setMinutes(time.minutes);

            newOptions.pushObject({
              title: date
            });
          }
        });
      });

      // check if we have at least 2 options now
      if (newOptions.length < 2) {
        return;
      }

      this.set('options', newOptions);

      // tricker save action
      this.send('save');
    },

    save: function(){
      // redirect to create/settings route
      this.transitionToRoute('create.settings');
    }
  },

  /*
   * only used on init, not on increasing number of input fields!
   */
  datetimes: function(key, value, previousValue){
    var datetimes = Ember.A(),
        dates = this.get('options'),
        datetimesCount = this.get('datetimesInputFields'),
        self = this;

    if (typeof dates !== 'undefined') {
      dates.forEach(function(date){
        var o = {
          title: date.title,
          times: Ember.A()
        };

        for(var i = 1; i<=datetimesCount; i++) {
          o.times.pushObject({
            value: ''
          });
        }

        datetimes.pushObject(self.get('datetimesTimesArray').create({'contents':o}));
      });
    }

    return datetimes;
  }.property('options'),

  /*
   * helper Object as work-a-round to observe a nested array
   */
  datetimesTimesArray: Ember.Object.extend({
    '@eachTimesValue': function(){
      var times = [];
      this.get('contents.times').forEach(function(value){
        times.push(value.value);
      });
      return times;
    }.property('contents.times.@each.value')
  }),

  enoughTimes: function(){
    var datetimes = this.get('datetimes'),
        self = this,
        isValid = true;

    datetimes.forEach(function(value, key){
      var times = self.get('datetimes.' + key + '.@eachTimesValue'),
          valid = false;

      times.forEach(function(time){
        if(self.getHoursAndMinutesFromInput(time) !== false){
          valid = true;
        }
      });

      if (valid === false) {
        isValid = false;
      }
    });

    return isValid;
  }.property('datetimes.@each.@eachTimesValue'),

  getHoursAndMinutesFromInput: function(time){
    // try to split time in minutes and hours
    var t;
    if (time.indexOf(':') !== -1) {
      t = time.split(':');
    }
    else {
      // time is not in a correct format
      return false;
    }

    if (t.length !== 2) {
      // time is not in a correct format
      return false;
    }

    // get hours and minutes
    var h = parseInt(t[0]),
        m = parseInt(t[1]);

    // check time for valid format
    if (h >= 0 && h <= 23 &&
        m >= 0 && m <= 59) {
      return {
        hours: h,
        minutes: m
      };
    }
    else {
      return false;
    }
  },

  validations: {
    enoughTimes: {
      acceptance: {
        message: Ember.I18n.t('create.options-datetime.error.notEnoughTimes')
      }
    }
  }
});<commit_msg>fix wrong action name<commit_after>export default Ember.ObjectController.extend(Ember.Validations.Mixin, {
  actions: {
    /*
     * copy first line
     */
    copyFirstLine: function(){
      var datetimes = this.get('datetimes'),
          firstLine = datetimes[0];

      datetimes.forEach(function(datetime, key) {
        // skip first element
        if (key > 0) {
          var newTimes = [];
          firstLine.contents.times.forEach(function(time){
            newTimes.pushObject({
              value: time.value
            });
          });

          datetime.set('contents.times', newTimes);
        }
      });
    },

    /*
     * increase number of inputs fields for time
     */
    moreTimes: function(){
      this.set('datetimesInputFields', this.get('datetimesInputFields') + 1);

      this.get('datetimes').forEach(function(datetime){
        datetime.contents.times.pushObject({
          value: ''
        });
      });

      // update polyfill used for legacy support of html5 input time after new form elements have been insert
      // has to wait after dom is updated
      Ember.run.next(this, function() { $('input[type=time]').updatePolyfill(); });
    },

    /*
     * set new options depending on selected times
     */
    submit: function(){
      var datetimes = this.get('datetimes'),
          newOptions = [],
          self = this;

      datetimes.forEach(function(datetime){
        datetime.contents.times.forEach(function(t){
          var date = new Date(datetime.contents.title),
              delimiter = '';

          // check if there is a value for time
          if (Ember.isEmpty(t.value)) {
            return;
          }

          // try to split time in minutes and hours
          var time = self.getHoursAndMinutesFromInput(t.value);

          // check time for valid format
          if (time !== false) {
            // hours and minutes seems valid, so update the date
            date.setHours(time.hours);
            date.setMinutes(time.minutes);

            newOptions.pushObject({
              title: date
            });
          }
        });
      });

      // check if we have at least 2 options now
      if (newOptions.length < 2) {
        return;
      }

      this.set('options', newOptions);

      // tricker save action
      this.send('save');
    },

    save: function(){
      // redirect to create/settings route
      this.transitionToRoute('create.settings');
    }
  },

  /*
   * only used on init, not on increasing number of input fields!
   */
  datetimes: function(key, value, previousValue){
    var datetimes = Ember.A(),
        dates = this.get('options'),
        datetimesCount = this.get('datetimesInputFields'),
        self = this;

    if (typeof dates !== 'undefined') {
      dates.forEach(function(date){
        var o = {
          title: date.title,
          times: Ember.A()
        };

        for(var i = 1; i<=datetimesCount; i++) {
          o.times.pushObject({
            value: ''
          });
        }

        datetimes.pushObject(self.get('datetimesTimesArray').create({'contents':o}));
      });
    }

    return datetimes;
  }.property('options'),

  /*
   * helper Object as work-a-round to observe a nested array
   */
  datetimesTimesArray: Ember.Object.extend({
    '@eachTimesValue': function(){
      var times = [];
      this.get('contents.times').forEach(function(value){
        times.push(value.value);
      });
      return times;
    }.property('contents.times.@each.value')
  }),

  enoughTimes: function(){
    var datetimes = this.get('datetimes'),
        self = this,
        isValid = true;

    datetimes.forEach(function(value, key){
      var times = self.get('datetimes.' + key + '.@eachTimesValue'),
          valid = false;

      times.forEach(function(time){
        if(self.getHoursAndMinutesFromInput(time) !== false){
          valid = true;
        }
      });

      if (valid === false) {
        isValid = false;
      }
    });

    return isValid;
  }.property('datetimes.@each.@eachTimesValue'),

  getHoursAndMinutesFromInput: function(time){
    // try to split time in minutes and hours
    var t;
    if (time.indexOf(':') !== -1) {
      t = time.split(':');
    }
    else {
      // time is not in a correct format
      return false;
    }

    if (t.length !== 2) {
      // time is not in a correct format
      return false;
    }

    // get hours and minutes
    var h = parseInt(t[0]),
        m = parseInt(t[1]);

    // check time for valid format
    if (h >= 0 && h <= 23 &&
        m >= 0 && m <= 59) {
      return {
        hours: h,
        minutes: m
      };
    }
    else {
      return false;
    }
  },

  validations: {
    enoughTimes: {
      acceptance: {
        message: Ember.I18n.t('create.options-datetime.error.notEnoughTimes')
      }
    }
  }
});<|endoftext|>