devexpress-reporting
Version:
DevExpress Reporting provides the capability to develop a reporting application to create and customize reports.
750 lines (749 loc) • 36.9 kB
JavaScript
/**
* DevExpress HTML/JS Reporting (designer\controls\xrReport.js)
* Version: 24.2.6
* Build date: Mar 18, 2025
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* License: https://www.devexpress.com/Support/EULAs/universal.xml
*/
import { SurfaceElementArea } from '@devexpress/analytics-core/analytics-elements';
import { $dx, addDisposeCallback, assignObj, collectionsVisitor, convertFromCssPixelUnits, createObservableArrayMapCollection, CssCalculator, deserializeChildArray, DragDropHandler, extend, getFirstItemByPropertyValue, getFullPath, getPaperSize, getUniqueName, getUniqueNameForNamedObjectsArray, HoverInfo, NotifyAboutWarning, Resizable, roundingXDecimals, unitsToPixel } from '@devexpress/analytics-core/analytics-internal';
import { deserializeArray, Disposable } from '@devexpress/analytics-core/analytics-utils';
import { FilterStringOptions } from '@devexpress/analytics-core/analytics-widgets';
import * as ko from 'knockout';
import { defaultCulture } from '../../common/defaultCulture';
import { transformNewLineCharacters } from '../../common/utils/_utils';
import { bandSurfaceCollapsedHeight } from '../bands/bandSurfaceCollapsedHeight';
import { BandViewModel } from '../bands/xrBand';
import { addBandToContainer } from '../bands/_bandContainerUtils';
import { BandsHolder } from '../bands/_bandHolder';
import { getLevelCount, initLevels, setMarkerWidth, sortBands } from '../bands/_bandUtils';
import { CalculatedField } from '../dataObjects/calculatedField';
import { collectAvailableParameters } from '../dataObjects/metadata/_parameterUtils';
import { createNewObjectItem } from '../dataObjects/objectItemCreation';
import { ObjectsStorage } from '../dataObjects/objectStorage';
import { ParameterPanelLayoutItem } from '../dataObjects/parameters/layoutItems';
import { Parameter } from '../dataObjects/parameters/parameter';
import { UniversalDataSource } from '../dataObjects/universalDataSource';
import { ReportParameterHelper } from '../helpers/reportParameterHelper';
import { ReportModelSerializer } from '../internal/serialization/_serializer';
import { LocalizationItem } from '../localization/_localization';
import { ReportLocalizationEngine } from '../localization/_localizationEngine';
import { pageHeight, pageWidth } from './metadata/xrReport';
import { ExtensionModel } from './properties/extension';
import { FormattingRule } from './properties/formattingrules';
import { StyleModel } from './properties/style';
import { WatermarkModel } from './properties/watermark';
import { getUnitProperties } from './utils/_initUtils';
import { ReportLocalizationProvider } from './utils/_localizationUtils';
import { patchMargins } from './utils/_modelPatch';
import { getExistTableOfContents } from './utils/_tocUtils';
import { XRCrossBandControlViewModel } from './xrCrossband';
import { XRReportElementViewModel } from './xrReportelement';
import { XRTableSurface } from './xrTable';
import { XRTableCellSurface } from './xrTableCell';
export class ReportViewModel extends XRReportElementViewModel {
static createObjectStorage(_componentStorage, _objectStorage, collectSubscription = (subscription) => void 0) {
const objectStorage = ko.observableArray([
..._objectStorage(),
..._componentStorage()
]);
collectSubscription(objectStorage.subscribe((changeSet) => {
changeSet.forEach((change) => {
if (change.status === 'added') {
if (change.value.objectType && ReportViewModel.availableDataSourceTypes.some(x => change.value.objectType().indexOf(x) !== -1)) {
_componentStorage.push(change.value);
}
else {
_objectStorage.push(change.value);
}
}
else if (change.status === 'deleted') {
if (change.value.objectType && ReportViewModel.availableDataSourceTypes.some(x => change.value.objectType().indexOf(x) !== -1) && _componentStorage().indexOf(change.value) !== -1) {
_componentStorage.remove(change.value);
}
else {
_objectStorage.remove(change.value);
}
}
});
}, null, 'arrayChange'));
return objectStorage;
}
_getDpi(unitType) {
switch (unitType) {
case 'HundredthsOfAnInch': return 100;
case 'TenthsOfAMillimeter': return 254;
case 'Pixels': return 96;
}
}
_recalculateUnits(unitType) {
const newDpi = this._getDpi(unitType), oldDpi = this._innerDpi(), coef = newDpi / oldDpi;
const unitProperties = getUnitProperties(this);
unitProperties && unitProperties.reCalculateObject(coef);
this.enumerateComponents((target) => {
target().forEach((item) => {
const unitProperties = getUnitProperties(item);
unitProperties && unitProperties.reCalculateObject(coef);
});
});
this._localization.recalculateUnits(coef);
this._innerDpi(newDpi);
}
_updatePageSize(paperKind) {
const size = paperKind === 'Custom' ? this.size : getPaperSize(paperKind);
this.pageHeight(roundingXDecimals(ko.unwrap(this.landscape() ? size.width : size.height) * (this._innerDpi.peek() / 100), false, 0));
this.pageWidth(roundingXDecimals(ko.unwrap(this.landscape() ? size.height : size.width) * (this._innerDpi.peek() / 100), false, 0));
}
enumerateComponents(process = () => void 0) {
const controls = [];
collectionsVisitor(this, process, ['controls', 'bands', 'subBands', 'crossBandControls', 'rows', 'cells', 'watermarks', 'parameters', 'parameterPanelLayoutItems', 'fields', 'levels', 'styles'], controls);
return [].concat.apply([], controls);
}
createLocalizationProvider() {
return new ReportLocalizationProvider(this);
}
createReportViewModel(report, serializer) {
return new ReportViewModel(report, serializer);
}
findStyle(styleName) {
const result = null;
for (let i = 0; i < this.styles().length; i++) {
if (this.styles()[i].name() === styleName) {
return this.styles()[i];
}
}
return result;
}
_getBandForToc(bands) {
let currentBand = null;
bands.some((band) => {
if (!getExistTableOfContents(band)) {
currentBand = band;
}
else if (band.bands().length > 0) {
currentBand = this._getBandForToc(band.bands());
}
return !!currentBand;
});
return currentBand;
}
getOrCreateBandForToC(createNew = true) {
const availableTypes = ['ReportHeaderBand', 'ReportFooterBand'];
const bands = this.bands().filter(element => {
const typesIndex = availableTypes.indexOf(element.controlType);
if (typesIndex !== -1) {
availableTypes.splice(typesIndex, 1);
return true;
}
return false;
});
let currentBand = this._getBandForToc(bands);
const canCreate = availableTypes.length > 0;
if (createNew && !currentBand && canCreate) {
currentBand = this.createChild({ '@ControlType': availableTypes[0] });
}
return { band: currentBand, canAdd: canCreate || !!currentBand };
}
canAddToC() {
return this.getOrCreateBandForToC(false).canAdd;
}
_initializeBands() {
const traverse = (xs) => xs.reduce((res, x) => { res.push(x, ...traverse(ko.unwrap(x['bands']) || [])); return res; }, []);
const bandNames = traverse(this.bands()).map(x => x.name());
if (this.bands().length === 0) {
this.createChild({ '@ControlType': 'DetailBand', '@Name': 'Detail1' });
}
else if (getFirstItemByPropertyValue(this.bands(), 'controlType', 'DetailBand') === null && getFirstItemByPropertyValue(this.bands(), 'controlType', 'VerticalDetailBand') === null) {
this.createChild({ '@ControlType': 'DetailBand', '@Name': getUniqueName(bandNames, 'Detail') });
}
if (getFirstItemByPropertyValue(this.bands(), 'controlType', 'TopMarginBand') === null) {
this.createChild({ '@ControlType': 'TopMarginBand', '@Name': getUniqueName(bandNames, 'TopMargin') });
}
if (getFirstItemByPropertyValue(this.bands(), 'controlType', 'BottomMarginBand') === null) {
this.createChild({ '@ControlType': 'BottomMarginBand', '@Name': getUniqueName(bandNames, 'BottomMargin') });
}
}
isPropertyDisabled(name) {
if (name === 'pageWidth' || name === 'pageHeight') {
return this.paperKind() !== 'Custom';
}
else if (name === 'dataMember') {
return this.dataSource() === null;
}
return super.isPropertyDisabled(name);
}
dispose() {
super.dispose();
this.disposeObservableArray(this.parameters);
this.disposeObservableArray(this.calculatedFields);
this.disposeObservableArray(this.watermarks);
this.disposeObservableArray(this.crossBandControls);
this.disposeObservableArray(this.formattingRuleSheet);
this.disposeObservableArray(this.bands);
this.disposeObservableArray(this.objectStorage);
this.disposeObservableArray(this.styles);
this.resetObservableArray(this.extensions);
this.resetObservableArray(this.objectStorage);
this.resetObservableArray(this.parameters);
this.resetObservableArray(this.parameterPanelLayoutItems);
this.resetObservableArray(this.calculatedFields);
this.resetObservableArray(this.watermarks);
this.resetObservableArray(this.crossBandControls);
this.resetObservableArray(this.formattingRuleSheet);
this.resetObservableArray(this.bands);
this.resetObservableArray(this.styles);
this.resetObservableArray(this.components);
}
preInitProperties() {
this.controlType = 'DevExpress.XtraReports.UI.XtraReport';
}
constructor(report, serializer, knownEnums) {
super(patchMargins(report = report.XtraReportsLayoutSerializer || report), null, serializer = serializer || new ReportModelSerializer());
if (this.pageWidth() === pageWidth.defaultVal) {
this.pageWidth(ReportViewModel.defaultPageSize.width);
}
if (this.pageHeight() === pageHeight.defaultVal) {
this.pageHeight(ReportViewModel.defaultPageSize.height);
}
this.knownEnums = knownEnums;
this._dataBindingMode = ko.observable('');
this._update = ko.observable(false);
this._disposables.push(this.isModelReady = ko.pureComputed(() => { return !this._update(); }));
this._disposables.push(this.key = ko.pureComputed(() => { return this.name(); }));
this._disposables.push(this['displayName'] = ko.pureComputed({
read: () => { return this.displayNameObject(); },
write: (newValue) => { this.displayNameObject(newValue); }
}));
this.dataSourceRefs = [];
this.dataSourceHelper = ko.observable();
this.stylesHelper = ko.observable();
this.dataBindingsProvider = ko.observable();
this._disposables.push(this.parameterHelper = new ReportParameterHelper(this));
this.parameterHelper.initialize(knownEnums);
this._disposables.push(this.measureUnit.subscribe((unitType) => {
this._update(true);
this._recalculateUnits(unitType);
this._updatePageSize(this.paperKind.peek());
this._update(false);
}));
this._disposables.push(this.landscape.subscribe((newVal) => {
const width = this.pageWidth();
this.pageWidth(this.pageHeight());
this.pageHeight(width);
}));
this._disposables.push(this.dataSource.subscribe((newVal) => {
if (!newVal) {
this.dataMember(null);
}
else {
const path = this.dsHelperProvider()?.getDataSourcePath(newVal);
if (path)
this.dataBindingsProvider()?.getItems({ fullPath: path, pathParts: [path] }).then((items) => {
if (items.length) {
if (!items.some(dataMember => dataMember.name == this.dataMember()))
this.dataMember(null);
}
});
}
}));
this.styles = deserializeArray(report.StyleSheet, (item) => { return new StyleModel(item, this, serializer); });
this._objectStorage = deserializeArray(report.ObjectStorage, (item) => { return createNewObjectItem(item, this.dsHelperProvider, serializer); });
this._componentStorage = deserializeArray(report.ComponentStorage, (item) => { return createNewObjectItem(item, this.dsHelperProvider, serializer); });
this.objectStorage = ReportViewModel.createObjectStorage(this._componentStorage, this._objectStorage, (subscription) => this._disposables.push(subscription));
this.objectsStorageHelper = new ObjectsStorage(this.objectStorage, this.dsHelperProvider);
this._disposables.push(this.objectsStorageHelper);
this.parameters = deserializeArray(report.Parameters, (item) => { return new Parameter(item, this, serializer); });
this.parameterPanelLayoutItems = deserializeArray(report.ParameterPanelLayoutItems, (item) => { return ParameterPanelLayoutItem.createLayoutItem(item, this, serializer); });
this.parameterHelper.updateParameterLayoutItems();
this.objectStorage().forEach((objectStorage) => {
if (objectStorage instanceof UniversalDataSource) {
objectStorage['tableInfoCollection']().forEach((tableInfoCollection) => {
tableInfoCollection.filterString().helper.parameters = this.parameters;
});
}
});
this.bands = deserializeChildArray(report.Bands, this, (item) => { return this.createControl(item, serializer); });
initLevels(this.bands());
this.bands().sort(sortBands);
this.extensions = deserializeArray(report.Extensions, (item) => { return new ExtensionModel(item, serializer); });
this.crossBandControls = deserializeArray(report.CrossBandControls, (item) => { return this.createControl(item, serializer); });
this.calculatedFields = deserializeArray(report.CalculatedFields, (item) => { return new CalculatedField(item, serializer); });
this.watermarks = deserializeArray(report.Watermarks, (item) => { return new WatermarkModel(item, serializer); });
this._initializeBands();
this.formattingRuleSheet = deserializeArray(report.FormattingRuleSheet, (item) => { return new FormattingRule(item, this, serializer); });
this.components = ko.observableArray([]);
this._disposables.push(this.formattingRuleSheet.subscribe((args) => {
args.forEach((rule) => {
if (!rule.value.name()) {
rule.value.name(getUniqueNameForNamedObjectsArray(this.formattingRuleSheet(), 'formattingRule'));
}
if (!rule.value.parent) {
rule.value.parent = this;
}
});
}, null, 'arrayChange'));
this._disposables.push(this.margins.left.subscribe((newVal) => {
if (this.isModelReady() && newVal > this.pageWidth() - this.margins.right()) {
this.margins.right(this.pageWidth() - this.margins.left());
}
}));
this._disposables.push(this.margins.right.subscribe((newVal) => {
if (this.isModelReady() && newVal > this.pageWidth() - this.margins.left()) {
this.margins.left(this.pageWidth() - this.margins.right());
}
}));
this._disposables.push(this.paperKind.subscribe((newVal) => {
newVal !== 'Custom' && this._updatePageSize(newVal);
}));
const dataMember = ko.pureComputed(() => {
return getFullPath(this.getPath('dataMember'), this.dataMember());
});
const dataSource = this.dataSource;
const disabled = ko.pureComputed(() => !dataSource());
const filterString = new FilterStringOptions(this['_filterString'], dataMember, disabled);
this._disposables.push(dataMember);
this._disposables.push(disabled);
filterString.helper.parameters = ko.computed(() => {
return collectAvailableParameters(this.parameters());
});
this._disposables.push(filterString.helper.parameters);
this['filterString'] = filterString;
this._scriptReferencesString = ko.observable(this.scriptReferencesString());
this._disposables.push(this.scriptReferencesString = ko.pureComputed({
read: () => { return this._scriptReferencesString(); },
write: (newVal) => { this._scriptReferencesString(transformNewLineCharacters(newVal)); }
}));
this._localizationItems = deserializeArray(report.LocalizationItems, (item) => { return new LocalizationItem(item, serializer); });
this._disposables.push(this._localization = new ReportLocalizationEngine(this));
this._localizationItems.removeAll();
let currentLanguage = defaultCulture;
this.language = ko.observable(currentLanguage);
this._localization.apply(currentLanguage);
this._disposables.push(this.language.subscribe((newVal) => {
this._localization.save(currentLanguage);
this._localization.apply(newVal);
currentLanguage = newVal;
}));
}
isLocalized() {
return this._localization.isLocalized();
}
initialize() {
super.initialize();
this.size.height = this.pageHeight;
this.size.width = this.pageWidth;
}
getNearestParent(target) {
return this;
}
addChild(control) {
if (control instanceof XRCrossBandControlViewModel) {
control.parentModel(this);
control.startBand(this.bands()[0]);
control.endBand(this.bands()[0]);
this.crossBandControls.push(control);
}
else if (control instanceof BandViewModel) {
addBandToContainer(this, control);
}
else {
NotifyAboutWarning('Attempt to add wrong child control.');
}
}
removeChild(control) {
if (control instanceof XRCrossBandControlViewModel) {
this.crossBandControls.splice(this.crossBandControls().indexOf(control), 1);
}
else if (control instanceof BandViewModel) {
if (this.bands().length > 1) {
this.bands.splice(this.bands().indexOf(control), 1);
}
}
else {
NotifyAboutWarning('Attempt to remove wrong child control.');
}
}
clearLocalization(culture = this.language()) {
this._localization.items.clear(culture);
this._localization.apply(culture);
}
serialize() {
this._localization.save();
if (this.isLocalized()) {
this._localizationItems(this._localization.serialize());
}
else {
this._localization.apply(defaultCulture);
this._localization.items.clear();
}
return new ReportModelSerializer(this).serialize();
}
save() {
this.parameterHelper.clearLayoutItems();
const data = this.serialize();
if (this.onSave) {
this.onSave(data);
}
return data;
}
getPath(propertyName) {
const helper = ko.unwrap(this.dataSourceHelper);
if (!helper)
return;
let path = helper.getDataSourcePath(this.dataSource());
if (propertyName === 'expression' && this.dataMember())
path += '.' + this.dataMember();
return path;
}
clone(dataSourceRefsFromParent) {
const filteredDataSourceRefs = [];
let dataSourceRefs = [...this.dataSourceRefs];
if (this['objectStorageIsEmpty']() && dataSourceRefsFromParent && dataSourceRefsFromParent.length) {
dataSourceRefs = [...dataSourceRefs, ...dataSourceRefsFromParent];
}
const collectStorages = (storage, isComponentStorage = false) => {
storage.reduce((result, storageItem, index) => {
const dataSourceRef = dataSourceRefs.filter(x => x.ref === storageItem['_model']['@Ref'])[0];
if (dataSourceRef) {
result.push({
index,
isComponentStorage,
dataSourceRef: extend(true, {}, dataSourceRef)
});
}
return result;
}, filteredDataSourceRefs);
};
collectStorages(this._objectStorage());
collectStorages(this._componentStorage(), true);
const report = new ReportViewModel(this.save());
report.dataSourceRefs = [];
filteredDataSourceRefs.forEach((item) => {
const storage = item.isComponentStorage ? report._componentStorage() : report._objectStorage();
item.dataSourceRef.ref = storage[item.index]['_model']['@Ref'];
report.dataSourceRefs.push(item.dataSourceRef);
});
return report;
}
isStyleProperty(propertyName) { return false; }
get dataBindingMode() {
return ko.unwrap(this._dataBindingMode);
}
}
ReportViewModel.availableDataSourceTypes = ['DataSource', 'ObjectSource'];
ReportViewModel.bandsTypeOrdering = ['TopMarginBand', 'ReportHeaderBand', 'PageHeaderBand', 'GroupHeaderBand', 'DetailBand', 'DetailReportBand', 'GroupFooterBand', 'ReportFooterBand', 'PageFooterBand', 'BottomMarginBand'];
ReportViewModel.unitProperties = ['snapGridSize', 'margins'];
ReportViewModel.defaultPageSize = {
width: 850,
height: 1100
};
export class ReportSurface extends SurfaceElementArea {
_createMargin(side, oppositeSide) {
return ko.pureComputed({
read: () => this.rtl() ? this[oppositeSide]() : this[side](),
write: (value) => {
this.rtl() ? this[oppositeSide](value) : this[side](value);
}
});
}
_updateWatermarkImageNaturalSize(val) {
if (!val)
return;
const image = new Image();
image.src = val.getDataUrl();
image.onload = (e) => {
this._watermarkImageNaturalSize({ width: image.naturalWidth, height: image.naturalHeight });
image.onload = null;
};
}
get _unitAbsoluteRect() {
return {
top: 0, left: 0,
right: this._control.size.width(), bottom: this._control.size.height(),
width: this._control.size.width(), height: this._control.size.height(),
};
}
dispose() {
super.dispose();
this._watermarkSubscriptions.forEach(watermark => watermark.dispose());
this.disposeObservableArray(this.crossBandControls);
this.resetObservableArray(this.crossBandControls);
}
get watermark() {
return this.report.watermarks()[0];
}
constructor(report, zoom = ko.observable(1)) {
super(report, {
measureUnit: report.measureUnit, zoom: zoom
}, ReportSurface._unitProperties);
this.report = report;
this._watermarkSubscriptions = [];
this._assignSelectedWatermark = () => {
this._watermarkSubscriptions.push(this.watermark.imageSource.subscribe((newValue) => {
this._updateWatermarkImageNaturalSize(newValue);
}));
this._updateWatermarkImageNaturalSize(this.watermark.imageSource.peek());
this._watermarkSubscriptions.push(this._watermarkTextRenderingResult = ko.pureComputed(() => {
const canvas = document.createElement('canvas');
const originalWidthPx = unitsToPixel(this.report.pageWidth(), this.measureUnit());
const originalHeightPx = unitsToPixel(this.report.pageHeight(), this.measureUnit());
canvas.width = originalWidthPx;
canvas.height = originalHeightPx;
const context = canvas.getContext('2d');
context.translate(originalWidthPx / 2, originalHeightPx / 2);
switch (this.watermark.textDirection()) {
case 'Vertical':
context.rotate(-Math.PI / 2);
break;
case 'ForwardDiagonal':
context.rotate(-50 * Math.PI / 180);
break;
case 'BackwardDiagonal':
context.rotate(50 * Math.PI / 180);
}
context.textAlign = 'center';
context.textBaseline = 'middle';
const font = new CssCalculator(this.watermark, ko.observable(false)).fontCss();
context.font = [font.fontStyle.toLowerCase(), font.fontWeight.toLowerCase(), font.fontSize, font.fontFamily].filter(x => x).join(' ');
context.fillStyle = this.watermark.foreColor();
context.fillText(this.watermark.text(), 0, 0);
return canvas.toDataURL('image/png');
}));
};
this.surfaceContextMenuHandler = (selection, surface, e) => {
const target = e.target;
if (target.className === 'dxrd-band-marker-content')
return;
const focused = selection.focused && selection.focused();
if (!focused)
return;
if (focused instanceof XRTableSurface && selection.dropTarget instanceof XRTableCellSurface
&& focused.rows && focused.rows().some(row => row === selection.dropTarget.parent))
return;
!selection.disabled() && selection.clickHandler(selection.dropTarget ? null : surface, e);
};
this.allowMultiselect = false;
this.locked = false;
this.focused = ko.observable(false);
this.selected = ko.observable(false);
this.templateName = ko.observable('dxrd-report');
this.underCursor = ko.observable(new HoverInfo());
this.crossBandControls = ko.observableArray();
this.minHeight = ko.observable();
this.maxMarkerWidth = ko.observable();
this.validationMode = ko.observable(false);
this.parent = null;
this.zoom = zoom;
this.dpi = report.dpi;
this._disposables.push(this.rtl = ko.pureComputed(() => report.rtl() && report.rtlLayout() === 'Yes'));
this.measureUnit = report.measureUnit;
this._context = this;
this._watermarkImageNaturalSize = ko.observable({ width: 0, height: 0 });
this.drawWatermark = report.drawWatermark;
this._disposables.push(report.watermarks.subscribe((args) => {
args.forEach(arg => {
if (arg.status === 'deleted') {
const isSelectedWatermarkDeleted = arg.index === 0;
if (isSelectedWatermarkDeleted) {
this._watermarkSubscriptions.forEach(watermark => watermark.dispose());
report.watermarks().length > 0 && this._assignSelectedWatermark();
}
}
else if (arg.status === 'added' && report.watermarks().length === 1) {
this._assignSelectedWatermark();
}
});
}, null, 'arrayChange'));
this.watermark && this._assignSelectedWatermark();
this._disposables.push(this._width = ko.pureComputed({
read: () => {
return this['pageWidth']();
}
}));
this._disposables.push(this._height = ko.pureComputed({
read: () => {
return this['pageHeight']();
}
}));
this.margins = {
bottom: this['_bottom'],
left: this._createMargin('_left', '_right'),
right: this._createMargin('_right', '_left'),
top: this['_top']
};
this._disposables.push(this.pageWidthWithoutMargins = ko.computed(() => {
return this.pageWidth() - this.margins.left() - this.margins.right();
}));
this._disposables.push(this.margins.left);
this._disposables.push(this.margins.right);
this._disposables.push(this.bandsHolder = new BandsHolder(this));
this.bandsHolder.initialize(report.bands);
this._disposables.push(ko.computed(() => {
const levelCount = getLevelCount(this.bandsHolder);
setMarkerWidth(this.bandsHolder, levelCount, 0);
this.maxMarkerWidth(bandSurfaceCollapsedHeight * levelCount + 22);
}));
this._disposables.push(this.effectiveHeight = ko.pureComputed(() => {
const minHeight = this.bandsHolder.getHeight();
this.minHeight(minHeight);
return minHeight;
}));
this._disposables.push(createObservableArrayMapCollection(report.crossBandControls, this.crossBandControls, this._createSurface));
this._disposables.push(this.ghostContainerOffset = ko.pureComputed(() => {
return this.rtl() ? 0 : this.margins.left();
}));
const marginOptions = new SurfaceMarginResizeOptions(this.margins, this.rtl, this.pageWidth);
this._disposables.push(marginOptions);
this.rightMarginOffset = marginOptions.rightMarginOffset;
this.leftMarginOffset = marginOptions.leftMarginOffset;
this.rightMarginResizableOffset = marginOptions.rightMarginResizableOffset;
this.leftMarginResizableOffset = marginOptions.leftMarginResizableOffset;
this.leftMarginResizeOptions = marginOptions.leftMarginOptions;
this.rightMarginResizeOptions = marginOptions.rightMarginOptions;
}
getChildrenCollection() {
return this.bandsHolder.bands;
}
isFit(dropTarget) {
return dropTarget.underCursor().y >= -0.1
&& dropTarget.underCursor().x >= 0
&& ((this === dropTarget) ? this.effectiveHeight() : dropTarget.rect().height) > dropTarget.underCursor().y
&& (this.pageWidth() - this.margins.left()) > dropTarget.underCursor().x;
}
canDrop() { return true; }
wrapRtlProperty(data, undoEngine, element) {
const wrapper = ko.computed({
read: data.value,
write: (newValue) => {
undoEngine.peek().start();
const prevValue = this.rtl.peek();
data.value(newValue);
if (prevValue !== this.rtl.peek()) {
const report = this.getControlModel();
const left = report.margins.left();
report.margins.left(report.margins.right());
report.margins.right(left);
}
undoEngine.peek().end();
}
});
addDisposeCallback(element, () => { wrapper.dispose(); });
return assignObj(data, extend({}, data, { value: wrapper }));
}
clickHandler(selection, e) {
!selection.disabled() && selection.clickHandler(this, e);
e.stopPropagation();
}
reportContextMenuHandler(selection, e) {
if (!e.target.closest('.dxrd-surface') && !selection.disabled())
selection.clickHandler(this, e);
}
checkParent(surfaceParent) { return false; }
}
ReportSurface._unitProperties = {
_width: (o) => { return o.size.width; },
_height: (o) => { return o.size.height; },
pageWidth: (o) => { return o.size.width; },
pageHeight: (o) => { return o.size.height; },
snapGridSize: (o) => {
return o.snapGridSize;
},
_bottom: (o) => { return o.margins.bottom; },
_left: (o) => { return o.margins.left; },
_right: (o) => { return o.margins.right; },
_top: (o) => { return o.margins.top; }
};
class SurfaceMarginResizeOptions extends Disposable {
_createOptions(undoEngine, startDelegate, resizeDelegate) {
return {
handles: ko.pureComputed(() => {
return this.rtl() ? this.oppositeHandle : this.handle;
}),
start: (e, ui) => {
startDelegate(e, ui);
undoEngine().start();
},
resize: (e, ui) => {
resizeDelegate(e, ui);
},
stop: (e, ui) => {
undoEngine().end();
},
disabled: DragDropHandler.started
};
}
constructor(margins, rtl, pageWidth) {
super();
this.rtl = rtl;
this.handle = 'w';
this.oppositeHandle = 'e';
const elements = [];
this._disposables.push(rtl.subscribe((value) => {
$dx(elements).find('.ui-resizable-e, .ui-resizable-w')
.removeClass('ui-resizable-' + (value ? this.handle : this.oppositeHandle))
.addClass('ui-resizable-' + (value ? this.oppositeHandle : this.handle));
}));
let rightOptions = null;
let leftOptions = null;
this._disposables.push(this.rightMarginOffset = ko.pureComputed(() => {
return rtl() ? 0 : pageWidth() - margins.left() - margins.right();
}));
this._disposables.push(this.leftMarginOffset = ko.pureComputed(() => {
return rtl() ? pageWidth() - margins.left() : 0;
}));
this._disposables.push(this.rightMarginResizableOffset = ko.pureComputed(() => {
return rtl() ? margins.right() : this.rightMarginOffset();
}));
this._disposables.push(this.leftMarginResizableOffset = ko.pureComputed(() => {
return rtl() ? margins.right() : 0;
}));
this.rightMarginOptions = (undoEngine, element) => {
if (!rightOptions) {
let originalMarginRight = margins.right();
let maxRightMargin = void 0;
rightOptions = this._createOptions(undoEngine, (e, element) => {
originalMarginRight = margins.right();
maxRightMargin = pageWidth() - margins.left() - 1;
}, (e, element) => {
const startResizePosition = convertFromCssPixelUnits(element.dataset.originalLeftMousePosition);
const positionDiff = e.pageX - startResizePosition;
margins.right(Math.max(0, Math.min(originalMarginRight + (rtl() ? positionDiff : -positionDiff), maxRightMargin)));
if (!element.classList.contains('dxrd-ruler-shadow')) {
$dx(element).css({ left: this.rightMarginResizableOffset() + 'px', width: '0px' });
}
else {
$dx(element).css({ left: this.rightMarginOffset() + 'px' });
}
});
this._disposables.push(rightOptions);
}
const resizableElement = new Resizable(element, rightOptions).initialize();
addDisposeCallback(element, () => {
resizableElement.dispose();
});
elements.push(element);
return rightOptions;
};
this.leftMarginOptions = (undoEngine, element) => {
if (!leftOptions) {
let startMarginLeftPosition = margins.left();
leftOptions = this._createOptions(undoEngine, (e, element) => {
startMarginLeftPosition = margins.left();
}, (e, element) => {
const startResizePosition = convertFromCssPixelUnits(element.dataset.originalLeftMousePosition);
const sizeDiff = e.pageX - startResizePosition;
const maxLeftmargin = pageWidth() - margins.right();
margins.left(Math.min(Math.max(1, startMarginLeftPosition + (rtl() ? -sizeDiff : sizeDiff)), maxLeftmargin));
$dx(element).css({ left: this.leftMarginResizableOffset() + 'px', width: (pageWidth() - margins.left() - margins.right()) + 'px' });
});
this._disposables.push(leftOptions);
}
const resizableElement = new Resizable(element, leftOptions).initialize();
addDisposeCallback(element, () => {
resizableElement.dispose();
});
elements.push(element);
return leftOptions;
};
}
}