convert row-wrapper

This commit is contained in:
Kristoffer Lind
2019-01-25 14:02:26 +01:00
parent 1c4bcbb497
commit f0121b3a75
5 changed files with 583 additions and 0 deletions

1
.gitattributes vendored
View File

@@ -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

View File

@@ -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 (
<span style={paddingStyle}></span>
);
} 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 = (
<th class = "empty" style={seperatorStyle}>*</th>
);
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 = (
<td className={'grid-cells-small' + sufixCells} style={cellStyle}>
{columnNumber}
</td>
);
} else {
cellElement = (
<td className={'grid-cells' + sufixCells} style={cellStyle}>
{columnNumber}
</td>
);
}
} else {
const cellStyle = {
fontFamily: vFontFamily,
...styleBuilder.getStyle(),
textAlign: 'right',
paddingRight: '4px'
};
if (vSpecialF.substring(vSpecialF.length - 1) == '%' && vNumMeasures > 1) {
cellElement = (
<td className={'grid-cells-small' + sufixCells} style={cellStyle}>
{columnNumber}
</td>
);
} else {
cellElement = (
<td className={'grid-cells' + sufixCells} style={cellStyle}>
{columnNumber}
</td>
);
}
}
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 = (
<tr>
<td class="fdim-cells" style={rowStyle}>
{paddingTextElement}{columnText}
</td>
{cells}
</tr>
);
rows.push(rowElement);
}
return rows;
}
}
render () {
return (
<React.Fragment>
{this.generateRows()}
</React.Fragment>
);
}
}
ElseDimensionRowList.propTypes = {};
export default ElseDimensionRowList;

130
src/row-wrapper.jsx Normal file
View File

@@ -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 (
<SingleDimensionRowList {...this.props} />
);
} else {
return (
<ElseDimensionRowList {...this.props} />
);
}
}
render () {
return (
<div className='row-wrapper'>
<table>
{this.generateDimensionRowList()}
</table>
</div>
);
}
}
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(
<RowWrapper
{...state}
{...preparedProps}
/>
);
return html;
}

View File

@@ -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 (
<span style={paddingStyle}></span>
);
} else {
return null;
}
}
// <SingleDimensionMeasures />
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 = (
<tr>
<td class="fdim-cells" style={rowStyle}>
{paddingTextElement}{columnText}
</td>
{cells}
</tr>
);
rows.push(rowElement);
}
}
return rows;
}
render () {
return (
<React.Fragment>
{this.generateRows()}
</React.Fragment>
);
}
}
SingleDimensionRowList.propTypes = {};
export default SingleDimensionRowList;

115
src/style-builder.js Normal file
View File

@@ -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 = {
'<comment>': () => { hasComments = true; },
// text
'<bold>': () => { style.fontWeight = 'bold'; },
'<italic>': () => { style.fontStyle = 'italic'; },
'<oblique>': () => { style.fontStyle = 'oblique'; },
// background and comment color
'<dark>': () => applyColor(colors.vColLibDark),
'<night>': () => applyColor(colors.vColLibNight),
'<soft>': () => applyColor(colors.vColLibSoft),
'<red>': () => applyColor(colors.vColLibRed),
'<orange>': () => applyColor(colors.vColLibOrange),
'<violete>': () => applyColor(colors.vColLibViolete),
'<blue>': () => applyColor(colors.vColLibBlue),
'<green>': () => 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?
'<white>': () => { style.color = 'white'; },
// font size
'<large>': () => { style.fontSize = (15 + vLetterSize) + 'px'; },
'<medium>': () => { style.fontSize = (14 + vLetterSize) + 'px'; },
'<small>': () => { style.fontSize = (13 + vLetterSize) + 'px'; },
// text alignment
'<center>': () => { 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;