devexpress-reporting
Version:
DevExpress Reporting provides the capability to develop a reporting application to create and customize reports.
269 lines (268 loc) • 13.4 kB
JavaScript
/**
* DevExpress HTML/JS Reporting (designer\controls\utils\_bindings.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 * as ko from 'knockout';
import { XRCheckBoxSurface } from '../xrCheckbox';
import { controlsFactory } from '../../utils/settings';
import { ImageSource } from '../../../common/imageSource';
import { findSurface, extend, NotifyAboutWarning, formatUnicorn, getLocalization, base64DecodeUnicode } from '@devexpress/analytics-core/analytics-internal';
import { BandViewModel } from '../../bands/xrBand';
const svgAttrs = ko.bindingHandlers['svgAttrs'];
ko.bindingHandlers['svgAttrs'] = {
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
svgAttrs.update(element, valueAccessor, allBindingsAccessor, viewModel);
if (viewModel instanceof XRCheckBoxSurface) {
element.setAttribute('preserveAspectRatio', 'none');
}
}
};
const checkControlsUnderDropPoint = (event, domElement, controls) => {
let result = false;
const dropX = event.clientX;
const dropY = event.clientY;
const elementRect = domElement.getBoundingClientRect();
for (const control of controls) {
const x = elementRect.x + control.location.x();
const y = elementRect.y + control.location.y();
const width = control.size.width();
const height = control.size.height();
if (dropX >= x && dropX <= x + width && dropY >= y && dropY <= y + height) {
result = true;
}
}
return result;
};
const checkIfControlSupportFile = (controlType) => {
const notifyControlNotSupportFile = (control, fileTypes) => {
NotifyAboutWarning(formatUnicorn(getLocalization('{0} does not support this file type. You can upload files with the following types: {1}.', 'ASPxReportsStringId.ReportDesigner_DropFileWarning_ControlNotSupportFile'), control, fileTypes), true);
};
switch (controlType) {
case 'XRPictureBox':
{
notifyControlNotSupportFile(getLocalization('Picture Box', 'DevExpress.XtraReports.UI.XRPictureBox'), 'PNG, JPG, JPEG');
return true;
}
case 'XRPdfContent':
{
notifyControlNotSupportFile(getLocalization('PDF Content', 'DevExpress.XtraReports.UI.XRPdfContent'), 'PDF');
return true;
}
case 'XRRichText':
{
notifyControlNotSupportFile(getLocalization('Rich Text', 'DevExpress.XtraReports.UI.XRRichText'), 'DOCX, RTF, HTML, TXT');
return true;
}
case 'XRLabel':
{
notifyControlNotSupportFile(getLocalization('Label', 'DevExpress.XtraReports.UI.XRLabel'), 'TXT');
return true;
}
default:
return false;
}
};
const mapTypeToRichFormat = {
'application/msword': 'rtf',
'text/html': 'html',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
'text/plain': 'txt',
};
const createControl = (type) => {
const infoObject = extend({ '@ControlType': type }, controlsFactory().controlsMap[type].defaultVal);
return controlsFactory().createControl(infoObject, null);
};
const getDropTargetSurface = (control, bandToDrop) => {
const parent = control.getNearestParent(bandToDrop);
return findSurface(parent);
};
const dropedFileHandler = (files, dropTarget, dragDropHandler) => {
const isFit = dropTarget.root?.surface?.isFit;
const file = files[0];
const reader = new FileReader();
if (!dropTarget) {
return;
}
reader.onload = (loadEvent) => {
try {
const fileContent = loadEvent.target?.result;
const formatted = (fileContent).replace(/(^data:[^,]+,)|(^data:)/, '');
switch (true) {
case file.type.startsWith('image/'):
{
if (dropTarget.controlType !== 'XRPictureBox' && checkIfControlSupportFile(dropTarget.controlType)) {
break;
}
if (dropTarget.controlType === 'XRPictureBox') {
dropTarget.imageSource(new ImageSource('img', formatted));
break;
}
if (dropTarget instanceof BandViewModel) {
const pictureBox = createControl('XRPictureBox');
pictureBox.imageSource(new ImageSource('img', formatted));
const dropTargetSurface = getDropTargetSurface(pictureBox, dropTarget);
if (isFit && isFit(dropTargetSurface)) {
dragDropHandler.addControl(pictureBox, dropTargetSurface, pictureBox.size);
}
break;
}
break;
}
case file.type === 'application/pdf':
{
if (dropTarget.controlType !== 'XRPdfContent' && checkIfControlSupportFile(dropTarget.controlType)) {
break;
}
if (dropTarget.controlType === 'XRPdfContent') {
dropTarget.source(formatted);
break;
}
const pdfContent = createControl('XRPdfContent');
pdfContent.source(formatted);
if (dropTarget instanceof BandViewModel) {
if (dropTarget.controlType === 'TopMarginBand' || dropTarget.controlType === 'BottomMarginBand') {
const topMarginString = getLocalization('Top Margin', 'DevExpress.XtraReports.UI.TopMarginBand');
const bottomMarginString = getLocalization('Bottom Margin', 'DevExpress.XtraReports.UI.BottomMarginBand');
const pdfContentString = getLocalization('PDF Content', 'DevExpress.XtraReports.UI.XRPdfContent');
const localizedFormatedMessage = formatUnicorn(getLocalization('{0} control could not be created in the following bands: {1}.', 'ASPxReportsStringId.ReportDesigner_DropFileWarning_BandNotSupportControl'), pdfContentString, `${topMarginString}, ${bottomMarginString}`);
NotifyAboutWarning(localizedFormatedMessage, true);
break;
}
const dropTargetSurface = getDropTargetSurface(pdfContent, dropTarget);
if (isFit && isFit(dropTargetSurface)) {
dragDropHandler.addControl(pdfContent, dropTargetSurface, pdfContent.size);
}
break;
}
break;
}
case !!mapTypeToRichFormat[file.type]:
{
if (dropTarget.controlType === 'XRLabel' && file.type === 'text/plain') {
const content = base64DecodeUnicode(formatted);
dropTarget.text(content);
break;
}
if (dropTarget.controlType !== 'XRRichText' && checkIfControlSupportFile(dropTarget.controlType)) {
break;
}
const format = mapTypeToRichFormat[file.type];
if (dropTarget.controlType === 'XRRichText') {
dropTarget._newDocumentData({ format, content: formatted, contentType: 'base64' });
break;
}
const richTextContentRtf = createControl('XRRichText');
richTextContentRtf._newDocumentData({ format, content: formatted, contentType: 'base64' });
if (dropTarget instanceof BandViewModel && file.type !== 'text/plain') {
const dropTargetSurface = getDropTargetSurface(richTextContentRtf, dropTarget);
if (isFit && isFit(dropTargetSurface)) {
dragDropHandler.addControl(richTextContentRtf, dropTargetSurface, richTextContentRtf.size);
}
break;
}
}
case file.type === 'text/plain':
{
if (dropTarget.controlType !== 'XRLabel' && checkIfControlSupportFile(dropTarget.controlType)) {
break;
}
const textControl = createControl('XRLabel');
const content = base64DecodeUnicode(formatted);
textControl.text(content);
if (dropTarget instanceof BandViewModel) {
const dropTargetSurface = getDropTargetSurface(textControl, dropTarget);
if (isFit && isFit(dropTargetSurface)) {
dragDropHandler.addControl(textControl, dropTargetSurface, textControl.size);
}
break;
}
break;
}
default:
NotifyAboutWarning(formatUnicorn(getLocalization('File type not supported. You can upload files in the following formats: {0}.', 'ASPxReportsStringId.ReportDesigner_DropFileWarning_WrongFormat'), 'PNG, JPG, JPEG, PDF, TXT, DOCX, RTF, HTML'), true);
break;
}
}
catch (error) {
console.error(error);
}
};
reader.readAsDataURL(file);
};
ko.bindingHandlers['dragDropFileToControl'] = {
init: (element, valueAccessor, allBindings, viewModel, bindingContext) => {
const { dragDropFileEnabled } = valueAccessor();
if (!ko.unwrap(dragDropFileEnabled)) {
return;
}
let counter = 0;
element.addEventListener('dragenter', event => {
event.stopPropagation();
counter++;
viewModel.showDropBorders && viewModel.showDropBorders(true);
});
element.addEventListener('dragleave', event => {
event.stopPropagation();
counter--;
if (counter === 0) {
viewModel.showDropBorders && viewModel.showDropBorders(false);
}
});
element.addEventListener('dragover', event => {
event.preventDefault();
});
element.addEventListener('drop', event => {
event.preventDefault();
event.stopPropagation();
viewModel.showDropBorders && viewModel.showDropBorders(false);
counter = 0;
const { dragDropHandler } = valueAccessor();
const files = event.dataTransfer.files;
const dropTarget = viewModel.getControlModel && viewModel.getControlModel();
if (dropTarget instanceof BandViewModel) {
if (checkControlsUnderDropPoint(event, element, dropTarget.controls())) {
NotifyAboutWarning(getLocalization('This control does not support file uploads.', 'ASPxReportsStringId.ReportDesigner_DropFileWarning_ControlNotSupportUpload'), true);
return;
}
}
dragDropHandler.snapToGridOnCreateControl = dragDropHandler.snapHelper.getSnappingMode() === 'SnapToGrid' && event.altKey !== true;
files.length > 0 && dropedFileHandler(files, dropTarget, dragDropHandler);
});
},
};
ko.bindingHandlers['dragDropJsonToDataSource'] = {
init: (element, valueAccessor, allBindings, viewModel, bindingContext) => {
const jsonStringEditor = viewModel;
element.addEventListener('dragenter', event => {
event.stopPropagation();
viewModel.showDropBorders && viewModel.showDropBorders(true);
});
element.addEventListener('dragleave', event => {
event.stopPropagation();
viewModel.showDropBorders && viewModel.showDropBorders(false);
});
element.addEventListener('dragover', event => {
event.preventDefault();
});
element.addEventListener('drop', event => {
event.preventDefault();
const files = event.dataTransfer.files;
if (files.length > 0) {
const file = files[0];
const format = file.name.split('.').pop();
if (format !== 'json') {
return;
}
const reader = new FileReader();
reader.onload = (e) => {
const fileContent = e.target?.result;
jsonStringEditor.value(fileContent);
};
reader.readAsText(file);
}
});
}
};