Error executing template "Designs/Swift/Paragraph/CPQ_Inputs.cshtml"
System.IO.IOException: The process cannot access the file 'E:\DynamicWeb\Solutions\CPQ-Dev-Old\wwwroot\Files\System\Log\Custom\DWCPQ - modelForm\2026-07-31.log' because it is being used by another process.
at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.StreamWriter.ValidateArgsAndOpenPath(String path, Boolean append, Encoding encoding, Int32 bufferSize)
at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding)
at DW_CPQ_API.Helpers.LogHelper.WriteLine(String text, Boolean append)
at DW_CPQ_API.Helpers.LogHelper.WriteFormattedLog(LogLevel level, String text)
at DW_CPQ_API.Helpers.LogHelper.Info(String text)
at DW_CPQ_API.ModelController.LoadFormInput()
at DW_CPQ_API.ModelController.LoadFormApplyRules()
at DW_CPQ_API.ModelController.GetModelData()
at DW_CPQ_API.ModelController..ctor(String modelVersionId, Nullable`1 pageId, NameValueCollection requestVars)
at DW_CPQ_API.ModelController..ctor(Int32 pageId, NameValueCollection requestVars)
at CompiledRazorTemplates.Dynamic.RazorEngine_b56c023e858a4a09a4086d5edd325fd5.ExecuteAsync()
at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer)
at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel>
2 @using Dynamicweb.Ecommerce.ProductCatalog
3 @using System
4 @using DW_CPQ_API
5 @using System.Text.Json
6 @using System.Linq
7
8 @{
9
10 var modelController = Dynamicweb.Context.Current.Items["ModelController"] as ModelController;
11
12 if(modelController == null)
13 {
14 modelController = new ModelController(Model.PageID, Dynamicweb.Context.Current.Request.Params);
15 Dynamicweb.Context.Current.Items["ModelController"] = modelController;
16 }
17
18 //when debugmode is "true" set input name in div element as its title attribute for easy identification
19 string debugmode ="";
20 if( Dynamicweb.Context.Current.Request.QueryString.Get("debugmode") != null)
21 {
22 debugmode= Dynamicweb.Context.Current.Request.QueryString.Get("debugmode")!;
23 }
24 var cpq_model = modelController.DocumentResult;
25
26 string sectionTitle = Model.Item?.GetString("CPQ_SectionTitle") ?? "";
27 string inputGroupName = Model.Item?.GetString("CPQ_InputGroupName") ?? "";
28 string rowTabName = "";
29 var currentParagraph = Dynamicweb.Content.Services.Paragraphs.GetParagraph(Model.ID);
30 if (currentParagraph != null && currentParagraph.GridRowId > 0)
31 {
32 var row = Dynamicweb.Content.Services.Grids.GetGridRowById(currentParagraph.GridRowId);
33 if (row != null)
34 {
35 var rowItem = Dynamicweb.Content.Services.Items.GetItem(row.ItemType, row.ItemId);
36 rowTabName = rowItem?["CPQ_TabName"]?.ToString() ?? "";
37 }
38 }
39
40 string inputGroupPrefixSource = rowTabName;
41 string inputGroupPrefix = new string((inputGroupPrefixSource ?? string.Empty)
42 .Select(ch => char.IsLetterOrDigit(ch) || ch == '_' || ch == '-' ? ch : '_')
43 .ToArray());
44 if (string.IsNullOrWhiteSpace(inputGroupPrefix))
45 {
46 inputGroupPrefix = "default";
47 }
48
49 var cpqPage = Dynamicweb.Content.Services.Pages.GetPage(Model.PageID);
50 string cpqTheme = (cpqPage.Item["CPQ_Theme"] ?? "cpq-bold").ToString();
51
52 int inputColumns = Convert.ToInt32(Model.Item?.GetValue("CPQ_InputColumns") ?? 1);
53
54 string versionId=modelController.ModelVersionId;
55
56 string normalizedInputGroupName = (inputGroupName ?? string.Empty).Trim();
57 var allGroups = cpq_model.Groups ?? new List<DW_CPQ_API.Classes.InputGroup>();
58
59 var selectedRootGroups = allGroups
60 .Where(x => string.Equals((x.Name ?? string.Empty).Trim(), normalizedInputGroupName, StringComparison.OrdinalIgnoreCase)
61 || string.Equals((x.Label ?? string.Empty).Trim(), normalizedInputGroupName, StringComparison.OrdinalIgnoreCase))
62 .ToList();
63
64 var selectedRootGroupNames = selectedRootGroups
65 .Select(x => (x.Name ?? string.Empty).Trim())
66 .Where(x => !string.IsNullOrWhiteSpace(x))
67 .Distinct(StringComparer.OrdinalIgnoreCase)
68 .ToList();
69
70 var childGroups = new List<DW_CPQ_API.Classes.InputGroup>();
71 if (selectedRootGroupNames.Any())
72 {
73 var pendingParents = new Queue<string>(selectedRootGroupNames);
74 var visitedParents = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
75
76 while (pendingParents.Count > 0)
77 {
78 var parentName = (pendingParents.Dequeue() ?? string.Empty).Trim();
79 if (string.IsNullOrWhiteSpace(parentName) || !visitedParents.Add(parentName))
80 {
81 continue;
82 }
83
84 var directChildren = allGroups
85 .Where(x => string.Equals((x.ParentGroup ?? string.Empty).Trim(), parentName, StringComparison.OrdinalIgnoreCase))
86 .OrderBy(x => x.Seq ?? 0)
87 .ToList();
88
89 foreach (var child in directChildren)
90 {
91 var childName = (child.Name ?? string.Empty).Trim();
92 if (string.IsNullOrWhiteSpace(childName))
93 {
94 continue;
95 }
96
97 if (!childGroups.Any(x => string.Equals((x.Name ?? string.Empty).Trim(), childName, StringComparison.OrdinalIgnoreCase)))
98 {
99 childGroups.Add(child);
100 pendingParents.Enqueue(childName);
101 }
102 }
103 }
104 }
105
106 var filterGroupNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
107 if (string.IsNullOrWhiteSpace(normalizedInputGroupName))
108 {
109 // Intentionally keep filterGroupNames empty so no inputs are rendered
110 // when CPQ_InputGroupName is not set.
111 }
112 else if (selectedRootGroupNames.Any())
113 {
114 foreach (var rootName in selectedRootGroupNames)
115 {
116 filterGroupNames.Add(rootName);
117 }
118
119 foreach (var childGroup in childGroups)
120 {
121 var childName = (childGroup.Name ?? string.Empty).Trim();
122 if (!string.IsNullOrWhiteSpace(childName))
123 {
124 filterGroupNames.Add(childName);
125 }
126 }
127 }
128 else
129 {
130 filterGroupNames.Add(normalizedInputGroupName);
131 }
132
133 var filteredInputs = cpq_model.Inputs
134 .Where(x => filterGroupNames.Contains((x.GroupName ?? string.Empty).Trim()))
135 .ToList();
136
137 var groupLabelByName = allGroups
138 .Where(x => !string.IsNullOrWhiteSpace(x.Name))
139 .GroupBy(x => (x.Name ?? string.Empty).Trim(), StringComparer.OrdinalIgnoreCase)
140 .ToDictionary(
141 x => x.Key,
142 x => x.FirstOrDefault(y => !string.IsNullOrWhiteSpace(y.Label))?.Label ?? x.First().Name ?? x.Key,
143 StringComparer.OrdinalIgnoreCase);
144
145 bool showSubgroupTitles = selectedRootGroupNames.Any() && childGroups.Any();
146 var renderedSubgroupTitles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
147
148 string hideSection = "";
149 int inputCount = filteredInputs.Count(x => x.Visible == null || x.Visible == true);
150
151 if (!string.IsNullOrWhiteSpace(normalizedInputGroupName))
152 {
153 var inputGrp = selectedRootGroups.FirstOrDefault();
154 if( inputGrp != null )
155 {
156 if(inputGrp.Visible == false || inputCount == 0)
157 {
158 hideSection = "style=\"display:none;\"";
159 }
160 else
161 {
162 sectionTitle = inputGrp.Label;
163 }
164 }
165 else
166 {
167 if( inputCount == 0 )
168 {
169 hideSection = "style=\"display:none;\"";
170 }
171 }
172 }
173
174 }
175
176 <div class="input-section-@inputGroupName" @hideSection>
177 @if( !string.IsNullOrEmpty(sectionTitle) )//&&
178 {
179 <div class="input-section-title">@sectionTitle</div>
180 }
181 @if (!string.IsNullOrWhiteSpace(normalizedInputGroupName))
182 {
183 <div name="result"></div>
184 <form>
185
186 <div class="container inputs-container input-columns-@inputColumns">
187
188 @foreach(var inputItem in filteredInputs)
189 {
190 if (showSubgroupTitles && !selectedRootGroupNames.Contains((inputItem.GroupName ?? string.Empty).Trim()))
191 {
192 var subgroupName = (inputItem.GroupName ?? string.Empty).Trim();
193 if (!string.IsNullOrWhiteSpace(subgroupName) && renderedSubgroupTitles.Add(subgroupName))
194 {
195 var subgroupTitle = groupLabelByName.ContainsKey(subgroupName) ? groupLabelByName[subgroupName] : subgroupName;
196 <div class="input-section-title mt-3" data-subgroup="@subgroupName.ToLower()">@subgroupTitle</div>
197 }
198 }
199
200 var hidden = "";
201 if( inputItem.Visible != null && inputItem.Visible == false ) hidden = "display:none;";
202
203 var normalizedFieldWidth = (inputItem.FieldWidth ?? "").Trim().ToLowerInvariant();
204 var fieldWidthClass = normalizedFieldWidth == "halfwidth" ? "field-width-half" : "field-width-full";
205
206 var strRequired = "";
207 if( inputItem.Required != null && inputItem.Required == true ) strRequired = "add-label-required";
208
209 bool isRequired = inputItem.Required == true;
210 // bool isInvalid = isRequired && string.IsNullOrEmpty(inputItem.Value);
211 //string validationClass = isInvalid ? "is-invalid" : "";
212 var inputSettings = inputItem.Settings ?? new List<DW_CPQ_API.Classes.NameValue>();
213 bool isReadOnly = Convert.ToBoolean(inputSettings.FirstOrDefault(x => x.Name == "readonly")?.Value?.ToString() ?? false);
214 string valuePrefix = inputSettings.FirstOrDefault(x => x.Name.Equals("value-prefix", StringComparison.OrdinalIgnoreCase))?.Value?.ToString() ?? "";
215 string valueSuffix = inputSettings.FirstOrDefault(x => x.Name.Equals("value-suffix", StringComparison.OrdinalIgnoreCase))?.Value?.ToString() ?? "";
216 string valueFormat = inputSettings.FirstOrDefault(x => x.Name.Equals("value-format", StringComparison.OrdinalIgnoreCase) || x.Name.Equals("format", StringComparison.OrdinalIgnoreCase))?.Value?.ToString()?.Trim().ToLowerInvariant() ?? "";
217 string settingsKeywordText = string.Join(" ", inputSettings
218 .Select(x => $"{x.Name} {x.Value}")
219 .Where(x => !string.IsNullOrWhiteSpace(x)))
220 .ToLowerInvariant();
221 if (string.IsNullOrWhiteSpace(valueFormat))
222 {
223 if (settingsKeywordText.Contains("currency")) valueFormat = "currency";
224 else if (settingsKeywordText.Contains("inch")) valueFormat = "inch";
225 else if (settingsKeywordText.Contains("kg")) valueFormat = "kg";
226 }
227 if (string.IsNullOrWhiteSpace(valuePrefix) && string.IsNullOrWhiteSpace(valueSuffix))
228 {
229 if (valueFormat == "currency") valuePrefix = "$";
230 if (valueFormat == "inch") valueSuffix = "\"";
231 if (valueFormat == "kg") valueSuffix = "kg";
232 }
233 bool hasValueAffix = !string.IsNullOrWhiteSpace(valuePrefix) || !string.IsNullOrWhiteSpace(valueSuffix);
234
235 string inputOptionColumns = inputSettings.FirstOrDefault(x => x.Name == "option-columns")?.Value?.ToString() ?? "3";
236 string imageClass = inputSettings.FirstOrDefault(x => x.Name == "option-image-class")?.Value?.ToString() ?? "";
237
238 bool hideOptionLabel = (inputSettings.FirstOrDefault(x => x.Name == "hide-label")?.Value?.ToString() ?? "").ToLower() == "true";
239 bool noLabel = (inputSettings.FirstOrDefault(x => x.Name == "no-label")?.Value?.ToString() ?? "").ToLower() == "true";
240
241 <div class="input-@(inputItem.Type)-container input-container @fieldWidthClass @(inputItem.Type=="radiobox"||inputItem.Type=="radioswatch"||inputItem.Type=="checkboxLarge"?"input-grid":"")" id="@($"{inputGroupPrefix}_visible_{inputItem.Name}")" style="@hidden" title="@(debugmode=="true"?inputItem.Name:"")">
242
243 @{
244 if( noLabel )
245 {
246 <div id="@($"{inputGroupPrefix}_label_{inputItem.Name}")" style="display:none;"></div>
247 }
248 else
249 {
250 <div class="input-label @strRequired" id="@($"{inputGroupPrefix}_label_{inputItem.Name}")">@inputItem.Label</div>
251 }
252 }
253
254 <div class="input-control input-control-col-@inputOptionColumns" @(noLabel?"style=\"width:100%\"":"")>
255
256 @if( inputItem.Type == "toggle" )
257 {
258
259 string isChecked = "";
260 // if( inputItem.Value != null && (inputItem.Value.ToLower()=="true" || inputItem.Value.ToLower()=="on"|| inputItem.Value.ToLower()=="yes") )
261 if( inputItem.Value is bool toggleValue && toggleValue)
262 {
263 isChecked = "checked";
264 }
265 <label class="toggle-switch" >
266 <input type="checkbox" name="@inputItem.Name" id="@($"{inputGroupPrefix}_{inputItem.Name}")" @isChecked onclick="updateModelForm({inputname:this.name,inputvalue:this.checked});" data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())">
267 <span class="toggle-slider"></span>
268 </label>
269 }
270 @if( inputItem.Type == "radio" ) // Radio Button
271 {
272 bool optionInline = Convert.ToBoolean(inputItem.Settings.FirstOrDefault(x => x.Name == "option-inline")?.Value.ToString() ?? inputItem.Options.Count <= 2);
273 string inlineClass = "";
274 if( optionInline ) inlineClass = "form-check-inline";
275 foreach( var option in inputItem.Options )
276 {
277 string optionDisabled = "";
278 if( option.Disabled ) optionDisabled = "disabled";
279 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}";
280 <div class="form-check @inlineClass @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")">
281 <input class="form-check-input" type="radio" id="@optionId" name="@inputItem.Name" value="@option.Value" onclick="updateModelForm({inputname:this.name,inputvalue:this.value});" checked="@option.Selected" @optionDisabled data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" />
282 <label class="form-check-label" onclick="this.parentElement.querySelector('#@optionId').click();">@option.Label</label>
283 @if( !string.IsNullOrEmpty(option.Image) )
284 {
285 <img src="@option.Image" class="@imageClass" onclick="this.parentElement.querySelector('#@optionId').click();" />
286 }
287 </div>
288 }
289 }
290 @if( inputItem.Type == "radiobox" )
291 {
292 foreach (var option in inputItem.Options)
293 {
294 string optionDisabled = "";
295 if( option.Disabled ) optionDisabled = "option-disabled";
296 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}";
297 var selectedText = option.Selected ? "selected" : "";
298 <div class="@selectedText @optionDisabled @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")"
299 onclick="this.querySelector('#@optionId').click();">
300 <input type="radio" name="@inputItem.Name" id="@optionId" value="@option.Value" style="display:none;" checked="@option.Selected"
301 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" onclick="updateModelForm({inputname:this.name, inputvalue:this.value});"/>
302 @if( !string.IsNullOrEmpty(option.Image) )
303 {
304 <img src="@option.Image" class="@imageClass" />
305 }
306 @if(!hideOptionLabel)
307 {
308 <label onclick="this.parentElement.querySelector('#@optionId').click();">@option.Label</label>
309 }
310 </div>
311 }
312 }
313 @if ( inputItem.Type == "radioswatch" )
314 {
315 <div class="color-options">
316 @foreach (var option in inputItem.Options)
317 {
318 string optionDisabled = option.Disabled ? "option-disabled" : "";
319 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}";
320 var selectedClass = option.Selected ? "selected" : "";
321
322 <div class="color-item @selectedClass @optionDisabled @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"
323 id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")"
324 onclick="this.querySelector('#@optionId').click();">
325
326 <input type="radio"
327 name="@inputItem.Name"
328 id="@optionId"
329 value="@option.Value"
330 style="display:none;"
331 checked="@option.Selected"
332 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())"
333 onclick="updateModelForm({inputname:this.name, inputvalue:this.value});" />
334
335 <div class="color-circle"
336 style="background:@option.Value;">
337 </div>
338
339 @if (!hideOptionLabel)
340 {
341 <label>@option.Label</label>
342 }
343 </div>
344 }
345 </div>
346 }
347 @if( inputItem.Type == "checkbox" )
348 {
349 foreach( var option in inputItem.Options )
350 {
351 string optionDisabled = "";
352 if( option.Disabled ) optionDisabled = "option-disabled";
353 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}";
354 <div class="@optionDisabled @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")"
355 onclick="if(event.target.closest('label,input')) return; this.querySelector('#@optionId').click();">
356 @if( !string.IsNullOrEmpty(option.Image) )
357 {
358 <img src="@option.Image" class="@imageClass" />
359 }
360 <label class="highlight">
361 <input type="checkbox" name="@inputItem.Name" id="@optionId" value="@option.Value" onclick="updateModelForm({inputname:this.name, inputvalue:this.value});" checked="@option.Selected" data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" />
362 <span>@option.Label</span>
363 </label>
364
365 </div>
366 }
367 }
368 @if( inputItem.Type == "checkboxLarge" )
369 {
370 foreach (var option in inputItem.Options)
371 {
372 string optionDisabled = "";
373 if( option.Disabled ) optionDisabled = "option-disabled";
374 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}";
375 <div class="@optionDisabled @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")"
376 onclick="if(event.target.closest('input')) return; this.querySelector('#@optionId').click();">
377 <input type="checkbox" name="@inputItem.Name" id="@optionId" value="@option.Value" class="hidden-checkbox" onclick="updateModelForm({inputname:this.name, inputvalue:this.value});"
378 checked="@option.Selected" @optionDisabled data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" />
379 <img src="@option.Image" class="@imageClass" />
380 <span class="checkbox-indicator @(option.Selected ? "checked" : "")">
381 <span class="checkmark @(option.Selected ? "visible" : "")">✔</span>
382 </span>
383 <label>
384 <span>@option.Label</span>
385 </label>
386 </div>
387 }
388 }
389 @if (inputItem.Type == "select"){
390 @RenderPartial("Components/CPQ/Select.cshtml", new DW_CPQ_API.Classes.CPQInputViewModel{ InputItem = inputItem, InputGroupPrefix = inputGroupPrefix });
391 }
392
393 @if (inputItem.Type == "text")
394 {
395 if (hasValueAffix)
396 {
397 <div class="input-group cpq-input-with-format">
398 @if (!string.IsNullOrWhiteSpace(valuePrefix))
399 {
400 <span class="input-group-text cpq-input-prefix">@valuePrefix</span>
401 }
402 <input class="form-control @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"
403 value="@inputItem.Value"
404 name="@inputItem.Name"
405 type="text"
406 id="@($"{inputGroupPrefix}_{inputItem.Name}")"
407 data-field="@inputItem.Name"
408 placeholder="@inputItem.Placeholder"
409 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});"
410 @(isReadOnly ? "readonly=\"readonly\"" : "")
411 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" />
412 @if (!string.IsNullOrWhiteSpace(valueSuffix))
413 {
414 <span class="input-group-text cpq-input-suffix">@valueSuffix</span>
415 }
416 </div>
417 }
418 else
419 {
420 <input class="form-control @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"
421 value="@inputItem.Value"
422 name="@inputItem.Name"
423 type="text"
424 id="@($"{inputGroupPrefix}_{inputItem.Name}")"
425 data-field="@inputItem.Name"
426 placeholder="@inputItem.Placeholder"
427 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});"
428 @(isReadOnly ? "readonly=\"readonly\"" : "")
429 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" />
430 }
431 }
432
433 @if( inputItem.Type == "number" )
434 {
435 decimal minValue = Convert.ToDecimal(inputItem.Settings.FirstOrDefault(x => x.Name == "min")?.Value.ToString() ?? 0);
436 decimal maxValue = Convert.ToDecimal(inputItem.Settings.FirstOrDefault(x => x.Name == "max")?.Value.ToString() ?? 0);
437 decimal stepValue = Convert.ToDecimal(inputItem.Settings.FirstOrDefault(x => x.Name == "step")?.Value.ToString() ?? 0);
438
439 string minmaxString = "";
440 if( minValue != maxValue )
441 {
442 minmaxString = $"min=\"{minValue}\" max=\"{maxValue}\"";
443 }
444
445 string stepString = "";
446 if( stepValue > 0 )
447 {
448 stepString = $"step=\"{stepValue}\"";
449 }
450
451 <!-- need readonly option -->
452 @* <input class="form-control"
453 value="@inputItem.Value"
454 name="@inputItem.Name"
455 type="number"
456 id="@($"{inputGroupPrefix}_{inputItem.Name}")"
457 placeholder="@inputItem.Placeholder"
458 @(isReadOnly ? "readonly=\"readonly\"" : "")
459 @minmaxString @stepString onblur="checkLimits(this)"
460 /> *@
461
462 @if (hasValueAffix)
463 {
464 <div class="input-group cpq-input-with-format">
465 @if (!string.IsNullOrWhiteSpace(valuePrefix))
466 {
467 <span class="input-group-text cpq-input-prefix">@valuePrefix</span>
468 }
469 <input
470 class="form-control @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"
471 type="number"
472 id="@($"{inputGroupPrefix}_{inputItem.Name}")"
473 data-field="@inputItem.Name"
474 name="@inputItem.Name"
475 value="@inputItem.Value"
476 onfocus="this.select();"
477 placeholder="@inputItem.Placeholder"
478 readonly="@isReadOnly"
479 disabled="@isReadOnly"
480 @minmaxString @stepString onblur="updateModelForm({inputname:this.name,inputvalue:this.value});"
481 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())"
482 />
483 @if (!string.IsNullOrWhiteSpace(valueSuffix))
484 {
485 <span class="input-group-text cpq-input-suffix">@valueSuffix</span>
486 }
487 </div>
488 }
489 else
490 {
491 <input
492 class="form-control @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"
493 type="number"
494 id="@($"{inputGroupPrefix}_{inputItem.Name}")"
495 data-field="@inputItem.Name"
496 name="@inputItem.Name"
497 value="@inputItem.Value"
498 onfocus="this.select();"
499 placeholder="@inputItem.Placeholder"
500 readonly="@isReadOnly"
501 disabled="@isReadOnly"
502 @minmaxString @stepString onblur="updateModelForm({inputname:this.name,inputvalue:this.value});"
503 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())"
504 />
505 }
506 <div class="invalid-feedback">
507 Value out of range
508 </div>
509 }
510
511 @if (inputItem.Type == "lookup")
512 {
513 var jsonString = "{}";
514 if(inputItem.Parameters != null && inputItem.Parameters.Count > 0)
515 {
516 jsonString = JsonSerializer.Serialize(inputItem.Parameters);
517 }
518
519 <div class="mb-3 @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)">
520 <div class="position-relative">
521 <input type="text"
522 id="@($"{inputGroupPrefix}_lookup_{inputItem.Name}")"
523 name="lookup_@inputItem.Name"
524 class="form-control lookup-input cpqlookup"
525 value="@inputItem.ValueText"
526 placeholder="Type to search..."
527 data-params='@jsonString'
528 data-lookupName="@inputItem.Name"
529 data-versionId="@versionId"
530 autocomplete="off"
531 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" />
532 </div>
533
534 <input type="hidden"
535 value="@inputItem.Value"
536 name="@inputItem.Name"
537 id="@($"{inputGroupPrefix}_{inputItem.Name}")" />
538
539 <div id="@($"{inputGroupPrefix}_lookupresult_{inputItem.Name}")" class="lookup-results"></div>
540
541 <div class="invalid-feedback">
542 This field is required.
543 </div>
544 </div>
545 }
546
547 @if (inputItem.Type == "longtext")
548 {
549 <div id="@($"{inputGroupPrefix}_visible_{inputItem.Name}")" class="mb-3 @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)">
550 <textarea
551 class="form-control @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"
552 id="@($"{inputGroupPrefix}_{inputItem.Name}")"
553 data-field="@inputItem.Name"
554 name="@inputItem.Name"
555 placeholder="@inputItem.Placeholder"
556 rows="2"
557 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});"
558 @(isReadOnly ? "readonly=\"readonly\"" : "")
559 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())">@inputItem.Value</textarea>
560 </div>
561 }
562
563 @if (inputItem.Type == "richtext")
564 {
565 <div id="@($"{inputGroupPrefix}_visible_{inputItem.Name}")" class="mb-3 @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)">
566 <textarea
567 class="form-control rich-editor"
568 id="@($"{inputGroupPrefix}_{inputItem.Name}")"
569 data-field="@inputItem.Name"
570 name="@inputItem.Name"
571 placeholder="@inputItem.Placeholder"
572 rows="1"
573 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});"
574 @(isReadOnly ? "readonly=\"readonly\"" : "")
575 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())">@inputItem.Value</textarea>
576 </div>
577 }
578
579 @if (inputItem.Type == "button")
580 {
581 <div id="@($"{inputGroupPrefix}_visible_{inputItem.Name}")" class="mb-3 @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)">
582 <button
583 type="button"
584 class="btn @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"
585 id="@($"{inputGroupPrefix}_{inputItem.Name}")"
586 name="@inputItem.Name"
587 @(isReadOnly ? "disabled" : "")
588 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())">
589 @inputItem.Value
590 </button>
591 </div>
592 }
593
594 @if (inputItem.Type == "date")
595 {
596 <div class="mb-3 @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)">
597 <input type="text"
598 class="form-control datepicker @(inputItem.Required == true && string.IsNullOrEmpty(inputItem.Value as string) ? "is-invalid" : "")"
599 name="@inputItem.Name"
600 id="@($"{inputGroupPrefix}_{inputItem.Name}")"
601 value="@inputItem.Value"
602 placeholder="Select date"
603 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});"
604 @(inputItem.Required == true ? "required" : "")
605 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" />
606 </div>
607 }
608
609 @if (inputItem.Type == "popup")
610 {
611 <input class="form-control popup-message-field @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"
612 value="@inputItem.Value"
613 name="@inputItem.Name"
614 type="text"
615 id="@($"{inputGroupPrefix}_{inputItem.Name}")"
616 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});"
617 placeholder="@inputItem.Placeholder"
618 @(isReadOnly ? "readonly=\"readonly\"" : "")
619 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" />
620 }
621
622 @if( inputItem.Type == "buttonGroup" )
623 {
624 @foreach (var option in inputItem.Options)
625 {
626 string optionDisabled = option.Disabled ? "option-disabled" : "";
627 string selectedText = option.Selected ? "selected" : "";
628 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}";
629 var url = option.Value.StartsWith("http") ? option.Value : "https://" + option.Value;
630
631 <a href="@url"
632 target="_blank"
633 class="option-link @selectedText @optionDisabled @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"
634 id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")"
635 onclick="selectOption(this,true);">
636
637 @if( !string.IsNullOrEmpty(option.Image) )
638 {
639 <img src="@option.Image" class="@imageClass" />
640 }
641 @if(!hideOptionLabel)
642 {
643 <label for="@optionId" class="option-label">@option.Label</label>
644 }
645 </a>
646 }
647 }
648
649 </div>
650 </div>
651 }
652 </div>
653 </form>
654 }
655 </div>
656