UNPKG

comindware.core.ui

Version:

Comindware Core UI provides the basic components like editors, lists, dropdowns, popups that we so desperately need while creating Marionette-based single-page applications.

319 lines (284 loc) • 12.1 kB
import LocalizationService from '../../../../../services/LocalizationService'; import helpers from '../../../../../utils/helpers'; import ItemCollection from '../collection/ItemsCollection'; import FilterState from '../classes/FilterState'; import AvailableGridView from '../views/AvailableGridView'; import SelectedGridView from '../views/SelectedGridView'; import { virtualCollectionFilterActions } from 'Meta'; const toolbarActions = { MOVE_ALL: 'Move-all' }; const debounceInterval = { short: 100, medium: 300 }; const convertToArray = (value : null | string | string[]) => Array.isArray(value) ? value : value ? [value] : []; export default Marionette.MnObject.extend({ initialize(options) { this.options = options; this.readonly = this.options.readonly; this.filterFnParameters = options.filterFnParameters; this.filterFn = {}; Object.values(this.filterFnParameters).forEach(parameter => this.filterFn[parameter] = model => this.filterFnParameters[model.get('type')] !== parameter); this.members = {}; this.isMemberService = options.memberService && options.memberService.getMembers; const showUsers = !this.options.hideUsers; const showGroups = !this.options.hideGroups; this.filterState = new FilterState({ showUsers, showGroups, filterFnParameters: this.filterFnParameters }); this.__createModel(); this.model.set({ title: this.__getFullMemberSplitTitle(), items: this.members, showUsers, showGroups, itemsToSelectText: this.options.itemsToSelectText, selectedItemsText: this.options.selectedItemsText, confirmEdit: true, emptyListText: this.options.emptyListText }); }, __getDisplayText() { const membersCount = { users: 0, groups: 0 }; const members = this.members; const selected = convertToArray(this.options.selected); selected.forEach(id => membersCount[members[id]?.type]++); if (typeof this.options.getDisplayText === 'function') { return this.options.getDisplayText(selected); } const usersResultText = (this.options.hideUsers) ? '' : helpers.getPluralForm(membersCount.users, LocalizationService.get('CORE.FORM.EDITORS.MEMBERSPLIT.USERS')).replace('{0}', membersCount.users).concat(' '); const groupsResultText = (this.options.hideGroups) ? '' : helpers.getPluralForm(membersCount.groups, LocalizationService.get('CORE.FORM.EDITORS.MEMBERSPLIT.GROUPS')).replace('{0}', membersCount.groups); return `${usersResultText}${groupsResultText}`; }, async updateItems(filterState, selectedItems = this.options.selected) { this.options.selected = selectedItems; if (this.isMemberService) { await this.__updateMemberItems(filterState, selectedItems); } else { await this.__updateGeneralItems(); } this.trigger('update:text', this.__getDisplayText()); }, async __updateMemberItems(filterState = this.filterState, selectedItems = this.options.selected) { this.members = {}; this.__setLoading(true, { both: true }); try { const data = await this.options.memberService.getMembers(this.__getSettings(filterState, selectedItems)); data.available.forEach(item => (this.members[item.id] = item)); data.selected.forEach(item => (this.members[item.id] = item)); this.processValues(selectedItems); this.model.get('available').totalCount = data.totalCount; } catch (e) { console.log(e); } finally { this.__setLoading(false); } }, async __updateGeneralItems() { this.members = {}; this.__setLoading(true, { both: false }); try { const users = await this.options.users; const groups = await this.options.groups; users.forEach(model => (this.members[model.id] = model)); groups.forEach(model => (this.members[model.id] = model)); this.processValues(); } catch (e) { console.log(e); } finally { this.__setLoading(false); } }, __getSettings(filterState, selectedItems) { const selectedModels = convertToArray(selectedItems); const settings = { filterText: filterState?.searchString, filterType: filterState?.filterType, selected: selectedModels }; return settings; }, __getFullMemberSplitTitle() { switch (this.options.title) { case 'Members': return LocalizationService.get('CORE.FORM.EDITORS.MEMBERSPLIT.MEMBERSTITLE'); case 'Performers': return LocalizationService.get('CORE.FORM.EDITORS.MEMBERSPLIT.PERFORMERSTITLE'); case undefined: return LocalizationService.get('CORE.FORM.EDITORS.MEMBERSPLIT.TITLE'); default: return this.options.title; } }, createView() { const gridViewOptions = { model: this.model, config: this.options.config, hideToolbar: this.options.hideToolbar, filterFnParameters: this.filterFnParameters }; const availableText = this.options.itemsToSelectText; const availableGridView = this.isMemberService ? new AvailableGridView( Object.assign({}, gridViewOptions, { memberService: this.options.memberService, filterState: this.filterState, title: availableText, textFilterDelay: this.options.textFilterDelay }) ) : new SelectedGridView(Object.assign({}, gridViewOptions, { membersCollection: this.model.get('available'), title: availableText })); const selectedGridView = new SelectedGridView( Object.assign({}, gridViewOptions, { title: this.options.selectedItemsText }) ); let columns = [availableGridView, selectedGridView]; if (this.readonly) { columns = [selectedGridView]; } this.view = new Core.layout.HorizontalLayout({ class: 'member-split-wrp', columns }); this.bondedCollections = {}; this.bondedCollections[availableGridView.cid] = availableGridView.collection; this.bondedCollections[selectedGridView.cid] = selectedGridView.collection; columns.forEach(view => { this.listenTo(view.gridView, 'execute', act => this.__executeAction(view, act)); this.listenTo(view.gridView, 'click', model => this.__moveItems(view, model)); }); if (this.isMemberService) { this.listenTo(availableGridView, 'members:update', async filterState => { availableGridView.gridView.toggleSearchActivity(false); await this.__updateMemberItems(filterState); availableGridView.gridView.toggleSearchActivity(true); }); } this.view.once('attach', () => availableGridView.gridView.searchView.focus()); }, __executeAction(gridView, act) { switch (act.get('id')) { case this.filterFnParameters.users: case this.filterFnParameters.groups: if (gridView.options.memberService) { this.__updateFilterState(gridView, act); break; } this.__applyFilter(gridView, act); break; case toolbarActions.MOVE_ALL: this.__moveItems(gridView); break; default: break; } }, __updateFilterState(gridView, act) { const filterState = gridView.filterState; if (act.get('isChecked')) { filterState.add(act.get('id')); } else { filterState.remove(act.get('id')); } if (filterState.filterType) { gridView.collection.filter(); this.__updateMemberItems(filterState); } else { gridView.collection.filter(() => false); } }, __applyFilter(gridView, act) { const collection = gridView.collection; const actionId = act.get('id'); const isChecked = act.get('isChecked'); if (!isChecked) { collection.filter(this.filterFn[actionId], { action: virtualCollectionFilterActions.PUSH }); } else { collection.filter(this.filterFn[actionId], { action: virtualCollectionFilterActions.REMOVE }); } }, __updateMembers() { const allSelectedModels = Object.assign({}, this.model.get('selected').parentCollection); this.options.selected = allSelectedModels.models.map(model => model.id); this.trigger('popup:ok'); }, saveMembers() { this.__updateMembers(); this.trigger('update:text', this.__getDisplayText()); }, cancelMembers() { this.trigger('popup:cancel'); }, __createModel() { this.model = new Backbone.Model(); const availableModels = new ItemCollection(new Backbone.Collection([]), { isSliding: true, selectableBehavior: 'single', comparator: Core.utils.helpers.comparatorFor(Core.utils.comparators.stringComparator2Asc, 'name') }); if (this.groupConfig) { availableModels.group(this.groupConfig); } availableModels.totalCount = 0; this.model.set('available', availableModels); const selectedComparator = this.options.orderEnabled ? Core.utils.helpers.comparatorFor(Core.utils.comparators.numberComparator2Asc, 'order') : Core.utils.helpers.comparatorFor(Core.utils.comparators.stringComparator2Asc, 'name'); const selectedModels = new ItemCollection(new Backbone.Collection([]), { isSliding: true, selectableBehavior: 'single', comparator: selectedComparator }); this.model.set('selected', selectedModels); this.model.set('allowRemove', this.options.allowRemove); }, processValues(selected = this.options.selected) { const items = Object.assign({}, this.members); this.options.exclude.forEach(id => { if (items[id]) { delete items[id]; } }); const selectedItems = convertToArray(selected).map(id => { const model = items[id]; delete items[id]; return model; }); const availableItems = Object.values(items); this.model.get('available').reset(availableItems); this.model.get('selected').reset(selectedItems); }, __moveItems(gridView, model) { if (this.readonly) { return; } const source = this.bondedCollections[gridView.cid]; const targetKey = Object.keys(this.bondedCollections).find(key => key !== gridView.cid); const target = this.bondedCollections[targetKey]; const movingModels = model || Object.assign([], source.models); target.parentCollection.add(movingModels); source.parentCollection.remove(movingModels); this.__updateMembers(); target.rebuild(); source.rebuild(); if (!model) { source.trigger('filter'); } this.updateItems(); }, __setLoading(state, { both } = { both: true }) { if (this.view && !this.view.isDestroyed()) { if (both) { this.view.columns.forEach(view => { view.setLoading(state); }); } else { this.view.columns[0].setLoading(state); } } } });