/**
@module ember-flexberry
*/
import Component from '@ember/component';
import { observer } from '@ember/object';
import { isNone } from '@ember/utils';
import RequiredActionsMixin from '../mixins/required-actions';
import DomActionsMixin from '../mixins/dom-actions';
import DynamicActionsMixin from '../mixins/dynamic-actions';
import DynamicPropertiesMixin from '../mixins/dynamic-properties';
import { translationMacro as t } from 'ember-i18n';
/**
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-dialog').
@property {String} flexberryClassNames.wrapper Component's wrapping <div> CSS-class name ('flexberry-dialog').
@property {String} flexberryClassNames.header Component's header block CSS-class name ('flexberry-dialog-header').
@property {String} flexberryClassNames.content Component's content block CSS-class name ('flexberry-dialog-content').
@property {String} flexberryClassNames.toolbar Component's toolbar block CSS-class name ('flexberry-dialog-toolbar').
@property {String} flexberryClassNames.approveButton Component's approve button CSS-class name ('flexberry-dialog-approve-button').
@property {String} flexberryClassNames.cancelButton Component's cancel button CSS-class name ('flexberry-dialog-cancel-button').
@property {String} flexberryClassNames.closeButton Component's close button CSS-class name ('flexberry-dialog-close-button').
@readonly
@static
@for FlexberryDialogComponent
*/
const flexberryClassNamesPrefix = 'flexberry-dialog';
const flexberryClassNames = {
prefix: flexberryClassNamesPrefix,
wrapper: flexberryClassNamesPrefix,
header: flexberryClassNamesPrefix + '-header',
content: flexberryClassNamesPrefix + '-content',
toolbar: flexberryClassNamesPrefix + '-toolbar',
approveButton: flexberryClassNamesPrefix + '-approve-button',
cancelButton: flexberryClassNamesPrefix + '-cancel-button',
closeButton: flexberryClassNamesPrefix + '-close-button'
};
/**
Flexberry dialog component with [Semantic UI modal style](http://semantic-ui.com/modules/modal.html).
@class FlexberryDialogComponent
@extends <a href="https://emberjs.com/api/ember/release/classes/Component">Component</a>
@uses RequiredActionsMixin
@uses DomActionsMixin
@uses DynamicActionsMixin
@uses DynamicPropertiesMixin
*/
let FlexberryDialogComponent = Component.extend(
RequiredActionsMixin,
DomActionsMixin,
DynamicActionsMixin,
DynamicPropertiesMixin, {
/**
Selected from DOM dialog block.
@property _dialog
@type <a href="http://learn.jquery.com/using-jquery-core/jquery-object/">jQuery-object</a>
@private
*/
_dialog: null,
/**
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-dialog class="large" approve=(action "onDialogApprove")}}
```
@property classNames
@type String[]
@default ['flexberry-dialog', 'ui', 'modal']
*/
classNames: [flexberryClassNames.wrapper, 'ui', 'modal'],
/**
Component's content CSS-class.
@property contentClass
@type String
@default null
*/
contentClass: null,
/**
Component's caption.
@property caption
@type String
@default null
*/
caption: null,
/**
Component's content.
@property content
@type String
@default null
*/
content: null,
/**
Component's approve button caption.
@property approveButtonCaption
@type String
@default t('components.flexberry-dialog.approve-button.caption')
*/
approveButtonCaption: t('components.flexberry-dialog.approve-button.caption'),
/**
Component's deny button caption.
@property denyButtonCaption
@type String
@default t('components.flexberry-dialog.deny-button.caption')
*/
denyButtonCaption: t('components.flexberry-dialog.deny-button.caption'),
/**
Component's vertical offset to allow for content outside of dialog, for example a close button, to be centered.
@property offset
@type Number
@default 0
*/
offset: 0,
/**
Flag: indicates whether multiple dialogs are allowed at the same time.
@property allowMultiple
@type Boolean
@default false
*/
allowMultiple: false,
/**
Flag: indicates whether dialog is closable (can be closed on it's dimmer click).
@property allowMultiple
@type Boolean
@default false
*/
closable: false,
/**
Component's transition animation name.
@property duration
@type String
@default 'scale'
*/
transition: 'scale',
/**
Component's animation duration (in milliseconds).
@property duration
@type Number
@default 200
*/
duration: 200,
/**
Flag: indicates whether dialog is visible or not.
If true, then dialog will be shown, otherwise dialog will be closed.
@property visible
@type Boolean
@default false
*/
visible: false,
/**
Observes {{#crossLink "FlexberryDialogComponent/visible:property"}}'visible' property{{/crossLink}}.
Shows dialog if property is true, otherwise hides dialog.
@method _visibleDidChange
@private
*/
_visibleDidChange: observer('visible', function() {
let $dialog = this.get('_dialog');
if (isNone($dialog)) {
return;
}
if (this.get('visible')) {
$dialog.modal('show');
} else {
$dialog.modal('hide');
}
}),
/**
Initializes DOM-related component's properties.
*/
didInsertElement() {
this._super(...arguments);
// Initialize Semantic UI modal.
let $dialog = this.$().modal({
autofocus: false,
detachable: true,
observeChanges: false,
offset: this.get('offset'),
allowMultiple: this.get('allowMultiple'),
closable: this.get('closable'),
transition: this.get('transition'),
duration: this.get('duration'),
onShow: () => {
let e = { showDialog: true, target: this.get('_dialog') };
this.sendDynamicAction('beforeShow', e);
return e.showDialog;
},
onHide: () => {
if (this.get('isDestroying') || this.get('isDestroyed')) {
// Prevent hide animation on destroyed component to avoid animation exceptions.
return false;
}
let e = { closeDialog: true, target: this.get('_dialog') };
this.sendDynamicAction('beforeHide', e);
return e.closeDialog;
},
onVisible: () => {
this.set('visible', true);
let e = { target: this.get('_dialog') };
this.sendDynamicAction('show', e);
},
onHidden: () => {
this.set('visible', false);
let e = { target: this.get('_dialog') };
this.sendDynamicAction('hide', e);
},
onApprove: () => {
let e = { closeDialog: true, target: this.get('_dialog') };
this.sendDynamicAction('approve', e);
return e.closeDialog;
},
onDeny: () => {
let e = { closeDialog: true, target: this.get('_dialog') };
this.sendDynamicAction('deny', e);
return e.closeDialog;
}
});
// Show dialog if necessary.
if (this.get('visible') && !isNone($dialog)) {
$dialog.modal('show');
}
this.set('_dialog', $dialog);
},
/**
Destroys DOM-related component's properties.
*/
willDestroyElement() {
this._super(...arguments);
let $dialog = this.get('_dialog');
if (isNone($dialog)) {
return;
}
// Remove dialog from DOM (from its dimmer).
$dialog.remove();
// Hide dialog's dimmer.
$dialog.modal('hideDimmer');
// Destroy dialog.
$dialog.modal('destroy');
},
/**
Component's action invoking when dialog starts to show.
@method sendingActions.beforeShow
*/
/**
Component's action invoking when dialog starts to hide.
@method sendingActions.beforeHide
*/
/**
Component's action invoking when dialog is shown.
@method sendingActions.show
*/
/**
Component's action invoking when dialog is hidden.
@method sendingActions.hide
*/
/**
Component's action invoking when dialog is approved.
@method sendingActions.approve
*/
/**
Component's action invoking when dialog is denied.
@method sendingActions.deny
*/
}
);
// Add component's CSS-class names as component's class static constants
// to make them available outside of the component instance.
FlexberryDialogComponent.reopenClass({
flexberryClassNames
});
export default FlexberryDialogComponent;