diff --git a/addon/components/button-dropdown-menu.js b/addon/components/button-dropdown-menu.js new file mode 100644 index 0000000000..f8568d8016 --- /dev/null +++ b/addon/components/button-dropdown-menu.js @@ -0,0 +1,16 @@ +import FlexberryBaseComponent from 'ember-flexberry/components/flexberry-base-component'; + +export default FlexberryBaseComponent.extend({ + classNames: ['button-dropdown-menu', 'menu'], + + actions: { + /** + * Call action of a clicked button. + */ + sendButtonAction() { + /* eslint-disable ember/closure-actions */ + this.sendAction('sendButtonAction', ...arguments); + /* eslint-enable ember/closure-actions */ + } + } +}); diff --git a/addon/components/edit-panel.js b/addon/components/edit-panel.js new file mode 100644 index 0000000000..09163f20c3 --- /dev/null +++ b/addon/components/edit-panel.js @@ -0,0 +1,262 @@ +/** + @module ember-flexberry + */ +import $ from 'jquery'; +import { isNone } from '@ember/utils'; +import { A } from '@ember/array'; +import { assert } from '@ember/debug'; +import { computed } from '@ember/object'; +import { sort } from '@ember/object/computed'; +import FlexberryBaseComponent from 'ember-flexberry/components/flexberry-base-component'; + +export default FlexberryBaseComponent.extend({ + + classNames: ['flexberry-edit-panel'], + + /** + Edit panel current width. + + @property _editPanelWidth + @type Number + @private + */ + _editPanelWidth: undefined, + + /** + Buttons width. + + @property _buttonsWidth + @type Number + @private + */ + _buttonsWidth: computed('buttons.@each.width', function() { + return this.get('buttons') + .map(btn => btn.width) + .reduce((prev, curr) => prev + curr); + }), + + /** + Close button width. + + @property _closeButtonWidth + @type Number + @private + */ + _closeButtonWidth: undefined, + + /** + Margin button width. + + @property _closeButtonWidth + @type Number + @private + */ + _marginWidth: 20, + + /** + Menu dropdown width. + + @property _buttonDropdownWidth + @type Number + @private + */ + _buttonDropdownWidth: computed('_menuButtons.length', function() { + return (this.get('_menuButtons.length') > 0 && + $(this.element).find('.button-dropdown.menu-buttons').length > 0) ? + $(this.element).find('.button-dropdown.menu-buttons').outerWidth(true) + : 225; + }), + + /** + Menu buttons. + + @property _menuButtons + @type Array + @private + */ + _menuButtons: undefined, + + /** + Panel buttons. + + @property _panelButtons + @type Array + @private + */ + _panelButtons: undefined, + + /** + Buttons. + + @property _panelButtons + @type Array + */ + buttons: undefined, + + /** + Sorting buttons type. + + @property _buttonsSorting + @type Object + @private + */ + _buttonsSorting: undefined, + + /** + Sorting panel buttons type. + + @property panelButtonsSorted + @type Object + */ + panelButtonsSorted: sort('_panelButtons', '_buttonsSorting'), + + /** + Sorting menu buttons type. + + @property menuButtonsSorted + @type Object + */ + menuButtonsSorted: sort('_menuButtons', '_buttonsSorting'), + + /** + Show close button in panel. + + @property showCloseButton + @type boolean + */ + showCloseButton: false, + + /** + Flag, the component is embedded in another component, for example, in the flexberry-olv toolbar. + Set to send action in the controller. + + @type {Boolean} + */ + deepMount: false, + + /** + Update display buttons. + + @method _updateDisplayButtons + @private + */ + _updateDisplayButtons() { + let btnInPanel = A(); + let btnInMenu = A(); + + if (this.get('_buttonsWidth') + this.get('_closeButtonWidth') + this.get('_marginWidth') <= this.get('_editPanelWidth')) { + btnInPanel = this.get('buttons'); + } else { + let maxWidthForButtonsPanel = this.get('_editPanelWidth') - + (this.get('_buttonDropdownWidth') + + this.get('_closeButtonWidth') + + this.get('_marginWidth')); + let currentButtonsWidth = 0; + let isButtonsPanelFull = false; + + this.get('buttons').forEach(btn => { + if (currentButtonsWidth + btn.width <= maxWidthForButtonsPanel && !isButtonsPanelFull) { + btnInPanel.pushObject(btn); + currentButtonsWidth += btn.width; + } else { + isButtonsPanelFull = true; + btnInMenu.pushObject(btn); + } + }); + } + + this.set('_panelButtons', btnInPanel); + this.set('_menuButtons', btnInMenu); + }, + + /** + Initializes component. + */ + init() { + this._super(...arguments); + + this.set('_buttonsSorting', ['id:asc']); + this.get('buttons').forEach((btn, i) => btn.id = `edit_btn${i}`); + this.set('_panelButtons', this.get('buttons')); + this.set('_menuButtons', A()); + + }, + + /** + Initializes DOM-related component's logic. + */ + didInsertElement() { + this._super(...arguments); + + const $editPanel = $(this.element); + this.set('_editPanelWidth', $editPanel.outerWidth()); + + let closeButtonWidth = this.get('showCloseButton') ? + $editPanel.find('.ui.button.close-button').outerWidth(true) + : 0; + this.set('_closeButtonWidth', closeButtonWidth); + + // get and save button width + this.get('_panelButtons').forEach(btn => { + let button = $editPanel.find(`#${btn.id}`); + btn.width = button.outerWidth(true); + }); + + this._updateDisplayButtons(); + + $(window).bind('resize', $.proxy(function() { + const elementWidth = $(this.element).outerWidth(); + if (this.get('_editPanelWidth') !== elementWidth) { + this.set('_editPanelWidth', elementWidth); + this._updateDisplayButtons(); + } + }, this)); + }, + + /** + Handles DOM-related component's properties after each render. + */ + didRender() { + this.$('.ui.dropdown.selection.group-toolbar').dropdown(); + }, + + /** + Cleans up DOM-related component's logic. + */ + willDestroyElement() { + this._super(...arguments); + + $(window).unbind('resize'); + }, + + actions: { + /** + * Call action of a clicked button. + * + * @method actions.sendButtonAction + * @public + * @param {String|Object} action action. + */ + sendButtonAction(action) { + assert('{{edit-panel}}: button.action parameter missing', !isNone(action)); + + let actionName = ''; + let actionParams = []; + + if (typeof action === 'string') { + actionName = action; + } else if (!isNone(action.params)) { + actionName = action.name; + actionParams = action.params; + } + + if (this.get('deepMount')) { + this.currentController.send(actionName, ...actionParams); + } else { + /* eslint-disable ember/closure-actions */ + this.sendAction(actionName, ...actionParams); + /* eslint-enable ember/closure-actions */ + } + } + } +}); diff --git a/addon/components/flexberry-button-dropdown.js b/addon/components/flexberry-button-dropdown.js new file mode 100644 index 0000000000..747a5df8a2 --- /dev/null +++ b/addon/components/flexberry-button-dropdown.js @@ -0,0 +1,92 @@ +/** + @module ember-flexberry + */ + +import FlexberryBaseComponent from 'ember-flexberry/components/flexberry-base-component'; +import { assert } from '@ember/debug'; +import { isNone } from '@ember/utils'; + +export default FlexberryBaseComponent.extend({ + + classNames: ['button-dropdown'], + + title: '', + + elementId: undefined, + + /** + * menu buttons. + * @example + * ` + * buttons: [ + * { + * action: actionName, + * text: buttonText, + * disabled: buttonDisabled + * class: '.button-class' + * }, { + * action: { + * name: 'actionName', + * params: ['paramValue1', 'paramValue2'] + * }, + * text: buttonText, + * disabled: buttonDisabled + * class: '.button-class' + * }, { + * text: buttonText, + * disabled: buttonDisabled + * buttons: [{ + * action: actionName, + * text: buttonText, + * disabled: buttonDisabled + * class: '.button-class' + * }, { + * action: actionName, + * text: buttonText, + * disabled: buttonDisabled + * class: '.button-class' + * }] + * }, + * ] + * ` + */ + buttons: undefined, + + /** + * Flag, the component is embedded in another component, for example, in the flexberry-olv toolbar. + * Set to send action in the controller. + * @type {Boolean} + */ + deepMount: false, + + actions: { + /** + * Call action of a clicked button. + * + * @method actions.sendButtonAction + * @public + * @param {String|Object} action action. + */ + sendButtonAction(action) { + assert('{{button-dropdown}}: button.action parameter missing', !isNone(action)); + + let actionName = ''; + let actionParams = []; + + if (typeof action === 'string') { + actionName = action; + } else if (!isNone(action.params)) { + actionName = action.name; + actionParams = action.params; + } + + if (this.get('deepMount')) { + this.currentController.send(actionName, ...actionParams); + } else { + /* eslint-disable ember/closure-actions */ + this.sendAction(actionName, ...actionParams); + /* eslint-enable ember/closure-actions */ + } + } + } +}); diff --git a/addon/locales/en/translations.js b/addon/locales/en/translations.js index 98beaab9c4..c4b094fe59 100644 --- a/addon/locales/en/translations.js +++ b/addon/locales/en/translations.js @@ -8,7 +8,8 @@ export default { 'save-button-text': 'Save', 'saveAndClose-button-text': 'Save and close', 'delete-button-text': 'Delete', - 'close-button-text': 'Close' + 'close-button-text': 'Close', + 'more-button-text': 'More' }, 'error-form': { diff --git a/addon/locales/ru/translations.js b/addon/locales/ru/translations.js index ce1e81b163..846cacc412 100644 --- a/addon/locales/ru/translations.js +++ b/addon/locales/ru/translations.js @@ -8,7 +8,8 @@ export default { 'save-button-text': 'Сохранить', 'saveAndClose-button-text': 'Сохранить и закрыть', 'delete-button-text': 'Удалить', - 'close-button-text': 'Закрыть' + 'close-button-text': 'Закрыть', + 'more-button-text': 'Еще' }, 'error-form': { diff --git a/app/components/button-dropdown-menu.js b/app/components/button-dropdown-menu.js new file mode 100644 index 0000000000..00e3d644bf --- /dev/null +++ b/app/components/button-dropdown-menu.js @@ -0,0 +1 @@ +export { default } from 'ember-flexberry/components/button-dropdown-menu'; diff --git a/app/components/edit-panel.js b/app/components/edit-panel.js new file mode 100644 index 0000000000..330b7e542a --- /dev/null +++ b/app/components/edit-panel.js @@ -0,0 +1 @@ +export { default } from 'ember-flexberry/components/edit-panel'; diff --git a/app/components/flexberry-button-dropdown.js b/app/components/flexberry-button-dropdown.js new file mode 100644 index 0000000000..c15f8a98d1 --- /dev/null +++ b/app/components/flexberry-button-dropdown.js @@ -0,0 +1 @@ +export { default } from 'ember-flexberry/components/flexberry-button-dropdown'; diff --git a/app/templates/components/button-dropdown-menu.hbs b/app/templates/components/button-dropdown-menu.hbs new file mode 100644 index 0000000000..565d8f371f --- /dev/null +++ b/app/templates/components/button-dropdown-menu.hbs @@ -0,0 +1,20 @@ +{{#each buttons as |button|}} + {{#if (not button.disabled)}} +
+ {{/if}} +{{/each}} \ No newline at end of file diff --git a/app/templates/components/edit-panel.hbs b/app/templates/components/edit-panel.hbs new file mode 100644 index 0000000000..c593f19598 --- /dev/null +++ b/app/templates/components/edit-panel.hbs @@ -0,0 +1,33 @@ +{{#unless readonly}} + {{#if panelButtonsSorted}} + {{#each panelButtonsSorted as |button|}} + {{#if (not button.disabled)}} + {{#if button.buttons}} + {{flexberry-button-dropdown + title=button.text + elementId=button.id + deepMount=deepMount + buttons=button.buttons + }} + {{else}} + + {{/if}} + {{/if}} + {{/each}} + {{/if}} + + {{#if menuButtonsSorted}} + {{flexberry-button-dropdown + title=(t "forms.edit-form.more-button-text") + deepMount=deepMount + buttons=menuButtonsSorted + classNames="menu-buttons" + }} + {{/if}} +{{/unless}} + +{{#if showCloseButton}} + +{{/if}} \ No newline at end of file diff --git a/app/templates/components/flexberry-button-dropdown.hbs b/app/templates/components/flexberry-button-dropdown.hbs new file mode 100644 index 0000000000..b286ef4250 --- /dev/null +++ b/app/templates/components/flexberry-button-dropdown.hbs @@ -0,0 +1,8 @@ + diff --git a/blueprints/flexberry-edit-form/files/app/templates/__name__.hbs b/blueprints/flexberry-edit-form/files/app/templates/__name__.hbs index ec69a32547..63dee64da3 100644 --- a/blueprints/flexberry-edit-form/files/app/templates/__name__.hbs +++ b/blueprints/flexberry-edit-form/files/app/templates/__name__.hbs @@ -3,21 +3,26 @@