<commit_before>var Board = require("../lib/board.js"),
    events = require("events"),
    util = require("util"),
    __ = require("../lib/fn.js");

function calculate( method, y, x ) {
  return Math[ method ]( y, x ) * 180 / Math.PI;
}

function acceleration( axis, vRange, sensitivity ) {
  var voltage;

  // convert raw reading to voltage
  // (read * vRange / 1024) - (vRange / 2)
  voltage = ( axis * vRange / 1024 ) - ( vRange / 2 );

  // 800mV sensitivity
  return voltage / sensitivity;
}

// Filter for change events
// Pass in data by type
// e.g. accel.get("smooth")
function axisChange( data, threshold ) {
  var changed, axes;
  axes = Object.keys(data);
  changed = axes.map(function( axis ) {
    var extent = data[ axis ].length - 1;
    return data[ axis ][ extent ] - data[ axis ][ extent - 1 ];
  });
  return changed.some(function( element ) {
    return Math.abs( element ) > threshold;
  });
}

// relatively terse updating function
// vs. this.data.thing.axis.whatever = value
// queue is the array on whatever object we want to update
function update( queue, value, extent ) {
  queue.push( value );
  if (queue.length > extent) {
    queue.shift();
  }
  return queue;
}

// build data based on types and axes passed in
// initialize at zero
function dataStr( types, axes ){
  var container = {};
  types.forEach(function( type ){
    container[ type ] = {};
    axes.forEach(function( axis ) {
      container[ type ][ axis ] = [ 0 ];
    });
  });
  return container;
}

/**
 * Accelerometer
 * @constructor
 *
 * five.Accelerometer([ x, y[, z] ]);
 *
 * five.Accelerometer({
 *   pins: [ x, y[, z] ]
 *   freq: ms
 *  });
 *
 *
 * @param {Object} opts [description]
 *
 */
function Accelerometer( opts ) {

  if ( !(this instanceof Accelerometer) ) {
    return new Accelerometer( opts );
  }

  var err = null;

  // Initialize a Device instance on a Board
  Board.Device.call(
    this, opts = Board.Options( opts )
  );

  this.mode = this.firmata.MODES.ANALOG;

  // Accelerometer instance properties
  this.voltage = opts.voltage || 3.3;
  this.sensitivity = opts.sensitivity || 0.8;
  this.freq = opts.freq || 50;
  // Threshold needs to be tested
  this.threshold = opts.threshold || 0.5;

  // axis keys
  this.axes = opts.axes || [ "x", "y", "z" ];
  // types (not really important unless you need them)
  this.types = opts.types || [ "smooth", "accel", "trend" ];
  // how many past values to store
  this.extent = opts.extent || 2;
  // some smoothing methods require bootstrapping
  this.initial = opts.initial || true;

  // build data based on types and axes passed in
  // initialize at zero
  this.data = dataStr( this.types, this.axes );

  // Blending property for the smoother.
  // Smaller is less filtering
  this.alpha = opts.alpha || 0.2;

  // default smoother is an exponential smoother
  this.smoother = opts.smoother || function( smopts ) {
    var smooth, accel;
    smooth = smopts.smooth;
    accel = smopts.accel;

    this.axes.forEach(function( axis ) {
      var acper, smper, currsm;
      // Exponential smoothing
      // see http://people.duke.edu/~rnau/411avg.htm
      acper = accel[ axis ];
      smper = smooth[ axis ];
      // bootstrap for initial state
      if ( smper.length < smopts.extent ) {
        smooth[ axis ] = update( smper, acper[ 0 ], smopts.extent );
      } else {
        // convolves past smoothed/nonsmooth readings
        currsm = smper[ 0 ] + smopts.alpha * ( acper[ 0 ] - smper[ 0 ] );
        // update current smoothed values
        smooth[ axis ] = update( smper , currsm, smopts.extent );
      }
    });
    return smooth;
  };

  // Setup read listeners for each pin, update instance
  // properties as they are received. Special values are
  // calculated during the throttled event emit phase
  this.pins.forEach(function( pin, index ) {

    // Set the pin to input mode to ANALOG
    this.firmata.pinMode( pin, this.mode );

    this.firmata.analogRead( pin, function( data ) {
      var paxis, accel, sink;
      paxis = this.axes[ index ];
      accel = acceleration( data, this.voltage, this.sensitivity );
      sink = this.data.accel[ paxis ];
      // The output we're interested in most of the time
      this.data.accel[ paxis ] = update( sink , accel, this.extent );

    }.bind( this ));

  }, this );

  // Throttle event emitter
  setInterval(function() {
    this.data.smooth = this.smoother( {
      accel: this.data.accel,
      smooth: this.data.smooth,
      alpha: this.alpha,
      extent: this.extent
    });
    var data = {
      smooth: this.data.smooth,
      rough: this.data.accel
    };

    // Check each axis for change above some threshold
    if ( axisChange( this.data.accel, this.threshold ) ) {
      [ "axischange", "change" ].forEach(function( type ) {
        this.emit( type, err, data );
      }, this);
    }

    this.emit( "acceleration", err, data );

  }.bind(this), this.freq );

  /**
   * raw x, y, z data
   * @property raw
   * @type Object
   */

  /**
   * smooth x, y, z data
   * @property smooth
   * @type Object
   */

  /**
   * accel calculated x, y, z data
   * @property axis
   * @type Object
   */

  Object.defineProperties( this, {
    /**
     * [read-only] Calculated pitch value
     * @property pitch
     * @type Number
     */
    pitch: {
      get: function() {
        var x, y, z, accel;
        accel = this.data.accel;
        x = accel.x[ 1 ];
        y = accel.y[ 1 ];
        z = this.axes.indexOf( "z" ) > -1 ? accel.z[ 1 ]: 0;
        return Math.abs(
          Math.atan2(
            x,
            Math.sqrt( Math.pow( y, 2 ) + Math.pow( z, 2 ) )
          )
        );
      }
    },
    /**
     * [read-only] Calculated roll value
     * @property roll
     * @type Number
     */
    roll: {
      get: function() {
        var x, y, z, accel;
        accel = this.data.accel;
        x = accel.x[ 1 ];
        y = accel.y[ 1 ];
        z = this.axes.indexOf( "z" ) > -1 ? accel.z[ 1 ]: 0;
        return Math.abs(
          Math.atan2(
            y,
            Math.sqrt( Math.pow( x, 2 ) + Math.pow( z, 2 ) )
          )
        );
      }
    }
  });
}

util.inherits( Accelerometer, events.EventEmitter );

Object.defineProperty( Accelerometer, "G", {
  /**
   * [read-only] One g is the acceleration due to gravity at the Earth's surface
   *
   * meters/s ^ 2
   *
   * @property G
   * @type Number
   */
  value: 9.81
});

/**
 * Fires once every N ms, equal to value of `freq`. Defaults to 500ms
 *
 * @event
 * @name acceleration
 * @memberOf Accelerometer
 */

/**
 * Fires only when X, Y or Z has changed
 *
 * @event
 * @name axischange
 * @memberOf Accelerometer
 */

module.exports = Accelerometer;

// References
//
// http://www.instructables.com/id/Accelerometer-Gyro-Tutorial/
//
// Images
//
// http://www.instructables.com/image/F7NMMPEG4PBOJPY/The-Accelerometer.jpg
<commit_msg>move smoother out of constructor.<commit_after>var Board = require("../lib/board.js"),
    events = require("events"),
    util = require("util"),
    __ = require("../lib/fn.js");

function calculate( method, y, x ) {
  return Math[ method ]( y, x ) * 180 / Math.PI;
}

function acceleration( axis, vRange, sensitivity ) {
  var voltage;

  // convert raw reading to voltage
  // (read * vRange / 1024) - (vRange / 2)
  voltage = ( axis * vRange / 1024 ) - ( vRange / 2 );

  // 800mV sensitivity
  return voltage / sensitivity;
}

// Filter for change events
// Pass in data by type
// e.g. accel.get("smooth")
function axisChange( data, threshold ) {
  var changed, axes;
  axes = Object.keys(data);
  changed = axes.map(function( axis ) {
    var extent = data[ axis ].length - 1;
    return data[ axis ][ extent ] - data[ axis ][ extent - 1 ];
  });
  return changed.some(function( element ) {
    return Math.abs( element ) > threshold;
  });
}

// relatively terse updating function
// vs. this.data.thing.axis.whatever = value
// queue is the array on whatever object we want to update
function update( queue, value, extent ) {
  queue.push( value );
  if (queue.length > extent) {
    queue.shift();
  }
  return queue;
}

// build data based on types and axes passed in
// initialize at zero
function dataStr( types, axes ){
  var container = {};
  types.forEach(function( type ){
    container[ type ] = {};
    axes.forEach(function( axis ) {
      container[ type ][ axis ] = [ 0 ];
    });
  });
  return container;
}

/* Expects an options argument e.g.
{
  accel: this.data.accel,
  smooth: this.data.smooth,
  alpha: this.alpha,
  extent: this.extent
}
*/

function exponential( smopts ) {
  var smooth, accel;
  smooth = smopts.smooth;
  accel = smopts.accel;

  this.axes.forEach(function( axis ) {
    var acper, smper, currsm;
    // Exponential smoothing
    // see http://people.duke.edu/~rnau/411avg.htm
    acper = accel[ axis ];
    smper = smooth[ axis ];
    // bootstrap for initial state
    if ( smper.length < smopts.extent ) {
      smooth[ axis ] = update( smper, acper[ 0 ], smopts.extent );
    } else {
      // convolves past smoothed/nonsmooth readings
      currsm = smper[ 0 ] + smopts.alpha * ( acper[ 0 ] - smper[ 0 ] );
      // update current smoothed values
      smooth[ axis ] = update( smper , currsm, smopts.extent );
    }
  });
  return smooth;
};

/**
 * Accelerometer
 * @constructor
 *
 * five.Accelerometer([ x, y[, z] ]);
 *
 * five.Accelerometer({
 *   pins: [ x, y[, z] ]
 *   freq: ms
 *  });
 *
 *
 * @param {Object} opts [description]
 *
 */
function Accelerometer( opts ) {

  if ( !(this instanceof Accelerometer) ) {
    return new Accelerometer( opts );
  }

  var err = null;

  // Initialize a Device instance on a Board
  Board.Device.call(
    this, opts = Board.Options( opts )
  );

  this.mode = this.firmata.MODES.ANALOG;

  // Accelerometer instance properties
  this.voltage = opts.voltage || 3.3;
  this.sensitivity = opts.sensitivity || 0.8;
  this.freq = opts.freq || 50;
  // Threshold needs to be tested
  this.threshold = opts.threshold || 0.5;

  // axis keys
  this.axes = opts.axes || [ "x", "y", "z" ];
  // types (not really important unless you need them)
  this.types = opts.types || [ "smooth", "accel", "trend" ];
  // how many past values to store
  this.extent = opts.extent || 2;
  // some smoothing methods require bootstrapping
  this.initial = opts.initial || true;

  // build data based on types and axes passed in
  // initialize at zero
  this.data = dataStr( this.types, this.axes );

  // Blending property for the smoother.
  // Smaller is less filtering
  this.alpha = opts.alpha || 0.2;

  // default smoother is an exponential smoother
  this.smoother = opts.smoother || exponential;

  // Setup read listeners for each pin, update instance
  // properties as they are received. Special values are
  // calculated during the throttled event emit phase
  this.pins.forEach(function( pin, index ) {

    // Set the pin to input mode to ANALOG
    this.firmata.pinMode( pin, this.mode );

    this.firmata.analogRead( pin, function( data ) {
      var paxis, accel, sink;
      paxis = this.axes[ index ];
      accel = acceleration( data, this.voltage, this.sensitivity );
      sink = this.data.accel[ paxis ];
      // The output we're interested in most of the time
      this.data.accel[ paxis ] = update( sink , accel, this.extent );

    }.bind( this ));

  }, this );

  // Throttle event emitter
  setInterval(function() {
    this.data.smooth = this.smoother({
      accel: this.data.accel,
      smooth: this.data.smooth,
      alpha: this.alpha,
      extent: this.extent
    });
    var data = {
      smooth: this.data.smooth,
      rough: this.data.accel
    };

    // Check each axis for change above some threshold
    if ( axisChange( this.data.accel, this.threshold ) ) {
      [ "axischange", "change" ].forEach(function( type ) {
        this.emit( type, err, data );
      }, this);
    }

    this.emit( "acceleration", err, data );

  }.bind(this), this.freq );

  /**
   * raw x, y, z data
   * @property raw
   * @type Object
   */

  /**
   * smooth x, y, z data
   * @property smooth
   * @type Object
   */

  /**
   * accel calculated x, y, z data
   * @property axis
   * @type Object
   */

  Object.defineProperties( this, {
    /**
     * [read-only] Calculated pitch value
     * @property pitch
     * @type Number
     */
    pitch: {
      get: function() {
        var x, y, z, accel;
        accel = this.data.accel;
        x = accel.x[ 1 ];
        y = accel.y[ 1 ];
        z = this.axes.indexOf( "z" ) > -1 ? accel.z[ 1 ]: 0;
        return Math.abs(
          Math.atan2(
            x,
            Math.sqrt( Math.pow( y, 2 ) + Math.pow( z, 2 ) )
          )
        );
      }
    },
    /**
     * [read-only] Calculated roll value
     * @property roll
     * @type Number
     */
    roll: {
      get: function() {
        var x, y, z, accel;
        accel = this.data.accel;
        x = accel.x[ 1 ];
        y = accel.y[ 1 ];
        z = this.axes.indexOf( "z" ) > -1 ? accel.z[ 1 ]: 0;
        return Math.abs(
          Math.atan2(
            y,
            Math.sqrt( Math.pow( x, 2 ) + Math.pow( z, 2 ) )
          )
        );
      }
    }
  });
}

util.inherits( Accelerometer, events.EventEmitter );

Object.defineProperty( Accelerometer, "G", {
  /**
   * [read-only] One g is the acceleration due to gravity at the Earth's surface
   *
   * meters/s ^ 2
   *
   * @property G
   * @type Number
   */
  value: 9.81
});

/**
 * Fires once every N ms, equal to value of `freq`. Defaults to 500ms
 *
 * @event
 * @name acceleration
 * @memberOf Accelerometer
 */

/**
 * Fires only when X, Y or Z has changed
 *
 * @event
 * @name axischange
 * @memberOf Accelerometer
 */

module.exports = Accelerometer;

// References
//
// http://www.instructables.com/id/Accelerometer-Gyro-Tutorial/
//
// Images
//
// http://www.instructables.com/image/F7NMMPEG4PBOJPY/The-Accelerometer.jpg
<|endoftext|>


<commit_before>/*
 *
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
*/
/**
 *  ScaleDialog.js
 *
 *  Created by Julia Svinareva on 21/08/19
 *  Copyright (c) 2019 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'common/main/lib/component/Window',
    'common/main/lib/component/MetricSpinner'
], function () { 'use strict';

    SSE.Views.ScaleDialog = Common.UI.Window.extend(_.extend({
        options: {
            width: 215,
            header: true,
            style: 'min-width: 215px;',
            cls: 'modal-dlg'
        },

        initialize : function(options) {
            _.extend(this.options, {
                title: this.textTitle
            }, options || {});

            this._state = {
                width: null,
                height: null
            };

            this.template = [
                '
',
                '

',
                '
',
                    '
',
                        '' + this.textWidth + '',
                        '

',
                    '
',
                    '
',
                        '' + this.textHeight + '',
                        '

',
                    '
',
                '
',
                '

',
                '

',
                '
',
                '
',
                '<button class="btn normal dlg-btn primary" result="ok" style="margin-right: 10px;">' + this.okButtonText + '</button>',
                '<button class="btn normal dlg-btn" result="cancel">' + this.cancelButtonText + '</button>',
                '
'
            ].join('');

            this.options.tpl = _.template(this.template)(this.options);

            this.api = this.options.api;
            this._originalProps = this.options.props;

            this.arrDataScale = [
                {displayValue: this.textAuto, value: 0},
                {displayValue: '1 ' + this.textOnePage, value: 1},
                {displayValue: '2 ' + this.textFewPages, value: 2},
                {displayValue: '3 ' + this.textFewPages, value: 3},
                {displayValue: '4 ' + this.textFewPages, value: 4},
                {displayValue: '5 ' + this.textManyPages, value: 5},
                {displayValue: '6 ' + this.textManyPages, value: 6},
                {displayValue: '7 ' + this.textManyPages, value: 7},
                {displayValue: '8 ' + this.textManyPages, value: 8},
                {displayValue: '9 ' + this.textManyPages, value: 9}
            ];

            Common.UI.Window.prototype.initialize.call(this, this.options);
        },

        render: function() {
            Common.UI.Window.prototype.render.call(this);

            this.radioFitTo = new Common.UI.RadioBox({
                el: $('#radio-fit-to'),
                labelText: this.textFitTo,
                name: 'asc-radio-scale'
            });
            this.radioFitTo.on('change', _.bind(this.onRadioScale, this, 'fitto'));

            this.radioScaleTo = new Common.UI.RadioBox({
                el: $('#radio-scale-to'),
                labelText: this.textScaleTo,
                name: 'asc-radio-scale'
            });
            this.radioScaleTo.on('change', _.bind(this.onRadioScale, this, 'scaleto'));

            this.cmbScaleWidth = new Common.UI.ComboBox({
                el: $('#scale-width'),
                cls: 'input-group-nr',
                style: 'width: 90px;',
                menuStyle   : 'min-width: 90px;',
                editable: true,
                data: this.arrDataScale,
                scrollAlwaysVisible: true
            }).on('selected', _.bind(function (field) {
                this._state.width = field.getValue();
                if ((this._state.width === 0 || this._state.width === null) && (this._state.height === 0 || this._state.height === null)) {
                    this.radioScaleTo.setValue(true, true);
                } else {
                    this.radioFitTo.setValue(true, true);
                }
                }, this))
                .on('changed:before', _.bind(this.onChangeComboScale, this, 'width'));

            this.cmbScaleHeight = new Common.UI.ComboBox({
                el: $('#scale-height'),
                cls: 'input-group-nr',
                style: 'width: 90px;',
                menuStyle   : 'min-width: 90px;',
                editable: true,
                data: this.arrDataScale,
                scrollAlwaysVisible: true
            }).on('selected', _.bind(function (field) {
                this._state.height = field.getValue();
                if ((this._state.width === 0 || this._state.width === null) && (this._state.height === 0 || this._state.height === null)) {
                    this.radioScaleTo.setValue(true, true);
                } else {
                    this.radioFitTo.setValue(true, true);
                }
                }, this))
                .on('changed:before', _.bind(this.onChangeComboScale, this, 'height'));

            this.spnScale = new Common.UI.MetricSpinner({
                el          : $('#scale'),
                step        : 1,
                width       : 75,
                defaultUnit : "%",
                maxValue    : 400,
                minValue    : 10,
                defaultValue: '100 %'
            }).on('change', _.bind(function (field) {
                this.radioScaleTo.setValue(true, true);
                this.cmbScaleHeight.setValue(0,true);
                this.cmbScaleWidth.setValue(0,true);
                this._state.width = 0;
                this._state.height = 0;
            }, this));

            var $window = this.getChild();
            $window.find('.dlg-btn').on('click', _.bind(this.onBtnClick, this));

            this.afterRender();
        },

        afterRender: function() {
            this._setDefaults(this._originalProps);
        },

        _handleInput: function(state) {
            if (this.options.handler) {
                this.options.handler.call(this, state,  (state == 'ok') ? this.getSettings() : undefined);
            }
            this.close();
        },

        onBtnClick: function(event) {
            this._handleInput(event.currentTarget.attributes['result'].value);
        },

        onPrimary: function() {
            this._handleInput('ok');
            return false;
        },

        onRadioScale: function(type, field, newValue) {
            if (type === 'scaleto') {
                this.cmbScaleHeight.setValue(0,true);
                this._state.height = 0;
                this.cmbScaleWidth.setValue(0,true);
                this._state.width = 0;
            } else {
                this.cmbScaleHeight.setValue(0,true);
                this._state.height = 0;
                this.cmbScaleWidth.setValue(1,true);
                this._state.width = 1;
            }
        },

        _setDefaults: function (props) {
            if (this.api) {
                var pageProps = props ? props : this.api.asc_getPageOptions();
                var pageSetup = pageProps.asc_getPageSetup(),
                    width = pageSetup.asc_getFitToWidth(),
                    height = pageSetup.asc_getFitToHeight(),
                    scale = pageSetup.asc_getScale();
                this._state.width = (width !== null && width !== 0) ? width : null;
                this._state.height = (height !== null && height !== 0) ? height : null;

                width = (width !== null) ? width : 0;
                height = (height !== null) ? height : 0;

                if (width === 0 && height === 0) {
                    this.radioScaleTo.setValue(true,true);
                } else {
                    this.radioFitTo.setValue(true,true);
                }

                if (_.findWhere(this.arrDataScale, {value: width})) {
                    this.cmbScaleWidth.setValue(width);
                } else {
                    this.cmbScaleWidth.setRawValue(width.toString() + ' ' + this.getTextPages(width));
                }
                if (_.findWhere(this.arrDataScale, {value: height})) {
                    this.cmbScaleHeight.setValue(height);
                } else {
                    this.cmbScaleHeight.setRawValue(height.toString() + ' ' + this.getTextPages(height));
                }

                this.spnScale.setValue((scale !== null) ? scale : '', true);
            }
        },

        getSettings: function () {
            var props = {};
            props.width = (this._state.width === null) ? null : this._state.width;
            props.height = (this._state.height === null) ? null : this._state.height;
            props.scale = this.spnScale.getNumberValue();
            return props;
        },

        getTextPages: function (val) {
            var lastNum = val % 10,
                textPage;
            if (lastNum > 0 && lastNum < 1.001) {
                textPage = this.textOnePage;
            } else if (lastNum > 0 && lastNum < 4.001) {
                textPage = this.textFewPages;
            } else {
                textPage = this.textManyPages;
            }
            return textPage;
        },

        onChangeComboScale: function(type, combo, record, e) {
            var me = this,
                textPage,
                value = record.value.toLowerCase();
            var exprAuto = new RegExp('^\\s*(' + me.textAuto.toLowerCase() + ')\\s*$');
            if (exprAuto.exec(value)) {
                value = 0;
            } else {
                value = parseInt(value);
                !isNaN(value) && (textPage = me.getTextPages(value));
            }
            if (isNaN(value) || value < 0 || value > 32767) {
                Common.UI.error({
                    msg: me.textError,
                    callback: function() {
                        _.defer(function(btn) {
                            Common.NotificationCenter.trigger('edit:complete', me);
                        })
                    }
                });
                value = (type === 'width') ? me._state.width : me._state.height;
                textPage = me.getTextPages(value);
            }
            if (value === null) value = 0;
            if (type === 'width') {
                if (_.findWhere(me.arrDataScale, {value: value})) {
                    me.cmbScaleWidth.setValue(value);
                } else {
                    me.cmbScaleWidth.setValue('');
                    me.cmbScaleWidth.setRawValue(value.toString() + ' ' + textPage);
                }
                me._state.width = value;
            } else if (type === 'height') {
                if (_.findWhere(me.arrDataScale, {value: value})) {
                    me.cmbScaleHeight.setValue(value);
                } else {
                    me.cmbScaleHeight.setValue('');
                    me.cmbScaleHeight.setRawValue(value.toString() + ' ' + textPage);
                }
                me._state.height = value;
            }
        },

        textTitle: 'Scale Settings',
        cancelButtonText: 'Cancel',
        okButtonText:   'Ok',
        textWidth: 'Width',
        textHeight: 'Height',
        textAuto: 'Auto',
        textOnePage: 'page',
        textFewPages: 'pages',
        textManyPages: 'pages',
        textError: 'The entered value is incorrect.',
        textScaleTo: 'Scale To',
        textFitTo: 'Fit To'

    }, SSE.Views.ScaleDialog || {}))
});<commit_msg>[SSE] Scale Settings<commit_after>/*
 *
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
*/
/**
 *  ScaleDialog.js
 *
 *  Created by Julia Svinareva on 21/08/19
 *  Copyright (c) 2019 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'common/main/lib/component/Window',
    'common/main/lib/component/MetricSpinner'
], function () { 'use strict';

    SSE.Views.ScaleDialog = Common.UI.Window.extend(_.extend({
        options: {
            width: 215,
            header: true,
            style: 'min-width: 215px;',
            cls: 'modal-dlg'
        },

        initialize : function(options) {
            _.extend(this.options, {
                title: this.textTitle
            }, options || {});

            this._state = {
                width: null,
                height: null
            };

            this.template = [
                '
',
                '

',
                '
',
                    '
',
                        '' + this.textWidth + '',
                        '

',
                    '
',
                    '
',
                        '' + this.textHeight + '',
                        '

',
                    '
',
                '
',
                '

',
                '

',
                '
',
                '
',
                '<button class="btn normal dlg-btn primary" result="ok" style="margin-right: 10px;">' + this.okButtonText + '</button>',
                '<button class="btn normal dlg-btn" result="cancel">' + this.cancelButtonText + '</button>',
                '
'
            ].join('');

            this.options.tpl = _.template(this.template)(this.options);

            this.api = this.options.api;
            this._originalProps = this.options.props;

            this.arrDataScale = [
                {displayValue: this.textAuto, value: 0},
                {displayValue: '1 ' + this.textOnePage, value: 1},
                {displayValue: '2 ' + this.textFewPages, value: 2},
                {displayValue: '3 ' + this.textFewPages, value: 3},
                {displayValue: '4 ' + this.textFewPages, value: 4},
                {displayValue: '5 ' + this.textManyPages, value: 5},
                {displayValue: '6 ' + this.textManyPages, value: 6},
                {displayValue: '7 ' + this.textManyPages, value: 7},
                {displayValue: '8 ' + this.textManyPages, value: 8},
                {displayValue: '9 ' + this.textManyPages, value: 9}
            ];

            Common.UI.Window.prototype.initialize.call(this, this.options);
        },

        render: function() {
            Common.UI.Window.prototype.render.call(this);

            this.radioFitTo = new Common.UI.RadioBox({
                el: $('#radio-fit-to'),
                labelText: this.textFitTo,
                name: 'asc-radio-scale'
            });
            this.radioFitTo.on('change', _.bind(this.onRadioScale, this, 'fitto'));

            this.radioScaleTo = new Common.UI.RadioBox({
                el: $('#radio-scale-to'),
                labelText: this.textScaleTo,
                name: 'asc-radio-scale'
            });
            this.radioScaleTo.on('change', _.bind(this.onRadioScale, this, 'scaleto'));

            this.cmbScaleWidth = new Common.UI.ComboBox({
                el: $('#scale-width'),
                cls: 'input-group-nr',
                style: 'width: 90px;',
                menuStyle   : 'min-width: 90px;',
                editable: true,
                data: this.arrDataScale,
                scrollAlwaysVisible: true
            }).on('selected', _.bind(this.changeWidthHeight, this, 'width'))
              .on('changed:after', _.bind(this.changeWidthHeight, this, 'width'))
              .on('changed:before', _.bind(this.onChangeComboScale, this, 'width'));

            this.cmbScaleHeight = new Common.UI.ComboBox({
                el: $('#scale-height'),
                cls: 'input-group-nr',
                style: 'width: 90px;',
                menuStyle   : 'min-width: 90px;',
                editable: true,
                data: this.arrDataScale,
                scrollAlwaysVisible: true
            }).on('selected', _.bind(this.changeWidthHeight, this, 'height'))
              .on('changed:after', _.bind(this.changeWidthHeight, this, 'height'))
              .on('changed:before', _.bind(this.onChangeComboScale, this, 'height'));

            this.spnScale = new Common.UI.MetricSpinner({
                el          : $('#scale'),
                step        : 1,
                width       : 75,
                defaultUnit : "%",
                maxValue    : 400,
                minValue    : 10,
                defaultValue: '100 %'
            }).on('change', _.bind(function (field) {
                this.radioScaleTo.setValue(true, true);
                this.cmbScaleHeight.setValue(0,true);
                this.cmbScaleWidth.setValue(0,true);
                this._state.width = 0;
                this._state.height = 0;
            }, this));

            var $window = this.getChild();
            $window.find('.dlg-btn').on('click', _.bind(this.onBtnClick, this));

            this.afterRender();
        },

        afterRender: function() {
            this._setDefaults(this._originalProps);
        },

        _handleInput: function(state) {
            if (this.options.handler) {
                this.options.handler.call(this, state,  (state == 'ok') ? this.getSettings() : undefined);
            }
            this.close();
        },

        onBtnClick: function(event) {
            this._handleInput(event.currentTarget.attributes['result'].value);
        },

        onPrimary: function() {
            this._handleInput('ok');
            return false;
        },

        changeWidthHeight: function (type, field) {
            var value = field.getValue();
            if (typeof(value) === 'string') {
                value = parseInt(value);
                if (isNaN(value)) {
                    value = 0;
                }
            }
            if (type === 'width') {
                this._state.width = value;
            } else {
                this._state.height = value;
            }
            if ((this._state.width === 0 || this._state.width === null) && (this._state.height === 0 || this._state.height === null)) {
                this.radioScaleTo.setValue(true, true);
            } else {
                this.radioFitTo.setValue(true, true);
            }
        },

        onRadioScale: function(type, field, newValue) {
            if (type === 'scaleto') {
                this.cmbScaleHeight.setValue(0,true);
                this._state.height = 0;
                this.cmbScaleWidth.setValue(0,true);
                this._state.width = 0;
            } else {
                this.cmbScaleHeight.setValue(0,true);
                this._state.height = 0;
                this.cmbScaleWidth.setValue(1,true);
                this._state.width = 1;
            }
        },

        _setDefaults: function (props) {
            if (this.api) {
                var pageProps = props ? props : this.api.asc_getPageOptions();
                var pageSetup = pageProps.asc_getPageSetup(),
                    width = pageSetup.asc_getFitToWidth(),
                    height = pageSetup.asc_getFitToHeight(),
                    scale = pageSetup.asc_getScale();
                this._state.width = (width !== null && width !== 0) ? width : null;
                this._state.height = (height !== null && height !== 0) ? height : null;

                width = (width !== null) ? width : 0;
                height = (height !== null) ? height : 0;

                if (width === 0 && height === 0) {
                    this.radioScaleTo.setValue(true,true);
                } else {
                    this.radioFitTo.setValue(true,true);
                }

                if (_.findWhere(this.arrDataScale, {value: width})) {
                    this.cmbScaleWidth.setValue(width);
                } else {
                    this.cmbScaleWidth.setRawValue(width.toString() + ' ' + this.getTextPages(width));
                }
                if (_.findWhere(this.arrDataScale, {value: height})) {
                    this.cmbScaleHeight.setValue(height);
                } else {
                    this.cmbScaleHeight.setRawValue(height.toString() + ' ' + this.getTextPages(height));
                }

                this.spnScale.setValue((scale !== null) ? scale : '', true);
            }
        },

        getSettings: function () {
            var props = {};
            props.width = (this._state.width === null) ? null : this._state.width;
            props.height = (this._state.height === null) ? null : this._state.height;
            props.scale = this.spnScale.getNumberValue();
            return props;
        },

        getTextPages: function (val) {
            var lastNum = val % 10,
                textPage;
            if (lastNum > 0 && lastNum < 1.001) {
                textPage = this.textOnePage;
            } else if (lastNum > 0 && lastNum < 4.001) {
                textPage = this.textFewPages;
            } else {
                textPage = this.textManyPages;
            }
            return textPage;
        },

        onChangeComboScale: function(type, combo, record, e) {
            var me = this,
                textPage,
                value = record.value.toLowerCase();
            var exprAuto = new RegExp('^\\s*(' + me.textAuto.toLowerCase() + ')\\s*$');
            if (exprAuto.exec(value)) {
                value = 0;
            } else {
                value = parseInt(value);
                !isNaN(value) && (textPage = me.getTextPages(value));
            }
            if (isNaN(value) || value < 0 || value > 32767) {
                Common.UI.error({
                    msg: me.textError,
                    callback: function() {
                        _.defer(function(btn) {
                            Common.NotificationCenter.trigger('edit:complete', me);
                        })
                    }
                });
                value = (type === 'width') ? me._state.width : me._state.height;
                textPage = me.getTextPages(value);
            }
            if (value === null) value = 0;
            if (type === 'width') {
                if (_.findWhere(me.arrDataScale, {value: value})) {
                    me.cmbScaleWidth.setValue(value);
                } else {
                    me.cmbScaleWidth.setValue('');
                    me.cmbScaleWidth.setRawValue(value.toString() + ' ' + textPage);
                }
                me._state.width = value;
            } else if (type === 'height') {
                if (_.findWhere(me.arrDataScale, {value: value})) {
                    me.cmbScaleHeight.setValue(value);
                } else {
                    me.cmbScaleHeight.setValue('');
                    me.cmbScaleHeight.setRawValue(value.toString() + ' ' + textPage);
                }
                me._state.height = value;
            }
        },

        textTitle: 'Scale Settings',
        cancelButtonText: 'Cancel',
        okButtonText:   'Ok',
        textWidth: 'Width',
        textHeight: 'Height',
        textAuto: 'Auto',
        textOnePage: 'page',
        textFewPages: 'pages',
        textManyPages: 'pages',
        textError: 'The entered value is incorrect.',
        textScaleTo: 'Scale To',
        textFitTo: 'Fit To'

    }, SSE.Views.ScaleDialog || {}))
});<|endoftext|>


<commit_before>// Copyright 2016, EMC Inc.

'use strict';

var injector = require('../../../index.js').injector;
var controller = injector.get('Http.Services.Swagger').controller;
var _ = injector.get('_'); // jshint ignore:line
var configuration = injector.get('Services.Configuration');
var accountService = injector.get('Http.Services.Api.Account');
var Errors = injector.get('Errors');
var Promise = injector.get('Promise');
var assert = injector.get('Assert');

var addUser = controller({success: 201}, function(req, res) {
    var userObj = _.pick(req.swagger.params.body.value, ['username', 'password', 'role']);
    var localUserException = configuration.get('enableLocalHostException', true);
    userObj.role = userObj.role || 'ReadOnly';  //TODO: move to Constants when Role code is added

    return Promise.try(function() {
        assert.string(userObj.username);
        assert.string(userObj.password);
        assert.string(userObj.role);
        return accountService.listUsers();
    })
    .then(function(users) {
        if(!users.length && localUserException && res.locals.ipAddress === '127.0.0.1') {
            // Only when there are no users, and the remote is a local connection, and we
            // permit it, then let them add the first user.
            return accountService.createUser(userObj)
            .then(function(user) {
                return _.pick(user, ['username', 'role']);
            });
        }

        if( !_.find(users, function(user) {
            return user.username === userObj.username;
        })) {
            if( req.isAuthenticated && req.isAuthenticated() ) {
                return accountService.createUser(userObj)
                .then(function(user) {
                    return _.pick(user, ['username', 'role']);
                });
            }
        }

        throw new Errors.UnauthorizedError('Unauthorized');
    });
});

var modifyUser = controller(function(req) {
    var name = req.swagger.params.name.value;
    var userObj = _.pick(req.swagger.params.body.value, ['password', 'role']);
    var configureUsersAllows = ['password', 'role'];
    var configureSelfAllows = ['password'];

    return Promise.try(function() {
        if(!req.isAuthenticated || !req.isAuthenticated()) {
            throw new Errors.UnauthorizedError('Unauthorized');
        }
        return accountService.getUserByName(name);
    })
    .then(function(entry) {
        if(!entry) {
            throw new Error.NotFoundError();
        }

        if(req.hasRole('Administrator') || req.hasRole('ConfigureUsers')) {
            if( Object.keys(_.omit(req.swagger.params.body.value, configureUsersAllows)).length !== 0 ) {
                throw new Errors.BadRequestError('Bad Request');
            }
            return accountService.modifyUserByName(name, userObj);
        } else if(req.user === entry.username && req.hasRole('ConfigureSelf')) {
            if( Object.keys(_.omit(req.swagger.params.body.value, configureSelfAllows)).length !== 0 ) {
                throw new Errors.BadRequestError('Bad Request');
            }
            return accountService.modifyUserByName(name, _.pick(userObj, 'password'));
        }
        throw new Errors.ForbiddenError('Forbidden');
    });
});

var listUsers = controller(function() {
    return accountService.listUsers();
});

var getUser = controller(function(req) {
    var name = req.swagger.params.name.value;
    return accountService.getUserByName(name);
});

var removeUser = controller({success: 204}, function(req) {
    var name = req.swagger.params.name.value;
    return accountService.removeUserByName(name);
});

module.exports = {
    addUser: addUser,
    modifyUser: modifyUser,
    listUsers: listUsers,
    getUser: getUser,
    removeUser: removeUser
};
<commit_msg>Allow backdoor process, to create Administrator user<commit_after>// Copyright 2016, EMC Inc.

'use strict';

var injector = require('../../../index.js').injector;
var controller = injector.get('Http.Services.Swagger').controller;
var _ = injector.get('_'); // jshint ignore:line
var configuration = injector.get('Services.Configuration');
var accountService = injector.get('Http.Services.Api.Account');
var Errors = injector.get('Errors');
var Promise = injector.get('Promise');
var assert = injector.get('Assert');

var addUser = controller({success: 201}, function(req, res) {
    var userObj = _.pick(req.swagger.params.body.value, ['username', 'password', 'role']);
    var localUserException = configuration.get('enableLocalHostException', true);
    userObj.role = userObj.role || 'ReadOnly';  //TODO: move to Constants when Role code is added

    return Promise.try(function() {
        assert.string(userObj.username);
        assert.string(userObj.password);
        assert.string(userObj.role);
        return accountService.listUsers();
    })
    .then(function(users) {
        if((!users.length && localUserException && res.locals.ipAddress === '127.0.0.1') || _.isEmpty(_.filter(users, {role: 'Administrator'}))) {
            // Only when there are no users, and the remote is a local connection, and we
            // permit it, then let them add the first user.
            // Added backdoor process to add an Administrator, in case there are none.
            return accountService.createUser(userObj)
            .then(function(user) {
                return _.pick(user, ['username', 'role']);
            });
        }

        if( !_.find(users, function(user) {
            return user.username === userObj.username;
        })) {
            if( req.isAuthenticated && req.isAuthenticated() ) {
                return accountService.createUser(userObj)
                .then(function(user) {
                    return _.pick(user, ['username', 'role']);
                });
            }
        }

        throw new Errors.UnauthorizedError('Unauthorized');
    });
});

var modifyUser = controller(function(req) {
    var name = req.swagger.params.name.value;
    var userObj = _.pick(req.swagger.params.body.value, ['password', 'role']);
    var configureUsersAllows = ['password', 'role'];
    var configureSelfAllows = ['password'];

    return Promise.try(function() {
        if(!req.isAuthenticated || !req.isAuthenticated()) {
            throw new Errors.UnauthorizedError('Unauthorized');
        }
        return accountService.getUserByName(name);
    })
    .then(function(entry) {
        if(!entry) {
            throw new Error.NotFoundError();
        }

        if(req.hasRole('Administrator') || req.hasRole('ConfigureUsers')) {
            if( Object.keys(_.omit(req.swagger.params.body.value, configureUsersAllows)).length !== 0 ) {
                throw new Errors.BadRequestError('Bad Request');
            }
            return accountService.modifyUserByName(name, userObj);
        } else if(req.user === entry.username && req.hasRole('ConfigureSelf')) {
            if( Object.keys(_.omit(req.swagger.params.body.value, configureSelfAllows)).length !== 0 ) {
                throw new Errors.BadRequestError('Bad Request');
            }
            return accountService.modifyUserByName(name, _.pick(userObj, 'password'));
        }
        throw new Errors.ForbiddenError('Forbidden');
    });
});

var listUsers = controller(function() {
    return accountService.listUsers();
});

var getUser = controller(function(req) {
    var name = req.swagger.params.name.value;
    return accountService.getUserByName(name);
});

var removeUser = controller({success: 204}, function(req) {
    var name = req.swagger.params.name.value;
    return accountService.removeUserByName(name);
});

module.exports = {
    addUser: addUser,
    modifyUser: modifyUser,
    listUsers: listUsers,
    getUser: getUser,
    removeUser: removeUser
};
<|endoftext|>


<commit_before>import { EditorState, CharacterMetadata } from 'draft-js';

import { BLOCK_TYPE, ENTITY_TYPE } from '../api/constants';

/**
 * Helper functions to filter/whitelist specific formatting.
 * Meant to be used when pasting unconstrained content.
 */
export default {
    /**
     * Applies whitelist and blacklist operations to the editor content,
     * so the resulting editor state is shaped according to Draftail
     * expectations and configuration.
     * As of now, this doesn't filter line breaks if they aren't disabled
     * as Draft.js does not preserve this type of whitespace on paste anyway.
     */
    filterEditorState(
        editorState,
        maxListNesting,
        enableHorizontalRule,
        blockTypes = [],
        inlineStyles = [],
        entityTypes = [],
    ) {
        let nextEditorState = editorState;
        const enabledBlockTypes = blockTypes.map(type => type.type).concat([
            // Always enabled in a Draftail editor.
            BLOCK_TYPE.UNSTYLED,
            // This is filtered at the entity stage if it has to be.
            BLOCK_TYPE.ATOMIC,
        ]);
        const enabledInlineStyles = inlineStyles.map(type => type.type);
        const enabledEntityTypes = entityTypes.map(type => type.type);

        if (enableHorizontalRule) {
            enabledEntityTypes.push(ENTITY_TYPE.HORIZONTAL_RULE);
        }

        nextEditorState = this.resetBlockDepth(nextEditorState, maxListNesting);

        nextEditorState = this.resetBlockType(
            nextEditorState,
            enabledBlockTypes,
        );

        nextEditorState = this.filterInlineStyle(
            nextEditorState,
            enabledInlineStyles,
        );

        nextEditorState = this.filterEntityType(
            nextEditorState,
            enabledEntityTypes,
        );

        return nextEditorState;
    },

    /**
     * Resets the depth of all the content to at most maxListNesting.
     */
    resetBlockDepth(editorState, maxListNesting) {
        const content = editorState.getCurrentContent();
        const blockMap = content.getBlockMap();

        const changedBlocks = blockMap
            .filter(block => block.getDepth() > maxListNesting)
            .map(block => block.set('depth', maxListNesting));

        if (changedBlocks.size !== 0) {
            return EditorState.set(editorState, {
                currentContent: content.merge({
                    blockMap: blockMap.merge(changedBlocks),
                }),
            });
        }

        return editorState;
    },

    /**
     * Resets all blocks that use unavailable types to unstyled.
     */
    resetBlockType(editorState, enabledBlockTypes) {
        const content = editorState.getCurrentContent();
        const blockMap = content.getBlockMap();

        const changedBlocks = blockMap
            .filter(block => !enabledBlockTypes.includes(block.getType()))
            .map(block => block.set('type', BLOCK_TYPE.UNSTYLED));

        if (changedBlocks.size !== 0) {
            return EditorState.set(editorState, {
                currentContent: content.merge({
                    blockMap: blockMap.merge(changedBlocks),
                }),
            });
        }

        return editorState;
    },

    /**
     * Removes all styles that use unavailable types.
     */
    filterInlineStyle(editorState, enabledTypes) {
        const content = editorState.getCurrentContent();
        const blockMap = content.getBlockMap();

        const blocks = blockMap.map(block => {
            let altered = false;

            const chars = block.getCharacterList().map(char => {
                let newChar = char;

                char
                    .getStyle()
                    .filter(type => !enabledTypes.includes(type))
                    .forEach(type => {
                        altered = true;
                        newChar = CharacterMetadata.removeStyle(newChar, type);
                    });

                return newChar;
            });

            return altered ? block.set('characterList', chars) : block;
        });

        return EditorState.set(editorState, {
            currentContent: content.merge({
                blockMap: blockMap.merge(blocks),
            }),
        });
    },

    /**
     * Reset all entity types (images, links, documents, embeds) that are unavailable.
     */
    filterEntityType(editorState, enabledTypes) {
        const content = editorState.getCurrentContent();
        const blockMap = content.getBlockMap();
        let blocks = blockMap;

        /**
         * Resets atomic blocks to unstyled if the atomic block entity isn't enabled.
         */
        const changedBlocks = blocks
            .filter(block => block.getType() === BLOCK_TYPE.ATOMIC)
            .filter(block => {
                const entityKey = block.getEntityAt(0);

                if (entityKey) {
                    const entityType = content.getEntity(entityKey).getType();

                    return !enabledTypes.includes(entityType);
                }

                return false;
            })
            .map(block => block.set('type', BLOCK_TYPE.UNSTYLED));

        if (changedBlocks.size !== 0) {
            blocks = blockMap.merge(changedBlocks);
        }

        /**
         * Removes entities from the character list if the character entity isn't enabled.
         * Also removes image entities placed outside of atomic blocks, which can happen
         * on paste.
         * A better approach would probably be to split the block where the image is and
         * create an atomic block there, but that's another story. This is what Draft.js
         * does when the copy-paste is all within one editor.
         */
        blocks = blocks.map(block => {
            const blockType = block.getType();
            let altered = false;

            const chars = block.getCharacterList().map(char => {
                const entityKey = char.getEntity();

                if (entityKey) {
                    const entityType = content.getEntity(entityKey).getType();
                    const shouldFilter = !enabledTypes.includes(entityType);
                    /**
                     * Special case for images. They should only be in atomic blocks.
                     * This only removes the image entity, not the camera emoji (📷)
                     * that Draft.js inserts.
                     * If we want to remove this in the future, consider that:
                     * - It needs to be removed in the block text, where it's 2 chars / 1 code point.
                     * - The corresponding CharacterMetadata needs to be removed too, and it's 2 instances
                     */
                    const shouldFilterImage =
                        entityType === ENTITY_TYPE.IMAGE &&
                        blockType !== BLOCK_TYPE.ATOMIC;

                    if (shouldFilter || shouldFilterImage) {
                        altered = true;
                        return CharacterMetadata.applyEntity(char, null);
                    }
                }

                return char;
            });

            return altered ? block.set('characterList', chars) : block;
        });

        return EditorState.set(editorState, {
            currentContent: content.merge({
                blockMap: blockMap.merge(blocks),
            }),
        });
    },
};
<commit_msg>Normalise atomic block text on paste<commit_after>import { EditorState, CharacterMetadata } from 'draft-js';

import { BLOCK_TYPE, ENTITY_TYPE } from '../api/constants';

/**
 * Helper functions to filter/whitelist specific formatting.
 * Meant to be used when pasting unconstrained content.
 */
export default {
    /**
     * Applies whitelist and blacklist operations to the editor content,
     * so the resulting editor state is shaped according to Draftail
     * expectations and configuration.
     * As of now, this doesn't filter line breaks if they aren't disabled
     * as Draft.js does not preserve this type of whitespace on paste anyway.
     */
    filterEditorState(
        editorState,
        maxListNesting,
        enableHorizontalRule,
        blockTypes = [],
        inlineStyles = [],
        entityTypes = [],
    ) {
        let nextEditorState = editorState;
        const enabledBlockTypes = blockTypes.map(type => type.type).concat([
            // Always enabled in a Draftail editor.
            BLOCK_TYPE.UNSTYLED,
            // This is filtered at the entity stage if it has to be.
            BLOCK_TYPE.ATOMIC,
        ]);
        const enabledInlineStyles = inlineStyles.map(type => type.type);
        const enabledEntityTypes = entityTypes.map(type => type.type);

        if (enableHorizontalRule) {
            enabledEntityTypes.push(ENTITY_TYPE.HORIZONTAL_RULE);
        }

        nextEditorState = this.resetBlockDepth(nextEditorState, maxListNesting);

        nextEditorState = this.resetBlockType(
            nextEditorState,
            enabledBlockTypes,
        );

        nextEditorState = this.filterInlineStyle(
            nextEditorState,
            enabledInlineStyles,
        );

        nextEditorState = this.filterEntityType(
            nextEditorState,
            enabledEntityTypes,
        );

        return nextEditorState;
    },

    /**
     * Resets the depth of all the content to at most maxListNesting.
     */
    resetBlockDepth(editorState, maxListNesting) {
        const content = editorState.getCurrentContent();
        const blockMap = content.getBlockMap();

        const changedBlocks = blockMap
            .filter(block => block.getDepth() > maxListNesting)
            .map(block => block.set('depth', maxListNesting));

        if (changedBlocks.size !== 0) {
            return EditorState.set(editorState, {
                currentContent: content.merge({
                    blockMap: blockMap.merge(changedBlocks),
                }),
            });
        }

        return editorState;
    },

    /**
     * Resets all blocks that use unavailable types to unstyled.
     */
    resetBlockType(editorState, enabledBlockTypes) {
        const content = editorState.getCurrentContent();
        const blockMap = content.getBlockMap();

        const changedBlocks = blockMap
            .filter(block => !enabledBlockTypes.includes(block.getType()))
            .map(block => block.set('type', BLOCK_TYPE.UNSTYLED));

        if (changedBlocks.size !== 0) {
            return EditorState.set(editorState, {
                currentContent: content.merge({
                    blockMap: blockMap.merge(changedBlocks),
                }),
            });
        }

        return editorState;
    },

    /**
     * Removes all styles that use unavailable types.
     */
    filterInlineStyle(editorState, enabledTypes) {
        const content = editorState.getCurrentContent();
        const blockMap = content.getBlockMap();

        const blocks = blockMap.map(block => {
            let altered = false;

            const chars = block.getCharacterList().map(char => {
                let newChar = char;

                char
                    .getStyle()
                    .filter(type => !enabledTypes.includes(type))
                    .forEach(type => {
                        altered = true;
                        newChar = CharacterMetadata.removeStyle(newChar, type);
                    });

                return newChar;
            });

            return altered ? block.set('characterList', chars) : block;
        });

        return EditorState.set(editorState, {
            currentContent: content.merge({
                blockMap: blockMap.merge(blocks),
            }),
        });
    },

    /**
     * Reset all entity types (images, links, documents, embeds) that are unavailable.
     */
    filterEntityType(editorState, enabledTypes) {
        const content = editorState.getCurrentContent();
        const blockMap = content.getBlockMap();
        let blocks = blockMap;

        const normalisedBlocks = blocks
            .filter(
                block =>
                    block.getType() === BLOCK_TYPE.ATOMIC &&
                    block.getText() !== ' ',
            )
            .map(block =>
                block.merge({
                    text: ' ',
                    characterList: block.getCharacterList().slice(0, 1),
                }),
            );

        if (normalisedBlocks.size !== 0) {
            blocks = blockMap.merge(normalisedBlocks);
        }

        /**
         * Resets atomic blocks to unstyled if the atomic block entity isn't enabled.
         */
        const resetBlocks = blocks
            .filter(block => block.getType() === BLOCK_TYPE.ATOMIC)
            .filter(block => {
                const entityKey = block.getEntityAt(0);
                let shouldReset = false;

                if (entityKey) {
                    const entityType = content.getEntity(entityKey).getType();

                    shouldReset = !enabledTypes.includes(entityType);
                }

                return shouldReset;
            })
            .map(block => block.set('type', BLOCK_TYPE.UNSTYLED));

        if (resetBlocks.size !== 0) {
            blocks = blockMap.merge(resetBlocks);
        }

        /**
         * Removes entities from the character list if the character entity isn't enabled.
         * Also removes image entities placed outside of atomic blocks, which can happen
         * on paste.
         * A better approach would probably be to split the block where the image is and
         * create an atomic block there, but that's another story. This is what Draft.js
         * does when the copy-paste is all within one editor.
         */
        blocks = blocks.map(block => {
            const blockType = block.getType();
            let altered = false;

            const chars = block.getCharacterList().map(char => {
                const entityKey = char.getEntity();

                if (entityKey) {
                    const entityType = content.getEntity(entityKey).getType();
                    const shouldFilter = !enabledTypes.includes(entityType);
                    /**
                     * Special case for images. They should only be in atomic blocks.
                     * This only removes the image entity, not the camera emoji (📷)
                     * that Draft.js inserts.
                     * If we want to remove this in the future, consider that:
                     * - It needs to be removed in the block text, where it's 2 chars / 1 code point.
                     * - The corresponding CharacterMetadata needs to be removed too, and it's 2 instances
                     */
                    const shouldFilterImage =
                        entityType === ENTITY_TYPE.IMAGE &&
                        blockType !== BLOCK_TYPE.ATOMIC;

                    if (shouldFilter || shouldFilterImage) {
                        altered = true;
                        return CharacterMetadata.applyEntity(char, null);
                    }
                }

                return char;
            });

            return altered ? block.set('characterList', chars) : block;
        });

        return EditorState.set(editorState, {
            currentContent: content.merge({
                blockMap: blockMap.merge(blocks),
            }),
        });
    },
};
<|endoftext|>


<commit_before>function Staff() {
  this.lineThickness = 1;
  this.lineSpacing = 12;
  this.lineColor = "#000000";

  this.noteHeight = 12;
  this.noteWidth = 16;
  this.noteColor = "#000000";

  this.staffSeparation = 12;
  this.sectionWidth = 76;

  this.leftMargin = 10;
  this.rightMargin = 10;
  this.topMargin = 10 + (2 * this.lineSpacing);
}

function drawStaff(key, songChordIndex, song, context) {
  // key is number from 0 to 11, 0 = C major, 11 = B major
  // song is an array of objects with property "notes", a string of integers separated by spaces

  var staff = new Staff();

  var lineThickness = staff.lineThickness;
  var lineSpacing = staff.lineSpacing;
  var lineColor = staff.lineColor;

  var noteHeight = staff.noteHeight;
  var noteWidth = staff.noteWidth;
  var noteColor = staff.noteColor;

  var staffSeparation = staff.staffSeparation;
  var sectionWidth = staff.sectionWidth;

  var leftMargin = staff.leftMargin;
  var rightMargin = staff.rightMargin;
  var topMargin = staff.topMargin;

  var trebleCorner = {x: leftMargin, y: topMargin};
  var bassCornerY = trebleCorner.y + (5 * lineSpacing) + staffSeparation;
  var bassCorner = {x: leftMargin, y: bassCornerY};

  // http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas

  function drawBoldEllipse(ctx, x, y, w, h) {
    var sqrt2 = 1.4142;
    var center = {x: x + (w / 2), y: y + (h / 2) };
    var topRight = {x: center.x + ((w / 2) / sqrt2), y: center.y - ((h / 2) / sqrt2)};
    var bottomLeft = {x: center.x - ((w / 2) / sqrt2), y: center.y + ((h / 2) / sqrt2)};

    var xOffset = w / 5;
    var yOffset = h / 5;
    var xOffsetWider = w / 2;
    var yOffsetWider = h / 2;

    ctx.beginPath();
    ctx.moveTo(bottomLeft.x, bottomLeft.y);
    ctx.bezierCurveTo(x - xOffset, center.y,
                      center.x, y - yOffset,
                      topRight.x, topRight.y);
    ctx.bezierCurveTo(center.x, y - yOffsetWider,
                      x - xOffsetWider, center.y,
                      bottomLeft.x, bottomLeft.y);
    ctx.lineWidth = 1;
    ctx.strokeStyle = noteColor;
    ctx.fillStyle = noteColor;
    ctx.fill();

    ctx.beginPath();
    ctx.moveTo(topRight.x, topRight.y);
    ctx.bezierCurveTo(x + xOffset + w, center.y,
                      center.x, y + yOffset + h,
                      bottomLeft.x, bottomLeft.y);
    ctx.bezierCurveTo(center.x, y + yOffsetWider + h,
                      x + xOffsetWider + w, center.y,
                      topRight.x, topRight.y);
    ctx.fill();

  }

  function drawLines(startPoint) {
    for (var i = 0; i < 5; i++) {
      context.beginPath();
      context.moveTo(startPoint.x, startPoint.y + (i * lineSpacing));
      context.lineTo(context.canvas.width - rightMargin, startPoint.y + (i * lineSpacing));
      context.lineWidth = lineThickness;
      context.strokeStyle = lineColor;
      context.stroke();
    }
  }

  function drawSharp(ctx, x, y, w, h) {
    var horizontalSpacing = 5;
    var verticalSpacing = 8;
    var rise = 6;
    var topRightOffset = 2;
    var leftOffset = 4;

    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x, y + h);
    ctx.lineWidth = 1;
    ctx.strokeStyle = lineColor;
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(x + horizontalSpacing, y - topRightOffset);
    ctx.lineTo(x + horizontalSpacing, y - topRightOffset + h);
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(x - leftOffset, y + (h / 2.5));
    ctx.lineTo(x - leftOffset + w, y + (h / 2.5) - rise);
    ctx.lineWidth = 3;
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(x - leftOffset, y + (h / 2.5) + verticalSpacing);
    ctx.lineTo(x - leftOffset + w, y + (h / 2.5) + verticalSpacing - rise);
    ctx.lineWidth = 3;
    ctx.stroke();
  }

  function drawNote(index, offset) {
    var jumps = [0,  0,  1,  1,  2,  3,  3,  4,  4,  5,  5,  6,
                 7,  7,  8,  8,  9, 10, 10, 11, 11, 12, 12, 13,
                 14, 14, 15, 15, 16, 17, 17, 18, 18, 19, 19, 20,
                 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 26, 27];
    var sharps = [0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0,
                  0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0,
                  0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0,
                  0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0];

    var left = offset.x + 10;
    var top = offset.y;

    var baseline = top + staffSeparation + (12.5 * lineSpacing);  // Bass C

    var noteTop = baseline - (jumps[index] * (noteHeight / 2));

    context.beginPath();
    // context.rect(left, noteTop, noteWidth, noteHeight)
    drawBoldEllipse(context, left, noteTop, noteWidth, noteHeight);

    context.lineWidth = 1;
    context.strokeStyle = noteColor;
    context.stroke();

    var sharpLeftOffset = 12;
    var sharpTopOffset = 8;
    var sharpWidth = 14;
    var sharpHeight = noteHeight * 2.7;
    if (sharps[index]) {
      // draw sharp symbol

      drawSharp(context, left - sharpLeftOffset, noteTop - sharpTopOffset, sharpWidth, sharpHeight );
    }

  }

  function drawNotes(notesString, index) {
    var notes = notesString.trim().split(" ");
    var leftMargin = 20;
    var left = leftMargin + (index * sectionWidth);
    notes.forEach(function(note) {
      drawNote(parseInt(note), {x: left, y: 10});
    });
  }

  function drawTrebleClef() {

  }

  function drawBassClef() {

  }

  context.clearRect(0, 0, context.canvas.width, context.canvas.height);
  drawLines(trebleCorner);

  drawLines(bassCorner);

  var rectTopMargin = 5;
  var rectCorner = {x: leftMargin + (songChordIndex * sectionWidth), y: rectTopMargin };
  var rectWidth = sectionWidth - 10;
  var rectHeight = rectTopMargin + (15 * lineSpacing);
  var rectColor = "#339955";

  if(songChordIndex >= 0) {
    context.beginPath();
    context.rect(rectCorner.x, rectCorner.y, rectWidth, rectHeight);
    context.lineWidth = 2;
    context.strokeStyle = rectColor;
    context.stroke();
  }

  song.forEach(function(chordObj, i) {
    // console.log("draw notes " + notes);
    drawNotes(chordObj.notes, i);
  });

  //drawLines(song.length * sectionWidth, {x: 10, y: 10});
  //song.forEach(function(notes) {
  //  drawNotes(notes);
  //}
}

function drawScaleSubtitle(context) {
  var staffConstants = new Staff();
  var topMargin = 18;
  var leftOffset = 20;
  context.font = "20px sans-serif";
  var noteName = ['C', '', 'D', '', 'E', 'F', '', 'G', '', 'A', '', 'B'];
  for (var i = 0; i < 12; i++) {
    context.fillText(noteName[i], staffConstants.leftMargin + leftOffset + (i * staffConstants.sectionWidth), topMargin);
  }
}
<commit_msg>adjust margin<commit_after>function Staff() {
  this.lineThickness = 1;
  this.lineSpacing = 12;
  this.lineColor = "#000000";

  this.noteHeight = 12;
  this.noteWidth = 16;
  this.noteColor = "#000000";

  this.staffSeparation = 12;
  this.sectionWidth = 76;

  this.leftMargin = 10;
  this.rightMargin = 10;
  this.topMargin = 10 + (2 * this.lineSpacing);
}

function drawStaff(key, songChordIndex, song, context) {
  // key is number from 0 to 11, 0 = C major, 11 = B major
  // song is an array of objects with property "notes", a string of integers separated by spaces

  var staff = new Staff();

  var lineThickness = staff.lineThickness;
  var lineSpacing = staff.lineSpacing;
  var lineColor = staff.lineColor;

  var noteHeight = staff.noteHeight;
  var noteWidth = staff.noteWidth;
  var noteColor = staff.noteColor;

  var staffSeparation = staff.staffSeparation;
  var sectionWidth = staff.sectionWidth;

  var leftMargin = staff.leftMargin;
  var rightMargin = staff.rightMargin;
  var topMargin = staff.topMargin;

  var trebleCorner = {x: leftMargin, y: topMargin};
  var bassCornerY = trebleCorner.y + (5 * lineSpacing) + staffSeparation;
  var bassCorner = {x: leftMargin, y: bassCornerY};

  // http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas

  function drawBoldEllipse(ctx, x, y, w, h) {
    var sqrt2 = 1.4142;
    var center = {x: x + (w / 2), y: y + (h / 2) };
    var topRight = {x: center.x + ((w / 2) / sqrt2), y: center.y - ((h / 2) / sqrt2)};
    var bottomLeft = {x: center.x - ((w / 2) / sqrt2), y: center.y + ((h / 2) / sqrt2)};

    var xOffset = w / 5;
    var yOffset = h / 5;
    var xOffsetWider = w / 2;
    var yOffsetWider = h / 2;

    ctx.beginPath();
    ctx.moveTo(bottomLeft.x, bottomLeft.y);
    ctx.bezierCurveTo(x - xOffset, center.y,
                      center.x, y - yOffset,
                      topRight.x, topRight.y);
    ctx.bezierCurveTo(center.x, y - yOffsetWider,
                      x - xOffsetWider, center.y,
                      bottomLeft.x, bottomLeft.y);
    ctx.lineWidth = 1;
    ctx.strokeStyle = noteColor;
    ctx.fillStyle = noteColor;
    ctx.fill();

    ctx.beginPath();
    ctx.moveTo(topRight.x, topRight.y);
    ctx.bezierCurveTo(x + xOffset + w, center.y,
                      center.x, y + yOffset + h,
                      bottomLeft.x, bottomLeft.y);
    ctx.bezierCurveTo(center.x, y + yOffsetWider + h,
                      x + xOffsetWider + w, center.y,
                      topRight.x, topRight.y);
    ctx.fill();

  }

  function drawLines(startPoint) {
    for (var i = 0; i < 5; i++) {
      context.beginPath();
      context.moveTo(startPoint.x, startPoint.y + (i * lineSpacing));
      context.lineTo(context.canvas.width - rightMargin, startPoint.y + (i * lineSpacing));
      context.lineWidth = lineThickness;
      context.strokeStyle = lineColor;
      context.stroke();
    }
  }

  function drawSharp(ctx, x, y, w, h) {
    var horizontalSpacing = 5;
    var verticalSpacing = 8;
    var rise = 6;
    var topRightOffset = 2;
    var leftOffset = 4;

    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x, y + h);
    ctx.lineWidth = 1;
    ctx.strokeStyle = lineColor;
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(x + horizontalSpacing, y - topRightOffset);
    ctx.lineTo(x + horizontalSpacing, y - topRightOffset + h);
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(x - leftOffset, y + (h / 2.5));
    ctx.lineTo(x - leftOffset + w, y + (h / 2.5) - rise);
    ctx.lineWidth = 3;
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(x - leftOffset, y + (h / 2.5) + verticalSpacing);
    ctx.lineTo(x - leftOffset + w, y + (h / 2.5) + verticalSpacing - rise);
    ctx.lineWidth = 3;
    ctx.stroke();
  }

  function drawNote(index, offset) {
    var jumps = [0,  0,  1,  1,  2,  3,  3,  4,  4,  5,  5,  6,
                 7,  7,  8,  8,  9, 10, 10, 11, 11, 12, 12, 13,
                 14, 14, 15, 15, 16, 17, 17, 18, 18, 19, 19, 20,
                 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 26, 27];
    var sharps = [0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0,
                  0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0,
                  0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0,
                  0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0];

    var left = offset.x + 10;
    var top = offset.y;

    var baseline = top + staffSeparation + (12.5 * lineSpacing);  // Bass C

    var noteTop = baseline - (jumps[index] * (noteHeight / 2));

    context.beginPath();
    // context.rect(left, noteTop, noteWidth, noteHeight)
    drawBoldEllipse(context, left, noteTop, noteWidth, noteHeight);

    context.lineWidth = 1;
    context.strokeStyle = noteColor;
    context.stroke();

    var sharpLeftOffset = 12;
    var sharpTopOffset = 8;
    var sharpWidth = 14;
    var sharpHeight = noteHeight * 2.7;
    if (sharps[index]) {
      // draw sharp symbol

      drawSharp(context, left - sharpLeftOffset, noteTop - sharpTopOffset, sharpWidth, sharpHeight );
    }

  }

  function drawNotes(notesString, index) {
    var notes = notesString.trim().split(" ");
    var leftMargin = 20;
    var left = leftMargin + (index * sectionWidth);
    notes.forEach(function(note) {
      drawNote(parseInt(note), {x: left, y: 10});
    });
  }

  function drawTrebleClef() {

  }

  function drawBassClef() {

  }

  context.clearRect(0, 0, context.canvas.width, context.canvas.height);
  drawLines(trebleCorner);

  drawLines(bassCorner);

  var rectTopMargin = 5;
  var rectCorner = {x: leftMargin + (songChordIndex * sectionWidth), y: rectTopMargin };
  var rectWidth = sectionWidth - 10;
  var rectHeight = rectTopMargin + (15 * lineSpacing);
  var rectColor = "#339955";

  if(songChordIndex >= 0) {
    context.beginPath();
    context.rect(rectCorner.x, rectCorner.y, rectWidth, rectHeight);
    context.lineWidth = 2;
    context.strokeStyle = rectColor;
    context.stroke();
  }

  song.forEach(function(chordObj, i) {
    // console.log("draw notes " + notes);
    drawNotes(chordObj.notes, i);
  });

  //drawLines(song.length * sectionWidth, {x: 10, y: 10});
  //song.forEach(function(notes) {
  //  drawNotes(notes);
  //}
}

function drawScaleSubtitle(context) {
  var staffConstants = new Staff();
  var topMargin = 18;
  var leftOffset = 21;
  context.font = "20px sans-serif";
  var noteName = ['C', '', 'D', '', 'E', 'F', '', 'G', '', 'A', '', 'B'];
  for (var i = 0; i < 12; i++) {
    context.fillText(noteName[i], staffConstants.leftMargin + leftOffset + (i * staffConstants.sectionWidth), topMargin);
  }
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name       Kill nrcQ restrictions
// @namespace  http://use.i.E.your.homepage/
// @version    0.1
// @description  When browsing nrcq with more than 10 views you need to sign in to view the content, this plugin disables the lay-over.
// @match      http://www.nrcq.nl/*
// @copyright  2015+, You
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js
// ==/UserScript==

// Load the jquery library.
this.$ = this.jQuery = jQuery.noConflict(true);

$(document).ready(function()
  {
    // change the class from opened to closed
    $(document.body).removeClass("boxy-opened").addClass("boxy-closed");

    // Remove the overlays.
    $('div.boxy-overlay').remove();
    $('div.boxy').remove();
  }
);
<commit_msg>Use experimental object observers for mocking. only works in chromium for now.<commit_after>// ==UserScript==
// @name       Kill nrcQ restrictions
// @namespace  http://use.i.E.your.homepage/
// @version    0.2
// @description  When browsing nrcq with more than 10 views you need to sign in to view the content, this plugin disables the lay-over.
// @match      http://www.nrcq.nl/*
// @copyright  2015+, You
// @run-at document-start
// @grant       none
// ==/UserScript==

// initialize the objects
window.nmt = window.nmt || {};
nmt.q = nmt.q || {};

// The observer function.
var observer = function(changes) {
  changes.forEach(function(change) {
    // Any time boxy is added to nmt.q
    if (change.name == 'boxy') {
      // mock the boxy inDom func.
      nmt.q.boxy = function(x) {
        this.inDom = false;
      }
      // destroy the observer
      doUnobserve(nmt.q);
    };
  });
};

// Use experimental feature.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe#Browser_compatibility
Object.observe(nmt.q, observer, ["add"]);

function doUnobserve(obj) {
  Object.unobserve(obj, observer);
}
<|endoftext|>


<commit_before>// @flow

import React, { Component } from 'react';
import { observable } from 'mobx';
import { observer, inject } from 'mobx-react';
import { Switch } from '@blueprintjs/core';
import { head, noop } from 'lodash';
import ReactGA from 'react-ga';
import { lifecycle } from 'recompose';
import ReactTooltip from 'react-tooltip';

import counterService from 'services/counterService';
import recsStore from 'stores/RecsStore';
import Person from 'models/Person';
import { CurrentUser } from 'models/CurrentUser';
import { ACTION_TYPES } from 'const';
import LS from 'utils/localStorage';

import type { ActionsType } from 'types/person';

import './Autolike.scss';

type PropsType = {
  currentUser: CurrentUser,
  enabled: boolean,
  handleSetEnabled: () => void,
  onButtonClick: (payload: Object) => void,
  onError: (reason: ActionsType) => void,
  onMatch: (person: Person) => void,
};

const labelEhnance = lifecycle({
  componentDidMount() {
    ReactTooltip.rebuild();
  },
  componentWillUnmount() {
    ReactTooltip.rebuild();
  },
});

const Label = labelEhnance(() => (

    Autolike {' '}

));

@inject('currentUser')
@observer
class Autolike extends Component {
  componentWillUnmount() {
    counterService.unsubscribe(this.handleAutolike);
  }

  props: PropsType;

  @observable enabled = false;
  @observable velocity = parseInt(LS.get('settings.autolikeVelocity', 1), 10);
  @observable giveUp = parseInt(LS.get('settings.autolikeGiveUp', 5), 10);
  @observable retryNumber = 0;

  handleSetEnabled = (e) => {
    console.log(e.target)
    // ReactGA.event({
    //   category: 'Autolike',
    //   action: `Turn ${!this.enabled ? 'on' : 'off'}`,
    // });

    // if (!this.enabled) {
    //   counterService.subscribe({
    //     handler: this.handleAutolike,
    //     delay: this.velocity * 1000,
    //   });
    //   this.retryNumber = 0;
    // } else {
    //   counterService.unsubscribe(this.handleAutolike);
    // }

    // this.enabled = !this.enabled;
  };

  handleSetVelocity = ({ target: { value } }: SyntheticInputEvent) => {
    this.velocity = parseInt(value, 10);
    LS.setSettings({ autolikeVelocity: value });

    ReactGA.event({
      category: 'Autolike',
      action: 'Velocity',
      label: value,
    });

    counterService.unsubscribe(this.handleAutolike);

    if (this.enabled) {
      counterService.subscribe({
        handler: this.handleAutolike,
        delay: parseInt(value, 10) * 1000,
      });
    }
  };

  handleSetGiveUp = ({ target: { value } }: SyntheticInputEvent) => {
    const val = parseInt(value, 10);

    if (val < 0) {
      return;
    }

    ReactGA.event({
      category: 'Autolike',
      action: 'Give up',
      label: value,
    });

    LS.setSettings({ autolikeGiveUp: value });
    this.giveUp = val;
  };

  handleAutolike = () => {
    const person = head(recsStore.allVisible);

    if (this.props.currentUser.likeReset.seconds > 0) {
      this.enabled = false;
      this.retryNumber = 0;

      counterService.unsubscribe(this.handleAutolike);

      return;
    }

    if (person) {
      person.callAction(ACTION_TYPES.LIKE, noop, this.props.onMatch, this.props.onError);
    }

    if (!recsStore.is_fetching && !recsStore.is_loading_more) {
      if (this.retryNumber >= this.giveUp && this.giveUp > 0) {
        counterService.unsubscribe(this.handleAutolike);
        this.enabled = false;
        this.retryNumber = 0;
      } else {
        recsStore.fetchCore();
      }
    }

    if (recsStore.allVisible.length === 0) {
      this.retryNumber = this.retryNumber + 1;
    } else {
      this.retryNumber = 0;
    }
  };

  render() {
    return (

        <Switch
          className="pt-align-right autolike__toggle"
          checked={this.enabled}
          disabled={this.props.currentUser.likeReset.seconds > 0}
          label={}
          onChange={this.handleSetEnabled}
        />

          Velocity:

            <select value={this.velocity} onChange={this.handleSetVelocity}>
              <option value="0.5">0.5s</option>
              <option value="1">1s</option>
              <option value="2">2s</option>
              <option value="4">4s</option>
            </select>

            Give up after N fails:

            <input className="pt-input" type="number" value={this.giveUp} onChange={this.handleSetGiveUp} />

0 = don{'\''}t care

    );
  }
}

export default Autolike;
<commit_msg>Unccoment code<commit_after>// @flow

import React, { Component } from 'react';
import { observable } from 'mobx';
import { observer, inject } from 'mobx-react';
import { Switch } from '@blueprintjs/core';
import { head, noop } from 'lodash';
import ReactGA from 'react-ga';
import { lifecycle } from 'recompose';
import ReactTooltip from 'react-tooltip';

import counterService from 'services/counterService';
import recsStore from 'stores/RecsStore';
import Person from 'models/Person';
import { CurrentUser } from 'models/CurrentUser';
import { ACTION_TYPES } from 'const';
import LS from 'utils/localStorage';

import type { ActionsType } from 'types/person';

import './Autolike.scss';

type PropsType = {
  currentUser: CurrentUser,
  enabled: boolean,
  handleSetEnabled: () => void,
  onButtonClick: (payload: Object) => void,
  onError: (reason: ActionsType) => void,
  onMatch: (person: Person) => void,
};

const labelEhnance = lifecycle({
  componentDidMount() {
    ReactTooltip.rebuild();
  },
  componentWillUnmount() {
    ReactTooltip.rebuild();
  },
});

const Label = labelEhnance(() => (

    Autolike {' '}

));

@inject('currentUser')
@observer
class Autolike extends Component {
  componentWillUnmount() {
    counterService.unsubscribe(this.handleAutolike);
  }

  props: PropsType;

  @observable enabled = false;
  @observable velocity = parseInt(LS.get('settings.autolikeVelocity', 1), 10);
  @observable giveUp = parseInt(LS.get('settings.autolikeGiveUp', 5), 10);
  @observable retryNumber = 0;

  handleSetEnabled = (e) => {
    ReactGA.event({
      category: 'Autolike',
      action: `Turn ${!this.enabled ? 'on' : 'off'}`,
    });

    if (!this.enabled) {
      counterService.subscribe({
        handler: this.handleAutolike,
        delay: this.velocity * 1000,
      });
      this.retryNumber = 0;
    } else {
      counterService.unsubscribe(this.handleAutolike);
    }

    this.enabled = !this.enabled;
  };

  handleSetVelocity = ({ target: { value } }: SyntheticInputEvent) => {
    this.velocity = parseInt(value, 10);
    LS.setSettings({ autolikeVelocity: value });

    ReactGA.event({
      category: 'Autolike',
      action: 'Velocity',
      label: value,
    });

    counterService.unsubscribe(this.handleAutolike);

    if (this.enabled) {
      counterService.subscribe({
        handler: this.handleAutolike,
        delay: parseInt(value, 10) * 1000,
      });
    }
  };

  handleSetGiveUp = ({ target: { value } }: SyntheticInputEvent) => {
    const val = parseInt(value, 10);

    if (val < 0) {
      return;
    }

    ReactGA.event({
      category: 'Autolike',
      action: 'Give up',
      label: value,
    });

    LS.setSettings({ autolikeGiveUp: value });
    this.giveUp = val;
  };

  handleAutolike = () => {
    const person = head(recsStore.allVisible);

    if (this.props.currentUser.likeReset.seconds > 0) {
      this.enabled = false;
      this.retryNumber = 0;

      counterService.unsubscribe(this.handleAutolike);

      return;
    }

    if (person) {
      person.callAction(ACTION_TYPES.LIKE, noop, this.props.onMatch, this.props.onError);
    }

    if (!recsStore.is_fetching && !recsStore.is_loading_more) {
      if (this.retryNumber >= this.giveUp && this.giveUp > 0) {
        counterService.unsubscribe(this.handleAutolike);
        this.enabled = false;
        this.retryNumber = 0;
      } else {
        recsStore.fetchCore();
      }
    }

    if (recsStore.allVisible.length === 0) {
      this.retryNumber = this.retryNumber + 1;
    } else {
      this.retryNumber = 0;
    }
  };

  render() {
    return (

        <Switch
          className="pt-align-right autolike__toggle"
          checked={this.enabled}
          disabled={this.props.currentUser.likeReset.seconds > 0}
          label={}
          onChange={this.handleSetEnabled}
        />

          Velocity:

            <select value={this.velocity} onChange={this.handleSetVelocity}>
              <option value="0.5">0.5s</option>
              <option value="1">1s</option>
              <option value="2">2s</option>
              <option value="4">4s</option>
            </select>

            Give up after N fails:

            <input className="pt-input" type="number" value={this.giveUp} onChange={this.handleSetGiveUp} />

0 = don{'\''}t care

    );
  }
}

export default Autolike;
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

var App = require('app');

function calculatePosition(movedTop, defaultTop, scrollTop, defaultLeft, scrollLeft) {
  var css = {
    top: 'auto',
    left: 'auto'
  };
  if (scrollTop >= defaultTop) {
    css.top = movedTop;
  } else if (scrollTop > 0) {
    css.top = (defaultTop - scrollTop) + 'px';
  }
  //if (css.top == '0px') debugger;
  if (scrollLeft > 0) {
    css.left = defaultLeft;
  }
  return css;
}

/**
 *
 * @type {Em.Object}
 */
App.ScrollManager = Em.Object.create({

  /**
   @typedef FixedElement
   @type {object}
   @property {string} id - identifier for element (not css-id). used to determine if element already exists in the list !IMPORTANT - don't push same element two times!
   @property {string} updatedElementSelector - css-selector for element that should be replaced
   @property {string} elementForLeftOffsetSelector - css-selector for element which is used to determine left-offset for updatedElementSelector-element
   @property {number} defaultTop - value for top-offset when user scrolls not under the updatedElementSelector-element
   @property {number} movedTop - value for top-offset when user scrolls  under the updatedElementSelector-element
   */

  /**
   * List of elements that should be placed on the top of the page
   * @type {FixedElement[]}
   */
  elements: [],

  /**
   * Recalculate position for each elements of the elements
   * Should be called from some view
   *
   * @method updatePositionForElements
   */
  updatePositionForElements: function () {
    var self = this;
    //reset defaultTop value in closure
    $(window).unbind('scroll');

    $(window).on('scroll', function () {
      self.get('elements').forEach(function (element) {
        var defaultTop, defaultLeft;
        var infoBar = $(Em.get(element, 'updatedElementSelector'));
        var versionSlider = $(Em.get(element, 'elementForLeftOffsetSelector'));
        var scrollTop = $(window).scrollTop();
        var scrollLeft = $(window).scrollLeft();
        if (!infoBar.length) {
          return;
        }
        defaultTop = (infoBar.get(0).getBoundingClientRect() && infoBar.get(0).getBoundingClientRect().top) || Em.get(element, 'defaultTop');
        // keep the version info bar always aligned to version slider
        defaultLeft = (versionSlider.get(0).getBoundingClientRect() && versionSlider.get(0).getBoundingClientRect().left);
        infoBar.css(calculatePosition(Em.get(element, 'movedTop'), defaultTop, scrollTop, defaultLeft, scrollLeft));
      });
    });

  }

});
<commit_msg>AMBARI-10758. JS error appears on scroll host configs page (onechiporenko)<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

var App = require('app');

function calculatePosition(movedTop, defaultTop, scrollTop, defaultLeft, scrollLeft) {
  var css = {
    top: 'auto',
    left: 'auto'
  };
  if (scrollTop >= defaultTop) {
    css.top = movedTop;
  } else if (scrollTop > 0) {
    css.top = (defaultTop - scrollTop) + 'px';
  }
  //if (css.top == '0px') debugger;
  if (scrollLeft > 0) {
    css.left = defaultLeft;
  }
  return css;
}

/**
 *
 * @type {Em.Object}
 */
App.ScrollManager = Em.Object.create({

  /**
   @typedef FixedElement
   @type {object}
   @property {string} id - identifier for element (not css-id). used to determine if element already exists in the list !IMPORTANT - don't push same element two times!
   @property {string} updatedElementSelector - css-selector for element that should be replaced
   @property {string} elementForLeftOffsetSelector - css-selector for element which is used to determine left-offset for updatedElementSelector-element
   @property {number} defaultTop - value for top-offset when user scrolls not under the updatedElementSelector-element
   @property {number} movedTop - value for top-offset when user scrolls  under the updatedElementSelector-element
   */

  /**
   * List of elements that should be placed on the top of the page
   * @type {FixedElement[]}
   */
  elements: [],

  /**
   * Recalculate position for each elements of the elements
   * Should be called from some view
   *
   * @method updatePositionForElements
   */
  updatePositionForElements: function () {
    var self = this;
    //reset defaultTop value in closure
    $(window).unbind('scroll');

    $(window).on('scroll', function () {
      self.get('elements').forEach(function (element) {
        var defaultTop, defaultLeft;
        var infoBar = $(Em.get(element, 'updatedElementSelector'));
        var elementForLeftOffset = $(Em.get(element, 'elementForLeftOffsetSelector'));
        var scrollTop = $(window).scrollTop();
        var scrollLeft = $(window).scrollLeft();
        if (!infoBar.length) {
          return;
        }
        defaultTop = (infoBar.get(0).getBoundingClientRect() && infoBar.get(0).getBoundingClientRect().top) || Em.get(element, 'defaultTop');
        // keep the version info bar always aligned to version slider
        defaultLeft = elementForLeftOffset.get(0) && elementForLeftOffset.get(0).getBoundingClientRect() && elementForLeftOffset.get(0).getBoundingClientRect().left;
        infoBar.css(calculatePosition(Em.get(element, 'movedTop'), defaultTop, scrollTop, defaultLeft, scrollLeft));
      });
    });

  }

});
<|endoftext|>


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

    angular
        .module('app.users')
        .controller('UserFormController', UserFormController);

    UserFormController.$inject = ['$timeout', '$rootScope', '$scope'];

    function UserFormController($timeout, $rootScope, $scope) {
        var vm = this;

        vm.user = {};
        vm.user.gender = 'male';
        vm.submit = submit;
        vm.loadWards = loadWards;
        vm.stakes = [
            {id: 1, name: 'Brasília'},
            {id: 2, name: 'Brasília Norte'}
        ];
        vm.wards = null;

        activate();

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

        function activate() {
            vm.genders = [{
                label: 'users.MALE',
                value: 'male',
            }, {
                label: 'users.FEMALE',
                value: 'female',
            }];

        }

        function submit() {
            console.log(vm.user);
        }

        function loadWards() {
            console.log('selected stake', vm.user.stake);
            vm.wards = [
                {id: 2, name: 'Asa Sul'},
                {id: 1, name: 'Guará I'},
            ];
        }
    }
})();<commit_msg>[modify] UserFormController para adicionar usuário na lista<commit_after>(function() {
    'use strict';

    angular
        .module('app.users')
        .controller('UserFormController', UserFormController);

    UserFormController.$inject = ['$timeout', '$rootScope', '$scope', '$state'];

    function UserFormController($timeout, $rootScope, $scope, $state) {
        var vm = this;

        vm.user = {
            profile: 'USER',
            imageUrl: 'img/avatar.png',
            gender: 'male'
        };
        vm.submit = submit;
        vm.loadWards = loadWards;
        vm.stakes = [
            {id: 1, name: 'Brasília'},
            {id: 2, name: 'Brasília Norte'}
        ];
        vm.wards = null;

        activate();

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

        function activate() {
            vm.genders = [{
                label: 'users.MALE',
                value: 'male',
            }, {
                label: 'users.FEMALE',
                value: 'female',
            }];

        }

        function submit() {
            $scope.parent.users.push(vm.user);
            $state.go('app.users.list');
        }

        function loadWards() {
            console.log('selected stake', vm.user.stake);
            vm.wards = [
                {id: 2, name: 'Asa Sul'},
                {id: 1, name: 'Guará I'},
            ];
        }
    }
})();<|endoftext|>