@mwater/visualization 5.4.1 → 5.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ColorComponent.js +2 -1
- package/lib/IdSelection.d.ts +16 -0
- package/lib/IdSelection.js +59 -0
- package/lib/MWaterAddRelatedIndicatorComponent.js +2 -2
- package/lib/MWaterCompleteTableSelectComponent.d.ts +3 -8
- package/lib/MWaterCompleteTableSelectComponent.js +36 -42
- package/lib/MWaterLoaderComponent.d.ts +11 -10
- package/lib/MWaterLoaderComponent.js +1 -1
- package/lib/MWaterResponsesFilterComponent.js +1 -1
- package/lib/MWaterTableSelectComponent.d.ts +0 -1
- package/lib/MWaterTableSelectComponent.js +4 -6
- package/lib/autotranslate.d.ts +20 -0
- package/lib/autotranslate.js +122 -0
- package/lib/axes/AxisBuilder.js +3 -3
- package/lib/axes/AxisColorEditorComponent.js +4 -0
- package/lib/axes/AxisComponent.d.ts +8 -12
- package/lib/axes/AxisComponent.js +32 -80
- package/lib/axes/CategoryMapComponent.js +4 -4
- package/lib/axes/RangesComponent.js +2 -2
- package/lib/dashboards/DashboardComponent.d.ts +12 -20
- package/lib/dashboards/DashboardComponent.js +109 -69
- package/lib/dashboards/DashboardDesign.d.ts +11 -2
- package/lib/dashboards/DashboardUtils.d.ts +5 -0
- package/lib/dashboards/DashboardUtils.js +30 -0
- package/lib/dashboards/DashboardViewComponent.d.ts +2 -0
- package/lib/dashboards/DashboardViewComponent.js +16 -3
- package/lib/dashboards/ServerDashboardDataSource.js +2 -1
- package/lib/dashboards/SettingsModalComponent.d.ts +1 -1
- package/lib/dashboards/SettingsModalComponent.js +256 -19
- package/lib/dashboards/WidgetComponent.d.ts +6 -3
- package/lib/dashboards/WidgetComponent.js +3 -1
- package/lib/datagrids/CellEditor.d.ts +19 -0
- package/lib/datagrids/CellEditor.js +223 -0
- package/lib/datagrids/DatagridComponent.d.ts +18 -87
- package/lib/datagrids/DatagridComponent.js +304 -222
- package/lib/datagrids/DatagridViewComponent.d.ts +15 -53
- package/lib/datagrids/DatagridViewComponent.js +256 -257
- package/lib/datagrids/DirectDatagridDataSource.js +2 -3
- package/lib/datagrids/ExprCellComponent.d.ts +8 -15
- package/lib/datagrids/ExprCellComponent.js +11 -15
- package/lib/datagrids/FindReplaceModalComponent.d.ts +4 -6
- package/lib/datagrids/FindReplaceModalComponent.js +38 -75
- package/lib/index.css +1 -1
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -1
- package/lib/languages.js +6 -1
- package/lib/layouts/blocks/HorizontalBlockComponent.js +2 -2
- package/lib/mWaterLoader.d.ts +1 -1
- package/lib/maps/BufferLayer.d.ts +7 -5
- package/lib/maps/BufferLayer.js +69 -48
- package/lib/maps/BufferLayerDesign.d.ts +21 -14
- package/lib/maps/BufferLayerDesignerComponent.d.ts +16 -31
- package/lib/maps/BufferLayerDesignerComponent.js +68 -102
- package/lib/maps/ChoroplethLayer.d.ts +5 -4
- package/lib/maps/ChoroplethLayer.js +32 -9
- package/lib/maps/ChoroplethLayerDesign.d.ts +6 -2
- package/lib/maps/ChoroplethLayerDesigner.js +4 -2
- package/lib/maps/ClusterLayer.d.ts +3 -4
- package/lib/maps/ClusterLayer.js +2 -1
- package/lib/maps/DetailLevelSelectComponent.js +1 -1
- package/lib/maps/DirectMapDataSource.js +2 -1
- package/lib/maps/EditPopupComponent.js +5 -3
- package/lib/maps/GridLayer.d.ts +3 -4
- package/lib/maps/GridLayer.js +2 -1
- package/lib/maps/GridLayerDesigner.js +5 -3
- package/lib/maps/HoverContent.d.ts +11 -3
- package/lib/maps/HoverContent.js +25 -9
- package/lib/maps/Layer.d.ts +24 -3
- package/lib/maps/Layer.js +5 -1
- package/lib/maps/LayerFactory.js +0 -8
- package/lib/maps/LayerLegendComponent.js +0 -1
- package/lib/maps/LayerSwitcherComponent.d.ts +1 -0
- package/lib/maps/LayerSwitcherComponent.js +1 -1
- package/lib/maps/LeafletMapComponent.js +3 -1
- package/lib/maps/LegendComponent.d.ts +1 -0
- package/lib/maps/LegendComponent.js +9 -1
- package/lib/maps/MWaterServerLayer.d.ts +2 -2
- package/lib/maps/MWaterServerLayer.js +2 -2
- package/lib/maps/MapComponent.js +3 -3
- package/lib/maps/MapDesign.d.ts +2 -0
- package/lib/maps/MapDesignerComponent.d.ts +4 -3
- package/lib/maps/MapDesignerComponent.js +68 -74
- package/lib/maps/MapLayerViewDesignerComponent.js +2 -2
- package/lib/maps/MapUtils.d.ts +4 -0
- package/lib/maps/MapUtils.js +19 -0
- package/lib/maps/MapViewComponent.d.ts +8 -3
- package/lib/maps/MarkersLayer.d.ts +5 -4
- package/lib/maps/MarkersLayer.js +33 -7
- package/lib/maps/MarkersLayerDesign.d.ts +19 -16
- package/lib/maps/PopupFilterJoinsUtils.d.ts +6 -3
- package/lib/maps/PopupFilterJoinsUtils.js +0 -6
- package/lib/maps/RasterMapViewComponent.d.ts +3 -31
- package/lib/maps/RasterMapViewComponent.js +7 -2
- package/lib/maps/ServerMapDataSource.js +2 -1
- package/lib/maps/SwitchableTileUrlLayer.d.ts +3 -3
- package/lib/maps/SwitchableTileUrlLayer.js +2 -1
- package/lib/maps/TileUrlLayer.d.ts +4 -5
- package/lib/maps/TileUrlLayer.js +2 -1
- package/lib/maps/VectorMapViewComponent.d.ts +5 -37
- package/lib/maps/VectorMapViewComponent.js +19 -8
- package/lib/maps/maps.d.ts +3 -0
- package/lib/quickfilter/Quickfilter.d.ts +2 -0
- package/lib/quickfilter/QuickfiltersComponent.d.ts +2 -0
- package/lib/quickfilter/QuickfiltersComponent.js +9 -7
- package/lib/quickfilter/QuickfiltersDesignComponent.d.ts +5 -30
- package/lib/quickfilter/QuickfiltersDesignComponent.js +56 -63
- package/lib/richtext/ExprItemsHtmlConverter.d.ts +5 -2
- package/lib/richtext/ExprItemsHtmlConverter.js +4 -4
- package/lib/richtext/ExprItemsTranslator.d.ts +5 -0
- package/lib/richtext/ExprItemsTranslator.js +149 -0
- package/lib/richtext/ItemsHtmlConverter.d.ts +1 -1
- package/lib/richtext/ItemsHtmlConverter.js +31 -15
- package/lib/wellknown.js +12 -9
- package/lib/widgets/IFrameWidget.d.ts +4 -4
- package/lib/widgets/ImageWidget.d.ts +7 -4
- package/lib/widgets/ImageWidget.js +9 -1
- package/lib/widgets/ImageWidgetComponent.d.ts +1 -0
- package/lib/widgets/ImageWidgetComponent.js +1 -1
- package/lib/widgets/MapWidget.d.ts +5 -48
- package/lib/widgets/MapWidget.js +26 -63
- package/lib/widgets/MarkdownWidget.d.ts +3 -0
- package/lib/widgets/MarkdownWidget.js +3 -0
- package/lib/widgets/TOCWidget.d.ts +15 -27
- package/lib/widgets/TOCWidget.js +107 -183
- package/lib/widgets/Widget.d.ts +18 -7
- package/lib/widgets/Widget.js +4 -0
- package/lib/widgets/WidgetScopesViewComponent.js +1 -1
- package/lib/widgets/charts/Chart.d.ts +10 -1
- package/lib/widgets/charts/Chart.js +22 -11
- package/lib/widgets/charts/ChartViewComponent.d.ts +4 -0
- package/lib/widgets/charts/ChartViewComponent.js +6 -3
- package/lib/widgets/charts/ChartWidget.d.ts +2 -0
- package/lib/widgets/charts/ChartWidget.js +9 -1
- package/lib/widgets/charts/ChartWidgetComponent.d.ts +4 -0
- package/lib/widgets/charts/ChartWidgetComponent.js +2 -2
- package/lib/widgets/charts/calendar/CalendarChart.d.ts +1 -0
- package/lib/widgets/charts/calendar/CalendarChart.js +26 -0
- package/lib/widgets/charts/calendar/CalendarChartViewComponent.js +3 -1
- package/lib/widgets/charts/imagemosaic/ImageMosaicChart.d.ts +1 -0
- package/lib/widgets/charts/imagemosaic/ImageMosaicChart.js +8 -0
- package/lib/widgets/charts/layered/LayeredChart.d.ts +2 -0
- package/lib/widgets/charts/layered/LayeredChart.js +63 -3
- package/lib/widgets/charts/layered/LayeredChartCompiler.d.ts +1 -1
- package/lib/widgets/charts/layered/LayeredChartCompiler.js +1 -1
- package/lib/widgets/charts/layered/LayeredChartDesignerComponent.js +2 -2
- package/lib/widgets/charts/layered/LayeredChartViewComponent.js +8 -3
- package/lib/widgets/charts/pivot/PivotChart.d.ts +1 -0
- package/lib/widgets/charts/pivot/PivotChart.js +63 -0
- package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +1 -1
- package/lib/widgets/charts/pivot/SegmentDesignerComponent.js +7 -4
- package/lib/widgets/charts/table/OrderingsComponent.js +1 -1
- package/lib/widgets/charts/table/TableChart.d.ts +1 -0
- package/lib/widgets/charts/table/TableChart.js +15 -0
- package/lib/widgets/text/TextComponent.d.ts +11 -4
- package/lib/widgets/text/TextComponent.js +11 -8
- package/lib/widgets/text/TextWidget.d.ts +6 -3
- package/lib/widgets/text/TextWidget.js +7 -1
- package/lib/widgets/text/TextWidgetComponent.d.ts +4 -0
- package/lib/widgets/text/TextWidgetComponent.js +7 -1
- package/lib/widgets/text/TextWidgetDesign.d.ts +2 -4
- package/lib/widgets/text/TextWidgetDesign.js +1 -1
- package/package.json +7 -8
- package/src/ColorComponent.tsx +1 -2
- package/src/IdSelection.ts +62 -0
- package/src/MWaterAddRelatedIndicatorComponent.ts +3 -2
- package/src/MWaterCompleteTableSelectComponent.tsx +36 -46
- package/src/MWaterLoaderComponent.ts +28 -26
- package/src/MWaterResponsesFilterComponent.ts +5 -2
- package/src/MWaterTableSelectComponent.tsx +5 -9
- package/src/autotranslate.ts +141 -0
- package/src/axes/AxisBuilder.ts +3 -3
- package/src/axes/AxisColorEditorComponent.tsx +5 -0
- package/src/axes/{AxisComponent.ts → AxisComponent.tsx} +106 -106
- package/src/axes/CategoryMapComponent.ts +4 -4
- package/src/axes/RangesComponent.ts +3 -2
- package/src/dashboards/DashboardComponent.tsx +189 -125
- package/src/dashboards/DashboardDesign.ts +9 -2
- package/src/dashboards/DashboardUtils.ts +39 -0
- package/src/dashboards/DashboardViewComponent.tsx +22 -3
- package/src/dashboards/ServerDashboardDataSource.ts +2 -1
- package/src/dashboards/SettingsModalComponent.tsx +450 -35
- package/src/dashboards/WidgetComponent.tsx +12 -6
- package/src/datagrids/CellEditor.tsx +354 -0
- package/src/datagrids/DatagridComponent.tsx +646 -0
- package/src/datagrids/DatagridViewComponent.tsx +539 -0
- package/src/datagrids/DirectDatagridDataSource.ts +2 -3
- package/src/datagrids/{ExprCellComponent.ts → ExprCellComponent.tsx} +28 -23
- package/src/datagrids/{FindReplaceModalComponent.ts → FindReplaceModalComponent.tsx} +109 -122
- package/src/index.css +1 -1
- package/src/index.ts +0 -1
- package/src/languages.ts +6 -1
- package/src/layouts/blocks/HorizontalBlockComponent.ts +2 -2
- package/src/mWaterLoader.ts +1 -1
- package/src/maps/BufferLayer.ts +83 -60
- package/src/maps/BufferLayerDesign.ts +20 -14
- package/src/maps/BufferLayerDesignerComponent.tsx +309 -0
- package/src/maps/ChoroplethLayer.ts +40 -19
- package/src/maps/ChoroplethLayerDesign.ts +4 -2
- package/src/maps/ChoroplethLayerDesigner.tsx +4 -2
- package/src/maps/ClusterLayer.ts +4 -10
- package/src/maps/DetailLevelSelectComponent.ts +1 -1
- package/src/maps/DirectMapDataSource.ts +2 -1
- package/src/maps/EditPopupComponent.ts +7 -3
- package/src/maps/GridLayer.ts +4 -10
- package/src/maps/GridLayerDesigner.tsx +5 -3
- package/src/maps/HoverContent.tsx +40 -16
- package/src/maps/Layer.ts +28 -10
- package/src/maps/LayerFactory.ts +0 -8
- package/src/maps/LayerLegendComponent.ts +2 -4
- package/src/maps/LayerSwitcherComponent.tsx +6 -2
- package/src/maps/LeafletMapComponent.tsx +3 -1
- package/src/maps/LegendComponent.tsx +10 -1
- package/src/maps/MWaterServerLayer.ts +3 -3
- package/src/maps/MapComponent.ts +3 -3
- package/src/maps/MapDesign.ts +3 -0
- package/src/maps/MapDesignerComponent.tsx +165 -162
- package/src/maps/MapLayerViewDesignerComponent.ts +2 -2
- package/src/maps/MapUtils.ts +24 -0
- package/src/maps/MapViewComponent.tsx +11 -3
- package/src/maps/MarkersLayer.ts +44 -18
- package/src/maps/MarkersLayerDesign.ts +19 -16
- package/src/maps/PopupFilterJoinsUtils.ts +6 -2
- package/src/maps/RasterMapViewComponent.ts +9 -45
- package/src/maps/ServerMapDataSource.ts +2 -2
- package/src/maps/SwitchableTileUrlLayer.tsx +4 -10
- package/src/maps/TileUrlLayer.tsx +4 -10
- package/src/maps/VectorMapViewComponent.tsx +28 -55
- package/src/maps/maps.ts +3 -0
- package/src/quickfilter/Quickfilter.ts +3 -0
- package/src/quickfilter/QuickfiltersComponent.ts +13 -7
- package/src/quickfilter/QuickfiltersDesignComponent.tsx +127 -128
- package/src/richtext/ExprItemsHtmlConverter.ts +9 -5
- package/src/richtext/ExprItemsTranslator.ts +176 -0
- package/src/richtext/ItemsHtmlConverter.ts +33 -18
- package/src/wellknown.ts +33 -30
- package/src/widgets/ImageWidget.ts +10 -1
- package/src/widgets/ImageWidgetComponent.ts +3 -2
- package/src/widgets/{MapWidget.ts → MapWidget.tsx} +90 -101
- package/src/widgets/MarkdownWidget.ts +3 -0
- package/src/widgets/TOCWidget.tsx +281 -0
- package/src/widgets/Widget.ts +25 -5
- package/src/widgets/WidgetScopesViewComponent.ts +2 -1
- package/src/widgets/charts/Chart.ts +31 -12
- package/src/widgets/charts/ChartViewComponent.ts +13 -3
- package/src/widgets/charts/ChartWidget.ts +11 -1
- package/src/widgets/charts/ChartWidgetComponent.tsx +9 -1
- package/src/widgets/charts/calendar/CalendarChart.ts +29 -0
- package/src/widgets/charts/calendar/CalendarChartViewComponent.tsx +3 -1
- package/src/widgets/charts/imagemosaic/ImageMosaicChart.ts +9 -0
- package/src/widgets/charts/layered/LayeredChart.ts +71 -3
- package/src/widgets/charts/layered/LayeredChartCompiler.ts +2 -2
- package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +4 -2
- package/src/widgets/charts/layered/LayeredChartViewComponent.ts +10 -4
- package/src/widgets/charts/pivot/PivotChart.ts +73 -0
- package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +1 -1
- package/src/widgets/charts/pivot/SegmentDesignerComponent.tsx +6 -4
- package/src/widgets/charts/table/OrderingsComponent.tsx +2 -1
- package/src/widgets/charts/table/TableChart.ts +17 -0
- package/src/widgets/text/TextComponent.tsx +22 -12
- package/src/widgets/text/TextWidget.ts +9 -2
- package/src/widgets/text/TextWidgetComponent.tsx +16 -1
- package/src/widgets/text/TextWidgetDesign.ts +4 -7
- package/test/IdSelectionTests.ts +54 -0
- package/test/LayeredChartCompilerTests.ts +0 -2
- package/test/richtext/ExprItemsTranslatorTests.ts +144 -0
- package/test/wellknownTests.ts +144 -0
- package/src/datagrids/DatagridComponent.ts +0 -478
- package/src/datagrids/DatagridViewComponent.ts +0 -464
- package/src/datagrids/EditExprCellComponent.tsx +0 -305
- package/src/datagrids/README.md +0 -3
- package/src/maps/BufferLayerDesignerComponent.ts +0 -311
- package/src/widgets/TOCWidget.ts +0 -326
- package/test/LegoLayoutEngineTests.ts +0 -69
|
@@ -473,7 +473,7 @@ export default class LayeredChartCompiler {
|
|
|
473
473
|
}
|
|
474
474
|
|
|
475
475
|
// Compiles data for a polar chart (pie/donut) with no x axis
|
|
476
|
-
compileDataPolar(design: LayeredChartDesign, data: C3ChartData, locale
|
|
476
|
+
compileDataPolar(design: LayeredChartDesign, data: C3ChartData, locale?: string): C3Data {
|
|
477
477
|
let order: "asc" | "desc" | null
|
|
478
478
|
const columns: any = []
|
|
479
479
|
const types: { [key: string]: ChartTypes } = {}
|
|
@@ -670,7 +670,7 @@ export default class LayeredChartCompiler {
|
|
|
670
670
|
const trendlineSeries = seriesY + ":trendline"
|
|
671
671
|
columns.push([trendlineSeries].concat(calculateLinearRegression(yValues, xValues)))
|
|
672
672
|
types[trendlineSeries] = line ? line() : "line"
|
|
673
|
-
names[trendlineSeries] = names[seriesY] + T`
|
|
673
|
+
names[trendlineSeries] = names[seriesY] + " " + T`Trendline`
|
|
674
674
|
xs[trendlineSeries] = seriesX
|
|
675
675
|
colors[trendlineSeries] = layer.color || defaultColors[layerIndex]
|
|
676
676
|
legendHide.push(trendlineSeries) // Hide in legend
|
|
@@ -270,7 +270,8 @@ export default class LayeredChartDesignerComponent extends React.Component<Layer
|
|
|
270
270
|
"button",
|
|
271
271
|
{ className: "btn btn-link", type: "button", onClick: this.handleAddLayer },
|
|
272
272
|
R("span", { className: "fas fa-plus" }),
|
|
273
|
-
|
|
273
|
+
" ",
|
|
274
|
+
T`Add Another Series`
|
|
274
275
|
)
|
|
275
276
|
: undefined
|
|
276
277
|
)
|
|
@@ -481,7 +482,8 @@ class ThresholdsComponent extends React.Component<{
|
|
|
481
482
|
"button",
|
|
482
483
|
{ type: "button", className: "btn btn-sm btn-link", onClick: this.handleAdd },
|
|
483
484
|
R("i", { className: "fa fa-plus" }),
|
|
484
|
-
|
|
485
|
+
" ",
|
|
486
|
+
T`Add Y Threshold`
|
|
485
487
|
)
|
|
486
488
|
)
|
|
487
489
|
}
|
|
@@ -105,7 +105,8 @@ export default class LayeredChartViewComponent extends React.Component<
|
|
|
105
105
|
schema: this.props.schema,
|
|
106
106
|
dataSource: this.props.dataSource,
|
|
107
107
|
exprValues: this.props.data.header || {},
|
|
108
|
-
width: this.props.width
|
|
108
|
+
width: this.props.width,
|
|
109
|
+
locale: this.context
|
|
109
110
|
})
|
|
110
111
|
)
|
|
111
112
|
}
|
|
@@ -125,7 +126,8 @@ export default class LayeredChartViewComponent extends React.Component<
|
|
|
125
126
|
schema: this.props.schema,
|
|
126
127
|
dataSource: this.props.dataSource,
|
|
127
128
|
exprValues: this.props.data.footer || {},
|
|
128
|
-
width: this.props.width
|
|
129
|
+
width: this.props.width,
|
|
130
|
+
locale: this.context
|
|
129
131
|
})
|
|
130
132
|
)
|
|
131
133
|
}
|
|
@@ -171,7 +173,7 @@ interface C3ChartComponentProps {
|
|
|
171
173
|
class C3ChartComponent extends React.Component<C3ChartComponentProps> {
|
|
172
174
|
throttledCreateChart: ((props: C3ChartComponentProps) => any) & _.Cancelable
|
|
173
175
|
chart: any
|
|
174
|
-
chartDiv:
|
|
176
|
+
chartDiv: HTMLDivElement | null
|
|
175
177
|
|
|
176
178
|
constructor(props: C3ChartComponentProps) {
|
|
177
179
|
super(props)
|
|
@@ -190,6 +192,10 @@ class C3ChartComponent extends React.Component<C3ChartComponentProps> {
|
|
|
190
192
|
this.chart.destroy()
|
|
191
193
|
}
|
|
192
194
|
|
|
195
|
+
if (!this.chartDiv) {
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
|
|
193
199
|
const compiler = new LayeredChartCompiler({ schema: props.schema })
|
|
194
200
|
const chartOptions: any = compiler.createChartOptions({
|
|
195
201
|
design: this.props.design,
|
|
@@ -531,7 +537,7 @@ class C3ChartComponent extends React.Component<C3ChartComponentProps> {
|
|
|
531
537
|
|
|
532
538
|
return R("div", {
|
|
533
539
|
ref: c => {
|
|
534
|
-
|
|
540
|
+
this.chartDiv = c
|
|
535
541
|
}
|
|
536
542
|
})
|
|
537
543
|
}
|
|
@@ -14,6 +14,7 @@ import PivotChartLayoutBuilder from "./PivotChartLayoutBuilder"
|
|
|
14
14
|
import { WidgetDataSource } from "../../WidgetDataSource"
|
|
15
15
|
import { PivotChartDesign, PivotChartSegment } from "./PivotChartDesign"
|
|
16
16
|
import { JsonQLFilter } from "../../../JsonQLFilter"
|
|
17
|
+
import { translateHtmlItems } from "../../../richtext/ExprItemsTranslator"
|
|
17
18
|
|
|
18
19
|
// Store true as a weakly cached value if a design is already clean
|
|
19
20
|
const cleanDesignCache = new WeakCache()
|
|
@@ -422,4 +423,76 @@ export default class PivotChart extends Chart {
|
|
|
422
423
|
getPlaceholderIcon() {
|
|
423
424
|
return "fa-magic"
|
|
424
425
|
}
|
|
426
|
+
|
|
427
|
+
translateDesign(design: PivotChartDesign, translate: (input: string) => string) {
|
|
428
|
+
return produce(design, draft => {
|
|
429
|
+
// Helper function to translate a segment and its children
|
|
430
|
+
const translateSegment = (segment: PivotChartSegment) => {
|
|
431
|
+
// Translate segment label
|
|
432
|
+
if (segment.label) {
|
|
433
|
+
segment.label = translate(segment.label)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Translate value axis labels
|
|
437
|
+
if (segment.valueAxis?.categoryLabels) {
|
|
438
|
+
for (const key in segment.valueAxis.categoryLabels) {
|
|
439
|
+
segment.valueAxis.categoryLabels[key] = translate(segment.valueAxis.categoryLabels[key])
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Translate null label
|
|
444
|
+
if (segment.valueAxis?.nullLabel) {
|
|
445
|
+
segment.valueAxis.nullLabel = translate(segment.valueAxis.nullLabel)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Recursively translate children
|
|
449
|
+
if (segment.children) {
|
|
450
|
+
segment.children.forEach(translateSegment)
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Translate all row segments
|
|
455
|
+
draft.rows.forEach(translateSegment)
|
|
456
|
+
|
|
457
|
+
// Translate all column segments
|
|
458
|
+
draft.columns.forEach(translateSegment)
|
|
459
|
+
|
|
460
|
+
// Translate all intersections
|
|
461
|
+
for (const intersection of Object.values(draft.intersections)) {
|
|
462
|
+
// Translate value axis labels
|
|
463
|
+
if (intersection.valueAxis?.categoryLabels) {
|
|
464
|
+
for (const key in intersection.valueAxis.categoryLabels) {
|
|
465
|
+
intersection.valueAxis.categoryLabels[key] = translate(intersection.valueAxis.categoryLabels[key])
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Translate null label
|
|
470
|
+
if (intersection.valueAxis?.nullLabel) {
|
|
471
|
+
intersection.valueAxis.nullLabel = translate(intersection.valueAxis.nullLabel)
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Translate segment value axis override labels
|
|
475
|
+
if (intersection.segmentValueAxisOverrides) {
|
|
476
|
+
for (const axis of Object.values(intersection.segmentValueAxisOverrides)) {
|
|
477
|
+
if (axis?.categoryLabels) {
|
|
478
|
+
for (const key in axis.categoryLabels) {
|
|
479
|
+
axis.categoryLabels[key] = translate(axis.categoryLabels[key])
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
if (axis?.nullLabel) {
|
|
483
|
+
axis.nullLabel = translate(axis.nullLabel)
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Translate header and footer using ExprItemsTranslator
|
|
490
|
+
if (draft.header?.items) {
|
|
491
|
+
draft.header.items = translateHtmlItems(draft.header.items, translate)
|
|
492
|
+
}
|
|
493
|
+
if (draft.footer?.items) {
|
|
494
|
+
draft.footer.items = translateHtmlItems(draft.footer.items, translate)
|
|
495
|
+
}
|
|
496
|
+
})
|
|
497
|
+
}
|
|
425
498
|
}
|
|
@@ -393,7 +393,7 @@ class LayoutCellComponent extends React.Component<LayoutCellComponentProps> {
|
|
|
393
393
|
R("a", { className: "link-plain", onClick: this.props.onEditSection }, T`Edit`),
|
|
394
394
|
cell.summarize
|
|
395
395
|
? [
|
|
396
|
-
R("span", { className: "text-muted" },
|
|
396
|
+
R("span", { className: "text-muted" }, ` / `),
|
|
397
397
|
R("a", { className: "link-plain", onClick: this.props.onSummarizeSegment }, T`Summarize`)
|
|
398
398
|
]
|
|
399
399
|
: undefined
|
|
@@ -95,13 +95,15 @@ export default class SegmentDesignerComponent extends React.Component<
|
|
|
95
95
|
<ui.Radio key="single" value={this.state.mode} radioValue={"single"} onChange={this.handleMode}>
|
|
96
96
|
{T`Single ${this.props.segmentType}`}
|
|
97
97
|
<span className="text-muted">
|
|
98
|
-
{
|
|
98
|
+
{` - `}
|
|
99
|
+
{T`used for summary ${this.props.segmentType}s and empty ${this.props.segmentType}s`}
|
|
99
100
|
</span>
|
|
100
101
|
</ui.Radio>,
|
|
101
102
|
|
|
102
103
|
<ui.Radio key="multiple" value={this.state.mode} radioValue={"multiple"} onChange={this.handleMode}>
|
|
103
104
|
{T`Multiple ${this.props.segmentType}s`}
|
|
104
|
-
|
|
105
|
+
{" - "}
|
|
106
|
+
<span className="text-muted">{T`disaggregate data by a field`}</span>
|
|
105
107
|
</ui.Radio>
|
|
106
108
|
)
|
|
107
109
|
}
|
|
@@ -170,7 +172,7 @@ export default class SegmentDesignerComponent extends React.Component<
|
|
|
170
172
|
ui.FormGroup,
|
|
171
173
|
{
|
|
172
174
|
labelMuted: true,
|
|
173
|
-
label: [R(ui.Icon, { id: "glyphicon-filter" }), T`
|
|
175
|
+
label: [R(ui.Icon, { id: "glyphicon-filter" }), " ", T`Filters`],
|
|
174
176
|
hint: T`Filters all data associated with this ${this.props.segmentType}`
|
|
175
177
|
},
|
|
176
178
|
R(FilterExprComponent, {
|
|
@@ -265,7 +267,7 @@ export default class SegmentDesignerComponent extends React.Component<
|
|
|
265
267
|
ui.FormGroup,
|
|
266
268
|
{
|
|
267
269
|
labelMuted: true,
|
|
268
|
-
label: [R(ui.Icon, { id: "fa-sort-amount-asc" }), T`
|
|
270
|
+
label: [R(ui.Icon, { id: "fa-sort-amount-asc" }), " ", T`Sort`],
|
|
269
271
|
hint: T`Sorts the display of this ${this.props.segmentType}`
|
|
270
272
|
},
|
|
271
273
|
R(ExprComponent, {
|
|
@@ -56,7 +56,8 @@ export default class OrderingsComponent extends React.Component<OrderingsCompone
|
|
|
56
56
|
"button",
|
|
57
57
|
{ type: "button", className: "btn btn-sm btn-secondary", onClick: this.handleAdd, key: "add" },
|
|
58
58
|
R("span", { className: "fas fa-plus" }),
|
|
59
|
-
|
|
59
|
+
" ",
|
|
60
|
+
T`Add Ordering`
|
|
60
61
|
)
|
|
61
62
|
)
|
|
62
63
|
}
|
|
@@ -431,4 +431,21 @@ export default class TableChart extends Chart {
|
|
|
431
431
|
getPlaceholderIcon() {
|
|
432
432
|
return "fa-table"
|
|
433
433
|
}
|
|
434
|
+
|
|
435
|
+
translateDesign(design: TableChartDesign, translate: (input: string) => string) {
|
|
436
|
+
return produce(design, draft => {
|
|
437
|
+
// Translate title text
|
|
438
|
+
if (draft.titleText) {
|
|
439
|
+
draft.titleText = translate(draft.titleText)
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Translate column headers and axis labels
|
|
443
|
+
for (const column of draft.columns) {
|
|
444
|
+
// Translate header text
|
|
445
|
+
if (column.headerText) {
|
|
446
|
+
column.headerText = translate(column.headerText)
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
})
|
|
450
|
+
}
|
|
434
451
|
}
|
|
@@ -3,18 +3,22 @@ import _ from "lodash"
|
|
|
3
3
|
import RichTextComponent from "../../richtext/RichTextComponent"
|
|
4
4
|
import ExprInsertModalComponent from "./ExprInsertModalComponent"
|
|
5
5
|
import ExprUpdateModalComponent from "./ExprUpdateModalComponent"
|
|
6
|
-
import ExprItemsHtmlConverter from "../../richtext/ExprItemsHtmlConverter"
|
|
6
|
+
import ExprItemsHtmlConverter, { HtmlItemExpr, HtmlItemOrExpr } from "../../richtext/ExprItemsHtmlConverter"
|
|
7
7
|
import { TextWidgetDesign } from "./TextWidgetDesign"
|
|
8
8
|
import { DataSource, Schema } from "@mwater/expressions"
|
|
9
9
|
import { LocaleContext } from "@mwater/expressions-ui"
|
|
10
10
|
|
|
11
11
|
export interface TextComponentProps {
|
|
12
12
|
design: TextWidgetDesign
|
|
13
|
+
|
|
14
|
+
/** Called when design changes. If not set, will be in display mode, otherwise in edit mode */
|
|
13
15
|
onDesignChange?: (design: TextWidgetDesign) => void
|
|
14
16
|
schema: Schema
|
|
15
17
|
dataSource: DataSource
|
|
18
|
+
|
|
16
19
|
/** Expression values */
|
|
17
20
|
exprValues: { [key: string]: any }
|
|
21
|
+
|
|
18
22
|
width?: number
|
|
19
23
|
height?: number
|
|
20
24
|
|
|
@@ -23,10 +27,15 @@ export interface TextComponentProps {
|
|
|
23
27
|
|
|
24
28
|
/** Optional lookup of string name to value. Used for {{branding}} and other replacement strings in text widget */
|
|
25
29
|
namedStrings?: { [key: string]: string }
|
|
30
|
+
|
|
31
|
+
/** Locale to use for display */
|
|
32
|
+
locale: string
|
|
26
33
|
}
|
|
27
34
|
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Text component which is provided with the data it needs, rather than loading it.
|
|
37
|
+
* Used by TextWidgetComponent and also by other components that embed text fields
|
|
38
|
+
*/
|
|
30
39
|
export default class TextComponent extends React.Component<TextComponentProps> {
|
|
31
40
|
static contextType = LocaleContext
|
|
32
41
|
exprInsertModal: ExprInsertModalComponent | null = null
|
|
@@ -38,7 +47,7 @@ export default class TextComponent extends React.Component<TextComponentProps> {
|
|
|
38
47
|
this.props.schema,
|
|
39
48
|
this.props.onDesignChange != null,
|
|
40
49
|
this.props.exprValues,
|
|
41
|
-
// Display summaries if in design
|
|
50
|
+
// Display summaries if in design mode and singleRowTable is set
|
|
42
51
|
this.props.onDesignChange != null && this.props.singleRowTable != null,
|
|
43
52
|
// Only replace named strings if not editing
|
|
44
53
|
this.props.onDesignChange == null ? this.props.namedStrings : undefined,
|
|
@@ -46,12 +55,12 @@ export default class TextComponent extends React.Component<TextComponentProps> {
|
|
|
46
55
|
)
|
|
47
56
|
}
|
|
48
57
|
|
|
49
|
-
handleItemsChange = (items:
|
|
58
|
+
handleItemsChange = (items: HtmlItemOrExpr[]) => {
|
|
50
59
|
const design = { ...this.props.design, items }
|
|
51
60
|
return this.props.onDesignChange!(design)
|
|
52
61
|
}
|
|
53
62
|
|
|
54
|
-
handleInsertExpr = (item:
|
|
63
|
+
handleInsertExpr = (item: HtmlItemExpr) => {
|
|
55
64
|
const html = '<div data-embed="' + _.escape(JSON.stringify(item)) + '"></div>'
|
|
56
65
|
|
|
57
66
|
return this.editor!.pasteHTML(html)
|
|
@@ -70,26 +79,27 @@ export default class TextComponent extends React.Component<TextComponentProps> {
|
|
|
70
79
|
})
|
|
71
80
|
|
|
72
81
|
const items = replaceItemInItems(this.props.design.items || [], item)
|
|
73
|
-
|
|
82
|
+
this.props.onDesignChange!({ ...this.props.design, items })
|
|
74
83
|
}
|
|
75
84
|
|
|
76
|
-
handleItemClick = (item:
|
|
77
|
-
|
|
85
|
+
handleItemClick = (item: HtmlItemExpr) => {
|
|
86
|
+
this.exprUpdateModal!.open(item, (item) => {
|
|
78
87
|
// Replace in items
|
|
79
|
-
|
|
88
|
+
this.replaceItem(item)
|
|
80
89
|
})
|
|
81
90
|
}
|
|
82
91
|
|
|
83
92
|
handleAddExpr = (ev: React.MouseEvent<HTMLDivElement>) => {
|
|
84
93
|
ev.preventDefault()
|
|
85
|
-
|
|
94
|
+
this.exprInsertModal!.open()
|
|
86
95
|
}
|
|
87
96
|
|
|
88
97
|
renderExtraPaletteButtons() {
|
|
89
98
|
return (
|
|
90
99
|
<div key="expr" className="mwater-visualization-text-palette-item" onMouseDown={this.handleAddExpr}>
|
|
91
100
|
<i className="fa fa-plus" />
|
|
92
|
-
{
|
|
101
|
+
{" "}
|
|
102
|
+
{T`Expression`}
|
|
93
103
|
</div>
|
|
94
104
|
)
|
|
95
105
|
}
|
|
@@ -12,6 +12,7 @@ import { JsonQLSelectQuery } from "@mwater/jsonql"
|
|
|
12
12
|
import { HtmlItem } from "../../richtext/ItemsHtmlConverter"
|
|
13
13
|
import { HtmlItemExpr } from "../../richtext/ExprItemsHtmlConverter"
|
|
14
14
|
import { TextWidgetDesign } from "./TextWidgetDesign"
|
|
15
|
+
import { getHtmlItemsStrings } from "../../richtext/ExprItemsTranslator"
|
|
15
16
|
|
|
16
17
|
export default class TextWidget extends Widget {
|
|
17
18
|
// Creates a React element that is a view of the widget
|
|
@@ -44,7 +45,9 @@ export default class TextWidget extends Widget {
|
|
|
44
45
|
singleRowTable: options.singleRowTable,
|
|
45
46
|
namedStrings: options.namedStrings,
|
|
46
47
|
ref: options.widgetRef,
|
|
47
|
-
refreshKey: options.refreshKey
|
|
48
|
+
refreshKey: options.refreshKey,
|
|
49
|
+
locale: options.locale,
|
|
50
|
+
translate: options.translate
|
|
48
51
|
})
|
|
49
52
|
}
|
|
50
53
|
|
|
@@ -191,7 +194,7 @@ export default class TextWidget extends Widget {
|
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
// Get expression items recursively
|
|
194
|
-
getExprItems(items
|
|
197
|
+
getExprItems(items?: HtmlItem[]): HtmlItemExpr[] {
|
|
195
198
|
let exprItems: any[] = []
|
|
196
199
|
for (let item of items || []) {
|
|
197
200
|
if ((item as any).type === "expr") {
|
|
@@ -267,4 +270,8 @@ export default class TextWidget extends Widget {
|
|
|
267
270
|
|
|
268
271
|
return entries
|
|
269
272
|
}
|
|
273
|
+
|
|
274
|
+
getTranslatableStrings(design: TextWidgetDesign, schema: Schema): string[] {
|
|
275
|
+
return getHtmlItemsStrings(design.items || [])
|
|
276
|
+
}
|
|
270
277
|
}
|
|
@@ -13,6 +13,7 @@ import ActionCancelModalComponent from "@mwater/react-library/lib/ActionCancelMo
|
|
|
13
13
|
import { FormGroup } from "@mwater/react-library/lib/bootstrap"
|
|
14
14
|
import ColorComponent from "../../ColorComponent"
|
|
15
15
|
import { Select } from "@mwater/react-library/lib/bootstrap"
|
|
16
|
+
import { translateHtmlItems } from "../../richtext/ExprItemsTranslator"
|
|
16
17
|
|
|
17
18
|
export interface TextWidgetComponentProps {
|
|
18
19
|
design: TextWidgetDesign
|
|
@@ -28,8 +29,15 @@ export interface TextWidgetComponentProps {
|
|
|
28
29
|
/** Table that is filtered to have one row */
|
|
29
30
|
singleRowTable?: string
|
|
30
31
|
namedStrings?: any
|
|
32
|
+
|
|
31
33
|
/** A key that changes when the widget should be refreshed */
|
|
32
34
|
refreshKey?: any
|
|
35
|
+
|
|
36
|
+
/** Locale to use for display */
|
|
37
|
+
locale: string
|
|
38
|
+
|
|
39
|
+
/** Translate function to use for display. Returns same string when editing. */
|
|
40
|
+
translate: (input: string) => string
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
// Widget which displays styled text with embedded expressions
|
|
@@ -200,9 +208,15 @@ export default class TextWidgetComponent extends AsyncLoadComponent<TextWidgetCo
|
|
|
200
208
|
|
|
201
209
|
const padding = this.props.design.padding ?? 0
|
|
202
210
|
|
|
211
|
+
// Translate items if needed
|
|
212
|
+
const translatedDesign = this.props.onDesignChange ? this.props.design : {
|
|
213
|
+
...this.props.design,
|
|
214
|
+
items: translateHtmlItems(this.props.design.items || [], this.props.translate)
|
|
215
|
+
}
|
|
216
|
+
|
|
203
217
|
return (
|
|
204
218
|
<TextComponent
|
|
205
|
-
design={
|
|
219
|
+
design={translatedDesign}
|
|
206
220
|
onDesignChange={this.props.onDesignChange}
|
|
207
221
|
schema={this.props.schema}
|
|
208
222
|
dataSource={this.props.dataSource}
|
|
@@ -211,6 +225,7 @@ export default class TextWidgetComponent extends AsyncLoadComponent<TextWidgetCo
|
|
|
211
225
|
height={this.props.height ? this.props.height - padding * 2 : undefined}
|
|
212
226
|
singleRowTable={this.props.singleRowTable}
|
|
213
227
|
namedStrings={this.props.namedStrings}
|
|
228
|
+
locale={this.props.locale}
|
|
214
229
|
/>
|
|
215
230
|
)
|
|
216
231
|
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { HtmlItem } from "../../richtext/ItemsHtmlConverter"
|
|
3
|
-
|
|
4
|
-
export type TextWidgetItem = HtmlItem | HtmlItemExpr
|
|
1
|
+
import { HtmlItemOrExpr } from "../../richtext/ExprItemsHtmlConverter"
|
|
5
2
|
|
|
6
3
|
export interface TextWidgetDesign {
|
|
7
4
|
/** Text widget stores its content as array of items. See ItemsHtmlConverter TODO */
|
|
8
|
-
items
|
|
5
|
+
items?: HtmlItemOrExpr[]
|
|
9
6
|
|
|
10
7
|
/** "title" for title block. default is "default" */
|
|
11
8
|
style?: "title" | "default" | "header" | "footer"
|
|
@@ -29,5 +26,5 @@ export interface TextWidgetDesign {
|
|
|
29
26
|
|
|
30
27
|
/** Returns true if the text widget design is empty. */
|
|
31
28
|
export function isEmptyTextWidgetDesign(design: TextWidgetDesign | undefined): boolean {
|
|
32
|
-
return design == null || design.items.length === 0
|
|
33
|
-
}
|
|
29
|
+
return design == null || (design.items != null && design.items.length === 0)
|
|
30
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { assert } from "chai"
|
|
2
|
+
import IdSelection from "../src/IdSelection"
|
|
3
|
+
|
|
4
|
+
describe("IdSelection", function () {
|
|
5
|
+
beforeEach(function(this: any) {
|
|
6
|
+
this.sel = new IdSelection()
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
it("adds id", function(this: any) {
|
|
10
|
+
const sel = this.sel.add("1")
|
|
11
|
+
assert.isTrue(sel.isSelected("1"))
|
|
12
|
+
assert.isFalse(sel.isSelected("2"))
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it("removes id", function(this: any) {
|
|
16
|
+
let sel = this.sel.add("1")
|
|
17
|
+
sel = sel.remove("1")
|
|
18
|
+
assert.isFalse(sel.isSelected("1"))
|
|
19
|
+
assert.isFalse(sel.isSelected("2"))
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it("toggles id", function(this: any) {
|
|
23
|
+
let sel = this.sel.toggle("1")
|
|
24
|
+
assert.isTrue(sel.isSelected("1"))
|
|
25
|
+
sel = sel.toggle("1")
|
|
26
|
+
assert.isFalse(sel.isSelected("1"))
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it("inverts", function(this: any) {
|
|
30
|
+
let sel = this.sel.add("1")
|
|
31
|
+
sel = sel.invert()
|
|
32
|
+
assert.isTrue(sel.isSelected("2"))
|
|
33
|
+
assert.isFalse(sel.isSelected("1"))
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("adds in inverts", function(this: any) {
|
|
37
|
+
let sel = this.sel.add("1")
|
|
38
|
+
sel = sel.invert()
|
|
39
|
+
sel = sel.add("1")
|
|
40
|
+
assert.isTrue(sel.isSelected("1"))
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it("none", function(this: any) {
|
|
44
|
+
let sel = this.sel.add("1")
|
|
45
|
+
sel = sel.none()
|
|
46
|
+
assert.isFalse(sel.isSelected("1"))
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
return it("all", function(this: any) {
|
|
50
|
+
const sel = this.sel.all("1")
|
|
51
|
+
assert.isTrue(sel.isSelected("1"))
|
|
52
|
+
assert.isTrue(sel.isSelected("2"))
|
|
53
|
+
})
|
|
54
|
+
})
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { assert } from "chai"
|
|
2
|
+
import { translateHtmlItems, getHtmlItemsStrings } from "../../src/richtext/ExprItemsTranslator"
|
|
3
|
+
import { HtmlItemElement } from "../../src/richtext/ItemsHtmlConverter"
|
|
4
|
+
import { HtmlItemExpr, HtmlItemOrExpr } from "../../src/richtext/ExprItemsHtmlConverter"
|
|
5
|
+
|
|
6
|
+
describe("ExprItemsTranslator", function () {
|
|
7
|
+
describe("translateHtmlItems", function () {
|
|
8
|
+
it("should translate simple strings", function () {
|
|
9
|
+
const items: HtmlItemOrExpr[] = ["Hello ", "World"]
|
|
10
|
+
const translatedItems = translateHtmlItems(items, (input) => input.toUpperCase())
|
|
11
|
+
assert.deepEqual(translatedItems, ["HELLO WORLD"])
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it("should translate nested items", function () {
|
|
15
|
+
const items: HtmlItemOrExpr[] = [
|
|
16
|
+
{
|
|
17
|
+
type: "element",
|
|
18
|
+
tag: "p",
|
|
19
|
+
items: ["Hello", { type: "element", tag: "b", items: ["World"] } as HtmlItemElement]
|
|
20
|
+
} as HtmlItemElement
|
|
21
|
+
]
|
|
22
|
+
const translatedItems = translateHtmlItems(items, (input) => input.toUpperCase())
|
|
23
|
+
assert.deepEqual(translatedItems, [
|
|
24
|
+
{
|
|
25
|
+
type: "element",
|
|
26
|
+
tag: "p",
|
|
27
|
+
items: ["HELLO", { type: "element", tag: "b", items: ["WORLD"] } as HtmlItemElement]
|
|
28
|
+
} as HtmlItemElement
|
|
29
|
+
])
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it("should translate expression items", function () {
|
|
33
|
+
const items: HtmlItemOrExpr[] = [
|
|
34
|
+
{
|
|
35
|
+
type: "expr",
|
|
36
|
+
id: "1",
|
|
37
|
+
expr: { type: "literal", valueType: "text", value: "Hello" },
|
|
38
|
+
labelText: "Greeting"
|
|
39
|
+
} as HtmlItemExpr
|
|
40
|
+
]
|
|
41
|
+
const translatedItems = translateHtmlItems(items, (input) => input.toUpperCase())
|
|
42
|
+
assert.deepEqual(translatedItems, [
|
|
43
|
+
{
|
|
44
|
+
type: "expr",
|
|
45
|
+
id: "1",
|
|
46
|
+
expr: { type: "literal", valueType: "text", value: "Hello" },
|
|
47
|
+
labelText: "GREETING"
|
|
48
|
+
} as HtmlItemExpr
|
|
49
|
+
])
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it("should translate expression items within a string", function () {
|
|
53
|
+
const items: HtmlItemOrExpr[] = [
|
|
54
|
+
"Hello, ",
|
|
55
|
+
{
|
|
56
|
+
type: "expr",
|
|
57
|
+
id: "1",
|
|
58
|
+
expr: { type: "literal", valueType: "text", value: "Hello" },
|
|
59
|
+
labelText: "Greeting"
|
|
60
|
+
} as HtmlItemExpr,
|
|
61
|
+
"!"
|
|
62
|
+
]
|
|
63
|
+
const translatedItems = translateHtmlItems(items, (input) => input.toUpperCase())
|
|
64
|
+
assert.deepEqual(translatedItems, [
|
|
65
|
+
"HELLO, ",
|
|
66
|
+
{
|
|
67
|
+
type: "expr",
|
|
68
|
+
id: "1",
|
|
69
|
+
expr: { type: "literal", valueType: "text", value: "Hello" },
|
|
70
|
+
labelText: "GREETING"
|
|
71
|
+
} as HtmlItemExpr,
|
|
72
|
+
"!"
|
|
73
|
+
])
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it("should translate links while preserving the href", function () {
|
|
77
|
+
const items: HtmlItemOrExpr[] = [
|
|
78
|
+
"Hello, ",
|
|
79
|
+
{
|
|
80
|
+
type: "element",
|
|
81
|
+
tag: "a",
|
|
82
|
+
items: ["there"],
|
|
83
|
+
href: "https://example.com"
|
|
84
|
+
} as HtmlItemElement,
|
|
85
|
+
"!"
|
|
86
|
+
]
|
|
87
|
+
const translatedItems = translateHtmlItems(items, (input) => input.toUpperCase())
|
|
88
|
+
assert.deepEqual(translatedItems, [
|
|
89
|
+
"HELLO, ",
|
|
90
|
+
{
|
|
91
|
+
type: "element",
|
|
92
|
+
tag: "a",
|
|
93
|
+
items: ["THERE"],
|
|
94
|
+
href: "HTTPS://EXAMPLE.COM"
|
|
95
|
+
} as HtmlItemElement,
|
|
96
|
+
"!"
|
|
97
|
+
])
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it("should collect all unique strings", function () {
|
|
101
|
+
const items: HtmlItemOrExpr[] = [
|
|
102
|
+
"Start ",
|
|
103
|
+
{
|
|
104
|
+
type: "element",
|
|
105
|
+
tag: "p",
|
|
106
|
+
items: ["Hello ", { type: "element", tag: "b", items: ["World"] }]
|
|
107
|
+
} as HtmlItemElement,
|
|
108
|
+
" This is a ",
|
|
109
|
+
{
|
|
110
|
+
type: "expr",
|
|
111
|
+
id: "1",
|
|
112
|
+
expr: { type: "literal", valueType: "text", value: "Hello" },
|
|
113
|
+
labelText: "Greeting"
|
|
114
|
+
} as HtmlItemExpr,
|
|
115
|
+
"!"
|
|
116
|
+
]
|
|
117
|
+
const strings = getHtmlItemsStrings(items)
|
|
118
|
+
assert.deepEqual(strings, ["Start", "Hello <b>World</b>", "Greeting", "This is a {0}!"])
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
describe("getHtmlItemsStrings", function () {
|
|
123
|
+
it("should collect all unique strings", function () {
|
|
124
|
+
const items: HtmlItemOrExpr[] = [
|
|
125
|
+
"Start ",
|
|
126
|
+
{
|
|
127
|
+
type: "element",
|
|
128
|
+
tag: "p",
|
|
129
|
+
items: ["Hello ", { type: "element", tag: "b", items: ["World"] }]
|
|
130
|
+
} as HtmlItemElement,
|
|
131
|
+
" This is a ",
|
|
132
|
+
{
|
|
133
|
+
type: "expr",
|
|
134
|
+
id: "1",
|
|
135
|
+
expr: { type: "literal", valueType: "text", value: "Hello" },
|
|
136
|
+
labelText: "Greeting"
|
|
137
|
+
} as HtmlItemExpr,
|
|
138
|
+
"!"
|
|
139
|
+
]
|
|
140
|
+
const strings = getHtmlItemsStrings(items)
|
|
141
|
+
assert.deepEqual(strings, ["Start", "Hello <b>World</b>", "Greeting", "This is a {0}!"])
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
})
|