<commit_before>/*
  Backgrid ObjectCell extension
  http://github.com/amiliaapp/backgrid-object-cell

  Creates a Backgrid Cell for editing an object or array into a Bootstrap modal dialog.
  Adds these new cells (under Backgrid.Extension):
    - ObjectCell: To render and edit an object. Will display a modal dialog with a form.
  - ArrayObjectCell: To render and edit an array of objects. Will display a modal
                     dialog with a Backgrid.
  Adds these new editors as well:
    - ObjectCellEditor
  - ArrayObjectCelleditor

  Depends on Bootstrap 3. For Bootstrap 2.3, slight mods are required. See note at bottom.

  Copyright (c) 2014 Amilia Inc.
  Written by Martin Drapeau
  Licensed under the MIT @license
 */
(function(){

  /**
     ObjectCell can render and edit an object stored inside a model attribute.
     Provide a formatter to serialize as a string to show in the cell.
     When editing, will open a Bootstrap modal dialog with a form to edit fields
     that you specify in schema. After editing, will set the modified attribute
     on the model.
     Options:
       - formatter: Provide a fromRaw function to humanize.
       - schema: An array of field objects in the form {name:'field attribute', label:'field label', ...}
                 Valid field attributes are:
                   - name: Name of object attribute to edit.
                   - label: Label to display in form.
                   - placeholder: Optional. Placeholder to put on input.
  */

  var ObjectCellEditor = Backgrid.Extension.ObjectCellEditor = Backgrid.CellEditor.extend({
    modalTemplate: _.template([
      '
',
      '
',
      '
',
      '
',
      '        ×',
      '
<%=title%>
',
      '
',
      '

',
      '
',
      '        Save',
      '        Cancel',
      '
',
      '
',
      '
',
      '
'
    ].join("\n")),
    stringTemplate: _.template([
      '
',
      '  <%=label%>',
      '
',
      '    <input type="text" class="form-control" name="<%=name%>" value="<%=value%>" placeholder="<%=placeholder%>" />',
      '
',
      '
'
    ].join("\n")),

    extendWithOptions: function(options) {
      _.extend(this, options);
    },

    render: function () {
      // In the cell just show the humanized value
      this.$el.text(this.formatter.fromRaw(this.model.get(this.column.get("name")), this.model));
      return this;
    },
    postRender: function(model, column) {
      var editor = this,
          objectModel = this.objectModel;

      if (!_.isArray(this.schema)) throw new TypeError("schema must be an array");

      // Create a Backbone model from our object if it does not exist
      if (!objectModel) {
        this.origObject = _.clone(this.model.get(this.column.get("name")));
        objectModel = this.objectModel = new Backbone.Model(_.clone(this.origObject));
      }

      var $dialog = this.createDialog();

      // Add the Bootstrap form
      var $form = $('<form class="form-horizontal">');
      $dialog.find('div.modal-body').append($form);
      _.each(this.schema, function(field) {
        if (!_.isObject(field) || !field.name || !field.label)
          throw new TypeError("schama elements must be field objects in the form {name:'field attribute', label:'field label'}");
        var template = editor.stringTemplate,
            data = _.extend({placeholder: ""}, field, {value: objectModel.get(field.name)});
        $form.append(template(data));
      });

      return this;
    },
    createDialog: function() {
      var editor = this,
          $dialog = this.$dialog = $(this.modalTemplate({title: this.column.get("label")}));

      // Handle close and save events
      $dialog.find('a.close').click(function(e) {
        e.preventDefault();
        editor.cancel();
        return false;
      });
      $dialog.find('a.save').click(function(e) {
        e.preventDefault();
        editor.save();
        return false;
      });

      // Show the Bootstrap modal dialog
      $dialog.modal({keyboard: false});

      // Hack to properly close the modal when clicking on the background.
      $('.modal-backdrop').off().click(_.bind(editor.cancel, this));

      return $dialog;
    },
    save: function(options) {
      options || (options = {});
      var model = this.model,
          column = this.column,
          objectModel = this.objectModel,
          $form = this.$dialog.find('form');

      // Retrieve values from the form, and store inside the object model
      var changes = {};
      _.each(this.schema, function(field) {
        changes[field.name] = $form.find('input[name='+field.name+']').val();
      });
      objectModel.set(changes);

      model.set(column.get("name"), objectModel.toJSON(), options);
      model.trigger("backgrid:edited", model, column, new Backgrid.Command({keyCode:13}));

      return this;
    },
    cancel: function() {
      this.model.trigger("backgrid:edited", this.model, this.column, new Backgrid.Command({keyCode:27}));
      return this;
    },
    remove: function() {
      this.$dialog.modal("hide").remove();
      Backgrid.CellEditor.prototype.remove.apply(this, arguments);
      return this;
    }
  });

  var ObjectCell = Backgrid.Extension.ObjectCell = Backgrid.Cell.extend({
    editorOptionDefaults: {
      schema: []
    },
    formatter: {
      // Defaults to JSON stringification
      fromRaw: function(object) {
        return JSON.stringify(object);
      }
    },
    editor: ObjectCellEditor,
    initialize: function(options) {
      Backgrid.Cell.prototype.initialize.apply(this, arguments);

      // Pass on cell options to the editor
      var cell = this,
          editorOptions = {};
      _.each(this.editorOptionDefaults, function(def, opt) {
        if (!cell[opt]) cell[opt] = def;
        if (options && options[opt]) cell[opt] = options[opt];
        editorOptions[opt] = cell[opt];
      });
      this.listenTo(this.model, "backgrid:edit", function (model, column, cell, editor) {
        if (column.get("name") == this.column.get("name"))
          editor.extendWithOptions(editorOptions);
      });
    }
  });

  /**
     ArrayObjectCell can render and edit an array of objects stored inside a
     model attribute. Provide a formatter to serialize as a string to show in the cell.
     When editing, will open a Bootstrap modal dialog with a Backgrid table to edit
     each object. Specify which object attributes to edit via option objectColumns.
     After editing, will set the modified attribute on the model.
     The
     Options:
       - formatter: Provide a fromRaw function to humanize.
       - backgrid: Backgrid grid class to instantiate. Defaults to Backgrid.Grid.
       - gridOptions: Backgrid options. Should include columns.
  */

  var ArrayObjectCellEditor = Backgrid.Extension.ArrayObjectCellEditor = Backgrid.Extension.ObjectCellEditor.extend({
    postRender: function () {
      var view = this,
          model = this.model,
          column = this.column,
          gridOptions = this.gridOptions;

      // Extract the object, and create a Backbone model from it.
      var array = _.map(model.get(column.get("name")), function(object) {return _.clone(object);}),
          objectCollection = this.objectCollection = new Backbone.Collection(array);

      // Create our Bootstrap modal dialog
      var $dialog = this.createDialog();

      // Add the Backgrid Grid
      var grid = new this.backgrid(_.extend({collection: objectCollection}, gridOptions)),
          $grid = grid.render().$el;
      $dialog.find('div.modal-body').append($grid);

      return this;
    },
    save: function() {
      var model = this.model,
          column = this.column,
          objectCollection = this.objectCollection;

      model.set(column.get("name"), objectCollection.toJSON());
      model.trigger("backgrid:edited", model, column, new Backgrid.Command({keyCode:13}));

      return this;
    }
  });

  var ArrayObjectCell = Backgrid.Extension.ArrayObjectCell = Backgrid.Extension.ObjectCell.extend({
    editorOptionDefaults: {
      backgrid: Backgrid.Grid,
      gridOptions: {}
    },
    formatter: {
      // Defaults to JSON stringification
      fromRaw: function(array) {
        return JSON.stringify(array);
      }
    },
    editor: ArrayObjectCellEditor
  });

  /**
    Bootstrap 2.3 use requires are change in modal and form templates.

    Backgrid.Extension.ObjectCellEditor.prototype.modalTemplate = _.template([
      '
',
      '
',
      '    ×',
      '
<%=title%>
',
      '
',
      '

',
      '
',
      '    Save',
      '    Cancel',
      '
',
      '
'
    ].join("\n"));
    Backgrid.Extension.ObjectCellEditor.prototype.stringTemplate = _.template([
      '
',
      '  <%=label%>',
      '
',
      '    <input type="text" name="<%=name%>" value="<%=value%>" placeholder="<%=placeholder%>" />',
      '
',
      '
'
    ].join("\n"));
  */

}).call(this);<commit_msg>Update backgrid-object-cell.js<commit_after>/*
  Backgrid ObjectCell extension
  http://github.com/amiliaapp/backgrid-object-cell

  Creates a Backgrid Cell for editing an object or array into a Bootstrap modal dialog.
  Adds these new cells (under Backgrid.Extension):
    - ObjectCell: To render and edit an object. Will display a modal dialog with a form.
  - ArrayObjectCell: To render and edit an array of objects. Will display a modal
                     dialog with a Backgrid.
  Adds these new editors as well:
    - ObjectCellEditor
  - ArrayObjectCelleditor

  Depends on Bootstrap 3. For Bootstrap 2.3, slight mods are required. See note at bottom.

  Copyright (c) 2014 Amilia Inc.
  Written by Martin Drapeau
  Licensed under the MIT @license
 */
(function(){

  /**
     ObjectCell can render and edit an object stored inside a model attribute.
     Provide a formatter to serialize as a string to show in the cell.
     When editing, will open a Bootstrap modal dialog with a form to edit fields
     that you specify in schema. After editing, will set the modified attribute
     on the model.
     Options:
       - formatter: Provide a fromRaw function to humanize.
       - schema: An array of field objects in the form {name:'field attribute', label:'field label', ...}
                 Valid field attributes are:
                   - name: Name of object attribute to edit.
                   - label: Label to display in form.
                   - placeholder: Optional. Placeholder to put on input.
  */

  var ObjectCellEditor = Backgrid.Extension.ObjectCellEditor = Backgrid.CellEditor.extend({
    modalTemplate: _.template([
      '
',
      '
',
      '
',
      '
',
      '        ×',
      '
<%=title%>
',
      '
',
      '

',
      '
',
      '        Save',
      '        Cancel',
      '
',
      '
',
      '
',
      '
'
    ].join("\n")),
    stringTemplate: _.template([
      '
',
      '  <%=label%>',
      '
',
      '    <input type="text" class="form-control" name="<%=name%>" value="<%=value%>" placeholder="<%=placeholder%>" />',
      '
',
      '
'
    ].join("\n")),

    extendWithOptions: function(options) {
      _.extend(this, options);
    },

    render: function () {
      // In the cell just show the humanized value
      this.$el.text(this.formatter.fromRaw(this.model.get(this.column.get("name")), this.model));
      return this;
    },
    postRender: function(model, column) {
      var editor = this,
          objectModel = this.objectModel;

      if (!_.isArray(this.schema)) throw new TypeError("schema must be an array");

      // Create a Backbone model from our object if it does not exist
      if (!objectModel) {
        this.origObject = _.clone(this.model.get(this.column.get("name")));
        objectModel = this.objectModel = new Backbone.Model(_.clone(this.origObject));
      }

      var $dialog = this.createDialog();

      // Add the Bootstrap form
      var $form = $('<form class="form-horizontal"></form>');
      $dialog.find('div.modal-body').append($form);
      _.each(this.schema, function(field) {
        if (!_.isObject(field) || !field.name || !field.label)
          throw new TypeError("schama elements must be field objects in the form {name:'field attribute', label:'field label'}");
        var template = editor.stringTemplate,
            data = _.extend({placeholder: ""}, field, {value: objectModel.get(field.name)});
        $form.append(template(data));
      });

      return this;
    },
    createDialog: function() {
      var editor = this,
          $dialog = this.$dialog = $(this.modalTemplate({title: this.column.get("label")}));

      // Handle close and save events
      $dialog.find('a.close').click(function(e) {
        e.preventDefault();
        editor.cancel();
        return false;
      });
      $dialog.find('a.save').click(function(e) {
        e.preventDefault();
        editor.save();
        return false;
      });

      // Show the Bootstrap modal dialog
      $dialog.modal({keyboard: false});

      // Hack to properly close the modal when clicking on the background.
      $('.modal-backdrop').off().click(_.bind(editor.cancel, this));

      return $dialog;
    },
    save: function(options) {
      options || (options = {});
      var model = this.model,
          column = this.column,
          objectModel = this.objectModel,
          $form = this.$dialog.find('form');

      // Retrieve values from the form, and store inside the object model
      var changes = {};
      _.each(this.schema, function(field) {
        changes[field.name] = $form.find('input[name='+field.name+']').val();
      });
      objectModel.set(changes);

      model.set(column.get("name"), objectModel.toJSON(), options);
      model.trigger("backgrid:edited", model, column, new Backgrid.Command({keyCode:13}));

      return this;
    },
    cancel: function() {
      this.model.trigger("backgrid:edited", this.model, this.column, new Backgrid.Command({keyCode:27}));
      return this;
    },
    remove: function() {
      this.$dialog.modal("hide").remove();
      Backgrid.CellEditor.prototype.remove.apply(this, arguments);
      return this;
    }
  });

  var ObjectCell = Backgrid.Extension.ObjectCell = Backgrid.Cell.extend({
    editorOptionDefaults: {
      schema: []
    },
    formatter: {
      // Defaults to JSON stringification
      fromRaw: function(object) {
        return JSON.stringify(object);
      }
    },
    editor: ObjectCellEditor,
    initialize: function(options) {
      Backgrid.Cell.prototype.initialize.apply(this, arguments);

      // Pass on cell options to the editor
      var cell = this,
          editorOptions = {};
      _.each(this.editorOptionDefaults, function(def, opt) {
        if (!cell[opt]) cell[opt] = def;
        if (options && options[opt]) cell[opt] = options[opt];
        editorOptions[opt] = cell[opt];
      });
      this.listenTo(this.model, "backgrid:edit", function (model, column, cell, editor) {
        if (column.get("name") == this.column.get("name"))
          editor.extendWithOptions(editorOptions);
      });
    }
  });

  /**
     ArrayObjectCell can render and edit an array of objects stored inside a
     model attribute. Provide a formatter to serialize as a string to show in the cell.
     When editing, will open a Bootstrap modal dialog with a Backgrid table to edit
     each object. Specify which object attributes to edit via option objectColumns.
     After editing, will set the modified attribute on the model.
     The
     Options:
       - formatter: Provide a fromRaw function to humanize.
       - backgrid: Backgrid grid class to instantiate. Defaults to Backgrid.Grid.
       - gridOptions: Backgrid options. Should include columns.
  */

  var ArrayObjectCellEditor = Backgrid.Extension.ArrayObjectCellEditor = Backgrid.Extension.ObjectCellEditor.extend({
    postRender: function () {
      var view = this,
          model = this.model,
          column = this.column,
          gridOptions = this.gridOptions;

      // Extract the object, and create a Backbone model from it.
      var array = _.map(model.get(column.get("name")), function(object) {return _.clone(object);}),
          objectCollection = this.objectCollection = new Backbone.Collection(array);

      // Create our Bootstrap modal dialog
      var $dialog = this.createDialog();

      // Add the Backgrid Grid
      var grid = new this.backgrid(_.extend({collection: objectCollection}, gridOptions)),
          $grid = grid.render().$el;
      $dialog.find('div.modal-body').append($grid);

      return this;
    },
    save: function() {
      var model = this.model,
          column = this.column,
          objectCollection = this.objectCollection;

      model.set(column.get("name"), objectCollection.toJSON());
      model.trigger("backgrid:edited", model, column, new Backgrid.Command({keyCode:13}));

      return this;
    }
  });

  var ArrayObjectCell = Backgrid.Extension.ArrayObjectCell = Backgrid.Extension.ObjectCell.extend({
    editorOptionDefaults: {
      backgrid: Backgrid.Grid,
      gridOptions: {}
    },
    formatter: {
      // Defaults to JSON stringification
      fromRaw: function(array) {
        return JSON.stringify(array);
      }
    },
    editor: ArrayObjectCellEditor
  });

  /**
    Bootstrap 2.3 use requires are change in modal and form templates.

    Backgrid.Extension.ObjectCellEditor.prototype.modalTemplate = _.template([
      '
',
      '
',
      '    ×',
      '
<%=title%>
',
      '
',
      '

',
      '
',
      '    Save',
      '    Cancel',
      '
',
      '
'
    ].join("\n"));
    Backgrid.Extension.ObjectCellEditor.prototype.stringTemplate = _.template([
      '
',
      '  <%=label%>',
      '
',
      '    <input type="text" name="<%=name%>" value="<%=value%>" placeholder="<%=placeholder%>" />',
      '
',
      '
'
    ].join("\n"));
  */

}).call(this);
<|endoftext|>


<commit_before>// @flow
import Awral from 'awral'
/**
 * `parseJSON()` adds property "ok"
 *  that identicates that response is OK
 *
 *  This func to determinates is response from API was successful or failed
 *
 * @param  {Object} result - response from API
 * @return {Boolean} - indicates was request successful or not
 */
const check = (result: Object = {ok: false}): boolean => result.ok
const beforeCheck = a => a
const afterCheck = a => a.data
// Create default Awral
export const awral = Awral.of({check, beforeCheck, afterCheck})
<commit_msg>chore(actions/utils): add comment about Awral<commit_after>// @flow
import Awral from 'awral'
/**
 * `parseJSON()` adds property "ok"
 *  that identicates that response is OK
 *
 *  This func to determinates is response from API was successful or failed
 *
 * @param  {Object} result - response from API
 * @return {Boolean} - indicates was request successful or not
 */
const check = (result: Object = {ok: false}): boolean => result.ok
const beforeCheck = a => a
const afterCheck = a => a.data
/**
  Create default Awral
  Awral is my own tool.
  It's not well known, but it can make your work with actions even more simpler.
  {@link https://github.com/Metnew/awral}
*/
export const awral = Awral.of({check, beforeCheck, afterCheck})
<|endoftext|>


<commit_before>var message_states = Object.freeze(
  {
    MESSAGE_FAILED: -1,
    MESSAGE_SENT: 1,
    MESSAGE_DELIVERED_SERVICE: 2,
    MESSAGE_DELIVERED_USER: 3,
    MESSAGE_READ: 4,
    MESSAGE_REPLIED: 5
  }
)

var Message = {
  body: null,
  servicechain: null
}

module.exports = {message_states, message}<commit_msg>Set up module exports differently<commit_after>var message_states = Object.freeze(
  {
    MESSAGE_FAILED: -1,
    MESSAGE_SENT: 1,
    MESSAGE_DELIVERED_SERVICE: 2,
    MESSAGE_DELIVERED_USER: 3,
    MESSAGE_READ: 4,
    MESSAGE_REPLIED: 5
  }
)

var Message = {
  body: null,
  servicechain: null
}

exports.message_states = message_states
exports.Message = Message<|endoftext|>


<commit_before>#!/usr/bin/env node
var fs = require('fs');
var path = require('path');
var cwd = path.join(__dirname, '..');
var spawn = require('child_process').spawn;
var script = path.join(__dirname, '..', 'node_modules', 'nodewebkit', 'bin', 'nodewebkit');
var child = spawn('node', [script], {cwd: cwd}, { detached: true , stdio: 'ignore' });

child.unref();
process.exit();
<commit_msg>Fix options Conflicts: 	bin/stopplicht-start.js<commit_after>#!/usr/bin/env node
var fs = require('fs');
var path = require('path');
var cwd = path.join(__dirname, '..');
var spawn = require('child_process').spawn;
var script = path.join(__dirname, '..', 'node_modules', 'nodewebkit', 'bin', 'nodewebkit');
var child = spawn('node', [script], {cwd: cwd, detached: true , stdio: 'ignore' });

child.unref();
process.exit();
<|endoftext|>


<commit_before>"use strict";

class gsuiSlider extends HTMLElement {
	constructor() {
		const [ input, ...html ] = GSUI.getTemplate( "gsui-slider" );

		super();
		this._min = 0;
		this._max = 100;
		this._step = 1;
		this._scrollStep = 1;
		this._wheelChange = false;
		this._mousemoveSize = 0;
		this._strokeWidth = 4;

		this.oninput =
		this.onchange =
		this.oninputend =
		this.oninputstart = null;

		this.value =
		this._previousval = "";
		this._enable = true;
		this._circ =
		this._axeX =
		this._locked =
		this._connected = false;
		this.width =
		this.height =
		this._pxval =
		this._pxmoved =
		this._svgLineLen = 0;
		this._children = html;
		this._elInput = input;
		this._elLine = html[ 0 ];
		this._elLineColor = this._elLine.firstElementChild;
		this._elSvg = html[ 1 ];
		this._elSvgLine = this._elSvg.firstElementChild;
		this._elSvgLineColor = this._elSvg.lastElementChild;
		Object.seal( this );

		this.classList.add( "gsuiSlider" );
		this.onwheel = this._wheel.bind( this );
		this.onmouseup = this._mouseup.bind( this );
		this.onmousedown = this._mousedown.bind( this );
		this.onmousemove = this._mousemove.bind( this );
		this.onmouseleave = this._mouseleave.bind( this );
	}

	// .........................................................................
	connectedCallback() {
		if ( this._children ) {
			const brc = this.getBoundingClientRect();

			this.append( ...this._children );
			this.width = brc.width;
			this.height = brc.height;
			this._children = null;
			this._connected = true;
			this._setSVGcirc();
			this._updateVal();
		}
	}
	static get observedAttributes() {
		return [ "type", "min", "max", "step", "scroll-step", "wheel-change", "mousemove-size", "stroke-width" ];
	}
	attributeChangedCallback( prop, prev, val ) {
		if ( prev !== val ) {
			let updateVal;

			switch ( prop ) {
				case "type":
					this._setType( val );
					this._setSVGcirc();
					updateVal = true;
					break;
				case "min":
					this._elInput.min = this._min = +val;
					updateVal = true;
					break;
				case "max":
					this._elInput.max = this._max = +val;
					updateVal = true;
					break;
				case "step":
					this._elInput.step = this._step = +val;
					updateVal = true;
					break;
				case "scroll-step":
					this._scrollStep = +val;
					break;
				case "wheel-change":
					this._wheelChange = typeof val === "string";
					break;
				case "mousemove-size":
					this._mousemoveSize = +val;
					break;
				case "stroke-width":
					this._strokeWidth = +val;
					this._setSVGcirc();
					break;
			}
			if ( updateVal ) {
				this._previousval = this._getInputVal();
				this._updateVal();
			}
		}
	}

	// .........................................................................
	setValue( val, bymouse ) {
		if ( !this._locked || bymouse ) {
			const prevVal = this._getInputVal(),
				newVal = ( this._elInput.value = val, this._getInputVal() );

			if ( newVal !== prevVal ) {
				this._updateVal();
				if ( bymouse && this.oninput ) {
					this.oninput( +newVal );
				}
			}
			if ( !bymouse ) {
				this._previousval = newVal;
			}
		}
	}
	enable( b ) {
		this._enable = b;
		this.classList.toggle( "gsuiSlider-disable", !b );
	}

	// private:
	// .........................................................................
	_setType( type ) {
		const st = this._elLineColor.style,
			circ = type === "circular",
			axeX = type === "linear-x";

		this._circ = circ;
		this._axeX = axeX;
		this.classList.toggle( "gsuiSlider-circular", circ );
		this.classList.toggle( "gsuiSlider-linear", !circ );
		if ( !circ ) {
			if ( axeX ) {
				st.left =
				st.width = "";
				st.top = "0";
				st.height = "100%";
			} else {
				st.top =
				st.height = "";
				st.left = "0";
				st.width = "100%";
			}
		}
	}
	_setSVGcirc() {
		if ( this._circ && this.width && this.height ) {
			const size = Math.min( this.width, this.height ),
				size2 = size / 2,
				circR = ~~( ( size - this._strokeWidth ) / 2 );

			this._elSvg.setAttribute( "viewBox", `0 0 ${ size } ${ size }` );
			this._elSvgLine.setAttribute( "cx", size2 );
			this._elSvgLine.setAttribute( "cy", size2 );
			this._elSvgLine.setAttribute( "r", circR );
			this._elSvgLineColor.setAttribute( "cx", size2 );
			this._elSvgLineColor.setAttribute( "cy", size2 );
			this._elSvgLineColor.setAttribute( "r", circR );
			this._elSvgLine.style.strokeWidth =
			this._elSvgLineColor.style.strokeWidth = this._strokeWidth;
			this._svgLineLen = circR * 2 * Math.PI;
		}
	}
	_getInputVal() {
		const val = this._elInput.value;

		return Math.abs( +val ) < .000001 ? "0" : val;
	}
	_getRange() {
		return this._max - this._min;
	}
	_getMousemoveSize() {
		return this._mousemoveSize || (
			this._circ
				? this._svgLineLen
				: this._axeX
					? this._elLine.getBoundingClientRect().width
					: this._elLine.getBoundingClientRect().height
		);
	}
	_updateVal() {
		this.value = +this._getInputVal();
		if ( this._connected ) {
			const len = this._getRange(),
				prcval = ( this.value - this._min ) / len,
				prcstart = -this._min / len,
				prclen = Math.abs( prcval - prcstart ),
				prcmin = Math.min( prcval, prcstart );

			if ( this._circ ) {
				const line = this._elSvgLineColor.style;

				line.transform = `rotate(${ 90 + prcmin * 360 }deg)`;
				line.strokeDasharray = `${ prclen * this._svgLineLen }, 999999`;
			} else {
				const line = this._elLineColor.style;

				if ( this._axeX ) {
					line.left = `${ prcmin * 100 }%`;
					line.width = `${ prclen * 100 }%`;
				} else {
					line.bottom = `${ prcmin * 100 }%`;
					line.height = `${ prclen * 100 }%`;
				}
			}
		}
	}
	_onchange() {
		const val = this._getInputVal();

		if ( this._previousval !== val ) {
			this.onchange && this.onchange( +val );
			this._previousval = val;
		}
	}

	// events:
	// .........................................................................
	_wheel( e ) {
		if ( this._enable && this._wheelChange ) {
			const d = e.deltaY > 0 ? -1 : 1;

			this.setValue( +this._getInputVal() + this._scrollStep * d, true );
			return false;
		}
	}
	_mousedown() {
		if ( this._enable ) {
			this._onchange();
			if ( this.oninputstart ) {
				this.oninputstart( this.value );
			}
			this._pxval = this._getRange() / this._getMousemoveSize();
			this._pxmoved = 0;
			this.requestPointerLock();
		}
	}
	_mousemove( e ) {
		if ( this._locked ) {
			const bound = this._getRange() / 5,
				mov = this._circ || !this._axeX ? -e.movementY : e.movementX,
				val = +this._previousval + ( this._pxmoved + mov ) * this._pxval;

			if ( this._min - bound < val && val < this._max + bound ) {
				this._pxmoved += mov;
			}
			this.setValue( val, true );
		}
	}
	_mouseup() {
		if ( this._locked ) {
			document.exitPointerLock();
			this._locked = false;
			this._onchange();
			if ( this.oninputend ) {
				this.oninputend( this.value );
			}
		}
	}
	_mouseleave() {
		this._onchange();
	}
}

customElements.define( "gsui-slider", gsuiSlider );

document.addEventListener( "pointerlockchange", () => {
	const el = document.pointerLockElement;

	if ( el ) {
		if ( el.classList.contains( "gsuiSlider" ) ) {
			el._locked = true;
			gsuiSlider._focused = el;
		}
	} else if ( gsuiSlider._focused ) {
		gsuiSlider._focused._mouseup();
	}
} );
<commit_msg>gsuiSlider: move the classList.add into the connectedCallback<commit_after>"use strict";

class gsuiSlider extends HTMLElement {
	constructor() {
		const [ input, ...html ] = GSUI.getTemplate( "gsui-slider" );

		super();
		this._min = 0;
		this._max = 100;
		this._step = 1;
		this._scrollStep = 1;
		this._wheelChange = false;
		this._mousemoveSize = 0;
		this._strokeWidth = 4;

		this.oninput =
		this.onchange =
		this.oninputend =
		this.oninputstart = null;

		this.value =
		this._previousval = "";
		this._enable = true;
		this._circ =
		this._axeX =
		this._locked =
		this._connected = false;
		this.width =
		this.height =
		this._pxval =
		this._pxmoved =
		this._svgLineLen = 0;
		this._children = html;
		this._elInput = input;
		this._elLine = html[ 0 ];
		this._elLineColor = this._elLine.firstElementChild;
		this._elSvg = html[ 1 ];
		this._elSvgLine = this._elSvg.firstElementChild;
		this._elSvgLineColor = this._elSvg.lastElementChild;
		Object.seal( this );

		this.onwheel = this._wheel.bind( this );
		this.onmouseup = this._mouseup.bind( this );
		this.onmousedown = this._mousedown.bind( this );
		this.onmousemove = this._mousemove.bind( this );
		this.onmouseleave = this._mouseleave.bind( this );
	}

	// .........................................................................
	connectedCallback() {
		this.classList.add( "gsuiSlider" );
		if ( this._children ) {
			const brc = this.getBoundingClientRect();

			this.append( ...this._children );
			this.width = brc.width;
			this.height = brc.height;
			this._children = null;
			this._connected = true;
			this._setSVGcirc();
			this._updateVal();
		}
	}
	static get observedAttributes() {
		return [ "type", "min", "max", "step", "scroll-step", "wheel-change", "mousemove-size", "stroke-width" ];
	}
	attributeChangedCallback( prop, prev, val ) {
		if ( prev !== val ) {
			let updateVal;

			switch ( prop ) {
				case "type":
					this._setType( val );
					this._setSVGcirc();
					updateVal = true;
					break;
				case "min":
					this._elInput.min = this._min = +val;
					updateVal = true;
					break;
				case "max":
					this._elInput.max = this._max = +val;
					updateVal = true;
					break;
				case "step":
					this._elInput.step = this._step = +val;
					updateVal = true;
					break;
				case "scroll-step":
					this._scrollStep = +val;
					break;
				case "wheel-change":
					this._wheelChange = typeof val === "string";
					break;
				case "mousemove-size":
					this._mousemoveSize = +val;
					break;
				case "stroke-width":
					this._strokeWidth = +val;
					this._setSVGcirc();
					break;
			}
			if ( updateVal ) {
				this._previousval = this._getInputVal();
				this._updateVal();
			}
		}
	}

	// .........................................................................
	setValue( val, bymouse ) {
		if ( !this._locked || bymouse ) {
			const prevVal = this._getInputVal(),
				newVal = ( this._elInput.value = val, this._getInputVal() );

			if ( newVal !== prevVal ) {
				this._updateVal();
				if ( bymouse && this.oninput ) {
					this.oninput( +newVal );
				}
			}
			if ( !bymouse ) {
				this._previousval = newVal;
			}
		}
	}
	enable( b ) {
		this._enable = b;
		this.classList.toggle( "gsuiSlider-disable", !b );
	}

	// private:
	// .........................................................................
	_setType( type ) {
		const st = this._elLineColor.style,
			circ = type === "circular",
			axeX = type === "linear-x";

		this._circ = circ;
		this._axeX = axeX;
		this.classList.toggle( "gsuiSlider-circular", circ );
		this.classList.toggle( "gsuiSlider-linear", !circ );
		if ( !circ ) {
			if ( axeX ) {
				st.left =
				st.width = "";
				st.top = "0";
				st.height = "100%";
			} else {
				st.top =
				st.height = "";
				st.left = "0";
				st.width = "100%";
			}
		}
	}
	_setSVGcirc() {
		if ( this._circ && this.width && this.height ) {
			const size = Math.min( this.width, this.height ),
				size2 = size / 2,
				circR = ~~( ( size - this._strokeWidth ) / 2 );

			this._elSvg.setAttribute( "viewBox", `0 0 ${ size } ${ size }` );
			this._elSvgLine.setAttribute( "cx", size2 );
			this._elSvgLine.setAttribute( "cy", size2 );
			this._elSvgLine.setAttribute( "r", circR );
			this._elSvgLineColor.setAttribute( "cx", size2 );
			this._elSvgLineColor.setAttribute( "cy", size2 );
			this._elSvgLineColor.setAttribute( "r", circR );
			this._elSvgLine.style.strokeWidth =
			this._elSvgLineColor.style.strokeWidth = this._strokeWidth;
			this._svgLineLen = circR * 2 * Math.PI;
		}
	}
	_getInputVal() {
		const val = this._elInput.value;

		return Math.abs( +val ) < .000001 ? "0" : val;
	}
	_getRange() {
		return this._max - this._min;
	}
	_getMousemoveSize() {
		return this._mousemoveSize || (
			this._circ
				? this._svgLineLen
				: this._axeX
					? this._elLine.getBoundingClientRect().width
					: this._elLine.getBoundingClientRect().height
		);
	}
	_updateVal() {
		this.value = +this._getInputVal();
		if ( this._connected ) {
			const len = this._getRange(),
				prcval = ( this.value - this._min ) / len,
				prcstart = -this._min / len,
				prclen = Math.abs( prcval - prcstart ),
				prcmin = Math.min( prcval, prcstart );

			if ( this._circ ) {
				const line = this._elSvgLineColor.style;

				line.transform = `rotate(${ 90 + prcmin * 360 }deg)`;
				line.strokeDasharray = `${ prclen * this._svgLineLen }, 999999`;
			} else {
				const line = this._elLineColor.style;

				if ( this._axeX ) {
					line.left = `${ prcmin * 100 }%`;
					line.width = `${ prclen * 100 }%`;
				} else {
					line.bottom = `${ prcmin * 100 }%`;
					line.height = `${ prclen * 100 }%`;
				}
			}
		}
	}
	_onchange() {
		const val = this._getInputVal();

		if ( this._previousval !== val ) {
			this.onchange && this.onchange( +val );
			this._previousval = val;
		}
	}

	// events:
	// .........................................................................
	_wheel( e ) {
		if ( this._enable && this._wheelChange ) {
			const d = e.deltaY > 0 ? -1 : 1;

			this.setValue( +this._getInputVal() + this._scrollStep * d, true );
			return false;
		}
	}
	_mousedown() {
		if ( this._enable ) {
			this._onchange();
			if ( this.oninputstart ) {
				this.oninputstart( this.value );
			}
			this._pxval = this._getRange() / this._getMousemoveSize();
			this._pxmoved = 0;
			this.requestPointerLock();
		}
	}
	_mousemove( e ) {
		if ( this._locked ) {
			const bound = this._getRange() / 5,
				mov = this._circ || !this._axeX ? -e.movementY : e.movementX,
				val = +this._previousval + ( this._pxmoved + mov ) * this._pxval;

			if ( this._min - bound < val && val < this._max + bound ) {
				this._pxmoved += mov;
			}
			this.setValue( val, true );
		}
	}
	_mouseup() {
		if ( this._locked ) {
			document.exitPointerLock();
			this._locked = false;
			this._onchange();
			if ( this.oninputend ) {
				this.oninputend( this.value );
			}
		}
	}
	_mouseleave() {
		this._onchange();
	}
}

customElements.define( "gsui-slider", gsuiSlider );

document.addEventListener( "pointerlockchange", () => {
	const el = document.pointerLockElement;

	if ( el ) {
		if ( el.classList.contains( "gsuiSlider" ) ) {
			el._locked = true;
			gsuiSlider._focused = el;
		}
	} else if ( gsuiSlider._focused ) {
		gsuiSlider._focused._mouseup();
	}
} );
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { Dropdown } from 'react-bootstrap';

import { modules } from 'stripes-loader'; // eslint-disable-line

import { clearOkapiToken, clearCurrentUser } from '../../okapiActions';

import css from './MainNav.css';
import NavButton from './NavButton';
import NavDivider from './NavDivider';
import NavGroup from './NavGroup';
import Breadcrumbs from './Breadcrumbs';
import NavIcon from './NavIcon';

import NavDropdownMenu from './NavDropdownMenu';

if (!Array.isArray(modules.app) || modules.app.length < 1) {
  throw new Error('At least one module of type "app" must be enabled.');
}

class MainNav extends Component {

  static contextTypes = {
    router: PropTypes.object.isRequired,
  }

  static propTypes = {
    stripes: PropTypes.shape({
      config: PropTypes.shape({
        showPerms: PropTypes.bool,
      }),
      store: PropTypes.shape({
        dispatch: PropTypes.func.isRequired,
      }),
    }),
  };

  constructor(props) {
    super(props);
    this.state = {
      userMenuOpen: false,
    };
    this.store = props.stripes.store;
    this.toggleUserMenu = this.toggleUserMenu.bind(this);
    this.logout = this.logout.bind(this);
  }

  toggleUserMenu() {
    const isOpen = this.state.userMenuOpen;
    this.setState({
      userMenuOpen: !isOpen,
    });
  }

  logout() {
    this.store.dispatch(clearOkapiToken());
    this.store.dispatch(clearCurrentUser());
    this.context.router.history.push('/');
  }

  render() {
    const { stripes } = this.props;
    const currentUser = stripes.user ? stripes.user.user : undefined;
    const currentPerms = stripes.user ? stripes.user.perms : undefined;

    const userIcon = (
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 26 26">
        <rect width="26" height="26" style={{ fill: '#3D9964' }} />
        <path d="M1.1 24.9c0 0 0-2.6 0.8-3.7 0.8-1 5.8-5.2 11.1-5.1s9.9 3.1 10.9 4.4 1.1 4.4 1.1 4.4L1.1 24.9z" style={{ fill: '#FFF' }} />
        <path d="M18.6 11.4c0 4.2-2.5 7.6-5.6 7.6 -3.1 0-5.6-3.4-5.6-7.6S8.4 3.8 13 3.8 18.6 7.2 18.6 11.4z" style={{ fill: '#FFF' }} />
        <path d="M13 19.5c-3.4 0-6.1-3.6-6.1-8.1 0-3.5 0.6-8.1 6.1-8.1 5.5 0 6.1 4.6 6.1 8.1C19.1 15.9 16.4 19.5 13 19.5zM13 4.3c-3.6 0-5.1 2.1-5.1 7.1 0 3.9 2.3 7.1 5.1 7.1 2.8 0 5.1-3.2 5.1-7.1C18.1 6.5 16.6 4.3 13 4.3z" style={{ fill: '#3D9964' }} />
      </svg>
    );

    let maybePerms;
    const config = stripes.config;
    if (config && config.showPerms) {
      maybePerms = (

Perms: {Object.keys(currentPerms || {}).sort().join(', ')}

      );
    }

    const userDD = (

        <li className={`${css.nowrap} ${css.ddTextItem}`}>Logged in as { currentUser != null ? `${currentUser.first_name} ${currentUser.last_name}` : null }

<button id="button-logout" className={css.ddButton} type="button" onClick={this.logout}>Log out</button>

        {maybePerms}

    );

    const menuLinks = modules.app.map((entry) => {
      const name = entry.module.replace(/^@folio\//, '');
      const perm = `module.${name}.enabled`;
      if (!stripes.hasPerm(perm)) return null;

      return (<NavButton href={entry.home || entry.route} title={entry.displayName} key={entry.route}>
        <NavIcon color="#61f160" />

          {entry.displayName}

      </NavButton>);
    });

    let firstNav;
    let breadcrumbArray = []; // eslint-disable-line

    if (breadcrumbArray.length === 0) {
      firstNav = (
        <NavGroup md="hide">

            <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 26 26">
              <polygon style={{fill: "#999"}} points="13 16.5 1.2 5.3 3.2 3.1 13 12.4 22.8 3.1 24.8 5.3 " />
              <polygon style={{fill: "#999"}} points="13 24.8 1.2 13.5 3.2 11.3 13 20.6 22.8 11.3 24.8 13.5 " />
            </svg>

          <NavButton href="/">
            <NavIcon color="#fdae35" />
            FOLIO
          </NavButton>
          <NavButton href="/settings">
            <NavIcon color="#7d3fb3" />
            Settings
          </NavButton>
        </NavGroup>
      );
    } else {
      firstNav = (
        <NavGroup>
          <NavButton md="hide">
            <NavIcon color="#fdae35" />
          </NavButton>
          <Breadcrumbs linkArray={breadcrumbArray} />
        </NavGroup>
      );
    }

    return (

        {firstNav}
        <NavGroup>
          <NavGroup>
            {menuLinks}
            <NavDivider md="hide" />
            <NavButton md="hide" ><NavIcon color="#7eb970" /></NavButton>
            <NavButton md="hide"><NavIcon color="#b33f3f" /></NavButton>
            <NavButton md="hide"><NavIcon color="#3fb38e" /></NavButton>
            <NavButton md="hide"><NavIcon color="#3f6cb3" /></NavButton>
            <NavDivider md="hide" />
            <NavButton md="hide"><NavIcon color="#7d3fb3" /></NavButton>
          </NavGroup>
          <NavGroup className={css.smallAlignRight}>
            <Dropdown open={this.state.userMenuOpen} id="UserMenuDropDown" onToggle={this.toggleUserMenu} pullRight >
              <NavButton bsRole="toggle" title="User Menu" aria-haspopup="true" aria-expanded={this.state.userMenuOpen}><NavIcon icon={userIcon} /></NavButton>
              <NavDropdownMenu bsRole="menu" onToggle={this.toggleUserMenu} aria-label="User Menu">{userDD}</NavDropdownMenu>
            </Dropdown>
          </NavGroup>
        </NavGroup>

    );
  }
}

export default MainNav;
<commit_msg>Fix logout<commit_after>import React, { Component, PropTypes } from 'react';
import { Dropdown } from 'react-bootstrap';

import { modules } from 'stripes-loader'; // eslint-disable-line

import { clearOkapiToken, clearCurrentUser } from '../../okapiActions';

import css from './MainNav.css';
import NavButton from './NavButton';
import NavDivider from './NavDivider';
import NavGroup from './NavGroup';
import Breadcrumbs from './Breadcrumbs';
import NavIcon from './NavIcon';

import NavDropdownMenu from './NavDropdownMenu';

if (!Array.isArray(modules.app) || modules.app.length < 1) {
  throw new Error('At least one module of type "app" must be enabled.');
}

class MainNav extends Component {

  static contextTypes = {
    router: PropTypes.object.isRequired,
  }

  static propTypes = {
    stripes: PropTypes.shape({
      config: PropTypes.shape({
        showPerms: PropTypes.bool,
      }),
      store: PropTypes.shape({
        dispatch: PropTypes.func.isRequired,
      }),
    }),
  };

  constructor(props) {
    super(props);
    this.state = {
      userMenuOpen: false,
    };
    this.store = props.stripes.store;
    this.toggleUserMenu = this.toggleUserMenu.bind(this);
    this.logout = this.logout.bind(this);
  }

  toggleUserMenu() {
    const isOpen = this.state.userMenuOpen;
    this.setState({
      userMenuOpen: !isOpen,
    });
  }

  logout() {
    window.location.assign('/');
  }

  render() {
    const { stripes } = this.props;
    const currentUser = stripes.user ? stripes.user.user : undefined;
    const currentPerms = stripes.user ? stripes.user.perms : undefined;

    const userIcon = (
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 26 26">
        <rect width="26" height="26" style={{ fill: '#3D9964' }} />
        <path d="M1.1 24.9c0 0 0-2.6 0.8-3.7 0.8-1 5.8-5.2 11.1-5.1s9.9 3.1 10.9 4.4 1.1 4.4 1.1 4.4L1.1 24.9z" style={{ fill: '#FFF' }} />
        <path d="M18.6 11.4c0 4.2-2.5 7.6-5.6 7.6 -3.1 0-5.6-3.4-5.6-7.6S8.4 3.8 13 3.8 18.6 7.2 18.6 11.4z" style={{ fill: '#FFF' }} />
        <path d="M13 19.5c-3.4 0-6.1-3.6-6.1-8.1 0-3.5 0.6-8.1 6.1-8.1 5.5 0 6.1 4.6 6.1 8.1C19.1 15.9 16.4 19.5 13 19.5zM13 4.3c-3.6 0-5.1 2.1-5.1 7.1 0 3.9 2.3 7.1 5.1 7.1 2.8 0 5.1-3.2 5.1-7.1C18.1 6.5 16.6 4.3 13 4.3z" style={{ fill: '#3D9964' }} />
      </svg>
    );
window.location.assign('/');
    let maybePerms;
    const config = stripes.config;
    if (config && config.showPerms) {
      maybePerms = (

Perms: {Object.keys(currentPerms || {}).sort().join(', ')}

      );
    }

    const userDD = (

        <li className={`${css.nowrap} ${css.ddTextItem}`}>Logged in as { currentUser != null ? `${currentUser.first_name} ${currentUser.last_name}` : null }

<button id="button-logout" className={css.ddButton} type="button" onClick={this.logout}>Log out</button>

        {maybePerms}

    );

    const menuLinks = modules.app.map((entry) => {
      const name = entry.module.replace(/^@folio\//, '');
      const perm = `module.${name}.enabled`;
      if (!stripes.hasPerm(perm)) return null;

      return (<NavButton href={entry.home || entry.route} title={entry.displayName} key={entry.route}>
        <NavIcon color="#61f160" />

          {entry.displayName}

      </NavButton>);
    });

    let firstNav;
    let breadcrumbArray = []; // eslint-disable-line

    if (breadcrumbArray.length === 0) {
      firstNav = (
        <NavGroup md="hide">

            <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 26 26">
              <polygon style={{fill: "#999"}} points="13 16.5 1.2 5.3 3.2 3.1 13 12.4 22.8 3.1 24.8 5.3 " />
              <polygon style={{fill: "#999"}} points="13 24.8 1.2 13.5 3.2 11.3 13 20.6 22.8 11.3 24.8 13.5 " />
            </svg>

          <NavButton href="/">
            <NavIcon color="#fdae35" />
            FOLIO
          </NavButton>
          <NavButton href="/settings">
            <NavIcon color="#7d3fb3" />
            Settings
          </NavButton>
        </NavGroup>
      );
    } else {
      firstNav = (
        <NavGroup>
          <NavButton md="hide">
            <NavIcon color="#fdae35" />
          </NavButton>
          <Breadcrumbs linkArray={breadcrumbArray} />
        </NavGroup>
      );
    }

    return (

        {firstNav}
        <NavGroup>
          <NavGroup>
            {menuLinks}
            <NavDivider md="hide" />
            <NavButton md="hide" ><NavIcon color="#7eb970" /></NavButton>
            <NavButton md="hide"><NavIcon color="#b33f3f" /></NavButton>
            <NavButton md="hide"><NavIcon color="#3fb38e" /></NavButton>
            <NavButton md="hide"><NavIcon color="#3f6cb3" /></NavButton>
            <NavDivider md="hide" />
            <NavButton md="hide"><NavIcon color="#7d3fb3" /></NavButton>
          </NavGroup>
          <NavGroup className={css.smallAlignRight}>
            <Dropdown open={this.state.userMenuOpen} id="UserMenuDropDown" onToggle={this.toggleUserMenu} pullRight >
              <NavButton bsRole="toggle" title="User Menu" aria-haspopup="true" aria-expanded={this.state.userMenuOpen}><NavIcon icon={userIcon} /></NavButton>
              <NavDropdownMenu bsRole="menu" onToggle={this.toggleUserMenu} aria-label="User Menu">{userDD}</NavDropdownMenu>
            </Dropdown>
          </NavGroup>
        </NavGroup>

    );
  }
}

export default MainNav;
<|endoftext|>


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

const NEOList = ({ NEOs, lastAction }) => {
  return (

      {(lastAction === "FETCH_NEO_SUCCESS")
        ?

              { NEOs
                .sort((a,b) => a.close_approach_data[0].miss_distance.kilometers - b.close_approach_data[0].miss_distance.kilometers)
                .map((NEO, index) =>

Name: {NEO.name}.
                  miss-distance: {NEO.close_approach_data[0].miss_distance.kilometers / 6371} earth radii,
                  diameter: {NEO.estimated_diameter.kilometers.estimated_diameter_max} km

              )}

        : (lastAction === "FETCH_NEO_REQUEST")
        ?

Loading...

        : (lastAction === "FETCH_NEO_FAILURE")
        ?

Error...

        :

      }

    )
}

NEOList.propTypes = {
  NEOs: PropTypes.array
};

export default NEOList;
<commit_msg>units for NEO stats are more human-readable<commit_after>import React, { PropTypes } from 'react';

const NEOList = ({ NEOs, lastAction }) => {
  return (

      {(lastAction === "FETCH_NEO_SUCCESS")
        ?

              { NEOs
                .sort((a,b) => a.close_approach_data[0].miss_distance.kilometers - b.close_approach_data[0].miss_distance.kilometers)
                .map((NEO, index) =>

Name: {NEO.name}.
                  miss-distance: {Math.round(NEO.close_approach_data[0].miss_distance.kilometers / 6371)} earth radii,
                  diameter: {Math.round(NEO.estimated_diameter.kilometers.estimated_diameter_max * 1000)} m

              )}

        : (lastAction === "FETCH_NEO_REQUEST")
        ?

Loading...

        : (lastAction === "FETCH_NEO_FAILURE")
        ?

Error...

        :

      }

    )
}

NEOList.propTypes = {
  NEOs: PropTypes.array
};

export default NEOList;
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import { transparentize } from 'polished';
import React from 'react';
import styled, { css } from 'styled-components';
import _ from 'lodash';

import {
  colors,
  typography,
  renderThemeIfPresentOrDefault,
  ifThemeInPropsIsPresentUse
} from '../styles';

const size = 16;

function renderThemedLabelActiveBackground(props) {
  if (props.theme.lightRadio || !props.theme.brand01) return '';
  return transparentize(0.9, props.theme.brand01)
}

function renderThemedLabelBackground(props) {
  if (props.theme.lightRadio) return 'transparent';
  return props.theme.white10;
}

const RadioLabel = styled.label`
  ${typography.bodyCompact}
  background: ${props => ifThemeInPropsIsPresentUse({ props, value: renderThemedLabelBackground(props), defaultValue: props.theme.background })};
  display: flex;
  align-items: center;
  width: 100%;
  color: ${renderThemeIfPresentOrDefault({ key: 'white60', defaultValue: colors.black60 })};
  cursor: pointer;
  padding: ${props => {
    if (!_.isEmpty(props.label.super) && !_.isEmpty(props.label.main) && !_.isEmpty(props.theme.padding)) {
      return `6px ${props.theme.padding} 4px ${props.theme.padding}`;
    } else if (!_.isEmpty(props.theme.padding)) {
      return props.theme.padding;
    }
    return '0.75em';
  }};
  margin: ${props => props.theme.margin} 0;

  ${props => props.active && css`
    background: ${props => ifThemeInPropsIsPresentUse({ props, value: renderThemedLabelActiveBackground(props), defaultValue: props.theme.backgroundFocused })};
    color: ${renderThemeIfPresentOrDefault({ key: 'brand01', defaultValue: colors.black90 })};
  `}
`;

const RadioInput = styled.input`
  display: none;
`;

function renderThemedRadioCircleBorder(props) {
  return props.theme.white60;
}

function renderRadioCircleBorder(props) {
  return props.theme.lightRadio ? colors.black40 : colors.black
}

function renderThemedOuterRadioCircle(props) {
  if (!props.active) return '';
  return `border-color: ${props.theme.brand01};`
}

function renderOuterRadioCircle(props) {
  if (!props.theme.lightRadio || !props.active) return '';
  return `border-color: ${colors.green};`
}

const RadioCircle = styled.span`
  min-width: ${size}px;
  min-height: ${size}px;
  border-radius: 50%;
  display: inline-block;
  border: 2px solid ${props => ifThemeInPropsIsPresentUse({ props, value: renderThemedRadioCircleBorder(props), defaultValue: renderRadioCircleBorder(props) })};
  position: relative;
  vertical-align: middle;
  margin-right: 0.5714em;
  background: ${renderThemeIfPresentOrDefault({ key: 'transparent', defaultValue: colors.white })};
  box-sizing: content-box;

  ${props => ifThemeInPropsIsPresentUse({ props, value: renderThemedOuterRadioCircle(props), defaultValue: renderOuterRadioCircle(props) })}
  ${props => props.active && css`
    &:before {
      content: '';
      border-radius: 50%;
      width: ${size * 0.625}px;
      height: ${size * 0.625}px;
      background-color: ${renderThemeIfPresentOrDefault({ key: 'brand01', defaultValue: colors.green })};
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
  `}
`;

const MultiLineLabelWrapper = styled.div`
    display: inline-block;
    vertical-align: middle;
`;

const SuperscriptLabel = styled.div`
    color: ${renderThemeIfPresentOrDefault({ key: 'white60', defaultValue: colors.black60 })};
    ${typography.caption}
`;

const MainLabel = styled.div`
    color: ${renderThemeIfPresentOrDefault({ key: 'white60', defaultValue: colors.black90 })};
    ${typography.subhead1}
`;

const RadioComponent = ({ id, name, label = "", value, setValue, selectedValue = "" }) => {
  const active = value === selectedValue;

  const findLabel = (label) => {
    if (!_.isEmpty(label.super) && !_.isEmpty(label.main)) {
      return (
        <MultiLineLabelWrapper>
          <SuperscriptLabel>{label.super}</SuperscriptLabel>
          <MainLabel>{label.main}</MainLabel>
        </MultiLineLabelWrapper>
      );
    }
    return label;
  }

  return (

    <RadioInput
      className="pb-test__radio"
      type="radio"
      id={id}
      name={name}
      value={value}
      checked={active}
      onChange={() => { setValue(value) }}
    />
    <RadioLabel htmlFor={id} active={active} label={label}>
      <RadioCircle active={active}></RadioCircle>{findLabel(label)}
    </RadioLabel>

);
};

RadioComponent.propTypes = {
  id: PropTypes.string.isRequired,
  name: PropTypes.string.isRequired,
  label: PropTypes.any,
  selectedValue: PropTypes.any,
  value: PropTypes.any.isRequired,
  setValue: PropTypes.func.isRequired
};

export default RadioComponent;
<commit_msg>fix(RadioList): Remove brand-colored background when active. Add whit… (#329)<commit_after>import PropTypes from 'prop-types';
import { transparentize } from 'polished';
import React from 'react';
import styled, { css } from 'styled-components';
import _ from 'lodash';

import {
  colors,
  typography,
  renderThemeIfPresentOrDefault,
  ifThemeInPropsIsPresentUse
} from '../styles';

const size = 16;

function renderThemedLabelActiveBackground(props) {
  if (props.theme.lightRadio || !props.theme.brand01) return '';
  return transparentize(0.9, props.theme.brand01)
}

function renderThemedLabelBackground(props) {
  if (props.theme.lightRadio) return 'transparent';
  return props.theme.primary05;
}

const RadioLabel = styled.label`
  ${typography.bodyCompact}
  background: ${props => ifThemeInPropsIsPresentUse({ props, value: renderThemedLabelBackground(props), defaultValue: props.theme.background })};
  display: flex;
  align-items: center;
  width: 100%;
  color: ${renderThemeIfPresentOrDefault({ key: 'white60', defaultValue: colors.black60 })};
  cursor: pointer;
  padding: ${props => {
    if (!_.isEmpty(props.label.super) && !_.isEmpty(props.label.main) && !_.isEmpty(props.theme.padding)) {
      return `6px ${props.theme.padding} 4px ${props.theme.padding}`;
    } else if (!_.isEmpty(props.theme.padding)) {
      return props.theme.padding;
    }
    return '0.75em';
  }};
  margin: ${props => props.theme.margin} 0;

  ${props => {
    if (props.active) {
      return css`
        background: ${props => ifThemeInPropsIsPresentUse({ props, value: renderThemedLabelActiveBackground(props), defaultValue: props.theme.backgroundFocused })};
        color: ${renderThemeIfPresentOrDefault({ key: 'brand01', defaultValue: colors.black90 })};
      `;
    }

    return css`
      &:hover {
        color: ${renderThemeIfPresentOrDefault({ key: 'white', defaultValue: colors.black })};
        span {
          border-color: ${renderThemeIfPresentOrDefault({ key: 'white', defaultValue: colors.black })};
        }
      }
    `
  }}
`;

const RadioInput = styled.input`
  display: none;
`;

function renderThemedRadioCircleBorder(props) {
  return props.theme.white60;
}

function renderRadioCircleBorder(props) {
  return props.theme.lightRadio ? colors.black40 : colors.black
}

function renderThemedOuterRadioCircle(props) {
  if (!props.active) return '';
  return `border-color: ${props.theme.brand01};`
}

function renderOuterRadioCircle(props) {
  if (!props.theme.lightRadio || !props.active) return '';
  return `border-color: ${colors.green};`
}

const RadioCircle = styled.span`
  min-width: ${size}px;
  min-height: ${size}px;
  border-radius: 50%;
  display: inline-block;
  border: 2px solid ${props => ifThemeInPropsIsPresentUse({ props, value: renderThemedRadioCircleBorder(props), defaultValue: renderRadioCircleBorder(props) })};
  position: relative;
  vertical-align: middle;
  margin-right: 0.5714em;
  background: ${renderThemeIfPresentOrDefault({ key: 'transparent', defaultValue: colors.white })};
  box-sizing: content-box;

  ${props => ifThemeInPropsIsPresentUse({ props, value: renderThemedOuterRadioCircle(props), defaultValue: renderOuterRadioCircle(props) })}
  ${props => props.active && css`
    &:before {
      content: '';
      border-radius: 50%;
      width: ${size * 0.625}px;
      height: ${size * 0.625}px;
      background-color: ${renderThemeIfPresentOrDefault({ key: 'brand01', defaultValue: colors.green })};
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
  `}
`;

const MultiLineLabelWrapper = styled.div`
    display: inline-block;
    vertical-align: middle;
`;

const SuperscriptLabel = styled.div`
    color: ${renderThemeIfPresentOrDefault({ key: 'white60', defaultValue: colors.black60 })};
    ${typography.caption}
`;

const MainLabel = styled.div`
    color: ${renderThemeIfPresentOrDefault({ key: 'white60', defaultValue: colors.black90 })};
    ${typography.subhead1}
`;

const RadioComponent = ({ id, name, label = "", value, setValue, selectedValue = "" }) => {
  const active = value === selectedValue;

  const findLabel = (label) => {
    if (!_.isEmpty(label.super) && !_.isEmpty(label.main)) {
      return (
        <MultiLineLabelWrapper>
          <SuperscriptLabel>{label.super}</SuperscriptLabel>
          <MainLabel>{label.main}</MainLabel>
        </MultiLineLabelWrapper>
      );
    }
    return label;
  }

  return (

    <RadioInput
      className="pb-test__radio"
      type="radio"
      id={id}
      name={name}
      value={value}
      checked={active}
      onChange={() => { setValue(value) }}
    />
    <RadioLabel htmlFor={id} active={active} label={label}>
      <RadioCircle active={active}></RadioCircle>{findLabel(label)}
    </RadioLabel>

);
};

RadioComponent.propTypes = {
  id: PropTypes.string.isRequired,
  name: PropTypes.string.isRequired,
  label: PropTypes.any,
  selectedValue: PropTypes.any,
  value: PropTypes.any.isRequired,
  setValue: PropTypes.func.isRequired
};

export default RadioComponent;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Link } from 'react-router';
import classnames from 'classnames';
import { categories } from '../../data/styleguide';

require('./Sidebar.scss');

export class Sidebar extends Component {
  render() {
    const { location } = this.props;
    return (

          {
            categories.map((category) => (

                  <Link
                    className={classnames({ sidebarActive: location.indexOf(dasherize(category.name)) >= 0 })}
                    to={`/${dasherize(category.name)}`}
                  >
                    {category.name}
                  </Link>

                  { category.items.map((item) => (

                        <Link
                          className={classnames({ sidebarActive: location.indexOf(dasherize(item.name)) >= 0 })}
                          to={`/${dasherize(category.name)}/${dasherize(item.name)}`}
                        >
                          {item.name}
                        </Link>

                    )
                  )}

)
            )
          }

    );
  }
}

function dasherize(str) {
  return str.replace(/\s+/g, '_').toLowerCase();
}
<commit_msg>removes classnames dep and uses activeclassname from react router instead<commit_after>import React, { Component } from 'react';
import { Link } from 'react-router';
import { categories } from '../../data/styleguide';

require('./Sidebar.scss');

export class Sidebar extends Component {
  render() {
    const { location } = this.props;
    return (

          {
            categories.map((category) => (

                  <Link
                    activeClassName="sidebarActive"
                    to={`/${dasherize(category.name)}`}
                  >
                    {category.name}
                  </Link>

                  { category.items.map((item) => (

                        <Link
                          activeClassName="sidebarActive"
                          to={`/${dasherize(category.name)}/${dasherize(item.name)}`}
                        >
                          {item.name}
                        </Link>

                    )
                  )}

)
            )
          }

    );
  }
}

function dasherize(str) {
  return str.replace(/\s+/g, '_').toLowerCase();
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Async from 'react-promise';
import invariant from 'invariant';

import MarkerStrategy from '../strategies/marker';
import PathStrategy from '../strategies/path';
import MarkerGroupStrategy from '../strategies/markergroup';
import PathGroupStrategy from '../strategies/pathgroup';
import DirectionStrategy from '../strategies/direction/index';
import MapStrategy from '../strategies/map';
import {
  isStatelessComponent,
  renderStatelessComponent,
  isClassComponent,
  renderClassComponent,
} from '../strategies/utils';

class StaticGoogleMap extends Component {
  static propTypes = {
    as: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
    onGenerate: PropTypes.func,
    rootURL: PropTypes.string,

    size: PropTypes.string.isRequired,
    scale: PropTypes.oneOf([1, 2, 4, '1', '2', '4']),
    format: PropTypes.oneOf([
      'png',
      'png8',
      'png32',
      'gif',
      'jpg',
      'jpg-baseline',
    ]),
    maptype: PropTypes.oneOf(['roadmap', 'satellite', 'terrain', 'hybrid']),

    language: PropTypes.string,
    region: PropTypes.string,
    visible: PropTypes.string,
    style: PropTypes.string,

    center: PropTypes.string,
    zoom: PropTypes.string,

    client: PropTypes.string,
    apiKey: PropTypes.string,
    signature: PropTypes.string,
    channel: PropTypes.string,
  };

  static defaultProps = {
    as: 'img',
    scale: 1,
    format: 'png',
    rootURL: 'https://maps.googleapis.com/maps/api/staticmap',
    apiKey: '',
    maptype: 'roadmap',
  };

  buildParts(children, props) {
    return React.Children.map(children, child => {
      if (!React.isValidElement(child)) {
        return null;
      }

      switch (child.type.name) {
        case 'Marker':
          return MarkerStrategy(child, props);
        case 'MarkerGroup':
          return MarkerGroupStrategy(child, props);
        case 'Path':
          return PathStrategy(child, props);
        case 'PathGroup':
          return PathGroupStrategy(child, props);
        case 'Direction':
          return DirectionStrategy(child, props);
        default:
          const componentType = child.type;

          if (isStatelessComponent(componentType)) {
            return this.buildParts(
              renderStatelessComponent(componentType, { ...child.props }),
              props
            );
          }

          if (isClassComponent(componentType)) {
            return this.buildParts(
              renderClassComponent(componentType, { ...child.props }),
              props
            );
          }

          return null;
      }
    });
  }

  render() {
    const { children, onGenerate, as: Component, ...props } = this.props;
    const {
      rootURL,
      size,
      zoom,
      scale,
      style,
      center,
      format,
      client,
      region,
      visible,
      channel,
      maptype,
      language,
      signature,
      apiKey,
      ...componentProps
    } = props;

    invariant(size, 'size property is not set');
    invariant(
      children,
      'Component must have `Marker`, `Path` or `Direction` child'
    );

    const childrenUrlParts = this.buildParts(children, props) || [];
    const mainUrlParts = MapStrategy(props);

    /**
     * All the parts should return a string if a component that does not return a promise isn't used
     * The Directions's component returns a promise and would instead use the Async component to render
     * This allows us render sync otherwise and partially support server side rendering.
     */
    if (!childrenUrlParts.some(part => typeof part === 'object')) {
      const childURL = childrenUrlParts.filter(part => part).join('&');
      const url = `${mainUrlParts}&${childURL}`;

      if (onGenerate) {
        onGenerate(url);
      }

      return <Component {...componentProps} src={url} />;
    }

    const urlParts = Promise.all(childrenUrlParts).then(
      parts => `${mainUrlParts}&${parts.filter(part => part).join('&')}`
    );

    return (
      <Async
        promise={urlParts}
        then={URL => {
          if (onGenerate) {
            onGenerate(URL);
          }

          return <Component {...componentProps} src={URL} />;
        }}
        catch={err => (
          console.error(err), Image generation failed.
        )}
      />
    );
  }
}

export default StaticGoogleMap;
<commit_msg>#7 Add a more reliable check for component type<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Async from 'react-promise';
import invariant from 'invariant';

import MarkerStrategy from '../strategies/marker';
import PathStrategy from '../strategies/path';
import MarkerGroupStrategy from '../strategies/markergroup';
import PathGroupStrategy from '../strategies/pathgroup';
import DirectionStrategy from '../strategies/direction/index';
import MapStrategy from '../strategies/map';
import Marker from './Marker';
import Path from './Path';
import Direction from './Direction';
import {
  isStatelessComponent,
  renderStatelessComponent,
  isClassComponent,
  renderClassComponent,
} from '../strategies/utils';

class StaticGoogleMap extends Component {
  static propTypes = {
    as: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
    onGenerate: PropTypes.func,
    rootURL: PropTypes.string,

    size: PropTypes.string.isRequired,
    scale: PropTypes.oneOf([1, 2, 4, '1', '2', '4']),
    format: PropTypes.oneOf([
      'png',
      'png8',
      'png32',
      'gif',
      'jpg',
      'jpg-baseline',
    ]),
    maptype: PropTypes.oneOf(['roadmap', 'satellite', 'terrain', 'hybrid']),

    language: PropTypes.string,
    region: PropTypes.string,
    visible: PropTypes.string,
    style: PropTypes.string,

    center: PropTypes.string,
    zoom: PropTypes.string,

    client: PropTypes.string,
    apiKey: PropTypes.string,
    signature: PropTypes.string,
    channel: PropTypes.string,
  };

  static defaultProps = {
    as: 'img',
    scale: 1,
    format: 'png',
    rootURL: 'https://maps.googleapis.com/maps/api/staticmap',
    apiKey: '',
    maptype: 'roadmap',
  };

  buildParts(children, props) {
    return React.Children.map(children, child => {
      if (!React.isValidElement(child)) {
        return null;
      }

      switch (child.type) {
        case Marker:
          return MarkerStrategy(child, props);
        case Marker.Group:
          return MarkerGroupStrategy(child, props);
        case Path:
          return PathStrategy(child, props);
        case Path.Group:
          return PathGroupStrategy(child, props);
        case Direction:
          return DirectionStrategy(child, props);
        default:
          const componentType = child.type;

          if (isStatelessComponent(componentType)) {
            return this.buildParts(
              renderStatelessComponent(componentType, { ...child.props }),
              props
            );
          }

          if (isClassComponent(componentType)) {
            return this.buildParts(
              renderClassComponent(componentType, { ...child.props }),
              props
            );
          }

          return null;
      }
    });
  }

  render() {
    const { children, onGenerate, as: Component, ...props } = this.props;
    const {
      rootURL,
      size,
      zoom,
      scale,
      style,
      center,
      format,
      client,
      region,
      visible,
      channel,
      maptype,
      language,
      signature,
      apiKey,
      ...componentProps
    } = props;

    invariant(size, 'size property is not set');
    invariant(
      children,
      'Component must have `Marker`, `Path` or `Direction` child'
    );

    const childrenUrlParts = this.buildParts(children, props) || [];
    const mainUrlParts = MapStrategy(props);

    /**
     * All the parts should return a string if a component that does not return a promise isn't used
     * The Directions's component returns a promise and would instead use the Async component to render
     * This allows us render sync otherwise and partially support server side rendering.
     */
    if (!childrenUrlParts.some(part => typeof part === 'object')) {
      const childURL = childrenUrlParts.filter(part => part).join('&');
      const url = `${mainUrlParts}&${childURL}`;

      if (onGenerate) {
        onGenerate(url);
      }

      return <Component {...componentProps} src={url} />;
    }

    const urlParts = Promise.all(childrenUrlParts).then(
      parts => `${mainUrlParts}&${parts.filter(part => part).join('&')}`
    );

    return (
      <Async
        promise={urlParts}
        then={URL => {
          if (onGenerate) {
            onGenerate(URL);
          }

          return <Component {...componentProps} src={URL} />;
        }}
        catch={err => (
          console.error(err), Image generation failed.
        )}
      />
    );
  }
}

export default StaticGoogleMap;
<|endoftext|>


<commit_before>import React from 'react';
import domOnlyProps from 'form/domOnlyProps';
import FormLabel from 'components/FormLabel';
import FormError from 'components/FormError';
import IconBullet from 'components/IconBullet';
import styles from './text-field.scss';

const getClassname = (element, error) => {
  return [
    styles[element || 'input'],
    styles[error ? 'invalid' : 'valid']
  ].join(' ');
};

export default ({ config, helper }) => {
  const hasError = helper.touched && helper.error;
  const isValid = helper.touched && !helper.error;

  return (

      <FormLabel
        fieldId={config.name}
        label={config.label}
        hint={config.hint}
      />

        <config.element
          className={getClassname(config.element, hasError)}
          id={config.name}
          // pass props from config e.g. type, placeholder, maxlength
          {...config.html}
          // domOnlyProps required with latest react and redux-form 5.x
          // see: https://github.com/erikras/redux-form/issues/1441#issuecomment-236966387
          {...domOnlyProps(helper)}
        />
        {hasError &&
          <FormError text={helper.error} />
        }

          {hasError &&
            <IconBullet
              id={'X'}
              modifier={'error'}
            />
          }
          {isValid &&
            <IconBullet
              id={'Checkmark'}
              modifier={'success'}
            />
          }

  );
};
<commit_msg>Change validation logic slightly<commit_after>import React from 'react';
import domOnlyProps from 'form/domOnlyProps';
import FormLabel from 'components/FormLabel';
import FormError from 'components/FormError';
import IconBullet from 'components/IconBullet';
import styles from './text-field.scss';

const getClassname = (element, error) => {
  return [
    styles[element || 'input'],
    styles[error ? 'invalid' : 'valid']
  ].join(' ');
};

export default ({ config, helper }) => {
  const hasError = helper.touched && helper.error;
  const isValid = helper.touched && !helper.error && helper.value;

  return (

      <FormLabel
        fieldId={config.name}
        label={config.label}
        hint={config.hint}
      />

        <config.element
          className={getClassname(config.element, hasError)}
          id={config.name}
          // pass props from config e.g. type, placeholder, maxlength
          {...config.html}
          // domOnlyProps required with latest react and redux-form 5.x
          // see: https://github.com/erikras/redux-form/issues/1441#issuecomment-236966387
          {...domOnlyProps(helper)}
        />
        {hasError &&
          <FormError text={helper.error} />
        }

          {hasError &&
            <IconBullet
              id={'X'}
              modifier={'error'}
            />
          }
          {isValid &&
            <IconBullet
              id={'Checkmark'}
              modifier={'success'}
            />
          }

  );
};
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Dropzone from 'react-dropzone';

import Nav from 'react-bootstrap/lib/Nav';
import Navbar from 'react-bootstrap/lib/Navbar';
import NavItem from 'react-bootstrap/lib/NavItem';
import Button from 'react-bootstrap/lib/Button';
import Modal from 'react-bootstrap/lib/Modal';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import Alert from 'react-bootstrap/lib/Alert';

import FontAwesomeIcon from 'fm3/components/FontAwesomeIcon';

import { setTool, setActivePopup, closePopup } from 'fm3/actions/mainActions';
import { trackViewerSetData, trackViewerResetData, trackViewerSetTrackUID, trackViewerResetTrackUID } from 'fm3/actions/trackViewerActions';
import { toastsAdd } from 'fm3/actions/toastsActions';

import { getMapLeafletElement } from 'fm3/leafletElementHolder';
import { getNodejsBackendURL, MAX_GPX_TRACK_SIZE_IN_MB } from 'fm3/backendDefinitions';

import 'fm3/styles/trackViewer.scss';

class TrackViewerMenu extends React.Component {
  componentWillReceiveProps(newProps) {
    if (newProps.trackGeojson && JSON.stringify(this.props.trackGeojson) !== JSON.stringify(newProps.trackGeojson)) {
      const geojsonBounds = L.geoJson(newProps.trackGeojson).getBounds();
      getMapLeafletElement().fitBounds(geojsonBounds);
    }
  }

  onFileDrop = (acceptedFiles, rejectedFiles) => {
    if (acceptedFiles.length > 0) {
      const reader = new FileReader();
      reader.readAsText(acceptedFiles[0], 'UTF-8');
      reader.onload = (event) => {
        const gpxAsString = event.target.result;
        this.props.onResetTrackUID();
        this.props.onTrackViewerSetData(gpxAsString);
        this.props.onClosePopup();
      };

      reader.onerror = (e) => {
        this.props.onLoadError(`Nepodarilo sa spracovať súbor: ${e && e.message}`);
      };
    }

    if (rejectedFiles.length) {
      this.props.onLoadError('Nesprávny formát súboru: Nahraný súbor musí mať príponu .gpx');
    }
  }

  shareTrack = () => {
    if (this.props.trackUID) {
      this.props.onLaunchPopup('track-viewer-share');
    } else if (this.props.trackGpx.length > (MAX_GPX_TRACK_SIZE_IN_MB * 1000000)) {
      this.props.onLoadError(`Veľkosť nahraného súboru prevyšuje ${MAX_GPX_TRACK_SIZE_IN_MB}MB. Zdieľanie podporujeme len pre menšie súbory.`);
    } else {
      fetch(`${getNodejsBackendURL()}/tracklogs`, {
        method: 'POST',
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          data: btoa(this.props.trackGpx),
          mediaType: 'application/gpx+xml',
        }),
      }).then(res => res.json())
      .then((res) => {
        this.props.onSetTrackUID(res.uid);
        this.props.onLaunchPopup('track-viewer-share');
      }).catch((e) => {
        this.props.onLoadError(`Nepodarilo sa nahrať súbor: ${e}`);
      });
    }
  }

  render() {
    const { activePopup, onCancel, onLaunchPopup, onClosePopup, trackGpx, trackUID } = this.props;

    let shareURL = '';
    if (trackUID) {
      shareURL = `${window.location.origin}/?tool=track-viewer&track-uid=${trackUID}`;
    }
    return (

        <Navbar.Form pullLeft>
          <Button onClick={() => onLaunchPopup('upload-track')}>
            <FontAwesomeIcon icon="upload" /> Nahrať trasu
          </Button>
          {' '}
          {trackGpx &&
            <Button onClick={this.shareTrack}>
              <FontAwesomeIcon icon="share-alt" /> Zdieľať
            </Button>
          }
        </Navbar.Form>

          <NavItem onClick={onCancel}><Glyphicon glyph="remove" /> Zavrieť</NavItem>

        <Modal show={activePopup === 'upload-track'} onHide={onClosePopup}>
          <Modal.Header closeButton>
            <Modal.Title>Nahrať záznam trasy</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <Dropzone onDrop={this.onFileDrop} multiple={false} accept=".gpx" className="dropzone">

Potiahnite sem .gpx súbor, alebo sem kliknite pre jeho výber.

            </Dropzone>
          </Modal.Body>
          <Modal.Footer>
            <Button onClick={onClosePopup}><Glyphicon glyph="remove" /> Zrušiť</Button>
          </Modal.Footer>
        </Modal>

        <Modal show={activePopup === 'track-viewer-share'} onHide={onClosePopup}>
          <Modal.Header closeButton>
            <Modal.Title>Zdieľať záznam trasy</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            Trasa je dostupná na tejto adrese:
            <Alert>
              {shareURL}
            </Alert>
          </Modal.Body>
          <Modal.Footer>
            <Button onClick={onClosePopup}><Glyphicon glyph="remove" /> Zavrieť</Button>
          </Modal.Footer>
        </Modal>

    );
  }
}

TrackViewerMenu.propTypes = {
  activePopup: PropTypes.string,
  onCancel: PropTypes.func.isRequired,
  onClosePopup: PropTypes.func.isRequired,
  onLaunchPopup: PropTypes.func.isRequired,
  onTrackViewerSetData: PropTypes.func.isRequired,
  onLoadError: PropTypes.func.isRequired,
  onSetTrackUID: PropTypes.func.isRequired,
  onResetTrackUID: PropTypes.func.isRequired,
  trackGeojson: PropTypes.object,  // eslint-disable-line
  trackGpx: PropTypes.string,
  trackUID: PropTypes.string,
};

export default connect(
  state => ({
    activePopup: state.main.activePopup,
    trackGeojson: state.trackViewer.trackGeojson,
    trackGpx: state.trackViewer.trackGpx,
    trackUID: state.trackViewer.trackUID,
  }),
  dispatch => ({
    onCancel() {
      dispatch(trackViewerResetData());
      dispatch(setTool(null));
    },
    onLaunchPopup(popupName) {
      dispatch(setActivePopup(popupName));
    },
    onClosePopup() {
      dispatch(closePopup());
    },
    onTrackViewerSetData(gpx) {
      dispatch(trackViewerSetData(gpx));
    },
    onSetTrackUID(uid) {
      dispatch(trackViewerSetTrackUID(uid));
    },
    onResetTrackUID() {
      dispatch(trackViewerResetTrackUID());
    },
    onLoadError(message) {
      dispatch(toastsAdd({
        collapseKey: 'trackViewer.loadError',
        message,
        style: 'danger',
        timeout: 3000,
      }));
    },
  }),
)(TrackViewerMenu);
<commit_msg>#118: automatically open upload track popup when entering blank track viewer<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Dropzone from 'react-dropzone';

import Nav from 'react-bootstrap/lib/Nav';
import Navbar from 'react-bootstrap/lib/Navbar';
import NavItem from 'react-bootstrap/lib/NavItem';
import Button from 'react-bootstrap/lib/Button';
import Modal from 'react-bootstrap/lib/Modal';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import Alert from 'react-bootstrap/lib/Alert';

import FontAwesomeIcon from 'fm3/components/FontAwesomeIcon';

import { setTool, setActivePopup, closePopup } from 'fm3/actions/mainActions';
import { trackViewerSetData, trackViewerResetData, trackViewerSetTrackUID, trackViewerResetTrackUID } from 'fm3/actions/trackViewerActions';
import { toastsAdd } from 'fm3/actions/toastsActions';

import { getMapLeafletElement } from 'fm3/leafletElementHolder';
import { getNodejsBackendURL, MAX_GPX_TRACK_SIZE_IN_MB } from 'fm3/backendDefinitions';

import 'fm3/styles/trackViewer.scss';

class TrackViewerMenu extends React.Component {
  componentWillMount() {
    const startingWithBlankTrackViewer = this.props.trackUID === null;
    if (startingWithBlankTrackViewer) {
      this.props.onLaunchPopup('upload-track');
    }
  }

  componentWillReceiveProps(newProps) {
    if (newProps.trackGeojson && JSON.stringify(this.props.trackGeojson) !== JSON.stringify(newProps.trackGeojson)) {
      const geojsonBounds = L.geoJson(newProps.trackGeojson).getBounds();
      getMapLeafletElement().fitBounds(geojsonBounds);
    }
  }

  onFileDrop = (acceptedFiles, rejectedFiles) => {
    if (acceptedFiles.length > 0) {
      const reader = new FileReader();
      reader.readAsText(acceptedFiles[0], 'UTF-8');
      reader.onload = (event) => {
        const gpxAsString = event.target.result;
        this.props.onResetTrackUID();
        this.props.onTrackViewerSetData(gpxAsString);
        this.props.onClosePopup();
      };

      reader.onerror = (e) => {
        this.props.onLoadError(`Nepodarilo sa spracovať súbor: ${e && e.message}`);
      };
    }

    if (rejectedFiles.length) {
      this.props.onLoadError('Nesprávny formát súboru: Nahraný súbor musí mať príponu .gpx');
    }
  }

  shareTrack = () => {
    if (this.props.trackUID) {
      this.props.onLaunchPopup('track-viewer-share');
    } else if (this.props.trackGpx.length > (MAX_GPX_TRACK_SIZE_IN_MB * 1000000)) {
      this.props.onLoadError(`Veľkosť nahraného súboru prevyšuje ${MAX_GPX_TRACK_SIZE_IN_MB}MB. Zdieľanie podporujeme len pre menšie súbory.`);
    } else {
      fetch(`${getNodejsBackendURL()}/tracklogs`, {
        method: 'POST',
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          data: btoa(this.props.trackGpx),
          mediaType: 'application/gpx+xml',
        }),
      }).then(res => res.json())
      .then((res) => {
        this.props.onSetTrackUID(res.uid);
        this.props.onLaunchPopup('track-viewer-share');
      }).catch((e) => {
        this.props.onLoadError(`Nepodarilo sa nahrať súbor: ${e}`);
      });
    }
  }

  render() {
    const { activePopup, onCancel, onLaunchPopup, onClosePopup, trackGpx, trackUID } = this.props;

    let shareURL = '';
    if (trackUID) {
      shareURL = `${window.location.origin}/?tool=track-viewer&track-uid=${trackUID}`;
    }
    return (

        <Navbar.Form pullLeft>
          <Button onClick={() => onLaunchPopup('upload-track')}>
            <FontAwesomeIcon icon="upload" /> Nahrať trasu
          </Button>
          {' '}
          {trackGpx &&
            <Button onClick={this.shareTrack}>
              <FontAwesomeIcon icon="share-alt" /> Zdieľať
            </Button>
          }
        </Navbar.Form>

          <NavItem onClick={onCancel}><Glyphicon glyph="remove" /> Zavrieť</NavItem>

        <Modal show={activePopup === 'upload-track'} onHide={onClosePopup}>
          <Modal.Header closeButton>
            <Modal.Title>Nahrať záznam trasy</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <Dropzone onDrop={this.onFileDrop} multiple={false} accept=".gpx" className="dropzone">

Potiahnite sem .gpx súbor, alebo sem kliknite pre jeho výber.

            </Dropzone>
          </Modal.Body>
          <Modal.Footer>
            <Button onClick={onClosePopup}><Glyphicon glyph="remove" /> Zrušiť</Button>
          </Modal.Footer>
        </Modal>

        <Modal show={activePopup === 'track-viewer-share'} onHide={onClosePopup}>
          <Modal.Header closeButton>
            <Modal.Title>Zdieľať záznam trasy</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            Trasa je dostupná na nasledovnej adrese:
            <Alert>
              {shareURL}
            </Alert>
          </Modal.Body>
          <Modal.Footer>
            <Button onClick={onClosePopup}><Glyphicon glyph="remove" /> Zavrieť</Button>
          </Modal.Footer>
        </Modal>

    );
  }
}

TrackViewerMenu.propTypes = {
  activePopup: PropTypes.string,
  onCancel: PropTypes.func.isRequired,
  onClosePopup: PropTypes.func.isRequired,
  onLaunchPopup: PropTypes.func.isRequired,
  onTrackViewerSetData: PropTypes.func.isRequired,
  onLoadError: PropTypes.func.isRequired,
  onSetTrackUID: PropTypes.func.isRequired,
  onResetTrackUID: PropTypes.func.isRequired,
  trackGeojson: PropTypes.object,  // eslint-disable-line
  trackGpx: PropTypes.string,
  trackUID: PropTypes.string,
};

export default connect(
  state => ({
    activePopup: state.main.activePopup,
    trackGeojson: state.trackViewer.trackGeojson,
    trackGpx: state.trackViewer.trackGpx,
    trackUID: state.trackViewer.trackUID,
  }),
  dispatch => ({
    onCancel() {
      dispatch(trackViewerResetData());
      dispatch(setTool(null));
    },
    onLaunchPopup(popupName) {
      dispatch(setActivePopup(popupName));
    },
    onClosePopup() {
      dispatch(closePopup());
    },
    onTrackViewerSetData(gpx) {
      dispatch(trackViewerSetData(gpx));
    },
    onSetTrackUID(uid) {
      dispatch(trackViewerSetTrackUID(uid));
    },
    onResetTrackUID() {
      dispatch(trackViewerResetTrackUID());
    },
    onLoadError(message) {
      dispatch(toastsAdd({
        collapseKey: 'trackViewer.loadError',
        message,
        style: 'danger',
        timeout: 3000,
      }));
    },
  }),
)(TrackViewerMenu);
<|endoftext|>


<commit_before>'use strict';

var React = require('react');
var Reflux = require('reflux');
var d3 = require('d3');

var actions = require('../../actions/actions');
var Admin_store = require('../../stores/admin_store');
module.exports = React.createClass({
  mixins: [
    Reflux.connect(Admin_store, 'task')
  ],
  statics: {
    fetchData: function(params) {
      actions.getTasks(params.task);
    }
  },
  render: function() {
    var task = this.state.task;
    var info = '';

    if (typeof task !== 'undefined') {
      var dateDisplay = d3.time.format('%B %-d');
      var timeDisplay = d3.time.format('%-I:%-M%p');
      var actionDay = dateDisplay(new Date(task.updated * 1000));
      var actionTime = timeDisplay(new Date(task.updated * 1000));
      var status = '';
      (task.status) ? status = 'Completed': status = 'Still are items to work';
      info = (

                        Title

                        {task.title}

                        Id Task

                        {task.id}

                        Source

                        {task.source}

                        Description

                        {task.description}

                        Updated

                      {actionDay} {actionTime}

                        Status

                      {status}

      );
    }

    return (
        /* jshint ignore:start */

{info}

        /* jshint ignore:end */
    );

  }
});
<commit_msg>Better copy<commit_after>'use strict';

var React = require('react');
var Reflux = require('reflux');
var d3 = require('d3');

var actions = require('../../actions/actions');
var Admin_store = require('../../stores/admin_store');
module.exports = React.createClass({
  mixins: [
    Reflux.connect(Admin_store, 'task')
  ],
  statics: {
    fetchData: function(params) {
      actions.getTasks(params.task);
    }
  },
  render: function() {
    var task = this.state.task;
    var info = '';

    if (typeof task !== 'undefined') {
      var dateDisplay = d3.time.format('%B %-d');
      var timeDisplay = d3.time.format('%-I:%-M%p');
      var actionDay = dateDisplay(new Date(task.updated * 1000));
      var actionTime = timeDisplay(new Date(task.updated * 1000));
      var status = '';
      (task.status) ? status = 'Completed': status = 'Items remaining to be done';
      info = (

                        Title

                        {task.title}

                        Id Task

                        {task.id}

                        Source

                        {task.source}

                        Description

                        {task.description}

                        Updated

                      {actionDay} {actionTime}

                        Status

                      {status}

      );
    }

    return (
        /* jshint ignore:start */

{info}

        /* jshint ignore:end */
    );

  }
});
<|endoftext|>