Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7a76c7db9 | ||
|
|
16c380e1c6 | ||
|
|
072a3b80c4 | ||
|
|
5572b7ce67 | ||
|
|
71cf92c217 | ||
|
|
20282b0b99 | ||
|
|
d14f5951ac | ||
|
|
729a31920d |
@@ -1,7 +1,6 @@
|
||||
import qlik from 'qlik';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ApplyPreMask } from '../masking';
|
||||
import { addSeparators } from '../utilities';
|
||||
import Tooltip from '../tooltip/index.jsx';
|
||||
|
||||
class DataCell extends React.PureComponent {
|
||||
@@ -11,22 +10,38 @@ class DataCell extends React.PureComponent {
|
||||
}
|
||||
|
||||
handleSelect () {
|
||||
const { data: { meta: { dimensionCount } }, general: { allowFilteringByClick }, measurement, qlik } = this.props;
|
||||
const {
|
||||
data: {
|
||||
headers,
|
||||
meta: {
|
||||
dimensionCount,
|
||||
altState
|
||||
}
|
||||
},
|
||||
general: {
|
||||
allowFilteringByClick
|
||||
},
|
||||
measurement,
|
||||
component
|
||||
} = this.props;
|
||||
|
||||
const hasSecondDimension = dimensionCount > 1;
|
||||
if (!allowFilteringByClick) {
|
||||
return;
|
||||
}
|
||||
|
||||
qlik.backendApi.selectValues(0, [measurement.parents.dimension1.elementNumber], true);
|
||||
const app = qlik.currApp(component);
|
||||
app.field(headers.dimension1[0].name, altState)
|
||||
.select([measurement.parents.dimension1.elementNumber], false, false);
|
||||
|
||||
if (hasSecondDimension) {
|
||||
qlik.backendApi.selectValues(1, [measurement.parents.dimension2.elementNumber], true);
|
||||
app.field(headers.dimension2[0].name, altState)
|
||||
.select([measurement.parents.dimension2.elementNumber], false, false);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
data,
|
||||
general,
|
||||
measurement,
|
||||
styleBuilder,
|
||||
@@ -39,11 +54,12 @@ class DataCell extends React.PureComponent {
|
||||
fontFamily: styling.options.fontFamily,
|
||||
...styleBuilder.getStyle(),
|
||||
paddingLeft: '5px',
|
||||
textAlign: textAlignment
|
||||
textAlign: textAlignment,
|
||||
minWidth: general.cellWidth,
|
||||
maxWidth: general.cellWidth
|
||||
};
|
||||
|
||||
const isEmptyCell = measurement.displayValue === '';
|
||||
const isColumnPercentageBased = (/%/).test(measurement.format);
|
||||
let formattedMeasurementValue;
|
||||
if (isEmptyCell) {
|
||||
formattedMeasurementValue = '';
|
||||
@@ -70,16 +86,9 @@ class DataCell extends React.PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
let cellClass = 'grid-cells';
|
||||
const hasTwoDimensions = data.headers.dimension2 && data.headers.dimension2.length > 0;
|
||||
const shouldUseSmallCells = isColumnPercentageBased && data.headers.measurements.length > 1 && hasTwoDimensions;
|
||||
if (shouldUseSmallCells) {
|
||||
cellClass = 'grid-cells-small';
|
||||
}
|
||||
|
||||
return (
|
||||
<td
|
||||
className={`${cellClass}${general.cellSuffix}`}
|
||||
className="grid-cells"
|
||||
onClick={isEmptyCell ? null : this.handleSelect}
|
||||
style={cellStyle}
|
||||
>
|
||||
@@ -97,27 +106,23 @@ class DataCell extends React.PureComponent {
|
||||
DataCell.propTypes = {
|
||||
data: PropTypes.shape({
|
||||
headers: PropTypes.shape({
|
||||
dimension1: PropTypes.array.isRequired,
|
||||
measurements: PropTypes.array.isRequired
|
||||
}).isRequired,
|
||||
meta: PropTypes.shape({
|
||||
altState: PropTypes.string.isRequired,
|
||||
dimensionCount: PropTypes.number.isRequired
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
general: PropTypes.shape({
|
||||
cellSuffix: PropTypes.string.isRequired
|
||||
cellWidth: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
measurement: PropTypes.shape({
|
||||
format: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
value: PropTypes.any
|
||||
}).isRequired,
|
||||
qlik: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: function (props, propName) {
|
||||
if (props.isSnapshot || typeof props[propName] === 'function') {
|
||||
return null;
|
||||
}
|
||||
return new Error('Missing implementation of qlik.backendApi.selectValues.');
|
||||
}
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
component: PropTypes.shape({}).isRequired,
|
||||
styleBuilder: PropTypes.shape({
|
||||
hasComments: PropTypes.func.isRequired
|
||||
}).isRequired,
|
||||
@@ -129,51 +134,11 @@ DataCell.propTypes = {
|
||||
export default DataCell;
|
||||
|
||||
function formatMeasurementValue (measurement, styling) {
|
||||
const isColumnPercentageBased = (/%/).test(measurement.format);
|
||||
let formattedMeasurementValue = '';
|
||||
if (isColumnPercentageBased) {
|
||||
if (isNaN(measurement.value)) {
|
||||
formattedMeasurementValue = styling.symbolForNulls;
|
||||
} else {
|
||||
formattedMeasurementValue = ApplyPreMask('0,00%', measurement.value);
|
||||
}
|
||||
} else {
|
||||
let magnitudeDivider;
|
||||
switch (measurement.magnitude.toLowerCase()) {
|
||||
case 'k':
|
||||
magnitudeDivider = 1000;
|
||||
break;
|
||||
case 'm':
|
||||
magnitudeDivider = 1000000;
|
||||
break;
|
||||
default:
|
||||
magnitudeDivider = 1;
|
||||
}
|
||||
const formattingStringWithoutMagnitude = measurement.format.replace(/k|K|m|M/gi, '');
|
||||
if (isNaN(measurement.value)) {
|
||||
formattedMeasurementValue = styling.symbolForNulls;
|
||||
} else {
|
||||
let preFormatValue = measurement.value;
|
||||
if (isColumnPercentageBased) {
|
||||
preFormatValue *= 100;
|
||||
}
|
||||
switch (formattingStringWithoutMagnitude) {
|
||||
case '#.##0':
|
||||
formattedMeasurementValue = addSeparators((preFormatValue / magnitudeDivider), '.', ',', 0);
|
||||
break;
|
||||
case '#,##0':
|
||||
formattedMeasurementValue = addSeparators((preFormatValue / magnitudeDivider), ',', '.', 0);
|
||||
break;
|
||||
default:
|
||||
formattedMeasurementValue = ApplyPreMask(
|
||||
formattingStringWithoutMagnitude,
|
||||
(preFormatValue / magnitudeDivider)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isNaN(measurement.value)) {
|
||||
return styling.symbolForNulls;
|
||||
}
|
||||
return formattedMeasurementValue;
|
||||
|
||||
return measurement.displayValue;
|
||||
}
|
||||
|
||||
function getConditionalColor (measurement, conditionalColoring) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import DataCell from './data-cell.jsx';
|
||||
import RowHeader from './row-header.jsx';
|
||||
import { injectSeparators } from '../utilities';
|
||||
|
||||
const DataTable = ({ data, general, qlik, renderData, styling }) => {
|
||||
const DataTable = ({ data, general, component, renderData, styling }) => {
|
||||
const {
|
||||
headers: {
|
||||
dimension1,
|
||||
@@ -42,8 +42,9 @@ const DataTable = ({ data, general, qlik, renderData, styling }) => {
|
||||
<tr key={dimensionEntry.displayValue}>
|
||||
{!renderData ?
|
||||
<RowHeader
|
||||
altState={data.meta.altState}
|
||||
entry={dimensionEntry}
|
||||
qlik={qlik}
|
||||
component={component}
|
||||
rowStyle={rowStyle}
|
||||
styleBuilder={styleBuilder}
|
||||
styling={styling}
|
||||
@@ -80,7 +81,7 @@ const DataTable = ({ data, general, qlik, renderData, styling }) => {
|
||||
general={general}
|
||||
key={`${dimensionEntry.displayValue}-${id}`}
|
||||
measurement={measurementData}
|
||||
qlik={qlik}
|
||||
component={component}
|
||||
styleBuilder={styleBuilder}
|
||||
styling={styling}
|
||||
/>
|
||||
@@ -107,7 +108,7 @@ DataTable.propTypes = {
|
||||
matrix: PropTypes.arrayOf(PropTypes.array.isRequired).isRequired
|
||||
}).isRequired,
|
||||
general: PropTypes.shape({}).isRequired,
|
||||
qlik: PropTypes.shape({}).isRequired,
|
||||
component: PropTypes.shape({}).isRequired,
|
||||
renderData: PropTypes.bool,
|
||||
styling: PropTypes.shape({
|
||||
hasCustomFileStyle: PropTypes.bool.isRequired
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import qlik from 'qlik';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import HeaderPadding from './header-padding.jsx';
|
||||
@@ -11,13 +12,14 @@ class RowHeader extends React.PureComponent {
|
||||
}
|
||||
|
||||
handleSelect () {
|
||||
const { entry, qlik } = this.props;
|
||||
qlik.backendApi.selectValues(0, [entry.elementNumber], true);
|
||||
const { entry, altState, component } = this.props;
|
||||
const app = qlik.currApp(component);
|
||||
app.field(entry.name, altState).select([entry.elementNumber], false, false);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { entry, rowStyle, styleBuilder, styling, qlik } = this.props;
|
||||
const inEditState = qlik.inEditState();
|
||||
const { entry, rowStyle, styleBuilder, styling, component } = this.props;
|
||||
const inEditState = component.inEditState();
|
||||
|
||||
return (
|
||||
<td
|
||||
@@ -43,18 +45,12 @@ class RowHeader extends React.PureComponent {
|
||||
|
||||
RowHeader.propTypes = {
|
||||
entry: PropTypes.shape({
|
||||
displayValue: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
qlik: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: function (props, propName) {
|
||||
if (props.isSnapshot || typeof props[propName] === 'function') {
|
||||
return null;
|
||||
}
|
||||
return new Error('Missing implementation of qlik.backendApi.selectValues.');
|
||||
}
|
||||
}).isRequired
|
||||
displayValue: PropTypes.string.isRequired,
|
||||
elementNumber: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
altState: PropTypes.string.isRequired,
|
||||
component: PropTypes.shape({}).isRequired,
|
||||
rowStyle: PropTypes.shape({}).isRequired,
|
||||
styleBuilder: PropTypes.shape({}).isRequired,
|
||||
styling: PropTypes.shape({}).isRequired
|
||||
|
||||
@@ -22,7 +22,9 @@ async function buildDataCube (originCubeDefinition, hasTwoDimensions, app) {
|
||||
cubeDefinition.qDimensions.push(originCubeDefinition.qDimensions[1]);
|
||||
}
|
||||
const cube = await createCube(cubeDefinition, app);
|
||||
return cube.qHyperCube.qDataPages[0].qMatrix;
|
||||
const cubeMatrix = cube.qHyperCube.qDataPages[0].qMatrix;
|
||||
app.destroySessionObject(cube.qInfo.qId);
|
||||
return cubeMatrix;
|
||||
}
|
||||
|
||||
export async function initializeDataCube (component, layout) {
|
||||
@@ -37,6 +39,7 @@ export async function initializeDataCube (component, layout) {
|
||||
const hyperCubeDef = properties.qExtendsId
|
||||
? (await app.getObjectProperties(properties.qExtendsId)).properties.qHyperCubeDef
|
||||
: properties.qHyperCubeDef;
|
||||
hyperCubeDef.qStateName = layout.qStateName || "";
|
||||
|
||||
return buildDataCube(hyperCubeDef, layout.qHyperCube.qDimensionInfo.length === 2, app);
|
||||
}
|
||||
|
||||
@@ -214,10 +214,10 @@ const tableFormat = {
|
||||
component: 'slider',
|
||||
label: 'Column width',
|
||||
ref: 'columnwidthslider',
|
||||
min: 1,
|
||||
max: 3,
|
||||
step: 1,
|
||||
defaultValue: 2
|
||||
min: 20,
|
||||
max: 250,
|
||||
step: 10,
|
||||
defaultValue: 50
|
||||
},
|
||||
SymbolForNulls: {
|
||||
ref: 'symbolfornulls',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import qlik from 'qlik';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { HEADER_FONT_SIZE } from '../initialize-transformed';
|
||||
@@ -10,25 +11,28 @@ class ColumnHeader extends React.PureComponent {
|
||||
}
|
||||
|
||||
handleSelect () {
|
||||
const { entry, qlik } = this.props;
|
||||
qlik.backendApi.selectValues(1, [entry.elementNumber], true);
|
||||
const { entry, altState, component } = this.props;
|
||||
const app = qlik.currApp(component);
|
||||
app.field(entry.name, altState).select([entry.elementNumber], false, false);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { baseCSS, cellSuffix, colSpan, entry, styling, qlik } = this.props;
|
||||
const inEditState = qlik.inEditState();
|
||||
const { baseCSS, cellWidth, colSpan, entry, styling, component } = this.props;
|
||||
const inEditState = component.inEditState();
|
||||
const isMediumFontSize = styling.headerOptions.fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
|
||||
|
||||
const style = {
|
||||
...baseCSS,
|
||||
fontSize: `${14 + styling.headerOptions.fontSizeAdjustment}px`,
|
||||
height: isMediumFontSize ? '43px' : '33px',
|
||||
verticalAlign: 'middle'
|
||||
verticalAlign: 'middle',
|
||||
minWidth: cellWidth,
|
||||
maxWidth: cellWidth
|
||||
};
|
||||
|
||||
return (
|
||||
<th
|
||||
className={`grid-cells2${cellSuffix}`}
|
||||
className="grid-cells"
|
||||
colSpan={colSpan}
|
||||
onClick={this.handleSelect}
|
||||
style={style}
|
||||
@@ -46,28 +50,20 @@ class ColumnHeader extends React.PureComponent {
|
||||
}
|
||||
|
||||
ColumnHeader.defaultProps = {
|
||||
cellSuffix: '',
|
||||
colSpan: 1
|
||||
};
|
||||
|
||||
ColumnHeader.propTypes = {
|
||||
baseCSS: PropTypes.shape({}).isRequired,
|
||||
cellSuffix: PropTypes.string,
|
||||
cellWidth: PropTypes.string,
|
||||
colSpan: PropTypes.number,
|
||||
entry: PropTypes.shape({
|
||||
displayValue: PropTypes.string.isRequired,
|
||||
elementNumber: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
qlik: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: function (props, propName) {
|
||||
if (props.isSnapshot || typeof props[propName] === 'function') {
|
||||
return null;
|
||||
}
|
||||
return new Error('Missing implementation of qlik.backendApi.selectValues.');
|
||||
}
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
altState: PropTypes.string.isRequired,
|
||||
component: PropTypes.shape({}).isRequired,
|
||||
styling: PropTypes.shape({
|
||||
headerOptions: PropTypes.shape({
|
||||
fontSizeAdjustment: PropTypes.number.isRequired
|
||||
|
||||
@@ -5,7 +5,7 @@ import ColumnHeader from './column-header.jsx';
|
||||
import MeasurementColumnHeader from './measurement-column-header.jsx';
|
||||
import { injectSeparators } from '../utilities';
|
||||
|
||||
const HeadersTable = ({ data, general, qlik, styling, isKpi }) => {
|
||||
const HeadersTable = ({ data, general, component, styling, isKpi }) => {
|
||||
const baseCSS = {
|
||||
backgroundColor: styling.headerOptions.colorSchema,
|
||||
color: styling.headerOptions.textColor,
|
||||
@@ -28,7 +28,7 @@ const HeadersTable = ({ data, general, qlik, styling, isKpi }) => {
|
||||
<tr>
|
||||
{isKpi ?
|
||||
<ExportColumnHeader
|
||||
id={qlik.options.id}
|
||||
id={component.$scope.layout.qInfo.qId}
|
||||
allowExcelExport={general.allowExcelExport}
|
||||
baseCSS={baseCSS}
|
||||
general={general}
|
||||
@@ -67,12 +67,13 @@ const HeadersTable = ({ data, general, qlik, styling, isKpi }) => {
|
||||
}
|
||||
return (
|
||||
<ColumnHeader
|
||||
altState={data.meta.altState}
|
||||
baseCSS={baseCSS}
|
||||
cellSuffix={general.cellSuffix}
|
||||
cellWidth={general.cellWidth}
|
||||
colSpan={measurements.length}
|
||||
entry={entry}
|
||||
key={entry.displayValue}
|
||||
qlik={qlik}
|
||||
component={component}
|
||||
styling={styling}
|
||||
/>
|
||||
);
|
||||
@@ -124,19 +125,13 @@ HeadersTable.propTypes = {
|
||||
dimension1: PropTypes.array,
|
||||
dimension2: PropTypes.array,
|
||||
measurements: PropTypes.array
|
||||
}),
|
||||
meta: PropTypes.shape({
|
||||
altState: PropTypes.string.isRequired
|
||||
})
|
||||
}).isRequired,
|
||||
general: PropTypes.shape({}).isRequired,
|
||||
qlik: PropTypes.shape({
|
||||
backendApi: PropTypes.shape({
|
||||
selectValues: function (props, propName) {
|
||||
if (props.isSnapshot || typeof props[propName] === 'function') {
|
||||
return null;
|
||||
}
|
||||
return new Error('Missing implementation of qlik.backendApi.selectValues.');
|
||||
}
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
component: PropTypes.shape({}).isRequired,
|
||||
styling: PropTypes.shape({
|
||||
headerOptions: PropTypes.shape({}),
|
||||
options: PropTypes.shape({})
|
||||
|
||||
@@ -4,27 +4,27 @@ import { HEADER_FONT_SIZE } from '../initialize-transformed';
|
||||
import Tooltip from '../tooltip/index.jsx';
|
||||
|
||||
const MeasurementColumnHeader = ({ baseCSS, general, hasSecondDimension, measurement, styling }) => {
|
||||
const title = `${measurement.name} ${measurement.magnitudeLabelSuffix}`;
|
||||
const title = `${measurement.name}`;
|
||||
const { fontSizeAdjustment } = styling.headerOptions;
|
||||
const isMediumFontSize = fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
|
||||
|
||||
if (hasSecondDimension) {
|
||||
const isPercentageFormat = measurement.format.substring(measurement.format.length - 1) === '%';
|
||||
let baseFontSize = 14;
|
||||
let cellClass = 'grid-cells2';
|
||||
if (isPercentageFormat) {
|
||||
baseFontSize = 13;
|
||||
cellClass = 'grid-cells2-small';
|
||||
}
|
||||
const cellStyle = {
|
||||
...baseCSS,
|
||||
fontSize: `${baseFontSize + fontSizeAdjustment}px`,
|
||||
height: isMediumFontSize ? '45px' : '35px',
|
||||
verticalAlign: 'middle'
|
||||
verticalAlign: 'middle',
|
||||
minWidth: general.cellWidth,
|
||||
maxWidth: general.cellWidth
|
||||
};
|
||||
return (
|
||||
<th
|
||||
className={`${cellClass}${general.cellSuffix}`}
|
||||
className="grid-cells"
|
||||
style={cellStyle}
|
||||
>
|
||||
<Tooltip
|
||||
@@ -41,11 +41,13 @@ const MeasurementColumnHeader = ({ baseCSS, general, hasSecondDimension, measure
|
||||
...baseCSS,
|
||||
fontSize: `${15 + fontSizeAdjustment}px`,
|
||||
height: isMediumFontSize ? '90px' : '70px',
|
||||
verticalAlign: 'middle'
|
||||
verticalAlign: 'middle',
|
||||
minWidth: general.cellWidth,
|
||||
maxWidth: general.cellWidth
|
||||
};
|
||||
return (
|
||||
<th
|
||||
className={`grid-cells2${general.cellSuffix}`}
|
||||
className="grid-cells"
|
||||
style={style}
|
||||
>
|
||||
<Tooltip
|
||||
@@ -65,7 +67,7 @@ MeasurementColumnHeader.defaultProps = {
|
||||
MeasurementColumnHeader.propTypes = {
|
||||
baseCSS: PropTypes.shape({}).isRequired,
|
||||
general: PropTypes.shape({
|
||||
cellSuffix: PropTypes.string.isRequired
|
||||
cellWidth: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
hasSecondDimension: PropTypes.bool,
|
||||
measurement: PropTypes.shape({
|
||||
|
||||
@@ -71,7 +71,7 @@ export default {
|
||||
const jsx = (
|
||||
<Root
|
||||
editmodeClass={editmodeClass}
|
||||
qlik={this}
|
||||
component={this}
|
||||
state={state}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -24,40 +24,10 @@ function getFontSizeAdjustment (option) {
|
||||
return fontSizeAdjustmentOptions[option] || 0;
|
||||
}
|
||||
|
||||
function getCellSuffix (option) {
|
||||
const cellSuffixOptions = {
|
||||
1: '-s',
|
||||
3: '-l'
|
||||
};
|
||||
|
||||
return cellSuffixOptions[option] || '';
|
||||
}
|
||||
|
||||
function getMeasurementFormat (measurement) {
|
||||
if (measurement.qNumFormat.qType === 'U' || measurement.qNumFormat.qFmt === '##############') {
|
||||
return '#.##0';
|
||||
} else if (measurement.qNumFormat.qType === 'R') {
|
||||
return measurement.qNumFormat.qFmt.replace(/(|)/gi, '');
|
||||
}
|
||||
return measurement.qNumFormat.qFmt;
|
||||
}
|
||||
|
||||
function getMagnitudeLabelSuffix (magnitudeOption) {
|
||||
const magnitudeLabelSuffixOptions = {
|
||||
'k': ' (k)',
|
||||
'm': ' (m)'
|
||||
};
|
||||
|
||||
return magnitudeLabelSuffixOptions[magnitudeOption] || '';
|
||||
}
|
||||
|
||||
function generateMeasurements (information) {
|
||||
return information.map(measurement => {
|
||||
const format = getMeasurementFormat(measurement);
|
||||
const formatMagnitude = format.substr(format.length - 1).toLowerCase();
|
||||
const transformedMeasurement = {
|
||||
format,
|
||||
magnitudeLabelSuffix: getMagnitudeLabelSuffix(formatMagnitude),
|
||||
format: measurement.qNumFormat.qFmt || '#.##0',
|
||||
name: measurement.qFallbackTitle
|
||||
};
|
||||
|
||||
@@ -78,11 +48,6 @@ function generateMatrixCell ({ cell, dimension1Information, dimension2Informatio
|
||||
const matrixCell = {
|
||||
displayValue: cell.qText,
|
||||
format: measurementInformation.format,
|
||||
magnitude: measurementInformation.magnitudeLabelSuffix.substring(
|
||||
measurementInformation.magnitudeLabelSuffix.length - 2,
|
||||
measurementInformation.magnitudeLabelSuffix.length - 1
|
||||
),
|
||||
magnitudeLabelSuffix: measurementInformation.magnitudeLabelSuffix,
|
||||
name: measurementInformation.name,
|
||||
parents: {
|
||||
dimension1: {
|
||||
@@ -273,13 +238,15 @@ function initializeTransformed ({ $element, component, dataCube, designList, lay
|
||||
},
|
||||
matrix, // 2d array of all rows/cells to render in body of datatable
|
||||
meta: {
|
||||
dimensionCount: dimensionsInformation.length
|
||||
dimensionCount: dimensionsInformation.length,
|
||||
altState: layout.qStateName || ""
|
||||
}
|
||||
},
|
||||
general: {
|
||||
allowExcelExport: layout.allowexportxls,
|
||||
allowFilteringByClick: layout.filteroncellclick,
|
||||
cellSuffix: getCellSuffix(layout.columnwidthslider), // TOOD: move to matrix cells or is it headers.measurements?
|
||||
// If using the previous solution just set 60px
|
||||
cellWidth: `${layout.columnwidthslider > 10 ? layout.columnwidthslider : 60}px`,
|
||||
errorMessage: layout.errormessage,
|
||||
footnote: layout.footnote,
|
||||
maxLoops,
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
._cell(@Width: 50px) {
|
||||
min-width: @Width !important;
|
||||
max-width: @Width !important;
|
||||
.grid-cells {
|
||||
cursor: pointer;
|
||||
line-height: 1em !important;
|
||||
}
|
||||
@@ -74,67 +72,6 @@
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
// *****************
|
||||
// Medium column size
|
||||
// *****************
|
||||
|
||||
.grid-cells {
|
||||
position: relative;
|
||||
._cell(70px);
|
||||
}
|
||||
|
||||
.grid-cells2 {
|
||||
._cell(70px);
|
||||
}
|
||||
|
||||
.grid-cells-small {
|
||||
._cell(52px);
|
||||
}
|
||||
|
||||
.grid-cells2-small {
|
||||
._cell(52px);
|
||||
}
|
||||
|
||||
// *****************
|
||||
// Small column size
|
||||
// *****************
|
||||
.grid-cells-s {
|
||||
._cell(67px);
|
||||
}
|
||||
|
||||
.grid-cells2-s {
|
||||
._cell(67px);
|
||||
}
|
||||
|
||||
.grid-cells-small-s {
|
||||
._cell(52px);
|
||||
}
|
||||
|
||||
.grid-cells2-small-s {
|
||||
._cell(52px);
|
||||
}
|
||||
|
||||
// *****************
|
||||
// Large column size
|
||||
// *****************
|
||||
.grid-cells-l {
|
||||
._cell(82px);
|
||||
}
|
||||
|
||||
.grid-cells2-l {
|
||||
._cell(82px);
|
||||
}
|
||||
|
||||
.grid-cells-small-l {
|
||||
._cell(66px);
|
||||
}
|
||||
|
||||
.grid-cells2-small-l {
|
||||
._cell(66px);
|
||||
}
|
||||
|
||||
// END OF GRID CELLS
|
||||
|
||||
// First Column
|
||||
.fdim-cells {
|
||||
min-width: 230px !Important;
|
||||
@@ -149,14 +86,6 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.grid-cells-header {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.grid-cells-title {
|
||||
min-width: 522px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
height: 50px;
|
||||
width: 350px;
|
||||
|
||||
132
src/masking.js
132
src/masking.js
@@ -1,132 +0,0 @@
|
||||
import { addSeparators } from './utilities';
|
||||
|
||||
export function ApplyPreMask (mask, value) { // aqui
|
||||
if (mask.indexOf(';') >= 0) {
|
||||
if (value >= 0) {
|
||||
switch (mask.substring(0, mask.indexOf(';'))) {
|
||||
case '#.##0':
|
||||
return (addSeparators(value, '.', ',', 0));
|
||||
case '#,##0':
|
||||
return (addSeparators(value, ',', '.', 0));
|
||||
case '+#.##0':
|
||||
return (addSeparators(value, '.', ',', 0));
|
||||
case '+#,##0':
|
||||
return (addSeparators(value, ',', '.', 0));
|
||||
default:
|
||||
return (applyMask(mask.substring(0, mask.indexOf(';')), value));
|
||||
}
|
||||
} else {
|
||||
const vMyValue = value * -1;
|
||||
let vMyMask = mask.substring(mask.indexOf(';') + 1, mask.length);
|
||||
vMyMask = vMyMask.replace('(', '');
|
||||
vMyMask = vMyMask.replace(')', '');
|
||||
switch (vMyMask) {
|
||||
case '#.##0':
|
||||
return (`(${addSeparators(vMyValue, '.', ',', 0)})`);
|
||||
case '#,##0':
|
||||
return (`(${addSeparators(vMyValue, ',', '.', 0)})`);
|
||||
case '-#.##0':
|
||||
return (`(${addSeparators(vMyValue, '.', ',', 0)})`);
|
||||
case '-#,##0':
|
||||
return (`(${addSeparators(vMyValue, ',', '.', 0)})`);
|
||||
default:
|
||||
return (`(${applyMask(vMyMask, vMyValue)})`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return (applyMask(mask, value));
|
||||
}
|
||||
}
|
||||
|
||||
function applyMask (originalMask, originalValue) {
|
||||
if (!originalMask || isNaN(Number(originalValue))) {
|
||||
return originalValue;
|
||||
}
|
||||
|
||||
let isNegative;
|
||||
let result;
|
||||
let integer;
|
||||
// find prefix/suffix
|
||||
let len = originalMask.length;
|
||||
const start = originalMask.search(/[0-9\-\+#]/);
|
||||
const prefix = start > 0 ? originalMask.substring(0, start) : '';
|
||||
// reverse string: not an ideal method if there are surrogate pairs
|
||||
let str = originalMask.split('')
|
||||
.reverse()
|
||||
.join('');
|
||||
const end = str.search(/[0-9\-\+#]/);
|
||||
let offset = len - end;
|
||||
const substr = originalMask.substring(offset, offset + 1);
|
||||
let index = offset + ((substr === '.' || (substr === ',')) ? 1 : 0);
|
||||
const suffix = end > 0 ? originalMask.substring(index, len) : '';
|
||||
|
||||
// mask with prefix & suffix removed
|
||||
let mask = originalMask.substring(start, index);
|
||||
|
||||
// convert any string to number according to formation sign.
|
||||
let value = mask.charAt(0) === '-' ? -originalValue : Number(originalValue);
|
||||
isNegative = value < 0 ? value = -value : 0; // process only abs(), and turn on flag.
|
||||
|
||||
// search for separator for grp & decimal, anything not digit, not +/- sign, not #.
|
||||
result = mask.match(/[^\d\-\+#]/g);
|
||||
const decimal = (result && result[result.length - 1]) || '.'; // treat the right most symbol as decimal
|
||||
const group = (result && result[1] && result[0]) || ','; // treat the left most symbol as group separator
|
||||
|
||||
// split the decimal for the format string if any.
|
||||
mask = mask.split(decimal);
|
||||
// Fix the decimal first, toFixed will auto fill trailing zero.
|
||||
value = value.toFixed(mask[1] && mask[1].length);
|
||||
value = String(Number(value)); // convert number to string to trim off *all* trailing decimal zero(es)
|
||||
|
||||
// fill back any trailing zero according to format
|
||||
const posTrailZero = mask[1] && mask[1].lastIndexOf('0'); // look for last zero in format
|
||||
const part = value.split('.');
|
||||
// integer will get !part[1]
|
||||
if (!part[1] || (part[1] && part[1].length <= posTrailZero)) {
|
||||
value = (Number(value)).toFixed(posTrailZero + 1);
|
||||
}
|
||||
const szSep = mask[0].split(group); // look for separator
|
||||
mask[0] = szSep.join(''); // join back without separator for counting the pos of any leading 0.
|
||||
|
||||
const posLeadZero = mask[0] && mask[0].indexOf('0');
|
||||
if (posLeadZero > -1) {
|
||||
while (part[0].length < (mask[0].length - posLeadZero)) {
|
||||
part[0] = `0${part[0]}`;
|
||||
}
|
||||
} else if (Number(part[0]) === 0) {
|
||||
part[0] = '';
|
||||
}
|
||||
|
||||
value = value.split('.');
|
||||
value[0] = part[0];
|
||||
|
||||
// process the first group separator from decimal (.) only, the rest ignore.
|
||||
// get the length of the last slice of split result.
|
||||
const posSeparator = (szSep[1] && szSep[szSep.length - 1].length);
|
||||
if (posSeparator) {
|
||||
integer = value[0];
|
||||
str = '';
|
||||
offset = integer.length % posSeparator;
|
||||
len = integer.length;
|
||||
for (index = 0; index < len; index++) {
|
||||
str += integer.charAt(index); // ie6 only support charAt for sz.
|
||||
// -posSeparator so that won't trail separator on full length
|
||||
// jshint -W018
|
||||
if (!((index - offset + 1) % posSeparator) && index < len - posSeparator) {
|
||||
str += group;
|
||||
}
|
||||
}
|
||||
value[0] = str;
|
||||
}
|
||||
value[1] = (mask[1] && value[1]) ? decimal + value[1] : '';
|
||||
|
||||
// remove negative sign if result is zero
|
||||
result = value.join('');
|
||||
if (result === '0' || result === '') {
|
||||
// remove negative sign if result is zero
|
||||
isNegative = false;
|
||||
}
|
||||
|
||||
// put back any negation, combine integer and fraction, and add back prefix & suffix
|
||||
return prefix + ((isNegative ? '-' : '') + result) + suffix;
|
||||
}
|
||||
12
src/root.jsx
12
src/root.jsx
@@ -4,7 +4,7 @@ import HeadersTable from './headers-table/index.jsx';
|
||||
import DataTable from './data-table/index.jsx';
|
||||
import { LinkedScrollWrapper, LinkedScrollSection } from './linked-scroll';
|
||||
|
||||
const Root = ({ state, qlik, editmodeClass }) => (
|
||||
const Root = ({ state, component, editmodeClass }) => (
|
||||
<div className="root">
|
||||
<LinkedScrollWrapper>
|
||||
<div className={`kpi-table ${editmodeClass}`}>
|
||||
@@ -12,14 +12,14 @@ const Root = ({ state, qlik, editmodeClass }) => (
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
isKpi
|
||||
qlik={qlik}
|
||||
component={component}
|
||||
styling={state.styling}
|
||||
/>
|
||||
<LinkedScrollSection linkVertical>
|
||||
<DataTable
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
qlik={qlik}
|
||||
component={component}
|
||||
renderData={false}
|
||||
styling={state.styling}
|
||||
/>
|
||||
@@ -31,7 +31,7 @@ const Root = ({ state, qlik, editmodeClass }) => (
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
isKpi={false}
|
||||
qlik={qlik}
|
||||
component={component}
|
||||
styling={state.styling}
|
||||
/>
|
||||
</LinkedScrollSection>
|
||||
@@ -42,7 +42,7 @@ const Root = ({ state, qlik, editmodeClass }) => (
|
||||
<DataTable
|
||||
data={state.data}
|
||||
general={state.general}
|
||||
qlik={qlik}
|
||||
component={component}
|
||||
styling={state.styling}
|
||||
/>
|
||||
</LinkedScrollSection>
|
||||
@@ -52,7 +52,7 @@ const Root = ({ state, qlik, editmodeClass }) => (
|
||||
);
|
||||
|
||||
Root.propTypes = {
|
||||
qlik: PropTypes.shape({}).isRequired,
|
||||
component: PropTypes.shape({}).isRequired,
|
||||
state: PropTypes.shape({
|
||||
data: PropTypes.object.isRequired,
|
||||
general: PropTypes.object.isRequired,
|
||||
|
||||
@@ -9,21 +9,6 @@ export function distinctArray (array) {
|
||||
.map(entry => JSON.parse(entry));
|
||||
}
|
||||
|
||||
export function addSeparators (number, thousandSeparator, decimalSeparator, numberOfDecimals) {
|
||||
const numberString = number.toFixed(numberOfDecimals);
|
||||
const numberStringParts = numberString.split('.');
|
||||
let [
|
||||
wholeNumber,
|
||||
decimal
|
||||
] = numberStringParts;
|
||||
decimal = numberStringParts.length > 1 ? decimalSeparator + decimal : '';
|
||||
const regexCheckForThousand = /(\d+)(\d{3})/;
|
||||
while (regexCheckForThousand.test(wholeNumber)) {
|
||||
wholeNumber = wholeNumber.replace(regexCheckForThousand, `$1${thousandSeparator}$2`);
|
||||
}
|
||||
return wholeNumber + decimal;
|
||||
}
|
||||
|
||||
export function Deferred () {
|
||||
this.promise = new Promise((resolve, reject) => {
|
||||
this.resolve = resolve;
|
||||
|
||||
Reference in New Issue
Block a user