Error executing template "Designs/Swift/Paragraph/Custom_ProductSpecification.cshtml"
System.ArgumentOutOfRangeException: Index and length must refer to a location within the string.
Parameter name: length
at System.String.Substring(Int32 startIndex, Int32 length)
at CompiledRazorTemplates.Dynamic.RazorEngine_f705726a392245bd92e50f2ebaa8535c.<>c__DisplayClass2_0.<RenderFieldValue>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\Co3\itools.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Custom_ProductSpecification.cshtml:line 297
at CompiledRazorTemplates.Dynamic.RazorEngine_f705726a392245bd92e50f2ebaa8535c.<>c__DisplayClass1_0.<RenderField>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\Co3\itools.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Custom_ProductSpecification.cshtml:line 263
at CompiledRazorTemplates.Dynamic.RazorEngine_f705726a392245bd92e50f2ebaa8535c.<>c__DisplayClass0_0.<RenderFieldsFromList>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\Co3\itools.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Custom_ProductSpecification.cshtml:line 153
at CompiledRazorTemplates.Dynamic.RazorEngine_f705726a392245bd92e50f2ebaa8535c.Execute() in D:\dynamicweb.net\Solutions\Co3\itools.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Custom_ProductSpecification.cshtml:line 95
at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer)
at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
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
4 @{
5 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false;
6
7 ProductViewModel product = new ProductViewModel();
8
9 ProductViewModelSettings productSetting = new ProductViewModelSettings
10 {
11 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID,
12 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code,
13 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2,
14 ShopId = Pageview.Area.EcomShopId
15 };
16
17 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
18 {
19 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
20 } else if (Pageview.Item["DummyProduct"] != null) {
21
22 string dummyProductId = "";
23 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page);
24 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel();
25 if (productList.Products != null)
26 {
27 foreach (var p in productList.Products) { dummyProductId = p.Id; }
28 ProductViewModel dummyProduct = dummyProductId != "" ? ViewModelFactory.CreateView(productSetting, dummyProductId) : new ProductViewModel();
29 product = dummyProduct;
30 } else {
31 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id);
32 }
33 } else if (Pageview.Item["DummyProduct"] == null) {
34 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id);
35 }
36 }
37
38 @if (product?.Id != null) {
39 IEnumerable<string> selectedDisplayGroupIds = Model.Item.GetRawValueString("DisplayGroups").Split(',').ToList();
40 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>();
41
42 foreach (var selection in selectedDisplayGroupIds)
43 {
44 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values)
45 {
46 if (selection == group.Id)
47 {
48 displayGroups.Add(group);
49 }
50 }
51 }
52
53 bool showProductFields = Model.Item.GetBoolean("ProductFields");
54
55 bool hideTitle = Model.Item.GetBoolean("HideTitle");
56
57 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
58
59 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4");
60
61 string contentPadding = Model.Item.GetRawValueString("ContentPadding", "");
62 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding;
63 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding;
64
65 string layout = Model.Item.GetRawValueString("Layout", "list");
66 string size = Model.Item.GetRawValueString("Size", "full");
67
68 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0)
69 {
70 product.ProductFields.Clear();
71 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" });
72 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" });
73 showProductFields = true;
74 }
75
76 <div class="@(theme) h-100 item_@Model.Item.SystemName.ToLower()">
77 <div class="@contentPadding">
78 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) {
79 if (!hideTitle)
80 {
81 <div class="text-start pb-2 pb-lg-4">
82 <h2 class="@titleFontSize">@Model.Item.GetString("Title")</h2>
83 </div>
84 }
85 }
86
87 @if (displayGroups.Count != 0) {
88 foreach (var group in displayGroups) {
89 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders");
90
91 if (!hideHeader) {
92 <h4 class="h4 mb-4">@group.Name</h4>
93 }
94
95 @RenderFieldsFromList(group.Fields, layout);
96 }
97 }
98
99 @if (product.ProductFields != null && showProductFields) {
100 if (product.ProductFields.Count > 0) {
101 @RenderFieldsFromList(product.ProductFields, layout);
102 }
103 }
104
105 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) {
106 if (product.ProductCategories.Count > 0) {
107 foreach (var group in product.ProductCategories) {
108 CategoryFieldViewModel category = group.Value;
109 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders");
110
111 if (!hideHeader) {
112 <h4 class="h4 mb-4">@group.Value.Name</h4>
113 }
114
115 @RenderFieldsFromList(category.Fields, layout);
116 }
117 }
118 }
119 </div>
120 </div>
121 } else if (Pageview.IsVisualEditorMode) {
122 <div class="alert alert-warning m-0">@Translate("No products available")</div>
123 }
124
125
126 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout) {
127 string size = Model.Item.GetRawValueString("Size", "full");
128 string extraMargin = size == "full" ? "mb-3" : "";
129 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels");
130
131 <div class="@extraMargin">
132 @if (layout == "columns") {
133 string gaps = size == "full" ? "gap-0" : "gap-2";
134
135 <div class="grid @gaps">
136 @foreach (var field in fields) {
137 @RenderField(field.Value, layout)
138 }
139 </div>
140 }
141 @if (layout == "list") {
142 <dl class="grid gap-0">
143 @foreach (var field in fields) {
144 @RenderField(field.Value, layout)
145 }
146 </dl>
147 }
148 @if (layout == "table") {
149 string tableSize = size == "full" ? "" : "table-sm";
150
151 <table class="table table-striped @tableSize">
152 @foreach (var field in fields) {
153 @RenderField(field.Value, layout)
154 }
155 </table>
156 }
157 @if (layout == "bullets") {
158 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75";
159 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\"";
160
161 <ul class="@listSize" @listStyle>
162 @foreach (var field in fields) {
163 @RenderField(field.Value, layout)
164 }
165 </ul>
166 }
167 @if (layout == "commas") {
168 List<string> featuresList = new List<string>();
169
170 foreach (var field in fields)
171 {
172 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) {
173 List<string> options = new List<string>();
174 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) {
175 if (!string.IsNullOrWhiteSpace(option.Value)) {
176 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) {
177 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>";
178 options.Add(colorSpan);
179 } else if (!string.IsNullOrEmpty(option.Value)) {
180 options.Add(option.Name);
181 }
182 }
183 }
184 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray()));
185 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) {
186 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray()));
187 }
188
189 if (!hideFieldLabels) {
190 featuresList.Add(field.Value.Name + ": " + optionsString);
191 } else {
192 featuresList.Add(optionsString);
193 }
194 } else {
195 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) {
196 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) {
197 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>";
198
199 if (!hideFieldLabels) {
200 featuresList.Add(field.Value.Name + ": " + colorSpan);
201 } else {
202 featuresList.Add(colorSpan);
203 }
204 } else {
205 if (!hideFieldLabels) {
206 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString());
207 } else {
208 featuresList.Add(field.Value.Value.ToString());
209 }
210 }
211 }
212 }
213 }
214
215 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray()));
216
217 <div class="opacity-75 fs-7">@featuresString</div>
218 }
219 </div>
220 }
221
222 @helper RenderField(FieldValueViewModel field, string layout) {
223 string size = Model.Item.GetRawValueString("Size", "full");
224 string fieldValue = field?.Value != null ? field.Value.ToString() : "";
225 string fieldLabel = field?.Name != null ? Translate($"Custom Product Specification - Label - {field.Name}", field.Name) : "";
226 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels");
227 bool noValues = false;
228
229 if (!string.IsNullOrEmpty(fieldValue)) {
230 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) {
231 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>;
232 noValues = values.Count > 0 ? false : true;
233 }
234 }
235
236 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) {
237 if (layout == "columns") {
238 <div class="grid g-col-6 g-col-lg-4">
239 @if(!hideFieldLabels)
240 {
241 <dt class="g-col-4 py-2 fw-bold">@fieldLabel</dt>
242 }
243 <dd class="g-col-8 py-2 mb-0">@RenderFieldValue(field)</dd>
244 </div>
245 }
246 if (layout == "list") {
247 string extraPadding = size == "full" ? "py-2" : "";
248
249 if (!hideFieldLabels)
250 {
251 <dt class="g-col-4 @extraPadding fw-bold">@fieldLabel</dt>
252 }
253 <dd class="g-col-8 @extraPadding mb-0">
254 @RenderFieldValue(field)
255 </dd>
256 }
257 if (layout == "table") {
258 <tr>
259 @if (!hideFieldLabels)
260 {
261 <th class="fw-bold" scope="row">@fieldLabel</th>
262 }
263 <td>@RenderFieldValue(field)</td>
264 </tr>
265 }
266 if (layout == "bullets") {
267 <li>
268 @if (!hideFieldLabels)
269 {
270 <strong>@fieldLabel</strong>
271 }
272 <span>@RenderFieldValue(field)</span>
273 </li>
274 }
275 }
276 }
277
278 @helper RenderFieldValue(FieldValueViewModel field) {
279 string fieldValue = field?.Value != null ? field.Value.ToString() : "";
280
281 bool isLink = field?.Type == "Link";
282 bool isColor = false;
283 bool isBrandName = field?.SystemName == "Brand_name";
284
285 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue;
286 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue;
287
288
289 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>))
290 {
291 int valueCount = 0;
292 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>;
293 int totalValues = values.Count;
294
295 foreach (FieldOptionValueViewModel option in values)
296 {
297 if (option.Value.Substring(0,1) == "#") {
298 isColor = true;
299 }
300
301 if (!isColor) {
302 @option.Name
303 } else {
304 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span>
305 }
306
307 if (valueCount != totalValues && valueCount < (totalValues - 1)) {
308 if (isColor) {
309 <text> </text>
310 } else {
311 <text>, </text>
312 }
313 }
314 valueCount++;
315 }
316 }
317 else
318 {
319 if (fieldValue.Substring(0,1) == "#") {
320 isColor = true;
321 }
322
323 if (!isColor) {
324 if(isLink)
325 {
326 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link");
327 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty;
328 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty;
329
330 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a>
331 }
332 else if (isBrandName)
333 {
334 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope>
335 <span itemprop="name">@fieldValue</span>
336 </span>
337 }
338 else
339 {
340 @fieldValue
341 }
342
343 } else {
344 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span>
345 }
346 }
347 }
348