<commit_before>import {home, discussions, direct, getUserFeed, getUserComments, getUserLikes, getSinglePost, subscribers, subscriptions, getUserInfo} from './action-creators'

//query params are strings, so + hack to convert to number
const getOffset = nextRoute => +nextRoute.location.query.offset || 0

const getUserName = nextRoute => {
  return nextRoute.params.userName
}

export const routeActions = {
  'home': next => home(getOffset(next)),
  'discussions': next => discussions(getOffset(next)),
  'userFeed': next => getUserFeed(next.params.userName, getOffset(next)),
  'userComments': next => getUserComments(next.params.userName, getOffset(next)),
  'userLikes': next => getUserLikes(next.params.userName, getOffset(next)),
  'post': next => getSinglePost(next.params.postId),
  'direct': next => direct(getOffset(next)),
  'subscribers': next => subscribers(getUserName(next)),
  'subscriptions': next => subscriptions(getUserName(next)),
  'getUserInfo': next => getUserInfo(getUserName(next))
}

export const bindRouteActions = dispatch => route => next => {
  return dispatch(routeActions[route](next))
}
<commit_msg>Refactor route-actions.js<commit_after>import {
  // Private (content depends on current user)
  home,
  discussions,
  direct,

  // Public (content depends on URL params)
  getUserInfo,
  getUserFeed,
  getUserComments,
  getUserLikes,
  subscribers,
  subscriptions,
  getSinglePost
} from './action-creators'

//query params are strings, so + hack to convert to number
const getOffset = nextRoute => +nextRoute.location.query.offset || 0

const getUserName = nextRoute => {
  return nextRoute.params.userName
}

export const routeActions = {
  'home': next => home(getOffset(next)),
  'discussions': next => discussions(getOffset(next)),
  'direct': next => direct(getOffset(next)),

  'getUserInfo': next => getUserInfo(getUserName(next)),
  'userFeed': next => getUserFeed(next.params.userName, getOffset(next)),
  'userComments': next => getUserComments(next.params.userName, getOffset(next)),
  'userLikes': next => getUserLikes(next.params.userName, getOffset(next)),
  'subscribers': next => subscribers(getUserName(next)),
  'subscriptions': next => subscriptions(getUserName(next)),
  'post': next => getSinglePost(next.params.postId)
}

export const bindRouteActions = dispatch => route => next => {
  return dispatch(routeActions[route](next))
}
<|endoftext|>


<commit_before>function presentation_reload() {
    if ($('#config > #ajax').html() == 'on') {
        $.ajax({
            type: 'GET',
            url: '/projector/',
            dataType: 'json',
            data: '',
            success: function(data) {
                $('#currentTime').removeClass('ajax_error');
                $('#content').html(data.content);
                document.title = data.title;
                $('#currentTime').html(data.time);
                $('#content').clearQueue();
                $('#content').animate({'font-size': data.bigger + '%'}, 200);
                $('#content li').css({'font-size': data.bigger + '%'}, 200);
                $('#content #sidebar').css({'font-size': '16px'}, 0);
                $('#content').animate({'margin-top': data.up + 'em'}, 200);
                /*
                 * Gehe durch alle messages li durch. Wenn der Wert in der data steht, lasse es,
                 * ansonsten füge ein neues li ein und lösche es aus der data weg.
                 * Alles was jetzt noch in der data ist, muss als neues li eingefügt werden.
                 */

                //# $.each($('#messages li'), function (index, value) {
                    //# message_id = value.attr('id').split('_')[1];
                    //# if (message_id in data) {
                        //# this.html(data[message_id]);
                    //# }
                //# });
                $('#messages li').remove();
                $.each(data['messages'], function (index, value){
                    $('#messages ul').append('
' + value[1] + '
');
                });
                setTimeout("presentation_reload()", 500);
            },
            error: function () {
                $('#currentTime').addClass('ajax_error');
                setTimeout("presentation_reload()", 1000);
            }
        });
    }
}

function switchajax() {
    if ($('#config > #ajax').html() == 'on') {
        $('#config > #ajax').html('off');
        $('#ajaxswitcher').html('Ajax Anschalten');
    } else {
        $('#config > #ajax').html('on');
        $('#ajaxswitcher').html('Ajax Ausschalten');
    }
}

$(document).ready(function() {
    switchajax();
    switchajax();
    presentation_reload();
});

// *** Countdown variables and functions ***
var timer_value;
var timer_is_running=false;
var timer_is_visible=false;
var timerIntervalId;

function resetTimer(value) {
    stopTimer()
    timer_value = value;
    updateTimer();
}
function stopTimer() {
  timer_is_running = false;
  clearInterval(timerIntervalId);
}

function startTimer() {
  timer_is_running = true;
  if (timer_value > 0) {
    timerIntervalId = setInterval("decrementTimer()", 1000);
  }
}
function decrementTimer() {
  timer_value--;
  if (timer_value <= 0) {
    timer_value = 0;
    stopTimer();
  }
  updateTimer();
}
function convertSeconds(s) {
  var m = Math.floor(s / 60);
  s %= 60;
  var h = Math.floor(m / 60);
  m %= 60;
  return (h>0?h+':':'') + (h>0&&m<10?'0':'') + m + ':' + (s<10?'0':'') + s;
}

function updateTimer() {
  if (timer_value >= 0) {
    $("#countdown").html(convertSeconds(timer_value));
  }
}
<commit_msg>Automated merge with ssh://openslides.org/openslides<commit_after>function presentation_reload() {
    if ($('#config > #ajax').html() == 'on') {
        $.ajax({
            type: 'GET',
            url: '/projector/',
            dataType: 'json',
            data: '',
            success: function(data) {
                $('#currentTime').removeClass('ajax_error');
                $('#content').html(data.content);
                document.title = data.title;
                $('#currentTime').html(data.time);
                $('#content').clearQueue();
                $('#content').animate({'font-size': data.bigger + '%'}, 200);
                $('#content li').css({'font-size': data.bigger + '%'}, 200);
                $('#content #sidebar').css({'font-size': '16px'}, 0);
                $('#content').animate({'margin-top': data.up + 'em'}, 200);
                $('#messages li').remove();
                $.each(data['messages'], function (index, value){
                    $('#messages ul').append('
' + value[1] + '
');
                });
                setTimeout("presentation_reload()", 500);
            },
            error: function () {
                $('#currentTime').addClass('ajax_error');
                setTimeout("presentation_reload()", 1000);
            }
        });
    }
}

function switchajax() {
    if ($('#config > #ajax').html() == 'on') {
        $('#config > #ajax').html('off');
        $('#ajaxswitcher').html('Ajax Anschalten');
    } else {
        $('#config > #ajax').html('on');
        $('#ajaxswitcher').html('Ajax Ausschalten');
    }
}

$(document).ready(function() {
    switchajax();
    switchajax();
    presentation_reload();
});

// *** Countdown variables and functions ***
var timer_value;
var timer_is_running=false;
var timer_is_visible=false;
var timerIntervalId;

function resetTimer(value) {
    stopTimer()
    timer_value = value;
    updateTimer();
}
function stopTimer() {
  timer_is_running = false;
  clearInterval(timerIntervalId);
}

function startTimer() {
  timer_is_running = true;
  if (timer_value > 0) {
    timerIntervalId = setInterval("decrementTimer()", 1000);
  }
}
function decrementTimer() {
  timer_value--;
  if (timer_value <= 0) {
    timer_value = 0;
    stopTimer();
  }
  updateTimer();
}
function convertSeconds(s) {
  var m = Math.floor(s / 60);
  s %= 60;
  var h = Math.floor(m / 60);
  m %= 60;
  return (h>0?h+':':'') + (h>0&&m<10?'0':'') + m + ':' + (s<10?'0':'') + s;
}

function updateTimer() {
  if (timer_value >= 0) {
    $("#countdown").html(convertSeconds(timer_value));
  }
}
<|endoftext|>


<commit_before>const { TextDiff } = require('../../validators/text-diff');

const APIARY_STATUS_CODE_TYPE = 'text/vnd.apiary.status-code';

/**
 * Validates given real and expected status codes.
 * @param {Object} real
 * @param {number} expected
 */
function validateStatusCode(real, expected) {
  const validator = new TextDiff(real.statusCode, expected.statusCode);
  const rawData = validator.validate();
  const results = validator.evaluateOutputToResults();

  return {
    validator: 'TextDiff',
    realType: APIARY_STATUS_CODE_TYPE,
    expectedType: APIARY_STATUS_CODE_TYPE,
    rawData,
    results: results.map((result) =>
      Object.assign({}, result, {
        message:
          result.message === 'Real and expected data does not match.'
            ? `Status code is '${real.statusCode}' instead of '${
                expected.statusCode
              }'`
            : result.message
      })
    )
  };
}

module.exports = { validateStatusCode };
<commit_msg>feat: uses plain strings comparison for statusCode validation<commit_after>const APIARY_STATUS_CODE_TYPE = 'text/vnd.apiary.status-code';

/**
 * Validates given real and expected status codes.
 * @param {Object} real
 * @param {number} expected
 */
function validateStatusCode(real, expected) {
  const results = [];
  const isValid = real.statusCode === expected.statusCode;

  if (!isValid) {
    results.push({
      message: `Status code is '${real.statusCode}' instead of '${
        expected.statusCode
      }'`,
      severity: 'error'
    });
  }

  return {
    validator: 'TextDiff',
    realType: APIARY_STATUS_CODE_TYPE,
    expectedType: APIARY_STATUS_CODE_TYPE,
    rawData: '',
    results
  };
}

module.exports = { validateStatusCode };
<|endoftext|>


<commit_before>import sinon from 'sinon';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import Immutable from 'immutable';
import React from 'react';
import { Text, View, TouchableHighlight } from 'react-native';
import CounterComponent from '../../src/Framework/Counter/Counter.component';

const props = {
  counter: Immutable.Map({ counter: 1 }),
  increment: sinon.spy(),
  decrement: sinon.spy(),
  incrementIfOdd: sinon.spy(),
  incrementAsync: sinon.spy()
};

describe('components <CounterComponent />', function spec() {
  it('should render correctly', () => {
    setTimeout(() => {
      const wrapper = shallow(<CounterComponent {...props} />);
        expect(wrapper.find(View)).to.have.length(1);
        const view = wrapper.find(View);
        expect(view.find(Text)).to.have.length(5);
        expect(view.find(Text).node.props.children).to.eql(['Clicked: ', 1, ' times']);
        const touchs = view.find(TouchableHighlight);
        expect(touchs).to.have.length(4);
        ['+', '-', 'Increment if odd', 'Increment async'].forEach((text, i) => {
        expect(touchs.at(i).find(Text).node.props.children).to.equal(text);
      });

      ['increment', 'decrement', 'incrementIfOdd', 'incrementAsync']
        .forEach((func, i) => {
          it(`should call ${func} with TouchableHighlight on press`, () => {
            const wrapper = shallow(<CounterComponent {...props} />);
            wrapper.find(View).find(TouchableHighlight).nodes[i].props.onPress();
            expect(props[func].calledOnce).to.be.true;
          });
        });
    });
  }, 5000);
});
<commit_msg>Fix ESLint violations<commit_after>import sinon from 'sinon';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import Immutable from 'immutable';
import React from 'react';
import { Text, View, TouchableHighlight } from 'react-native';
import CounterComponent from '../../src/Framework/Counter/Counter.component';

const props = {
  counter: Immutable.Map({ counter: 1 }),
  increment: sinon.spy(),
  decrement: sinon.spy(),
  incrementIfOdd: sinon.spy(),
  incrementAsync: sinon.spy()
};

describe('components <CounterComponent />', () => {
  it('should render correctly', () => {
    setTimeout(() => {
      let wrapper = shallow(<CounterComponent {...props} />);
      expect(wrapper.find(View)).to.have.length(1);
      const view = wrapper.find(View);
      expect(view.find(Text)).to.have.length(5);
      expect(view.find(Text).node.props.children).to.eql(['Clicked: ', 1, ' times']);
      const touchs = view.find(TouchableHighlight);
      expect(touchs).to.have.length(4);
      ['+', '-', 'Increment if odd', 'Increment async'].forEach((text, i) => {
        expect(touchs.at(i).find(Text).node.props.children).to.equal(text);
      });

      ['increment', 'decrement', 'incrementIfOdd', 'incrementAsync']
        .forEach((func, i) => {
          it(`should call ${func} with TouchableHighlight on press`, () => {
            wrapper = shallow(<CounterComponent {...props} />);
            wrapper.find(View).find(TouchableHighlight).nodes[i].props.onPress();
            expect(props[func].calledOnce).to.be.true;
          });
        });
    });
  }, 5000);
});
<|endoftext|>


<commit_before>var GraphicLayerSwitcher = OpenLayers.Class(OpenLayers.Control, {
  layerStates: null,
  layersDiv: null,
  ascending: true,

  initialize: function(options) {
    OpenLayers.Control.prototype.initialize.apply(this, arguments);
    this.layerStates = [];
  },

  destroy: function() {
    OpenLayers.Event.stopObservingElement(this.div);

    //clear out layers info and unregister their events
    this.map.events.un({
      'addlayer': this.redraw,
      'changelayer': this.redraw,
      'removelayer': this.redraw,
      'changebaselayer': this.redraw,
      scope: this
    });
    OpenLayers.Control.prototype.destroy.apply(this, arguments);
  },

  setMap: function(map) {
    OpenLayers.Control.prototype.setMap.apply(this, arguments);

    this.map.events.on({
      'addlayer': this.redraw,
      'changelayer': this.redraw,
      'removelayer': this.redraw,
      'changebaselayer': this.redraw,
      scope: this
    });
  },

  draw: function() {
    OpenLayers.Control.prototype.draw.apply(this);
    this.loadContents();
    this.redraw();
    return this.div;
  },

  checkRedraw: function() {
    var redraw = false;
    if (!this.layerStates.length ||
        (this.map.layers.length != this.layerStates.length)) {
      redraw = true;
    } else {
      for (var i = 0, len = this.layerStates.length; i < len; i++) {
        var layerState = this.layerStates[i];
        var layer = this.map.layers[i];
        if ((layerState.name != layer.name) ||
            (layerState.inRange != layer.inRange) ||
            (layerState.id != layer.id)) {
          redraw = true;
          break;
        }
      }
    }
    return redraw;
  },

  redraw: function() {
    if (!this.checkRedraw()) {
      return this.div;
    }

    this.div.innerHTML = '';

    var len = this.map.layers.length;
    this.layerStates = [];
    for (var i = 0; i < this.map.layers.length; i++) {
      var layer = this.map.layers[i];
      this.layerStates[i] = {
        'name': layer.name,
        'visibility': layer.visibility,
        'inRange': layer.inRange,
        'id': layer.id
      };
    }

    var layers = this.map.layers.slice();

    var layer_switcher = $('

');
    var base_layers = $('
' +
        '
');
    var overlay_layers = $('

');

    var current = $(
        '' +
        '' +
        '');
    current.addClass('GraphicLayerSwitcher current');

    current.on('click touchend', function(e) {
      $(this).hide();
      $('.GraphicLayerSwitcher.box').show();
      e.stopPropagation();
    });

    $(this.div).append(current);

    if (!this.ascending) { layers.reverse(); }
    for (var i = 0; i < layers.length; i++) {
      var layer = layers[i];
      var baseLayer = layer.isBaseLayer;
      var id = this.id + '_input_' + layer.name.replace(/ /g, '_');

      if (layer.displayInLayerSwitcher) {
        // populate base layer box
        var on;
        if (baseLayer) on = (layer == this.map.baseLayer);
        else on = layer.getVisibility();

        var layer_image = '../../images/layers/' + layer.name +
            (on ? '.png' : '.bw.png');

        var item = $(
            "" +
            "" +
            layer.name +
            '
');

        if (on) {
          item.addClass('active');
        }

        item.on('click touchend', $.proxy(this.onInputClick,
            {'layerSwitcher': this, 'layer': layer}));

        if (baseLayer) {
          item.on('mouseover touchstart', $.proxy(function() {
            if (this.layer != this.map.baseLayer) {
              $('#' + this.id).find('img').attr('src',
                  '../../images/layers/' + this.layer.name + '.png');

              $('.GraphicLayerSwitcher.base .active').find('img').attr('src',
                  '../../images/layers/' + this.map.baseLayer.name + '.bw.png');
            }
          }, { id: id, layer: layer, map: this.map}));

          item.on('mouseout touchend', $.proxy(function() {
            if (this.layer != this.map.baseLayer) {
              $('#' + this.id).find('img').attr('src',
                  '../../images/layers/' + this.layer.name + '.bw.png');

              $('.GraphicLayerSwitcher.base .active').find('img').attr('src',
                  '../../images/layers/' + this.map.baseLayer.name + '.png');
            }
          }, { id: id, layer: layer, map: this.map }));

          base_layers.append(item);
        } else {
          overlay_layers.append(item);
        }

      }
    }

    // hide box when clicked outside
    $(document).on('mouseup touchend', function(e) {
      if (base_layers.find(e.target).length === 0 &&
          overlay_layers.find(e.target).length === 0) {
        $('.GraphicLayerSwitcher.box').hide();
        $('.GraphicLayerSwitcher.current').show();
        OpenLayers.Event.stop(e);
      }
    });

    // close selector box when inactive for 5 seconds
    var close_timeout = false;
    $(this.div).on('mousemove touchstart', function() {
      clearTimeout(close_timeout);
      close_timeout = setTimeout(function() {
        $('.GraphicLayerSwitcher.box').hide();
        $('.GraphicLayerSwitcher.current').show();
      }, 5000);
    });

    layer_switcher.append(base_layers);
    layer_switcher.append(overlay_layers);

    $(this.div).append(layer_switcher);

    // prevent mouse events bubbling throu the overlay
    base_layers.on('mouseup', $.proxy(this.mouseUp, this));
    base_layers.on('mousedown', $.proxy(this.mouseDown, this));

    overlay_layers.on('mouseup', $.proxy(this.mouseUp, this));
    overlay_layers.on('mousedown', $.proxy(this.mouseDown, this));

    return this.div;
  },

  updateLayerItems: function() {
    for (var i = 0; i < this.map.layers.length; i++) {
      var layer = this.map.layers[i];
      var baseLayer = layer.isBaseLayer;

      var id = this.id + '_input_' + layer.name.replace(/ /g, '_');

      if (layer.displayInLayerSwitcher) {
        // populate base layer box
        var on;
        if (baseLayer) on = (layer == this.map.baseLayer);
        else on = layer.getVisibility();

        var layer_image = '../../images/layers/' + layer.name +
            (on ? '.png' : '.bw.png');

        $('#' + id).find('img').attr('src', layer_image);

        if (on) {
          $('#' + id).addClass('active');
        } else {
          $('#' + id).removeClass('active');
        }
      }
    }
  },

  onInputClick: function(e) {
    if (this.layer.isBaseLayer) {
      this.layer.map.setBaseLayer(this.layer);
      $.cookie('base_layer', this.layer.name, { path: '/', expires: 365 });
    } else {
      this.layer.setVisibility(!this.layer.getVisibility());

      overlay_layers = [];
      for (var i = 0; i < this.layer.map.layers.length; ++i) {
        var layer = this.layer.map.layers[i];
        if (!layer.isBaseLayer && layer.visibility && layer.displayInLayerSwitcher)
          overlay_layers.push(layer.name);
      }
      $.cookie('overlay_layers', overlay_layers.join(';'), { path: '/', expires: 365 });
    }

    this.layerSwitcher.updateLayerItems();
    OpenLayers.Event.stop(e);
  },

  updateMap: function() {
    // set the newly selected base layer
    for (var i = 0, len = this.baseLayers.length; i < len; i++) {
      var layerEntry = this.baseLayers[i];
      if (layerEntry.inputElem.checked) {
        this.map.setBaseLayer(layerEntry.layer, false);
      }
    }

    // set the correct visibilities for the overlays
    for (var i = 0, len = this.dataLayers.length; i < len; i++) {
      var layerEntry = this.dataLayers[i];
      layerEntry.layer.setVisibility(layerEntry.inputElem.checked);
    }
  },

  loadContents: function() {
    OpenLayers.Event.observe(this.div, 'click',
        this.ignoreEvent);
    OpenLayers.Event.observe(this.div, 'dblclick', this.ignoreEvent);
  },

  ignoreEvent: function(evt) {
    OpenLayers.Event.stop(evt);
  },

  mouseDown: function(evt) {
    this.isMouseDown = true;
    this.ignoreEvent(evt);
  },

  mouseUp: function(evt) {
    if (this.isMouseDown) {
      this.isMouseDown = false;
      this.ignoreEvent(evt);
    }
  },

  CLASS_NAME: 'GraphicLayerSwitcher'
});

<commit_msg>GraphicLayerSwitcher: Fixed event propagation bug<commit_after>var GraphicLayerSwitcher = OpenLayers.Class(OpenLayers.Control, {
  layerStates: null,
  layersDiv: null,
  ascending: true,

  initialize: function(options) {
    OpenLayers.Control.prototype.initialize.apply(this, arguments);
    this.layerStates = [];
  },

  destroy: function() {
    OpenLayers.Event.stopObservingElement(this.div);

    //clear out layers info and unregister their events
    this.map.events.un({
      'addlayer': this.redraw,
      'changelayer': this.redraw,
      'removelayer': this.redraw,
      'changebaselayer': this.redraw,
      scope: this
    });
    OpenLayers.Control.prototype.destroy.apply(this, arguments);
  },

  setMap: function(map) {
    OpenLayers.Control.prototype.setMap.apply(this, arguments);

    this.map.events.on({
      'addlayer': this.redraw,
      'changelayer': this.redraw,
      'removelayer': this.redraw,
      'changebaselayer': this.redraw,
      scope: this
    });
  },

  draw: function() {
    OpenLayers.Control.prototype.draw.apply(this);
    this.loadContents();
    this.redraw();
    return this.div;
  },

  checkRedraw: function() {
    var redraw = false;
    if (!this.layerStates.length ||
        (this.map.layers.length != this.layerStates.length)) {
      redraw = true;
    } else {
      for (var i = 0, len = this.layerStates.length; i < len; i++) {
        var layerState = this.layerStates[i];
        var layer = this.map.layers[i];
        if ((layerState.name != layer.name) ||
            (layerState.inRange != layer.inRange) ||
            (layerState.id != layer.id)) {
          redraw = true;
          break;
        }
      }
    }
    return redraw;
  },

  redraw: function() {
    if (!this.checkRedraw()) {
      return this.div;
    }

    this.div.innerHTML = '';

    var len = this.map.layers.length;
    this.layerStates = [];
    for (var i = 0; i < this.map.layers.length; i++) {
      var layer = this.map.layers[i];
      this.layerStates[i] = {
        'name': layer.name,
        'visibility': layer.visibility,
        'inRange': layer.inRange,
        'id': layer.id
      };
    }

    var layers = this.map.layers.slice();

    var layer_switcher = $('

');
    var base_layers = $('
' +
        '
');
    var overlay_layers = $('

');

    var current = $(
        '' +
        '' +
        '');
    current.addClass('GraphicLayerSwitcher current');

    current.on('click touchend', function(e) {
      $(this).hide();
      $('.GraphicLayerSwitcher.box').show();
      e.stopPropagation();
    });

    $(this.div).append(current);

    if (!this.ascending) { layers.reverse(); }
    for (var i = 0; i < layers.length; i++) {
      var layer = layers[i];
      var baseLayer = layer.isBaseLayer;
      var id = this.id + '_input_' + layer.name.replace(/ /g, '_');

      if (layer.displayInLayerSwitcher) {
        // populate base layer box
        var on;
        if (baseLayer) on = (layer == this.map.baseLayer);
        else on = layer.getVisibility();

        var layer_image = '../../images/layers/' + layer.name +
            (on ? '.png' : '.bw.png');

        var item = $(
            "" +
            "" +
            layer.name +
            '
');

        if (on) {
          item.addClass('active');
        }

        item.on('click touchend', $.proxy(this.onInputClick,
            {'layerSwitcher': this, 'layer': layer}));

        if (baseLayer) {
          item.on('mouseover touchstart', $.proxy(function() {
            if (this.layer != this.map.baseLayer) {
              $('#' + this.id).find('img').attr('src',
                  '../../images/layers/' + this.layer.name + '.png');

              $('.GraphicLayerSwitcher.base .active').find('img').attr('src',
                  '../../images/layers/' + this.map.baseLayer.name + '.bw.png');
            }
          }, { id: id, layer: layer, map: this.map}));

          item.on('mouseout touchend', $.proxy(function() {
            if (this.layer != this.map.baseLayer) {
              $('#' + this.id).find('img').attr('src',
                  '../../images/layers/' + this.layer.name + '.bw.png');

              $('.GraphicLayerSwitcher.base .active').find('img').attr('src',
                  '../../images/layers/' + this.map.baseLayer.name + '.png');
            }
          }, { id: id, layer: layer, map: this.map }));

          base_layers.append(item);
        } else {
          overlay_layers.append(item);
        }

      }
    }

    // hide box when clicked outside
    $(document).on('mouseup touchend', function(e) {
      if (base_layers.find(e.target).length === 0 &&
          overlay_layers.find(e.target).length === 0) {
        $('.GraphicLayerSwitcher.box').hide();
        $('.GraphicLayerSwitcher.current').show();
      }
    });

    // close selector box when inactive for 5 seconds
    var close_timeout = false;
    $(this.div).on('mousemove touchstart', function() {
      clearTimeout(close_timeout);
      close_timeout = setTimeout(function() {
        $('.GraphicLayerSwitcher.box').hide();
        $('.GraphicLayerSwitcher.current').show();
      }, 5000);
    });

    layer_switcher.append(base_layers);
    layer_switcher.append(overlay_layers);

    $(this.div).append(layer_switcher);

    // prevent mouse events bubbling throu the overlay
    base_layers.on('mouseup', $.proxy(this.mouseUp, this));
    base_layers.on('mousedown', $.proxy(this.mouseDown, this));

    overlay_layers.on('mouseup', $.proxy(this.mouseUp, this));
    overlay_layers.on('mousedown', $.proxy(this.mouseDown, this));

    return this.div;
  },

  updateLayerItems: function() {
    for (var i = 0; i < this.map.layers.length; i++) {
      var layer = this.map.layers[i];
      var baseLayer = layer.isBaseLayer;

      var id = this.id + '_input_' + layer.name.replace(/ /g, '_');

      if (layer.displayInLayerSwitcher) {
        // populate base layer box
        var on;
        if (baseLayer) on = (layer == this.map.baseLayer);
        else on = layer.getVisibility();

        var layer_image = '../../images/layers/' + layer.name +
            (on ? '.png' : '.bw.png');

        $('#' + id).find('img').attr('src', layer_image);

        if (on) {
          $('#' + id).addClass('active');
        } else {
          $('#' + id).removeClass('active');
        }
      }
    }
  },

  onInputClick: function(e) {
    if (this.layer.isBaseLayer) {
      this.layer.map.setBaseLayer(this.layer);
      $.cookie('base_layer', this.layer.name, { path: '/', expires: 365 });
    } else {
      this.layer.setVisibility(!this.layer.getVisibility());

      overlay_layers = [];
      for (var i = 0; i < this.layer.map.layers.length; ++i) {
        var layer = this.layer.map.layers[i];
        if (!layer.isBaseLayer && layer.visibility && layer.displayInLayerSwitcher)
          overlay_layers.push(layer.name);
      }
      $.cookie('overlay_layers', overlay_layers.join(';'), { path: '/', expires: 365 });
    }

    this.layerSwitcher.updateLayerItems();
    OpenLayers.Event.stop(e);
  },

  updateMap: function() {
    // set the newly selected base layer
    for (var i = 0, len = this.baseLayers.length; i < len; i++) {
      var layerEntry = this.baseLayers[i];
      if (layerEntry.inputElem.checked) {
        this.map.setBaseLayer(layerEntry.layer, false);
      }
    }

    // set the correct visibilities for the overlays
    for (var i = 0, len = this.dataLayers.length; i < len; i++) {
      var layerEntry = this.dataLayers[i];
      layerEntry.layer.setVisibility(layerEntry.inputElem.checked);
    }
  },

  loadContents: function() {
    OpenLayers.Event.observe(this.div, 'click',
        this.ignoreEvent);
    OpenLayers.Event.observe(this.div, 'dblclick', this.ignoreEvent);
  },

  ignoreEvent: function(evt) {
    OpenLayers.Event.stop(evt);
  },

  mouseDown: function(evt) {
    this.isMouseDown = true;
    this.ignoreEvent(evt);
  },

  mouseUp: function(evt) {
    if (this.isMouseDown) {
      this.isMouseDown = false;
      this.ignoreEvent(evt);
    }
  },

  CLASS_NAME: 'GraphicLayerSwitcher'
});

<|endoftext|>


<commit_before>/*
  ======== A Handy Little Nodeunit Reference ========
  https://github.com/caolan/nodeunit

  Test methods:
    test.expect(numAssertions)
    test.done()
  Test assertions:
    test.ok(value, [message])
    test.equal(actual, expected, [message])
    test.notEqual(actual, expected, [message])
    test.deepEqual(actual, expected, [message])
    test.notDeepEqual(actual, expected, [message])
    test.strictEqual(actual, expected, [message])
    test.notStrictEqual(actual, expected, [message])
    test.throws(block, [error], [message])
    test.doesNotThrow(block, [error], [message])
    test.ifError(value)
*/
var connectionCommands = require('../lib/connectionCommands'),
    exports = module.exports,

exports.commands = {
  'simpleCommand': function(test) {
    var _log = console.log;

    console.log = function(chunk) {
      test.expect(1);
      test.equal(chunk, 'error', 'Error should be displayed');
      test.done();
    };

    connectionCallbacks.simpleCallback('error', '');
    console.log = _log;
  }
};
<commit_msg>added tests for commandExists function<commit_after>/*
  ======== A Handy Little Nodeunit Reference ========
  https://github.com/caolan/nodeunit

  Test methods:
    test.expect(numAssertions)
    test.done()
  Test assertions:
    test.ok(value, [message])
    test.equal(actual, expected, [message])
    test.notEqual(actual, expected, [message])
    test.deepEqual(actual, expected, [message])
    test.notDeepEqual(actual, expected, [message])
    test.strictEqual(actual, expected, [message])
    test.notStrictEqual(actual, expected, [message])
    test.throws(block, [error], [message])
    test.doesNotThrow(block, [error], [message])
    test.ifError(value)
*/
var connectionCommands = require('../lib/connectionCommands'),
    exports = module.exports;

exports.commands = {
  'commandExists': function(test) {
      test.expect(3);
      test.equal(
        connectionCommands.commandExists('version'),
        true,
        'Function "version" should exist'
      );

      test.equal(
        connectionCommands.commandExists('createAdmin'),
        true,
        'Function "createAdmin" should exist'
      );

      test.equal(
        connectionCommands.commandExists('deleteAdmin'),
        true,
        'Function "deleteAdmin" should exist'
      );

      test.done();
  }
};
<|endoftext|>


<commit_before>/**
 * Copyright 2020 Google LLC
 *
 * 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.
 */

const firebase = require('../../lib/firebase_handler.js').firebase;

// Firebase utility class for managing search queries for an agent
// (migrated from Datastore)
const firebaseUtil = {
  /**
   * Gets a mock search entry point based on the agentId.
   *
   * @param {string} agentId The agent id with the associated search query.
   * @param {function} callback Callback method for after
   * the method is complete.
   */
  getMock: (agentId, callback) => {
    // remove "brands/" from agent ID
    agentId = agentId.substring(agentId.lastIndexOf('/') + 1);
    const db = firebase.database();
    const agentRef = db.ref('admin/agentsMock').child(agentId);
    agentRef.once('value', (snapshot) => {
      const data = snapshot.val();
      if (data !== null && data !== undefined) {
        callback(data);
      } else {
        callback(false);
      }
    });
  },

  /**
   * Saves a new search query for an agent to the datastore.
   *
   * @param {string} searchText The search text.
   * @param {string} agentId The agent id.
   * @param {function} callback
   * Callback method for after the method is complete.
   */
  saveMock: (searchText, agentId, callback) => {
    if (searchText === '') {
      return;
    }
    // remove "brands/" from agent ID
    agentId = agentId.substring(agentId.lastIndexOf('/') + 1);
    // if existing search, then replace searchText with new searchText.
    const db = firebase.database();
    const agentRef = db.ref('admin/agentsMock').child(agentId);
    agentRef.transaction(
        (data) => {
          if (data) {
            data.searchText = searchText;
          } else {
            data = {
              agentId: agentId,
              searchText: searchText,
            };
          }
          return data;
        },
        () => {
          if (callback !== undefined) {
            callback();
          }
        },
    );
  },

  getBotInfo: function(fullAgentId, callback) {
    const db = firebase.database();
    const agentId = fullAgentId.substring(fullAgentId.lastIndexOf('/') + 1);
    const agentRef = db.ref('admin/agents').child(agentId);
    agentRef.once('value', (snapshot) => {
      const data = snapshot.val();
      callback(data);
    });
  },

  /**
   * Saves a new bot mapping for an agent to the datastore.
   *
   * @param {str} fullAgentId The brand/ID/agent/ID
   * @param {object} formObject The form key/value pairs
   * @param {function} callback
   * Callback method for after the method is complete.
   */
  saveBotInfo: (fullAgentId, formObject, callback) => {
    const dfProjectId = formObject.projectId;
    const dfServiceAccountKey = formObject.dfServiceAccountKey;

    // remove brands from agent ID
    const agentId = fullAgentId.substring(fullAgentId.lastIndexOf('/') + 1);
    let csatTriggerWindow = formObject.csatTriggerWindow;

    if (csatTriggerWindow.length == 0) {
      csatTriggerWindow = 0;
    }

    const db = firebase.database();
    const agentRef = db.ref('admin/agents').child(agentId);

    const botInfo = {
      dfServiceAccountKey: dfServiceAccountKey,
      agentId: fullAgentId,
      csatTriggerWindow: csatTriggerWindow,
      projectId: dfProjectId,
    };
    // update botInfo in database
    agentRef.set(botInfo, (err) => {
      if (err) {
        console.error(err);
      } else {
        if (callback) {
          callback();
        }
      }
    });
  },

  /**
   * getConversationsList - gets list of conversations associated with provider
   * @return {Array} List of conversations
   */
  getConversationsList: () => {
    return new Promise((resolve, reject) => {
      const db = firebase.database();
      const conversationsRef = db.ref(`conversations/`);
      conversationsRef.once('value', (snapshot) => {
        const data = snapshot.val();
        if (!data) {
          resolve(conversations);
        } else {
          // search for conversations within agent, appending to list of
          // conversations
          const conversations = [];
          const agentIds = Object.keys(data);
          for (let i = 0; i < agentIds.length; i++) {
            const agentId = agentIds[i];
            const convIds = Object.keys(data[agentId]);
            for (let j = 0; j < convIds.length; j++) {
              const id = convIds[j];
              conversations.push({
                conversationId: id,
                displayName: data[agentId][id].name,
                agentId: agentId,
              });
            }
          }
          resolve(conversations);
        }
      });
    });
  },
  /**
   * createMessageListener - Creates a message to listen for the latest live
   * agent messages and respond
   * @param {String} agentId The Agent ID
   * @param  {string} conversationId The Conversation ID
   * @param  {function} callback Callback to run with message details
   */
  createMessageListener: (agentId, conversationId, callback) => {
    const db = firebase.database();
    const conversationsRef = db
        .ref(`conversations/${agentId}/${conversationId}/messages`);
    conversationsRef.on('value', (snapshot) => {
      const data = snapshot.val();
      // find the message with the last timestamp
      if (data === undefined || data === null) {
        return;
      } else {
        // iterate through and find the latest timestamp key
        const newestKey = Object.keys(data).reduce((newestKey, key) => {
          if (data[key].timestamp > data[newestKey].timestamp) {
            return key;
          }
          return newestKey;
        });
        // run callback on new live agent message if not already sent
        if (!data[newestKey].sent) {
          callback(data[newestKey], newestKey);
        }
      }
    });
  },

  /**
   * setMessageSent - Update an agent message to be "sent"
   * @param {String} agentId The Agent ID
   * @param  {String} conversationId The conversation ID
   * @param  {String} messageId Message ID to set as read
   */
  setMessageSent: (agentId, conversationId, messageId) => {
    const db = firebase.database();
    const conversationsRef = db.ref(
        `conversations/${agentId}/${conversationId}/messages/${messageId}`,
    );
    conversationsRef.update({sent: true});
  },
};

module.exports = firebaseUtil;
<commit_msg>fixed spacing + added comment<commit_after>/**
 * Copyright 2020 Google LLC
 *
 * 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.
 */

const firebase = require('../../lib/firebase_handler.js').firebase;

// Firebase utility class for managing search queries for an agent
// (migrated from Datastore)
const firebaseUtil = {
  /**
   * Gets a mock search entry point based on the agentId.
   *
   * @param {string} agentId The agent id with the associated search query.
   * @param {function} callback Callback method for after
   * the method is complete.
   */
  getMock: (agentId, callback) => {
    // remove "brands/" from agent ID
    agentId = agentId.substring(agentId.lastIndexOf('/') + 1);
    const db = firebase.database();
    const agentRef = db.ref('admin/agentsMock').child(agentId);
    agentRef.once('value', (snapshot) => {
      const data = snapshot.val();
      if (data !== null && data !== undefined) {
        callback(data);
      } else {
        callback(false);
      }
    });
  },

  /**
   * Saves a new search query for an agent to the datastore.
   *
   * @param {string} searchText The search text.
   * @param {string} agentId The agent id.
   * @param {function} callback
   * Callback method for after the method is complete.
   */
  saveMock: (searchText, agentId, callback) => {
    if (searchText === '') {
      return;
    }
    // remove "brands/" from agent ID
    agentId = agentId.substring(agentId.lastIndexOf('/') + 1);
    // if existing search, then replace searchText with new searchText.
    const db = firebase.database();
    const agentRef = db.ref('admin/agentsMock').child(agentId);
    agentRef.transaction(
        (data) => {
          if (data) {
            data.searchText = searchText;
          } else {
            data = {
              agentId: agentId,
              searchText: searchText,
            };
          }
          return data;
        },
        () => {
          // on finish, run callback if present
          if (callback !== undefined) {
            callback();
          }
        },
    );
  },

  getBotInfo: function(fullAgentId, callback) {
    const db = firebase.database();
    const agentId = fullAgentId.substring(fullAgentId.lastIndexOf('/') + 1);
    const agentRef = db.ref('admin/agents').child(agentId);
    agentRef.once('value', (snapshot) => {
      const data = snapshot.val();
      callback(data);
    });
  },

  /**
   * Saves a new bot mapping for an agent to the datastore.
   *
   * @param {str} fullAgentId The brand/ID/agent/ID
   * @param {object} formObject The form key/value pairs
   * @param {function} callback
   * Callback method for after the method is complete.
   */
  saveBotInfo: (fullAgentId, formObject, callback) => {
    const dfProjectId = formObject.projectId;
    const dfServiceAccountKey = formObject.dfServiceAccountKey;

    // remove brands from agent ID
    const agentId = fullAgentId.substring(fullAgentId.lastIndexOf('/') + 1);
    let csatTriggerWindow = formObject.csatTriggerWindow;

    if (csatTriggerWindow.length == 0) {
      csatTriggerWindow = 0;
    }

    const db = firebase.database();
    const agentRef = db.ref('admin/agents').child(agentId);

    const botInfo = {
      dfServiceAccountKey: dfServiceAccountKey,
      agentId: fullAgentId,
      csatTriggerWindow: csatTriggerWindow,
      projectId: dfProjectId,
    };
    // update botInfo in database
    agentRef.set(botInfo, (err) => {
      if (err) {
        console.error(err);
      } else {
        if (callback) {
          callback();
        }
      }
    });
  },

  /**
   * getConversationsList - gets list of conversations associated with provider
   * @return {Array} List of conversations
   */
  getConversationsList: () => {
    return new Promise((resolve, reject) => {
      const db = firebase.database();
      const conversationsRef = db.ref(`conversations/`);
      conversationsRef.once('value', (snapshot) => {
        const data = snapshot.val();
        if (!data) {
          resolve(conversations);
        } else {
          // search for conversations within agent, appending to list of
          // conversations
          const conversations = [];
          const agentIds = Object.keys(data);
          for (let i = 0; i < agentIds.length; i++) {
            const agentId = agentIds[i];
            const convIds = Object.keys(data[agentId]);
            for (let j = 0; j < convIds.length; j++) {
              const id = convIds[j];
              conversations.push({
                conversationId: id,
                displayName: data[agentId][id].name,
                agentId: agentId,
              });
            }
          }
          resolve(conversations);
        }
      });
    });
  },

  /**
   * createMessageListener - Creates a message to listen for the latest live
   * agent messages and respond
   * @param {string} agentId The Agent ID
   * @param {string} conversationId The Conversation ID
   * @param {function} callback Callback to run with message details
   */
  createMessageListener: (agentId, conversationId, callback) => {
    const db = firebase.database();
    const conversationsRef = db
        .ref(`conversations/${agentId}/${conversationId}/messages`);
    conversationsRef.on('value', (snapshot) => {
      const data = snapshot.val();
      // find the message with the last timestamp
      if (data === undefined || data === null) {
        return;
      } else {
        // iterate through and find the latest timestamp key
        const newestKey = Object.keys(data).reduce((newestKey, key) => {
          if (data[key].timestamp > data[newestKey].timestamp) {
            return key;
          }
          return newestKey;
        });
        // run callback on new live agent message if not already sent
        if (!data[newestKey].sent) {
          callback(data[newestKey], newestKey);
        }
      }
    });
  },

  /**
   * setMessageSent - Update an agent message to be "sent"
   * @param {String} agentId The Agent ID
   * @param  {String} conversationId The conversation ID
   * @param  {String} messageId Message ID to set as read
   */
  setMessageSent: (agentId, conversationId, messageId) => {
    const db = firebase.database();
    const conversationsRef = db.ref(
        `conversations/${agentId}/${conversationId}/messages/${messageId}`,
    );
    conversationsRef.update({sent: true});
  },
};

module.exports = firebaseUtil;
<|endoftext|>


<commit_before>import React  from 'react'
import MapView from '../components/MapView'

export default class MapContainer extends React.Component {
  onChange (e) {
    let bounds = this.getBounds()
    bounds = [
      bounds._southWest.lat,
      bounds._southWest.lng,
      bounds._northEast.lat,
      bounds._northEast.lng,
    ]
    console.log(bounds)
    // dispatch(runCommand('get_photos_by_bounds', { bounds: bounds }))
  }

  render() {
    // Calculate the maximum boundary of the photo points
    let top = null
    let bottom = null
    let left = null
    let right = null

    if (this.props.photos) {
      this.props.photos.map((photo) => {
        if (photo.location) {
          if (!top || photo.location[0] > top) {
            top = parseFloat(photo.location[0])
          }
          if (!bottom || photo.location[0] < bottom) {
            bottom = parseFloat(photo.location[0])
          }
          if (!left || photo.location[1] < left) {
            left = parseFloat(photo.location[1])
          }
          if (!right || photo.location[1] > right) {
            right = parseFloat(photo.location[1])
          }
        }
        return true
      })

      // Default to show the whole world if none of the current photos have locations
      let bounds = [['-45', '-1'], ['45', '1']]
      if (top && bottom && left && right) {
        bounds = [[bottom.toFixed(8), left.toFixed(8)], [top.toFixed(8), right.toFixed(8)]]
      }

      return <MapView photos={this.props.photos} bounds={bounds} hideAttribution={this.props.hideAttribution} />
    }

    if (this.props.location) {
      return <MapView location={this.props.location} zoom={this.props.zoom} hideAttribution={this.props.hideAttribution} />
    }
  }
}
<commit_msg>Removing back obsolete file<commit_after><|endoftext|>


<commit_before>/*global define*/
/*jslint white:true,browser:true*/
define([
    'bluebird',
    'jquery',
    'base/js/namespace',
    'kb_common/html',
    '../../validation',
    '../../events',
    'bootstrap',
    'css!font-awesome'
], function (Promise, $, Jupyter, html, Validation, Events) {
    'use strict';

    // Constants
    var t = html.tag,
        div = t('div'), input = t('input'), span = t('span'), button = t('button');

    function factory(config) {
        var options = {},
            spec = config.parameterSpec,
            parent,
            container,
            $container,
            bus = config.bus,
            model = {
                value: undefined
            };

        // Validate configuration.
        // Nothing to do...

        options.environment = config.isInSidePanel ? 'sidePanel' : 'standard';
        options.multiple = spec.multipleItems();
        options.required = spec.required();
        options.enabled = true;

        /*
         * If the parameter is optional, and is empty, return null.
         * If it allows multiple values, wrap single results in an array
         * There is a weird twist where if it ...
         * well, hmm, the only consumer of this, isValid, expects the values
         * to mirror the input rows, so we shouldn't really filter out any
         * values.
         */

        function getInputValue() {
            return $container.find('[data-element="input-container"] [data-element="input"]').val();
        }

        function setModelValue(value) {
            return Promise.try(function () {
                if (model.value !== value) {
                    model.value = value;
                    return true;
                }
                return false;
            })
                .then(function (changed) {
                    render();
                });
        }

        function unsetModelValue() {
            return Promise.try(function () {
                model.value = undefined;
            })
                .then(function (changed) {
                    render();
                });
        }

        function resetModelValue() {
            if (spec.spec.default_values && spec.spec.default_values.length > 0) {
                setModelValue(spec.spec.default_values[0]);
            } else {
                unsetModelValue();
            }
        }

        /*
         *
         * Text fields can occur in multiples.
         * We have a choice, treat single-text fields as a own widget
         * or as a special case of multiple-entry --
         * with a min-items of 1 and max-items of 1.
         *
         *
         */

        function validate() {
            return Promise.try(function () {
                if (!options.enabled) {
                    return {
                        isValid: true,
                        validated: false,
                        diagnosis: 'disabled'
                    };
                }

                var rawValue = getInputValue(),
                    validationResult = Validation.validateText(rawValue, {
                        required: options.required
                    });

                return {
                    isValid: validationResult.isValid,
                    validated: true,
                    diagnosis: validationResult.diagnosis,
                    errorMessage: validationResult.errorMessage,
                    value: validationResult.parsedValue
                };
            });
        }

        /*
         * Creates the markup
         * Places it into the dom node
         * Hooks up event listeners
         */
        function makeInputControl(currentValue, events, bus) {
            // CONTROL
            return input({
                id: events.addEvents({
                    events: [
                        {
                            type: 'change',
                            handler: function (e) {
                                validate()
                                    .then(function (result) {
                                        if (result.isValid) {
                                            bus.send({
                                                type: 'changed',
                                                newValue: result.value
                                            });
                                        } else if (result.diagnosis === 'required-missing') {
                                    bus.send({
                                        type: 'changed',
                                        newValue: result.value
                                    });
                                }
                                        setModelValue(result.value);
                                        bus.send({
                                            type: 'validation',
                                            errorMessage: result.errorMessage,
                                            diagnosis: result.diagnosis
                                        });
                                    });
                            }
                        },
                        {
                            type: 'focus',
                            handler: function (e) {
                                Jupyter.keyboard_manager.disable();
                            }
                        },
                        {
                            type: 'blur',
                            handler: function (e) {
                                Jupyter.keyboard_manager.enable();
                            }
                        }
                    ]}),
                class: 'form-control',
                dataElement: 'input',
                value: currentValue
            });
        }

        function render() {
            Promise.try(function () {
                var events = Events.make(),
                    inputControl = makeInputControl(model.value, events, bus);

                $container.find('[data-element="input-container"]').html(inputControl);
                events.attachEvents(container);
            })
                .then(function () {
                    return autoValidate();
                });
        }

        function layout(events) {
            var content = div({
                dataElement: 'main-panel'
            }, [
                div({dataElement: 'input-container'})
            ]);
            return {
                content: content,
                events: events
            };
        }

        function autoValidate() {
            return validate()
                .then(function (result) {
                    bus.send({
                        type: 'validation',
                        errorMessage: result.errorMessage,
                        diagnosis: result.diagnosis
                    });
                });
        }

        // LIFECYCLE API

        function init() {
        }

        function attach(node) {
            return Promise.try(function () {
                parent = node;
                container = node.appendChild(document.createElement('div'));
                $container = $(container);

                var events = Events.make(),
                    theLayout = layout(events);

                container.innerHTML = theLayout.content;
                events.attachEvents(container);
            });
        }

         function start() {
            return Promise.try(function () {
                bus.on('reset-to-defaults', function (message) {
                    resetModelValue();
                });
                bus.on('update', function (message) {
                    setModelValue(message.value);
                });
                bus.send({type: 'sync'});
                return null;
            });
        }

        function run(params) {
            return Promise.try(function () {
                return setModelValue(params.value);
            });
        }

        return {
            init: init,
            attach: attach,
            start: start,
            run: run
        };
    }

    return {
        make: function (config) {
            return factory(config);
        }
    };
});<commit_msg>first attempt at auto saving fields<commit_after>/*global define*/
/*jslint white:true,browser:true*/
define([
    'bluebird',
    'jquery',
    'base/js/namespace',
    'kb_common/html',
    '../../validation',
    '../../events',
    'bootstrap',
    'css!font-awesome'
], function (Promise, $, Jupyter, html, Validation, Events) {
    'use strict';

    // Constants
    var t = html.tag,
        div = t('div'), input = t('input'), span = t('span'), button = t('button');

    function factory(config) {
        var options = {},
            spec = config.parameterSpec,
            parent,
            container,
            $container,
            bus = config.bus,
            model = {
                value: undefined
            };

        // Validate configuration.
        // Nothing to do...

        options.environment = config.isInSidePanel ? 'sidePanel' : 'standard';
        options.multiple = spec.multipleItems();
        options.required = spec.required();
        options.enabled = true;

        /*
         * If the parameter is optional, and is empty, return null.
         * If it allows multiple values, wrap single results in an array
         * There is a weird twist where if it ...
         * well, hmm, the only consumer of this, isValid, expects the values
         * to mirror the input rows, so we shouldn't really filter out any
         * values.
         */

        function getInputValue() {
            return $container.find('[data-element="input-container"] [data-element="input"]').val();
        }

        function setModelValue(value) {
            return Promise.try(function () {
                if (model.value !== value) {
                    model.value = value;
                    return true;
                }
                return false;
            })
                .then(function (changed) {
                    render();
                });
        }

        function unsetModelValue() {
            return Promise.try(function () {
                model.value = undefined;
            })
                .then(function (changed) {
                    render();
                });
        }

        function resetModelValue() {
            if (spec.spec.default_values && spec.spec.default_values.length > 0) {
                setModelValue(spec.spec.default_values[0]);
            } else {
                unsetModelValue();
            }
        }

        /*
         *
         * Text fields can occur in multiples.
         * We have a choice, treat single-text fields as a own widget
         * or as a special case of multiple-entry --
         * with a min-items of 1 and max-items of 1.
         *
         *
         */

        function validate() {
            return Promise.try(function () {
                if (!options.enabled) {
                    return {
                        isValid: true,
                        validated: false,
                        diagnosis: 'disabled'
                    };
                }

                var rawValue = getInputValue(),
                    validationResult = Validation.validateText(rawValue, {
                        required: options.required
                    });

                return {
                    isValid: validationResult.isValid,
                    validated: true,
                    diagnosis: validationResult.diagnosis,
                    errorMessage: validationResult.errorMessage,
                    value: validationResult.parsedValue
                };
            });
        }

        /*
         * Creates the markup
         * Places it into the dom node
         * Hooks up event listeners
         */
        function makeInputControl(currentValue, events, bus) {
            // CONTROL
            var editPauseTime = 0,
                editPauseTimer,
                editPauseInterval = 2000;
            return input({
                id: events.addEvents({
                    events: [
                        {
                            type: 'change',
                            handler: function (e) {
                                validate()
                                    .then(function (result) {
                                        if (result.isValid) {
                                            bus.send({
                                                type: 'changed',
                                                newValue: result.value
                                            });
                                        } else if (result.diagnosis === 'required-missing') {
                                    bus.send({
                                        type: 'changed',
                                        newValue: result.value
                                    });
                                }
                                        setModelValue(result.value);
                                        bus.send({
                                            type: 'validation',
                                            errorMessage: result.errorMessage,
                                            diagnosis: result.diagnosis
                                        });
                                    });
                            }
                        },
                        {
                            type: 'keyup',
                            handler: function (e) {
                                editPauseTime = new Date().getTime();
                                if (editPauseTimer) {
                                    window.clearTimeout(editPauseTimer);
                                }
                                editPauseTimer = window.setTimeout(function () {
                                    var now = new Date().getTime();
                                    if ((now - editPauseTime) > editPauseInterval) {
                                        editPauseTimer = null;
                                        e.target.dispatchEvent(new Event('change'));
                                    }
                                }, 2500);
                            }
                        },
                        {
                            type: 'focus',
                            handler: function (e) {
                                Jupyter.keyboard_manager.disable();
                            }
                        },
                        {
                            type: 'blur',
                            handler: function (e) {
                                Jupyter.keyboard_manager.enable();
                            }
                        }
                    ]}),
                class: 'form-control',
                dataElement: 'input',
                value: currentValue
            });
        }

        function render() {
            Promise.try(function () {
                var events = Events.make(),
                    inputControl = makeInputControl(model.value, events, bus);

                $container.find('[data-element="input-container"]').html(inputControl);
                events.attachEvents(container);
            })
                .then(function () {
                    return autoValidate();
                });
        }

        function layout(events) {
            var content = div({
                dataElement: 'main-panel'
            }, [
                div({dataElement: 'input-container'})
            ]);
            return {
                content: content,
                events: events
            };
        }

        function autoValidate() {
            return validate()
                .then(function (result) {
                    bus.send({
                        type: 'validation',
                        errorMessage: result.errorMessage,
                        diagnosis: result.diagnosis
                    });
                });
        }

        // LIFECYCLE API

        function init() {
        }

        function attach(node) {
            return Promise.try(function () {
                parent = node;
                container = node.appendChild(document.createElement('div'));
                $container = $(container);

                var events = Events.make(),
                    theLayout = layout(events);

                container.innerHTML = theLayout.content;
                events.attachEvents(container);
            });
        }

         function start() {
            return Promise.try(function () {
                bus.on('reset-to-defaults', function (message) {
                    resetModelValue();
                });
                bus.on('update', function (message) {
                    setModelValue(message.value);
                });
                bus.send({type: 'sync'});
                return null;
            });
        }

        function run(params) {
            return Promise.try(function () {
                return setModelValue(params.value);
            });
        }

        return {
            init: init,
            attach: attach,
            start: start,
            run: run
        };
    }

    return {
        make: function (config) {
            return factory(config);
        }
    };
});<|endoftext|>


<commit_before>import React from 'react';
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
import AsyncRenderer from '../components/AsyncRenderer';
import removeDuplicateModules from '../utils/removeDuplicateModules';

const renderPass = (context, element, staticMarkup = false) => {
  context.callback = () => {
    if (context.finishedLoadingModules && !context.statesRenderPass) {
      context.statesRenderPass = true;
      context.renderResult = renderPass(context, element, staticMarkup);
      if (context.fetchingStates <= 0 && context.modulesLoading <= 0) {
        context.resolve({
          html: context.renderResult,
          state: context.fetchStateResults === undefined ? null : context.fetchStateResults,
          modules: context.modules === undefined ? null : removeDuplicateModules(context.modules)
        });
      }
    } else if (context.finishedLoadingModules && context.statesRenderPass || !context.hasModules) {
      context.renderResult = renderPass(context, element, staticMarkup);
      if (context.fetchingStates <= 0 && context.modulesLoading <= 0) {
        context.resolve({
          html: context.renderResult,
          state: context.fetchStateResults === undefined ? null : context.fetchStateResults,
          modules: context.modules === undefined ? null : removeDuplicateModules(context.modules)
        });
      }
    }
  };

  let component = (
    <AsyncRenderer context={context}>
      {element}
    </AsyncRenderer>
  )
  let result;
  try {
    if (staticMarkup) {
      result = renderToStaticMarkup(component);
    } else {
      result = renderToString(component );
    }
  } catch (e) {
    return context.reject(e);
  }

  if (!context.hasModules && !context.hasStates) {
    context.resolve({
      html: result,
      state: context.fetchStateResults === undefined ? null : context.fetchStateResults,
      modules: context.modules === undefined ? null : removeDuplicateModules(context.modules)
    });
  }
  return result;
};

export default renderPass;
<commit_msg>Fixed code styling<commit_after>import React from 'react';
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
import AsyncRenderer from '../components/AsyncRenderer';
import removeDuplicateModules from '../utils/removeDuplicateModules';

const renderPass = (context, element, staticMarkup = false) => {
  context.callback = () => {
    if (context.finishedLoadingModules && !context.statesRenderPass) {
      context.statesRenderPass = true;
      context.renderResult = renderPass(context, element, staticMarkup);
      if (context.fetchingStates <= 0 && context.modulesLoading <= 0) {
        context.resolve({
          html: context.renderResult,
          state: context.fetchStateResults === undefined ? null : context.fetchStateResults,
          modules: context.modules === undefined ? null : removeDuplicateModules(context.modules)
        });
      }
    } else if (context.finishedLoadingModules && context.statesRenderPass || !context.hasModules) {
      context.renderResult = renderPass(context, element, staticMarkup);
      if (context.fetchingStates <= 0 && context.modulesLoading <= 0) {
        context.resolve({
          html: context.renderResult,
          state: context.fetchStateResults === undefined ? null : context.fetchStateResults,
          modules: context.modules === undefined ? null : removeDuplicateModules(context.modules)
        });
      }
    }
  };

  let component = (
    <AsyncRenderer context={context}>
      {element}
    </AsyncRenderer>
  );

  let result;
  try {
    if (staticMarkup) {
      result = renderToStaticMarkup(component);
    } else {
      result = renderToString(component);
    }
  } catch (e) {
    return context.reject(e);
  }

  if (!context.hasModules && !context.hasStates) {
    context.resolve({
      html: result,
      state: context.fetchStateResults === undefined ? null : context.fetchStateResults,
      modules: context.modules === undefined ? null : removeDuplicateModules(context.modules)
    });
  }
  return result;
};

export default renderPass;
<|endoftext|>


<commit_before>var lifx = require('../../lifx');
var util = require('util');
var mqtt = require('mqtt');

var broker = 'localhost';
var lx = lifx.init();

console.log("Searching for a LIFX gateway...");
console.log('');
console.log('=== Instructions ===');
console.log('Publish JSON to one of the following topics:');
console.log('  /lifx/bulbcmd/<lifxAddress>/colour : {"hue":<hue>,"saturation":<sat>,"luminance":<lum>,"colourTemp":<whiteCol>}');
console.log('  /lifx/bulbcmd/<lifxAddress>/on : {"on":<boolean>}');
console.log('(where hue/sat/lum/whiteCol are 16-bit integers)');
console.log('');
console.log('or subscribe to one of the following topics:');
console.log('  /lifx/newbulb : gets notified when a new bulb is found');
console.log('  /lifx/bulb/<lifxAddress> : gets messages whenever the bulb state changes (will likely get duplicates)');
console.log('');

var mqttClient = mqtt.createClient(1883, broker);

lx.on('gateway', function(g) {
	mqttClient.publish('/lifx/gateway', JSON.stringify({ipAddress:g.ipAddress, lifxAddress:g.lifxAddress.toString('hex')}));
});
lx.on('bulb', function(b) {
	mqttClient.publish('/lifx/newbulb', JSON.stringify({bulb:b,mqttTopicBase:"/lifx/bulbcmd/"+b.lifxAddress.toString('hex')}));
});
lx.on('bulbstate', function(s) {
	mqttClient.publish('/lifx/bulb/'+s.bulb.lifxAddress.toString('hex'), JSON.stringify(s));
});
lx.on('bulbonoff', function(s) {
	mqttClient.publish('/lifx/bulb/'+s.bulb.lifxAddress.toString('hex'), JSON.stringify({on:s.on}));
});

mqttClient.subscribe('/lifx/bulbcmd/#');
mqttClient.on('message', function(topic, message) {
	console.log(topic + " " + message);
	if (matches = topic.match(/bulbcmd\/([0-9a-f]{12})\/([a-z]*)$/)) {
		var lifxAddress = matches[1];
		var cmd = matches[2];
		try{
			var params = JSON.parse(message);
		} catch (e) {
			console.log("Could not parse JSON message: " + message);
		}
                // Find bulb
                var bulb = null;
                for (var b in lx.bulbs) {
                    if (lx.bulbs[b].lifxAddress.toString("hex") == lifxAddress) {
                        bulb = lx.bulbs[b];
                    }
                }
                if (!bulb) {
                    console.log("Bulb " + lifxAddress + " not found");
                    return;
                }
		switch (cmd) {

			case "colour":
				if (
					typeof params.hue == 'undefined'
					|| typeof params.saturation == 'undefined'
					|| typeof params.luminance == 'undefined'
					|| typeof params.colourTemp == 'undefined'
				) {
					console.log("Incomplete message; expecting all of hue/saturation/luminance/colourTemp in message " + message);
				} else {
					lx.lightsColour(params.hue, params.saturation, params.luminance, params.colourTemp, 0, lifxAddress);
				}
				break;

			case "on":
			case "off":
				if (typeof params.on != 'undefined') {
					if (params.on) {
						lx.lightsOn(bulb);
					} else {
						lx.lightsOff(bulb);
					}
				} else if (typeof params.off != 'undefined') {
					if (params.off) {
						lx.lightsOff(bulb);
					} else {
						lx.lightsOn(bulb);
					}
				} else {
					console.log("Incomplete message; expecting one of on/off in message " + message);
				}
				break;
		}
	}
	if (matches = topic.match(/bulbcmd\/all\/([a-z]*)$/)) {
		var cmd = matches[1];
		try{
			var params = JSON.parse(message);
		} catch (e) {
			console.log("Could not parse JSON message: " + message);
		}
		switch (cmd) {

			case "colour":
				if (
					typeof params.hue == 'undefined'
					|| typeof params.saturation == 'undefined'
					|| typeof params.luminance == 'undefined'
					|| typeof params.colourTemp == 'undefined'
				) {
					console.log("Incomplete message; expecting all of hue/saturation/luminance/colourTemp in message " + message);
				} else {
					lx.lightsColour(params.hue, params.saturation, params.luminance, params.colourTemp, 0);
				}
				break;

			case "on":
			case "off":
				if (typeof params.on != 'undefined') {
					if (params.on) {
						lx.lightsOn();
					} else {
						lx.lightsOff();
					}
				} else if (typeof params.off != 'undefined') {
					if (params.off) {
						lx.lightsOff();
					} else {
						lx.lightsOn();
					}
				} else {
					console.log("Incomplete message; expecting one of on/off in message " + message);
				}
				break;
		}
	}
});

<commit_msg>Updated MQTT bridge to use newer interface<commit_after>var lifx = require('../../lifx');
var util = require('util');
var mqtt = require('mqtt');

var broker = '10.1.0.1';
var lx = lifx.init();

console.log("Searching for a LIFX gateway...");
console.log('');
console.log('=== Instructions ===');
console.log('Publish JSON to one of the following topics:');
console.log('  /lifx/bulbcmd/<lifxAddress>/colour : {"hue":<hue>,"saturation":<sat>,"luminance":<lum>,"colourTemp":<whiteCol>}');
console.log('  /lifx/bulbcmd/<lifxAddress>/on : {"on":<boolean>}');
console.log('(where hue/sat/lum/whiteCol are 16-bit integers)');
console.log('');
console.log('or subscribe to one of the following topics:');
console.log('  /lifx/newbulb : gets notified when a new bulb is found');
console.log('  /lifx/bulb/<lifxAddress> : gets messages whenever the bulb state changes (will likely get duplicates)');
console.log('');

var mqttClient = mqtt.createClient(1883, broker);

lx.on('gateway', function(g) {
	mqttClient.publish('/lifx/gateway', JSON.stringify({ip:g.ip}));
});
lx.on('bulb', function(b) {
	mqttClient.publish('/lifx/newbulb', JSON.stringify({bulb:b,mqttTopicBase:"/lifx/bulbcmd/"+b.addr.toString('hex')}));
});
lx.on('bulbstate', function(bulb) {
	mqttClient.publish('/lifx/bulb/'+bulb.addr.toString('hex'), JSON.stringify(bulb));
});
lx.on('bulbonoff', function(bulb) {
	mqttClient.publish('/lifx/bulb/'+bulb.addr.toString('hex'), JSON.stringify({on:s.on}));
});

mqttClient.subscribe('/lifx/bulbcmd/#');
mqttClient.on('message', function(topic, message) {
	console.log(topic + " " + message);
	if (matches = topic.match(/bulbcmd\/([0-9a-f]{12})\/([a-z]*)$/)) {
		var lifxAddress = matches[1];
		var cmd = matches[2];
		try{
			var params = JSON.parse(message);
		} catch (e) {
			console.log("Could not parse JSON message: " + message);
		}
                // Find bulb
                var bulb = null;
                for (var b in lx.bulbs) {
                    if (lx.bulbs[b].addr.toString("hex") == lifxAddress) {
                        bulb = lx.bulbs[b];
                    }
                }
                if (!bulb) {
                    console.log("Bulb " + lifxAddress + " not found");
                    return;
                }
		switch (cmd) {

			case "colour":
				if (
					typeof params.hue == 'undefined'
					|| typeof params.saturation == 'undefined'
					|| typeof params.luminance == 'undefined'
					|| typeof params.colourTemp == 'undefined'
				) {
					console.log("Incomplete message; expecting all of hue/saturation/luminance/colourTemp in message " + message);
				} else {
					lx.lightsColour(params.hue, params.saturation, params.luminance, params.colourTemp, 0, lifxAddress);
				}
				break;

			case "on":
			case "off":
				if (typeof params.on != 'undefined') {
					if (params.on) {
						lx.lightsOn(bulb);
					} else {
						lx.lightsOff(bulb);
					}
				} else if (typeof params.off != 'undefined') {
					if (params.off) {
						lx.lightsOff(bulb);
					} else {
						lx.lightsOn(bulb);
					}
				} else {
					console.log("Incomplete message; expecting one of on/off in message " + message);
				}
				break;
		}
	}
	if (matches = topic.match(/bulbcmd\/all\/([a-z]*)$/)) {
		var cmd = matches[1];
		try{
			var params = JSON.parse(message);
		} catch (e) {
			console.log("Could not parse JSON message: " + message);
		}
		switch (cmd) {

			case "colour":
				if (
					typeof params.hue == 'undefined'
					|| typeof params.saturation == 'undefined'
					|| typeof params.luminance == 'undefined'
					|| typeof params.colourTemp == 'undefined'
				) {
					console.log("Incomplete message; expecting all of hue/saturation/luminance/colourTemp in message " + message);
				} else {
					lx.lightsColour(params.hue, params.saturation, params.luminance, params.colourTemp, 0);
				}
				break;

			case "on":
			case "off":
				if (typeof params.on != 'undefined') {
					if (params.on) {
						lx.lightsOn();
					} else {
						lx.lightsOff();
					}
				} else if (typeof params.off != 'undefined') {
					if (params.off) {
						lx.lightsOff();
					} else {
						lx.lightsOn();
					}
				} else {
					console.log("Incomplete message; expecting one of on/off in message " + message);
				}
				break;
		}
	}
});

<|endoftext|>


<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2015, Joyent, Inc.
 */

/*
 * Integration tests for `docker search`
 */

var h = require('./helpers');
var test = require('tape');

// --- Globals

var log = require('../lib/log');
var state = {
    log: log
};
var alice;

// --- Tests

test('docker search', function (tt) {

    tt.test(' setup', function (t) {
        h.getDockerEnv(t, state, {account: 'sdcdockertest_alice'},
                function (err, env) {
            t.ifErr(err);
            t.ok(env, 'have a DockerEnv for alice');
            alice = env;
            t.end();
        });
    });

    tt.test(' docker search busybox', function (t) {
        alice.docker('search busybox', function (err, stdout, stderr) {
            t.ifErr(err);
            t.ok(/^busybox /m.test(stdout), 'official busybox image');
            t.end();
        });
    });

    tt.test(' docker search quay.io/quay/elasticsearch', function (t) {
        alice.docker('search quay.io/quay/elasticsearch',
                function (err, stdout, stderr) {
            t.ifErr(err);
            t.ok(/^quay\/elasticsearch /m.test(stdout),
                'quay user elasticsearch');
            t.end();
        });
    });

    /*
     * This should fail, we don't expect to have any.
     *
     * It would be nice to fail quickly. E.g. on Docker-docker:
     *
     *  $ time docker search localhost:4321/foo
     *  FATA[0000] Error response from daemon: v1 \
     *    ping attempt failed with error: Get \
     *    http://localhost:4321/v1/_ping: dial tcp 127.0.0.1:5000: \
     *    connection refused
     *
     *  real    0m0.192s
     *  user    0m0.150s
     *  sys     0m0.005s
     *
     * However, sdc-docker currently takes ~15s to fail here.
     */
    tt.test(' docker search localhost:4321/foo', function (t) {
        alice.docker('search localhost:4321/foo',
                function (err, stdout, stderr) {
            t.ok(err);
            t.end();
        });
    });

});
<commit_msg>DOCKER-604: test suite fails on 'docker search quay.io/...' because quay.io is broken<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2015, Joyent, Inc.
 */

/*
 * Integration tests for `docker search`
 */

var h = require('./helpers');
var test = require('tape');

// --- Globals

var log = require('../lib/log');
var state = {
    log: log
};
var alice;

// --- Tests

test('docker search', function (tt) {

    tt.test(' setup', function (t) {
        h.getDockerEnv(t, state, {account: 'sdcdockertest_alice'},
                function (err, env) {
            t.ifErr(err);
            t.ok(env, 'have a DockerEnv for alice');
            alice = env;
            t.end();
        });
    });

    tt.test(' docker search busybox', function (t) {
        alice.docker('search busybox', function (err, stdout, stderr) {
            t.ifErr(err);
            t.ok(/^busybox /m.test(stdout), 'official busybox image');
            t.end();
        });
    });

    // DOCKER-604 skip this test for now, quay.io search is busted.
    tt.skip(' docker search quay.io/quay/elasticsearch', function (t) {
        alice.docker('search quay.io/quay/elasticsearch',
                function (err, stdout, stderr) {
            t.ifErr(err);
            t.ok(/^quay\/elasticsearch /m.test(stdout),
                'quay user elasticsearch');
            t.end();
        });
    });

    /*
     * This should fail, we don't expect to have any.
     *
     * It would be nice to fail quickly. E.g. on Docker-docker:
     *
     *  $ time docker search localhost:4321/foo
     *  FATA[0000] Error response from daemon: v1 \
     *    ping attempt failed with error: Get \
     *    http://localhost:4321/v1/_ping: dial tcp 127.0.0.1:5000: \
     *    connection refused
     *
     *  real    0m0.192s
     *  user    0m0.150s
     *  sys     0m0.005s
     *
     * However, sdc-docker currently takes ~15s to fail here.
     */
    tt.test(' docker search localhost:4321/foo', function (t) {
        alice.docker('search localhost:4321/foo',
                function (err, stdout, stderr) {
            t.ok(err);
            t.end();
        });
    });

});
<|endoftext|>


<commit_before>import React, { Component, Fragment } from 'react';
import gql from 'graphql-tag';
import { Query } from 'react-apollo';
import { withRouter } from 'react-router-dom';

import Nav from '../../components/Nav';
import DocTitle from '../../components/DocTitle';
import PageError from '../../components/PageError';

const getQueryArgs = ({ filters, ...args }) => {
  const queryArgs = Object.keys(args).map(
    // Using stringify to get the correct quotes depending on type
    argName => `${argName}: ${JSON.stringify(args[argName])}`
  );
  if (filters) {
    const filterArgs = filters.map(filter =>
      filter.field.getFilterGraphQL(filter)
    );
    if (filterArgs.length) {
      queryArgs.push(`where: { ${filterArgs.join(', ')} }`);
    }
  }
  return queryArgs.length ? `(${queryArgs.join(' ')})` : '';
};

const getQuery = ({ fields, filters, list, search, orderBy, skip, first }) => {
  const queryArgs = getQueryArgs({ first, filters, search, skip, orderBy });
  const metaQueryArgs = getQueryArgs({ filters, search });

  return gql`{
    ${list.listQueryName}${queryArgs} {
      id
      _label_
      ${fields.map(field => field.getQueryFragment()).join('\n')}
    }
    _${list.listQueryName}Meta${metaQueryArgs} {
      count
    }
  }`;
};

export type SortByType = {
  field: { label: string, path: string },
  direction: 'ASC' | 'DESC',
};
type Props = {
  list: Object,
};
type State = {
  currentPage: number,
  fields: Array<Object>,
  filters: Array<Object>,
  pageSize: number,
  search: string,
  skip: number,
  sortBy: SortByType,
};

class ListPageDataProvider extends Component<Props, State> {
  constructor(props) {
    super(props);

    // Prepare active fields and sort order
    const fields = props.list.fields.slice(0, 2);
    const sortBy = { field: fields[0], direction: 'ASC' };

    // We record the number of items returned by the latest query so that the
    // previous count can be displayed during a loading state.
    this.itemsCount = 0;

    // Declare initial state
    this.state = {
      currentPage: 1,
      fields,
      pageSize: 50,
      search: '',
      filters: [],
      skip: 0,
      sortBy,
    };
  }

  // ==============================
  // Search
  // ==============================

  handleSearchChange = ({ target: { value: search } }) => {
    this.setState({ search });
  };
  handleSearchClear = () => {
    this.setState({ search: '' });
    this.input.focus();
  };
  handleSearchSubmit = event => {
    let { list, adminPath, history } = this.props;

    event.preventDefault();

    if (this.items.length === 1) {
      history.push(`${adminPath}/${list.path}/${this.items[0].id}`);
    }
  };

  // ==============================
  // Filters
  // ==============================

  handleFilterRemove = value => () => {
    let filters = this.state.filters.slice(0);
    filters = filters.filter(f => f !== value);

    this.setState({ filters });
  };
  handleFilterRemoveAll = () => {
    this.setState({ filters: [] });
  };
  handleFilterAdd = value => {
    let filters = this.state.filters.slice(0);
    filters.push(value);

    this.setState({ filters });
  };
  handleFilterUpdate = updatedFilter => {
    let filters = this.state.filters.slice(0);

    const updateIndex = filters.findIndex(i => {
      return (
        i.field.path === updatedFilter.field.path &&
        i.type === updatedFilter.type
      );
    });

    filters.splice(updateIndex, 1, updatedFilter);

    this.setState({ filters });
  };

  // ==============================
  // Columns
  // ==============================

  handleFieldChange = selectedFields => {
    if (!selectedFields.length) {
      return;
    }

    // Ensure that the displayed fields maintain their original sortDirection
    // when they're added/removed
    const fields = this.props.list.fields.filter(field =>
      selectedFields.includes(field)
    );

    // Reset `sortBy` if we were ordering by a field which has been removed.
    const { sortBy } = this.state;
    const newSort = fields.includes(sortBy.field)
      ? sortBy
      : { ...sortBy, field: fields[0] };

    this.setState({ fields, sortBy: newSort });
  };

  // ==============================
  // Sorting
  // ==============================

  handleSortChange = sortBy => {
    this.setState({ sortBy });
  };

  // ==============================
  // Pagination
  // ==============================

  handlePageChange = currentPage => {
    const { pageSize } = this.state;
    const skip = (currentPage - 1) * pageSize;
    this.setState({ currentPage, skip });
  };

  render() {
    const { children, list } = this.props;
    const {
      currentPage,
      fields,
      filters,
      pageSize,
      search,
      skip,
      sortBy,
    } = this.state;

    const orderBy = `${sortBy.field.path}_${sortBy.direction}`;
    const first = pageSize;
    const query = getQuery({
      fields,
      filters,
      list,
      search,
      orderBy,
      skip,
      first,
    });

    return (
      <Fragment>
        <DocTitle>{list.plural}</DocTitle>

        <Query query={query} fetchPolicy="cache-and-network">
          {({ data, error, loading, refetch }) => {
            if (error) {
              return (
                <PageError>

{error.message}

                </PageError>
              );
            }

            // Leave the old values intact while new data is loaded
            if (!loading) {
              this.items = data && data[list.listQueryName];
              this.itemsCount =
                data &&
                data[`_${list.listQueryName}Meta`] &&
                data[`_${list.listQueryName}Meta`].count;
            }

            return children({
              query: { data, error, loading, refetch },
              data: {
                currentPage,
                fields,
                filters,
                items: this.items,
                itemsCount: this.itemsCount,
                pageSize,
                search,
                skip,
                sortBy,
              },
              handlers: {
                handleFilterRemove: this.handleFilterRemove,
                handleFilterRemoveAll: this.handleFilterRemoveAll,
                handleFilterAdd: this.handleFilterAdd,
                handleFilterUpdate: this.handleFilterUpdate,
                handleFieldChange: this.handleFieldChange,
                handlePageChange: this.handlePageChange,
                handleSearchChange: this.handleSearchChange,
                handleSearchClear: this.handleSearchClear,
                handleSearchSubmit: this.handleSearchSubmit,
                handleSortChange: this.handleSortChange,
              },
            });
          }}
        </Query>
      </Fragment>
    );
  }
}

export default withRouter(ListPageDataProvider);
<commit_msg>ensure "itemsCount" is always a number<commit_after>import React, { Component, Fragment } from 'react';
import gql from 'graphql-tag';
import { Query } from 'react-apollo';
import { withRouter } from 'react-router-dom';

import Nav from '../../components/Nav';
import DocTitle from '../../components/DocTitle';
import PageError from '../../components/PageError';

const getQueryArgs = ({ filters, ...args }) => {
  const queryArgs = Object.keys(args).map(
    // Using stringify to get the correct quotes depending on type
    argName => `${argName}: ${JSON.stringify(args[argName])}`
  );
  if (filters) {
    const filterArgs = filters.map(filter =>
      filter.field.getFilterGraphQL(filter)
    );
    if (filterArgs.length) {
      queryArgs.push(`where: { ${filterArgs.join(', ')} }`);
    }
  }
  return queryArgs.length ? `(${queryArgs.join(' ')})` : '';
};

const getQuery = ({ fields, filters, list, search, orderBy, skip, first }) => {
  const queryArgs = getQueryArgs({ first, filters, search, skip, orderBy });
  const metaQueryArgs = getQueryArgs({ filters, search });

  return gql`{
    ${list.listQueryName}${queryArgs} {
      id
      _label_
      ${fields.map(field => field.getQueryFragment()).join('\n')}
    }
    _${list.listQueryName}Meta${metaQueryArgs} {
      count
    }
  }`;
};

export type SortByType = {
  field: { label: string, path: string },
  direction: 'ASC' | 'DESC',
};
type Props = {
  list: Object,
};
type State = {
  currentPage: number,
  fields: Array<Object>,
  filters: Array<Object>,
  pageSize: number,
  search: string,
  skip: number,
  sortBy: SortByType,
};

class ListPageDataProvider extends Component<Props, State> {
  constructor(props) {
    super(props);

    // Prepare active fields and sort order
    const fields = props.list.fields.slice(0, 2);
    const sortBy = { field: fields[0], direction: 'ASC' };

    // We record the number of items returned by the latest query so that the
    // previous count can be displayed during a loading state.
    this.itemsCount = 0;

    // Declare initial state
    this.state = {
      currentPage: 1,
      fields,
      pageSize: 50,
      search: '',
      filters: [],
      skip: 0,
      sortBy,
    };
  }

  // ==============================
  // Search
  // ==============================

  handleSearchChange = ({ target: { value: search } }) => {
    this.setState({ search });
  };
  handleSearchClear = () => {
    this.setState({ search: '' });
    this.input.focus();
  };
  handleSearchSubmit = event => {
    let { list, adminPath, history } = this.props;

    event.preventDefault();

    if (this.items.length === 1) {
      history.push(`${adminPath}/${list.path}/${this.items[0].id}`);
    }
  };

  // ==============================
  // Filters
  // ==============================

  handleFilterRemove = value => () => {
    let filters = this.state.filters.slice(0);
    filters = filters.filter(f => f !== value);

    this.setState({ filters });
  };
  handleFilterRemoveAll = () => {
    this.setState({ filters: [] });
  };
  handleFilterAdd = value => {
    let filters = this.state.filters.slice(0);
    filters.push(value);

    this.setState({ filters });
  };
  handleFilterUpdate = updatedFilter => {
    let filters = this.state.filters.slice(0);

    const updateIndex = filters.findIndex(i => {
      return (
        i.field.path === updatedFilter.field.path &&
        i.type === updatedFilter.type
      );
    });

    filters.splice(updateIndex, 1, updatedFilter);

    this.setState({ filters });
  };

  // ==============================
  // Columns
  // ==============================

  handleFieldChange = selectedFields => {
    if (!selectedFields.length) {
      return;
    }

    // Ensure that the displayed fields maintain their original sortDirection
    // when they're added/removed
    const fields = this.props.list.fields.filter(field =>
      selectedFields.includes(field)
    );

    // Reset `sortBy` if we were ordering by a field which has been removed.
    const { sortBy } = this.state;
    const newSort = fields.includes(sortBy.field)
      ? sortBy
      : { ...sortBy, field: fields[0] };

    this.setState({ fields, sortBy: newSort });
  };

  // ==============================
  // Sorting
  // ==============================

  handleSortChange = sortBy => {
    this.setState({ sortBy });
  };

  // ==============================
  // Pagination
  // ==============================

  handlePageChange = currentPage => {
    const { pageSize } = this.state;
    const skip = (currentPage - 1) * pageSize;
    this.setState({ currentPage, skip });
  };

  render() {
    const { children, list } = this.props;
    const {
      currentPage,
      fields,
      filters,
      pageSize,
      search,
      skip,
      sortBy,
    } = this.state;

    const orderBy = `${sortBy.field.path}_${sortBy.direction}`;
    const first = pageSize;
    const query = getQuery({
      fields,
      filters,
      list,
      search,
      orderBy,
      skip,
      first,
    });

    return (
      <Fragment>
        <DocTitle>{list.plural}</DocTitle>

        <Query query={query} fetchPolicy="cache-and-network">
          {({ data, error, loading, refetch }) => {
            if (error) {
              return (
                <PageError>

{error.message}

                </PageError>
              );
            }

            // Leave the old values intact while new data is loaded
            if (!loading) {
              this.items = data && data[list.listQueryName];
              this.itemsCount =
                (data &&
                  data[`_${list.listQueryName}Meta`] &&
                  data[`_${list.listQueryName}Meta`].count) ||
                0;
            }

            return children({
              query: { data, error, loading, refetch },
              data: {
                currentPage,
                fields,
                filters,
                items: this.items,
                itemsCount: this.itemsCount,
                pageSize,
                search,
                skip,
                sortBy,
              },
              handlers: {
                handleFilterRemove: this.handleFilterRemove,
                handleFilterRemoveAll: this.handleFilterRemoveAll,
                handleFilterAdd: this.handleFilterAdd,
                handleFilterUpdate: this.handleFilterUpdate,
                handleFieldChange: this.handleFieldChange,
                handlePageChange: this.handlePageChange,
                handleSearchChange: this.handleSearchChange,
                handleSearchClear: this.handleSearchClear,
                handleSearchSubmit: this.handleSearchSubmit,
                handleSortChange: this.handleSortChange,
              },
            });
          }}
        </Query>
      </Fragment>
    );
  }
}

export default withRouter(ListPageDataProvider);
<|endoftext|>