<commit_before>/**
 * The Alert Component
 *
 * @module aui-alert
 */

var getClassName = A.getClassName,
    CSS_CLOSE = getClassName('close'),
    CSS_INFO = getClassName('alert', 'info'),
    CSS_DISMISSABLE = getClassName('alert', 'dismissable');

/**
 * A base class for Alert.
 *
 * Check the [live demo](http://alloyui.com/examples/alert/).
 *
 * @class A.Alert
 * @extends Widget
 * @uses A.WidgetCssClass, A.WidgetTransition
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 * @include http://alloyui.com/examples/alert/basic-markup.html
 * @include http://alloyui.com/examples/alert/basic.js
 */
A.Alert = A.Base.create('alert', A.Widget, [
    A.WidgetCssClass,
    A.WidgetStdMod,
    A.WidgetTransition
], {
    CONTENT_TEMPLATE: null,

    _eventHandle: null,

    /**
     * Renders the Alert component instance. Lifecycle.
     *
     * @method renderUI
     * @protected
     */
    renderUI: function() {
        this._uiSetCloseable(this.get('closeable'));

        if (this.get('useARIA')) {
            this.plug(A.Plugin.Aria);

            this.aria.setAttribute('hidden', false, this.get('boundingBox'));
        }
    },

    /**
     * Binds the events on the Alert UI. Lifecycle.
     *
     * @method bindUI
     * @protected
     */
    bindUI: function() {
        this.on('closeableChange', this._onCloseableChange);
        this.after('visibleChange', this._afterVisibleChange);
    },

    /**
     * Fires after visibility changes.
     *
     * @method _afterVisibleChange
     * @param {EventFacade} event
     * @protected
     */
    _afterVisibleChange: function(event) {
        if (!event.newVal && this.get('destroyOnHide')) {
            A.soon(A.bind('destroy', this));
        }
    },

    /**
     * Handles close icon click event.
     *
     * @method _onClickBoundingBox
     * @param {EventFacade} event
     * @protected
     */
    _onClickBoundingBox: function(event) {
        if (event.target.test('.' + CSS_CLOSE)) {
            this.hide();

            if (this.get('useARIA') && !this.get('destroyOnHide')) {
                this.aria.setAttribute('hidden', true, this.get('boundingBox'));
            }
        }
    },

    /**
     * Handles `closeable` events.
     *
     * @method _onCloseableChange
     * @param {EventFacade} event
     * @protected
     */
    _onCloseableChange: function(event) {
        this._uiSetCloseable(event.newVal);
    },

    /**
     * Sets `closeable` UI.
     *
     * @method _uiSetCloseable
     * @protected
     */
    _uiSetCloseable: function(val) {
        var boundingBox = this.get('boundingBox'),
            closeableNode = this.get('closeableNode');

        boundingBox.toggleClass(CSS_DISMISSABLE, val);

        closeableNode.remove();

        if (this._eventHandle) {
            this._eventHandle.detach();
        }

        if (val) {
            boundingBox.insert(closeableNode, 0);
            this._eventHandle = boundingBox.on('click', this._onClickBoundingBox, this);
        }
    }
}, {

    /**
     * Static property used to define the default attribute
     * configuration for the Alert.
     *
     * @property ATTRS
     * @type Object
     * @static
     */
    ATTRS: {
        /**
         * Whether the alert can be closed.
         *
         * @attribute closeable
         * @default true
         * @type {Boolean}
         */
        closeable: {
            validator: A.Lang.isBoolean,
            value: true
        },

        /**
         * Node used to generate a close button.
         *
         * @attribute closeableNode
         * @default `<button type="button" class="close">×</button>`
         * @type {Node}
         */
        closeableNode: {
            valueFn: function() {
                return A.Node.create('<button type="button" class="close">×</button>');
            }
        },

        /**
         * CSS class for alert.
         *
         * @attribute popoverCssClass
         * @default A.getClassName('alert-info')
         * @type {String}
         */
        cssClass: {
            value: CSS_INFO
        },

        /**
         * Determine if Alert should be destroyed when hidden.
         *
         * @attribute destroyOnHide
         * @default false
         * @type Boolean
         */
        destroyOnHide: {
            validator: A.Lang.isBoolean,
            value: false
        },

        /**
        * Boolean indicating if use of the WAI-ARIA Roles and States should be enabled..
        *
        * @attribute useARIA
        * @default true
        * @type {Boolean}
        */
        useARIA: {
            validator: A.Lang.isBoolean,
            value: true,
            writeOnce: 'initOnly'
        }
    },

    /**
     * Static property provides a string to identify the CSS prefix.
     *
     * @property CSS_PREFIX
     * @type {String}
     * @static
     */
    CSS_PREFIX: 'alert',

    /**
     * Object hash, defining how closeableNode value have to be parsed from markup.
     *
     * @property HTML_PARSER
     * @type Object
     * @static
     */
    HTML_PARSER: {
        closeableNode: '.' + CSS_CLOSE
    }
});
<commit_msg>AUI-3180 Correct 'alert-dimissable' to 'alert-dismissible' to keep consistency<commit_after>/**
 * The Alert Component
 *
 * @module aui-alert
 */

var getClassName = A.getClassName,
    CSS_CLOSE = getClassName('close'),
    CSS_INFO = getClassName('alert', 'info'),
    CSS_DISMISSIBLE = getClassName('alert', 'dismissible');

/**
 * A base class for Alert.
 *
 * Check the [live demo](http://alloyui.com/examples/alert/).
 *
 * @class A.Alert
 * @extends Widget
 * @uses A.WidgetCssClass, A.WidgetTransition
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 * @include http://alloyui.com/examples/alert/basic-markup.html
 * @include http://alloyui.com/examples/alert/basic.js
 */
A.Alert = A.Base.create('alert', A.Widget, [
    A.WidgetCssClass,
    A.WidgetStdMod,
    A.WidgetTransition
], {
    CONTENT_TEMPLATE: null,

    _eventHandle: null,

    /**
     * Renders the Alert component instance. Lifecycle.
     *
     * @method renderUI
     * @protected
     */
    renderUI: function() {
        this._uiSetCloseable(this.get('closeable'));

        if (this.get('useARIA')) {
            this.plug(A.Plugin.Aria);

            this.aria.setAttribute('hidden', false, this.get('boundingBox'));
        }
    },

    /**
     * Binds the events on the Alert UI. Lifecycle.
     *
     * @method bindUI
     * @protected
     */
    bindUI: function() {
        this.on('closeableChange', this._onCloseableChange);
        this.after('visibleChange', this._afterVisibleChange);
    },

    /**
     * Fires after visibility changes.
     *
     * @method _afterVisibleChange
     * @param {EventFacade} event
     * @protected
     */
    _afterVisibleChange: function(event) {
        if (!event.newVal && this.get('destroyOnHide')) {
            A.soon(A.bind('destroy', this));
        }
    },

    /**
     * Handles close icon click event.
     *
     * @method _onClickBoundingBox
     * @param {EventFacade} event
     * @protected
     */
    _onClickBoundingBox: function(event) {
        if (event.target.test('.' + CSS_CLOSE)) {
            this.hide();

            if (this.get('useARIA') && !this.get('destroyOnHide')) {
                this.aria.setAttribute('hidden', true, this.get('boundingBox'));
            }
        }
    },

    /**
     * Handles `closeable` events.
     *
     * @method _onCloseableChange
     * @param {EventFacade} event
     * @protected
     */
    _onCloseableChange: function(event) {
        this._uiSetCloseable(event.newVal);
    },

    /**
     * Sets `closeable` UI.
     *
     * @method _uiSetCloseable
     * @protected
     */
    _uiSetCloseable: function(val) {
        var boundingBox = this.get('boundingBox'),
            closeableNode = this.get('closeableNode');

        boundingBox.toggleClass(CSS_DISMISSIBLE, val);

        closeableNode.remove();

        if (this._eventHandle) {
            this._eventHandle.detach();
        }

        if (val) {
            boundingBox.insert(closeableNode, 0);
            this._eventHandle = boundingBox.on('click', this._onClickBoundingBox, this);
        }
    }
}, {

    /**
     * Static property used to define the default attribute
     * configuration for the Alert.
     *
     * @property ATTRS
     * @type Object
     * @static
     */
    ATTRS: {
        /**
         * Whether the alert can be closed.
         *
         * @attribute closeable
         * @default true
         * @type {Boolean}
         */
        closeable: {
            validator: A.Lang.isBoolean,
            value: true
        },

        /**
         * Node used to generate a close button.
         *
         * @attribute closeableNode
         * @default `<button type="button" class="close">×</button>`
         * @type {Node}
         */
        closeableNode: {
            valueFn: function() {
                return A.Node.create('<button type="button" class="close">×</button>');
            }
        },

        /**
         * CSS class for alert.
         *
         * @attribute popoverCssClass
         * @default A.getClassName('alert-info')
         * @type {String}
         */
        cssClass: {
            value: CSS_INFO
        },

        /**
         * Determine if Alert should be destroyed when hidden.
         *
         * @attribute destroyOnHide
         * @default false
         * @type Boolean
         */
        destroyOnHide: {
            validator: A.Lang.isBoolean,
            value: false
        },

        /**
        * Boolean indicating if use of the WAI-ARIA Roles and States should be enabled..
        *
        * @attribute useARIA
        * @default true
        * @type {Boolean}
        */
        useARIA: {
            validator: A.Lang.isBoolean,
            value: true,
            writeOnce: 'initOnly'
        }
    },

    /**
     * Static property provides a string to identify the CSS prefix.
     *
     * @property CSS_PREFIX
     * @type {String}
     * @static
     */
    CSS_PREFIX: 'alert',

    /**
     * Object hash, defining how closeableNode value have to be parsed from markup.
     *
     * @property HTML_PARSER
     * @type Object
     * @static
     */
    HTML_PARSER: {
        closeableNode: '.' + CSS_CLOSE
    }
});
<|endoftext|>


<commit_before>export { PassThrough_FiltersArray_BiasesArray };
export { PassThrough_FiltersArray_BiasesArray_Bag };
export { PassThrough };

import * as ValueDesc from "../../Unpacker/ValueDesc.js";
import * as TwoTensors from "../../util/TwoTensors.js";
import * as MultiLayerMap from "../../util/MultiLayerMap.js";
import { PadInfoCalculator } from "./Depthwise_PadInfoCalculator.js";

/**
 * A depthwise convolution and bias which just pass the input to output.
 *
 * It is usually used in passing the higher half channels of the input to output (for achieving ShuffleNetV2_ByMopbileNetV1's body/tail).
 *
 * Note1: Although depthwise (and pointwise) convolution could be past-through, the activation function will destroy the past-through
 * result. Using Pointwise_FiltersArray_BiasesArray may be better to handle this issue.
 *
 * Note2: If both effectFilterValue and surroundingFilterValue are the same as ( 1 / ( filterHeight * filter Width ) ), the result filter
 * will have the same effect as average pooling.
 *
 *
 *
 * @member {number} effectFilterValue
 *   The value used as the effect value of the pass-through depthwise convolution filter. Default is 1. If there will be no activation
 * function after this pass-through operation, value 1 is enough. However, if there wiil be an activation function, this past-through
 * result might be destroyed by the activation function. In order to alleviate this issue, a non-one filter value should be used. For
 * example, if every input value's range is [ 0,255 ] and RELU6 will be used as activation function, using 0.015625 (= 1 / 64 ) as
 * filterValue is appropriate because input values will be shrinked from [ 0, 255 ] into [ 0, 3.984375 ] which will still be kept
 * linear by RELU6.
 *
 * @member {number} surroundingFilterValue
 *   The value used as the surrounding value of the pass-through depthwise convolution filter. Default is 0.
 *
 * @member {number} biasValue
 *   The value used as the pass-through bias (used only if ( bBias == true ) ). Default is 0. If there will be no activation function
 * after this pass-through operation, value 0 is enough. However, if there wiil be an activation function, this past-through result
 * might be destroyed by the activation function. In order to alleviate this issue, a non-zero bias value should be used. For example,
 * if every input value's range is [ -2, +2 ] and RELU6 will be used as activation function, using +2 as biasValue is appropriate
 * because input values will be shifted from [ -2, +2 ] into [ 0, 4 ] which will still be kept linear by RELU6.
 *
 * @member {number[]} filtersShape
 *   The shape of the pass-through filters array.
 *
 * @member {number[]} biasesShape
 *   The shape of the pass-through biases array.
 *
 * @member {number[]} filtersArray
 *   The pass-through filters array.
 *
 * @member {number[]} biasesArray
 *   The pass-through biases array.
 *
 * @see PadInfoCalculator
 */
let PassThrough_FiltersArray_BiasesArray = ( ParentClass = Object ) => class extends PadInfoCalculator( ParentClass ) {

  /**
   * Used as default Depthwise.PassThrough_FiltersArray_BiasesArray provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "Depthwise.PassThrough_FiltersArray_BiasesArray.Pool",
    PassThrough_FiltersArray_BiasesArray, PassThrough_FiltersArray_BiasesArray.setAsConstructor );

  /**
   */
  constructor(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, effectFilterValue = 1, surroundingFilterValue = 0, biasValue = 0 ) {

    super( inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad );
    PassThrough_FiltersArray_BiasesArray.setAsConstructor_self.call( this,
      bBias, effectFilterValue, surroundingFilterValue, biasValue );
  }

  /** @override */
  static setAsConstructor(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, effectFilterValue = 1, surroundingFilterValue = 0, biasValue = 0 ) {

    super.setAsConstructor( inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad );
    PassThrough_FiltersArray_BiasesArray.setAsConstructor_self.call( this,
      bBias, effectFilterValue, surroundingFilterValue, biasValue );
    return this;
  }

  /** @override */
  static setAsConstructor_self( bBias, effectFilterValue = 1, surroundingFilterValue = 0, biasValue = 0 ) {
    this.bBias = bBias;
    this.effectFilterValue = effectFilterValue;
    this.surroundingFilterValue = surroundingFilterValue;
    this.biasValue = biasValue;

    this.filtersShape = Recyclable.Array.Pool.get_or_create_by( 4 );
    this.filtersShape[ 0 ] = this.filterHeight;
    this.filtersShape[ 1 ] = this.filterWidth;
    this.filtersShape[ 2 ] = this.inputChannelCount;
    this.filtersShape[ 3 ] = this.channelMultiplier;

//!!!???
    this.filtersArray = this.generate_PassThrough_FiltersArray( effectFilterValue, surroundingFilterValue );

    if ( this.bBias ) {
      this.biasesShape = Recyclable.Array.Pool.get_or_create_by( 3 );
      this.biasesShape[ 0 ] = 1;
      this.biasesShape[ 1 ] = 1;
      this.biasesShape[ 2 ] = this.outputChannelCount;

      this.biasesArray = Recyclable.Array.Pool.get_or_create_by( this.outputChannelCount );
      this.biasesArray.fill( biasValue );
    }
  }

  /** @override */
  disposeResources() {
    if ( this.biasesArray ) {
      this.biasesArray.disposeResources_and_recycleToPool();
      this.biasesArray = null;
    }

    if ( this.biasesShape ) {
      this.biasesShape.disposeResources_and_recycleToPool();
      this.biasesShape = null;
    }

//!!!???
    if ( this.filtersArray ) {
      this.filtersArray.disposeResources_and_recycleToPool();
      this.filtersArray = null;
    }

    if ( this.filtersShape ) {
      this.filtersShape.disposeResources_and_recycleToPool();
      this.filtersShape = null;
    }
    super.disposeResources();
  }

}

/**
 * Almost the same as Depthwise.PassThrough_FiltersArray_BiasesArray class except its parent class is fixed to Object. In other words,
 * caller can not specify the parent class of Depthwise.PassThrough_FiltersArray_BiasesArray_Root (so it is named "Root" which can not
 * have parent class).
 */
class PassThrough_FiltersArray_BiasesArray_Root extends PassThrough_FiltersArray_BiasesArray() {
}

/**
 * A pool for PassThrough_FiltersArray_BiasesArray with various parameters. It could reduce re-creating them of same parameters again
 * and again to improve performance.
 *
 */
class PassThrough_FiltersArray_BiasesArray_Bag extends MultiLayerMap.Base {

  //constructor() {
  //  super();
  //}

  /**
   *
   */
  get_by_PassThroughStyleId(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, nPassThroughStyleId ) {

//!!! ...unfinished... (2022/05/26) effectFilterValue, surroundingFilterValue ???

    const thePassThroughStyleInfo = ValueDesc.PassThroughStyle.Singleton.getInfoById( nPassThroughStyleId );
    return this.get_by_effectFilterValue_surroundingFilterValue_biasValue(
      inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
      bBias, thePassThroughStyleInfo.filterValue, 0, thePassThroughStyleInfo.biasValue );
  }

  /**
   *
   */
  get_by_effectFilterValue_surroundingFilterValue_biasValue(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, effectFilterValue = 1, surroundingFilterValue = 0, biasValue = 0 ) {

    return this.get_or_create_by_arguments1_etc( PassThrough_FiltersArray_BiasesArray_Bag.create_by,
      inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
      bBias, effectFilterValue, surroundingFilterValue, biasValue );
  }

  /** */
  static create_by(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, effectFilterValue, surroundingFilterValue, biasValue ) {

    return new PassThrough_FiltersArray_BiasesArray_Root(
      inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
      bBias, effectFilterValue, surroundingFilterValue, biasValue );
  }

}

/**
 * A depthwise convolution and bias which just pass the input to output.
 *
 * It is usually used in passing the higher half channels of the input to output (for achieving ShuffleNetV2_ByMopbileNetV1's body/tail).
 *
 *
 * @see PassThrough_FiltersArray_BiasesArray
 * @see PadInfoCalculator
 * @see TwoTensors.filtersTensor4d_biasesTensor3d
 */
class PassThrough extends PassThrough_FiltersArray_BiasesArray( TwoTensors.filtersTensor4d_biasesTensor3d() ) {

  /**
   */
  constructor(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, effectFilterValue = 1, surroundingFilterValue = 0, biasValue = 0 ) {

    super( inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
      bBias, effectFilterValue, surroundingFilterValue, biasValue );

    this.filtersTensor4d = tf.tensor4d( this.filtersArray, this.filtersShape );

    if ( this.bBias ) {
      this.biasesTensor3d = tf.tensor3d( this.biasesArray, this.biasesShape );
    }

    this.bInitOk = true;
  }

}

<commit_msg>Update Depthwise_PassThrough.js<commit_after>export { PassThrough_FiltersArray_BiasesArray };
export { PassThrough_FiltersArray_BiasesArray_Root };
export { PassThrough_FiltersArray_BiasesArray_Bag };
export { PassThrough };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
import * as ValueDesc from "../../Unpacker/ValueDesc.js";
import * as TwoTensors from "../../util/TwoTensors.js";
import * as MultiLayerMap from "../../util/MultiLayerMap.js";
import { PadInfoCalculator } from "./Depthwise_PadInfoCalculator.js";

/**
 * A depthwise convolution and bias which just pass the input to output.
 *
 * It is usually used in passing the higher half channels of the input to output (for achieving ShuffleNetV2_ByMopbileNetV1's body/tail).
 *
 * Note1: Although depthwise (and pointwise) convolution could be past-through, the activation function will destroy the past-through
 * result. Using Pointwise_FiltersArray_BiasesArray may be better to handle this issue.
 *
 * Note2: If both effectFilterValue and surroundingFilterValue are the same as ( 1 / ( filterHeight * filter Width ) ), the result filter
 * will have the same effect as average pooling.
 *
 *
 *
 * @member {number} effectFilterValue
 *   The value used as the effect value of the pass-through depthwise convolution filter. Default is 1. If there will be no activation
 * function after this pass-through operation, value 1 is enough. However, if there wiil be an activation function, this past-through
 * result might be destroyed by the activation function. In order to alleviate this issue, a non-one filter value should be used. For
 * example, if every input value's range is [ 0,255 ] and RELU6 will be used as activation function, using 0.015625 (= 1 / 64 ) as
 * filterValue is appropriate because input values will be shrinked from [ 0, 255 ] into [ 0, 3.984375 ] which will still be kept
 * linear by RELU6.
 *
 * @member {number} surroundingFilterValue
 *   The value used as the surrounding value of the pass-through depthwise convolution filter. Default is 0.
 *
 * @member {number} biasValue
 *   The value used as the pass-through bias (used only if ( bBias == true ) ). Default is 0. If there will be no activation function
 * after this pass-through operation, value 0 is enough. However, if there wiil be an activation function, this past-through result
 * might be destroyed by the activation function. In order to alleviate this issue, a non-zero bias value should be used. For example,
 * if every input value's range is [ -2, +2 ] and RELU6 will be used as activation function, using +2 as biasValue is appropriate
 * because input values will be shifted from [ -2, +2 ] into [ 0, 4 ] which will still be kept linear by RELU6.
 *
 * @member {number[]} filtersShape
 *   The shape of the pass-through filters array.
 *
 * @member {number[]} biasesShape
 *   The shape of the pass-through biases array.
 *
 * @member {number[]} filtersArray
 *   The pass-through filters array.
 *
 * @member {number[]} biasesArray
 *   The pass-through biases array.
 *
 * @see PadInfoCalculator
 */
let PassThrough_FiltersArray_BiasesArray
  = ( ParentClass = Object ) => class PassThrough_FiltersArray_BiasesArray extends PadInfoCalculator( ParentClass ) {

  /**
   * Used as default Depthwise.PassThrough_FiltersArray_BiasesArray provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "Depthwise.PassThrough_FiltersArray_BiasesArray.Pool",
    PassThrough_FiltersArray_BiasesArray, PassThrough_FiltersArray_BiasesArray.setAsConstructor );

  /**
   */
  constructor(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, effectFilterValue = 1, surroundingFilterValue = 0, biasValue = 0 ) {

    super( inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad );
    PassThrough_FiltersArray_BiasesArray.setAsConstructor_self.call( this,
      bBias, effectFilterValue, surroundingFilterValue, biasValue );
  }

  /** @override */
  static setAsConstructor(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, effectFilterValue = 1, surroundingFilterValue = 0, biasValue = 0 ) {

    super.setAsConstructor( inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad );
    PassThrough_FiltersArray_BiasesArray.setAsConstructor_self.call( this,
      bBias, effectFilterValue, surroundingFilterValue, biasValue );
    return this;
  }

  /** @override */
  static setAsConstructor_self( bBias, effectFilterValue = 1, surroundingFilterValue = 0, biasValue = 0 ) {
    this.bBias = bBias;
    this.effectFilterValue = effectFilterValue;
    this.surroundingFilterValue = surroundingFilterValue;
    this.biasValue = biasValue;

    this.filtersShape = Recyclable.Array.Pool.get_or_create_by( 4 );
    this.filtersShape[ 0 ] = this.filterHeight;
    this.filtersShape[ 1 ] = this.filterWidth;
    this.filtersShape[ 2 ] = this.inputChannelCount;
    this.filtersShape[ 3 ] = this.channelMultiplier;

    PassThrough_FiltersArray_BiasesArray.generate_PassThrough_FiltersArray.call( this, effectFilterValue, surroundingFilterValue );

    if ( this.bBias ) {
      this.biasesShape = Recyclable.Array.Pool.get_or_create_by( 3 );
      this.biasesShape[ 0 ] = 1;
      this.biasesShape[ 1 ] = 1;
      this.biasesShape[ 2 ] = this.outputChannelCount;

      this.biasesArray = Recyclable.Array.Pool.get_or_create_by( this.outputChannelCount );
      this.biasesArray.fill( biasValue );
    }
  }

  /** @override */
  disposeResources() {
    if ( this.biasesArray ) {
      this.biasesArray.disposeResources_and_recycleToPool();
      this.biasesArray = null;
    }

    if ( this.biasesShape ) {
      this.biasesShape.disposeResources_and_recycleToPool();
      this.biasesShape = null;
    }

    if ( this.filtersArray ) {
      this.filtersArray.disposeResources_and_recycleToPool();
      this.filtersArray = null;
    }

    if ( this.filtersShape ) {
      this.filtersShape.disposeResources_and_recycleToPool();
      this.filtersShape = null;
    }
    super.disposeResources();
  }

  /**
   * Determine the following properties:
   *   - this.filtersArray
   *
   * It is an number array representing the depthwise convolution filters which could pass the input to output unchangely.
   *
   * If both effectFilterValue and otherFilterValue are the same as ( 1 / ( filterHeight * filter Width ) ), the result filter
   * will have the same effect as average pooling.
   *
   *
   * @param {number} effectFilterValue
   *   The filter value used for the effect input pixel of the depthwise convolution. For pass-through, it is usually 1.
   * Note: It is not always just at center of filter according to the filter shape and paddding.
   *
   * @param {number} surroundingFilterValue
   *   The filter value used for the surrounding input pixel of the depthwise convolution. For pass-through, it is usually 0.
   *
   */
  static generate_PassThrough_FiltersArray( effectFilterValue, surroundingFilterValue ) {

    if (   ( ValueDesc.AvgMax_Or_ChannelMultiplier.Singleton.Ids.AVG === this.AvgMax_Or_ChannelMultiplier )
        || ( ValueDesc.AvgMax_Or_ChannelMultiplier.Singleton.Ids.MAX === this.AvgMax_Or_ChannelMultiplier ) ) {

      if ( this.filtersArray ) {
        this.filtersArray.disposeResources_and_recycleToPool();
        this.filtersArray = null;
      }

      return; // The depthwise filter of AVG pooling and MAX pooling can not be manipulated.
    }

    // Make up a depthwise convolution filter.
    this.filtersArray = Recyclable.Array.Pool.get_or_create_by(
      this.filterHeight * this.filterWidth * this.inputChannelCount * this.channelMultiplier );

    // There is only one position (inside the effect depthwise filter) uses effectFilterValue.
    // All other positions of the filter should be surroundingFilterValue.
    //
    let oneEffectFilterY = this.padHeightTop;
    let oneEffectFilterX = this.padWidthLeft;

    // Note: Unfortunately, this may not work for ( dilation > 1 ) because the non-zero-filter-value might be just at the dilation
    //       position which does not exist in a filter. So, only ( dilation == 1 ) is supported.

    let filterIndex = 0; // The index in the filter weights array.

    for ( let filterY = 0, effectFilterY = 0; filterY < this.filterHeight; ++filterY ) {
      for ( let dilationFilterY = 0; dilationFilterY < this.dilationHeight; ++dilationFilterY, ++effectFilterY ) {

        for ( let filterX = 0, effectFilterX = 0; filterX < this.filterWidth; ++filterX ) {
          for ( let dilationFilterX = 0; dilationFilterX < this.dilationWidth; ++dilationFilterX, ++effectFilterX ) {

            // The filter's dilation part can not be manipulated. (They are always zero.)
            if ( ( 0 != dilationFilterY ) || ( 0 != dilationFilterX ) )
              continue;

            for ( let inChannel = 0; inChannel < this.inputChannelCount; ++inChannel ) {

              for ( let outChannelSub = 0; outChannelSub < this.channelMultiplier; ++outChannelSub ) {

                if ( ( effectFilterY == oneEffectFilterY ) && ( effectFilterX == oneEffectFilterX ) ) {
                  depthwiseFiltersArray[ filterIndex ] = effectFilterValue;
                } else {
                  depthwiseFiltersArray[ filterIndex ] = surroundingFilterValue;
                }

                ++filterIndex;
              }
            }
          }
        }
      }
    }
  }

}

/**
 * Almost the same as Depthwise.PassThrough_FiltersArray_BiasesArray class except its parent class is fixed to Object. In other words,
 * caller can not specify the parent class of Depthwise.PassThrough_FiltersArray_BiasesArray_Root (so it is named "Root" which can not
 * have parent class).
 */
class PassThrough_FiltersArray_BiasesArray_Root extends PassThrough_FiltersArray_BiasesArray() {
}

/**
 * A pool for PassThrough_FiltersArray_BiasesArray with various parameters. It could reduce re-creating them of same parameters again
 * and again to improve performance.
 *
 */
class PassThrough_FiltersArray_BiasesArray_Bag extends MultiLayerMap.Base {

  //constructor() {
  //  super();
  //}

  /**
   *
   */
  get_by_PassThroughStyleId(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, nPassThroughStyleId ) {

//!!! ...unfinished... (2022/05/26) effectFilterValue, surroundingFilterValue ???

    const thePassThroughStyleInfo = ValueDesc.PassThroughStyle.Singleton.getInfoById( nPassThroughStyleId );
    return this.get_by_effectFilterValue_surroundingFilterValue_biasValue(
      inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
      bBias, thePassThroughStyleInfo.filterValue, 0, thePassThroughStyleInfo.biasValue );
  }

  /**
   *
   */
  get_by_effectFilterValue_surroundingFilterValue_biasValue(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, effectFilterValue = 1, surroundingFilterValue = 0, biasValue = 0 ) {

    return this.get_or_create_by_arguments1_etc( PassThrough_FiltersArray_BiasesArray_Bag.create_by,
      inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
      bBias, effectFilterValue, surroundingFilterValue, biasValue );
  }

  /** */
  static create_by(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, effectFilterValue, surroundingFilterValue, biasValue ) {

    return new PassThrough_FiltersArray_BiasesArray_Root(
      inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
      bBias, effectFilterValue, surroundingFilterValue, biasValue );
  }

}

/**
 * A depthwise convolution and bias which just pass the input to output.
 *
 * It is usually used in passing the higher half channels of the input to output (for achieving ShuffleNetV2_ByMopbileNetV1's body/tail).
 *
 *
 * @see PassThrough_FiltersArray_BiasesArray
 * @see PadInfoCalculator
 * @see TwoTensors.filtersTensor4d_biasesTensor3d
 */
class PassThrough extends PassThrough_FiltersArray_BiasesArray( TwoTensors.filtersTensor4d_biasesTensor3d() ) {

  /**
   */
  constructor(
    inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
    bBias, effectFilterValue = 1, surroundingFilterValue = 0, biasValue = 0 ) {

    super( inputHeight, inputWidth, inputChannelCount, AvgMax_Or_ChannelMultiplier, filterHeight, filterWidth, stridesPad,
      bBias, effectFilterValue, surroundingFilterValue, biasValue );

    this.filtersTensor4d = tf.tensor4d( this.filtersArray, this.filtersShape );

    if ( this.bBias ) {
      this.biasesTensor3d = tf.tensor3d( this.biasesArray, this.biasesShape );
    }

    this.bInitOk = true;
  }

}

<|endoftext|>


<commit_before>Vue.component('spark-settings-teams-screen', {
    /*
     * Bootstrap the component. Load the initial data.
     */
    ready: function () {
        this.getInvitations();
    },

    /*
     * Initial state of the component's data.
     */
    data: function () {
        return {
            user: null,
            teams: [],
            invitations: [],

            teamToDelete: null,
            deletingTeam: false,

            createTeamForm: {
                name: '',
                errors: [],
                creating: false,
                created: false
            }
        };
    },

    events: {
        /*
         * Handle the "userRetrieved" event.
         */
        userRetrieved: function (user) {
            this.user = user;
        },

        /*
         * Handle the "teamsRetrieved" event.
         */
        teamsRetrieved: function (teams) {
            this.teams = teams;
        }
    },

    methods: {
        /*
         * Get all of the user's pending invitations from the API.
         */
        getInvitations: function () {
            this.$http.get('/spark/api/teams/invitations')
                .success(function (invitations) {
                    this.invitations = invitations;
                });
        },

        createTeam: function (e) {
            e.preventDefault();

            this.createTeamForm.errors = [];
            this.createTeamForm.creating = true;

            this.$http.post('/settings/teams', this.createTeamForm)
                .success(function (teams) {
                    this.$dispatch('updateUser');
                    this.$dispatch('teamsUpdated', teams);

                    this.createTeamForm.name = '';
                    this.createTeamForm.creating = false;
                })
                .error(function (errors) {
                    Spark.setErrorsOnForm(this.createTeamForm, errors);
                    this.createTeamForm.creating = false;
                });
        },

        /*
         * Leave the team.
         */
        leaveTeam: function (team) {
            this.teams = _.reject(this.teams, function (t) {
                return t.id == team.id;
            });

            this.$http.delete('/settings/teams/' + team.id + '/membership')
                .success(function (teams) {
                    this.$dispatch('updateUser');
                    this.$dispatch('teamsUpdated', teams);
                });
        },

        /*
         * Confirm that the user really wants to delete the team.
         */
        confirmTeamDeletion: function (team) {
            this.teamToDelete = team;

            $('#modal-delete-team').modal('show');
        },

        /*
         * Delete the given team.
         */
        deleteTeam: function () {
            this.deletingTeam = true;

            this.$http.delete('/settings/teams/' + this.teamToDelete.id)
                .success(function (teams) {
                    this.deletingTeam = false;
                    $('#modal-delete-team').modal('hide');

                    this.$dispatch('updateUser');
                    this.$dispatch('teamsUpdated', teams);
                });
        },

        /*
         * Accept a pending invitation.
         */
        acceptInvite: function (invite) {
            this.invitations = _.reject(this.invitations, function (i) {
                return i.id == invite.id;
            });

            this.$http.post('/settings/teams/invitations/' + invite.id + '/accept')
                .success(function (teams) {
                    this.$dispatch('updateUser');
                    this.$dispatch('teamsUpdated', teams);
                });
        },

        /*
         * Reject a pending invitation.
         */
        rejectInvite: function (invite) {
            this.invitations = _.reject(this.invitations, function (i) {
                return i.id == invite.id;
            });

            this.$http.delete('settings/teams/invitations/' + invite.id);
        },

        /*
         * Determine if the current user owns the given team.
         */
        userOwns: function (team) {
            if ( ! this.user) {
                return false;
            }

            return this.user.id === team.owner_id;
        }
    }
});
<commit_msg>fix: #32 Creating a team updates 'Current Teams' with lots of empty rows<commit_after>Vue.component('spark-settings-teams-screen', {
    /*
     * Bootstrap the component. Load the initial data.
     */
    ready: function () {
        this.getInvitations();
    },

    /*
     * Initial state of the component's data.
     */
    data: function () {
        return {
            user: null,
            teams: [],
            invitations: [],

            teamToDelete: null,
            deletingTeam: false,

            createTeamForm: {
                name: '',
                errors: [],
                creating: false,
                created: false
            }
        };
    },

    events: {
        /*
         * Handle the "userRetrieved" event.
         */
        userRetrieved: function (user) {
            this.user = user;
        },

        /*
         * Handle the "teamsRetrieved" event.
         */
        teamsRetrieved: function (teams) {
            this.teams = teams;
        }
    },

    methods: {
        /*
         * Get all of the user's pending invitations from the API.
         */
        getInvitations: function () {
            this.$http.get('/spark/api/teams/invitations')
                .success(function (invitations) {
                    this.invitations = invitations;
                });
        },

        createTeam: function (e) {
            e.preventDefault();

            this.createTeamForm.errors = [];
            this.createTeamForm.creating = true;
            this.$http.options.emulateJSON = true;

            this.$http.post('/settings/teams', this.createTeamForm)
                .success(function (teams) {
                    this.$dispatch('updateUser');
                    this.$dispatch('teamsUpdated', teams);

                    this.createTeamForm.name = '';
                    this.createTeamForm.creating = false;
                })
                .error(function (errors) {
                    Spark.setErrorsOnForm(this.createTeamForm, errors);
                    this.createTeamForm.creating = false;
                });
        },

        /*
         * Leave the team.
         */
        leaveTeam: function (team) {
            this.teams = _.reject(this.teams, function (t) {
                return t.id == team.id;
            });

            this.$http.delete('/settings/teams/' + team.id + '/membership')
                .success(function (teams) {
                    this.$dispatch('updateUser');
                    this.$dispatch('teamsUpdated', teams);
                });
        },

        /*
         * Confirm that the user really wants to delete the team.
         */
        confirmTeamDeletion: function (team) {
            this.teamToDelete = team;

            $('#modal-delete-team').modal('show');
        },

        /*
         * Delete the given team.
         */
        deleteTeam: function () {
            this.deletingTeam = true;

            this.$http.delete('/settings/teams/' + this.teamToDelete.id)
                .success(function (teams) {
                    this.deletingTeam = false;
                    $('#modal-delete-team').modal('hide');

                    this.$dispatch('updateUser');
                    this.$dispatch('teamsUpdated', teams);
                });
        },

        /*
         * Accept a pending invitation.
         */
        acceptInvite: function (invite) {
            this.invitations = _.reject(this.invitations, function (i) {
                return i.id == invite.id;
            });

            this.$http.post('/settings/teams/invitations/' + invite.id + '/accept')
                .success(function (teams) {
                    this.$dispatch('updateUser');
                    this.$dispatch('teamsUpdated', teams);
                });
        },

        /*
         * Reject a pending invitation.
         */
        rejectInvite: function (invite) {
            this.invitations = _.reject(this.invitations, function (i) {
                return i.id == invite.id;
            });

            this.$http.delete('settings/teams/invitations/' + invite.id);
        },

        /*
         * Determine if the current user owns the given team.
         */
        userOwns: function (team) {
            if ( ! this.user) {
                return false;
            }

            return this.user.id === team.owner_id;
        }
    }
});
<|endoftext|>


<commit_before>import React, { useRef, useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import Icon from '../../base/icons/Icon';
import withWindowSize from '../../util/withWindowSize';

const OuterWrapper = styled.div`
  overflow: hidden;
  position: relative;
`;

const InnerWrapper = styled.div`
  alignitems: center;
  display: flex;
  height: 100%;
  position: relative;
  transition: transform 0.3s ease-in-out;
  white-space: nowrap;
  z-index: 0;
`;

const ScrollIcon = styled.div`
  align-items: center;
  cursor: pointer;
  display: flex;
  height: 100%;
  outline: 0;
  position: absolute;
  top: 0;
  z-index: 1;
`;

const ArrowContainer = styled.div`
  align-items: center;
  background-color: ${props => props.theme.colors.white};
  border-radius: 50%;
  box-shadow: 0 1px 1px ${props => props.theme.colors.boxShadowDark};
  color: ${props => props.theme.colors.gray9};
  display: flex;
  padding: 0.5em;
`;

const generateOnArrowKeyDownHandler = onKeyDown => event => {
  const code = event.code.toLowerCase();
  if (code === 'Enter' || code === 'Space') {
    onKeyDown();
  }
};

const ArrowLeft = ({ onClick }) => (
  <ScrollIcon
    role="button"
    tabIndex={0}
    style={{ left: '0', textAlign: 'left' }}
    onClick={onClick}
    onKeyDown={generateOnArrowKeyDownHandler(onClick)}
  >
    <ArrowContainer>
      <Icon name="chevron-left" />
    </ArrowContainer>
  </ScrollIcon>
);

ArrowLeft.propTypes = {
  onClick: PropTypes.func.isRequired
};

const ArrowRight = ({ onClick }) => (
  <ScrollIcon
    role="button"
    tabIndex={0}
    style={{ right: '0', textAlign: 'right' }}
    onClick={onClick}
    onKeyDown={generateOnArrowKeyDownHandler(onClick)}
  >
    <ArrowContainer>
      <Icon name="chevron-right" />
    </ArrowContainer>
  </ScrollIcon>
);

ArrowRight.propTypes = {
  onClick: PropTypes.func.isRequired
};

function HorizontalScrollWrapper({ windowWidth, children, slideAmount }) {
  const rootRef = useRef(null);
  const menuRef = useRef(null);
  const [rootWidth, setRootWidth] = useState(0);
  const [menuWidth, setMenuWidth] = useState(0);
  const [xPosition, setXPosition] = useState(0);
  const [cursorXPosition, setCursorXPosition] = useState(0);
  const [hasOverflow, setHasOverflow] = useState(false);
  const [isDragging, setIsDragging] = useState(false);

  useEffect(() => {
    const currentRootWidth = rootRef.current ? rootRef.current.clientWidth : 0;
    const currentMenuWidth = menuRef.current ? menuRef.current.scrollWidth : 0;

    if (currentRootWidth <= currentMenuWidth) {
      setRootWidth(currentRootWidth);
      setMenuWidth(currentMenuWidth);
      setHasOverflow(true);

      const absoluteXPosition = Math.abs(xPosition);
      if (currentRootWidth + absoluteXPosition > currentMenuWidth) {
        const distance = Math.abs(
          currentMenuWidth - currentRootWidth + xPosition
        );
        setXPosition(xPosition + distance);
      }
    } else if (hasOverflow) {
      setHasOverflow(false);
    }
  }, [windowWidth, rootRef.current, menuRef.current]);

  const handleDownEvent = downEvent => {
    if (!hasOverflow) return;

    let cursorX = 0;
    if (downEvent.type === 'mousedown') {
      cursorX = downEvent.pageX - xPosition;
    } else if (downEvent.type === 'touchstart') {
      const touchEvent = downEvent.changedTouches[0];
      cursorX = touchEvent.pageX - xPosition;
    }

    setCursorXPosition(cursorX);
    setIsDragging(true);
  };

  const handleMoveEvent = moveEvent => {
    if (!hasOverflow || !isDragging) return;

    let distance = 0;

    if (moveEvent.type === 'mousemove') {
      moveEvent.preventDefault();
      distance = moveEvent.pageX - cursorXPosition;
    } else if (moveEvent.type === 'touchmove') {
      const touchEvent = moveEvent.changedTouches[0];
      distance = touchEvent.pageX - cursorXPosition;
    }

    let newXPosition = (xPosition + distance) * 0.5;
    if (newXPosition > 0) {
      newXPosition = 0;
    }
    if (-newXPosition > menuWidth - rootWidth) {
      newXPosition = -(menuWidth - rootWidth);
    }

    setXPosition(newXPosition);
  };

  const handleUpEvent = () => {
    if (!hasOverflow || !isDragging) return;

    setIsDragging(false);
  };

  const handleLeftClick = event => {
    event.stopPropagation();
    event.preventDefault();

    let newXPosition = xPosition + slideAmount;
    if (newXPosition > 0) {
      newXPosition = 0;
    }

    setXPosition(newXPosition);
  };

  const handleRightClick = event => {
    event.stopPropagation();
    event.preventDefault();

    let newXPosition = xPosition - slideAmount;
    if (-newXPosition > menuWidth - rootWidth) {
      newXPosition = -(menuWidth - rootWidth);
    }

    setXPosition(newXPosition);
  };

  return (
    <OuterWrapper ref={rootRef}>
      <InnerWrapper
        ref={menuRef}
        role="presentation"
        onMouseDown={handleDownEvent}
        onMouseMove={handleMoveEvent}
        onMouseUp={handleUpEvent}
        onMouseLeave={handleUpEvent}
        onTouchStart={handleDownEvent}
        onTouchMove={handleMoveEvent}
        onTouchEnd={handleUpEvent}
        style={{
          transform: `translate3d(${xPosition}px, 0, 0)`
        }}
      >
        {children}
      </InnerWrapper>
      {hasOverflow && xPosition < 0 && <ArrowLeft onClick={handleLeftClick} />}
      {hasOverflow && -xPosition < menuWidth - rootWidth && (
        <ArrowRight onClick={handleRightClick} />
      )}
    </OuterWrapper>
  );
}

HorizontalScrollWrapper.propTypes = {
  windowWidth: PropTypes.number,
  children: PropTypes.node,
  /** Set the number of pixels the contents will move when clicking left/right arrows */
  slideAmount: PropTypes.number
};

HorizontalScrollWrapper.defaultProps = {
  windowWidth: undefined,
  children: null,
  slideAmount: 300
};

export default withWindowSize(HorizontalScrollWrapper);
<commit_msg>Update: making the scrolling when dragging smoother<commit_after>import React, { useRef, useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import Icon from '../../base/icons/Icon';
import withWindowSize from '../../util/withWindowSize';

const OuterWrapper = styled.div`
  overflow: hidden;
  position: relative;
`;

const InnerWrapper = styled.div`
  alignitems: center;
  display: flex;
  height: 100%;
  position: relative;
  white-space: nowrap;
  z-index: 0;
`;

const ScrollIcon = styled.div`
  align-items: center;
  cursor: pointer;
  display: flex;
  height: 100%;
  outline: 0;
  position: absolute;
  top: 0;
  z-index: 1;
`;

const ArrowContainer = styled.div`
  align-items: center;
  background-color: ${props => props.theme.colors.white};
  border-radius: 50%;
  box-shadow: 0 1px 1px ${props => props.theme.colors.boxShadowDark};
  color: ${props => props.theme.colors.gray9};
  display: flex;
  padding: 0.5em;
`;

const generateOnArrowKeyDownHandler = onKeyDown => event => {
  const code = event.code.toLowerCase();
  if (code === 'Enter' || code === 'Space') {
    onKeyDown();
  }
};

const ArrowLeft = ({ onClick }) => (
  <ScrollIcon
    role="button"
    tabIndex={0}
    style={{ left: '0', textAlign: 'left' }}
    onClick={onClick}
    onKeyDown={generateOnArrowKeyDownHandler(onClick)}
  >
    <ArrowContainer>
      <Icon name="chevron-left" />
    </ArrowContainer>
  </ScrollIcon>
);

ArrowLeft.propTypes = {
  onClick: PropTypes.func.isRequired
};

const ArrowRight = ({ onClick }) => (
  <ScrollIcon
    role="button"
    tabIndex={0}
    style={{ right: '0', textAlign: 'right' }}
    onClick={onClick}
    onKeyDown={generateOnArrowKeyDownHandler(onClick)}
  >
    <ArrowContainer>
      <Icon name="chevron-right" />
    </ArrowContainer>
  </ScrollIcon>
);

ArrowRight.propTypes = {
  onClick: PropTypes.func.isRequired
};

function HorizontalScrollWrapper({ windowWidth, children, slideAmount }) {
  const rootRef = useRef(null);
  const menuRef = useRef(null);
  const [rootWidth, setRootWidth] = useState(0);
  const [menuWidth, setMenuWidth] = useState(0);
  const [xPosition, setXPosition] = useState(0);
  const [cursorXPosition, setCursorXPosition] = useState(0);
  const [hasOverflow, setHasOverflow] = useState(false);
  const [isDragging, setIsDragging] = useState(false);

  useEffect(() => {
    const currentRootWidth = rootRef.current ? rootRef.current.clientWidth : 0;
    const currentMenuWidth = menuRef.current ? menuRef.current.scrollWidth : 0;

    if (currentRootWidth <= currentMenuWidth) {
      setRootWidth(currentRootWidth);
      setMenuWidth(currentMenuWidth);
      setHasOverflow(true);

      const absoluteXPosition = Math.abs(xPosition);
      if (currentRootWidth + absoluteXPosition > currentMenuWidth) {
        const distance = Math.abs(
          currentMenuWidth - currentRootWidth + xPosition
        );
        setXPosition(xPosition + distance);
      }
    } else if (hasOverflow) {
      setHasOverflow(false);
    }
  }, [windowWidth, rootRef.current, menuRef.current]);

  const handleDownEvent = downEvent => {
    if (!hasOverflow) return;

    let cursorX = 0;
    if (downEvent.type === 'mousedown') {
      cursorX = downEvent.pageX - xPosition;
    } else if (downEvent.type === 'touchstart') {
      const touchEvent = downEvent.changedTouches[0];
      cursorX = touchEvent.pageX - xPosition;
    }

    setCursorXPosition(cursorX);
    setIsDragging(true);
  };

  const handleMoveEvent = moveEvent => {
    if (!hasOverflow || !isDragging) return;

    let distance = 0;

    if (moveEvent.type === 'mousemove') {
      moveEvent.preventDefault();
      distance = moveEvent.pageX - cursorXPosition;
    } else if (moveEvent.type === 'touchmove') {
      const touchEvent = moveEvent.changedTouches[0];
      distance = touchEvent.pageX - cursorXPosition;
    }

    let newXPosition = (xPosition + distance) * 0.5;
    if (newXPosition > 0) {
      newXPosition = 0;
    }
    if (-newXPosition > menuWidth - rootWidth) {
      newXPosition = -(menuWidth - rootWidth);
    }

    setXPosition(newXPosition);
  };

  const handleUpEvent = () => {
    if (!hasOverflow || !isDragging) return;

    setIsDragging(false);
  };

  const handleLeftClick = event => {
    event.stopPropagation();
    event.preventDefault();

    let newXPosition = xPosition + slideAmount;
    if (newXPosition > 0) {
      newXPosition = 0;
    }

    setXPosition(newXPosition);
  };

  const handleRightClick = event => {
    event.stopPropagation();
    event.preventDefault();

    let newXPosition = xPosition - slideAmount;
    if (-newXPosition > menuWidth - rootWidth) {
      newXPosition = -(menuWidth - rootWidth);
    }

    setXPosition(newXPosition);
  };

  return (
    <OuterWrapper ref={rootRef}>
      <InnerWrapper
        ref={menuRef}
        role="presentation"
        onMouseDown={handleDownEvent}
        onMouseMove={handleMoveEvent}
        onMouseUp={handleUpEvent}
        onMouseLeave={handleUpEvent}
        onTouchStart={handleDownEvent}
        onTouchMove={handleMoveEvent}
        onTouchEnd={handleUpEvent}
        style={{
          transform: `translate3d(${xPosition}px, 0, 0)`,
          transition: `${isDragging ? '' : 'transform 0.3s ease-in-out'}`
        }}
      >
        {children}
      </InnerWrapper>
      {hasOverflow && xPosition < 0 && <ArrowLeft onClick={handleLeftClick} />}
      {hasOverflow && -xPosition < menuWidth - rootWidth && (
        <ArrowRight onClick={handleRightClick} />
      )}
    </OuterWrapper>
  );
}

HorizontalScrollWrapper.propTypes = {
  windowWidth: PropTypes.number,
  children: PropTypes.node,
  /** Set the number of pixels the contents will move when clicking left/right arrows */
  slideAmount: PropTypes.number
};

HorizontalScrollWrapper.defaultProps = {
  windowWidth: undefined,
  children: null,
  slideAmount: 300
};

export default withWindowSize(HorizontalScrollWrapper);
<|endoftext|>


<commit_before>/*
 * Laconica - a distributed open-source microblogging tool
 * Copyright (C) 2008, Controlez-Vous, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

$(document).ready(function(){
        // count character on keyup
        function counter(event){
            var maxLength     = 140;
            var currentLength = $("#status_textarea").val().length;
            var remaining = maxLength - currentLength;
            var counter   = $("#counter");
            counter.text(remaining);

            if (remaining <= 0) {
                counter.attr("class", "toomuch");
            } else {
                counter.attr("class", "");
            }
        }

        function submitonreturn(event) {
             if (event.keyCode == 13) {
                  $("#status_form").submit();
                  event.preventDefault();
                  event.stopPropagation();
                  return false;
             }
             return true;
        }

        if ($("#status_textarea").length) {
             $("#status_textarea").bind("keyup", counter);
             $("#status_textarea").bind("keydown", submitonreturn);

            // run once in case there's something in there
            counter();

             // set the focus
             $("#status_textarea").focus();
        }

     // XXX: refactor this code

     var favoptions = {dataType: 'xml',
               success: function(xml) {
                    var new_form = $('form.disfavor', xml).get(0);
                    var id = new_form.id.replace('disfavor', 'favor');
                    $('form#'+id).replace(new_form);
               }};

     var disoptions = {dataType: 'xml',
               success: function(xml) {
                    var new_form = $('form.favor', xml).get(0);
                    var id = new_form.id.replace('favor', 'disfavor');
                    $('form#'+id).replace(new_form);
               }};

     function addAjaxHidden() {
          var ajax = document.createElement('input');
          ajax.setAttribute('type', 'hidden');
          ajax.setAttribute('name', 'ajax');
          ajax.setAttribute('value', 1);
          this.appendChild(ajax);
     }

     $("form.favor").ajaxForm(favoptions);
     $("form.disfavor").ajaxForm(disoptions);

     $("form.favor").each(addAjaxHidden);
     $("form.disfavor").each(addAjaxHidden);
});

function doreply(nick) {
     rgx_username = /^[0-9a-zA-Z\-_.]*$/;
     if (nick.match(rgx_username)) {
          replyto = "@" + nick + " ";
          if ($("#status_textarea").length) {
               $("#status_textarea").val(replyto);
               $("#status_textarea").focus();
			   return false;
		  }
     }
     return true;
}

<commit_msg>replace -> replaceWith<commit_after>/*
 * Laconica - a distributed open-source microblogging tool
 * Copyright (C) 2008, Controlez-Vous, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

$(document).ready(function(){
        // count character on keyup
        function counter(event){
            var maxLength     = 140;
            var currentLength = $("#status_textarea").val().length;
            var remaining = maxLength - currentLength;
            var counter   = $("#counter");
            counter.text(remaining);

            if (remaining <= 0) {
                counter.attr("class", "toomuch");
            } else {
                counter.attr("class", "");
            }
        }

        function submitonreturn(event) {
             if (event.keyCode == 13) {
                  $("#status_form").submit();
                  event.preventDefault();
                  event.stopPropagation();
                  return false;
             }
             return true;
        }

        if ($("#status_textarea").length) {
             $("#status_textarea").bind("keyup", counter);
             $("#status_textarea").bind("keydown", submitonreturn);

            // run once in case there's something in there
            counter();

             // set the focus
             $("#status_textarea").focus();
        }

     // XXX: refactor this code

     var favoptions = {dataType: 'xml',
               success: function(xml) {
                    var new_form = $('form.disfavor', xml).get(0);
                    var id = new_form.id.replace('disfavor', 'favor');
                    $('form#'+id).replaceWith(new_form);
               }};

     var disoptions = {dataType: 'xml',
               success: function(xml) {
                    var new_form = $('form.favor', xml).get(0);
                    var id = new_form.id.replace('favor', 'disfavor');
                    $('form#'+id).replaceWith(new_form);
               }};

     function addAjaxHidden() {
          var ajax = document.createElement('input');
          ajax.setAttribute('type', 'hidden');
          ajax.setAttribute('name', 'ajax');
          ajax.setAttribute('value', 1);
          this.appendChild(ajax);
     }

     $("form.favor").ajaxForm(favoptions);
     $("form.disfavor").ajaxForm(disoptions);

     $("form.favor").each(addAjaxHidden);
     $("form.disfavor").each(addAjaxHidden);
});

function doreply(nick) {
     rgx_username = /^[0-9a-zA-Z\-_.]*$/;
     if (nick.match(rgx_username)) {
          replyto = "@" + nick + " ";
          if ($("#status_textarea").length) {
               $("#status_textarea").val(replyto);
               $("#status_textarea").focus();
			   return false;
		  }
     }
     return true;
}

<|endoftext|>


<commit_before><commit_msg>Update project jszip to v2.6.0<commit_after><|endoftext|>


<commit_before>import React from "react";
import PropTypes from 'prop-types';
import InputMask from "inputmask-core";
import { utils } from "../utils";
import cx from "classnames";

/**
 * Master Input component. To be used as core for different input types
 * components. Accepts all input properties and also supports custom
 * and maxlenght/required validations. Allows input masking.
 */
class Input extends React.Component {
  constructor(props) {
    super(props);
    // Initial state
    this.state = {
      "value": props.value || "",
      "errorText": null,
      "isValid": true,
      "remaining": props.maxLength
    };

    // Configure input mask if required
    if (this.props.mask) {
      let maskOptions = {
        "pattern": this.props.mask,
        "value": this.props.value
      };

      this.mask = new InputMask(maskOptions);
    }

    // Display a console warning if custom validation is set w/o an error message
    if (this.props.validator && !this.props.errorText) {
      console.warn(
        "You set a custom validator without error text message. Please use 'errorText' property to set it up."
      );
    }
  }

  _updateMaskSelection = () => {
    this.mask.selection = utils.getSelection(this.input);
  };

  _updateInputSelection = () => {
    let selection = this.mask.selection;
    utils.setSelection(this.input, selection);
  };

  _getDisplayValue = () => {
    let value = this.mask.getValue();
    return value === this.mask.emptyValue ? "" : value;
  };

  _handleKeyDown = event => {
    /**
     * Handle proper deletion of masked input characters.
     * We do this onKeyDown because backspace key event
     * won't reach onKeyPress event.
     */
    if (this.props.mask) {
      if (event.key === "Backspace") {
        event.preventDefault();
        this._updateMaskSelection();

        if (this.mask.backspace()) {
          let value = this._getDisplayValue();
          event.target.value = value;
          if (value) {
            this._updateInputSelection();
          }
        }
      }

      // Fire onChange event
      this._handleChange(event);
    }
  };

  _handleKeyPress = event => {
    if (this.props.mask) {
      // Ignore modified key presses and enter key to allow form submission
      if (
        event.metaKey ||
        event.altKey ||
        event.ctrlKey ||
        event.key === "Enter"
      ) {
        return;
      }

      event.preventDefault();
      this._updateMaskSelection();

      // Check if pressed key corresponds to mask pattern
      if (this.mask.input(event.key || event.data)) {
        event.target.value = this.mask.getValue();
        this._updateInputSelection();
      }

      // Fire onChange event
      this._handleChange(event);
    }
  };

  _handlePaste = event => {
    /**
     * Support pasting text in masked input. If text doesn't
     * pass mask validation, it won't be pasted.
     */
    if (this.props.mask) {
      event.preventDefault();
      this._updateMaskSelection();

      if (this.mask.paste(event.clipboardData.getData("Text"))) {
        event.target.value = this.mask.getValue();
        // Timeout needed for IE
        setTimeout(this._updateInputSelection, 0);
      }

      // Fire onChange event
      this._handleChange(event);
    }
  };

  _handleBeforeChange = event => {
    if (this.props.onBeforeChange) {
      this.props.onBeforeChange();
    }
  };

  _validate = (inputValue) => {

    /* Validate max character length */
    if (this.props.maxLength) {
      // Keep difference between maxlength and input value in state for count
      this.setState({
        "remaining": this.props.maxLength - inputValue.length
      });
      // Make sure the user input is less than maxLength value
      if (inputValue.length > this.props.maxLength) {
        this.setState({
          "value": inputValue.substring(0, this.props.maxLength),
          "remaining": 0
        });
        return false;
      }
    }

    /* Execute custom validator and change state and error messages accordingly */
    let customValidationPass = false;
    if (this.props.validator) {
      let valid = this.props.validator(inputValue);
      if (!valid) {
        this.setState({
          "errorText": this.props.errorText,
          "isValid": false
        });
      } else {
        customValidationPass = true;
      }
    }

    /* If the field is required, and it has no value, change state and display error message */
    if (this.props.required) {
      if (!inputValue.length) {
        this.setState({
          "errorText": this.props.requiredText || "This field is required.",
          "isValid": false
        });
      } else {
        /* Set state after both validation checks to display both when required */
        if (this.props.validator) {
          if (customValidationPass) {
            this.setState({ "isValid": true });
          }
        } else {
          this.setState({
            "isValid": true
          });
        }
      }
    }
  }

  _handleChange = event => {
    let inputValue = event.target.value;

    /* Masked input validations */
    if (this.props.mask) {
      let maskValue = this.mask.getValue();

      if (inputValue !== maskValue) {
        // Cut or delete operations will have shortened the value
        if (inputValue.length < maskValue.length) {
          let sizeDiff = maskValue.length - inputValue.length;
          this._updateMaskSelection();
          this.mask.selection.end = this.mask.selection.start + sizeDiff;
          this.mask.backspace();
        }
        // Set new input value based on mask
        let newValue = this._getDisplayValue();
        inputValue = newValue;

        if (newValue) {
          this._updateInputSelection();
        }
      }
    }

    if(this._validate(inputValue) != false) {
      /* Regardless of validations, set value in the component state */
      this.setState({
        "value": inputValue
        }, () => {
        if (this.props.onChange) {
          this.props.onChange(event);
        }
      });
    } else {
      /* Execute application code function at this point if available */
      if (this.props.onChange) {
        this.props.onChange(event);
      }
    }
  };

  render() {
    const {
      className,
      small,
      medium,
      large,
      type,
      name,
      multiline,
      placeholder,
      disabled,
      hidden,
      errorLocation,
      checked,
      ...props // eslint-disable-line no-unused-vars
    } = this.props;

    /* If checkbox, we need to render only input component (no wrappers) */
    let isCheckbox = type === "checkbox";

    let inputClasses = cx({
      "input": !isCheckbox,
      "checkbox": isCheckbox,
      "invalid": !this.state.isValid,
      "blockInput": errorLocation === "bottom",
      "small": small,
      "medium": medium,
      "large": large,
      "max": !small && !medium && !large,
      disabled,
      hidden
    });

    let eventHandlers = {
      "onClick": this._handleBeforeChange,
      "onChange": this._handleChange,
      "onKeyDown": this._handleKeyDown,
      "onKeyPress": this._handleKeyPress,
      "onPaste": this._handlePaste
    };

    let inputElement = multiline
      ? <textarea
          name={name}
          value={this.state.value}
          placeholder={placeholder}
          styleName={inputClasses}
          className={cx(className)}
          onChange={this._handleChange}
        />
      : <input
          type={type}
          name={name}
          value={this.state.value}
          placeholder={placeholder}
          styleName={inputClasses}
          className={cx(className)}
          ref={input => {
            this.input = input;
          }}
          {...eventHandlers}
        />;

    let errorTextElement =
      this.state.errorText &&
      {this.state.errorText};

    return isCheckbox
      ? <input
          type="checkbox"
          name={name}
          styleName={inputClasses}
          className={cx(className)}
          checked={checked}
          {...eventHandlers}
        />
      :

          {inputElement}
          {this.state.isValid ? null : errorTextElement}

;
  }
}

Input.propTypes = {
  /**
   * Defines a custom css class name.
   * @examples 'custom-imput'
   */
  "className": PropTypes.string,
  /**
   * Defines the input type. Accepts HTML5 input types.
   * @examples 'text', 'checkbox', 'radio', 'password', 'email'
   */
  "type": PropTypes.string,
  /**
   * Defines a name for the input.
   * @examples '<Input type="text" name="test"/>'
   */
  "name": PropTypes.string,
  /**
   * Sets the field as required. Will be validated onChange.
   * @examples '<Input type="text" required/>'
   */
  "required": PropTypes.bool,
  /**
   * Defines error message to be displayed when input is empty and required.
   * Otherwise, it will display pre-defined required field message.
   * @examples '<Input type="text" required requiredText="Custom required msg"/>'
   */
  "requiredText": PropTypes.string,
  /**
   * Defines error message to be displayed on custom validation.
   * @examples '<Input type="text" validator={this.validateTest} errorText="Custom validation msg"/>'
   */
  "errorText": PropTypes.string,
  /**
   * Defines error messages location (on validation).
   * > Valid values are 'right' and 'bottom'.
   * > Default value is 'right'.
   * @examples '<Input type="text" required requiredText="Custom required msg" errorLocation="buttom"/>'
   */
  "errorLocation": PropTypes.string,
  /**
   * Defines a determinate value for the input.
   * @examples '<Input type="text" value="test input"/>'
   */
  "value": PropTypes.string,
  /**
   * Determines if the input is disabled.
   * @examples '<Input type="text" disabled/>'
   */
  "disabled": PropTypes.bool,
  /**
   * Determines if the input is hidden.
   * @examples '<Input type="text" hidden/>'
   */
  "hidden": PropTypes.bool,
  /**
   * Only for input type checkbox. Determines if the input is checked.
   * @examples '<Input type="checkbox" checked/>'
   */
  "checked": PropTypes.bool,
  /**
   * Sets a maximum character lenght that will be validated onChange.
   * @examples '<Input type="text" maxLenght={25}/>'
   */
  "maxLength": PropTypes.number,
  /**
   * Defines placeholder text.
   * @examples '<Input type="text" placeholder="test input"/>'
   */
  "placeholder": PropTypes.string,
  /**
   * Renders a textarea element instead. To be used in TextArea component.
   * @examples '<Input multiline/>'
   */
  "multiline": PropTypes.bool,
  /**
   * Defines a small sized input element.
   * @examples '<Input type="text" small/>'
   */
  "small": PropTypes.bool,
  /**
   * Defines a medium sized input element.
   * @examples '<Input type="text" small/>'
   */
  "medium": PropTypes.bool,
  /**
   * Defines a large sized input element.
   * @examples '<Input type="text" small/>'
   */
  "large": PropTypes.bool,
  /**
   * Defines a pattern for masked input.
   * @examples '<Input type="text" mask="1111-1111-1111"/>'
   */
  "mask": PropTypes.string,
  /**
   * Sets a custom validator function that will be executed onChange.
   * > Should return a boolean value, otherwise will evaluate to false.
   * > Error message to be displayed will come from errorText prop.
   * @examples '<Input type="text" validator={this.validateTest} errorText="Custom validation msg"/>'
   */
  "validator": PropTypes.func,
  /**
     * Sets a handler function to be executed before onChange event occurs (executed onClick).
     * @examples <Input type="text" onBeforeChange={this.customOnClickFunc}/>
     */
  "onBeforeChange": PropTypes.func,
  /**
     * Sets a handler function to be executed when onChange event occurs.
     * @examples <Input type="text" onChange={this.customOnChangeFunc}/>
     */
  "onChange": PropTypes.func
};

Input.defaultProps = {
  "className": "",
  "disabled": false,
  "hidden": false,
  "focus": false,
  "errorLocation": "right"
};

export default Input;
<commit_msg>Persist event before passing it.<commit_after>import React from "react";
import PropTypes from 'prop-types';
import InputMask from "inputmask-core";
import { utils } from "../utils";
import cx from "classnames";

/**
 * Master Input component. To be used as core for different input types
 * components. Accepts all input properties and also supports custom
 * and maxlenght/required validations. Allows input masking.
 */
class Input extends React.Component {
  constructor(props) {
    super(props);
    // Initial state
    this.state = {
      "value": props.value || "",
      "errorText": null,
      "isValid": true,
      "remaining": props.maxLength
    };

    // Configure input mask if required
    if (this.props.mask) {
      let maskOptions = {
        "pattern": this.props.mask,
        "value": this.props.value
      };

      this.mask = new InputMask(maskOptions);
    }

    // Display a console warning if custom validation is set w/o an error message
    if (this.props.validator && !this.props.errorText) {
      console.warn(
        "You set a custom validator without error text message. Please use 'errorText' property to set it up."
      );
    }
  }

  _updateMaskSelection = () => {
    this.mask.selection = utils.getSelection(this.input);
  };

  _updateInputSelection = () => {
    let selection = this.mask.selection;
    utils.setSelection(this.input, selection);
  };

  _getDisplayValue = () => {
    let value = this.mask.getValue();
    return value === this.mask.emptyValue ? "" : value;
  };

  _handleKeyDown = event => {
    /**
     * Handle proper deletion of masked input characters.
     * We do this onKeyDown because backspace key event
     * won't reach onKeyPress event.
     */
    if (this.props.mask) {
      if (event.key === "Backspace") {
        event.preventDefault();
        this._updateMaskSelection();

        if (this.mask.backspace()) {
          let value = this._getDisplayValue();
          event.target.value = value;
          if (value) {
            this._updateInputSelection();
          }
        }
      }

      // Fire onChange event
      this._handleChange(event);
    }
  };

  _handleKeyPress = event => {
    if (this.props.mask) {
      // Ignore modified key presses and enter key to allow form submission
      if (
        event.metaKey ||
        event.altKey ||
        event.ctrlKey ||
        event.key === "Enter"
      ) {
        return;
      }

      event.preventDefault();
      this._updateMaskSelection();

      // Check if pressed key corresponds to mask pattern
      if (this.mask.input(event.key || event.data)) {
        event.target.value = this.mask.getValue();
        this._updateInputSelection();
      }

      // Fire onChange event
      this._handleChange(event);
    }
  };

  _handlePaste = event => {
    /**
     * Support pasting text in masked input. If text doesn't
     * pass mask validation, it won't be pasted.
     */
    if (this.props.mask) {
      event.preventDefault();
      this._updateMaskSelection();

      if (this.mask.paste(event.clipboardData.getData("Text"))) {
        event.target.value = this.mask.getValue();
        // Timeout needed for IE
        setTimeout(this._updateInputSelection, 0);
      }

      // Fire onChange event
      this._handleChange(event);
    }
  };

  _handleBeforeChange = event => {
    if (this.props.onBeforeChange) {
      this.props.onBeforeChange();
    }
  };

  _validate = (inputValue) => {
    /* Validate max character length */
    if (this.props.maxLength) {
      // Keep difference between maxlength and input value in state for count
      this.setState({
        "remaining": this.props.maxLength - inputValue.length
      });
      // Make sure the user input is less than maxLength value
      if (inputValue.length > this.props.maxLength) {
        this.setState({
          "value": inputValue.substring(0, this.props.maxLength),
          "remaining": 0
        });
        return false;
      }
    }

    /* Execute custom validator and change state and error messages accordingly */
    let customValidationPass = false;
    if (this.props.validator) {
      let valid = this.props.validator(inputValue);
      if (!valid) {
        this.setState({
          "errorText": this.props.errorText,
          "isValid": false
        });
      } else {
        customValidationPass = true;
      }
    }

    /* If the field is required, and it has no value, change state and display error message */
    if (this.props.required) {
      if (!inputValue.length) {
        this.setState({
          "errorText": this.props.requiredText || "This field is required.",
          "isValid": false
        });
      } else {
        /* Set state after both validation checks to display both when required */
        if (this.props.validator) {
          if (customValidationPass) {
            this.setState({ "isValid": true });
          }
        } else {
          this.setState({
            "isValid": true
          });
        }
      }
    }
  }

  _handleChange = event => {
    event.persist();
    let inputValue = event.target.value;

    /* Masked input validations */
    if (this.props.mask) {
      let maskValue = this.mask.getValue();

      if (inputValue !== maskValue) {
        // Cut or delete operations will have shortened the value
        if (inputValue.length < maskValue.length) {
          let sizeDiff = maskValue.length - inputValue.length;
          this._updateMaskSelection();
          this.mask.selection.end = this.mask.selection.start + sizeDiff;
          this.mask.backspace();
        }
        // Set new input value based on mask
        let newValue = this._getDisplayValue();
        inputValue = newValue;

        if (newValue) {
          this._updateInputSelection();
        }
      }
    }

    this._validate(inputValue);
    this.setState({
        "value": inputValue
        }, () => {
          if (this.props.onChange) {
            this.props.onChange(event);
          }
        });
  };

  render() {
    const {
      className,
      small,
      medium,
      large,
      type,
      name,
      multiline,
      placeholder,
      disabled,
      hidden,
      errorLocation,
      checked,
      ...props // eslint-disable-line no-unused-vars
    } = this.props;

    /* If checkbox, we need to render only input component (no wrappers) */
    let isCheckbox = type === "checkbox";

    let inputClasses = cx({
      "input": !isCheckbox,
      "checkbox": isCheckbox,
      "invalid": !this.state.isValid,
      "blockInput": errorLocation === "bottom",
      "small": small,
      "medium": medium,
      "large": large,
      "max": !small && !medium && !large,
      disabled,
      hidden
    });

    let eventHandlers = {
      "onClick": this._handleBeforeChange,
      "onChange": this._handleChange,
      "onKeyDown": this._handleKeyDown,
      "onKeyPress": this._handleKeyPress,
      "onPaste": this._handlePaste
    };

    let inputElement = multiline
      ? <textarea
          name={name}
          value={this.state.value}
          placeholder={placeholder}
          styleName={inputClasses}
          className={cx(className)}
          onChange={this._handleChange}
        />
      : <input
          type={type}
          name={name}
          value={this.state.value}
          placeholder={placeholder}
          styleName={inputClasses}
          className={cx(className)}
          ref={input => {
            this.input = input;
          }}
          {...eventHandlers}
        />;

    let errorTextElement =
      this.state.errorText &&
      {this.state.errorText};

    return isCheckbox
      ? <input
          type="checkbox"
          name={name}
          styleName={inputClasses}
          className={cx(className)}
          checked={checked}
          {...eventHandlers}
        />
      :

          {inputElement}
          {this.state.isValid ? null : errorTextElement}

;
  }
}

Input.propTypes = {
  /**
   * Defines a custom css class name.
   * @examples 'custom-imput'
   */
  "className": PropTypes.string,
  /**
   * Defines the input type. Accepts HTML5 input types.
   * @examples 'text', 'checkbox', 'radio', 'password', 'email'
   */
  "type": PropTypes.string,
  /**
   * Defines a name for the input.
   * @examples '<Input type="text" name="test"/>'
   */
  "name": PropTypes.string,
  /**
   * Sets the field as required. Will be validated onChange.
   * @examples '<Input type="text" required/>'
   */
  "required": PropTypes.bool,
  /**
   * Defines error message to be displayed when input is empty and required.
   * Otherwise, it will display pre-defined required field message.
   * @examples '<Input type="text" required requiredText="Custom required msg"/>'
   */
  "requiredText": PropTypes.string,
  /**
   * Defines error message to be displayed on custom validation.
   * @examples '<Input type="text" validator={this.validateTest} errorText="Custom validation msg"/>'
   */
  "errorText": PropTypes.string,
  /**
   * Defines error messages location (on validation).
   * > Valid values are 'right' and 'bottom'.
   * > Default value is 'right'.
   * @examples '<Input type="text" required requiredText="Custom required msg" errorLocation="buttom"/>'
   */
  "errorLocation": PropTypes.string,
  /**
   * Defines a determinate value for the input.
   * @examples '<Input type="text" value="test input"/>'
   */
  "value": PropTypes.string,
  /**
   * Determines if the input is disabled.
   * @examples '<Input type="text" disabled/>'
   */
  "disabled": PropTypes.bool,
  /**
   * Determines if the input is hidden.
   * @examples '<Input type="text" hidden/>'
   */
  "hidden": PropTypes.bool,
  /**
   * Only for input type checkbox. Determines if the input is checked.
   * @examples '<Input type="checkbox" checked/>'
   */
  "checked": PropTypes.bool,
  /**
   * Sets a maximum character lenght that will be validated onChange.
   * @examples '<Input type="text" maxLenght={25}/>'
   */
  "maxLength": PropTypes.number,
  /**
   * Defines placeholder text.
   * @examples '<Input type="text" placeholder="test input"/>'
   */
  "placeholder": PropTypes.string,
  /**
   * Renders a textarea element instead. To be used in TextArea component.
   * @examples '<Input multiline/>'
   */
  "multiline": PropTypes.bool,
  /**
   * Defines a small sized input element.
   * @examples '<Input type="text" small/>'
   */
  "small": PropTypes.bool,
  /**
   * Defines a medium sized input element.
   * @examples '<Input type="text" small/>'
   */
  "medium": PropTypes.bool,
  /**
   * Defines a large sized input element.
   * @examples '<Input type="text" small/>'
   */
  "large": PropTypes.bool,
  /**
   * Defines a pattern for masked input.
   * @examples '<Input type="text" mask="1111-1111-1111"/>'
   */
  "mask": PropTypes.string,
  /**
   * Sets a custom validator function that will be executed onChange.
   * > Should return a boolean value, otherwise will evaluate to false.
   * > Error message to be displayed will come from errorText prop.
   * @examples '<Input type="text" validator={this.validateTest} errorText="Custom validation msg"/>'
   */
  "validator": PropTypes.func,
  /**
     * Sets a handler function to be executed before onChange event occurs (executed onClick).
     * @examples <Input type="text" onBeforeChange={this.customOnClickFunc}/>
     */
  "onBeforeChange": PropTypes.func,
  /**
     * Sets a handler function to be executed when onChange event occurs.
     * @examples <Input type="text" onChange={this.customOnChangeFunc}/>
     */
  "onChange": PropTypes.func
};

Input.defaultProps = {
  "className": "",
  "disabled": false,
  "hidden": false,
  "focus": false,
  "errorLocation": "right"
};

export default Input;
<|endoftext|>