UNPKG

reportbro-designer

Version:

Designer to create pdf and excel report layouts. The reports can be generated with reportbro-lib (a Python package) on the server.

445 lines (410 loc) 15.7 kB
import DocElement from './DocElement'; import SectionBandElement from './SectionBandElement'; import Band from '../container/Band'; import MainPanelItem from '../menu/MainPanelItem'; import * as utils from '../utils'; /** * Section element. Sections can be added to the content band and contain a content band and optional * header/footer bands. * @class */ export default class SectionElement extends DocElement { constructor(id, initialData, rb) { super(rb.getLabel('docElementSection'), id, -1, 60, rb); this.setupComplete = false; this.elDividerHeader = null; this.elDividerFooter = null; this.elDividerBottom = null; this.dataSource = ''; this.label = ''; this.header = false; this.footer = false; this.headerData = null; this.contentData = null; this.footerData = null; this.setInitialData(initialData); } setup(openPanelItem) { super.setup(openPanelItem); this.createElement(); this.updateDisplay(); this.headerData = this.createBand(Band.bandType.header, null); this.contentData = this.createBand(Band.bandType.content, null); this.footerData = this.createBand(Band.bandType.footer, null); this.updateHeight(null, -1); this.setWidth(this.getContainerContentSize().width); this.setupComplete = true; this.updateName(); if (openPanelItem) { this.panelItem.open(); } } createBand(bandType, dataValues) { let data; let dataKey = bandType + 'Data'; let dataId; let panelItemProperties = { hasChildren: true, showDelete: false }; if (dataValues) { data = dataValues; } else if (this[dataKey]) { data = this[dataKey]; dataId = data.id; } else { data = {}; } data.parentId = this.id; data.containerId = this.containerId; if (!dataId) { dataId = this.rb.getUniqueId(); } let y = 0; if (bandType === Band.bandType.header) { data.y = '' + y; } else if (bandType === Band.bandType.content) { if (this.header && this.headerData !== null) { y += this.headerData.getValue('heightVal'); } data.y = '' + y; } else if (bandType === Band.bandType.footer) { if (this.header && this.headerData !== null) { y += this.headerData.getValue('heightVal'); } if (this.contentData !== null) { y += this.contentData.getValue('heightVal'); } data.y = '' + y; } if ((bandType === Band.bandType.header && !this.header) || (bandType === Band.bandType.footer && !this.footer)) { panelItemProperties.visible = false; } let bandElement = new SectionBandElement(dataId, data, bandType, this.rb); this.rb.addDataObject(bandElement); let panelItemBand = new MainPanelItem( 'sectionBand', this.panelItem, bandElement, panelItemProperties, this.rb); bandElement.setPanelItem(panelItemBand); this.panelItem.appendChild(panelItemBand); bandElement.setup(); if (bandType === Band.bandType.header) { bandElement.show(this.header); } else if (bandType === Band.bandType.footer) { bandElement.show(this.footer); } return bandElement; } /** * Register event handler for a container element so it can be dragged and * allow selection on double click. */ registerEventHandlers() { super.registerContainerEventHandlers(); } /** * Returns highest id of this component, this is the max id of the footer band because it is created last. * @returns {Number} */ getMaxId() { let id = this.id; if (this.footerData !== null) { id = this.footerData.getMaxId(); } return id; } appendContainerChildren(elements) { if (this.headerData !== null) { this.headerData.appendContainerChildren(elements); } if (this.contentData !== null) { this.contentData.appendContainerChildren(elements); } if (this.footerData !== null) { this.footerData.appendContainerChildren(elements); } } setValue(field, value) { super.setValue(field, value); if (field === 'label' || field === 'dataSource') { this.updateName(); } else if (field === 'header') { this.headerData.show(value); if (value) { this.headerData.getPanelItem().show(); } else { this.headerData.getPanelItem().hide(); } } else if (field === 'footer') { this.footerData.show(value); if (value) { this.footerData.getPanelItem().show(); } else { this.footerData.getPanelItem().hide(); } } else if (field === 'containerId') { this.headerData.containerId = value; this.contentData.containerId = value; this.footerData.containerId = value; } if (field === 'header' || field === 'footer') { this.updateBands(null); } } updateDisplayInternal(x, y, width, height) { if (this.el !== null) { this.el.style.top = this.rb.toPixel(y); this.el.style.width = '100%'; this.el.style.height = this.rb.toPixel(height); } } /** * Returns all fields of this object that can be modified in the properties panel. * @returns {String[]} */ getProperties() { return ['y', 'label', 'dataSource', 'header', 'footer', 'printIf']; } getElementType() { return DocElement.type.section; } select() { super.select(); let elSizerContainer = this.getSizerContainerElement(); // create sizers (to indicate selection) which do not support resizing for (let sizer of ['N', 'S']) { elSizerContainer.append( utils.createElement('div', { class: `rbroSizer rbroSizer${sizer} rbroSizerMove` })); } if (this.headerData !== null) { document.getElementById(`rbro_el${this.headerData.getId()}`).classList.add('rbroHighlightBandDescription'); } if (this.contentData !== null) { document.getElementById(`rbro_el${this.contentData.getId()}`).classList.add('rbroHighlightBandDescription'); } if (this.footerData !== null) { document.getElementById(`rbro_el${this.footerData.getId()}`).classList.add('rbroHighlightBandDescription'); } } deselect() { super.deselect(); const elBandDescriptions = this.el.querySelectorAll('.rbroSectionBandElement'); for (const elBandDescription of elBandDescriptions) { elBandDescription.classList.remove('rbroHighlightBandDescription'); } } /** * Returns allowed sizers when element is selected. * @returns {String[]} */ getSizers() { return []; } isAreaSelectionAllowed() { return false; } isDroppingAllowed() { return false; } createElement() { this.el = utils.createElement('div', { id: `rbro_el${this.id}`, class: 'rbroDocElement rbroSectionElement' }); this.el.append( utils.createElement('div', { id: `rbro_divider_section_top${this.id}`, class: 'rbroDivider rbroDividerSection', style: 'top: 0px' }) ); this.elDividerHeader = utils.createElement( 'div', { id: `rbro_divider_section_header${this.id}`, class: 'rbroDivider rbroDividerSectionBand rbroHidden' }); this.el.append(this.elDividerHeader); this.elDividerFooter = utils.createElement( 'div', { id: `rbro_divider_section_footer${this.id}`, class: 'rbroDivider rbroDividerSectionBand rbroHidden' }); this.el.append(this.elDividerFooter); this.elDividerBottom = utils.createElement( 'div', { id: `rbro_divider_section_bottom${this.id}`, class: 'rbroDivider rbroDividerSection' }); this.el.append(this.elDividerBottom); this.appendToContainer(); this.registerEventHandlers(); } remove() { super.remove(); // delete containers of section bands if (this.headerData !== null) { this.rb.deleteContainer(this.headerData.getLinkedContainer()); } if (this.contentData !== null) { this.rb.deleteContainer(this.contentData.getLinkedContainer()); } if (this.footerData !== null) { this.rb.deleteContainer(this.footerData.getLinkedContainer()); } } updateName() { if (this.label.trim() !== '') { this.name = this.label; } else { this.name = this.rb.getLabel('docElementSection'); if (this.dataSource.trim() !== '') { this.name += ' ' + this.dataSource; } } if (this.headerData !== null) { document.getElementById(`rbro_el_band_description${this.headerData.getId()}`).textContent = this.name + ' ' + this.headerData.getName(); } if (this.contentData !== null) { document.getElementById(`rbro_el_band_description${this.contentData.getId()}`).textContent = this.name + ' ' + this.contentData.getName(); } if (this.footerData !== null) { document.getElementById(`rbro_el_band_description${this.footerData.getId()}`).textContent = this.name + ' ' + this.footerData.getName(); } document.getElementById(`rbro_menu_item_name${this.id}`).textContent = this.name; } /** * Set internal width and width of all bands. Should be called whenever the document size changes. * @param {Number} width - total band width. */ setWidth(width) { this.widthVal = width; this.width = '' + width; if (this.headerData !== null) { this.headerData.widthVal = width; this.headerData.width = '' + width; } if (this.contentData !== null) { this.contentData.widthVal = width; this.contentData.width = '' + width; } if (this.footerData !== null) { this.footerData.widthVal = width; this.footerData.width = '' + width; } } /** * Update section element height and position, visibility of dividers for header/footer bands. * @param {SectionBandElement} band - if not null the bandHeight parameter will be used for band height * instead of the actual stored height value. This is needed to update the divider display during drag * of section band height. * @param {Number} bandHeight - used band height for given band parameter instead of stored height value. */ updateHeight(band, bandHeight) { let height = 0; if (this.header && this.headerData !== null) { if (band === this.headerData) { height += bandHeight; } else { height += this.headerData.getValue('heightVal'); } this.elDividerHeader.style.top = this.rb.toPixel(height); this.elDividerHeader.classList.remove('rbroHidden'); } else { this.elDividerHeader.classList.add('rbroHidden'); } if (this.contentData !== null) { if (band === this.contentData) { height += bandHeight; } else { height += this.contentData.getValue('heightVal'); } } if (this.footer && this.footerData !== null) { this.elDividerFooter.style.top = this.rb.toPixel(height); this.elDividerFooter.classList.remove('rbroHidden'); if (band === this.footerData) { height += bandHeight; } else { height += this.footerData.getValue('heightVal'); } } else { document.getElementById(`rbro_divider_section_footer${this.id}`).classList.add('rbroHidden'); } this.elDividerBottom.style.top = this.rb.toPixel(height); this.height = '' + height; this.heightVal = height; this.updateDisplay(); } /** * Update height and y-coordinate of all sub-bands (header, content, footer). */ updateBands(ignoreBandData) { if (this.setupComplete) { let y = 0; if (this.header) { if (this.headerData !== ignoreBandData) { this.headerData.setValue('y', '' + y); } y += this.headerData.getValue('heightVal'); } if (this.contentData !== ignoreBandData) { this.contentData.setValue('y', '' + y); } y += this.contentData.getValue('heightVal'); if (this.footer && this.footerData !== ignoreBandData) { this.footerData.setValue('y', '' + y); } } this.updateHeight(null, -1); } /** * Get linked containers of all bands. * @returns {Container[]} array with all linked containers of header/content/footer section bands. */ getLinkedContainers() { let containers = []; let container; for (let band of ['headerData', 'contentData', 'footerData']) { if (this[band] !== null) { container = this[band].getLinkedContainer(); if (container !== null) { containers.push(container); } } } return containers; } hasDataSource() { return true; } addChildren(docElements) { docElements.push(this.headerData); docElements.push(this.contentData); docElements.push(this.footerData); // children of section bands will be added through linked containers of section } /** * Adds SetValue commands to command group parameter in case the specified parameter is used in any of * the object fields. * @param {Parameter} parameter - parameter which will be renamed. * @param {String} newParameterName - new name of the parameter. * @param {CommandGroupCmd} cmdGroup - possible SetValue commands will be added to this command group. */ addCommandsForChangedParameterName(parameter, newParameterName, cmdGroup) { this.addCommandForChangedParameterName(parameter, newParameterName, 'dataSource', cmdGroup); this.addCommandForChangedParameterName(parameter, newParameterName, 'printIf', cmdGroup); } toJS() { const rv = super.toJS(); rv['headerData'] = this.headerData.toJS(); rv['contentData'] = this.contentData.toJS(); rv['footerData'] = this.footerData.toJS(); return rv; } /** * Returns class name. * This can be useful for introspection when the class names are mangled * due to the webpack uglification process. * @returns {string} */ getClassName() { return 'SectionElement'; } }