APIs

Show:
/**
  @module ember-flexberry
*/

import Component from '@ember/component';
import $ from 'jquery';
import RequiredActionsMixin from '../mixins/required-actions';
import DomActionsMixin from '../mixins/dom-actions';
import DynamicPropertiesMixin from '../mixins/dynamic-properties';
import DynamicActionsMixin from '../mixins/dynamic-actions';

/**
  Component's CSS-classes names.
  JSON-object containing string constants with CSS-classes names related to component's .hbs markup elements.

  @property {Object} flexberryClassNames
  @property {String} flexberryClassNames.prefix Component's CSS-class names prefix ('flexberry-colorpicker').
  @property {String} flexberryClassNames.wrapper Component's wrapping <div> CSS-class name ('flexberry-colorpicker').
  @readonly
  @static

  @for FlexberryColorpickerComponent
*/
const flexberryClassNamesPrefix = 'flexberry-colorpicker';
const flexberryClassNames = {
  prefix: flexberryClassNamesPrefix,
  wrapper: flexberryClassNamesPrefix,
  input: flexberryClassNamesPrefix + '-input'
};

/**
  Flexberry colorpicker component based on jquery-minicolors plugin (see http://labs.abeautifulsite.net/jquery-minicolors).

  Usage:
  templates/my-form.hbs
  ```handlebars
  {{flexberry-colorpicker
    value=model.color
    change=(action "onModelColorChange")
  }}
  ```

  controllers/my-form.js
  ```javascript
  actions: {
    onModelColorChange(e) {
      // Set new value to model's 'color' property.
      this.set('model.color', e.newValue);

      // Log original jQuery 'change' event object.
      console.log(e.originalEvent);
    }
  }
  ```

  Usage with {{#crossLink "FlexberryDdauCheckboxActionsHandlerMixin"}}flexberry-ddau-checkbox-actions-handler mixin{{/crossLink}}:
  ```handlebars
  {{flexberry-colorpicker
    value=model.color
    change=(action "onColorpickerChange" "model.color")
  }}
  ```

  controllers/my-form.js
  ```javascript
  import Controller from '@ember/controller';
  import FlexberryColorpickerActionsHandlerMixin from 'ember-flexberry/mixins/flexberry-colorpicker-actions-handler';

  export default Controller.extend(FlexberryColorpickerActionsHandlerMixin, {
  });
  ```

  @class FlexberryColorpickerComponent
  @extends <a href="https://emberjs.com/api/ember/release/classes/Component">Component</a>
  @uses RequiredActionsMixin
  @uses DomActionsMixin
  @uses DynamicActionsMixin
  @uses DynamicPropertiesMixin
*/
let FlexberryColorpickerComponent = Component.extend(
  RequiredActionsMixin,
  DomActionsMixin,
  DynamicActionsMixin,
  DynamicPropertiesMixin, {

    /**
      Component's required actions names.
      For actions enumerated in this array an assertion exceptions will be thrown,
      if actions handlers are not defined for them.

      @property _requiredActions
      @type String[]
      @default ['change']
    */
    _requiredActionNames: undefined,

    /**
      Reference to component's CSS-classes names.
      Must be also a component's instance property to be available from component's .hbs template.
    */
    flexberryClassNames,

    /**
      Component's wrapping <div> CSS-classes names.

      Any other CSS-classes can be added through component's 'class' property.
      ```handlebars
      {{flexberry-icon
        class="map icon"
      }}
      ```

      @property classNames
      @type String[]
      @default ['flexberry-colorpicker']
    */
    classNames: [flexberryClassNames.wrapper],

    actions: {
      /**
        Handles inner input's bubbled 'change' action.
        Invokes component's {{#crossLink "FlexberryColorpicker/sendingActions.change:method"}}'change'{{/crossLink}} action.

        @method actions.change
        @param {Object} e [jQuery event object](http://api.jquery.com/category/events/event-object/)
        which describes inner input's 'change' event.
      */
      change(e) {
        let $input = $(e.target);
        if (!$input.hasClass(flexberryClassNames.input)) {
          return false;
        }

        let { value, opacity } = $input.data('minicolors-lastChange') || { value: null, opacity: null };

        // Invoke component's custom 'change' action.
        this.sendDynamicAction('change', {
          newValue: value,
          newOpacity: opacity,
          originalEvent: e
        });

        // Prevent second call to this.sendAction('change', ...) inside dom-actions mixin,
        // otherwise component's outer 'change' action handler will be called twice.
        return false;
      }
    },

    /**
      An overridable method called when objects are instantiated.
    */
    init() {
      this._super(...arguments);
      this.set('_requiredActionNames', ['change']);
    },

    /**
      Initializes DOM-related component's properties.
    */
    didInsertElement() {
      this._super(...arguments);

      // Initialize jquery-minicolors (see more settings http://labs.abeautifulsite.net/jquery-minicolors/#settings).
      this.$(`.${flexberryClassNames.input}`).minicolors({
        theme: 'semanticui'
      });
    },

    /**
      Destroys DOM-related component's properties.
    */
    willDestroyElement() {
      this._super(...arguments);

      // Destroys jquery-minicolors.
      this.$(`.${flexberryClassNames.input}`).minicolors('destroy');
    }

    /**
      Component's action invoking when color changed.

      @method sendingActions.change
      @param {Object} e Action's event object.
      @param {Boolean} e.newValue Component's new value.
      @param {Object} e.originalEvent [jQuery event object](http://api.jquery.com/category/events/event-object/) which describes inner input's 'change' event.
    */
  }
);

// Add component's CSS-class names as component's class static constants
// to make them available outside of the component instance.
FlexberryColorpickerComponent.reopenClass({
  flexberryClassNames
});

export default FlexberryColorpickerComponent;