UNPKG

devexpress-reporting

Version:

DevExpress Reporting provides the capability to develop a reporting application to create and customize reports.

392 lines (391 loc) 18.7 kB
/** * DevExpress HTML/JS Reporting (designer\dataObjects\parameters\parameter.js) * Version: 25.1.3 * Build date: Jun 26, 2025 * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * License: https://www.devexpress.com/Support/EULAs/universal.xml */ import { DotnetTypes, extend, formatUnicorn, getLocalization } from '@devexpress/analytics-core/analytics-internal'; import { Disposable, ModelSerializer } from '@devexpress/analytics-core/analytics-utils'; import { editorTemplates, ObjectProperties } from '@devexpress/analytics-core/analytics-widgets'; import { RangeSpecific } from '@devexpress/analytics-core/analytics-widgets-internal'; import * as ko from 'knockout'; import { viewerEditorTemplates } from '../../../viewer/widgets/editorTemplates'; import { DefaultLocalizationProvider } from '../../controls/utils/_localizationUtils'; import { createExpressionEditorAction } from '../../internal/_expressionEditorAction'; import { designerEditorTemplates } from '../../widgets/editorTemplates'; import { ReportExpressionEditorWrapper } from '../../widgets/expressioneditor/reportExpressionEditorWrapper'; import { labelOrientation } from '../metadata/parameters/layoutItems'; import { extendValueSourceSettingsTypes, parameterExpressionSerializationInfo, parameterSerializationInfo, parameterValueSerializationInfo } from '../metadata/parameters/parameter'; import { DynamicListLookUpSettings, StaticListLookUpSettings } from './lookupSettings'; import { createExpressionProperty, ParameterExpressionBinding } from './parameterExpressionBinding'; import { parameterSeparator } from './parameterSettings'; import { ParameterTypesHelper } from './parameterTypesHelper'; import { PropertyExpressionMapper } from './propertyExpressionMapper'; import { RangeParametersSettings } from './rangeSettings'; import { ValueSourceSettingsHelper } from './valueSourceSettingsHelper'; const EditableParameterMode = { _ignoreEditors: ['valueSourceSettings', 'valueSourceSettingsType'], _displayNamePatcher: { 'isMultiValue': (info) => { info.displayName = 'Allow multiple values'; info.localizationId = 'ASPxReportsStringId.ReportDesigner_ParametersDialog_AllowMultipleValues'; }, 'allowNull': (info) => { info.displayName = 'Allow null value'; info.localizationId = 'ASPxReportsStringId.ReportDesigner_ParametersDialog_AllowNull'; }, 'selectAllValues': (info) => { info.displayName = 'Select all values'; info.localizationId = 'ASPxReportsStringId.ReportDesigner_ParametersDialog_SelectAllValues'; }, 'valueSourceSettingsType': (info) => info.displayName = 'Value Source' } }; export class Parameter extends Disposable { get _localizationProvider() { if (!this.__localizationProvider) { this.__localizationProvider = new DefaultLocalizationProvider(this); } return this.__localizationProvider; } getLocalizationProperty(propertyName) { return this._localizationProvider.getLocalizationProperty(propertyName); } getLocalizationProperties() { return this._localizationProvider.getLocalizationProperties(); } applyLocalization(propertyName, propertyValue) { this._localizationProvider.applyLocalization(propertyName, propertyValue); } _initializeValue() { const value = this.value(); if (this.isMultiValue()) { typeof value === 'string' ? this.value = ko.observableArray(this._parameterHelper.createMultiValueArray(value.split(parameterSeparator), this, (part) => { return this.parameterTypesHelper.convertSingleValue(part, this.type()); })) : this.value = ko.observableArray(); } else if (this.allowNull() && !value) { this.value(null); } else { this.value(this.parameterTypesHelper.convertSingleValue(value, this.type())); } } _preDeserialize(model) { if (model['@LookUpSettings']) { model['@ValueSourceSettings'] = model['@LookUpSettings']; delete model['@LookUpSettings']; } } _processObsoleteProperties() { if (this._obsoleteValue()) { this.value(this._obsoleteValue().content()); this._obsoleteValue(null); } delete this._obsoleteValue; } _getExpressionActions(name) { if (Parameter.propertiesWithExpressions.indexOf(name) === -1) return; const propertyInfo = this.info.filter(x => x.propertyName === name)[0]; const expression = this[this.propertyExpressionMapper.getExpressionPropertyName(name)]; const expressionLocalizedName = getLocalization(propertyInfo.displayName, propertyInfo.localizationId); const expressionForLocalizedString = getLocalization('{0} Expression', 'ReportStringId.UD_PropertyGrid_Menu_ItemExpression'); const expressionHint = ko.pureComputed(() => { return expression.value(); }); this._disposables.push(expressionHint); if (!this._expressionActions[name]) { const expressionEditor = new ReportExpressionEditorWrapper(ko.observable(this), ko.observable(expression)); this._disposables.push(expressionEditor); this._expressionActions[name] = [createExpressionEditorAction({ expressionEditor, hint: expressionHint, title: formatUnicorn(expressionForLocalizedString, expressionLocalizedName) })]; } return this._expressionActions[name]; } _updateTypeValues() { const types = this.info.filter(info => info.propertyName == 'type')[0]; const knownEnumValues = this.parameterTypesHelper.getEnumTypeValues(); if (!!knownEnumValues?.length) types.valuesArray = types.valuesArray.concat(knownEnumValues); } preprocessInfo(info) { if (this._isEditing()) { info.forEach(x => { if (EditableParameterMode._ignoreEditors.indexOf(x.propertyName) !== -1) { x.editor = undefined; } else if (x.editor && x.editor.header === editorTemplates.getEditor('bool').header) { x.editor = designerEditorTemplates.getEditor('parametersCheckbox'); } else if (x.editor && x.editor.custom === viewerEditorTemplates.multiValueEditable.custom) { x.editor = { custom: 'dxrd-multivalue-editing' }; } EditableParameterMode._displayNamePatcher[x.propertyName] && EditableParameterMode._displayNamePatcher[x.propertyName](x); }); } } getInfo() { let info = this.info; if (this.type) { const newInfo = extend(true, [], this.info); newInfo.splice(newInfo.indexOf(newInfo.filter((prop) => { return prop.propertyName === 'value'; })[0]), 1, this.valueInfo()); newInfo.splice(newInfo.indexOf(newInfo.filter((prop) => { return prop.propertyName === 'description'; })[0]) + 1, 0, labelOrientation); if (Parameter.availableRangeSettingTypes.indexOf(this.type()) !== -1) { const parameterSettingsTypeInfo = newInfo.filter((prop) => { return prop.propertyName === 'valueSourceSettingsType'; })[0]; if (parameterSettingsTypeInfo) parameterSettingsTypeInfo.valuesArray = extendValueSourceSettingsTypes; } if (this.valueSourceSettings() && this.valueSourceSettings() instanceof RangeParametersSettings) { const typeInfo = newInfo.filter((prop) => { return prop.propertyName === 'type'; })[0]; if (typeInfo) { typeInfo.valuesArray = ParameterTypesHelper.typeValues.filter(typeValue => Parameter.availableRangeSettingTypes.indexOf(typeValue.value) !== -1); } } info = newInfo; } this.preprocessInfo(info); this._parameterHelper && this._parameterHelper.customizeParameterProperties(this, info, { layoutItemType: 'Parameter', name: ko.unwrap(this.name) }); return info; } appendExpressionObjInfo(info) { for (let i = 0; i < info.length; i++) { if (info[i].propertyName == 'value') continue; const property = info[i]; if (Parameter.propertiesWithExpressions.indexOf(property.propertyName) != -1) { const newProperty = this.propertyExpressionMapper.registerExpressionProperty(property); info.splice(i + 1, 0, newProperty); i++; } } } getActionClassName(propertyName) { const expressionPropertyName = this.propertyExpressionMapper.getExpressionPropertyName(propertyName); const hasExpressions = !!this[expressionPropertyName].value(); return { 'dxrd-editormenu-expressions': hasExpressions, 'dxd-icon-accented': hasExpressions }; } constructor(model, _report, serializer) { super(); this._report = _report; this.templateName = 'dx-treelist-item'; this.labelOrientation = ko.observable('Horizontal'); this.actionProviders = []; this._expressionActions = {}; this.expressionObj = {}; this.info = extend(true, [], parameterSerializationInfo); this.propertyExpressionMapper = new PropertyExpressionMapper(); this._isEditing = ko.observable(false); this._showLayoutProperties = ko.observable(false); this.collapsed = ko.observable(false); this.valueSourceSettingsType = ko.observable('None'); this._canRemove = true; this.valueInfo = ko.observable(); this.multiValueInfo = ko.observable(); this.parameterTypesHelper = new ParameterTypesHelper(); this.appendExpressionObjInfo(this.info); this.actionProviders.push({ getActions: (name) => this._getExpressionActions(name) }); this._disposables.push(this._localizationProvider); const objectsStorage = _report.objectsStorageHelper; const parameterHelper = _report.parameterHelper; this._preDeserialize(model); this.parameterTypesHelper = new ParameterTypesHelper(_report.knownEnums); this._updateTypeValues(); serializer = serializer || new ModelSerializer(); serializer.deserialize(this, model); this.valueSourceSettingsHelper = new ValueSourceSettingsHelper(this); this.objectsStorage = objectsStorage; this._parameterHelper = parameterHelper; this['_name'] = ko.observable(this.parameterName()); this['change'] = (e, parameters) => { if (parameters.filter(x => x.parameterName() === e.value).length === 1) { this['_name'](e.value); } else { this.parameterName(this['_name']()); } }; if (!this._type()) { this._type(objectsStorage.getType(DotnetTypes.SystemString)); } this._processObsoleteProperties(); this.type = ko.pureComputed({ read: () => { return this._type().content(); }, write: (val) => { const oldVal = this._type().content(); if (val !== oldVal) { const editorValue = this.value(); if (this.isMultiValue()) this.value([]); else this.value(null); this.valueSourceSettingsHelper.updateSettingValues(undefined, null); setTimeout(() => { this._type(objectsStorage.getType(val)); if (this.isMultiValue()) return; if (val === DotnetTypes.SystemDateTime) { this.value(this.defaultValue); } else { this.value(this.parameterTypesHelper.convertSingleValue(editorValue, this.type())); } this.valueSourceSettingsHelper.updateSettingValues(this._type().content(), this.defaultValue); }, 1); } } }); this.expressionObj = { getInfo: () => { const info = this.getInfo().filter(x => x.propertyName.indexOf(ParameterExpressionBinding.expressionSuff) != -1); info.filter(x => x.propertyName == 'ValueExpressionObj')[0].displayName = 'Value'; return info; } }; this.info.forEach(property => { const index = property.propertyName.indexOf(ParameterExpressionBinding.expressionSuff); if (index !== -1) { this.expressionObj[property.propertyName] = createExpressionProperty(this, property.propertyName.substr(0, index)); } }); this._initializeValue(); this._disposables.push(this.isMultiValue.subscribe((newMultiValue) => { if (newMultiValue) { this.value = ko.observableArray([this._parameterHelper.createMultiValue(this, this.value())]); } else { this.value = ko.observable(this.defaultValue); this.selectAllValues(false); } })); this._disposables.push(this.selectAllValues.subscribe((newValue) => { if (newValue) { this.value = ko.observableArray([]); } else if (this.isMultiValue()) { this.value = ko.observableArray([this._parameterHelper.createMultiValue(this, this.value())]); } else { this.value = ko.observable(this.defaultValue); } this[parameterExpressionSerializationInfo.propertyName].value(''); })); this._disposables.push(this.valueSourceSettingsType.subscribe((newVal) => { if (newVal === 'None') { this.selectAllValues(false); } })); this._disposables.push(this._isEditing.subscribe((newVal) => { const settings = this.valueSourceSettings(); if (settings instanceof RangeParametersSettings || settings instanceof StaticListLookUpSettings) { settings._isEditing(newVal); } })); this.valueInfo = ko.pureComputed(() => { const result = extend(true, {}, parameterValueSerializationInfo, parameterHelper.getParameterInfo(this)); result.propertyName = 'value'; if (this.type() === DotnetTypes.SystemString || this.isMultiValue()) { result.defaultVal = ''; } return result; }); this.valueSourceSettingsHelper.initializeParameterSettingsType(); this.valueSourceSettingsHelper.initializeLookupValueSubscribe(_report); this.viewmodel = new ObjectProperties(ko.observable(this)); } isPropertyVisible(name) { if (name === 'valueSourceSettings') { return !!this.valueSourceSettings(); } else if (name === parameterValueSerializationInfo.propertyName) { return !(this.valueSourceSettings() instanceof RangeParametersSettings); } else if (name == parameterExpressionSerializationInfo.propertyName) { return this._isEditing() || this.isMultiValue(); } else if (name == labelOrientation.propertyName) { return this._showLayoutProperties(); } return this.propertyExpressionMapper.isPropertyVisible(name, this._isEditing()); } getParameterDescriptor() { return { description: this.description.peek(), displayName: 'Value', localizationId: 'DevExpress.XtraReports.Parameters.Parameter.Value', name: this.parameterName.peek(), type: this.type.peek(), value: this.value.peek(), visible: this.visible.peek(), enabled: this.enabled.peek(), multiValue: this.isMultiValue.peek(), allowNull: this.allowNull.peek(), selectAllValues: this.selectAllValues.peek(), tag: this.tag.peek() }; } assign(parameter) { this.getInfo().forEach((info) => { if (this[info.propertyName] && ko.isWritableObservable(this[info.propertyName])) this[info.propertyName](parameter[info.propertyName]()); }); } getRangeParameters() { let result = []; if (this.isList) { const settings = (this.valueSourceSettings()); result = [ settings.startParameter(), settings.endParameter() ]; } return result; } get name() { return this.parameterName(); } get specifics() { return this.isList ? RangeSpecific : this.parameterTypesHelper.getSpecifics(this.type()); } get icon() { return this.parameterTypesHelper.getIcon(this.type()); } get defaultValue() { return this.parameterTypesHelper.getDefaultValue(this.type()); } get displayName() { return this.parameterName(); } get isList() { return this.valueSourceSettings() instanceof RangeParametersSettings; } get dragData() { return { noDragable: this.isList }; } get canRemove() { return this._canRemove; } isPropertyDisabled(propertyName) { if (propertyName === 'allowNull' || propertyName === 'isMultiValue') { return this.valueSourceSettings() instanceof RangeParametersSettings; } if (propertyName === 'selectAllValues') { return !(this.isMultiValue() && (this.valueSourceSettings() instanceof StaticListLookUpSettings || this.valueSourceSettings() instanceof DynamicListLookUpSettings)); } if (propertyName === parameterValueSerializationInfo.propertyName || propertyName === parameterExpressionSerializationInfo.propertyName) return this.selectAllValues() && !this.isPropertyDisabled('selectAllValues'); return false; } } Parameter.propertiesWithExpressions = ['visible', 'enabled', 'value']; Parameter.ParametersRefString = 'Parameters'; Parameter.defaultGuidValue = ParameterTypesHelper.defaultGuidValue; Parameter.availableRangeSettingTypes = [DotnetTypes.SystemDateTime];