Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
072a3b80c4 | ||
|
|
5572b7ce67 | ||
|
|
71cf92c217 | ||
|
|
20282b0b99 | ||
|
|
d14f5951ac | ||
|
|
729a31920d |
@@ -1,7 +1,5 @@
|
||||
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 {
|
||||
@@ -17,16 +15,15 @@ class DataCell extends React.PureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
qlik.backendApi.selectValues(0, [measurement.parents.dimension1.elementNumber], true);
|
||||
qlik.backendApi.selectValues(0, [measurement.parents.dimension1.elementNumber], false);
|
||||
|
||||
if (hasSecondDimension) {
|
||||
qlik.backendApi.selectValues(1, [measurement.parents.dimension2.elementNumber], true);
|
||||
qlik.backendApi.selectValues(1, [measurement.parents.dimension2.elementNumber], false);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
data,
|
||||
general,
|
||||
measurement,
|
||||
styleBuilder,
|
||||
@@ -39,11 +36,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 +68,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}
|
||||
>
|
||||
@@ -101,7 +92,7 @@ DataCell.propTypes = {
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
general: PropTypes.shape({
|
||||
cellSuffix: PropTypes.string.isRequired
|
||||
cellWidth: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
measurement: PropTypes.shape({
|
||||
format: PropTypes.string,
|
||||
@@ -129,51 +120,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) {
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -15,7 +15,7 @@ class ColumnHeader extends React.PureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { baseCSS, cellSuffix, colSpan, entry, styling, qlik } = this.props;
|
||||
const { baseCSS, cellWidth, colSpan, entry, styling, qlik } = this.props;
|
||||
const inEditState = qlik.inEditState();
|
||||
const isMediumFontSize = styling.headerOptions.fontSizeAdjustment === HEADER_FONT_SIZE.MEDIUM;
|
||||
|
||||
@@ -23,12 +23,14 @@ class ColumnHeader extends React.PureComponent {
|
||||
...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,13 +48,12 @@ 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({
|
||||
elementNumber: PropTypes.number.isRequired,
|
||||
|
||||
@@ -68,7 +68,7 @@ const HeadersTable = ({ data, general, qlik, styling, isKpi }) => {
|
||||
return (
|
||||
<ColumnHeader
|
||||
baseCSS={baseCSS}
|
||||
cellSuffix={general.cellSuffix}
|
||||
cellWidth={general.cellWidth}
|
||||
colSpan={measurements.length}
|
||||
entry={entry}
|
||||
key={entry.displayValue}
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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: {
|
||||
@@ -279,7 +244,8 @@ function initializeTransformed ({ $element, component, dataCube, designList, lay
|
||||
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;
|
||||
}
|
||||
@@ -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