devexpress-reporting
Version:
DevExpress Reporting provides the capability to develop a reporting application to create and customize reports.
467 lines (466 loc) • 19.2 kB
JavaScript
/**
* DevExpress HTML/JS Reporting (viewer\internal\_page.js)
* Version: 24.2.7
* Build date: Apr 29, 2025
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* License: https://www.devexpress.com/Support/EULAs/universal.xml
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { compareSizes } from '@devexpress/analytics-core/analytics-elements-native';
import { $dx, DxDeferred, formatUnicorn, getLocalization, toQueryParameters, base64DecodeUnicode } from '@devexpress/analytics-core/analytics-internal-native';
import { BaseRenderingModel, mutable, mutableArray } from '@devexpress/analytics-core/analytics-serializer-native';
import { PreviewEditingFieldsKeyboardHelper } from '../accessibility/_previewEditingFieldsKeyboardHelper';
import { ZoomAutoBy } from '../constants';
import { HandlerUri, PageRenderFormat, PreviewRenderFormat } from '../settings';
import { brickText, initializeBrick, updateBricksPosition } from './_brickUtils';
import { createPreviewPageViewModel, updatePreviewPageViewModel } from './_page.viewModel';
import { PreviewRequestWrapper } from './_previewRequestWrapper';
import { PreviewSelection } from './_previewSelection';
import { getCurrentResolution } from './_utils';
const imageSrcMutableOptions = { rateLimit: { timeout: 100, method: 'notifyWhenChangesStop' } };
export class PreviewPage extends BaseRenderingModel {
createViewModel() {
return createPreviewPageViewModel.call(this, super.createViewModel());
}
updateViewModel(args) {
updatePreviewPageViewModel.call(this, args);
}
onPropertyChanged(args) {
if (args.propertyName === 'zoom') {
this._updatePageSize();
}
if (args.propertyName === 'previewSize')
this._onResize();
if (args.propertyName === 'originalSize' || args.propertyName === 'autoFitBy' || args.propertyName === 'brickLoading' || args.propertyName === 'previewSize') {
this._onAutoFitChanged && this._onAutoFitChanged();
}
if (args.propertyName === 'active' || args.propertyName === 'brick') {
if (!this.active) {
this.resetBrickRecusive(this.brick);
this._selectedBrickPath = null;
}
this._onPageActiveChanged && this._onPageActiveChanged(this.active);
}
if (args.propertyName === 'brick') {
this.bricks = this.getBricksFlatList(this.brick);
this.clickableBricks = this.bricks.filter((x) => !!x.navigation);
this.updateActiveBricks();
}
if (args.propertyName === 'isClientVisible') {
if (args.newValue) {
this._setPageImgSrc(this.reportPreview.documentId, this.reportPreview._unifier, this.zoom);
}
}
if (args.propertyName === 'imageSrc')
this._onImageSrcChanged();
}
_initializeEditingFields(editingFieldBricks, originalWidth, originalHeight) {
if (this._editingFieldsSubscriptionDispose) {
this.editingFields.forEach(field => field.dispose && field.dispose());
this._editingFieldsSubscriptionDispose();
}
const createEditingFields = () => {
const allEditingFields = this.reportPreview._editingFields;
if (!allEditingFields || editingFieldBricks.length === 0) {
return [];
}
const pageFieldViewModels = [];
for (let i = 0; i < editingFieldBricks.length; i++) {
const brick = editingFieldBricks[i];
const editingField = allEditingFields[brick.efIndex - 1];
if (!editingField)
return [];
editingField.brick = brick;
pageFieldViewModels.push(editingField.createModel(this, originalWidth, originalHeight, () => allEditingFields, brick.absoluteBounds));
brick.text = (brick => (() => brickText(brick, () => allEditingFields)))(brick);
}
return pageFieldViewModels;
};
this.editingFields = createEditingFields();
this._editingFieldsSubscriptionDispose = this.reportPreview.events.on('_editingFieldsChanged', (args) => {
this.editingFields = createEditingFields();
});
}
_getPixelRatio() {
return window['devicePixelRatio'] || 1;
}
_onPageLoaded(result, processClick) {
if (!result)
return;
this.useSvg = this._useSvg;
if (!this.useSvg) {
this.imageHeight = result.height;
this.imageWidth = result.width;
this.currentScaleFactor = this._currentScaleFactor;
this._updatePageSize();
this.displayImageSrc = 'data:image/png;base64,' + result.base64string;
}
else {
this.svgMarkup = base64DecodeUnicode(result.base64string);
}
if (this._isDisposed)
return;
this.pageLoading = false;
try {
if (!result || !result.brick) {
return;
}
this.brickColumnWidthArray = result.columnWidthArray;
this.originalSize = { width: result.brick.width, height: result.brick.height };
const editignFieldBricks = [];
this.initializeBrick(result.brick, processClick, editignFieldBricks);
this._initializeEditingFields(editignFieldBricks, result.brick.width, result.brick.height);
this._selectedBrickPath && this.selectBrick(this._selectedBrickPath);
}
finally {
if (!this.shouldSkipBrickLoading) {
this.brickLoading = false;
}
this.shouldSkipBrickLoading = false;
}
}
_onPageLoadFailed() {
if (this._isDisposed)
return;
if (this.isClientVisible) {
this.pageLoading = false;
this.pageIndex !== -1 && (this.brickLoading = false);
}
}
_updatePageSize() {
const newSize = {
width: this.imageWidth * this.zoom / this.currentScaleFactor / this._getPixelRatio(),
height: this.imageHeight * this.zoom / this.currentScaleFactor / this._getPixelRatio()
};
if (!compareSizes(newSize, this.size)) {
this.size = newSize;
}
}
_getAriaLabel() {
return formatUnicorn(getLocalization('Report Preview page {0} of {1}', 'ASPxReportsStringId.WebDocumentViewer_AriaLabelPreviewPage'), this.pageIndex + 1, this.reportPreview.pages.length);
}
constructor(reportPreview, pageIndex, processClick, subscribeToPageLoading = false) {
super();
this.reportPreview = reportPreview;
this.actualResolution = 0;
this.currentScaleFactor = 1;
this.imageHeight = 0;
this.imageWidth = 0;
this.imageSrcOptions = { rateLimit: { timeout: 100, method: 'notifyWhenChangesStop' } };
this.shouldSkipBrickLoading = false;
this.bricks = [];
this.clickableBricks = [];
this.maxZoom = 0;
this.disableResolutionReduction = false;
this.shouldSendRequest = true;
this._lastZoom = 0;
this._selectedBrickPath = null;
this._resizeTimeout = null;
this._onResize = () => {
imageSrcMutableOptions.rateLimit.timeout = 500;
this._resizeTimeout && clearTimeout(this._resizeTimeout);
this._resizeTimeout = setTimeout(() => {
imageSrcMutableOptions.rateLimit.timeout = 100;
}, 500);
};
this._editingFieldsSubscriptionDispose = null;
this.useSvg = this._shouldUseSvgEngine();
this.pageIndex = pageIndex;
this._onImageSrcChanged = () => {
this.lastGetPageDeferred && this.lastGetPageDeferred.resolve(null);
const currentGetPageDeferred = new DxDeferred();
this.lastGetPageDeferred = currentGetPageDeferred;
currentGetPageDeferred
.done((response) => this._onPageLoaded(response, processClick))
.fail((_e) => this._onPageLoadFailed());
this.shouldSendRequest && this._requestPage(reportPreview);
};
this.originalSize = { height: reportPreview._pageHeight, width: reportPreview._pageWidth };
this.addDisposable(reportPreview.events.on('originalZoomChanged', (args) => {
this.zoom = args.newValue;
}), reportPreview.events.on('previewSizeChanged', (args) => {
this.previewSize = args.newValue;
}), reportPreview.events.on('autoFitByChanged', (args) => {
this.autoFitBy = args.newValue;
}), reportPreview.events.on('pageLoadingChanged', (args) => {
if (subscribeToPageLoading) {
this.pageLoading = args.newValue;
}
}), reportPreview.events.on('pagesChanged', () => {
this.currentPageAriaLabelImgAlt = this._getAriaLabel();
}));
this.previewSize = reportPreview.previewSize;
this.autoFitBy = reportPreview.autoFitBy;
this.imageWidth = this.originalSize.width * this._getPixelRatio();
this.imageHeight = this.originalSize.height * this._getPixelRatio();
this.color = reportPreview._pageBackColor || '';
this.zoom = reportPreview.originalZoom;
this.isEmpty = pageIndex === -1 && !this.brick && !processClick;
this.currentPageAriaLabelImgAlt = this._getAriaLabel();
this._updatePageSize();
this.resetBrickRecusive = (brick) => {
if (brick && brick.active !== undefined) {
this.deactivateBrick(brick);
if (brick.bricks) {
brick.bricks.forEach((childBrick) => { this.resetBrickRecusive(childBrick); });
}
}
};
this.selectBrick = (path, ctrlKey) => {
if (PreviewSelection.started)
return;
processClick && processClick(null);
let currentBrick = this.brick;
!ctrlKey && this.resetBrickRecusive(currentBrick);
if (!path) {
return;
}
if (!currentBrick) {
this._selectedBrickPath = path;
return;
}
const pathElements = path.split(',');
pathElements.forEach((el) => {
currentBrick = currentBrick.bricks[parseInt(el)];
});
this.activateBrick(currentBrick);
};
this.editingFieldsKeyboardHelper = new PreviewEditingFieldsKeyboardHelper(this);
this._disposables.push(this.editingFieldsKeyboardHelper);
}
updateSize(zoom) {
const newResolution = getCurrentResolution(zoom);
return newResolution;
}
updateActiveBricks() {
this.activeBricks = this.bricks.filter(x => x.active);
}
getBricksTextContent(onlySelectedBricks = false) {
if (this.shouldSendRequest)
this._requestPage(this.reportPreview);
if (onlySelectedBricks) {
return this.reportPreview.getSelectedContent('');
}
else {
return this.reportPreview.getSelectedContent('', this.bricks);
}
}
activateBrick(brick) {
if (brick.active)
return;
brick.active = true;
this.updateActiveBricks();
}
deactivateBrick(brick) {
if (!brick.active)
return;
brick.active = false;
this.updateActiveBricks();
}
clearBricks() {
this.brickLoading = true;
}
dispose() {
super.dispose();
this._isDisposed = true;
this._editingFieldsSubscriptionDispose && this._editingFieldsSubscriptionDispose();
this.reportPreview = null;
this.lastGetPageDeferred?.reject();
}
_shouldUseSvgEngine(zoom) {
switch (PreviewRenderFormat()) {
case PageRenderFormat.Auto:
return this.reportPreview.showMultipagePreview ? zoom > 1 : true;
case PageRenderFormat.Png:
return false;
case PageRenderFormat.Svg:
return true;
}
}
_getImageOptions() {
return {
width: this.size.width,
height: this.size.height,
svgMarkup: this.svgMarkup,
displayImageSrc: this.displayImageSrc,
useSvg: this.useSvg,
color: this.color,
currentPageAriaLabelImgAlt: this.currentPageAriaLabelImgAlt,
pageLoaded: !!(this.displayImageSrc || this.svgMarkup)
};
}
_setPageImgSrc(documentId, unifier, zoom, shouldSkipBricks, forcePng) {
if (!documentId || this.pageIndex === -1) {
return;
}
if (this.maxZoom && this.maxZoom < zoom) {
zoom = this.maxZoom;
}
if (this._lastZoom < zoom) {
this._lastZoom = zoom;
}
else {
if (this.actualResolution && this.disableResolutionReduction && this.imageSrc)
return;
}
const newResolution = this.updateSize(zoom);
const useSvg = !forcePng && this._shouldUseSvgEngine(zoom);
if (useSvg) {
if (!this.useSvg && this.svgMarkup) {
this.useSvg = this._useSvg = true;
return;
}
else if (this.useSvg && this._unifier === unifier && this.imageSrc)
return;
}
else {
if ((this.actualResolution === newResolution || newResolution < 9) && this.imageSrc && !this.useSvg) {
this.useSvg = this._useSvg = false;
return;
}
}
this._useSvg = useSvg;
this.actualResolution = newResolution;
this._currentScaleFactor = zoom;
this.shouldSkipBrickLoading = shouldSkipBricks ?? false;
this._unifier = unifier;
this.imageSrc = HandlerUri() + '?' + toQueryParameters({
actionKey: 'getPage',
unifier,
arg: JSON.stringify(this._getCurrentPageRequest(documentId, shouldSkipBricks))
});
}
_requestPage(preview) {
if (this.isDisposing)
return;
this.brickLoading = true;
const documentId = this.reportPreview.documentId;
const currentGetPageDeferred = this.lastGetPageDeferred;
const ignoreError = preview._closeDocumentRequests && (() => preview._closeDocumentRequests[documentId] || currentGetPageDeferred.state() != 'pending');
PreviewRequestWrapper.getPage(this.imageSrc, ignoreError)
.then((response) => {
currentGetPageDeferred.resolve(response);
}).catch((_e) => {
currentGetPageDeferred.reject(_e);
});
}
_getCurrentPageRequest(documentId, shouldSkipBricks) {
return {
useSvgEngine: this._useSvg,
pageIndex: this.pageIndex,
documentId: documentId,
resolution: Math.floor(this.actualResolution * this._getPixelRatio()),
includeBricks: shouldSkipBricks ? false : this.brickLoading
};
}
_getPageSizeConfiguration() {
return {
width: this.originalSize.width,
height: this.originalSize.height,
autoFitBy: this.autoFitBy,
skipIfInvisible: false,
};
}
_clear() {
this.pageIndex = -1;
this.isClientVisible = false;
this._setPageImgSrc(null, null, 1);
this.actualResolution = 0;
}
initializeBrick(brick, processClick, editingFieldBricks) {
initializeBrick(brick, processClick, editingFieldBricks);
updateBricksPosition(brick, brick.height, brick.width);
this.brick = brick;
}
_clickToBrick(e) {
const target = $dx(e.currentTarget);
const offset = target.offset();
const xPerc = (e.clientX - offset.left + window.scrollX) / target.width() * 100;
const yPerc = (e.clientY - offset.top + window.scrollY) / target.height() * 100;
const bricks = this.bricks;
for (let i = 0; i < bricks.length; i++) {
if (parseFloat(bricks[i].topP) < yPerc && parseFloat(bricks[i].topP) + parseFloat(bricks[i].heightP) > yPerc
&& parseFloat(bricks[i].leftP) < xPerc && parseFloat(bricks[i].leftP) + parseFloat(bricks[i].widthP) > xPerc) {
bricks[i].onClick && bricks[i].onClick(e);
break;
}
}
}
getBricksFlatList(brick) {
if (brick) {
let bricks = [];
const innerBricksLength = brick.bricks && brick.bricks.length || 0;
for (let i = 0; i < innerBricksLength; i++) {
bricks = bricks.concat(this.getBricksFlatList(brick.bricks[i]));
}
bricks.push(brick);
return bricks;
}
return [];
}
}
__decorate([
mutable(() => [])
], PreviewPage.prototype, "editingFields", void 0);
__decorate([
mutable(false)
], PreviewPage.prototype, "isClientVisible", void 0);
__decorate([
mutable(1)
], PreviewPage.prototype, "zoom", void 0);
__decorate([
mutable(0)
], PreviewPage.prototype, "previewSize", void 0);
__decorate([
mutable(ZoomAutoBy.WholePage)
], PreviewPage.prototype, "autoFitBy", void 0);
__decorate([
mutable(() => { return { with: 0, height: 0 }; }, { deferred: true })
], PreviewPage.prototype, "size", void 0);
__decorate([
mutable(() => { return { with: 0, height: 0 }; })
], PreviewPage.prototype, "originalSize", void 0);
__decorate([
mutable(() => '', imageSrcMutableOptions)
], PreviewPage.prototype, "imageSrc", void 0);
__decorate([
mutable(true)
], PreviewPage.prototype, "pageLoading", void 0);
__decorate([
mutable(true)
], PreviewPage.prototype, "brickLoading", void 0);
__decorate([
mutable(() => '')
], PreviewPage.prototype, "displayImageSrc", void 0);
__decorate([
mutable(() => '')
], PreviewPage.prototype, "svgMarkup", void 0);
__decorate([
mutable(false)
], PreviewPage.prototype, "useSvg", void 0);
__decorate([
mutable(false)
], PreviewPage.prototype, "active", void 0);
__decorate([
mutable(null)
], PreviewPage.prototype, "brick", void 0);
__decorate([
mutable('')
], PreviewPage.prototype, "_unifier", void 0);
__decorate([
mutable('')
], PreviewPage.prototype, "currentPageAriaLabelImgAlt", void 0);
__decorate([
mutable({})
], PreviewPage.prototype, "smartTagAIMenu", void 0);
__decorate([
mutable({})
], PreviewPage.prototype, "smartTagAIMenuPosition", void 0);
__decorate([
mutableArray(() => [])
], PreviewPage.prototype, "activeBricks", void 0);