From f0121b3a759eaee06abbbe1272a4aad1ed2ff467 Mon Sep 17 00:00:00 2001 From: Kristoffer Lind Date: Fri, 25 Jan 2019 14:02:26 +0100 Subject: [PATCH] convert row-wrapper --- .gitattributes | 1 + src/else-dimension-row-list.jsx | 255 ++++++++++++++++++++++++++++++ src/row-wrapper.jsx | 130 +++++++++++++++ src/single-dimension-row-list.jsx | 82 ++++++++++ src/style-builder.js | 115 ++++++++++++++ 5 files changed, 583 insertions(+) create mode 100644 src/else-dimension-row-list.jsx create mode 100644 src/row-wrapper.jsx create mode 100644 src/single-dimension-row-list.jsx create mode 100644 src/style-builder.js diff --git a/.gitattributes b/.gitattributes index 99b2250..a2a8467 100644 --- a/.gitattributes +++ b/.gitattributes @@ -22,6 +22,7 @@ *.scss text eol=lf *.html text eol=lf *.js text eol=lf +*.jsx text eol=lf *.json text eol=lf *.md text eol=lf *.sh text eol=lf diff --git a/src/else-dimension-row-list.jsx b/src/else-dimension-row-list.jsx new file mode 100644 index 0000000..86c2a38 --- /dev/null +++ b/src/else-dimension-row-list.jsx @@ -0,0 +1,255 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { ApplyPreMask } from './masking'; +import { addSeparators } from './utilities'; +import StyleBuilder from './style-builder'; + +class ElseDimensionRowList extends React.PureComponent { + generatePaddingTextElement (hasCustomFileStyle) { + const { vPadding, vFontFamily } = this.props; + if (vPadding && !hasCustomFileStyle) { + const paddingStyle = { + marginLeft: '15px', + fontFamily: vFontFamily + }; + return ( + + ); + } else { + return null; + } + } + generateCells (rowNumber, columnText, styleBuilder) { + const { + vFontFamily, + vSeparatorCols, + measure_count, + sufixCells, + vSymbolForNulls, + vLetterSize, + vColorMetric1, + vColorMetric1Text, + vColorMetric2, + vColorMetric2Text, + vColorMetric3, + vColorMetric3Text, + vAllSemaphores, + ConceptMatrixPivot, + ConceptsAffectedMatrix, + vAllMetrics, + MetricsAffectedMatrix, + vCritic, + vMMedium, + vNumMeasures, + vNumMeasures2, + MeasuresFormat + } = 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); + } + } + generateRows () { + const { + vLetterSize, + vCustomFileBool, + vFontFamily, + ConceptMatrixFirstClean, + ConceptMatrixPivot, + } = this.props; + + const rows = []; + let columnText; + + var nPivotRows = ConceptMatrixFirstClean.length; + for (var rowNumber = 0; rowNumber < nPivotRows; rowNumber++) { + columnText = ConceptMatrixPivot[rowNumber][0];// the descriptive account text + if (columnText != '-') { + const styleBuilder = new StyleBuilder(this.props); + if (vCustomFileBool) { + styleBuilder.parseCustomFileStyle(columnText); + } 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 cells = this.generateCells(rowNumber, columnText, styleBuilder); + const rowElement = ( + + + {paddingTextElement}{columnText} + + {cells} + + ); + + rows.push(rowElement); + } + + return rows; + } + } + + render () { + return ( + + {this.generateRows()} + + ); + } +} + +ElseDimensionRowList.propTypes = {}; + +export default ElseDimensionRowList; diff --git a/src/row-wrapper.jsx b/src/row-wrapper.jsx new file mode 100644 index 0000000..360e39b --- /dev/null +++ b/src/row-wrapper.jsx @@ -0,0 +1,130 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { renderToStaticMarkup } from 'react-dom/server'; +import $ from 'jquery'; +import SingleDimensionRowList from './single-dimension-row-list'; +import ElseDimensionRowList from './single-dimension-row-list'; + +// TableBody? +class RowWrapper extends React.PureComponent { + generateDimensionRowList () { + if (this.props.vNumDims === 1) { + return ( + + ); + } else { + return ( + + ); + } + } + render () { + return ( +
+ + {this.generateDimensionRowList()} +
+
+ ); + } +} + +RowWrapper.propTypes = { + +}; + +async function prepareProps ({ state }) { + const { colors, layout, vAllSemaphores, vDynamicColorBody, vDynamicColorBodyP } = state; + const props = { + 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/PLSmartPivot/' + 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; +} + +export async function generateRowWrapper ({ state }) { + const preparedProps = await prepareProps({ state }); + const html = renderToStaticMarkup( + + ); + return html; +} diff --git a/src/single-dimension-row-list.jsx b/src/single-dimension-row-list.jsx new file mode 100644 index 0000000..f8ef340 --- /dev/null +++ b/src/single-dimension-row-list.jsx @@ -0,0 +1,82 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { ApplyPreMask } from './masking'; +import { addSeparators } from './utilities'; +import StyleBuilder from './style-builder'; + +// TODO: everything except cell rendering is pretty much identical to ElseDimensionRowList +// extract cells into subcomponents and merge to generic rowlist +class SingleDimensionRowList extends React.PureComponent { + generatePaddingTextElement (hasCustomFileStyle) { + const { vPadding, vFontFamily } = this.props; + if (vPadding && !hasCustomFileStyle) { + const paddingStyle = { + marginLeft: '15px', + fontFamily: vFontFamily + }; + return ( + + ); + } else { + return null; + } + } + // + generateRows () { + const { + vLetterSize, + vCustomFileBool, + vFontFamily, + ConceptMatrix, + lastrow + } = this.props; + + const rows = []; + let columnText; + + //apply the custom style + for (var rowNumber = 0; rowNumber <= lastrow; rowNumber++) { + columnText = ConceptMatrix[rowNumber][0]; + if (columnText != '-') { + const styleBuilder = new StyleBuilder(this.props); + if (vCustomFileBool) { + styleBuilder.parseCustomFileStyle(columnText); // TODO: parseCSVStyle? + } 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 cells = this.generateCells(rowNumber, columnText, styleBuilder); + const rowElement = ( + + + {paddingTextElement}{columnText} + + {cells} + + ); + + rows.push(rowElement); + } + } + + return rows; + } + render () { + return ( + + {this.generateRows()} + + ); + } +} + +SingleDimensionRowList.propTypes = {}; + +export default SingleDimensionRowList; diff --git a/src/style-builder.js b/src/style-builder.js new file mode 100644 index 0000000..52e5784 --- /dev/null +++ b/src/style-builder.js @@ -0,0 +1,115 @@ +function StyleBuilder (state) { + const { + CustomArray, + CustomArrayBasic, + vNumCustomHeaders, + vColorSchema, + vColorText, + vColorSchemaP, + vLetterSize, + colors + } = state; + let style = {}; + let hasComments = false; // vGlobalComment + let commentColor; // vGlobalCommentColor + let hasCustomFileStyle = false; // vGlobalComas, vGlobalComas2 + + function applyStandardAttributes (rowNumber) { + const isEven = rowNumber % 2 === 0; + style.backgroundColor = isEven ? vColorSchema : vColorSchemaP; + style.color = vColorText; + style.fontSize = (14 + vLetterSize) + 'px'; + } + + function applyColor (color) { + style.backgroundColor = color; + commentColor = color; + } + + const properties = { + '': () => { hasComments = true; }, + // text + '': () => { style.fontWeight = 'bold'; }, + '': () => { style.fontStyle = 'italic'; }, + '': () => { style.fontStyle = 'oblique'; }, + // background and comment color + '': () => applyColor(colors.vColLibDark), + '': () => applyColor(colors.vColLibNight), + '': () => applyColor(colors.vColLibSoft), + '': () => applyColor(colors.vColLibRed), + '': () => applyColor(colors.vColLibOrange), + '': () => applyColor(colors.vColLibViolete), + '': () => applyColor(colors.vColLibBlue), + '': () => applyColor(colors.vColLibGreen), + // 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'; }, + // text alignment + '
': () => { style.textAlign = 'center'; } + }; + + // 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'; + return isHexColor || isRGBColor; + } + + function applyProperty (property) { + if (properties[property]) { + properties[property](); + } else { + console.error(`Custom property ${property} does not exist`); // eslint-disable-line no-console + } + + if (isCSSColor(property)) { + applyColor(property); + } + } + + function applyCustomStyle(customStyle) { + style = { + ...style, + ...customStyle + }; + } + + function parseCustomFileStyle (columnText) { + hasCustomFileStyle = true; + for (let csvAttribute = 1; csvAttribute < vNumCustomHeaders; csvAttribute += 1) { + let customAttribute = ''; + if (CustomArrayBasic.indexOf(columnText) < 0) { + customAttribute = 'none'; // TODO: is this used anywhere? + } else { + customAttribute = CustomArray[CustomArrayBasic.indexOf(columnText)][csvAttribute]; + } + applyProperty(customAttribute); + } + + // TODO: rework hasStyle so that defaults can be on style from start + // Apply defaults + if (!style.color) { + style.color = 'white'; + } + if (!style.fontSize) { + style.fontSize = (14 + vLetterSize) + 'px'; + } + } + + return { + getCommentColor: () => commentColor, + getStyle: () => style, + hasCustomFileStyle: () => hasCustomFileStyle, // to replace vGlobalComas and vGlobalComas2 + hasFontSize: () => !!style.fontSize, // to vGlobalFontSize (vFontSize should just grab from style object or something) + hasComments: () => hasComments, + applyStandardAttributes, + applyProperty, + applyCustomStyle, + parseCustomFileStyle + }; +} + +export default StyleBuilder;