diff --git a/src/data-table/data-cell.jsx b/src/data-table/data-cell.jsx new file mode 100644 index 0000000..7178553 --- /dev/null +++ b/src/data-table/data-cell.jsx @@ -0,0 +1,132 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { ApplyPreMask } from '../masking'; +import { addSeparators } from '../utilities'; + +function formatMeasurementValue (measurement, styling) { + // TODO: measurement.name is a horrible propertyname, it's actually the column header + const isColumnPercentageBased = measurement.name.substring(0, 1) === '%'; + 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; + } + } + } + return formattedMeasurementValue; +} + +function getSemaphoreColors (measurement, semaphoreColors) { + if (measurement < semaphoreColors.status.critical) { + return semaphoreColors.statusColors.critical; + } + if (measurement < semaphoreColors.status.medium) { + return semaphoreColors.statusColors.medium; + } + return semaphoreColors.statusColors.normal; +} + +const DataCell = ({ data, general, measurement, styleBuilder, styling }) => { + const isColumnPercentageBased = measurement.name.substring(0, 1) === '%'; + let formattedMeasurementValue = formatMeasurementValue(measurement, styling); + if (styleBuilder.hasComments()) { + formattedMeasurementValue = '.'; + } + + let cellStyle = { + fontFamily: styling.options.fontFamily, + ...styleBuilder.getStyle(), + paddingRight: '4px', + textAlign: 'right' + + }; + const { semaphoreColors } = styling; + const isValidSemaphoreValue = !styleBuilder.hasComments() && !isNaN(measurement.value); + const shouldHaveSemaphoreColors = semaphoreColors.fieldsToApplyTo.applyToAll || semaphoreColors.fieldsToApplyTo.specificFields.indexOf(measurement.name) !== -1; + if (isValidSemaphoreValue && shouldHaveSemaphoreColors) { + const { backgroundColor, color } = getSemaphoreColors(measurement, semaphoreColors); + cellStyle = { + backgroundColor, + color, + fontFamily: styling.options.fontFamily, + fontSize: styleBuilder.getStyle().fontSize, + paddingLeft: '4px', + textAlign: 'right' + }; + } + + let cellClass = 'grid-cells'; + const shouldUseSmallCells = isColumnPercentageBased && data.headers.measurements.length > 1; + if (shouldUseSmallCells) { + cellClass = 'grid-cells-small'; + } + + return ( + + {formattedMeasurementValue} + + ); +}; + +DataCell.propTypes = { + data: PropTypes.shape({ + headers: PropTypes.shape({ + measurements: PropTypes.array.isRequired + }).isRequired + }).isRequired, + general: PropTypes.shape({ + cellSuffix: PropTypes.string.isRequired + }).isRequired, + measurement: PropTypes.shape({ + format: PropTypes.string, + name: PropTypes.string, + value: PropTypes.any + }).isRequired, + styleBuilder: PropTypes.shape({ + hasComments: PropTypes.func.isRequired + }).isRequired, + styling: PropTypes.shape({ + symbolForNulls: PropTypes.any.isRequired + }).isRequired +}; + +export default DataCell; diff --git a/src/data-table/header-padding.jsx b/src/data-table/header-padding.jsx new file mode 100644 index 0000000..45daea5 --- /dev/null +++ b/src/data-table/header-padding.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const HeaderPadding = ({ styleBuilder, styling }) => { + if (styling.usePadding && !styleBuilder.hasCustomFileStyle()) { + const paddingStyle = { + fontFamily: styling.options.fontFamily, + marginLeft: '15px' + }; + return ( + + ); + } + return null; +}; + +HeaderPadding.propTypes = { + styleBuilder: PropTypes.shape({ + hasCustomFileStyle: PropTypes.func.isRequired + }).isRequired, + styling: PropTypes.shape({ + options: PropTypes.shape({ + fontFamily: PropTypes.string.isRequired + }).isRequired + }).isRequired +}; + +export default HeaderPadding; diff --git a/src/data-table/index.jsx b/src/data-table/index.jsx new file mode 100644 index 0000000..afe4aa5 --- /dev/null +++ b/src/data-table/index.jsx @@ -0,0 +1,106 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import StyleBuilder from '../style-builder'; +import DataCell from './data-cell.jsx'; +import HeaderPadding from './header-padding.jsx'; +import { injectSeparators } from '../utilities'; + +const DataTable = ({ data, general, styling }) => { + const { + headers: { + dimension1, + measurements + }, + matrix + } = data; + + return ( +
+ + {dimension1.map((dimensionEntry, dimensionIndex) => { + const rowHeaderText = dimensionEntry.displayValue || ''; + if (rowHeaderText === '-') { + return null; + } + const styleBuilder = new StyleBuilder(styling); + if (styling.hasCustomFileStyle) { + styleBuilder.parseCustomFileStyle(rowHeaderText); + } else { + styleBuilder.applyStandardAttributes(dimensionIndex); + styleBuilder.applyCustomStyle({ + fontSize: `${14 + styling.options.fontSizeAdjustment}px` + }); + } + const rowStyle = { + fontFamily: styling.options.fontFamily, + width: '230px', + ...styleBuilder.getStyle() + }; + + return ( + + + {injectSeparators( + matrix[dimensionIndex], + styling.useSeparatorColumns, + { atEvery: measurements.length } + ).map(measurementData => { + if (measurementData.isSeparator) { + const separatorStyle = { + color: 'white', + fontFamily: styling.options.fontFamily, + fontSize: `${12 + styling.options.fontSizeAdjustment}px` + }; + + return ( + + ); + } + return ( + + ); + })} + + ); + })} +
+ + {dimensionEntry.displayValue} + + * +
+
+ ); +}; + +DataTable.propTypes = { + data: PropTypes.shape({ + headers: PropTypes.shape({ + dimension1: PropTypes.array.isRequired + }).isRequired, + matrix: PropTypes.arrayOf(PropTypes.array.isRequired).isRequired + }).isRequired, + general: PropTypes.shape({}).isRequired, + styling: PropTypes.shape({ + hasCustomFileStyle: PropTypes.bool.isRequired + }).isRequired +}; + +export default DataTable; diff --git a/src/else-dimension-measures.jsx b/src/else-dimension-measures.jsx deleted file mode 100644 index f06c7dd..0000000 --- a/src/else-dimension-measures.jsx +++ /dev/null @@ -1,222 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { ApplyPreMask } from './masking'; -import { addSeparators } from './utilities'; - -class ElseDimensionMeasures extends React.PureComponent { - render () { - const { - vFontFamily, - vSeparatorCols, - measure_count, - sufixCells, - vSymbolForNulls, - vLetterSize, - vColorMetric1, - vColorMetric1Text, - vColorMetric2, - vColorMetric2Text, - vColorMetric3, - vColorMetric3Text, - vAllSemaphores, - ConceptMatrixPivot, - ConceptsAffectedMatrix, - vAllMetrics, - MetricsAffectedMatrix, - vCritic, - vMMedium, - vNumMeasures, - vNumMeasures2, - MeasuresFormat, - rowNumber, - columnText, - styleBuilder - } = this.props; - - // modified in here - let columnNumber, - vMaskNum, - vColorSemaphore, - vColorSemaphoreText, - vDivide; - - const measurementCells = []; - - var nMeasure7 = 0; - var nMeasure72 = -1; - var nMeasure72Semaphore = 0; - - for (var nMeasures22 = 1; nMeasures22 <= vNumMeasures2; nMeasures22++) { - nMeasure7++; - nMeasure72++; - if (columnText.substring(0, 1) === '%') { - columnNumber = ApplyPreMask('0,00%', ConceptMatrixPivot[rowNumber][nMeasures22]); - var vSpecialF = '0,00%'; - } else { - switch (MeasuresFormat[nMeasure72].substr(MeasuresFormat[nMeasure72].length - 1)) { - case 'k': - vDivide = 1000; - break; - - case 'K': - vDivide = 1000; - break; - - case 'm': - vDivide = 1000000; - break; - - case 'M': - vDivide = 1000000; - break; - - default: - vDivide = 1; - break; - } - var vSpecialF = MeasuresFormat[nMeasure72].replace(/k|K|m|M/gi, ''); - if (!isNaN(ConceptMatrixPivot[rowNumber][nMeasures22])) { - vMaskNum = ConceptMatrixPivot[rowNumber][nMeasures22]; - if (vSpecialF.substring(vSpecialF.length - 1) === '%') { - vMaskNum = vMaskNum * 100; - } - - switch (vSpecialF) { - case '#.##0': - columnNumber = addSeparators((vMaskNum / vDivide), '.', ',', 0); - break; - case '#,##0': - columnNumber = addSeparators((vMaskNum / vDivide), ',', '.', 0); - break; - default: - columnNumber = ApplyPreMask(vSpecialF, (vMaskNum / vDivide)); - break; - } - } else { - columnNumber = vSymbolForNulls; - } - } - - if (vSeparatorCols && nMeasure7 === (measure_count + 1)) { - const seperatorStyle = { - color: 'white', - fontFamily: vFontFamily, - fontSize: (12 + vLetterSize) + 'px' - }; - const seperatorElement = ( - - * - - ); - measurementCells.push(seperatorElement); - nMeasure7 = 1; - } - if (nMeasure72 === (measure_count - 1)) { - nMeasure72 = -1; - nMeasure72Semaphore = measure_count; - } else { - nMeasure72Semaphore = nMeasure72 + 1; - } - - // apply the semaphores where needed - if (styleBuilder.hasComments()) { - columnNumber = '.'; - } - - let cellElement; - if ((vAllSemaphores || ConceptsAffectedMatrix.indexOf(columnText) >= 0) && (vAllMetrics || MetricsAffectedMatrix.indexOf(nMeasure72Semaphore) >= 0) && !isNaN(ConceptMatrixPivot[rowNumber][nMeasures22]) && !styleBuilder.hasComments()) { - if (ConceptMatrixPivot[rowNumber][nMeasures22] < vCritic) { - vColorSemaphore = vColorMetric1; - vColorSemaphoreText = vColorMetric1Text; - } else { - if (ConceptMatrixPivot[rowNumber][nMeasures22] < vMMedium) { - vColorSemaphore = vColorMetric2; - vColorSemaphoreText = vColorMetric2Text; - } else { - vColorSemaphore = vColorMetric3; - vColorSemaphoreText = vColorMetric3Text; - } - } - - const cellStyle = { - fontFamily: vFontFamily, - fontSize: styleBuilder.getStyle().fontSize, - color: vColorSemaphoreText, - backgroundColor: vColorSemaphore, - textAlign: 'right', - paddingLeft: '4px' - }; - if (vSpecialF.substring(vSpecialF.length - 1) === '%' && vNumMeasures > 1) { - cellElement = ( - - {columnNumber} - - ); - } else { - cellElement = ( - - {columnNumber} - - ); - } - } else { - const cellStyle = { - fontFamily: vFontFamily, - ...styleBuilder.getStyle(), - textAlign: 'right', - paddingRight: '4px' - }; - if (vSpecialF.substring(vSpecialF.length - 1) === '%' && vNumMeasures > 1) { - cellElement = ( - - {columnNumber} - - ); - } else { - cellElement = ( - - {columnNumber} - - ); - } - } - measurementCells.push(cellElement); - } - - return ( - - {measurementCells} - - ); - } -} - -ElseDimensionMeasures.propTypes = { - vFontFamily: PropTypes.any, - vSeparatorCols: PropTypes.any, - measure_count: PropTypes.any, - sufixCells: PropTypes.any, - vSymbolForNulls: PropTypes.any, - vLetterSize: PropTypes.any, - vColorMetric1: PropTypes.any, - vColorMetric1Text: PropTypes.any, - vColorMetric2: PropTypes.any, - vColorMetric2Text: PropTypes.any, - vColorMetric3: PropTypes.any, - vColorMetric3Text: PropTypes.any, - vAllSemaphores: PropTypes.any, - ConceptMatrixPivot: PropTypes.any, - ConceptsAffectedMatrix: PropTypes.any, - vAllMetrics: PropTypes.any, - MetricsAffectedMatrix: PropTypes.any, - vCritic: PropTypes.any, - vMMedium: PropTypes.any, - vNumMeasures: PropTypes.any, - vNumMeasures2: PropTypes.any, - MeasuresFormat: PropTypes.any, - rowNumber: PropTypes.any, - columnText: PropTypes.any, - styleBuilder: PropTypes.any -}; - -export default ElseDimensionMeasures; diff --git a/src/index.js b/src/index.js index e9524b1..49b61ac 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ import '@babel/polyfill'; -import paint from './paint'; +import paint from './paint.jsx'; import definition from './definition'; import './main.less'; diff --git a/src/initialize-transformed.js b/src/initialize-transformed.js index 35fcd5a..b58f7ca 100644 --- a/src/initialize-transformed.js +++ b/src/initialize-transformed.js @@ -3,7 +3,6 @@ import { distinctArray } from './utilities'; // TODO: rename colors function initializeColors ({ layout }) { - console.log(layout); return { vColLibBlue: layout.collibblue, vColLibBlueP: layout.collibbluep, @@ -142,7 +141,6 @@ function generateDataSet (component, dimensionsInformation, measurementsInformat }); if (hasSecondDimension) { - // console.log(row[0]); const currentDim1Entry = row[0].qText; const isSameDimension1AsPrevious = currentDim1Entry === previousDim1Entry; if (isSameDimension1AsPrevious) { diff --git a/src/paint.js b/src/paint.jsx similarity index 80% rename from src/paint.js rename to src/paint.jsx index e26c71f..2ed949d 100644 --- a/src/paint.js +++ b/src/paint.jsx @@ -1,72 +1,64 @@ import $ from 'jquery'; import { enableExcelExport } from './excel-export'; -import HeaderWrapper from './header-wrapper.jsx'; -import RowWrapper, { prepareProps } from './row-wrapper.jsx'; import initializeStore from './store'; import React from 'react'; // import ReactDOM from 'react-dom'; import { renderToStaticMarkup } from 'react-dom/server'; +import HeadersTable from './headers-table/index.jsx'; +import DataTable from './data-table/index.jsx'; export default async function paint ($element, layout, component) { - const state = initializeStore({ + const state = await initializeStore({ $element, - layout, - component + component, + layout }); + const { - ArrayGetSelectedCount, - vNumDims, ConceptMatrixColElem, ConceptMatrixColElemTable, - ConceptMatrixRowElem, - vSeparatorCols + ConceptMatrixRowElem } = state.properties; - const rowWrapperProps = await prepareProps({ - state: { - layout, - colors: state.colors, - ...state.properties - } - }); + const { + data: { meta: { dimensionCount } }, + selection: { dimensionSelectionCounts }, + styling: { useSeparatorColumns } + } = state; const jsx = (
- -
- -
); // TODO: switch to render when jquery interaction stuff in renderData is gone - // ReactDOM.render(jsx, $element[0]); - const html = renderToStaticMarkup(jsx); - $element.html(html); + // ReactDOM.render(jsx, $element[0]); RenderData(); @@ -124,8 +116,8 @@ export default async function paint ($element, layout, component) { // colgado el menú de confirm, por eso uso este sistema, que sí funciona. // it can cause issues like error messages and wrong selections if there are null values // and the check allow null values is active - if (vNumDims > 1 && indextd > 0) { - if (ArrayGetSelectedCount[1] > 0) { + if (dimensionCount > 1 && indextd > 0) { + if (dimensionSelectionCounts[1] > 0) { const SelectB = JSON.parse(JSON.stringify(ConceptMatrixColElemTable)); component.backendApi.selectValues(1, SelectB, true); $(this).toggleClass('selected'); @@ -136,7 +128,7 @@ export default async function paint ($element, layout, component) { $(this).toggleClass('selected'); } - if (indextd > 0 && ArrayGetSelectedCount[0] > 0) { + if (indextd > 0 && dimensionSelectionCounts[0] > 0) { const SelectA = JSON.parse(JSON.stringify(ConceptMatrixRowElem)); component.backendApi.selectValues(0, SelectA, true); $(this).toggleClass('selected'); @@ -155,13 +147,13 @@ export default async function paint ($element, layout, component) { let SelectCol = 0; - if (vNumDims > 1 && indextd > 0) { - if (ArrayGetSelectedCount[1] > 0) { + if (dimensionCount > 1 && indextd > 0) { + if (dimensionSelectionCounts[1] > 0) { const SelectB = JSON.parse(JSON.stringify(ConceptMatrixColElem)); component.backendApi.selectValues(1, SelectB, true); $(this).toggleClass('selected'); } - if (vSeparatorCols) { + if (useSeparatorColumns) { SelectCol = ConceptMatrixColElem[(Math.round(indextd / 2) - 1)]; } else { SelectCol = ConceptMatrixColElem[(Math.round(indextd) - 1)]; @@ -180,7 +172,7 @@ export default async function paint ($element, layout, component) { let SelectRow = 0; SelectRow = ConceptMatrixRowElem[(indextr)]; - if (ArrayGetSelectedCount[0] > 0) { + if (dimensionSelectionCounts[0] > 0) { const SelectA = JSON.parse(JSON.stringify(ConceptMatrixRowElem)); component.backendApi.selectValues(0, SelectA, true); $(this).toggleClass('selected'); diff --git a/src/row-list.jsx b/src/row-list.jsx deleted file mode 100644 index 742fac1..0000000 --- a/src/row-list.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import StyleBuilder from './style-builder'; - -class RowList extends React.PureComponent { - generatePaddingTextElement (hasCustomFileStyle) { - const { vPadding, vFontFamily } = this.props; - if (vPadding && !hasCustomFileStyle) { - const paddingStyle = { - fontFamily: vFontFamily, - marginLeft: '15px' - }; - return ( - - ); - } - return null; - } - - render () { - const { - vLetterSize, - vCustomFileBool, - vFontFamily, - tableData, - MeasurementsComponent - } = this.props; - - return ( - - {tableData.map((row, rowNumber) => { - const rowHeaderText = row[0] || ''; - if (rowHeaderText === '-') { - return null; - } - const styleBuilder = new StyleBuilder(this.props); - if (vCustomFileBool) { - styleBuilder.parseCustomFileStyle(rowHeaderText); - } else { - styleBuilder.applyStandardAttributes(rowNumber); - styleBuilder.applyCustomStyle({ fontSize: (14 + vLetterSize) + 'px' }); - } - - const rowStyle = { - fontFamily: vFontFamily, - width: '230px', - ...styleBuilder.getStyle() - }; - const paddingTextElement = this.generatePaddingTextElement(styleBuilder.hasCustomFileStyle()); - const measurementsProps = { - rowHeaderText, - rowNumber, - styleBuilder - }; - return ( - - - {paddingTextElement} - {rowHeaderText} - - - - ); - })} - - ); - } -} - -RowList.propTypes = { - tableData: PropTypes.array.isRequired -}; - -export default RowList; diff --git a/src/row-wrapper.jsx b/src/row-wrapper.jsx deleted file mode 100644 index 985bd07..0000000 --- a/src/row-wrapper.jsx +++ /dev/null @@ -1,129 +0,0 @@ -import $ from 'jquery'; -import PropTypes from 'prop-types'; -import React from 'react'; - -import ElseDimensionMeasures from './else-dimension-measures.jsx'; -import RowList from './row-list.jsx'; -import SingleDimensionMeasures from './single-dimension-measures.jsx'; - -const RowWrapper = props => { - const { - ConceptMatrix, - ConceptMatrixPivot, - vNumDims - } = props; - let MeasurementsComponent, - tableData; - if (vNumDims === 1) { - tableData = ConceptMatrix; - MeasurementsComponent = SingleDimensionMeasures; - } else { - tableData = ConceptMatrixPivot.filter(array => array.length); - MeasurementsComponent = ElseDimensionMeasures; - } - - return ( -
- - -
-
- ); -}; - -RowWrapper.propTypes = { - ConceptMatrix: PropTypes.array.isRequired, - ConceptMatrixPivot: PropTypes.array.isRequired -}; - -export default RowWrapper; - -export async function prepareProps ({ state }) { - const { colors, layout, vAllSemaphores, vDynamicColorBody, vDynamicColorBodyP } = state; - const props = { - colors, - vCustomFileBool: layout.customfilebool, - vCustomFile: layout.customfile, - vPadding: layout.indentbool, - vPaddingText: '', - vGlobalComas: 0, - vGlobalComas2: 0, - vGlobalComment: 0, - vGlobalCommentColor: '', - vGlobalFontSize: 0, - vComas: 0, - vMedium: false, - vFontSize: '', - vColorText: layout.BodyTextColorSchema, - vDivide: 1, - vSymbolForNulls: layout.symbolfornulls, - vDynamicColorBody: 'vColLib' + layout.ColorSchema, - vDynamicColorBodyP: 'vColLib' + layout.ColorSchema + 'P', - vAllMetrics: layout.allmetrics, - MetricsAffectedMatrix: JSON.parse('[' + layout.metricssemaphore + ']'), - vColorMetric1: layout.colorstatus1.color, - vColorMetric2: layout.colorstatus2.color, - vColorMetric3: layout.colorstatus3.color, - vColorMetric1Text: layout.colorstatus1text.color, - vColorMetric2Text: layout.colorstatus2text.color, - vColorMetric3Text: layout.colorstatus3text.color, - vColorSemaphore: '', - vColorSemaphoreText: '', - vCritic: layout.metricsstatus1, - vMMedium: layout.metricsstatus2, - CustomArray: new Array(), - CustomArrayBasic: new Array(), - vNumCustomHeaders: 0, - vColumnText: '', - vColumnNum: '', - vMaskNum: 0, - StyleTags: '', - vColorSchema: colors[vDynamicColorBody], - vColorSchemaP: colors[vDynamicColorBodyP], - vAllSemaphores: layout.allsemaphores, - ConceptsAffectedMatrix: new Array(10) - }; - if (vAllSemaphores == false) { - props.ConceptsAffectedMatrix[0] = layout.conceptsemaphore1; - props.ConceptsAffectedMatrix[1] = layout.conceptsemaphore2; - props.ConceptsAffectedMatrix[2] = layout.conceptsemaphore3; - props.ConceptsAffectedMatrix[3] = layout.conceptsemaphore4; - props.ConceptsAffectedMatrix[4] = layout.conceptsemaphore5; - props.ConceptsAffectedMatrix[5] = layout.conceptsemaphore6; - props.ConceptsAffectedMatrix[6] = layout.conceptsemaphore7; - props.ConceptsAffectedMatrix[7] = layout.conceptsemaphore8; - props.ConceptsAffectedMatrix[8] = layout.conceptsemaphore9; - props.ConceptsAffectedMatrix[9] = layout.conceptsemaphore10; - } - - function ReadCustomSchema () { - var Url = '/Extensions/qlik-smart-pivot/' + props.vCustomFile; - return $.get(Url).then(function (response) { - var allTextLines = response.split(/\r\n|\n/); - var headers = allTextLines[0].split(';'); - props.vNumCustomHeaders = headers.length; - - for (var i = 0; i < allTextLines.length; i++) { - props.CustomArray[i] = new Array(headers.length); - var data = allTextLines[i].split(';'); - - if (data.length == headers.length) { - for (var j = 0; j < headers.length; j++) { - props.CustomArrayBasic[i] = data[0]; - props.CustomArray[i][j] = data[j]; - } - } - } - }); - } - - const hasCustomSchema = (props.vCustomFileBool && props.vCustomFile.length > 4); - const schemaPromise = hasCustomSchema ? ReadCustomSchema() : Promise.resolve(); - await schemaPromise; - - return props; -} diff --git a/src/single-dimension-measures.jsx b/src/single-dimension-measures.jsx deleted file mode 100644 index f50eb47..0000000 --- a/src/single-dimension-measures.jsx +++ /dev/null @@ -1,159 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { ApplyPreMask } from './masking'; -import { addSeparators } from './utilities'; - -class SingleDimensionMeasures extends React.PureComponent { - render () { - const { - vFontFamily, - vSymbolForNulls, - vColorMetric1, - vColorMetric1Text, - vColorMetric2, - vColorMetric2Text, - vColorMetric3, - vColorMetric3Text, - ConceptMatrix, - vAllSemaphores, - ConceptsAffectedMatrix, - vAllMetrics, - MetricsAffectedMatrix, - vCritic, - vMMedium, - vNumMeasures, - MeasuresFormat, - rowNumber, - columnText, - styleBuilder - } = this.props; - - // modified in here - let vColumnNum, - vMaskNum, - vColorSemaphore, - vColorSemaphoreText, - vDivide; - - const measurementCells = []; - - // TODO: map ConceptMatrix[rowNumber] into cells - for (var nMeasures2 = 1; nMeasures2 <= vNumMeasures; nMeasures2++) { - var vSpecialF = MeasuresFormat[nMeasures2 - 1].replace(/k|K|m|M/gi, ''); - if (columnText.substring(0, 1) == '%') { - vColumnNum = ApplyPreMask('0,00%', ConceptMatrix[rowNumber][nMeasures2]); - vSpecialF = '0,00%'; - } else { - const magnitude = MeasuresFormat[nMeasures2 - 1].substr(MeasuresFormat[nMeasures2 - 1].length - 1); - switch (magnitude.toLowerCase()) { - case 'k': - vDivide = 1000; - break; - - case 'm': - vDivide = 1000000; - break; - - default: - vDivide = 1; - break; - } - if (!isNaN(ConceptMatrix[rowNumber][nMeasures2])) { - vMaskNum = ConceptMatrix[rowNumber][nMeasures2]; - if (vSpecialF.substring(vSpecialF.length - 1) == '%') { - vMaskNum = vMaskNum * 100; - } - switch (vSpecialF) { - case '#.##0': - vColumnNum = addSeparators((vMaskNum / vDivide), '.', ',', 0); - break; - - case '#,##0': - vColumnNum = addSeparators((vMaskNum / vDivide), ',', '.', 0); - break; - - default: - vColumnNum = ApplyPreMask(vSpecialF, (vMaskNum / vDivide)); - break; - } - } else { - vColumnNum = vSymbolForNulls; - } - } - if (styleBuilder.hasComments()) { - vColumnNum = '.'; - } - // apply the semaphore styles where needed - let cellStyle; - if ((vAllSemaphores || ConceptsAffectedMatrix.indexOf(columnText) >= 0) && (vAllMetrics || MetricsAffectedMatrix.indexOf(nMeasures2) >= 0) && !isNaN(ConceptMatrix[rowNumber][nMeasures2]) && !styleBuilder.hasComments()) { - if (ConceptMatrix[rowNumber][nMeasures2] < vCritic) { - vColorSemaphore = vColorMetric1; - vColorSemaphoreText = vColorMetric1Text; - } else { - if (ConceptMatrix[rowNumber][nMeasures2] < vMMedium) { - vColorSemaphore = vColorMetric2; - vColorSemaphoreText = vColorMetric2Text; - } else { - vColorSemaphore = vColorMetric3; - vColorSemaphoreText = vColorMetric3Text; - } - } - - cellStyle = { - fontFamily: vFontFamily, - fontSize: styleBuilder.getStyle().fontSize, - color: vColorSemaphoreText, - backgroundColor: vColorSemaphore, - textAlign: 'right', - paddingLeft: '4px' - }; - } else { - cellStyle = { - fontFamily: vFontFamily, - textAlign: 'right', - paddingLeft: '4px', - ...styleBuilder.getStyle() - }; - } - - const measurementCell = ( - - {vColumnNum} - - ); - - measurementCells.push(measurementCell); - } - - return ( - - {measurementCells} - - ); - } -} - -SingleDimensionMeasures.propTypes = { - vFontFamily: PropTypes.any, - vSymbolForNulls: PropTypes.any, - vColorMetric1: PropTypes.any, - vColorMetric1Text: PropTypes.any, - vColorMetric2: PropTypes.any, - vColorMetric2Text: PropTypes.any, - vColorMetric3: PropTypes.any, - vColorMetric3Text: PropTypes.any, - ConceptMatrix: PropTypes.any, - vAllSemaphores: PropTypes.any, - ConceptsAffectedMatrix: PropTypes.any, - vAllMetrics: PropTypes.any, - MetricsAffectedMatrix: PropTypes.any, - vCritic: PropTypes.any, - vMMedium: PropTypes.any, - vNumMeasures: PropTypes.any, - MeasuresFormat: PropTypes.any, - rowNumber: PropTypes.any, - columnText: PropTypes.any, - styleBuilder: PropTypes.any -}; - -export default SingleDimensionMeasures; diff --git a/src/style-builder.js b/src/style-builder.js index 391d5d0..72ecefb 100644 --- a/src/style-builder.js +++ b/src/style-builder.js @@ -1,16 +1,11 @@ -function StyleBuilder (state) { +function StyleBuilder (styling) { const { - CustomArray, - CustomArrayBasic, - vNumCustomHeaders, - vColorSchema, - vColorText, - vColorSchemaP, - vLetterSize, - colors - } = state; + colors, + customCSV, + options + } = styling; let style = { - fontSize: `${14 + vLetterSize}px` + fontSize: `${14 + options.fontSizeAdjustment}px` }; let hasComments = false; let commentColor; @@ -18,9 +13,9 @@ function StyleBuilder (state) { function applyStandardAttributes (rowNumber) { const isEven = rowNumber % 2 === 0; - style.backgroundColor = isEven ? vColorSchema : vColorSchemaP; - style.color = vColorText; - style.fontSize = `${14 + vLetterSize}px`; + style.backgroundColor = isEven ? options.backgroundColor : options.backgroundColorOdd; + style.color = options.color; + style.fontSize = `${13 + options.fontSizeAdjustment}px`; } function applyColor (color) { @@ -28,6 +23,7 @@ function StyleBuilder (state) { commentColor = color; } + /* eslint-disable sort-keys*/ const properties = { '': () => { hasComments = true; }, // text @@ -46,17 +42,18 @@ function StyleBuilder (state) { // font color TODO: this is a color just like the others, but it applies to text instead.. any way to make it less weird? '': () => { style.color = 'white'; }, // font size - '': () => { style.fontSize = `${15 + vLetterSize}px`; }, - '': () => { style.fontSize = `${14 + vLetterSize}px`; }, - '': () => { style.fontSize = `${13 + vLetterSize}px`; }, + '': () => { style.fontSize = `${15 + options.fontSizeAdjustment}px`; }, + '': () => { style.fontSize = `${14 + options.fontSizeAdjustment}px`; }, + '': () => { style.fontSize = `${13 + options.fontSizeAdjustment}px`; }, // text alignment '
': () => { style.textAlign = 'center'; } }; + /* eslint-enable sort-keys */ // TODO: need to improve this, it has way too many false positives function isCSSColor (property) { - const isHexColor = property.substring(0, 1) == '#'; - const isRGBColor = property.substring(0, 3).toUpperCase() == 'RGB'; + const isHexColor = property.substring(0, 1) === '#'; + const isRGBColor = property.substring(0, 3).toUpperCase() === 'RGB'; return isHexColor || isRGBColor; } @@ -84,27 +81,27 @@ function StyleBuilder (state) { } function parseCustomFileStyle (columnText) { - hasCustomFileStyle = true; - for (let csvAttribute = 1; csvAttribute < vNumCustomHeaders; csvAttribute += 1) { + for (let csvAttribute = 1; csvAttribute < customCSV.count; csvAttribute += 1) { let customAttribute = ''; - if (CustomArrayBasic.indexOf(columnText) < 0) { + if (customCSV.basic.indexOf(columnText) < 0) { customAttribute = 'none'; } else { - customAttribute = CustomArray[CustomArrayBasic.indexOf(columnText)][csvAttribute]; + hasCustomFileStyle = true; + customAttribute = customCSV.full[customCSV.basic.indexOf(columnText)][csvAttribute]; } applyProperty(customAttribute); } } return { + applyCustomStyle, + applyProperty, + applyStandardAttributes, getCommentColor: () => commentColor, getStyle: () => style, + hasComments: () => hasComments, hasCustomFileStyle: () => hasCustomFileStyle, hasFontSize: () => Boolean(style.fontSize), - hasComments: () => hasComments, - applyStandardAttributes, - applyProperty, - applyCustomStyle, parseCustomFileStyle }; } diff --git a/src/utilities.js b/src/utilities.js index 0e47a6d..3ad9f54 100644 --- a/src/utilities.js +++ b/src/utilities.js @@ -2,6 +2,13 @@ export function onlyUnique (value, index, self) { return self.indexOf(value) === index; } +export function distinctArray (array) { + return array + .map(entry => JSON.stringify(entry)) + .filter(onlyUnique) + .map(entry => JSON.parse(entry)); +} + export function addSeparators (nStr, thousandsSep, decimalSep, numDecimals) { let x1; nStr = nStr.toFixed(numDecimals); @@ -21,3 +28,25 @@ export function Deferred () { this.reject = reject; }); } + +export function injectSeparators (array, shouldHaveSeparator, suppliedOptions) { + const defaultOptions = { + atEvery: 1, + separator: { isSeparator: true } + }; + const options = { + ...defaultOptions, + ...suppliedOptions + }; + + if (!shouldHaveSeparator) { + return array; + } + return array.reduce((result, entry, index) => { + result.push(entry); + if (index < array.length - 1 && (index + 1) % options.atEvery === 0) { + result.push(options.separator); + } + return result; + }, []); +}