Skip to content

Commit

Permalink
Merge pull request #453 from SparkyTD/function-serializer
Browse files Browse the repository at this point in the history
Add custom JsonConverters to ensure that JS function strings are evaluated into function when deserialized by JS
  • Loading branch information
joadan authored Apr 28, 2024
2 parents 3b0d0f3 + f92451d commit bf03cd6
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace ApexCharts.Internal;

/// <summary>
/// Ensures that JS functions are serialized with the key '@eval' so they can be appropriately evaluated on the client side
/// Example:
/// <code>
/// myFunction: {
/// "@eval": "function(value) { return value; }"
/// }
/// </code>
/// </summary>
internal class FunctionStringConverter : JsonConverter<string>
{
public override bool CanConvert(Type typeToConvert) => true;

public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
}

public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName("@eval");
writer.WriteStringValue(value);
writer.WriteEndObject();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace ApexCharts.Internal;

/// <summary>
/// Ensures that JS function arrays are serialized with the key '@eval' so they can be appropriately evaluated on the client side
/// Example:
/// <code>
/// myFunction: {
/// "@eval": [ "function(value) { return value; }" ]
/// }
/// </code>
/// </summary>
internal class FunctionValueOrListConverterConverter : JsonConverter<CustomFunction>
{
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(CustomFunction);

public override CustomFunction Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
}

public override void Write(Utf8JsonWriter writer, CustomFunction value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName("@eval");
if (value == null || value.Count == 0)
JsonSerializer.Serialize(writer, null, options);
else if (value.Count == 1)
JsonSerializer.Serialize(writer, value[0], options);
else
JsonSerializer.Serialize<List<string>>(writer, value, options);
writer.WriteEndObject();
}
}
27 changes: 27 additions & 0 deletions src/Blazor-ApexCharts/Models/ApexChartOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using ApexCharts.Internal;

namespace ApexCharts
{
Expand Down Expand Up @@ -381,16 +382,19 @@ public class AnnotationsPoint : IAnnotation
/// <summary>
/// Click function
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Click { get; internal set; }

/// <summary>
/// Mouse Enter function
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string MouseEnter { get; internal set; }

/// <summary>
/// Mouse Leave function
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string MouseLeave { get; internal set; }


Expand Down Expand Up @@ -501,16 +505,19 @@ public class Label
/// <summary>
/// Click function
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Click { get; internal set; }

/// <summary>
/// Mouse Enter function
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string MouseEnter { get; internal set; }

/// <summary>
/// Mouse Leave function
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string MouseLeave { get; internal set; }

internal void SetEventFunction(AnnotationEventType eventType)
Expand Down Expand Up @@ -1105,6 +1112,7 @@ public class ExportCSV
/// <summary>
/// If timestamps are provided as X values, those timestamps can be formatted to convert them to date strings.
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string DateFormatter { get; set; }
}

Expand Down Expand Up @@ -1611,6 +1619,7 @@ public class ToolCustomIcon
/// Javascript function when the icon is clicked
/// if a OnClick callback is registered this will be overwritten.
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Click { get; set; }

/// <summary>
Expand Down Expand Up @@ -1768,6 +1777,7 @@ public class DataLabels
///
/// In the code above, seriesIndex is useful in multi-series chart, while dataPointIndex is the index of data-point in that series. w is an object consisting all globals and configuration which can be utilized the way mentioned in the above code.
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }
}

Expand Down Expand Up @@ -2262,6 +2272,7 @@ public class Legend
/// },
/// </code>
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }

/// <summary>
Expand All @@ -2278,6 +2289,7 @@ public class Legend
/// <remarks>
/// Note: This feature is only available in shared tooltips (when you have <see cref="Tooltip.Shared"/>: <see langword="true"/>).
/// </remarks>
[JsonConverter(typeof(FunctionStringConverter))]
public string TooltipHoverFormatter { get; set; }

/// <summary>
Expand Down Expand Up @@ -2391,6 +2403,7 @@ public class LegendMarkers
/// }
/// </code>
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string CustomHTML { get; set; }
}

Expand Down Expand Up @@ -2915,6 +2928,7 @@ public class BarTotalDataLabels
/// <summary>
/// Applies a custom function for the total value. The function accepts 2 params where the 1st one is the value while the 2nd one is the config object.
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }

/// <summary>
Expand Down Expand Up @@ -3284,6 +3298,7 @@ public class DonutLabelName
/// <summary>
/// A custom formatter function to apply on the name text in dataLabel
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }
}

Expand Down Expand Up @@ -3330,6 +3345,7 @@ public class DonutLabelTotal
/// <summary>
/// A custom formatter function to apply on the total value. It accepts one parameter w which contains the chart's config and global objects. Defaults to a total of all series percentage divided by the length of series.
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }
}

Expand Down Expand Up @@ -3371,6 +3387,7 @@ public class DonutLabelValue
/// <summary>
/// A custom formatter function to apply on the value label in dataLabel
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }
}

Expand Down Expand Up @@ -3634,6 +3651,7 @@ public class RadialBarDataLabelsTotal
/// <summary>
/// A custom formatter function to apply on the total value. It accepts one parameter w which contains the chart's config and global objects. Defaults to a total of all series percentage divided by the length of series.
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }
}

Expand Down Expand Up @@ -3670,6 +3688,7 @@ public class RadialBarDataLabelsValue
/// <summary>
/// A custom formatter function to apply on the value label in dataLabel
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }

/// <summary>
Expand Down Expand Up @@ -4152,6 +4171,7 @@ public class Tooltip
/// <summary>
/// Draw a custom html tooltip instead of the default one based on the values provided in the function arguments.
/// </summary>
[JsonConverter(typeof(FunctionValueOrListConverterConverter))]
public CustomFunction Custom { get; set; }

/// <summary>
Expand Down Expand Up @@ -4329,6 +4349,7 @@ public class TooltipX
/// <summary>
/// A custom formatter function which you can override and display according to your needs (a use case can be a date formatted using complex moment.js functions)
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }
}

Expand All @@ -4340,6 +4361,7 @@ public class TooltipYTitle
/// <summary>
/// The series name which appears besides values can be formatted using this function. Default behaviour is (seriesName) => returns seriesName
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }
}

Expand Down Expand Up @@ -4367,6 +4389,7 @@ public class TooltipY
/// }
/// </code>
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }
}

Expand All @@ -4383,6 +4406,7 @@ public class TooltipZ
/// <summary>
/// To format the z values of a Bubble series, you can use this function.
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }
}

Expand Down Expand Up @@ -4833,6 +4857,7 @@ public class XAxisLabels
/// }
/// </code>
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }

/// <summary>
Expand Down Expand Up @@ -4914,6 +4939,7 @@ public class YAxisLabels
/// <remarks>
/// Note: In horizantal bar charts, the second parameters also contains additional data like dataPointIndex &amp; seriesIndex.
/// </remarks>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }

/// <summary>
Expand Down Expand Up @@ -5059,6 +5085,7 @@ public class AxisTooltip
/// }
/// </code>
/// </summary>
[JsonConverter(typeof(FunctionStringConverter))]
public string Formatter { get; set; }

/// <inheritdoc cref="ApexCharts.AxisTooltipStyle" />
Expand Down
2 changes: 2 additions & 0 deletions src/Blazor-ApexCharts/Models/MultiType/CustomFunction.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using ApexCharts.Internal;

namespace ApexCharts
{
Expand Down
3 changes: 2 additions & 1 deletion src/Blazor-ApexCharts/wwwroot/js/blazor-apexcharts.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,8 @@ window.blazor_apexchart = {

parseOptions(options) {
return JSON.parse(options, (key, value) => {
if ((key === 'formatter' || key === 'dateFormatter' || key === 'custom' || key === 'click' || key === 'mouseEnter' || key === 'mouseLeave' || key === 'tooltipHoverFormatter') && value.length !== 0) {
if (value && typeof value === 'object' && '@eval' in value) {
value = value['@eval'];
if (Array.isArray(value))
return value.map(item => eval?.("'use strict'; (" + item + ")"));
else
Expand Down

0 comments on commit bf03cd6

Please sign in to comment.