import $ from 'jquery';
import Mixin from '@ember/object/mixin';
import { inject as service } from '@ember/service';
import { inject as controller } from '@ember/controller';
import { assert } from '@ember/debug';
import { typeOf, isNone } from '@ember/utils';
import { get, set } from '@ember/object';
import { isArray, A } from '@ember/array';
import { capitalize } from '@ember/string';
import { htmlSafe } from '@ember/template';
import { getValueFromLocales } from 'ember-flexberry-data/utils/model-functions';
import getAttrLocaleKey from '../utils/get-attr-locale-key';
export default Mixin.create({
_userSettingsService: service('user-settings'),
/**
Service that triggers {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}} events.
@property _groupEditEventsService
@type Service
@private
*/
_groupEditEventsService: service('objectlistview-events'),
/**
Controller to show advlimit config modal window.
@property advLimitController
@type <a href="http://emberjs.com/api/classes/Ember.InjectedProperty.html">Ember.InjectedProperty</a>
@default Ember.inject.controller('advlimit-dialog')
*/
advLimitController: controller('advlimit-dialog'),
/**
Controller to show filters modal window.
@property filtersDialogController
@type <a href="http://emberjs.com/api/classes/Ember.InjectedProperty.html">Ember.InjectedProperty</a>
@default Ember.inject.controller('filters-dialog')
*/
filtersDialogController: controller('filters-dialog'),
/**
Service for managing advLimits for lists.
@property advLimit
@type advLimit
*/
advLimit: service(),
/**
Default cell component that will be used to display values in columns cells.
@property {Object} cellComponent
@property {String} [cellComponent.componentName=undefined]
@property {String} [cellComponent.componentProperties=null]
*/
cellComponent: {
componentName: undefined,
componentProperties: null,
},
/**
Columns widtghs for current component.
@property {Object} currentColumnsWidths
*/
currentColumnsWidths: undefined,
actions: {
/**
Show columns config dialog.
@method actions.showConfigDialog
@param componentName Component name.
@param settingName Setting name.
@param useSidePageMode Indicates when use side page mode.
@param isExportExcel Indicates if it's export excel dialog.
@param immediateExport Indicate if auto export is needed.
*/
showConfigDialog(componentName, settingName, useSidePageMode=false, isExportExcel = false, immediateExport = false) {
this._showConfigDialog(componentName, settingName, useSidePageMode, this, isExportExcel, immediateExport);
},
/**
Show columns config dialog for groupedit.
@method actions.showSortGeDialog
@param componentName Component name.
@param useSidePageMode Indicates when use side page mode.
@param modelProjection Model projection.
@param geSorting Current sorting.
*/
showSortGeDialog(componentName, useSidePageMode=true, modelProjection, geSorting) {
this._showSortGeDialog(componentName, useSidePageMode, modelProjection, geSorting);
},
/**
Show columns config dialog.
@method actions.getGeneratedColumns
@param componentName Component name.
@param settingName Setting name.
@param modelProjection Model projection.
@param geSorting Current sorting.
*/
getGeneratedColumns(componentName, settingName, modelProjection, geSorting) {
let projectionAttributes = modelProjection.attributes;
let fixedColumns = this.get(`defaultDeveloperUserSettings.${componentName}.DEFAULT.columnWidths`) || A();
fixedColumns = fixedColumns.filter(({ fixed }) => fixed).map(obj => { return obj.propName; });
let colsOrder = this.get('_userSettingsService').getCurrentColsOrder(componentName, settingName);
let sorting = geSorting;
let columns = this._getGeneratedColumns(projectionAttributes, this, fixedColumns, colsOrder, sorting);
this.set('colDescs', columns);
this.get('_groupEditEventsService').setDefaultGeSortTrigger(this.get('colDescs'));
return columns;
},
/**
Show filters dialog.
@method actions.showFiltersDialog
@param componentName Component name.
@param filterColumns columns with available filters.
*/
showFiltersDialog(componentName, filterColumns, useSidePageMode) {
let controller = this.get('filtersDialogController');
controller.set('mainControler', this);
let loadingParams = {
view: 'application',
outlet: 'modal'
};
this.send('showModalDialog', 'filters-dialog');
loadingParams = {
view: 'filters-dialog',
outlet: 'modal-content'
};
this.send('showModalDialog', 'filters-dialog-content',
{ controller: controller, model: { filterColumns: filterColumns, componentName: componentName, useSidePageMode: useSidePageMode } }, loadingParams);
},
/**
Show adv limit config dialog.
@method actions.showAdvLimitDialog
@param componentName Component name.
@param advLimitName Adv limit name.
*/
showAdvLimitDialog(componentName, advLimitName) {
let advLimit = this.get('advLimit').getCurrentAdvLimit(componentName, advLimitName);
let store = this.get('store');
let controller = this.get('advLimitController');
controller.set('mainControler', this);
let loadingParams = {
view: 'application',
outlet: 'modal'
};
this.send('showModalDialog', 'advlimit-dialog');
loadingParams = {
view: 'advlimit-dialog',
outlet: 'modal-content'
};
this.send('showModalDialog', 'advlimit-dialog-content',
{ controller: controller, model: { advLimit: advLimit, advLimitName: advLimitName, componentName: componentName, store: store } }, loadingParams);
}
},
/**
Show columns config dialog.
@method _showConfigDialog
@param componentName
@param settingName
@param settingsSource
@param isExportExcel
@param immediateExport
@private
*/
_showConfigDialog(componentName, settingName, useSidePageMode, settingsSource, isExportExcel = false, immediateExport = false) {
let colsOrder = this.get('_userSettingsService').getCurrentColsOrder(componentName, settingName);
let sorting = this.get('_userSettingsService').getCurrentSorting(componentName, settingName);
let columnWidths = this.get('_userSettingsService').getCurrentColumnWidths(componentName, settingName);
let perPageValue = this.get('_userSettingsService').getCurrentPerPage(componentName, settingName);
let fixedColumns = this.get(`defaultDeveloperUserSettings.${componentName}.DEFAULT.columnWidths`) || A();
fixedColumns = fixedColumns.filter(({ fixed }) => fixed).map(obj => { return obj.propName; });
let saveColWidthState = false;
let propName;
let colDesc; //Column description
let colDescs = A(); //Columns description
let projectionAttributes;
let modelName = settingsSource.get('modelProjection.modelName');
if (isExportExcel) {
let exportExcelProjectionName = settingsSource.get('exportExcelProjection') || settingsSource.get('modelProjection.projectionName');
assert('Property exportExcelProjection is not defined in controller.', exportExcelProjectionName);
let exportExcelProjection = this.store.modelFor(modelName).projections.get(exportExcelProjectionName);
assert(`Projection "${exportExcelProjectionName}" is not defined in model "${modelName}".`, exportExcelProjection);
projectionAttributes = exportExcelProjection.attributes;
} else {
let modelProjection = settingsSource.get('modelProjection');
projectionAttributes = modelProjection.attributes;
}
let colList = this._generateColumns(projectionAttributes, isExportExcel, null, null, settingsSource);
let namedColList = {};
for (let i = 0; i < colList.length; i++) {
colDesc = colList[i];
propName = colDesc.propName;
colDesc.fixed = fixedColumns.indexOf(propName) > -1;
namedColList[propName] = colDesc;
}
if (isArray(colsOrder)) {
/*
Remove propName, that are not in colList
*/
let reliableColsOrder = A();
for (let i = 0; i < colsOrder.length; i++) {
let colOrder = colsOrder[i];
propName = colOrder.propName;
if ((propName in namedColList) && ('header' in namedColList[propName])) {
reliableColsOrder.pushObject(colOrder);
if (isExportExcel && colOrder.name) {
set(namedColList[propName], 'header.string', colOrder.name);
}
}
}
colsOrder = reliableColsOrder;
} else {
colsOrder = colList;
}
let namedSorting = {};
let sortPriority = 0;
if (isNone(sorting)) {
sorting = A();
}
for (let i = 0; i < sorting.length; i++) {
colDesc = sorting[i];
propName = colDesc.propName;
if (propName in namedColList) {
colDesc.sortPriority = ++sortPriority;
namedSorting[propName] = colDesc;
}
}
if (isNone(columnWidths)) {
columnWidths = A();
}
let namedColWidth = {};
if (isNone(settingName)) {
namedColWidth = settingsSource.get('currentColumnsWidths') || {};
} else {
for (let i = 0; i < columnWidths.length; i++) {
colDesc = columnWidths[i];
propName = colDesc.propName;
namedColWidth[propName] = colDesc.width;
}
}
if (columnWidths.length > 0) {
saveColWidthState = true;
}
for (let i = 0; i < colsOrder.length; i++) {
let colOrder = colsOrder[i];
propName = colOrder.propName;
if (!(propName in namedColList) || !('header' in namedColList[propName])) {
delete namedColList[propName];
continue;
}
let name = namedColList[propName].header;
let isHasMany = namedColList[propName].isHasMany;
let fixed = namedColList[propName].fixed;
delete namedColList[propName];
colDesc = { name: name, propName: propName, hide: colOrder.hide, isHasMany: isHasMany, fixed: fixed };
if (propName in namedSorting) {
let sortColumn = namedSorting[propName];
colDesc.sortOrder = sortColumn.direction === 'asc' ? 1 : -1;
colDesc.sortPriority = sortColumn.sortPriority;
} else {
colDesc.sortOrder = 0;
}
if (propName in namedColWidth) {
colDesc.columnWidth = namedColWidth[propName];
}
colDescs.pushObject(colDesc);
}
for (propName in namedColList) {
colDescs.pushObject({ propName: propName, name: namedColList[propName].header, hide: false, sortOrder: 0,
isHasMany: namedColList[propName].isHasMany, fixed: namedColList[propName].fixed });
}
let exportParams = { isExportExcel: isExportExcel };
let settName = settingName;
if (isExportExcel) {
let exportExcelProjectionName = settingsSource.get('exportExcelProjection') || settingsSource.get('modelProjection.projectionName');
exportParams.immediateExport = immediateExport;
exportParams.projectionName = exportExcelProjectionName;
exportParams.detSeparateCols = this.get('_userSettingsService').getDetSeparateCols(componentName, settingName);
exportParams.detSeparateRows = this.get('_userSettingsService').getDetSeparateRows(componentName, settingName);
if (settName) {
settName = settName.split('/');
settName.shift();
settName = settName.join('/');
}
}
let store = this.get('store');
let controller = this.get('colsconfigController');
controller.set('mainControler', this);
let loadingParams = {
view: 'application',
outlet: 'modal'
};
this.send('showModalDialog', 'colsconfig-dialog');
loadingParams = {
view: 'colsconfig-dialog',
outlet: 'modal-content'
};
this.send('showModalDialog', 'colsconfig-dialog-content',
{ controller: controller, model: { modelName: modelName, colDescs: colDescs, componentName: componentName,
settingName: settName, perPageValue: perPageValue, saveColWidthState: saveColWidthState,
exportParams: exportParams, store: store, useSidePageMode: useSidePageMode } }, loadingParams);
},
/**
Get columns info.
@method _getGeneratedColumns
@param projectionAttributes
@param settingsSource
@param fixedColumns
@param colsOrder
@param sorting
@private
*/
_getGeneratedColumns(projectionAttributes, settingsSource, fixedColumns, colsOrder, sorting) {
let colDesc; //Column description
let colDescs = A(); //Columns description
let propName;
let colList = this._generateColumns(projectionAttributes, false, null, null, settingsSource);
let namedColList = {};
for (let i = 0; i < colList.length; i++) {
colDesc = colList[i];
propName = colDesc.propName;
colDesc.fixed = fixedColumns.indexOf(propName) > -1;
namedColList[propName] = colDesc;
}
if (isArray(colsOrder)) {
/*
Remove propName, that are not in colList
*/
let reliableColsOrder = A();
for (let i = 0; i < colsOrder.length; i++) {
let colOrder = colsOrder[i];
propName = colOrder.propName;
if ((propName in namedColList) && ('header' in namedColList[propName])) {
reliableColsOrder.pushObject(colOrder);
}
}
colsOrder = reliableColsOrder;
} else {
colsOrder = colList;
}
let namedSorting = {};
let sortPriority = 0;
if (isNone(sorting)) {
sorting = A();
}
for (let i = 0; i < sorting.length; i++) {
colDesc = sorting[i];
propName = colDesc.propName;
if (propName in namedColList) {
colDesc.sortPriority = ++sortPriority;
namedSorting[propName] = colDesc;
}
}
for (let i = 0; i < colsOrder.length; i++) {
let colOrder = colsOrder[i];
propName = colOrder.propName;
if (!(propName in namedColList) || !('header' in namedColList[propName])) {
delete namedColList[propName];
continue;
}
let name = namedColList[propName].header;
let isHasMany = namedColList[propName].isHasMany;
let fixed = namedColList[propName].fixed;
delete namedColList[propName];
colDesc = { name: name, propName: propName, isHasMany: isHasMany, fixed: fixed };
if (propName in namedSorting) {
let sortColumn = namedSorting[propName];
colDesc.sortOrder = sortColumn.direction === 'asc' ? 1 : -1;
colDesc.sortPriority = sortColumn.sortPriority;
} else {
colDesc.sortOrder = 0;
}
colDescs.pushObject(colDesc);
}
for (propName in namedColList) {
colDescs.pushObject({ propName: propName, name: namedColList[propName].header, sortOrder: 0,
isHasMany: namedColList[propName].isHasMany, fixed: namedColList[propName].fixed });
}
return colDescs;
},
/**
Show columns config dialog for groupedit.
@method _showSortGeDialog
@param componentName
@param useSidePageMode
@param modelProjection
@param geSorting
@private
*/
_showSortGeDialog(componentName, useSidePageMode, modelProjection, geSorting) {
let colsOrder = this.get('_userSettingsService').getCurrentColsOrder(componentName);
let sorting = geSorting;
let fixedColumns = this.get(`defaultDeveloperUserSettings.${componentName}.DEFAULT.columnWidths`) || A();
fixedColumns = fixedColumns.filter(({ fixed }) => fixed).map(obj => { return obj.propName; });
let modelName = modelProjection.modelName;
let projectionAttributes = modelProjection.attributes;
let colDescs = this._getGeneratedColumns(projectionAttributes,
this, fixedColumns, colsOrder, sorting);
let store = this.get('store');
let controller = this.get('colsconfigController');
controller.set('mainControler', this);
this.send('showModalDialog', 'colsconfig-dialog');
let loadingParams = {
view: 'colsconfig-dialog',
outlet: 'modal-content'
};
this.send('showModalDialog', 'ge-sorting-dialog-content',
{ controller: controller, model: { modelName: modelName, colDescs: colDescs, componentName: componentName,
store: store, useSidePageMode: useSidePageMode, geSorting: geSorting } }, loadingParams);
},
/**
Generate the columns.
@method _generateColumns
@private
*/
_generateColumns(attributes, isExportExcel, columnsBuf, relationshipPath, settingsSource) {
columnsBuf = columnsBuf || A();
relationshipPath = relationshipPath || '';
for (let attrName in attributes) {
let currentRelationshipPath = relationshipPath;
if (!attributes.hasOwnProperty(attrName)) {
continue;
}
let attr = attributes[attrName];
assert(`Unknown kind of projection attribute: ${attr.kind}`, attr.kind === 'attr' || attr.kind === 'belongsTo' || attr.kind === 'hasMany');
switch (attr.kind) {
case 'hasMany': {
if (isExportExcel && !attr.options.hidden) {
let bindingPath = currentRelationshipPath + attrName;
let column = this._createColumn(attr, attrName, bindingPath, settingsSource, true);
columnsBuf.pushObject(column);
}
break;
}
case 'belongsTo': {
if (!attr.options.hidden) {
let bindingPath = currentRelationshipPath + attrName;
let column = this._createColumn(attr, attrName, bindingPath, settingsSource);
if (isNone(get(column, 'cellComponent.componentName'))) {
if (attr.options.displayMemberPath) {
column.propName += '.' + attr.options.displayMemberPath;
} else {
column.propName += '.id';
}
}
columnsBuf.pushObject(column);
}
currentRelationshipPath += attrName + '.';
this._generateColumns(attr.attributes, isExportExcel, columnsBuf, currentRelationshipPath, settingsSource);
break;
}
case 'attr': {
if (attr.options.hidden) {
break;
}
let bindingPath = currentRelationshipPath + attrName;
let column = this._createColumn(attr, attrName, bindingPath, settingsSource);
columnsBuf.pushObject(column);
break;
}
}
}
return columnsBuf.sortBy('index');
},
/**
Create the key from locales.
*/
_createKey(bindingPath, settingsSource) {
let projection = settingsSource.get('modelProjection');
let modelName = projection.modelName;
let key;
let mainModelProjection = this.get('mainModelProjection');
if (mainModelProjection) {
let modelClass = this.get('store').modelFor(modelName);
let nameRelationship;
let mainModelName;
modelClass.eachRelationship(function(name, descriptor) {
if (descriptor.kind === 'belongsTo' && descriptor.options.inverse) {
nameRelationship = descriptor.options.inverse;
mainModelName = descriptor.type;
}
});
key = getAttrLocaleKey(mainModelName, mainModelProjection.projectionName, bindingPath, nameRelationship);
} else {
key = getAttrLocaleKey(modelName, projection.projectionName, bindingPath);
}
return key;
},
/**
Create the column.
@method _createColumn
@private
*/
_createColumn(attr, attrName, bindingPath, settingsSource, isHasMany = false) {
let currentController = this.get('currentController');
let getCellComponent = get(currentController || {}, 'getCellComponent');
let cellComponent = settingsSource.get('cellComponent');
if (!this.get('editOnSeparateRoute') && typeOf(getCellComponent) === 'function') {
let recordModel = isNone(this.get('content')) ? null : this.get('content.type');
cellComponent = getCellComponent.call(currentController, attr, bindingPath, recordModel);
}
let key = this._createKey(bindingPath, settingsSource);
let valueFromLocales = getValueFromLocales(this.get('i18n'), key);
let index = get(attr, 'options.index');
let column = {
header: valueFromLocales || htmlSafe(attr.caption || capitalize(attrName)),
propName: bindingPath,
cellComponent: cellComponent,
isHasMany: isHasMany,
index: index,
};
if (valueFromLocales) {
column.keyLocale = key;
}
let customColumnAttributesFunc = settingsSource.get('customColumnAttributes');
if (customColumnAttributesFunc) {
let customColAttr = customColumnAttributesFunc(attr, bindingPath);
if (customColAttr && (typeof customColAttr === 'object')) {
$.extend(true, column, customColAttr);
}
}
let sortDef;
let sorting = settingsSource.get('sorting');
if (sorting && (sortDef = sorting[bindingPath])) {
column.sorted = true;
column.sortAscending = sortDef.sortAscending;
column.sortNumber = sortDef.sortNumber;
}
return column;
}
});