1+ @using Syncfusion .Blazor .RichTextEditor
2+ @using Syncfusion .Blazor .Buttons
3+ @using Syncfusion .Blazor .SplitButtons
4+ @using Syncfusion .Blazor .DropDowns
5+ @using System .Text .RegularExpressions ;
6+ <div class =" control-section" >
7+ <div class =" control-wrapper" >
8+ <div class =" " >
9+ <SfRichTextEditor ID =" _mailMergeEditor" @bind-Value =" _rteValue" SaveInterval =" 1" @ref =" _mailMergeEditor" >
10+ <RichTextEditorToolbarSettings Items =" @_tools" >
11+ <RichTextEditorEvents OnActionComplete =" @OnActionCompleteHandler" />
12+ <RichTextEditorCustomToolbarItems >
13+ <RichTextEditorCustomToolbarItem Name =" MergeData" >
14+ <Template >
15+ <SfButton CssClass =" @_buttonClass" OnClick =" OnClickHandler" id =" merge_data" tabindex =" -1" aria-label =" Merge User-specific Data" Disabled =" @_sourceCodeEnabled" >
16+ <div class =" e-tbar-btn-text" >Merge Data</div >
17+ </SfButton >
18+ </Template >
19+ </RichTextEditorCustomToolbarItem >
20+ <RichTextEditorCustomToolbarItem Name =" InsertField" >
21+ <Template >
22+ <SfDropDownButton CssClass =" @_dropDownButtonClass" id =" insertField" Items =" @_items" aria-label =" Insert Merge Field" Disabled =" @_sourceCodeEnabled" >
23+ <ChildContent >
24+ <span style =" display :inline-flex ;" >
25+ <span class =" e-rte-dropdown-btn-text" >Insert Field</span >
26+ </span >
27+ <DropDownButtonEvents ItemSelected =" OnItemSelect" OnOpen =" OnDropDownOpen" Closed =" OnDropDownClose" ></DropDownButtonEvents >
28+ </ChildContent >
29+ </SfDropDownButton >
30+ </Template >
31+ </RichTextEditorCustomToolbarItem >
32+ </RichTextEditorCustomToolbarItems >
33+ </RichTextEditorToolbarSettings >
34+ </SfRichTextEditor >
35+ <SfMention DataSource =" _mergeData" TItem =" MergeData" Target =" #_mailMergeEditor" MentionChar =" _mentionChar" AllowSpaces =" true" PopupWidth =' 250px' PopupHeight =' 200px' @ref =" mentionObj" >
36+ <DisplayTemplate >
37+ <span >{{ @( (context as MergeData ).Value ) }} </span >
38+ </DisplayTemplate >
39+ <ChildContent >
40+ <MentionFieldSettings Text =" Text" ></MentionFieldSettings >
41+ </ChildContent >
42+ </SfMention >
43+ </div >
44+ </div >
45+ </div >
46+ <style >
47+ .tailwind #insertField ,
48+ .tailwind3 #insertField {
49+ font-size : 14px
50+ }
51+ .tailwind3 #merge_data ,
52+ .tailwind3-dark #merge_data {
53+ font-weight :400 ;
54+ }
55+ </style >
56+ @code {
57+ private SfMention <MergeData > mentionObj ;
58+ private SfRichTextEditor _mailMergeEditor ;
59+ private string _buttonClass = " e-tbar-btn e-tbar-btn-text" ;
60+ private string _dropDownButtonClass = " e-rte-elements e-rte-dropdown-menu" ;
61+ private bool _sourceCodeEnabled = false ;
62+ private string _rteValue = @" <p>Dear <span contenteditable="" false"" class="" e-mention-chip"" ><span>{{FirstName}}</span></span> <span contenteditable="" false"" class="" e-mention-chip"" ><span>{{LastName}}</span></span>,</p>
63+ <p>We are thrilled to have you with us! Your unique promotional code for this month is: <span contenteditable="" false"" class="" e-mention-chip"" ><span>{{PromoCode}}</span></span>.</p>
64+ <p>Your current subscription plan is: <span contenteditable="" false"" class="" e-mention-chip"" ><span>{{SubscriptionPlan}}</span></span>.</p>
65+ <p>Your customer ID is: <span contenteditable="" false"" class="" e-mention-chip"" ><span>{{CustomerID}}</span></span>.</p>
66+ <p>Your promotional code expires on: <span contenteditable="" false"" class="" e-mention-chip"" ><span>{{ExpirationDate}}</span></span>.</p>
67+ <p>Feel free to browse our latest offerings and updates. If you need any assistance, don't hesitate to contact us at <a href="" mailto:{{SupportEmail}}"" ><span contenteditable="" false"" class="" e-mention-chip"" ><span>{{SupportEmail}}</span></span></a> or call us at <span contenteditable="" false"" class="" e-mention-chip"" ><span>{{SupportPhoneNumber}}</span></span>.</p>
68+ <p>Best regards,<br>The <span contenteditable="" false"" class="" e-mention-chip"" ><span>{{CompanyName}}</span></span> Team</p>" ;
69+ private char _mentionChar = '{' ;
70+ public class MergeData
71+ {
72+ public string Text { get ; set ; }
73+ public string Value { get ; set ; }
74+ }
75+ private List <MergeData > _mergeData = new List <MergeData >
76+ {
77+ new MergeData { Text = " First Name" , Value = " FirstName" },
78+ new MergeData { Text = " Last Name" , Value = " LastName" },
79+ new MergeData { Text = " Support Email" , Value = " SupportEmail" },
80+ new MergeData { Text = " Company Name" , Value = " CompanyName" },
81+ new MergeData { Text = " Promo Code" , Value = " PromoCode" },
82+ new MergeData { Text = " Support Phone Number" , Value = " SupportPhoneNumber" },
83+ new MergeData { Text = " Customer ID" , Value = " CustomerID" },
84+ new MergeData { Text = " Expiration Date" , Value = " ExpirationDate" },
85+ new MergeData { Text = " Subscription Plan" , Value = " SubscriptionPlan" }
86+ };
87+ private List <ToolbarItemModel > _tools = new List <ToolbarItemModel >()
88+ {
89+ new ToolbarItemModel () { Command = ToolbarCommand .Bold },
90+ new ToolbarItemModel () { Command = ToolbarCommand .Italic },
91+ new ToolbarItemModel () { Command = ToolbarCommand .Underline },
92+ new ToolbarItemModel () { Command = ToolbarCommand .Separator },
93+ new ToolbarItemModel () { Command = ToolbarCommand .Formats },
94+ new ToolbarItemModel () { Command = ToolbarCommand .Alignments },
95+ new ToolbarItemModel () { Command = ToolbarCommand .OrderedList },
96+ new ToolbarItemModel () { Command = ToolbarCommand .UnorderedList },
97+ new ToolbarItemModel () { Command = ToolbarCommand .Separator },
98+ new ToolbarItemModel () { Command = ToolbarCommand .CreateLink },
99+ new ToolbarItemModel () { Command = ToolbarCommand .Image },
100+ new ToolbarItemModel () { Command = ToolbarCommand .CreateTable },
101+ new ToolbarItemModel () { Command = ToolbarCommand .Separator },
102+ new ToolbarItemModel () { Name = " MergeData" , TooltipText = " Merge Data" },
103+ new ToolbarItemModel () { Name = " InsertField" , TooltipText = " Insert Field" },
104+ new ToolbarItemModel () { Command = ToolbarCommand .SourceCode },
105+ new ToolbarItemModel () { Command = ToolbarCommand .Separator },
106+ new ToolbarItemModel () { Command = ToolbarCommand .Undo },
107+ new ToolbarItemModel () { Command = ToolbarCommand .Redo },
108+ };
109+ private List <DropDownMenuItem > _items = new List <DropDownMenuItem >
110+ {
111+ new DropDownMenuItem { Text = " First Name" },
112+ new DropDownMenuItem { Text = " Last Name" },
113+ new DropDownMenuItem { Text = " Support Email" },
114+ new DropDownMenuItem { Text = " Company Name" },
115+ new DropDownMenuItem { Text = " Promo Code" },
116+ new DropDownMenuItem { Text = " Support Phone Number" },
117+ new DropDownMenuItem { Text = " Customer ID" },
118+ new DropDownMenuItem { Text = " Expiration Date" },
119+ new DropDownMenuItem { Text = " Subscription Plan" }
120+ };
121+ private Dictionary <string , string > _placeholderData = new Dictionary <string , string >
122+ {
123+ { " FirstName" , " John" },
124+ { " LastName" , " Doe" },
125+ { " PromoCode" , " ABC123" },
126+ { " SubscriptionPlan" , " Premium" },
127+ { " CustomerID" , " 123456" },
128+ { " ExpirationDate" , " 2024-12-31" },
129+ { " SupportEmail" , " support@example.com" },
130+ { " SupportPhoneNumber" , " +1-800-555-5555" },
131+ { " CompanyName" , " Example Inc." }
132+ };
133+ public void OnClickHandler ()
134+ {
135+ if (this ._mailMergeEditor != null )
136+ {
137+ var editorContent = this ._mailMergeEditor .Value ;
138+ var mergedContent = ReplacePlaceholders (editorContent , this ._placeholderData );
139+ _rteValue = mergedContent ;
140+ }
141+ }
142+ public async Task OnDropDownOpen ()
143+ {
144+ if (this ._mailMergeEditor != null )
145+ {
146+ await this ._mailMergeEditor .SaveSelectionAsync ();
147+ }
148+ }
149+ public async Task OnDropDownClose ()
150+ {
151+ if (this ._mailMergeEditor != null )
152+ {
153+ await this ._mailMergeEditor .RestoreSelectionAsync ();
154+ }
155+ }
156+ public async Task OnItemSelect (MenuEventArgs args )
157+ {
158+ if (args .Item .Text != null )
159+ {
160+ var value = _mergeData .FirstOrDefault (md => md .Text == args .Item .Text )? .Value ;
161+ string htmlContent = $" <span contenteditable=\" false\" class=\" e-mention-chip\" ><span>{{{{ {value }}}}}</span></span> " ;
162+ var undoOption = new ExecuteCommandOption { Undo = true };
163+ this ._mailMergeEditor .ExecuteCommandAsync (CommandName .InsertHTML , htmlContent , undoOption );
164+ await this ._mailMergeEditor .SaveSelectionAsync ();
165+ }
166+ }
167+ private void OnActionCompleteHandler (Syncfusion .Blazor .RichTextEditor .ActionCompleteEventArgs args )
168+ {
169+ if (args .RequestType == " SourceCode" )
170+ {
171+ this ._buttonClass = " e-tbar-btn e-tbar-btn-text e-overlay" ;
172+ this ._dropDownButtonClass = " e-rte-elements e-rte-dropdown-menu e-overlay" ;
173+ this ._sourceCodeEnabled = true ;
174+ }
175+ if (args .RequestType == " Preview" )
176+ {
177+ this ._buttonClass = " e-tbar-btn e-tbar-btn-text" ;
178+ this ._dropDownButtonClass = " e-rte-elements e-rte-dropdown-menu" ;
179+ this ._sourceCodeEnabled = false ;
180+ }
181+ }
182+ public static string ReplacePlaceholders (string template , Dictionary < string , string > data )
183+ {
184+ return Regex .Replace (template , @" {{\s*(\w+)\s*}}" , match =>
185+ {
186+ string key = match .Groups [1 ].Value .Trim ();
187+ return data .TryGetValue (key , out var value ) ? value : match .Value ;
188+ });
189+ }
190+ }
0 commit comments